高地址 → ┌─────────────────────────────────┐
│ 函数参数 │ (本题用不到)
├─────────────────────────────────┤
│ 返回地址(ret) │ 🔴 你要覆盖的目标!执行完函数跳这里
├─────────────────────────────────┤
│ 栈底基址(rbp) │ 8字节(64位程序rbp是8字节寄存器)
├─────────────────────────────────┤
│ buf[31] │
│ buf[30] │
│ ... │
│ buf[1] │
低地址 → │ buf[0] │ ← buf数组起始位置(共32字节)
└─────────────────────────────────┘
LOAD:0000000000400520 Elf64_Rela <601020h, 2000000007h, 0> ; R_X86_64_JUMP_SLOT system
LOAD:0000000000400520:这是这条重定位项在文件里的偏移地址(不是 system 函数的运行地址)。
<601020h>:这才是 system 在 GOT 表中的地址(system@GOT = 0x601020)。
R_X86_64_JUMP_SLOT system:说明这是 system 函数的 PLT/GOT 重定位项。
把栈想象成一排带编号的格子(1-72 号),buf 只占用 1-32 号格子:
程序本来只允许往 1-32 号格子里放东西;
但 read 函数是个 “粗心的搬运工”,你给它 72 个东西,它就从 1 号开始,挨个放到 1-72 号格子里;
33-40 号格子是 “栈底标记(rbp)”,41-48 号格子是 “返回地址”—— 搬运工不管这些,全给你塞满;
程序运行到最后,会去看 41-48 号格子里的 “指令地址”,结果看到的是你塞进去的 pop rdi 地址,就按你的指令走了。