You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何借助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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 01:40:21