CSAPP_BombLab

1 minute read

Published:

代码参考:https://github.com/ChenYuHengSJTU/CSAPP_Labs/tree/main/bomblab/bomb

准备

  • 从 README.md 中,可知,我们可以创建一个 answer.txt 文件放置输出,这样就可以使用./bomb answer.txt 来运行 bomb,无需多次输入
  • 使用 gdb bomb 启动调试
  • 进入 gdb 界面后,输入 run answer.txt 运行
  • 拆解第一个炸弹,进入 gdb 调试界面后加入断点 b phase_1, 拆解后面的炸弹以此类推

Phase_1

  • 启动 gdb 后设置断点,然后 c 运行至断点

  • 在 answer.txt 中输入 hello 作为假设的输入

  • gdb 中输入 layout asm 显示汇编代码

  • si 单步运行(进入调用的函数)

  • 首先进入函数 string_not_equal

/assets/post/2023-02/image_20230227152842.png

  • 打印寄存器 ` p $rdi ` , 发现是我们的输入,再打印另外一个传给 string_not_equal 的参数,p $rsi, 即得到答案 Border relations with Canada have never been better

assets\post\2023-02\image-20230301125437522.png

Phase_2:

  • 还是侥幸地输入 hello,然而还是炸了

  • 打断点,然后调出 tui 的汇编界面

assets\post\2023-02\image-20230301125814766.png

  • 可以看到,read_six_numbers 的函数调用
  • 输入 1 2 3 4 5 6

assets\post\2023-02\image-20230301130228780.png

  • 接着向下看汇编,可以看到,这是一个循环,依次对输入的六个数进行一定的操作

  • 其中最重要的应该是 add %eax,%eax, 将每次读入的数乘 2,然后与下一个数比较

  • 于是,我们的输入应该是一个公比为 2 的等比数列

  • 我的输入:1 2 4 8 16 32

assets\post\2023-02\image-20230301130448413.png

  • 我们依旧侥幸地输入 hello

  • 炸!

  • 看了一眼 phase_3 的汇编代码,第一眼并没有看到一些很有用的信息,于是从头开始单步执行 si 或 ni

  • 走到输入的函数调用__isoc99 sscanfaplt

  • 那么,传入的参数是什么呢

  • 打印 $edi p (char*)$esi

  • 发现新大陆,是 C 语言里极其常见的格式字符串 “%d %d”

  • 应该传入两个参数

  • 继续发扬优良传统,输入 0,1

  • 炸!

assets\post\2023-02\image-20230301131628096.png

  • 在这里(上图),我们发现,程序将两个参数 *(int*)$rsp,*(int*)($rsp+0xc) 依次与 $eax 比较,我们打印栈上的内容,发现是我们的输入!

assets\post\2023-02\image-20230301131749091.png

  • 再依次查看赋给 $eax 的值,可得答案:1 311

assets\post\2023-02\image-20230301131628096.png

Phase_4

  • hello!!!

assets\post\2023-02\image-20230301131847726.png

  • 查看汇编,我们发现,phase_4 调用了函数 func4

assets\post\2023-02\image-20230301131932909.png

  • 至于接下去嘛,试着试着,就过了,看汇编,好像就是输入 0 1

  • 我的输入:0 1

D:\SJTU\ChenYuHengSJTU.github.io\assets\post\2023-02\image-20230301132222457.png

Phase_5

  • 孤单的黑夜途中,只要输入 hello,bomb 就不会惶恐

  • 查看汇编,string_length,嗷,还是输入字符串

  • 不过这次有意思得多

  • phase_5 的汇编代码很长,跳来跳去,还随时接一句 callq 0x40143a<explode_bomb>

assets\post\2023-02\image-20230301132627539.png

  • 我们发现有一个常量地址,0x4024b0,我们打印之,发现!!!

  • maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?!

  • 我的回答是 ctrl-c 不行,但是 hello 可以

  • 不过这个字符串要怎么利用呢

assets\post\2023-02\image-20230301132958157.png

  • 一阵 ni,发现代码一直在这段汇编之间跳,然后处理完后调用 string_not_equal

  • layout regs, 方便查看寄存器的变化,我们发现,这个过程是,使用 0xf 依次对我们输入的每个字符的 ascii 码取低位,得到的值作为索引,到 maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?! 中取字符,来生成比较的字符串

  • 通过打印参数传递寄存器,得到被比较的字符串是 flyers

  • 然后仔细比较、取字符、拼接

  • 我的输入 ionefg

assets\post\2023-02\image-20230301133610376.png

Phase_6

  • hello

  • 不能皮了,phase_6 的代码还是又臭又长很难懂的

  • 不过做到 phase_6 了,不难看出输入还是六个数

  • 难道是???

  • 1 2 3 4 5 6

  • bomb!

  • 并且 —

assets\post\2023-02\image-20230301134005955.png

  • 由这里的循环,发现,这六个数必须在 1 和 6 之间,且不能相等

  • 呦吼,我们的输入到此刚好符合要求

  • 往下看

assets\post\2023-02\image-20230301134239734.png

  • 发现这里也有一个常量地址 $0x6032d0

  • 迫不及待地打印之 p *(int*)0x6032d0

  • 发现是 332

  • 咦,奇怪的数!

  • 往后打印,p *(int*)(0x6032d0 + 8)

assets\post\2023-02\image-20230301134631553.png

  • 这或许是?结构体?因为 p *(int*)(0x6032d0 + 8) 的结果恰是 0x6032d0 + 16,而指针长度恰好是 8 bytes,像不像链表?

  • 一顿打印猛如虎

  • 得到 332,1 -> 168,2 -> 924,3 -> 691,4 -> 477,5 -> 443,6

  • 不过虽然发现至此,我们的答案还是被炸了

  • 直接看最后!

assets\post\2023-02\image-20230301135006162.png

  • 我们发现,这个循环只有当最后的链表,从头到尾的数值依次增大才可以安全退出

  • 我们打印这时候的链表,可以得到结论,phase_6 是按照我们输入的 1 - 6 的序列来对链表进行排序的,我们输入 1 2 3 4 5 6,得到的是逆序链表,类似于翻转链表

  • 根据此规律,得到答案

  • 我的输入:4 3 2 1 6 5

assets\post\2023-02\image-20230301135307405.png