几个重要的寄存器
eip - 用于存放当前所执行的指令地址
esp - 栈(顶)指针寄存器
ebp - 基址(栈底)指针寄存器
简单的C程序
int g(int x) { ; } int f(int x) { return g(x); } int main(void) { ) + ; }
汇编代码分析
g: pushl %ebp movl %esp, %ebp ;下面两条指令的含义是:将传入的参数7和10相加并保存在寄存器eax中 movl (%ebp), %eax addl $, %eax popl %ebp ret f: pushl %ebp movl %esp, %ebp subl $, %esp ;下面两句指令的含义是:将参数7保存到函数f的栈帧中 movl (%ebp), %eax movl %eax, (%esp) call g leave ret main: pushl %ebp movl %esp, %ebp subl $, %esp movl $, (%esp) call f addl $, %eax leave ret
针对上面的汇编代码,我们有如下的图例分析
说明:
在执行call指令时,eip的所指向的指令是addl $5, %eax
call 指令等价于,将eip中的地址压栈保存,然后将函数f第一条指令(pushl %ebp)的地址放到eip中。
- pushl、popl、leave、ret和call指令的等价指令如下
pushl %eax ;将eax中的值压栈保存
<=>
subl $4, %esp
movl %eax, (%esp)
popl %eax
<=>
movl (%esp), %eax
addl $4, %esp
call 0x12345
<=>
pushl %eip(*)
movl $0x12345, %eip(*)
ret ; 将栈顶值弹出放到eip中,此时eip中的值便是将要执行的指令的地址
<=>
popl %eip(*)
leave ;恢复所调用程序的堆栈
< =>
movl %ebp, %esp
popl %ebp
enter ;与leave指令的操作相反
<=>
pushl %ebp
movl %esp, %ebp