逆向工程:bomb破解

Phase_1

 
17084259-078525ba663782ac.png
图片.png

使用objdump -d查看汇编代码,打开bomb.s文件后,从main函数开始看,会发现存在好几个以Phase为开头的函数,大概就是对应着我们需要闯关的关卡。首先我们从phase_1开始分析。

 
17084259-528526ff8e99eaa8.png
图片.png

这里就是phase_1的代码,我们可以发现80488db位置有一个call explode_bomb,这个应该就是引爆炸弹的位置。那前面的je指令应该就是跳过炸弹爆炸的条件。我们在phase_1处下断点。

 
17084259-4f1300f191d0086e.png
图片.png


程序停在了80488c0位置,单步执行。

 
17084259-c48ec61e98f0baab.png
图片.png


执行到这里时,即将调用strings_not_equal函数,可以看到栈顶的两个参数分别为我们随机输入的123和一个字符串。而调用的函数名含义为判断string是否相同(不同),那么猜测就是将我们的输入和内存中的某个字符串进行比较。call之前内存出现了字符串”With great power comes great responsibility.“试一试。

 
17084259-3db45f69b31cbfb6.png
图片.png

answer1:With great power comes great responsibility.

Phase_2

 
17084259-30015148f810e1c3.png
图片.png

首先和phase_1的步骤类似,在phase_2的位置下断点。

运行到phase_2时,先查看phase_2的汇编,发现80488f8位置有一个函数叫read_six_numbers,猜测这个炸弹的解法应该是输入合适的6个数字。先随便输入6个试试看:

 
17084259-2ddbc5f70936f17d.png
图片.png

直接运行到read_six_numbers函数,这个时候我们来看一下函数运行前后寄存器的值和内存中的值,理论上来说应该会将我们输入的这6个数 存入内存。

 
17084259-09a1bb44de4f2ab4.png
图片.png


发现在call之后立刻进行了第一次的cmp,比较的对象是esp+18所指的数字和3,那么这个地址指的东西是什么呢?发现是我们输入的第一个数,所以第一个数应该是3。

同理,第二个数应该是5。

前两位过了以后,我们跳转到了

 
17084259-3ab2f073c6a55af3.png
图片.png

这个地址,会发现执行了两部之后又跳走了,

 
17084259-77bb0b83b55849cd.png
图片.png


这里很明显,是取此时的两个数字进行相加,并与输入的第三个数字进行比较。由于是一个循环过程,我们猜测之后的过程应该也是这样的,所以我们尝试构造输入:

3 5 8 13 21 34 55

go next one!

Phase_3

首先查看一下汇编源码,主要观察有没有直接的调用函数。

call 8048600 __isoc99_sscanf@plt

会发现有一条这样的指令在Phase_3的开头就出现了,我们直接跑到这里看看发生了什么。

首先是$EAX被修改了。之后紧跟了一个cmp语句,所以这里应该就是第一个爆炸点。

我一开始输入了2个随机的数,不知道怎么就过了。。。我们就继续往下吧

 
17084259-e9d9a2a4b8b53ada.png
图片.png

然后就将一个数与7比较,如果比7大就boom,那我输入的是1,就继续往下。

 
17084259-2467552f790ef254.png
图片.png


从这里开始,将eax置为0,开始了漫长的计算。。。

我们直接去看结果吧...

 
17084259-d4ca093e1ba3f5c6.png
图片.png

好像变成了这个值,这个是多少呢?

0xfffffe39 = 1111 1111 1111 1111 1111 1110 0011 1001

由于第一步是将0减去一个正数,所以我们把这个结果当作有符号的整数处理。

0xfffffe39 = -455

继续往下运行发现,就是把这个数字和你输入的第二个值比较。

那么我们的输入就来了!

 
17084259-5bf32773a0368b2a.png
图片.png

Phase_4

 
17084259-94e962cea6326aa9.png
图片.png

发现了一个不一样的调用就是func4,我们先解决前面的问题。

在phase_4位置下断点。同时,我们发现了跟phase_3相同的函数,运行到此处发现它提示我们要输入2个整数。随便输入两个好了:

1 2

就这两个吧。调用之后立刻比较了eax和2的大小,我们的输入通过了。

接下来将eax-2后与2比较大小,要想不爆炸,eax就应该<=4。那么eax是什么呢,其实就是我们输入的第二个整数。

根据__isoc99_sscanf@plt函数和之前的炸弹限制,我们可以把第二个输入确定为4。此时,在func4的后一句下一个断点,将第二个输入指定为4后,随便选一个数作为第一个输入,查看eax的值。

 
17084259-0f74d1ce8e594626.png
图片.png

发现是0x30,换算一下就是48,所以我们的输入应该是:

48 4

Phase_5

做完实验发现,这涉及到了一个字典。。。

 
17084259-f23cb97f256ab624.png
图片.png

结果就是这样,但其实应该还有别的答案的。

 
17084259-48d6296b53e119fd.png
图片.png


汇编中其实是把6位的字符串输入当作一个偏移量,来对内存中某位置已经存在的字符串进行偏移。我的方法是,直接攻击出整个字典,也就是说输入a会得到什么,b会得到什么...

