Defusing a Binary Bomb

Lab1 拆除炸弹

一 问题描述

        本实验仅给出了一个可执行的二进制文件,该程序共有6处需要从终端进行输入,即该实验的6个问题,只有输入程序预期的数据,才能通过实验。

二 解题思路

        使用反编译objdump工具将二进制文件反编译成AT&T格式的汇编代码,阅读并分析汇编代码,同时结合gdb查看内存、寄存器等,确定输入数据。

1、  phase_1

phase_1函数部分的汇编代码如下所示。从地址804897c处的call指令调用可以发现,该程序从终端输入一段字符串在未进行任何解析的情况下,直接进行了对比操作,因此可以猜测该输入为一行字符串。

Defusing a Binary Bomb

继续观察该程序可以发现,该程序在进行对比之前在进行了一次push操作,并且该操作的地址为静态地址,猜测该地址存储的内容应该是一个全局变量,在程序编译的过程中就分配的地址。很明显,该静态地址将作为参数参与到string_not_equal函数的对比过程中,我们使用gdb设置断点,查看该静态地址的内容。

Defusing a Binary Bomb

        该地址内果然存放着一个字符串,“Now this is the 1st training here.”该字符串长得就很有答案的气质。直接拿该字符串做测试,果然是本题的答案。

Defusing a Binary Bomb

2、  phase_2

有了上一题的经验,本题我们可以直入主题,查看call指令,在80489a6处调用的call指令使程序跳到函数read_six_numbers处执行,可以猜测本次输入数据是6个数字。既然call指令需要读入6整数,那么这6个变量应该是临时变量,存储在栈区,其地址在call指令上边通知lea指令加载到%eax作为参数传入函数read_six_numbers中。

Defusing a Binary Bomb

接下来是一个循环操作,依次取前3个数据与后面三个数据进行比较,若不相等则立即引爆炸弹,若全部相等则通过测试。即这6个数字只要满足num1=num4,num2=num5,num3=num6就可以通过实验。这样的数据有很多,可以是3个数字的重复,也可以是6个完全相同的数字。测试数据:123123,通过测试。

Defusing a Binary Bomb

3、  phase_3

本题在数据的读取上与上面两道题的操作略有不同,直接用了sscanf函数读的数据,那么sscanf函数一定会有一个静态字符串,标识着待输入数据的类型。显然该字符串在地址0x8049057处,查看内存发现该字符创为“%d %d”,由此可推断本题的输入为两个整形数字,这两个整数的存放地址分别由lea指令与push指令压入栈区,即-0x8(%ebp)、-0x4(%ebp)。

接下来对输入的第一个数据进行了判断,即输入数据必须在1-7之间,小于0或者大于7的数据都将直接触发炸弹。

然后是一个应该是一个switch语句,分别对8(1-7)个允许的不同输入数据进行映射,得到与第一个数字相对应的结果,最后该结果与第二个数据做比较,若相等,则完成测试,否则触发炸弹。

问题到这里就变得明了,观察8048a3c下面的语句可以发现,映射结果直接写在了代码当中,总结如下:

a

Fun4(int a)

0

61

1

439

2

164

3

443

4

346

5

639

6

704

7

153

        则本题共有8组正确答案,实验证明均可通过测试。样例如下。

Defusing a Binary Bomb

Defusing a Binary Bomb

4、  phase_4

有了前面几道题的经验,可以很快确定本题的输入为一个整形数据,存放地址为【-0x8(%ebp)】。

本题属于上一题的升级版,上一题中的所有映射结果都清楚的写在代码当中,而本题是对这个输入数据进行一系列运算,即该数据作为fun4函数的参数,返回值作为映射结果,得到的映射结果与0x1cb91作比较,相等则完成测试,否则触发炸弹。

那么本题的重点在于fun4(a)=0x1cb91,我们的任务是研究fun4做了怎样的运算,从而推算出a的值。

很不幸,fun4在函数内部调用了自身,这是一个递归函数,我没有仔细研究fun4做了些什么,直接暴力测试了一组数据,从0开始测试,然后1、2、3…当测试到6的时候,通过了,通关gdb观察内存发现,fun4(6)果然等于0x1cb91。测试结果如下。

Defusing a Binary Bomb

Defusing a Binary Bomb

Defusing a Binary Bomb

Defusing a Binary Bomb

5、  phase_5

本题在中首先计算了输入字符串的长度,然后用该值与0x6做比较,显然,本题的输入数据为长度为6的字符串。

接下来是一个循环,依次获取每个字符对应的ascall码,然后对该ascall码与0xf作位与,即对16取余,该余数作为数组array的下标i,取出array[i]的值,并依次累加。

累加的结果与0x25(37)做比较,相等则通过测试,否则触发炸弹。

那么本题的关键在于查找array数组的值,从中选择6个(可以重复),保证这6个数相等于37。使用gdb观察array数组值为。

Index

Array

0

2

1

10

2

6

3

1

4

12

5

16

6

9

7

3

        从中选择6个数相加为37如10 + 10 + 12+ 2 + 2 + 1 = 37。然后寻找ascll码低四位十进制值分别为10、10、12、2、2、1字符,查找ascll码表发现有很多字符满足这样的要求,我们选择最简单的一组数字0-9,它们的ascall码低4位十进制数刚好对应0-9,满足需求。

则该答案为114337,通过测试。

Defusing a Binary Bomb

        显然,本题的答案不是唯一的,凡是满足要求的字符串都可以成为答案,如547307。

Defusing a Binary Bomb

Defusing a Binary Bomb

6、  phase_6

本题的汇编代码特别的长,需要分块研究。

首先程序读入6个整数,存放位置为【-0x38(%ebp)】,然后一组循环对这6个整数进行大小测试,所有数组必须大于等于1且小于等于6。

然后对这6个数据进行一组和第2、3题类似的映射操作,并使用一组双重循环对映射结果进行比较,后面的数必须小于前面的数,即从大到小的排序。

现在问题的关键在于程序进行了怎样的映射计算,程序只涉及到6个数据,果断暴力求解。使用gdb在0x8048c9f处设置断点,0-6依次作为第一个数据,观察映射结果。如下。

a

Result

1

0xce

2

0x3c8

3

0x106

4

0x211

5

0x276

6

0x158

得到1-6分别对应的数据后,对该数据按照从大到小的排序,其对应编号为2、5、4、6、3、1,该组编号即为本题唯一答案。通过测试。

Defusing a Binary Bomb

Defusing a Binary Bomb

Defusing a Binary Bomb

Defusing a Binary Bomb

Defusing a Binary Bomb

Defusing a Binary Bomb

Defusing a Binary Bomb

三 实验结果

        将本题所有答案放在一个文件anx.txt中,如下所示。

Defusing a Binary Bomb

测试通过结果如下。

Defusing a Binary Bomb