因此,我目前正在阅读实用的反向工程_x86,x64,ARM,Windows内核,反向工具和混淆,该书包括以下示例以说明堆栈框架。
addme(x,y)
01: 004113A0 55 push ebp
02: 004113A1 8B EC mov ebp, esp
03: ...
04: 004113BE 0F BF 45 08 movsx eax, word ptr [ebp+8]
05: 004113C2 0F BF 4D 0C movsx ecx, word ptr [ebp+0Ch]
06: 004113C6 03 C1 add eax, ecx
07: ...
08: 004113CB 8B E5 mov esp, ebp
09: 004113CD 5D pop ebp
10: 004113CE C3 retn
函数调用
01: 004129F3 50 push eax ;param2
02: ...
03: 004129F8 51 push ecx ;param1
04: 004129F9 E8 F1 E7 FF FF call addme
05: 004129FE 83 C4 08 add esp, 8
我了解到,在addme函数的第10行上,我们进行了 mov ebp,esp ,以为当前函数启动新的堆栈框架,但是我不明白为什么我们要调用 mov esp,ebp 。如果我正确理解,这是调用 mov esp,ebp 之前堆栈的当前状态。
TOP
**************************
* param2 *
**************************
* param1 *
**************************
* return addrs *
**************************
* old edp *
**************************
esp and edp are pointing after odl edp.
那为什么要拨打 mov esp,ebp ?
如果我提出问题的方式有问题,请告诉我。谢谢。
答案 0 :(得分:2)
指令对
mov esp, ebp
pop ebp
用于恢复调用函数的堆栈帧。也可以通过单条指令完成
leave
但是这可能比使用两条指令要慢(请参阅this post)。
但是mov esp, ebp
在这里真的有必要吗?
这取决于在函数中执行的操作。编译器通常会添加此行,因为它会从堆栈中删除局部变量。如果在函数中间使用return
,则堆栈上可能还会有其他值,临时结果也可以在堆栈上。想象return
是通过以下堆栈分配调用的:
+---------------------------+
| param 2 |
+---------------------------+
| param 1 |
+---------------------------+
| old eip (return address) |
+---------------------------+
| old ebp (last stackframe) | <-- ebp
+---------------------------+
| local variable 1 |
+---------------------------+
| local variable 2 |
+---------------------------+
| interim value | <-- esp
+---------------------------+
如果寄存器不再足以存储所有值,则可能会出现临时值。并且ebp
指向旧的ebp,而不是之后的内存位置(请参阅Does push esp
update ESP before or after storing?)