二进制炸弹实验binarybomb 拆弹

2021-08-18 14:31:41 浏览数 (1)

写在前面

这个实验是系统级编程的课程实验,非常有意思,给定一个可执行文件bomb.exe,这个程序打开之后需要用户输入一些东西,只有输入指定的字符串或者数字才能到达下一个步骤,一共有7个步骤,如果输入错误,屏幕会显示boom!!并退出程序,意味着你引爆了这个炸弹。你需要反汇编这个可执行文件来找到拆弹的线索。老师给我们提供了两种方法:使用GDB objdump来反汇编;使用IDA 来反汇编

做本实验采用的工具是IDA Pro6.6

Phase 1:

打开IDA,反汇编bomb.exe。可以看到如图

看到汇编代码,这里有一句string 内容是”Public speaking is very easy.”,然后将它放在ESP 4的位置,再将输入数据放在ESP的位置,调用_strings_not_equal方法,所以我们可以确定要输入的字符串是Public speaking is very easy. Phase 1解决。

Phase 2

打开IDA,选择phase2 的函数,按F4,可以看到反汇编得到的C语言代码,这代码是根据汇编函数反汇编得到的,跟原来的代码有很大差别,不过还是可以从中窥探出一些踪迹。

其中,核心代码是这段,也就是红色框框起来的代码:

很明显v5是一个计数器变量,用来遍历6个数,从蓝色框的结构我们可以猜测这是一个数组,int型的,因此if语句换个说法就是(i 1)*a[i-1]!=a[i],所以拆除炸弹所需要的6个数字应该满足(i 1)*a[i-1]!=a[i] ,也就是 2a[0]=a[1] 3a[1]=a[2] 4a[2]=a[3] 5a[3]=a[4] 6a[4]=a[5] 如果第一个数是1,那么这6个数是:1 2 6 24 120 720 Phase 2 解决。

Phase 3

打开IDA,选中phase 3的函数,按f4,我们可以得到phase 3的代码

可以看到这是一堆switch case代码 看到这句语句

可以得知我们应该输入两个整数,一个字符 选中右边的代码块可以对应到左边的汇编指令,我发现第一个整数对应的内存是[ebp-0x18] 字符对应的内存是[ebp-0x11],第二个整数对应的是[ebp-0x10].

对第一个整数进行判断

每个相应的case中都会给v9赋值,我们看汇编指令可以发现v9其实是[ebp-0x9],看到代码后边可以发现,是要将[ebp-0x11]也就是字符的值赋给eax54这个变量,然后再取低4位与[ebp-0x11]比较。

发现除了 2 3 7 之外其他的数都是十六进制的,并且7没有break,会出现问题,在这里我选2,那v9的值就是98,通过查ASCII码表可以知道98是小写字母b,那第一第二个参数就出来了,然后第三个参数,v29,如果不等于0xfb就会引爆炸弹,那0xfb是十进制的755,所以我们第三个参数就是755。所以我们应该输入2 b 755 。Phase 3解决。

Phase 4

打开IDA,选择phase 4,按f4反汇编成C语言代码,可以看到如图

通过查看程序可以知道,phase 4的主体代码很简单,就是让用户输入一个整数,调用一个func4(),如果返回值不是55就引爆炸弹。 所以我们看一下func4()。

所以我们一层层推,可知只有当参数是9的时候递归的结果是55,所以我们应该输入9,phase 4 解决。

Phase 5

打开IDA 选择phase 5 按住f4反汇编成c语言 可以看到如下图

通过程序我们可以看到,我们需要输入6个数

看到这句关键代码,eax6是一个Int型,而且下面的句子也出现了eax6,这时候光看这份不完整的代码就不够了,看一下汇编代码

可以看到,代码的意思是将数组_array_2464的第[eax]个字节存放到eax里面,再拼接起来,我们可以看到这个数组是一个字符串数组,在看到后面还有一个数组,将拼接的结果和aGiants数组压栈之后调用了_strings_not_equal函数,所以我们可以断定拆这个炸弹的方法就是从_array_2464这个数组中提取“giants”,那位置是15 0 5 11 13 1 。化成十六进制就是0xf 0x0 0x5 0xb 0xd 0x1.

