Bomblab

Posted zhibin123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bomblab相关的知识,希望对你有一定的参考价值。

这个实验曾经做过

这次又做了一遍,对之前的过程作了补充

binary bomb

一、实验目的

增强对程序机器级表示、汇编语言、调试器和逆向工程等理解。

二、实验要求

      1熟练使用gdb调试器和objdump;

2单步跟踪调试每一阶段的机器代码;

3理解汇编语言代码的行为或作用;

4“推断”拆除炸弹所需的目标字符串。

5在各阶段的开始代码前和引爆炸弹函数前设置断点,便于调试。

三、实验内容

准备:

使用objdump –d bomb > asm.txt命令,将bomb程序逆成汇编代码,分析汇编代码。

Phase_1:

       汇编代码如图

 

代码分析:

 

这是一个字符串比较,所以应该是和内存中的已有内容比较。

有一个内存地址,我们去看一下内存0x804a124的内容

 

找到字符串,输入之后

 

通过。

 

phase_2:

 

截图有点小。。

代码分析:

push   %esi

push   %ebx

sub    $0x34,%esp

lea    0x18(%esp),%eax

mov    %eax,0x4(%esp)

mov    0x40(%esp),%eax

mov    %eax,(%esp)

call   804911c <read_six_numbers>  ;读入6个数

cmpl   $0x0,0x18(%esp)             ;第一个数和0比较

jne    8048bdb <phase_2+0x27> ;如果不等于0就爆炸,所以第一个为0

cmpl   $0x1,0x1c(%esp)  ;第二个数和1比较

je     8048bfa <phase_2+0x46> ;如果等于1就跳走了,不等于就爆炸了

call   80490f5 <explode_bomb> ;爆炸

jmp    8048bfa <phase_2+0x46>

mov    -0x8(%ebx),%eax  ;eax = a[i-2] 存上上个数

add    -0x4(%ebx),%eax      ;eax = a[i - 2] + a[i - 1] 存上上个数与

cmp    %eax,(%ebx)  ;相当于把eax赋给ebx,也就是把当前位置的相邻

je     8048bf1 <phase_2+0x3d> ;ebx必须和eax相等,否则就爆炸

call   80490f5 <explode_bomb>

add    $0x4,%ebx  ;ebx+4,ebx指向了新的位置

cmp    %esi,%ebx ;ebx是否和ebx+30相等,不等就跳回到8048be2,循环

jne    8048be2 <phase_2+0x2e>

jmp    8048c04 <phase_2+0x50>;相等,结束

lea    0x20(%esp),%ebx  ;ebx指向新的地址

lea    0x30(%esp),%esi  ;esi始终存的是地址esp+30

jmp    8048be2 <phase_2+0x2e>

 

add    $0x34,%esp

pop    %ebx

pop    %esi

ret   

根据规律得出最后是a[i] = a[i - 2] + a[i - 1],而且第一个数是0,第二个数是1,递推出

 0 1 1 2 3 5

输入

 

通过。

Phase_3:

截取部分代码:

 

 

代码分析:

sub    $0x2c,%esp

lea    0x1c(%esp),%eax

mov    %eax,0xc(%esp)

lea    0x18(%esp),%eax

mov    %eax,0x8(%esp)

movl   $0x804a2ef,0x4(%esp)

 

mov    0x30(%esp),%eax

mov    %eax,(%esp)

call   8048860 <[email protected]> ; 输入

cmp    $0x1,%eax                     ;至少输入2个数

jg     8048c3b <phase_3+0x31> ;否则就爆炸

call   80490f5 <explode_bomb>

 

cmpl   $0x7,0x18(%esp);  <=7

ja     8048c7e <phase_3+0x74> ;如果第一个操作数大于7 ,就爆炸

 

mov    0x18(%esp),%eax

jmp    *0x804a180(,%eax,4) ;后面有截图,可以看到,在这个地址处存放着一些地址,根据输入的eax的值,跳到相应位置

;下面是8种情况  后面依次根据第一个数的内容跳到相应位置

 

mov    $0x90,%eax ;第一个数是0,跳到这里,将0x90放到eax中

jmp    8048c8f <phase_3+0x85>

 

mov    $0x166,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x160,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x1e2,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x2c5,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x2e0,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x3d8,%eax

jmp    8048c8f <phase_3+0x85>

 

call   80490f5 <explode_bomb>

 

mov    $0x0,%eax

jmp    8048c8f <phase_3+0x85>

 

mov    $0x15d,%eax

;---------------------------------------------------------所有的条件最后都汇总到这里,判断第二个数

cmp    0x1c(%esp),%eax ;将输入的第二个数字和从对应地址赋值的数比较,不相等就爆炸

je     8048c9a <phase_3+0x90>

