关于课程
这门课程围绕 CSAPP 展开。
书本相关的所有信息,你可以在 这里 找到。
你可以在 Bilibili 或者 YouTube 查看所有的课程视频,Bilibili附带中文字幕。
建议看完相应的章节然后去做相应的实验。大名鼎鼎的 CSAPP 的作者即是这门课程的讲师。你可以在 这里 找到实验相关的所有内容。
这门课程的实验代码可以在我的 Github 找到我的所有解答及相关资料。本次实验相关代码在 ./bomb 文件夹下。
bomb lab
文档
点击 这里, 然后点击标红处 即可下载此次实验对应的文档。
解压之后文件夹对应目录:
1 | ➜ 下载 tree bomb |
- bomb: 可执行文件
- bomb.c: 对应的部分 C 代码
- README: 本次实验的简单说明
内容
bomb目标代码文件运行时提示用户输入6个不同字符串,其中任意一个不正确炸弹会爆炸,也就意味着实验的失败。我们需要通过逆向工程来拆除炸弹,需要使用 gdb 和 objdump 。
环境
Linux, 请不要使用 Windows :)
过程
分析
执行 bomb 程序
1 | ➜ bomb git:(master) ./bomb |
一切正常。查看 bomb.c 程序:
1 | /*************************************************************************** |
由 45-64行可知, bomb程序可以通过标准输入和文件执行, 指定相应的文件在第二个参数。使用我已经破解的结果文件运行。
1 | ➜ bomb git:(master) ./bomb ./result |
没有任何问题。毫无疑问,首先反汇编。
1 | ➜ bomb git:(master) ✗ objdump -d bomb > assemblycode |
查看 main 处代码段。
1 | 0000000000400da0 <main>: |
第一个短语
查看 bomb.c 第73行可知: readline 函数返回指向输入的第一个字符的指针。
查看 main 函数第36-38行。
1 | 400e32: e8 67 06 00 00 callq 40149e <read_line> |
- 1 调用 read_line 函数
- 2 read_line 函数返回结果存在 rax 寄存器, 将其移入 rdi 寄存器,作为之后函数的第一个参数。
- 3 调用 phase_1 函数。
输入的字符指针作为第一个参数,一切都是那么的自然。根据38行指定的地址,查看 phase_1 函数汇编代码。
1 | 0000000000400ee0 <phase_1>: |
查看2-3行。
- 2 内存地址 0x402400 移入 esi寄存器
- 3 调用 strings_not_equal 函数,此时 rdi 为 input
从 strings_not_equal 函数名称和它所对应的两个参数可以知道:
input 应该和对应内存位置字符串相等。
我们使用 gdb 查看对应内存位置字符串:
1 | ➜ bomb git:(master) gdb bomb |
尝试运行 bomb 程序输入对应字符串试试:
1 | ➜ bomb git:(master) ./bomb |
是的,我们成功了!
第四行之后的汇编代码主要是:如果函数返回0,成功返回。不是0,调用 explode_bomb 函数,代表着我们的输入失败了。
第二个短语
查看 main 函数第 42-44 行。
1 | 400e4e: e8 4b 06 00 00 callq 40149e <read_line> |
和第一个方式相同,不再赘述。
查看对应位置 phase_2 汇编代码。
1 | 0000000000400efc <phase_2>: |
- 3-6: 将6个数字读到栈上。
- 7-9: 第一个数字不为1, 炸弹爆炸, 为1,跳到20行
- 10-26:检查每个数字是否为上个数字的2倍,不是则炸弹爆炸。
所以答案应该是: 1 2 4 8 16 32
1 | ➜ bomb git:(master) ./bomb |
第三个短语
查看 main 函数48-50行。
1 | 400e6a: e8 2f 06 00 00 callq 40149e <read_line> |
查看对应位置的 phase_3 代码段:
1 | 0000000000400f43 <phase_3>: |
gdb 打印第5行内存内容
1 | ➜ bomb git:(master) gdb bomb |
- 7-10: 输入最少为两个整数
- 11-37: 第一个数 <= 7, 第二个数由第一个数所计算出来的内存位置所决定
由第14行可知:跳转地址为 0x402470 + (第一个数 * 8) 地址所对应的值
gdb 查看 0x402470 附近100个字节的内容
1 | (gdb) x/100x 0x402470 |
可以得到两个数字的 8 个组合。
(0, 207) (1, 311) (2, 707) (3, 256) (4, 389) (5, 206) (6, 682) (7, 327)
输入这八个数字,都正确:
1 | ➜ bomb git:(master) ./bomb |
1 | ➜ bomb git:(master) ./bomb |
1 | ➜ bomb git:(master) ./bomb |
1 | ➜ bomb git:(master) ./bomb |
1 | ➜ bomb git:(master) ./bomb |
1 | ➜ bomb git:(master) ./bomb |
1 | ➜ bomb git:(master) ./bomb |
1 | ➜ bomb git:(master) ./bomb |
正如之前所分析的,在这两个数字之后加入任意内容都不影响我们第三个短语的成功
1 | ➜ bomb git:(master) ./bomb |
一切都是那么的自然
第四个短语
查看 main 函数 54-56 行:
1 | 400e86: e8 13 06 00 00 callq 40149e <read_line> |
输入字符的指针传递给 phase_4 作为第一个参数,查看 phase_4 对应位置汇编代码。由于这里 phase_4 调用了 func4 函数,因此将 func4 一并贴出。
1 | 0000000000400fce <func4>: |
- 29-33: 需要两个参数, 至于参数具体格式, 可以通过查看 esi 寄存器存储的内存地址内容
1 | (gdb) p (char*)0x4025cf |
显然,刚好需要两个整数。
- 34-47:第一个参数 <= 15,调用 func4的返回值应该是0,第二个数字是0
仔细分析 func4, 15 >> 1 == 7,如果输入是7,刚好满足 jle 和 jge 的条件, 而且 rax = 0, 满足题意,故答案为(7, 0)
1 | ➜ bomb git:(master) ./bomb |
第五个短语
查看 main 函数第 60-62 行:
1 | 400ea2: e8 f7 05 00 00 callq 40149e <read_line> |
查看 phase_5 对应汇编代码:
1 | 0000000000401062 <phase_5>: |
- 9-10: 字符串长度为6
- 13-41: 每个字符对应字节后四位作为偏移,以 0x4024b0 作为基地址,最终和 0x40245e 内存地址做比较。
使用 gdb 查看相应内存地址内容:
1 | (gdb) p (char*)0x40245e |
1 | (gdb) p (char*)0x4024b0 |
为了得到 flyers, 需要的偏移地址为 9fe567,理论上 ASCII 码可打印字符均可。
故答案为 9?>567 或者 y_^UVW 等等 只要满足最后四位要求即可。
1 | ➜ bomb git:(master) ./bomb |
1 | ➜ bomb git:(master) ./bomb |
我们成功了!
第六个短语
查看 main 函数第 66-68 行
1 | 400ebe: e8 db 05 00 00 callq 40149e <read_line> |
查看内存地址 0x4010f4
1 | 00000000004010f4 <phase_6>: |
或许看到如此冗长的汇编代码你会感到茫然,其实没有什么难度,多点耐心就好。
主要表达的是:
- 共有六个数字,每个数字 <= 6
- 每个数字执行固定操作 取反 + 7
- 用操作后的数字作为取址次数,0x6032d0作为基地址,按顺序将对应内存位置 + 8 的内容存储到堆栈。
- 按顺序,堆栈处所存储地址对应的数字应该是递减的
查看 0x6032d0 内存内容:
1 | (gdb) x/100x 0x6032d0 |
对应内存地址内容从小到大排列应该是 0x6032f0 0x603300 0x603310 0x603320 0x6032d0 0x6032e0
循环次数应该是 2 3 4 5 0 1,注意到 main 函数第57行:
1 | 40119f: b8 01 00 00 00 mov $0x1,%eax |
比较时 eax 初始值为1,每操作一次,然后比较。所以,实际的值应该为 3 4 5 6 1 2,又因为一开始对数字进行取反加7的操作,所以本来的6个数字应该是 4 3 2 1 6 5
1 | ➜ bomb git:(master) ./bomb |
全文完
任何建议或者疑问你可以发我邮件: ardxwe@gmail.com