我今天看视频学习C++内存管理学到栈攻击的知识点时遇到了一个问题:
以下程序在linux中通过
gcc 00_code.c -z execstack -fno-stack-protector
开启堆栈可执行机制并关闭栈保护机制后,在func1中通过数组越界访问的方式成功获取func2的使用权
我不理解的地方是为什么在func1中通过printf("a[n] = %d\n",a[6]);会成功调用func2,通过函数名怎么可能会让函数执行的呢?还是说在func1运行完出栈的时候调用的func2呢?
#include <stdio.h>
int func2()
{
printf("stackflow success!\n");
while(1);
}
void func1()
{
int a[4];
a[6] = func2;
printf("a[n] = %d\n",a[6]);
}
int main(int argc, char const *argv[])
{
func1();
return 0;
}
我觉得有可能是在func1函数出栈的时候调用了func2,我通过在func1最后加了一个while(1)循环,发现只要func1不退出,func2就不会被调用(只是猜测,具体我还是一头雾水)
【以下回答由 GPT 生成】
栈溢出导致的栈攻击是一种常见的安全漏洞。让我们来详细解释下你在代码中遇到的问题和相应的解决方案。
首先,让我们来理解栈的工作原理。在函数调用时,函数的局部变量、参数和返回地址等信息都会被存储在栈中。栈是一种后进先出(LIFO)结构,每当调用一个新函数时,就会在栈中创建一个新的帧。
在你的代码中,问题出现在func1
函数中的数组越界操作a[6] = func2
。当你访问一个数组超出其边界的位置时,会覆盖到栈上的其他数据,包括函数的返回地址。因为在func1
函数的栈帧上,局部变量a
的下标为 6 的位置处超过了a
的实际长度(大小为 4),所以会覆盖到func1
函数的返回地址。
因此,func2
函数的地址被写入到了func1
函数的返回地址位置上。当func1
函数执行完毕并返回时,CPU会根据返回地址跳转到该地址对应的代码,从而执行了func2
函数。
为了解决这个问题,你可以采取以下措施:
避免数组越界:确保在访问数组时不超出其边界范围。可以检查下标是否越界,或者使用更安全的数据结构,如动态分配内存。
使用编译器提供的栈保护:大多数编译器都提供了栈保护机制,可以检测到栈溢出并进行相应的处理。你在编译时使用的-fno-stack-protector
选项是关闭了栈保护功能,建议不要关闭这个选项,以提高代码的安全性。
使用内存安全的函数:你在代码中使用了printf
函数,然而它并不是一个内存安全的函数。当使用不当时,printf
可能导致安全漏洞,例如格式字符串漏洞。建议使用安全的版本,如snprintf
,并在使用时遵循安全的使用规则。
对用户输入进行验证和过滤:避免接收不受信任的输入数据,对输入进行验证和过滤,可以减少栈溢出攻击的风险。
综上所述,对于栈溢出导致的栈攻击问题,应当尽量避免数组越界和关闭栈保护机制,使用内存安全的函数,并对用户输入进行验证和过滤,以提高代码的安全性。这样可以降低栈溢出攻击的风险。
【相关推荐】
链接寄存器覆盖,缓冲区溢出攻击,是黑客常用的方式。
这段代码中存在两个问题:
在func1函数中,数组a只被定义了4个元素,但是在访问第6个元素时并没有出现编译错误,这是因为C语言中数组的下标从0开始计数,访问第6个元素实际上是访问了数组之外的内存,这种行为被称为数组越界访问,可能会导致程序崩溃或产生不可预料的行为。
将函数指针赋值给整型变量的行为是不合法的,因为这相当于将指针类型的值转换为整型类型的值。正确的做法是定义一个指向函数的指针,将函数的地址赋值给该指针,再通过指针来调用函数。
因为都是指针,
所以。运行的时候,不管是函数指针,还是数组的指针,都一样的被运行了。