一个最简易的C函数:执行一个加法
int add(int x, int y) { return x + y; } void main() { __asm { // 下断点 mov eax, eax; } add(1, 2); return; }
VS2019中,创建项目。F5执行,右键到反汇编窗口。
这是main()的对应汇编代码:
此时的堆栈信息如图:
对应堆栈信息如下:
寄存器内容:
可以看到ESP由原来的A88变成了A80,正好减少了8个字节。
此时继续F11执行即可进入函数内查看分步信息。
EBP寻址以前也有记录,这里介绍add函数对应汇编指令的含义:
PUSH EBP MOV EBP,ESP
此时ESP与EBP的状态如图:
SUB ESP,0C0h
C0/4=30,即开辟了30个4字节的内存(30格——3*16=48格格<10进制>),此时的堆栈信息如图:
一格为4字节,sub esp,c0就是开辟了c0个字节的内存,即48格。
且此时的ESP减少了C0,变成了009EF9B8,而EBP保存了原来的ESP的值。
PUSH EBX PUSH ESI PUSH EDI
对应堆栈信息:
LEA EDI,[EBP-0C0h] MOV ECX,030h MOV EAX,0CCCCCCCCh REP SOTS DWORD PTR ES:[EDI]
MOV ECX,030h
MOV EAX,0CCCCCCCCh
REP SOTS DWORD PTR ES:[EDI]
这三行指令的作用是循环执行把EAX的值放到EDI的位置,循环次数为ECX内保存的值(30h<48>次),正好是当前函数开辟的内存大小。
执行结束后堆栈信息如下:
且这几行指令执行结束后ESP与EBP的值并没有改变。只是把缓冲区的内容全部填充成了CCCCCCCC断点。以便在缓冲区溢出时及时停止
mov eax,dword ptr [x] add eax,dword ptr [y]
此时EAX:
(6)接下来就是恢复堆栈:
①还原EDI,ESI,EBX
POP EDI POP ESI POP EBX
②还原ESP
ADD ESP,0C0h
此时堆栈应该ESP=EBP=009EFA78
③还原EBP:把堆栈中存在栈顶的EBP的值POP到EBP中
POP EBP
堆栈信息如图:
④return:表示add函数执行结束,这里的堆栈已经回到了进入add()函数之前的状态。
RET
堆栈如图:
ADD ESP,8
此时的堆栈如图:
这样:ESP和EBP就回到了这个add函数执行之前的样子
原文:https://www.cnblogs.com/codexlx/p/13333831.html