0%

《逆向工程核心原理》学习笔记4

逆向工程核心原理第七章

准备阶段
  • 软件:Ollydbg,visual studio community

  • 使用visual studio创建一个名为StackFrame的c++控制台项目,粘入以下代码,然后运行生成x86(Win32)的StackFrame.exe文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include "stdio.h"
    long add(long a, long b) {
    long x = a, y = b;
    return (x + y);
    }
    int main(int argc, char* argv[]) {
    long a = 1, b = 2;
    printf("%d\n", add(a, b));
    return 0;
    }
栈帧
  • 简单来说,栈帧是利用EBP(栈帧指针,注意不是ESP)寄存器访问栈内局部变量、参数、函数返回地址等的手段

  • 跟据前面所学知识,我们知道ESP栈顶指针,它会随着数据出入栈,而不断改变,如果以它为基准来访问函数的局部变量、参数,那么编写程序将十分困难,这时候就要用到EBP栈帧指针来解决这一问题。调用函数时,把函数起始地址的ESP值记录到EBP当中,这样函数运行时无论ESP怎么变化,用EBP作为基准值能够安全访问函数的局部变量、参数、返回地址,这就是EBP这个寄存器作为栈帧指针的作用

  • 栈帧对应的汇编代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    PUSH EBP				; 函数开始(使用EBP前先把已有值保存到栈中)
    MOV EBP, ESP ; 保存当前的ESP(函数起始地址)到EBP中

    ... ; 函数体


    MOV ESP, EBP ; 将函数的起始地址返回到ESP中
    POP EBP ; 函数返回前,将最开始保存在栈中的EBP值恢复至EBP
    RETN ; 函数终止
  • 下面用图片来描述上面汇编代码发生变化时,EBPESP的变化,测试使用的exe为上述编译的StackFrame.exe

    • 函数开始时,ESP指向"0019FE78"地址,该地址储存着"00B320B3"地址,"00B320B3"地址是当前函数执行完后的返回地址,EBP则指向"0019FE94"地址,这是调用者所在函数(也就是上一个函数)的基础地址

      image-20211123153654338

      截屏2021-11-23 下午3.18.09

    • 接下来,我们执行push ebp,可以看到,由于执行了PUSH命令,ESP栈顶指针往栈顶方向移动,ESP指向的地址变为"0019FE74","0019FE74"所储存的则为我们EBP指向的地址"0019FE94"

      image-20211123154418096

      截屏2021-11-23 下午3.19.40

    • 接着运行mov ebp, esp,可以看到,EBP指向了ESP所指向的"0019FE74"地址,这样当前函数的栈帧就生成了(设置好了EBP)

      image-20211123154907891

      截屏2021-11-23 下午3.20.02

    • 接下来运行sub esp, 0xD8,模拟执行函数体,改变ESP的值,查看EBP和ESP的编号情况

      image-20211123155609652

      截屏2021-11-23 下午3.22.16

    • 可以看到执行函数体时,ESP的值会发生改变,但EBP的值则不变,因此可以用EBP为基准点来访问局部变量、函数参数。因为局部变量和函数参数储存的位置就在EBP和ESP所指的两块地址之间

    • 接着我们nop掉中间其他语句,直接测试函数返回时,EBP和ESP的变化情况

    • 运行mov esp, ebp,可以看到,此时ESP重新指向了"0019FE74"地址

      image-20211123160345570

      截屏2021-11-23 下午3.26.29

    • 执行pop ebp,可以看到,EBP和ESP又回到了函数运行前的状态

      image-20211123160827249

      截屏2021-11-23 下午3.28.34

    • 最后我们执行RETN,可以看到,函数返回到了"00B320B3"所对应的代码语句处

      截屏2021-11-23 下午3.30.32

    • 此时EBP和ESP的值则如下图所示,由此可知,函数运行RETN时,所对应的操作是从栈中弹出函数返回地址,让CPU从该处开始执行,所以ESP才会往POP方向移动

      image-20211123161317268

  • 小结:学习了有关栈帧的内容,了解了函数开始运行和结束运行时ESP和EBP两个寄存器的运作机制,又多学会了两个寄存器。