a b c d e f g h i j k l m n o p q r s t u v w x y z
a d u i e r s n f o t v b y l m a d u i e r s n f o

整个字典如上,问题自然就 迎刃而解了。

对了,还有一个问题是

 
17084259-39bb896afc8859be.png
图片.png

从这里可以判断出,输入应该是一个6位的字符串类型。

answer:reldog

Phase_6

来到第六关,在查看了汇编代码之后发现代码比较长,这里我需要使用辅助工具来帮助我理解,使用的是IDA pro。直接将文件拖进IDA后使用伪源码功能(F5)查看源码,这里的源码在命名和指针方面也不是很清晰,主要是用来帮助理解汇编的。

 
17084259-79f800378740b6ba.png
图片.png

首先是定义了很多变量,备注里标注的是这些变量对应的内存/寄存器。

 
17084259-8e624eef2d62ec8d.png
图片.png


接下来这一段,从代码本身看起来有些别扭,但大致看了一下之后进行动态调试就会发现,他是在规定输入的6个数字的范围。既不能相等也需要在1-6的整数范围内。所以将问题改为1-6的六个整数以某种方式输入,输入正确就可以解除炸弹。

 
17084259-ad9c48e8d8fe5679.png
图片.png

这一段就是这六个数字究竟应该怎么排列的代码了。我们直接找到explode_bomb的位置,发现他是在比较result和v7所指的内容,再继续往上追踪发现,v7在循环开始时被v15赋值。那么v15又是什么呢?

*(&v15 + v2++) = (int)v4;

我们会看到这一段。因为输入无非就是1 2 3 4 5 6六个数字,我们一个一个带进去试试看。

当输入为1的时候,v15指向的是node1 + v2,v2取决于循环的次数。

当输入为2的时候,v15指向的是node1[2]+v2,虽然我这里的写法不是很规范,但大致意思就是从node1的位置向后寻址,并读数。

继续往后分析也是类似的,那么我们就会猜测出一个这样的框架。

 
17084259-67bcfcf4252d243c.png
图片.png

最终决定输入的,应该是最右边那个值的排序顺序。

我选择查看一下node1-node6的所有值:

node1:0x0000000000000010000011b

node2:0x804b11c0000000200000069

node3:0x804b12800000003000002a6

node4:0x804b1340000000400000105

node5:0x804b1400000000500000320

node6:0x804b14c0000000600000178

会发现的是,node其实是一个链表指针的结构,前几位是下一个node对应的地址,后几位标注了node的编号,最后三位应该就是对应的值。

我们把node进行排序,根据最后三位的大小来试一试:

2<4<1<6<3<5

answer:2 4 1 6 3 5

 
17084259-fba53721e074563a.png
图片.png

成功!

Secret_phase

做到这里,我在IDA中发现了一个叫secret_phase的调用函数。根据关卡的命名,这个应该是一个隐藏关卡,可是按照之前的输入,并没有提示我进入。那到底该怎么进呢?

我们阅读之前的关卡伪源码会发现,还有一个调用的函数叫做phase_defused,阅读源码后发现应该是在第四关的时候,如果你的输入在多一个合适的字符串的话,就会在最后一关之后跳转到隐藏关卡。

 
17084259-fbf6e500b7d80e9e.png
图片.png

好像就应该是DrEvil

试试看?

 
17084259-dca10ee168501315.png
图片.png

可以看到我们加了一个输入,最后就提示我进入了隐藏关卡了!

这里我们去查看一下隐藏关卡的拆弹方法...

 
17084259-c43de87b849722ad.png
图片.png

可以看到有两个引爆条件,一个是v1>1001,另一个是fun7的返回值!=3。

v1比较好理解,他是read_line函数的返回值,也许只是将输入的字符串强制转化为int型并与1001比较,所以输入应该是1-1001的正整数。

关键是我们需要理解一下fun7的构造。

 
17084259-6f481256181ea5d8.png
图片.png

可以发现是一个递归函数。从secret_phase我们可以发现,我们需要的result应该是3,否则就会爆炸。

分析之后发现,这个fun7要想获得结果为3,只有一种情况:

2 * (2 * 0 + 1) + 1

含义是,第一次进入时,*a < b;第二次 *(a + 8) < b;第三次 *(a+16) == b。

我们会发现,secret_phase在调用fun7的时候传入的参数为(int&n1,v1),v1就是我们的输入,我们可以在IDA中双击&n1,查看一下对应地址的结构。
![图片.png](https://upload-images.jianshu.io/upload_images/17084259-0bee96264e68b371.png?imageMogr2/auto-orient
就在这个位置开始,从fun7中可以看到有两种判别方法,一种是 *(a+4) 一种是 *(a+8),这里对应的也是一样。所以我们可以根据

第一次进入时,*a < b;第二次 *(a + 8) < b;第三次 *(a+16) == b

这个判断,从地址中寻找数字。

结论如下:

input > 0x24; input >0x32; input == 0x6b == 107/strip%7CimageView2/2/w/1240)

 
17084259-ad932a34e730990e.png
图片.png

终于!我们保卫了国家,拆除了炸弹!!!

猜你喜欢

转载自blog.csdn.net/HizT_1999/article/details/101462019