聊一聊堆栈
vc 写的程序,反汇编之后,每个call都有一部分相似代码,大体如下。push ebp
mov ebp,esp
……
mov esp,ebp
pop ebp
retn
我们都知道,esp 在程序运行时始终是栈顶指针。程序运行的时候,esp寄存器随时在发生变化,所以在访问保存在堆栈中的“函数的局部变量和参数”时,用esp来寻找就会非常的困难。所以,调用新函数时,将esp的值保存在ebp中,再以ebp为基准,就能够快速方便的访问到函数的局部变量、参数、以及返回地址。
我们还知道,堆栈是负增长,就是最后入栈的值保存在较小的内存地址。所以我们可以总结一下规律。
1、通常情况下(32位系统,vc编译),ebp保存着调用函数最初的esp值,方便程序结束后恢复esp。
2、ebp+4 保存的是函数的返回地址。
3、ebp+8、esp+C 保存的是函数的参数。
4、ebp-4、ebp-8 。。。 保存的是函数的局部变量
再说几个跟栈有关的指令:
1、call指令:相当于push call 的下一跳政令,再jmp到call的地址,比如说 有代码 call40000,他下面的代码地址是100004,则这个call指令相当于push 100004, jmp 40000。压入栈的这个100004 ,在函数中就会变为 ebp+4 里面的值,为啥会变成ebp+4,上面说了,这里再说一下, 函数一进去就是 push ebp 所以,esp里面存了ebp的值,刚刚压入得100004,存放在了ebp+4中,下一条mov ebp,esp 使得 ebp==esp ,这样再找压人内容时,自然就可以通过ebp+4来找到。
2、retn指令 :相当于 jmp ,实际上是mov eip,100004。
EBP主要是用来体现函数局部变量的,栈帧技术就是利用EBP来实现局部变量有条不紊的调用
页:
[1]