参考:pwn小白入门02---汇编函数调用过程_苏璃只想划水的博客-CSDN博客_汇编 过程调用
测试程序
#include<stdio.h>
int sum(int x,int y){
int a=x+y;
return a;
}
int main(){
sum(1,2);
return 0;
}
编译
gcc -m32 pwn03.c -o pwn03
gdb分析
gdb pwn03
反汇编主函数
pwndbg> disass main
Dump of assembler code for function main:
0x000011d1 <+0>: endbr32
0x000011d5 <+4>: push ebp
0x000011d6 <+5>: mov ebp,esp
0x000011d8 <+7>: call 0x11f5 <__x86.get_pc_thunk.ax>
0x000011dd <+12>: add eax,0x2dff
0x000011e2 <+17>: push 0x2
0x000011e4 <+19>: push 0x1
0x000011e6 <+21>: call 0x11ad <sum>
0x000011eb <+26>: add esp,0x8
0x000011ee <+29>: mov eax,0x0
0x000011f3 <+34>: leave
0x000011f4 <+35>: ret
End of assembler dump.
在主函数处下断点,运行
pwndbg> b main
Breakpoint 1 at 0x565561d1
pwndbg> r
Starting program: /home/lingqi/Desktop/pwn/pwn03
当前状态
eip寄存器中存放的地址是cpu将要执行的指令的地址。
1.先将ebp中存储的数值0x0入栈
2.将esp指向的地址赋给ebp
此时栈底指针ebp和栈顶指针esp指向同一个位置,即当前栈帧为空。
3. 将sum(1,2)的参数2入栈
在调用函数之前,需要先把函数的各项参数压入栈中。根据栈先入后出的特性,我们要使2先入栈,1再入栈,使得参数1先出栈,2后出栈。
4.将sum(1,2)的参数1入栈
5.调用函数sum()
call指令是将call sum指令的下一条指令的地址(即指令add esp,8的地址0x565561eb)入栈,即为sum()函数的返回地址。然后将sum函数的第一条指令的地址放入eip寄存器中。
6.将ebp指向的地址入栈,即main函数时的ebp值入栈
7.将esp指向的地址放入ebp
8.将返回地址下存放的参数1(即0x1)放入edx
9. 将返回地址下存放的参数2(即0x2)放入eax
10.两数相加,将结果存入eax
11.将eax中的结果放入栈中ebp上方的局部变量1位置。
12.接下来离开sum函数,需要执行leave,ret指令。
leave 等价于
mov esp,ebp
pop ebp
执行leave函数:即将ebp的值赋给esp,这时esp,ebp都指向0xffffd608的位置。然后将先前存入栈中的ebp的值(0xffffd618)弹出放入当前ebp寄存器中,这时esp指向0xffffd60c(即为调用sum时放入栈中的main函数中call sum指令的下一条指令的地址(即指令add esp,8的地址0x565561eb))。
ret 等价于
pop
jump
然后执行ret指令,将先前存入栈中的eip的值放入当前eip寄存器中。
13.将栈顶指针esp的值加8,即把栈顶往栈底压,相当于把先前放入栈中的参数1,2移除。
可以发现,此时的栈结构与调用sum函数前没有区别。
14.清零eax,主函数返回。