几个重要的寄存器

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

针对上面的汇编代码,我们有如下的图例分析

一个简单C程序的汇编代码分析-LMLPHP

说明:

  • 在执行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
05-11 14:37