您的位置:首页 > 移动开发

CSAPP课程实验 bomb实验 拆炸弹实验 (2)

2015-05-19 20:39 288 查看
关卡1-3 phase1-3

正式进入关卡1,phase_1

首先是关卡1的汇编代码为:



可以看到前3句是非常熟悉的栈开辟代码,下面一起来看一下基本的栈调用过程的汇编代码:在gcc下是AT&T格式的,源操作数,目的操作数

Push %ebp 保存 ebp原有的值,防止被新调用的函数覆盖修改,在退出函数时通过pop ebp 恢。ebp每次调用新的函数,都要开辟新的栈,ebp将会到新的堆栈中 作为寻址的基址,所以每次要先push 将ebp原有的值压入堆栈中保存。

mov %esp,% ebp esp永远指向栈顶,是ebp指向当前栈的栈顶,作为基址,在开辟的堆栈局部空间中,进行寻址。来访问参数和局部变量

sub $0x18,%esp 栈向小地址生长,后压入的在小地址中,开辟一块栈局部空间

mov %ebp,% esp 栈清理

pop %ebp 恢复ebp寄存器

ret 0 ret指令将取出call指令压入的返回地址,跳转过去继续执行

首先找到炸弹爆炸点,可以看到是当调用strings_not_equal函数,当字符串不相等则就会爆炸,看到调用字符串比较函数之前传入的两个参数,第一个参数是放在0x8(%ebp)处,可以推断出应该是我们输入的字符串,第二个参数是在立即数$0x804a15c。这里判断函数传参数时,谁是第一个参数,看出栈顺序,栈是先入先出,先入的在小地址,先出来。此处在%esp处的就是第一个要出栈传递的第一个参数。分析出来之后,第一个关就是一个热身了,很简单,就是查看0x804a15c中的字符串的内容就是我们的通关密码。

在0x8048f6f处设置一个断点,然后查看到0x804a15c中的内容。



这里看到先设置了一个断点,然后在第一关的时候先随便输入一串字符串,然后进行调试,到预设的断点后,在进行查看。



这里可以看到通关的字符串内容就是We have to stand with our North Korean allies.

然后输入之后就可以简单轻松通过关卡1



关卡2:phase_2



首先来看汇编代码,

首先栈开辟代码:



然后看到一个非常显眼的函数调用:read_six_numbers 可以判断应该是输入6个数字。



Lea是加载有效地址的指令,就相当于c语言中的&,在这里结合栈是向小地址生长的,后进的放在小地址先被弹出,像在关卡1中分析的一样。在此处应该是将输入的第一个数字放在了-0x20(%ebp)的地方。接着往下看,



在这里第一个数跟0进行比较,也就是第一个数要为0才不会爆炸,另外-0x1c(%ebp)是输入的第二个数,则根据跳转判断可知要等于1。



再往下看,



首先第一句是取的我们输入的第三个数,放在ebx寄存器中作为基址,esi这里存的是六个数字之后的-0x8,也就是作为结束标志(六个数的存放是相对于ebp的偏移16进制为:-20,-1c,-18,-14,-10,-c)。esi出现一般会是循环或者数组中的变址,在此处考虑是循环的结束条件。第三句是取第二个数,第四句是将第一个数与第二个数相加,结果与第三个数相比较,在此处可以看到如果想不引爆,则第三个数=第一个数+第二个数。然后是从第三个数变成了第四个数,比较是否6个数结束了,没有则跳到0x8048d9b。可以看出来果然是一个循环,那么也就是输入的数字要满足的条件就是:an=an-1+an-2,推出了这个又从前面已知a1=0,a2=1,则六个数为:0
1 1 2 3 5 即为通关密码。第二关几乎不用调试,分析汇编代码就可以了。

循环写成c语言代码就相当于:





在这里我还去查看了一下-0x8(%ebp)中结束条件的内容:



第三关:phase_3

首先也是栈的开辟:



接下来出现了第一个引爆点,这个引爆点是说如果eax寄存器中的值小于1就会引爆,而eax寄存器中的值是调用sscanf函数的返回值,可以猜测该返回值可能是输入的数的个数。在看lea加载有效地址,猜测这里应该是输入两个数,分别从-0x10(%ebp)(输入的第二个数)和-0xc(%ebp)(输入的第一个数)加载进来并进行保存。



看到有个立即数$0x804a23e,用gdb调试看一下,在call sscanf处设置一个断点,进行查看。



在这里可以看到立即数中存的内容是两个%d,这个立即数中的内容应该是规定sscanf输入数的格式之类的相关描述,也就是初步证实了我们对于上面分析的输入的是两个数。





从这里可以看出来输入的第一个数要小于等于7



这里注意到有一个非常关键的jmp语句,如果你对汇编非常熟悉,这里一下就可以看出来这个是典型的switch case语句的汇编语句,对应的是一个跳转表,如果不熟悉也可以一步步的分析。现在假设你不知道。这里可以看出来跳转的地址跟你输入的第一个数有关,具体跳转到哪里,是要看0x804a1a0里面存的内容,继续设置断点在0x8048f41用gdb调试一下。



可以看到0x804a1a0存的跳转地址为0x8048f12,此处由于自己输入的是第一个数是1,所以跳转地址为(0x804a1a0+4)处存的地址



可知此时的跳转地址为:0x8048f19



此时先对eax寄存器赋初值为0,然后再进行如下一系列操作,得出eax寄存器的值为-641

其实可以如果你一开始知道它是一个switch case语句,而且知道跳转后都是对eax寄存器进行的算术操作,最后得出eax的值,可以在调试的时候输入不同的第一个数,然后直接读取eax寄存器最终的值,从而可以不必手工计算,





在这里看出输入第一个数要小于等于5,所以最后确定输入的第一个数的限制条件时小于等于5,然后cmp那句看出输入的第二个数要和每次根据第一个输入的case得到的eax的结果值相等。

那么该题的答案就不唯一了,可以输入0-5六个数,每次输入不同的数然后就可以直接查看它的case运算后的结果的eax寄存器的值得到第二个数。

最后得到的答案有:

0,147

1,-641

2,217

3,-534

4,0

5,-534

可以看出第三关考察的就是switch case跳转表。在此处一开始如果知道那一句关键性的



可以调试时利用命令:x/20xw 0x804a1a0 直接查看到每种case的跳转地址。



至此1-3关顺利通过:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: