今天继续学习csapp.
前一个lab: Csapp-Datalab 详解
本次lab, bomblab.
0. 说明·
这个实验相当好玩, 题如其名, 类似一个拆炸弹的过程. 实验只给了一个可执行文件, 需要学生通过gdb反汇编这个可执行文件, "拆弹"共有6个阶段, 每个阶段需要用户输入一个特定的字符串, 一旦输入错误, 炸弹就会爆炸,程序终止.
做完整个实验, 学生可以学会如何使用gdb, 能够看懂 gcc所编译出来的汇编代码. 掌握阅读汇编代码的能力.
gdb的使用可参考: gdb 调试基础
本次解释, 均已代码注释+图形解释.
所有汇编代码, 可通过 objdump -d bomb获得.
1. phase 1·
下面是phase 1的汇编代码:
1 | 0000000000400ee0 <phase_1>: |
所以,我们需要查看内存地址 0x402400的字符串是什么, 通过 x /100cb 0x402400
命令,可得:
找到 \0
的位置, 之前所有的字符组成的字符串即为答案:
1 | Border relations with Canada have never been better. |
2. phase 2·
源代码和注释:
1 | 0000000000400efc <phase_2>: |
这个题的重点有两个:
- 函数 read_sim_numers. 内部sscanf实现. 从函数名也可一直,本题要求输入值的数量为6.
- 指令地址 0x400f17开始的地方, 结合这里的4行代码, 可以推断,本题要求输入值的约束为:
$$ x_{i} \times 2 = x_{i+1} \quad i = {0\dots5} $$
且 0x400f0a要求第一个参数为1.
所以,答案为:
1 | 1 2 4 8 16 32 64 |
3. phase 3·
1 | 0000000000400f43 <phase_3>: |
这里注意三个点:
- 输入的字段数>1
- 第二个参数为0x137, 在指令地址为0x400fbe地方可见.
答案:
1 | 1 311 |
4. phase 4·
1 | 0000000000400fce <func4>: |
这是一个递归题目, 难点在参数1, 参数2的确定非常简单,直接为0.
而参数1,则需要带入到代码中,还原递归的过程.
还原为递归代码:
1 | void func4(int x, int y, int z) { |
最终可注意到, x = 7 3 1都可以.
答案:
1 | 7 0 或 3 0 或 1 0 |
5. phase 5·
1 | 0000000000401062 <phase_5>: |
这个题相当有意思,给我一种破译密码的感觉.
可以理解为, 当前手上有一份加密码表, 我们要找到一个合适的坐标, 通过这个坐标去, 然后去密码表上查找对应码字,使得这些码字组成等于"flyers".
解释:
- 坐标: 就是我们要输入的字符串的每个字符. 然后取这些字符的低4位作为坐标
- 密码表: 0x4024b地址空间.得到坐标后, 查看以0x4024b为首地址的字符串加上这些坐标,得到解密后的码字.
- 目标码: 0x40245e地址空间. 我们解密出来的码字要等于这个地址空间所拥有的字符串, 经查看,为flyers
另外,值得注意的是, 以字符的低4bit作为坐标, 这样会有多个字符有相同的低4bit. 查看acsii码表.
如果以数字表示坐标,则坐标为:
1 | 9 15 6 7 |
对比acsii码:
第一个坐标9, 对应到acsii表的第9行:
1 | ) 9 I Y i y |
也就是说, 第一个坐标,可以是这6个字符中的任意一个.
同理,第二个坐标15, 也就是F行:
1 | / ? 0 _ o DEL |
最后, 个人答案:
1 | 9/.567 |
6. phase 6·
phase 6是bomblab中最难的题, 我对代码做了详细的解释:
1 | 00000000004010f4 <phase_6>: |
总体来说, 内存中存在一个6个节点的链表,
比如:
1 | 41 -> 55 -> 15 -> 57 -> 12 -> 412 -> NULL |
我们输入6个数字, 然后经过 7 - 翻转来控制链表的排序. 举个例子:
例如: 输入
1 | 2 3 1 4 5 6 |
则代码会将 每个元素 = 7 - 每个元素. 则输入变为:
1 | 5 4 6 3 2 1 |
然后用 5 4 6 3 2 1
控制链表的排列, 得到:
1 | 12 -> 57 -> 412 -> 15 -> 55 -> 41 -> NULL |
最后检查排列的链表是否是降序的. 如果不是降序, 则bomb.
对于上面的链表,:
1 | 41 -> 55 -> 15 -> 57 -> 12 -> 412 -> NULL |
正确答案应该为:
1 | 1 3 5 6 4 2 |
至于题目中的链表是什么, 查看内存地址空间0x6032d0即可知道.
即:
1 | 332 -> 168 -> 924 -> 681 -> 477 -> 443 -> NULL |
所以答案:
1 | 4 3 2 1 6 5 |
7. 个人调试经验·
第一次调试汇编, 整个过程并不算容易。前5道题目勉勉强强通过gdb调试出来了。 第6题, 只在gdb中调试, 调试了大半天也没能做出来。 因为gdb的显示空间有限, 而且无法添加注释。 所以后来选择通过objdump先把汇编dump出来, 在结合gdb一起看, 边看变写注释, 很快就能debug出来了。