pwn栈溢出详解
问题原因
最近在给新生做辅导,发现他们容易混淆一个问题,或者说对于初学者而言,没有理论基础就直接上手实操容易弄混的一个问题:栈区和代码段分不清楚
由于pwn入门题一般是rop,所以大多数人都会有这样一个理解的误区:
把栈和程序执行流混为一谈了
不少初学者pwn手会把栈区当成程序执行流,但其实不是
要明白一点:
rip 指针所在的程序执行流才是程序执行的核心,栈只是用来辅助存储一些必要信息的工具
栈溢出原理分析
这里以Intel x64为例来讲一下
首先需要知道的基本知识:rsp 栈顶指针, rbp 栈底指针, rip 程序计数器(PC指针)
用下面的原理图来解释,提前声明:
栈区一格为8个字节,代码段一格为一句汇编指令
1,这是函数在执行main函数过程中的一段,此时的rip指向call func1,也就是说即将调用func1

2,执行call func1时,先执行的是push rip操作:

3,接着执行jmp func1操作:

4,此时rip已经指向func1的位置,然后开始执行func1里的代码:push rbp,将当前rbp的值入栈

5,mov rbp, rsp:是将rsp的值赋给rbp,也就是让rbp指向rsp指向的位置

6,sub rsp, 20h:将rsp向上移动0x20个字节,为函数要用到的数据开辟0x20大小的空间

7,函数一路执行,省略,直到leave指令

8,leave:mov rsp, rbp,即将rbp的值赋给rsp,也就是让rsp指向rbp指向的位置

9,leave:pop rbp,将栈顶元素出栈,并赋值给rbp

10,ret:即pop rip,将栈顶元素取出赋值给rip(程序计数器)
我们可以看到:这时函数的栈(rsp与rbp所夹的部分)又恢复到原来的样子,rip也恢复到程序调用func1之后的位置了,因此函数能通过调用栈正常执行。

而那个最初被存放在栈中的rip(图中的[rip_0]),就被成为 返回地址 ,也就是程序在完成这一次的函数调用后要继续执行的指令的地址
我们所说的栈溢出,通过对Data'写入时溢出,覆盖掉 返回地址 ,从而让程序接下来一步跳转到任意位置,完成对程序执行流的控制。比如:把 返回地址 覆盖成backdoor

由此,还可以延伸出ROP链攻击方法,在懂得栈溢出基本原理以后可以自行学习

浙公网安备 33010602011771号