call   80490f5 <explode_bomb>

add    $0x2c,%esp

ret 

 

用gdb看看内存里位置0x804a180位置处的内容是:

 

里面存的都是代码的地址,也就是要跳的位置

这个是条件判断,根据输入的第一个数,看第二个数是不是和程序的赋给的内容一样。

所以一共有8种情况,任意输入一种即可

如果第一个数是0,跳到0x8048c4d位置,把0x90给了eax,所以第二个就是0x90,也就是十进制的144

输入 0 144

 

通过

 

Phase_4:

这个是一个递归

代码截图:

 

 

代码分析:

sub    $0x2c,%esp

lea    0x1c(%esp),%eax

mov    %eax,0xc(%esp)

lea    0x18(%esp),%eax

mov    %eax,0x8(%esp)

movl   $0x804a2ef,0x4(%esp)

 

mov    0x30(%esp),%eax

mov    %eax,(%esp)

call   8048860 <[email protected]>;输入

 

cmp    $0x2,%eax ;输入两个数,不是的话就爆炸

jne    8048d2e <phase_4+0x33>

 

cmpl   $0xe,0x18(%esp)  ;第一个数小于等于14,否则爆炸

jbe    8048d33 <phase_4+0x38>

call   80490f5 <explode_bomb>

 

movl   $0xe,0x8(%esp) ;旧[esp+8] = e

 

movl   $0x0,0x4(%esp) ;旧[esp+4] = 0

 

mov    0x18(%esp),%eax

mov    %eax,(%esp)

call   8048c9e <func4> ;调用func4

 

cmp    $0xb,%eax  ;func4返回的一定是11,否则爆炸

jne    8048d5b <phase_4+0x60>

cmpl   $0xb,0x1c(%esp) ;第二个数一定是11,否则就爆炸

je     8048d60 <phase_4+0x65>

call   80490f5 <explode_bomb>

add    $0x2c,%esp

ret   

 

phase_4函数其中还调用了一个函数func4(),func4()返回的值是11,我们进行推断可以得出输入时0 11或者1 11

分析着很麻烦,发现第二个数必须是0xb,一定是11,前面有第一个数必须小于15,一共没几个情况,一个个试一下呗!发现很幸运的输入 0 11就过了!

 

 

Phase5:

代码如下:

 

代码分析:

08048d64 <phase_5>:

 8048d64:      53                        push   %ebx

 8048d65:      83 ec 18                    sub    $0x18,%esp

 8048d68:      8b 5c 24 20                 mov    0x20(%esp),%ebx

 8048d6c:      89 1c 24                    mov    %ebx,(%esp)

 8048d6f:       e8 57 02 00 00       call   8048fcb <string_length>

 

 8048d74:      83 f8 06             cmp    $0x6,%eax ;输入字符串长度一定是6,否则爆炸

 8048d77:      74 05                      je     8048d7e <phase_5+0x1a>

 8048d79:      e8 77 03 00 00       call   80490f5 <explode_bomb>

 

 8048d7e:      ba 00 00 00 00       mov    $0x0,%edx  ;赋初值

 8048d83:      b8 00 00 00 00       mov    $0x0,%eax  ;赋初值

 

 8048d88:      0f b6 0c 03          movzbl (%ebx,%eax,1),%ecx                        ;0扩展,

; ecx = ebx + eax

 8048d8c:      83 e1 0f             and    $0xf,%ecx              

                                                         ;ecx = ecx & 0xf ,和0xf按位与,控制在0~15之间

 8048d8f:       03 14 8d a0 a1 04 08   add    0x804a1a0(,%ecx,4),%edx ;     

;在内存中相应位置取出数字加到edx       中

 8048d96:      83 c0 01                    add    $0x1,%eax

                                   ;eax自加

 8048d99:      83 f8 06             cmp    $0x6,%eax                                         

                                                         ;eax和6比较,一共循环6次

 8048d9c:      75 ea                      jne    8048d88 <phase_5+0x24>

 

 8048d9e:      83 fa 2d                    cmp    $0x2d,%edx 

                                                 ;最后的edx中一定是0x2d,我们要找到这样的组合即可

 8048da1:      74 05                      je     8048da8 <phase_5+0x44>

 8048da3:      e8 4d 03 00 00       call   80490f5 <explode_bomb>

 8048da8:      83 c4 18                    add    $0x18,%esp

 8048dab:      5b                        pop    %ebx

 8048dac:      c3                        ret   

经过分析得出,我们要输入6个字符,然后对每个字符对16取模之后得到[0,15]的数,推测内存里应该有16个数,代码里还有一个内存地址,把取模后的数作为偏移地址,在内存中找到相应的值,加到一起,和是45就可以。

看一下内存地址有啥

 