但是要注意到它的偏移量不是直接通过输入数字获得的。它是通过每个输入的数取低4位,再与0xf进行与运算,结果是什么呢,当然就是输入的数的最后一个字节。

我知道内存中存放数值是变成16进制的,00 00 00 00,它取的是第一个00的后一个0的位置,所以我们输入了之后,我们希望内存是这个样子: 0f 00 00 00 00 00 00 00 05 00 00 00 0b 00 00 00 0d 00 00 00 01 00 00 00 当然0的位置随便是什么都可以,所以我选3f 30 35 3b 3d 31,查找ASCII码表可以知道它们分别是?05;=1 ,Phase 5 解决

Phase 6

打开IDA 选择phase 6 按住f4反汇编成c语言 可以看到如下图

根据炸弹会爆炸的情况分成3段:

第一段的意思是每个数字不能大于6,第二段的意思是这6个组成一个数组的话a[i]不能等于a[i 1],第三段的意思暂时不需要管,后面会说

我们看到struct s1应该是一个链表,f8指向下一个节点,s0应该是一个节点 从汇编代码和c代码中看不出什么,所以在phase 6的开头设一个断点,调试一下看看。 我们输入1 2 3 4 5 6,很显然这个输入是满足前面两个条件的,所以我们直接看最后一个条件,这里我们看到我输入的6个数,生成了6个节点

看到内存相应的位置 红色框的是我的链表,蓝色框的是每一个节点,我们可以清楚的看到节点的结构,第一行是一个数值,跟第二行有关,第二行是每个输入的数字,第三行是下一个节点的地址

继续执行到cmp语句,查看当前比较的两个参数,eax和edx

刚好是第一第二个节点的内存中第一行的值 如果要满足条件的话,前一个值要大于等于后一个值,由内存中的值可以得到,每个数字对应生成的该值为 6->01b0 5->00d4 4->03e5 3->012d 2->02d5 1->00fd 所以正确的排序应该是4 2 6 3 1 5 这里说一下为什么要用1到6来试,因为之前有说过这六个数不能大于6,而且如果他们小于0的话,在汇编代码中有一个eax-1的操作,0x00000000-1会变成0xFFFFFFFE,这也是不对的。 Phase 6解决

至此,炸弹拆除。

Secret phase:

但是我们可以发现在代码的字符串集中有这么一句话:

所以这个炸弹有一个secret phase 怎么进入这个secret phase呢 我在phase 6 的方法的最后设置了一个断点,发现当拆除phase 6之后会进入一个_phase_defused的函数

可以发现进入secret phase的条件有两个:一个是输入的字符串数目达到6,也就是拆除所有phase之后,另一个是从一个内存中读入一个整数和一个字符串,这个字符串要跟austinpower一样。 我们设置断点,进行调试,发现当它调用_sscanf函数的时候,它的参数是一个存放在地址00408190的内容

我点进去看这个地址,发现这个地址存放的是phase4的输入值,那里本来只有一个9

但是要进入secret phase呢就要再输入一个austinpower的字符串。

那我在拆炸弹的时候,在拆phase4的时候多输入一个austinpower,然后就成功进入了secret phase 我们看到secret phase的代码

这里有一个func7的函数,我们再来看一下func7

它定义了一个结构体,初步看应该是一个树的结构,再结合下面代码它访问的两个不同成员,可以确定是一棵二叉树。 那二叉树的值在哪呢?

我们可以看这个ebp-r,r的值是8,所以看到相应的位置

里面的值也是一个地址,双击到这个地址去看

这正好就是二叉树的内容。我根据内容把这棵树画出来是这样子:

好了,再来看一下func7的代码

调用func7会传递两个参数:二叉树的根节点和一个整数 如果这个数小于当前节点,就往一个子节点遍历,并且eax3=eax42 1 如果大于当前节点,就往另一个子节点遍历,并且eax3=eax52 如果相等则返回0。 而secret phase的拆弹条件是这个函数的返回值要等于7,所以我们逆推一下,只有满足7=3 3 1,3=1 1 1,1=0 0 1的时候才能说得通,所以我们可以确定这个二叉树的遍历顺序是一直往这个数小于当前节点的方向遍历,也就是往右边子节点遍历,要使二叉树往右边遍历,那这个整数就只能是1001. 到此,二进制炸弹完美解决。

0 人点赞