)
09 · 调试方法论 (双平台二进制漏洞调试)教学库 13/13 攻击跑通的背后是 40 轮调试。本篇把调试当工程:通用流程 → 双平台工具链 → 一次定位 padding的完整会话 →血泪陷阱清单。每条工具都给出教学库的真实用例。0. 核心原则证据先行: 任何结论必须有反汇编/寄存器/日志支撑, 禁止我觉得。一次只改一个变量: 改了 C 代码就必须重编译 重探测全部偏移。确定性优先: 先用 setarch 关 ASLR 让地址固定, 再开 ASLR 验证。1. 通用调试流程否否是新发现的问题是 (但没 shell)复现: 构造最小输入(Python POC / 管道文件)定位崩溃点gdb bt / cdb r rip崩溃在预期位置?取证: objdump / nm /strace 收集事实形成假设 (为什么崩)如: 对齐错 / pad 错 / 截断验证假设: 改 payload 重放(一次改一个变量!)假设成立?修复: 改 exploit / 改参数或重编译 victim回归: 全量重跑run_all.sh / run_all_win.bat记录: 写入 discover.md(错误根因反模式)图解: 流程本质是证据驱动的假设-验证循环。最贵的错误是跳过取证直接改代码 —— 教学库 40 轮调试中, 约 70% 的轮次是在修正“假设没验证就动手”。回归不是可选项: 8/8 Linux 5/5 Windows 全量重跑是没改坏别人的唯一证明。2. Linux 工具链配合关系先 setarch 固定地址 → 再 gdb/objdump 采地址gdb 确认崩溃点 → nm 算偏移 → find_gadgets 拼链strace 查 I/O 行为 (截断/阻塞) → 决定换漏洞原语所有结果 → Python POC 固化Linux 六件套 (全部实测)gdb 批处理定位崩溃 / 算 padding / 验证链gdb -batch -ex set disable-randomization on-ex run payload.bin用例: 定 lab6 canary 泄漏 %39/%41/%43objdump反汇编找 gadget / 看 prologueobjdump -d -M intel vuln用例: lab2 找 G10x4007fa G20x4007e0lab6 找 pop_rdi0xb13nm查 libc/二进制符号偏移nm -D libc.so.6 \| grep system用例: system 偏移 0x3cf100xf7de80000x3cf100xf7e24f10strace观察系统调用: 读入长度 / connectstrace -f -e traceexecve,connect ./vuln用例: lab5 验证反弹 connect 发出发现 gets 截断 0x0a (读入太短!)setarch关闭 ASLR 固定地址setarch x86_64 -R ./vuln用例: lab1 libc 固定 0xf7de800064位 libc 固定 0x7ffff7800000find_gadgets.py自动搜 gadgetpython3 tools/find_gadgets.py vuln pop rdi; ret用例: lab6 挖到 pop_rdi0xb13 ret0xb14图解: 六件套各有分工 ——setarch制造确定性 (教学的前提),gdb回答崩在哪、pad 是多少,objdump/nm提供静态事实(gadget/符号),strace揭示 I/O 层面的暗病 (截断、阻塞),find_gadgets.py把人工反汇编变自动。lab6 的完整调试线:strace 发现gets读不满 → 换 read 型漏洞 → objdump 确认新 pad →gdb 泄漏 canary/PIE/libc → find_gadgets 拼链 → setarch 固定验证。3. Windows 工具链Windows 工作流llvm-objdump 读导出/代码pe_util.py 换算出真实 VApython ctypes 构造并触发cdb 抓崩溃点 → 修正偏移Windows 四件套 (全部实测)llvm-objdump反汇编 PE (clang 自带)llvm-objdump -d --x86-asm-syntaxintel helper.dll用例: 确认 pop_shell0x14f0 run_cmd0x1430vp_protect0x1550 导出位置cdb (WinDbg 命令行)定位崩溃 / 看寄存器cdb -o -g -c g; r rip vuln.exe用例: JOP lab 崩溃点 rip 值区分 0xc0000374 (堆) vs 0xc0000005 (访问违例)python ctypes构造 payload / 反弹 shell 监听struct.pack(用例: sin_port 0x5c11 大端校验ctypes 注入 load helper.dllpe_util.py解析 PE 节表 / 偏移转换文件偏移 ↔ VA 互转用例: api_table0xb090 定位0x1a 陷阱字节扫描图解: Windows 侧没有 setarch —— 教学库靠固定 helper.dll(0x180000000)提供确定性; 没有统一 libc, 用pe_util.py代替nm做符号/节表解析;cdb代替 gdb (cdb -o -g -c g; r rip 附加运行, 崩溃后直接打印 rip);ctypes是 Python 侧的万能锤(构造 struct 触发漏洞 当反弹 shell 监听器)。注意 0xc0000374 堆损坏 (Windows 特有, 与 0xc0000005 访问违例的调试方向完全不同)。4. 典型会话: gdb 定位 padding (lab2 实例)二进制 vuln (64位)gdb分析者二进制 vuln (64位)gdb分析者objdump -d -M intel vuln反汇编 main/vulnlea -0x48(%rbp),%rax → buf 起点 rbp-0x48info frame / 推算帧布局saved rbp rbp, 返回地址 rbp8pad 0x48 (buf 到 rbp) 72返回地址落在 payload[72..79]set disable-randomization onrun pattern.bin (cyclic)SIGSEGV: RIP 0x4141414141414141(cyclic 命中返回地址 验证 pad72)确认: 返回地址偏移 72 → 链起点 payload[72]用 G10x4007fa G20x4007e0 构造 ret2csu 链重放执行到 putsplt 泄漏成功 → 链正确图解: 定位 padding 的完整闭环 静态推理(反汇编看 buf 偏移 帧布局 → 算 pad) →动态验证(cyclic 崩溃点 RIP 落在 ‘AAAA’ → 偏移命中) →链验证(跑通泄漏)。三步缺一不可: 只算不验会栽在saved ebx/红区/对齐等反直觉因素上 (lab1 的 pad72 就比直觉的 68多 4 字节, 因为 PIC 保存了 ebx)。5. 常见陷阱清单反模式 (禁止)六大陷阱 (全部实战踩过)gdb 断点命中 csu 启动路径断点打在 0x4007e0, 结果 csu_init也经过 → 误判链已执行解法: 条件断点 / ignore N 次实证: discover.md #7readline/gets 阻塞gdb run 后程序停在 read(0) 等输入解法: 输入走文件/管道echo payload \| ./vulnstrace 确认读入长度0x1a 陷阱 (Windows)文本模式管道把 0x1a 当 EOFpayload 截断在 0x1a解法: python 用二进制写 (b bytes)pe_util 预扫描 0x1a/0x0a二进制未重编译DEBUG 块残留 → 偏移全变20 轮误判!解法: 改码必重编译重探测全部偏移 (参数号/pad/gadget)0x0a 截断 (gets/scanf %s)地址含 0x0a 字节被截断PIE 偏移 0xaXX 全废解法: 换 read 型漏洞 (lab6)canary 含 0x0a/0x1a泄漏出的 canary 字节含换行→ abort (SIGABRT) 而非 SIGSEGV!解法: 重试机制 (再 fork 一次)凭记忆用旧偏移改代码不回归崩溃类型不区分SIGSEGV指针问题SIGABRTcanary/截断图解: 六个陷阱两大共性 ——I/O 层的暗病(T2/T3/T5/T6: 阻塞、EOF、字节截断) 和状态不同步(T1/T4: 断点误触发、二进制过期)。调试时先问两句: “输入真的完整到达了吗?” (strace/日志), “我调试的就是当前这版二进制吗?” (重编译时间戳)。崩溃类型速查:现象大概率根因教学库案例SIGSEGV (64位, libc 内 movaps)栈对齐错, 缺 ret gadgetlab2/lab6 早期SIGSEGV (RIP0x4141…)pad 错所有 lab 第一轮SIGABRTcanary 被破坏 (泄漏值含 0x0a)lab60xc0000005 (Windows)访问违例: 地址/DEPWindows JOP 早期0xc0000374 (Windows)堆损坏 (free-list 篡改)Windows 堆 lab程序提前退出scanf 残留 \n 被 gets 消费lab6 早期无输出无崩溃readline 阻塞 / 管道未关反复出现收尾铁律: 每次修复后跑tools/run_all.sh(8/8) 与run_all_win.bat(5/5), 全绿才算完; 每次坑都记入 discover.md,让 40 轮调试成为一次性的学费。