前16个看起来靠谱,和我们得到的结论一样。

现在只需要凑出6个数之和是45就行,凑个777888,然后在内存里这个数组中看一下,有7和8,下标分别是9和13,然后这6个数都是对16取模之后的下标,让他们几个都同时加32,得到41 41 41 45 45 45,对应的ascii表中的字符就是 )))--- ,输入后通过

 

同理,然后还可以加32 + 16,得到 57 57 57 61 61 61,对应的ascii码表中的字符就是===999,输入后:

 

通过

Phase_6:

 

 

 

 

代码分析:

输入6个数后,先进行了两个判断:1、判断是否都是在[1,6]上的数   2、判断有没有重复

 

              ;判断是否在[1,6]内

 8048dcf:       83 e8 01                   sub    $0x1,%eax                       ;eax--

 8048dd2:      83 f8 05             cmp    $0x5,%eax                            ;如果eax是小于等于0的数,减一后和5无符号比较,是大于5的;

                                                                                                                       ;如果eax是大于6的数,减一后还是大于5;

                                                                                                                      ;所以 输入的数字一定要  在区间 [ 1 , 6 ]  内  

 8048dd5:      76 05                      jbe    8048ddc <phase_6+0x2f>      ;无符号比较<=

 8048dd7:      e8 19 03 00 00       call   80490f5 <explode_bomb>

 

 8048ddc:      83 c6 01                    add    $0x1,%esi                       ;esi作为偏移

 8048ddf:       83 fe 06             cmp    $0x6,%esi                      ;一共循环6次

 

 8048de2:      75 07                      jne    8048deb <phase_6+0x3e>

 8048de4:      bb 00 00 00 00       mov    $0x0,%ebx                         ;6次循环结束

 8048de9:      eb 38                      jmp    8048e23 <phase_6+0x76>         ;跳出循环

              ;判断是都有重复的

 8048deb:      89 f3                       mov    %esi,%ebx

 8048ded:      8b 44 9c 10                 mov    0x10(%esp,%ebx,4),%eax   ;根据ebx取出一个输入的数

 8048df1:       39 44 b4 0c                 cmp    %eax,0xc(%esp,%esi,4)     ;取出的每个数都依次和其他的每个数字比较

 8048df5:       75 05                      jne    8048dfc <phase_6+0x4f>

 8048df7:       e8 f9 02 00 00       call   80490f5 <explode_bomb>    ;每个数字不能重复,否则爆炸

 8048dfc:       83 c3 01                    add    $0x1,%ebx

 8048dff:        83 fb 05                    cmp    $0x5,%ebx

 8048e02:      7e e9                      jle    8048ded <phase_6+0x40>

 8048e04:      eb c5                      jmp    8048dcb <phase_6+0x1e>

 ;判重结束;

 

接着根据输入构建一个链表

8048e12: ba 3c c1 04 08       mov    $0x804c13c,%edx  ;将第一个元素的下标放到edx里

 8048e17:      89 54 b4 28                 mov    %edx,0x28(%esp,%esi,4) ;把下一个的地址放到栈里 

 8048e1b:      83 c3 01                    add    $0x1,%ebx                      ;ebx++

 8048e1e:      83 fb 06                    cmp    $0x6,%ebx                            ;循环6次

 8048e21:      74 17                      je     8048e3a <phase_6+0x8d> 

 ;两个判断结束后跳到这里

 8048e23:      89 de                      mov    %ebx,%esi                      ;esi = ebx

 8048e25:      8b 4c 9c 10          mov    0x10(%esp,%ebx,4),%ecx   ;依次取出输入的几个数

 8048e29:      83 f9 01             cmp    $0x1,%ecx

 8048e2c:       7e e4                      jle    8048e12 <phase_6+0x65> ;如果取出的数是1,跳到0x8048e12

 8048e2e:      b8 01 00 00 00       mov    $0x1,%eax

 8048e33:      ba 3c c1 04 08       mov    $0x804c13c,%edx  ;将第一个元素的下标放到edx里

 8048e38:      eb cc                      jmp    8048e06 <phase_6+0x59>

 

 ;根据输入的6个数构建一个链表

 8048e3a:      8b 5c 24 28                 mov    0x28(%esp),%ebx         ;取出下一个地址

 8048e3e:      8d 44 24 2c                 lea    0x2c(%esp),%eax       

 8048e42:      8d 74 24 40                 lea    0x40(%esp),%esi

 8048e46:      89 d9                      mov    %ebx,%ecx

 

 8048e48:      8b 10                      mov    (%eax),%edx            ;将下一个地址放到edx中

 8048e4a:      89 51 08                   mov    %edx,0x8(%ecx)       ;将这个地址给ecx+8

 8048e4d:      83 c0 04                    add    $0x4,%eax ;指向下一个元素

 8048e50:      39 f0                       cmp    %esi,%eax ;走到最后一个跳出

 8048e52:      74 04                      je     8048e58 <phase_6+0xab>

 8048e54:      89 d1                      mov    %edx,%ecx              ;把下一个地址给ecx

 8048e56:      eb f0                      jmp    8048e48 <phase_6+0x9b>

 

 8048e58:      c7 42 08 00 00 00 00   movl   $0x0,0x8(%edx) 

 8048e5f:       be 05 00 00 00       mov    $0x5,%esi

