零、基本概念
1、ESP
栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的顶部。
2、EBP
基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
一、栗子
以下摘自网上一篇文章:

明白了吗?主要是用来保存 / 恢复堆栈,以便传递参数给函数。
在 MASM 里面,有一条更方便的语句,就是 invoke,使用它后,你就不用自己做这些事情了。
总的来说,esp 始终指向栈顶,ebp 是在堆栈中寻址用的。
我的理解:
调用一个函数时,先将堆栈原先的基址(EBP)入栈,以保存之前任务的信息。然后将栈顶指针的值赋给 EBP,将之前的栈顶作为新的基址(栈底),然后再这个基址上开辟相应的空间用作被调用函数的堆栈。
函数返回后,从 EBP 中可取出之前的 ESP 值,使栈顶恢复函数调用前的位置;再从恢复后的栈顶可弹出之前的 EBP 值,因为这个值在函数调用前一步被压入堆栈。这样,EBP 和 ESP 就都恢复了调用前的位置,堆栈恢复函数调用前的状态。
二、通过 ollydbg 跟踪 esp 和 ebp

可以看到,初始情况下,ebp 此时值为 0012FEDC,也就是栈帧的地址,而栈顶地址 esp 值为0012FDFC。可以看到两个值有一定的关系。而帧指针的地址较高。
然后我们让它执行前两句,push ebp,mov ebp,esp
可以看到前两句已经执行了,那么 ebp 跟 esp 的值也发生了变化。esp = 0012FDF8,ebp = 0012FDF8。为神马?一句句解读,push ebp,向栈里面压入了一个东西,那么栈顶此时应该发生变化了,也就是地址 -4 字节。为什么是减法呢?因为是向低地址增长的,这点一定得注意。所以此时 esp 变化成了 0012FDFC - 4 = OO12FDF8。至于 ebp 也等于 0012FDF8 就不解释了。
接着上图不解释:
此时呢,观察现在的值。栈顶 esp = 0012FDF4,而 ebp = 0012FDF8;没啥好说的,此时的栈顶已经又跑上去了,说明又有元素压栈了。那么执行这句 mov esp, ebp 之后,不用说,esp 跟 ebp 都会变成 0012FDF8.
我们重点看下一幅,执行完 pop,让 ebp 出栈,后会发生神马。

此时 ebp 已经出栈了,来看看那他们的值,esp = 0012FDFC,ebp = 0012FEDC。首先,ebp 出栈了,这个时候栈空了,所以栈顶会变成初始时的值 0012FDFC。相当于上图中的 esp = 0012FDF8 + 4 = 0012FDFC。注意出栈,则栈顶 + 4,然后呢。ebp 为啥变成了 0012FEDC 初始的值?ebp 不是一直保存着 esp 的初始地址么?
所以重点就在 pop 这个语句了。pop ebp 究竟表达神马意思?ebp 的值起初存在了栈中,出栈以后,它的值就恢复了原样。所以这一句灰常重要啊。pop 的意思也许就是把弹出的值赋给我们的变量,pop ebp,也就是把存在栈中的值弹出来赋给 ebp。
三、流程图
EBP 和 ESP 后面的序号是两个寄存器各自更新的次序。 
四、总结
1、两句的 mov ebp,esp 实际上是把 ebp 进栈后的栈顶地址给了 ebp。
2、在 ebp 没有出栈钱,它会一直保存 ebp 进栈以后的栈顶值,也就是 1 的值。
3、在 ebp 出栈前,需要把 esp 恢复到只有 ebp 在栈中时的值。
4、出栈后,esp 自然恢复到 ebp 进栈以前的初始值,而 pop ebp 则恢复了 ebp 的初始值。
5、pop 的语义很重要,pop ebp 的意思是把当前栈顶的元素出栈,送入 ebp 中,而不是让 ebp 出栈,这点必须明确!
(SAW:Game Over!)
本文详细解析了ESP和EBP寄存器在x86架构中的作用,阐述了它们在函数调用过程中的栈帧建立与恢复。ESP始终指向栈顶,而EBP作为栈帧基址,用于保存和恢复栈的状态。通过实例和流程图,展示了EBP和ESP如何变化,强调了POP指令的重要性,即恢复EBP的初始值。
1134

被折叠的 条评论
为什么被折叠?



