通过画堆栈图解析汇编中函数调用的过程

一些基础汇编的解析

Posted by WuJ on March 22, 2020

堆栈图解析汇编中函数调用的过程

C语言中的函数

三个关键点:局部变量、参数、函数返回值

下面是示例程序

#include "stdafx.h"
int Plus(int x, int y)
{
  int z = 2;
  return x+y+z;
}
int main(int argc, char* argv[])
{
  int r = Plus(3, 4);
  return 0;
}

画堆栈图

esp :栈顶

ebp:栈底

对于函数调用,先压入参数,再执行 call

对于参数,从右向左依次压入堆栈(stdcall 模式) 因此,本程式先压入 4,再压入 3

  1. 调用前的堆栈

    屏幕快照 2018-12-10 上午9.15.54

    屏幕快照 2018-12-10 上午9.18.00

  2. PUSH 4 PUSH 3 向栈内压入 4 ,esp - 4 ,eip 向下一条 向栈内压入 3 ,esp - 4 ,eip 向下一条

屏幕快照 2018-12-10 上午9.23.20

  1. call 指令

    一般的 mov 等指令无法改变 eip 的值,但是 call 可以 call 00401005: a. 将 eip 的值改为函数所在的地址 0x00401005 b. 将函数的 ret address 压入堆栈保存

    屏幕快照 2018-12-10 上午9.32.09

  2. 进入函数后,保留现场,划分堆栈

    屏幕快照 2018-12-10 上午9.34.12

  3. PUSH EBP

    屏幕快照 2018-12-10 上午9.35.57

    保存原栈底位置

  4. 提升堆栈,创建缓冲区

    屏幕快照 2018-12-10 上午9.40.04

    紫色部分即为“缓冲区”

    屏幕快照 2018-12-10 上午9.40.34

  5. 填充缓冲区

    LEA EDI ,DWORD PTR SS : [EBP - 44] (EDI中存放缓冲区的最顶地址) MOV ECX ,11 MOV EAX , CCCCCCCC REP STOS DWORD PTR ES : [EDI]

屏幕快照 2018-12-10 上午9.48.41

  1. 定义局部变量

    一般情况下: ebp - n 是局部变量 ebp + n 是参数

    EBP + 4 是返回地址(因此凡是想修改 ebp + 4 的指令都必须小心)

    屏幕快照 2018-12-10 上午9.50.53

  2. 执行加法

    屏幕快照 2018-12-10 上午9.55.12

    EAX 存放函数返回值

  3. 恢复堆栈

    MOV ESP ,EBP

    屏幕快照 2018-12-10 上午9.58.17

    POP EBP 恢复栈底

    屏幕快照 2018-12-10 上午9.58.47

  4. ret 指令

    将堆栈中 函数的返回地址 pop 到 eip 中

    屏幕快照 2018-12-10 上午10.10.51

    ADD ESP ,8 平衡堆栈

    屏幕快照 2018-12-10 上午10.10.21