要求链表的值是递减的

;这个链表中的值一定要是降序的

 8048e64:      8b 43 08                   mov    0x8(%ebx),%eax       ;下个元素的地址给eax

 8048e67:      8b 00                      mov    (%eax),%eax            ;取出下个元素的地址的值

 8048e69:      39 03                      cmp    %eax,(%ebx)           ;ebx的值>=eax  成功跳转,否则爆炸;也就是一定要满足降序规则 

 8048e6b:      7d 05                      jge    8048e72 <phase_6+0xc5>           

 8048e6d:      e8 83 02 00 00       call   80490f5 <explode_bomb>

 8048e72:      8b 5b 08                   mov    0x8(%ebx),%ebx ;读入下一个地址

 8048e75:      83 ee 01                   sub    $0x1,%esi  

 8048e78:      75 ea                      jne    8048e64 <phase_6+0xb7>  ;zf=0跳,也就是esi不等于1时跳

                                                               ;esi等于1时结束,循环5次,相继读入下一个元素的值

 8048e7a:      83 c4 44                    add    $0x44,%esp

 8048e7d:      5b                        pop    %ebx

 8048e7e:      5e                        pop    %esi

 8048e7f:       c3                        ret   

用gdb看一下内存里这几个元素里的东西

 

每个node的结构应该是这样

struct{

       int value;

       int id;

       int* next;

}

根据降序排列,顺序是0x3a9 0x39f 0x32f 0x2a0 0x22f 0x5c,对应的顺序是6 3 4 5 2 1

输入:

 

通过。

secret phase:

 

 

代码分析:

Defuse中:

movl   $0x804c4d0,(%esp)

 80492a8:      e8 b3 f5 ff ff           call   8048860 <[email protected]>

 80492ad:      83 f8 03             cmp    $0x3,%eax              ;如果检测到输入的内容是3个,就会将内存中的内容取出来进行比较。有内存地址0x804a352

 80492b0:      75 35                      jne    80492e7 <phase_defused+0x81>

 80492b2:      c7 44 24 04 52 a3 04   movl   $0x804a352,0x4(%esp)

 80492b9:      08

 80492ba:      8d 44 24 2c                 lea    0x2c(%esp),%eax

 80492be:      89 04 24                   mov    %eax,(%esp)

 80492c1:       e8 24 fd ff ff           call   8048fea <strings_not_equal>

 80492c6:       85 c0                      test   %eax,%eax

 80492c8:       75 1d                      jne    80492e7 <phase_defused+0x81>

 80492ca:       c7 04 24 18 a2 04 08   movl   $0x804a218,(%esp)

 80492d1:      e8 1a f5 ff ff            call   80487f0 <[email protected]>

 80492d6:      c7 04 24 40 a2 04 08   movl   $0x804a240,(%esp)

 80492dd:      e8 0e f5 ff ff            call   80487f0 <[email protected]>

 80492e2:      e8 ea fb ff ff            call   8048ed1 <secret_phase>

Gdb查看0x804a352:

 

特殊字符串是 DrEvil

Secrer_phase:

 

 

在第四关加上该字符串,在解决6个之后就会出现提示破解秘密phase

调用phase

Fun4函数分析:

 

经过推测,输入1001

 

通过。

 

四、实验结果

 

五、实验总结

       通过看汇编真正的能做一点东西,找到flag,这还是很有成就感的,一关一关的很有趣。

汇编中每个语句都是很简单的,但是综合起来,就是有一种感觉,跳上跳下的,到处跳!不过根据汇编读出来一个程序也很有趣,就是不如高级语言读起来容易。

       学会使用gdb的基本操作,也找到了一个比较好的插件哈哈peda,可以每一步运行时,都自动打印出stack里的东西,寄存器的东西,代码运行位置等,很方便。还学习了一个新的函数strtol().

       通过这个实验也把汇编又复习了一下,收获很多。

 

以上是关于Bomblab的主要内容,如果未能解决你的问题,请参考以下文章

csapp bomblab

csapp bomblab

Bomblab

CSAPP第二個實驗bomblab

2018.5.12 继续bomblab

Boom!!!计算机系统,从理解到爆炸,Bomblab