- 在 main() 函数调用 add_func() 函数前 , 先将调用 add_func() 函数的参数压栈 。
- 在调用 add_func() 函数时 , 会将 返回地址 压栈 , 接着进入 add_func() 函数 。
- add_func() 函数执行时 , 会将原来的 ebp寄存器 的值压栈 , 然后把 ebp寄存器 的设置为 esp寄存器 的值 。
- 接着 add_func() 函数会为局部变量申请空间 , 也就是将 esp寄存器 向下移动 。
- 然后把局部变量 c 设置为参数 a 的值 , 局部变量 d 设置为 参数 b 的值 。
- 最后将局部变量 c 和 d 的值相加 , 放置到 eax寄存器 中(C语言规定以 eax寄存器 传递返回值) , 然后调用 ret 指令返回到 main() 函数 。
- 上面介绍了 函数调用 的过程 , 现在我们来介绍一下函数调用完毕后 , 从被调用函数返回到原来的函数过程是如何处理的 。
- 从 add_func() 函数的汇编代码可以看到 , 当被调用函数执行完毕返回到调用函数前 , 会执行 leave 指令 , 这条指令等价于:
movl %ebp, %esppopl %ebp- 这两条汇编指令的意思是 , 将 esp寄存器 和 ebp寄存器 恢复到调用函数前的值 。
- 然后 , 调用 ret 指令返回到原来的函数 。ret 指令会从栈顶获取 返回地址 , 然后跳转到(jmp指令)此地址继续执行 。这时的 栈帧 的结构如下图所示:

文章插图
?
栈溢出攻击
- 前面说了那么 , 都是为了 栈溢出攻击 这节作铺垫的 。通过前面的学习 , 我们知道调用函数的 参数 、执行完函数后的 返回地址 和被调用函数的 局部变量 都是存放在栈中的 。
- 如果在调用函数时 , 不小心将 返回地址 覆盖了 , 那么调用完函数后 , 将不会跳转到原来的函数继续执行 , 而是跳转到覆盖后的地址执行 。如下图所示:

文章插图
?
- 那么 , 怎样才能把 返回地址 覆盖呢?我们可以通过下面的例子来说明:
#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <stdint.h>#define PTR_SIZE 8// 指针的大小#define EBP_SIZE 8// ebp寄存器的大小void inject_callback(){printf("inject_callback called...n");exit(0);}void func_call(char *addr, int len){char tmpBuf[16] = {0xff};memcpy(tmpBuf + 16 + EBP_SIZE, addr, len);printf("func_call called...n");}int main(int argc, char** argv){uint64_t injectPtr = (uint64_t)&inject_callback;func_call(&injectPtr, PTR_SIZE);printf("main exited...n");return 0;}- 我们使用以下命令编译上面代码 , 并且执行:
$ gcc stack-overflow.c -fno-stack-protector -o stack-overflow$ ./stack-overflowfunc_call called...inject_callback called...在编译上面程序时 , 一定要加上 -fno-stack-protector 参数 , 否则将会触发栈溢出保护 , 导致执行失败 。
- 在上面的代码中 , 我们并没有直接调用 inject_callback() 函数 , 而是通过把 inject_callback() 函数的地址复制到 func_call() 函数的局部变量 tmpBuf 中 。
- 由于局部变量 tmpBuf 的类型为字符串数组 , 而且大小为 16 个字节 。但我们复制数据是从 24(16 + 8)处开始复制 , 已经超出了局部变量 tmpBuf 的大小 , 如下图所示:

文章插图
?
- 从上图可以看出 , func_call() 函数在调用 memcpy() 函数复制数据时 , 由于不小心用 inject_callback() 函数的地址覆盖了返回地址 , 导致 func_call() 函数执行完毕后 , 跳转到 inject_callback() 函数处执行 。
推荐阅读
- 该如何解决卡顿问题呢 网络卡顿怎么解决
- 这份攻略教你如何通过“受教育”扣减交通违法记分
- 如何提升自己的表达能力
- 信息碎片化的时代,如何进行知识管理?
- 如何判断红茶有没有坏?
- 翼王石达开简介 石达开的最终结局如何 石达开简介
- 自己如何重装笔记本电脑操作系统呢? 笔记本操作系统
- 吃鱼头如何 听专家说说
- 家用纯水机如何选购
- 血糖|如何让自己的身体和思维相互协调,自我调节,终生控制体重?
