1. 更好地理解计算机系统的安全问题;
2. 提高编程技能和汇编语言的理解。
- VMware Workstation虚拟机环境下的Ubuntu 64位。
实验准备阶段:首先需要使用ubuntu联网环境跳转到链接下载实验所需的bomblab:http://csapp.cs.cmu.edu/3e/labs.html ,这里可以直接在Ubuntu火狐浏览器打开链接,找到bomblab点击Self Study Handout即可下载。
下好bomblab压缩包后终端输入$ tar –xvf bomb.tar进行解压缩,进入该目录所有文件如下所示:
图1 解压缩
之后即可在终端输入sudo apt-get install gdb安装调试器。
实验内容和步骤:
“Binary bombs”是一个可在Linux系统上运行的C程序,它由6个不同的阶段(phase1~phase6)组成。在每个阶段,程序会要求输入一个特定的字符串。如果输入的字符串符合程序的预期输入,那么这个阶段的炸弹就会被“解除”,否则炸弹就会“爆炸”,并输出“BOOM!!!”的提示信息。
实验的目的是尽可能多地解除这些炸弹的阶段。每个炸弹阶段考察了机器级语言程序的一个不同方面,难度逐级递增。
* 阶段1:字符串比较
首先运行gdb,命令行输入gdb bomb。
gdb bomb
在GDB中设置phase_1的断点,输入break phase_1。使用disassemble命令查看phase_1的汇编代码,输入disassemble phase_1。根据汇编代码的逻辑,推断出 phase_1的正确输入。
break phase_1
disassemble phase_1
这里通过mov $0x402400,%esi确定预设字符串存放地址,gdb输入x/s 0x402400获取字符串,结果为“Border relations with Canada have never been better.”。
x/s 0x402400
Border relations with Canada have never been better.
图2 phase_1
* 阶段2:循环
在GDB中设置phase_2的断点,输入break phase_2。使用disassemble命令查看phase_2的汇编代码,输入disassemble phase_2。根据汇编代码的逻辑,推断出 phase_2的正确输入。
break phase_2
disassemble phase_2
这里程序调用 read_six_numbers,表示需要输入 6 个数字。通过cmpl $0x1,(%rsp)判断第一个数字必须为 1,后续每个数字必须是前一个数字的 2 倍。
所以结果为1 2 4 8 16 32。
1 2 4 8 16 32
图3 phase_2
* 阶段3:条件/分支
在GDB中设置phase_3的断点,输入break phase_3。使用disassemble命令查看phase_3的汇编代码,输入disassemble phase_3。根据汇编代码的逻辑,推断出 phase_3的正确输入。
break phase_3
disassemble phase_3
这里程序调用 sscanf,表示需要输入两个整数。输入格式为 "%d %d"。通过cmpl $0x7,0xc(%rsp)可知第一个整数必须小于等于 7,然后通过jmp *0x402470(,%rax,8)可知根据第一个整数的值,跳转到不同的地址。每个跳转地址对应一个特定的值。第二个整数必须等于跳转地址对应的值。
根据逻辑,输入应为两个整数,第一个整数为 0 到 7,第二个整数为对应的值。例如:1 311。
1 311
图4 phase_3
* 阶段4:递归调用和栈
在GDB中设置phase_4的断点,输入break phase_4。使用disassemble命令查看phase_4的汇编代码,输入disassemble phase_4。根据汇编代码的逻辑,推断出 phase_4的正确输入。
break phase_4
disassemble phase_4
这里程序调用 sscanf,表示需要输入两个整数。输入格式为 "%d %d"。通过cmpl $0xe,0x8(%rsp)可知第一个整数必须小于等于 14,调用 func4 函数,返回值必须为 0,第二个整数必须为 0。根据逻辑,输入应为两个整数,第一个整数为 0 到 14,第二个整数为 0。例如:7 0。
7 0
图5 phase_4
* 阶段5:指针
在GDB中设置phase_5的断点,输入break phase_5。使用disassemble命令查看phase_5的汇编代码,输入disassemble phase_5。根据汇编代码的逻辑,推断出 phase_5的正确输入。
break phase_5
disassemble phase_5
这里程序调用 string_length,表示需要输入一个长度为 6 的字符串。然后对输入的每个字符进行处理,取其低 4 位作为索引,从 0x4024b0 处查找对应的字符。随后将处理后的字符拼接成一个新字符串,而且新字符串必须等于 "flyers"。
根据逻辑,输入应为 6 个字符,经过处理后得到 "flyers"。例如:ionefg。
ionefg
图6 phase_5
* 阶段6:链表/指针/结构
在GDB中设置phase_6的断点,输入break phase_6。使用disassemble命令查看phase_6的汇编代码,输入disassemble phase_6。根据汇编代码的逻辑,推断出 phase_6的正确输入。
break phase_6
disassemble phase_6
这里程序调用 read_six_numbers,表示需要输入 6 个数字。每个数字必须唯一且介于 1 到 6 之间。对输入的数字进行处理,重新排列链表节点的顺序。检查链表节点是否按特定顺序排列。
根据逻辑,输入为 4 3 2 1 6 5。
4 3 2 1 6 5
图7 phase_6
在炸弹拆除任务中,还存在一个隐藏阶段。然而,只有在第四个阶段解决后添加特定的字符串后,该隐藏阶段才会出现。为了完成任务,需要使用gdb调试器和objdump反汇编炸弹的可执行文件,然后单步跟踪每个阶段的机器代码,理解每个汇编语言的行为或作用。这将帮助“推断”出拆除炸弹所需的目标字符串。为了调试,可以在每个阶段的开始代码前和引爆炸弹的函数前设置断点。
在终端输入objdump -d bomb > bomb.asm得到bomb的反汇编文件bomb.asm如下所示。
objdump -d bomb > bomb.asm
图8 bomb.asm
Gdb输入r或者run运行。
图9 phase_1运行结果
图10 phase_2运行结果
图11 phase_3运行结果
图12 phase_4运行结果
图13 phase_5运行结果
图14 phase_6运行结果
1.通过分析汇编代码,理解程序的实际逻辑,锻炼了逆向思维能力。
2.熟练使用 GDB 进行动态调试,设置断点、查看寄存器和内存,提升了调试技能。
3.通过观察程序行为和分析代码,逐步推断出每个阶段的正确输入,增强了逻辑推理能力。
4.在每个阶段都需要仔细分析,稍有不慎就会“爆炸”,培养了耐心和细致的工作态度。
写在文末的话:
本实验据我的图片步骤基本上可以做到一遍过,关键在于每个阶段的汇编代码的分析,从而得到破解结果,所以需要设置断点,对自己结果自信的可以直接在每次分析后输入(gdb)r 运行,输入结果,这样会更有挑战性。图片因为窗口大小原因并没有截出所有结果,重点以及相关调试大家可参考这篇博客:https://blog.youkuaiyun.com/qq_74326393/article/details/146356482?spm=1001.2014.3001.5502