【逆向工程实战】拆解“二进制炸弹”:用GDB与objdump破解六重关卡

发布时间:2026/7/14 17:06:30
【逆向工程实战】拆解“二进制炸弹”:用GDB与objdump破解六重关卡 1. 逆向工程实战准备第一次接触二进制炸弹可能会觉得无从下手但别担心我们先来准备好趁手的工具。就像拆弹专家需要X光机和排爆工具一样我们需要以下装备必备工具清单objdump这个工具就像二进制文件的X光机能把程序内部结构照得一清二楚。常用命令objdump -d bomb bomb.asm # 反汇编整个程序 objdump -t bomb # 查看符号表GDB我们的动态调试神器相当于排爆机器人的遥控器。建议先掌握这些命令gdb ./bomb # 启动调试 (gdb) break explode_bomb # 必设的保险栓 (gdb) layout asm # 实时查看汇编环境配置技巧我习惯在Linux终端里开三个窗口一个运行炸弹程序一个用vim查看反汇编代码最后一个专用于GDB调试。这样三屏联动效率最高不用来回切换。理解二进制炸弹机制这个程序就像个电子锁保险箱有6个密码锁phase_1到phase_6。每个阶段会检查你的输入输入正确 → 进入下一关输入错误 → 打印BOOM!!!并扣分在课程实验中会影响成绩小贴士先用strings bomb看看有没有明文字符串线索有时候能直接发现密码提示就像在炸弹外壳上找到的说明书。2. 初探第一关字符串比对第一关最适合新手练手我们来看看典型的破解流程。打开反汇编文件找到phase_1部分phase_1: sub $0x8,%rsp mov $0x402400,%esi # 关键线索 callq 401338 strings_not_equal test %eax,%eax je 400fe7 phase_10x17 callq 4015a4 explode_bomb add $0x8,%rsp retq破解步骤详解发现程序将0x402400地址传给字符串比较函数在GDB中查看这个地址的内容(gdb) x/s 0x402400 The future will be better tomorrow.这就是密码运行程序输入这个字符串即可过关背后的原理mov $0x402400,%esi把预设字符串地址存入esi寄存器strings_not_equal会比较你的输入和这个字符串test %eax,%eax检查返回值非零就引爆踩坑记录我第一次直接看汇编时差点被test指令迷惑。其实test A,A就是检查A是否为零的常用技巧相当于if(A ! 0)。3. 破解第二关循环与数组来到第二关难度明显提升。先看反汇编代码的关键部分phase_2: push %rbp push %rbx sub $0x28,%rsp mov %rsp,%rsi callq 40145c read_six_numbers # 关键线索1 cmpl $0x1,(%rsp) # 第一个数必须是1 je 400f30 phase_20x34 callq 4015a4 explode_bomb mov $0x1,%ebx lea 0x4(%rsp),%rbp mov %ebx,%eax imul -0x4(%rbp),%eax # 关键线索2 cmp %eax,(%rbp) je 400f44 phase_20x48 callq 4015a4 explode_bomb add $0x1,%ebx add $0x4,%rbp cmp $0x6,%ebx jne 400f35 phase_20x39破解步骤发现需要输入6个数字read_six_numbers提示第一个数字必须是1cmpl $0x1指令分析循环结构发现递推关系nums[i] nums[i-1] * i推导出完整序列1, 2, 6, 24, 120, 720GDB实战技巧(gdb) break *0x400f25 # 在read_six_numbers后设断点 (gdb) run (gdb) x/6dw $rsp # 查看栈上的6个数字关键发现imul指令揭示了数字间的乘法关系%rbp是指向当前数组元素的指针%ebx是循环计数器从1到6经验分享遇到循环结构时我习惯在纸上画出寄存器变化表。比如记录每次循环后%eax和(%rbp)的值这样规律一目了然。4. 征服第三关switch跳转表第三关引入了switch语句反汇编代码开始变得复杂phase_3: sub $0x18,%rsp lea 0xc(%rsp),%rcx lea 0x8(%rsp),%rdx mov $0x4025cf,%esi # 格式字符串提示 mov $0x0,%eax callq 400bf0 __isoc99_sscanfplt cmp $0x1,%eax jg 400f6a phase_30x27 callq 4015a4 explode_bomb cmpl $0x7,0x8(%rsp) # 第一个输入必须7 ja 400fad phase_30x6a mov 0x8(%rsp),%eax jmpq *0x402470(,%rax,8) # 跳转表破解过程先用GDB查看0x4025cf处的格式字符串(gdb) x/s 0x4025cf %d %d # 说明需要输入两个整数发现第一个输入是switch的索引0-7查看跳转表内容(gdb) x/8a 0x402470 0x402470: 0x400f7c phase_357 # case 0 0x402478: 0x400fb9 phase_3118 # case 1 ...分析各case分支发现case 2会设置eax为0x2c3因此输入2 707即可过关7070x2c3跳转表原理jmpq *0x402470(,%rax,8)是典型的switch实现跳转表基地址0x402470每个条目8字节根据第一个输入选择跳转目标调试技巧使用ni(next instruction)单步执行配合info registers查看寄存器值变化能清晰跟踪程序走向。5. 攻克第四关递归函数分析第四关引入了递归调用反汇编代码看起来最复杂phase_4: sub $0x18,%rsp lea 0xc(%rsp),%rdx mov $0x4025cf,%esi # 依然是%d %d mov $0x0,%eax callq 400bf0 __isoc99_sscanfplt cmp $0x2,%eax jne 401035 phase_40x31 cmpl $0x0,0xc(%rsp) # 第二个输入必须0 jg 40103a phase_40x36 callq 4015a4 explode_bomb mov 0xc(%rsp),%edi callq 400fce func4 # 关键递归函数 cmp $0x37,%eax # 返回值必须55 je 401058 phase_40x54 callq 4015a4 explode_bomb破解步骤识别出需要输入两个数字第二个必须为正数分析func4的递归逻辑// 还原的C代码 int func4(int n) { if(n 1) return 1; return func4(n-1) func4(n-2) 1; }计算发现func4(9)55因此输入9 55即可递归分析技巧在GDB中用backtrace查看递归调用栈使用finish直接执行完当前函数记录各次调用的参数和返回值特别提醒遇到递归不要慌我习惯画树状图来表示调用关系再配合GDB的step和next逐步验证。6. 突破第五关字符串变换第五关考察字符串处理汇编代码开始涉及字符操作phase_5: push %rbx sub $0x10,%rsp mov %rdi,%rbx callq 401338 string_length cmp $0x6,%eax # 输入长度必须为6 je 4010d2 phase_50x2c callq 4015a4 explode_bomb mov $0x0,%eax movzbl (%rbx,%rax,1),%ecx and $0xf,%ecx # 取字符低4位 movzbl 0x4024b0(%rcx),%edx # 查表转换 mov %dl,0x10(%rsp,%rax,1) add $0x1,%rax cmp $0x6,%rax jne 4010d8 phase_50x32 movb $0x0,0x16(%rsp) mov $0x40245e,%esi lea 0x10(%rsp),%rdi callq 401338 strings_not_equal破解方法发现需要6字符输入每个字符取ASCII码低4位作为索引查看转换表(gdb) x/16bx 0x4024b0 0x4024b0: 0x6d 0x61 0x64 0x75 0x69 0x65 0x72 0x73 0x4024b8: 0x6e 0x66 0x6f 0x74 0x76 0x62 0x79 0x6c目标字符串是flyers对应索引[9,15,14,5,6,7]找ASCII码低4位匹配的字符如ionefg字符变换原理and $0xf,%ecx相当于c 0xFmovzbl进行零扩展字节加载转换表相当于一个字符映射器实用技巧用Python快速验证字符转换table maduiersnfotvbyl target flyers print([hex(ord(c)-ord(a)) for c in target])7. 终极挑战第六关与隐藏关第六关涉及链表操作而隐藏关需要特殊触发第六关破解分析发现需要输入6个1-6的不重复数字程序会根据输入重新排列链表节点需要使排列后的节点值按降序排列通过GDB查看节点值(gdb) x/24wx 0x6032d0 # 链表头正确的输入序列是4 2 6 3 1 5隐藏关触发在phase_4后附加特定字符串在phase_defused函数中设置断点发现需要输入9 55 DrEvil然后就能进入secret_phase链表分析技巧用GDB的x命令查看内存中的链表结构绘制节点图表示next指针关系使用print *(struct node*)0x6032d0查看结构体高级技巧对复杂数据结构我常用GDB的define命令创建自定义查看函数(gdb) define printlist set $p(struct node*)0x6032d0 while $p ! 0 printf val%d, next%p\n, $p-val, $p-next set $p$p-next end end通过这六关的实战我们系统性地掌握了逆向工程的核心技能。从最初的字符串比对到最后的链表操作每个阶段都揭示了程序在机器层面的运作机制。记住逆向工程就像侦探破案需要耐心、细致的观察和逻辑推理。当你成功拆解最后一个炸弹时那种成就感绝对值得所有努力