CSAPP炸弹实验bomblab
作者:互联网
bomblab是计组里面我做的最认真的一个实验了
折腾汇编两三个小时最后过关的感觉很有成就感!
这边给上我做的时候的一些过程,可以给大家参考
main函数分析
首先是找到main函数,发现它调用了从phase_1到phase_6这六个函数。这应该就是每一关需要看懂的函数了。
第一关: 入门
找到phase_1
,代码如下:
- 当
eax
的值等于0时,就会调用炸弹爆炸的explode_bomb
函数
于是可见上一步函数strings_not_equal
返回后的eax
必须要为1,结合函数可以推断出是需要"strings equal"即字符串相等。
我们看到0x08048b53
的指令是将0x0804a1a4
的值准备给strings_not_equal
函数,于是我们在gdb中查看对应位置的值,得到
于是可以猜测第一关的所需输入即为You can Russia from land here in Alaska.
于是开始第一关的尝试。非常重要的一步是在<explode_bomb>
之前设置断点,找到该函数的入口地址是0x80490e6
,即执行break *0x80490e6
。然后输入命令run,进入程序,在输入提示的下一行输入You can Rusia from land here in Alska.
,终端显示“Phase 1 defused. How about the next one?”表示第一关顺利通过。
第二关: 差等差数列
找到phase_2
函数,代码如下:
按照上一关的联想,这一次的任务即为read_six_numbers
,即输入6个数字。因此可以猜测是当6个数字输入正确时通过。
- 我们看到当输入数字后,当esp+24的值小于0时引爆炸弹,否则跳址到
0x08048b98
。于是我们假设输入的第一个数为0。 - 下一步是
mov $0x1,%ebx
,然后将ebx
的值移入eax
,然后add 0x14(%esp,%ebx,4),%eax
后进入循环。cmp %eax,0x18(%esp,%ebx,4)
相等后,ebx
每次加一,当不等于6时回到0x08048ba3
的比较,当等于时返回函数。
翻译过来就是从第二个数开始依次是数1加1、数2加2、数3加3、数4加4和数5加5。
解答:当输入的第一个数为0时,6个数依次为0、1、3、6、10、15
第三关: switch跳转表
找到phase_3函数,代码如下:
可以看到0x08048bce
对应的操作为mov $0x804a3c3, %eax
,
于是查看对应地址的值,发现是"%d %d"
,于是可以得知是输入两个数字
首先我们看到当输入小于等于7时将值移到eax
,然后根据eax
的值进行跳址。可以看到这是一个典型switch跳转表,我们查看输入的第一个数为0时对应0x0804a200
地址的值
然后根据计算,得到最后的结果为十进制-616,测试成功过关
第四关: 递归
找到phase_4函数,代码如下:
类比上题,我们已经知道0x0804a3c3对应值为"%d %d"
,可以知道这题同样也是要输入2个数字。
cmp $0x1,%eax
和jle
可以得知输入第二个数需要大于1,cmp $0x4,%eax
和jle
可以知道输入第一个数需要小于等于4,因此输入的第二个数的范围2到4
我们看到函数中调用了func4函数,于是我们查看func4
phase_4
中传参的输入的第二个数存入func4
中esi
,传入参数0x5存入ebx
可以看到当esi
小于等于0时返回0,当esi
为1时返回ebx
内值。- 然后调用
func4
传参esi-1,并把esi-1存入eax
,然后将返回值与eax
相加后存入edi
,又给esi
减2后调用func4
,将返回值与edi
相加后存入ebx
,然后返回ebx
。可以推测出其代码为递推式
func4(n, a) = (n-1) + func4(n-1, a) + func4(n-2, a)
func4(1, a) = a
func4(0, a) = 0
phase_4
中即是计算func4(5,a)
,于是当输入的第二个数为2,第一个数就为24
第五关:ASCII
找到phase_5函数,代码如下:
- 由
string_length
和下一步cmp $0x6,%eax
可以得知是要输入一个长为6的字符串 - 然后是一个循环,首先将
edx
和eax
都置0,然后每次循环eax
加一,直到6时退出循环,每次循环中movsbl
和and $0xf,%ecx
即依次取出字符串中的每个字符的低四位。然后对于每个字符低四位值与0x0804a220
相加后的的地址里的值累加最后得到的值与0x41
比较。 - 可以看到对应的表
- 我们查看ASCII码表中a到z的低四位,可以得到0x1,0x2,…,0xf,0x0,0x1,…,0xa
由于需要相加得0x41
,凑配出0xa+5*0xb
,查表得alllll
,也就是这一关的过关密钥
第六关: 链表
找到phase_6函数,代码如下:
说实话当初看到这一大段代码,我脑壳都裂开,但还是耐下性子一行一行看了
这里把这一大段汇编代码分成4大部分
初始
从调用read_six_numbers
可见这题又是输入6个数字
第一部分
第一部分,里面有一个循环
eax
等于输入第esi
个数,给eax
减一- 当
eax
大于5就引爆炸弹,同时由于是无符号比较,即jbe
,因此当eax
值小于0时其会变成一个极大数,同样大于5。 - 将初始为1的
esi
与6比较,若相等则跳出循环进入第二部分。 - 通过
mov 0x10(%esp, %ebx, 4), %eax
和cmp %eax, 0xc(%esp, %esi, 4)
可以得出esi
不能等于ebx+1
。 ebx
加1后当ebx
小于等于5时回到4。否则跳回1。
这组循环非常的拗口,但是初步判断可以得知是限制输入的6个数的条件。
仔细分析后得知这一段的功能是判断输入的6个数都要小于等于6并大于等于1,并且不能存在两两相等。
第二部分
第二部分经过分析是当数组不越界时即对输入6个数进行操作。使每个数都对应其对于7的取反,也就是changed_input[i]=7-input[i]
。
由于有了前面的基础,这里就不进行逐行的汇编代码分析了。
第三部分
第三部分经过分析是在数组后的连续空间申请一个每个元素为8个字节的数组,记为tmp[6]
。
然后通过循环来实现tmp[i]=8*(changed_input[i]-1)+0x0804c13c
。若changed_input[i]<1
则tmp[i]=0x0804c13c
。
与第二部分的结果相结合,可以得到tmp[i]=8*(6-input[i])+0x0804c13c
。而这个0x0804c13c
非常可疑,于是我们查看对应位置的值
我们看到这个就能猜出大概。这是一个链表。并且可以得出链表的具体形式
于是就可以知道,这一部分的操作是将我们输入的数字与链表元素相对应,6对应1,5对应2以此类推。
第四部分
第四个部分显然就是具体操作了。经过分析是对其进行大小比较,前一个需要大于等于后一个。由此可以知道,我们所需要的是输入按照值大到小的顺序对链表进行排序,同时注意反向对应。
链表序号1>3>4>6>5>2
输入序号6 4 3 1 2 5
到这里,这个炸弹就被破解了,是吗?
发现隐藏关卡
我们观察main函数中,每个phase函数后面都跟着一个phase_defuse
函数,但在先前的分析中又不起作用,于是我们猜测这与隐藏关的触发有关。
从上往下看首先发现cmpl $0x6,0x804c3cc
,估计是看你是否已经通过了前面6关,没有的话就直接跳到结束部分。若已经通过6关,应该会往下执行。又有一句出现了立即数的movl $0x804a3c9,0x4(%esp)
, 用x/s 0x804a3c9
,得到 "%d %d %s"
。发现与phase3和phase4前面的输入相同都是2个数字
下面是movl $0x804a3d2,(%esp)
,同样地,得到"DrEvil"
,猜测便是激活所需的字符串
于是我们回去看到phase_3
和phase_4
都是调用的sscanf
函数,于是我们猜测是在phase_3
或phase_4
后面额外输入DrEvil
即可解锁
然后我们看到下面的指令有movl $0x0804a298,(%esp)
,我们查看对应地址的字符串,得到
可见至此隐藏关卡就解锁了
验证果然解锁了隐藏关卡
隐藏关: BST
找到secret_phase函数,代码如下:
- 首先
read_line
函数可见是读取一行,猜测是输入字符串。 - 然后调用
strtol
函数,传入参数刚刚的str
和0
,查阅资料得知strtol
是一个库函数,作用是分离数字和字符串,于是可以猜测输入一个整数和一个字符串。 - 然后他将
eax
减一,然后当eax
大于等于0x3e8
时引爆炸弹,可以猜出输入的数字需要小于等于0x3e8
。 - 然后调用了函数
fun7
,传入参数输入的数字和0x0804c088
- 调用完后直接比较返回值是否是4,如果不是就引爆
那么问题就很简单,就是要让fun7返回4
下面看fun7的汇编代码
- 我们看到首先判断传入第一个参数a是否为0,如果是的话就返回
0x124ffffffff
。 - 然后比较传入第二个参数b和第一个参数a所对应的地址的值是否相等。由此可见输入的第一个数应该是一个地址。
- 若第二个参数b较小,再次调用
fun7
,传入参数a+4,b。然后将fun7
的返回值乘2后返回该值。 - 当两个参数相等时返回0。
- 若b较大,则再次调用
fun7
,传入参数a+8,b。然后返回返回值的2倍加1。
我们在secret_phase里调用fun7传入的第一个参数为0x0804c088,查看其作为地址对应的值
所以可以得到我们一开始输入的并非数字加上字符串,而是只要求那个数字x,然后调用fun7
并传参&36和x。
由于需要返回4,在几种分支情况中,可以得到需要b<*a,即输入的数字小于36。
我们查看0x0804c088
及其后地址的对应值
可以看到这对应一个跳转表
画出其结构发现是一棵BST。
我们思考要得到4,方法只有(0*2+1)*2*2,也就是b<*a且b<*(a+4)且b>*(*(a+4)+4)且b==(*(*(a+4)+4)+8)
也就是对应BST从根结点开始左,左,右对应结点的值即0x7
于是输入0x7对应十进制7,顺利通过所有关卡!!!
实验结果
第一关:You can Russia from land here in Alaska.
第二关:0 1 3 6 10 15(不唯一)
第三关:0 -616(不唯一)
第四关:24 2(不唯一)
第五关:alllll(不唯一)
第六关:6 4 3 1 2 5
隐藏关:7
标签:CSAPP,函数,func4,bomblab,eax,炸弹,phase,ebx,输入 来源: https://blog.csdn.net/Broken__Ice/article/details/111145372