CSAPP bomblab

一个需要注意的地方是除了主函数以外的函数都不支持单步调试,需要加断点。否则即使用 step 也会直接运行到函数返回(通常会导致炸弹爆炸)。

phase 1

图1

0x402400 中存放的就是目标字符串。

phase 2

图2

记 %rsp 存放的地址为 0x0。

phase_2+14:检查 0x0 处存的值是否为 1。

phase_2+52:将 %rbx 指向 0x4 的位置,将 %rbp 指向 0x18 的位置。

phase_2+27:将 0x0 处存的值(即 1)放入 %eax,%eax 内存放的元素变为原来的两倍,比较它和 %rbx 所指位置存的指是否相等。

phase_2+41:%rbx 移动 4 个字节,比较和 %rbp 是否相等,后回到 phase_2+27。

容易得到从 0x0 到 0x14 存放的 6 个数。

phase_3

图3

phase_3+29 说明需要输入大于一个数(和下一题类似,可以查看0x4025cf)。phase_3+46 说明输入的第一个数不能大于 7,并且根据它跳转到对应的位置。后面的每个分支都是对 %eax 赋值。phase_3+123 需要输入的第二个数与 %rax 相等。

查看 0x402470 存放的内容

![图4](/img/bomblab 4.png)

发现存放的就是每个分支的地址。所以输入一组对应的数就可以了。

phase_4

图5

查看 0x4025cf 可以确定需要输入两个整数。

图6

阅读代码可以发现,进入 func4 时,%rcx 中是第二个输入,%rdx 中是 0xe,%esi 中是 0x0,%edi 中是 第一个输入。要求:第二个输入为 0,func4 返回值为 0。

图7

阅读代码可以发现,只要第一个参数恰好等于 func4+17 处 %rcx 中的值,则可以避免递归,直接返回 0。

phase_5

图8

发现我们需要输入一个长度为 6 的字符串。

查看 string_length 可以确定 %rdx 用于保存我们输入字符串的首地址。

图9

查看 0x40245e 可以确定目标字符串是 flyers。

图10

查看 0x4024b0 可以得到一个字符数组。

图11

阅读代码,可以发现:我们输入的字符串的最低一个字节被用于在字符数组中索引对应的字符。所以只需要根据目标字符串确定索引,即输入字符串的最低一个字节。

phase_6

图12

图13

直到 phase_6+121,代码在检查输入的六个数:要求大于 0 小于等于 6,且各不相同。所以,输入的是 1-6 的一个排列。同时,将每个数 x 映射为了 7-x。

查看 0x6032d0,发现存放的是一张链表。前 8 个字节存放一个数,后 8 个字节存放一个指针,指向下一个结点。

图14

phase_6+130 到 phase_6 +181 根据输入的每个数分配结点地址。即 %rsp+0x20 存放第一个数对应的结点地址,%rsp+0x28 存放第二个数对应的结点地址,依此类推。

phase_6+183 到 phase_6+220 将每个结点的指针指向下一个结点,构建链表。

phase_6+222 到 phase_6+257 比较每个结点,要求前一个结点的数值大于后一个结点。

根据链表中存放的数,即可确定结点的编号,再用 7 减去编号,就是我们要输入的数。

图15


secret_phase

注意到给出的函数中有这样一段话,在暗示可能还有一个隐藏的炸弹。

1
2
/* Wow, they got it!  But isn't something... missing?  Perhaps
* something they overlooked? Mua ha ha ha ha! */

将整个文件进行反汇编,可以找到 fun7 和 secret_phase。

图16

图17

查找 secret_phase,发现它在 phase_defused 被调用。

图18

查看里面出现的地址,得到

图19

这里需要输入两个数字和一个字符串,也就是说,要在一个输入两个数字的关卡再输入 DrEvil 就可以进入隐藏关。

运行后查看,确认为第四关。

1705384019396

查看 secret_phase 出现的地址,发现构成了一棵二叉搜索树

图21

画出对应的树

图22

同时,写出 fun7 对应的代码,这是一个二叉树上搜索的过程:

1
2
3
4
5
6
7
8
9
10
int fun7(Tree* rdi, int esi) {
if (!rdi)
return -1;
if (rdi->val == esi)
return 0;
else if (rdi->val < esi)
return 2 * fun7(rdi -> right, esi) + 1;
else
return 2 * fun7(rdi -> left, esi);
}

考虑代码返回值的二进制表示:从低位向高位,0代表进入左子树,1代表进入右子树。要求 fun7 返回值为 22,容易找到对应的数。


图23

撒花!


CSAPP bomblab
https://je3ter.github.io/2024/02/17/CSAPP/CSAPP bomblab/
作者
Je3ter
发布于
2024年2月17日
许可协议