写在前面
bomblab 比起 datalab 更友好一些,除了考察对汇编代码的理解以外,也在锻炼我们的 gdb 调试技能。用时共计 2+2+0.8+0.5+1.5+4 = 10.8h,比 datalab 用时略少一点。刚开始拆弹的时候是很兴奋的,做到后面倒是感觉有点无聊了,我感觉 attacklab 可能更有趣一些(虽然我还没做)。
拆弹记录
首先肯定要对 bomb 进行反汇编,我是用 objdump 来反汇编,并把结果保存到了 txt 文件中。拿到汇编以后随便翻翻找到 phase 们,之后就进入拆弹阶段了。
第一个炸弹
phase_1 简单易懂,只是判断输入是否与某个字符串相等。我一开始以为字符串就是“0x402400”,后面才想到这是那个字符串的地址。用 gdb 设置断点即可得知字符串。
(别看我说得那么轻松,也是折腾了两小时多,毕竟完全没有 gdb 经验 🫠)
第二个炸弹
这也是一个不难的炸弹,把汇编代码往下读就能解决,喜欢的话可以加点注释帮助自己理解。
不过我仍然做了两个小时,主要在疑惑 read_six_numbers 后数字被读到了哪里。还有个有趣的犯蠢的地方,我一开始把 400f35 处的 0x18 当成了十进制 18,疑惑了很久 4n 怎么可能等于 18,后面猛然惊醒发现那是十六进制。🤣
在这里我用到了这些新指令:
1 | si # 单步执行 |
第三个炸弹
用时 50 分钟(有进步!),这次有了更系统的拆弹方法——先把代码分段,然后分析代码提出若干个猜测和问题,随着解答问题就逐渐做掉了。🫠
我们可以轻松注意到输入的数字不能少于一个,再往下读就会 400f75 这一行,算一算就会很自然地猜测:输入要求我们选一个选项,跳过去然后 cmp。
这里是我拆弹时提出的问题以及解答:
- 输入按怎样的格式存储起来?存储在哪里?
分析栈后发现,看起来是读取了两个数字,存储在栈中 - 400f6a 那行是怎么比较的?0x8(%rsp)是什么,输入值吗?猜测这是要求输入的选项值只能在 0-7 之间?
设一个断点就能回答这个问题了。 - 400f75 跳到了哪里?是根据选项跳跃吗?
根据选项跳跃 - 从选项跳到了 400fbe 后,0xc(%rsp)是定值还是会根据输入变化?
0xc(%rsp)是输入的第二个值。由于 8 对齐,我们需要用 0xc(%rsp)而非 0x10(%rsp)来得到第二个值。
第四个炸弹
用时半小时,我连 func4 都不想读,直接用 gdb 来执行 func4,找到返回 0 的输入就行了。这种解法感觉有逃课的嫌疑,不过你就说快不快吧!
在这里我用到了这个新指令:
1 | (gdb) call (int)func4(11, 0, 14) |
第五个炸弹
用时 1.5h,做到这里,我比起刚开始时已经对汇编代码熟悉不少了。首先把代码分成若干个小部分,然后猜测并验证每个部分的功能就能解决这个炸弹。比较有趣的地方是这里加入了一个金丝雀,我还疑惑了一阵子这是什么,后来才想到这是书上讲的金丝雀。
第六个炸弹
用时 4h,对这个炸弹,我感觉“根据运行时的状况猜代码的作用”比“分析代码”更加重要。一开始同样是把代码分成多个小局部,然后分段猜作用。这里引入了链表,还挺有趣。
彩蛋?什么彩弹?