• 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 <__isoc99_sscanf@plt> ; 输入

    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 <__isoc99_sscanf@plt>;输入

    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 <__isoc99_sscanf@plt>

     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 <puts@plt>

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

     80492dd:      e8 0e f5 ff ff            call   80487f0 <puts@plt>

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

    Gdb查看0x804a352:

     

    特殊字符串是 DrEvil

    Secrer_phase:

     

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

    调用phase

    Fun4函数分析:

     

    经过推测,输入1001

     

    通过。

    四、实验结果

     

     

  • 相关阅读:
    Linux系统配置静态ip
    爬虫之如何找js入口(一)
    asyncio动态添加任务
    关于python导包问题
    python动态添加属性
    requests模块
    反selenium关键字
    PIL模块
    openxlsx模块
    CSV
  • 原文地址:https://www.cnblogs.com/gudygudy/p/10358955.html
Copyright © 2020-2023  润新知