浅析栈溢出使用栈时,地址超出了栈的合法范围
栈溢出详解 栈溢出是指在使用栈时,地址超出了栈的合法范围,而出现的一种异常。这种异常很容易出现在 C/C++ 语言中,原因是编译器不对数组的访问进行越界检查,而数组变量通常申请在栈上。 栈溢出的两种情况: 第一种情况:在定义函数中的局部变量是,占用的空间超出了栈的大小或者在给函数传递参数时,参数过大,导致栈溢出。例如,在定义函数中的变量时定义了一个大于栈大小的数组,结果就会产生栈溢出。 第二种情况:在拷贝数组时没有进行越界检查,而栈又是从高向低生长的。最坏的情况是,我们在调用该函数前保存的返回地址被修改了,这样的就出现了可怕的栈溢出漏洞,导致远程代码的执行。 每个线程都有自己的一个栈,该线程中的所用函数共用此栈! 栈的构造形式: 1. 函数参数存储区: 在调用一个函数时,首先做的并不是保存 CUP 现场寄存器,而是首先将参数压到栈中,于是参数的传递是通过栈执行的,因此我们在编写程序低地址端高地址端时一定要注意参数的大小,如果参数过大,将会导致栈中其他的存储区没有空间而不能存储,尤其是返回地址区,如果该区没有空间存储,那么程序在跳出程序的函数时就找不到正确的返回地址,而导致程序的流程发生位置的改变,并且该改变很有可能导致程序的崩溃。 2. 返回地址区: 我们每调用一个函数时,都会用到两个重要的指令:call, jmp,首先被调用的是 call,在call 的地址处事一条 jmp 指令,指向真正的函数地址。大家都知道在 call 的过程中,会将当前的执行地址 EIP 中的内容压到栈中,而压得位置呢就是在参数的后面的返回地址区。当程序执行完的时候,会首先恢复 CPU 现场,然后将局部变量 pop( 注意:64 字节缓冲区是不会被弹出,而是栈顶指针跳过该缓冲区),恢复 EBP 内容,弹出返回地址并返回,注意哦,此时参数还没有弹出来呢! 栈溢出的危害: 栈溢出可能会导致程序的崩溃、远程代码的执行、返回地址的修改等严重的问题。因此,在编写程序时一定要注意栈的使用,避免栈溢出的发生。 栈溢出的防止方法: 1. 使用缓冲区来限制数组的大小,避免栈溢出。 2. 使用越界检查来检查数组的访问,避免栈溢出。 3. 使用安全的编译器来编译程序,例如使用 GCC 编译器的地址 sanitizer 来检查栈溢出。 栈溢出是一种非常危险的异常,需要我们在编写程序时非常注意栈的使用,避免栈溢出的发生。