Bomb lab实验

bomblab

phase_1

反汇编后

0000000000001204 <phase_1>:
    # 指令将栈指针寄存器减 8,作用是给栈空间分配 8 字节
    1204:   48 83 ec 08             sub    $0x8,%rsp 
    # lea 是 “load effective address”  的缩写,简单的说,lea 指令可以用来将一个内存地址直接赋给目的操作数
    # 从键盘输入六个整数,用空格分开
    1208:   48 8d 35 c1 15 00 00    lea    0x15c1(%rip),%rsi# 27d0 <_IO_stdin_used+0x150>
    120f:   e8 a9 04 00 00          callq  16bd <strings_not_equal>
    1214:   85 c0                   test   %eax,%eax
    1216:   75 05                   jne    121d <phase_1+0x19>
    1218:   48 83 c4 08             add    $0x8,%rsp
    121c:   c3                      retq   
    121d:   e8 a7 05 00 00          callq  17c9 <explode_bomb>
    1222:   eb f4                   jmp    1218 <phase_1+0x14>

解题过程:

  1. 打断点到 phase_1 这一函数体
  2. layout regs 更换界面
  3. run 启动程序
  4. 此时断点会到函数内第一行
  5. si 分步骤执行到 lea 指令,我们可以看到寄存器地址是 0x5555555567d0

  1. 下图有个 strings_not_equal 函数,推测是比较字符串,所以看看 0x5555555567d0 存放了什么字符串去和我输入的字符串进行比较,用 x /s 0x5555555567d0 取值

  1. 可以看到寄存器输出了一段英文,这就是需要比较的字符串。

I can see Russia from my house!

phase_2

0000000000001224 <phase_2>:
    # 存放寄存器状态
    1224:   55                      push   %rbp
    1225:   53                      push   %rbx
    # 分配局部变量空间
    1226:   48 83 ec 28             sub    $0x28,%rsp
    122a:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
    1231:   00 00 
    1233:   48 89 44 24 18          mov    %rax,0x18(%rsp)
    1238:   31 c0                   xor    %eax,%eax

    # 把栈指针状态存到寄存器rsi
    123a:   48 89 e6                mov    %rsp,%rsi
    # 进入函数 read_six_number-> 00000000000017ef
    123d:   e8 ad 05 00 00          callq  17ef <read_six_numbers>
    
    # 判断第一个元素是否小于0
    1242:   83 3c 24 00             cmpl   $0x0,(%rsp)
    1246:   78 0a                   js     1252 <phase_2+0x2e>
    1248:   bb 01 00 00 00          mov    $0x1,%ebx
    124d:   48 89 e5                mov    %rsp,%rbp
    1250:   eb 11                   jmp    1263 <phase_2+0x3f>
    1252:   e8 72 05 00 00          callq  17c9 <explode_bomb>
    #for i=1 i!=6 ++1
    1257:   eb ef                   jmp    1248 <phase_2+0x24>
    //当索引自增1
    1259:   48 83 c3 01             add    $0x1,%rbx
    //当索引为6,跳出循环
    125d:   48 83 fb 06             cmp    $0x6,%rbx
    1261:   74 13                   je     1276 <phase_2+0x52>
    
    //取当前数组位值
    1263:   89 d8                   mov    %ebx,%eax
    // 4rbx+rpb地址-0x4 + eax
    1265:   03 44 9d fc             add    -0x4(%rbp,%rbx,4),%eax
    // 4rbx+rpb地址-0x0 和eax比 就是数组当前位比上数组前一位的值加上数组索引
    1269:   39 44 9d 00             cmp    %eax,0x0(%rbp,%rbx,4)
    //相等就回到循环
    126d:   74 ea                   je     1259 <phase_2+0x35>
    //不相等就爆炸
    126f:   e8 55 05 00 00          callq  17c9 <explode_bomb>
    1274:   eb e3                   jmp    1259 <phase_2+0x35>
    1276:   48 8b 44 24 18          mov    0x18(%rsp),%rax
    127b:   64 48 33 04 25 28 00    xor    %fs:0x28,%rax
    1282:   00 00 
    1284:   75 07                   jne    128d <phase_2+0x69>
    1286:   48 83 c4 28             add    $0x28,%rsp
    128a:   5b                      pop    %rbx
    128b:   5d                      pop    %rbp
    128c:   c3                      retq   
    128d:   e8 be fb ff ff          callq  e50 <__stack_chk_fail@plt>

解题过程:

  1. 进入 gdb 打断点打到 phase_2

  1. 执行完 read_six_number

  1. 继续往下走,发现到循环里了

  1. 不难看出这里是数组当前位数组前一位的值加上数组索引的值相比较,不相等就炸。

  1. 输入 1 2 4 7 11 16

6.答案正确,跳回主函数

phase_3

0x0000000000001292 <+0>:        sub    $0x18,%rsp
   0x0000000000001296 <+4>:        mov    %fs:0x28,%rax
   0x000000000000129f <+13>:        mov    %rax,0x8(%rsp)
   0x00000000000012a4 <+18>:        xor    %eax,%eax
   0x00000000000012a6 <+20>:        lea    0x4(%rsp),%rcx
   0x00000000000012ab <+25>:        mov    %rsp,%rdx
   0x00000000000012ae <+28>:        lea    0x16da(%rip),%rsi        # 0x298f
   # 输入两个整数,以空格分开
   0x00000000000012b5 <+35>:        callq  0xef0 <__isoc99_sscanf@plt>
   # eax = 2
   # eax小于等于1就炸
   0x00000000000012ba <+40>:        cmp    $0x1,%eax
   0x00000000000012bd <+43>:        jle    0x12d8 <phase_3+70>
   # rsp第二个数 比上7 大于7就炸
   0x00000000000012bf <+45>:        cmpl   $0x7,(%rsp)
   0x00000000000012c3 <+49>:        ja     0x1310 <phase_3+126>
   
   0x00000000000012c5 <+51>:        mov    (%rsp),%eax
   0x00000000000012c8 <+54>:        lea    0x1551(%rip),%rdx        # 0x2820
   # 扩展从2位变4位地址
   0x00000000000012cf <+61>:        movslq (%rdx,%rax,4),%rax
   
   0x00000000000012d3 <+65>:        add    %rdx,%rax
   0x00000000000012d6 <+68>:        jmpq   *%rax
   0x00000000000012d8 <+70>:        callq  0x17c9 <explode_bomb>
   0x00000000000012dd <+75>:        jmp    0x12bf <phase_3+45>
   0x00000000000012df <+77>:        mov    $0x3e0,%eax
   0x00000000000012e4 <+82>:        jmp    0x1321 <phase_3+143>
   0x00000000000012e6 <+84>:        mov    $0x13a,%eax
   0x00000000000012eb <+89>:        jmp    0x1321 <phase_3+143>
   0x00000000000012ed <+91>:        mov    $0x1ee,%eax
   0x00000000000012f2 <+96>:        jmp    0x1321 <phase_3+143>
   0x00000000000012f4 <+98>:        mov    $0x4d,%eax
   0x00000000000012f9 <+103>:        jmp    0x1321 <phase_3+143>
   0x00000000000012fb <+105>:        mov    $0x3a,%eax
   0x0000000000001300 <+110>:        jmp    0x1321 <phase_3+143>
   0x0000000000001302 <+112>:        mov    $0x22c,%eax
   0x0000000000001307 <+117>:        jmp    0x1321 <phase_3+143>
   0x0000000000001309 <+119>:        mov    $0x8d,%eax
   0x000000000000130e <+124>:        jmp    0x1321 <phase_3+143>
   0x0000000000001310 <+126>:        callq  0x17c9 <explode_bomb>
   0x0000000000001315 <+131>:        mov    $0x0,%eax
   0x000000000000131a <+136>:        jmp    0x1321 <phase_3+143>
   0x000000000000131c <+138>:        mov    $0x3c2,%eax
   // 和扩容地址比较
   0x0000000000001321 <+143>:        cmp    %eax,0x4(%rsp)
   0x0000000000001325 <+147>:        je     0x132c <phase_3+154>
   0x0000000000001327 <+149>:        callq  0x17c9 <explode_bomb>
   0x000000000000132c <+154>:        mov    0x8(%rsp),%rax
   0x0000000000001331 <+159>:        xor    %fs:0x28,%rax
   0x000000000000133a <+168>:        jne    0x1341 <phase_3+175>
   0x000000000000133c <+170>:        add    $0x18,%rsp
   0x0000000000001340 <+174>:        retq
   0x0000000000001341 <+175>:        callq  0xe50 <__stack_chk_fail@plt>
  1. 看 35 行代码不难发现,这里需要输入两个以空格间隔的整数。

其中,40-49 行:

  • 判断输入的第一个数是否小于等于 1,符合则爆炸。
  • 判断输入的第一个数是否大于 7,符合则爆炸

  1. 这里可以推测输入第一个数是 1

  1. 这里可以得知我们输入的第二个数可以是 992

输入 1 992,phase_3 通过

phase_4

0x0000000000001385 <+0>:         sub    $0x18,%rsp
   // rax = 40
   0x0000000000001389 <+4>:         mov    %fs:0x28,%rax
   // rsp + 8 = 40
   0x0000000000001392 <+13>:        mov    %rax,0x8(%rsp)
   0x0000000000001397 <+18>:        xor    %eax,%eax
   0x0000000000001399 <+20>:        lea    0x4(%rsp),%rcx
   0x000000000000139e <+25>:        mov    %rsp,%rdx
   // 输入两个整数
   0x00000000000013a1 <+28>:        lea    0x15e7(%rip),%rsi        # 0x298f
   0x00000000000013a8 <+35>:        callq  0xef0 <__isoc99_sscanf@plt>
   //比较数组数值是否为2不是就炸
   0x00000000000013ad <+40>:        cmp    $0x2,%eax
   0x00000000000013b0 <+43>:        jne    0x13b8 <phase_4+51>
   0x00000000000013b2 <+45>:        cmpl   $0xe,(%rsp)
   0x00000000000013b6 <+49>:        jbe    0x13bd <phase_4+56>
   0x00000000000013b8 <+51>:        callq  0x17c9 <explode_bomb>
   0x00000000000013bd <+56>:        mov    $0xe,%edx
   0x00000000000013c2 <+61>:        mov    $0x0,%esi
   0x00000000000013c7 <+66>:        mov    (%rsp),%edi
   0x00000000000013ca <+69>:        callq  0x1346 <func4>
   //调用完func4,eax需要等于3
   0x00000000000013cf <+74>:        cmp    $0x3,%eax
   0x00000000000013d2 <+77>:        jne    0x13db <phase_4+86>
   //
   0x00000000000013d4 <+79>:        cmpl   $0x3,0x4(%rsp)
   0x00000000000013d9 <+84>:        je     0x13e0 <phase_4+91>
   0x00000000000013db <+86>:        callq  0x17c9 <explode_bomb>
   0x00000000000013e0 <+91>:        mov    0x8(%rsp),%rax
   0x00000000000013e5 <+96>:        xor    %fs:0x28,%rax
   0x00000000000013ee <+105>:       jne    0x13f5 <phase_4+112>
   0x00000000000013f0 <+107>:       add    $0x18,%rsp
   0x00000000000013f4 <+111>:       retq
   0x00000000000013f5 <+112>:       callq  0xe50 <__stack_chk_fail@plt>
  1. 断点打到 phase_4,可以看到前面分配了两个内存点到 rcx,rsi,用来接收从键盘输入的两个整数。

  1. 验证数组里是否是两个数,第一个数是否小于 14,否则爆炸。

  1. 可以看到 69 行进入到 func4 方法里面了,反汇编一下,
0x0000000000001346 <+0>:        sub    $0x8,%rsp

0x000000000000134a <+4>:        mov    %edx,%eax
0x000000000000134c <+6>:        sub    %esi,%eax
<em>// cx = ax</em>
0x000000000000134e <+8>:        mov    %eax,%ecx
 <em>//逻辑右移 cx 31位 正0负1</em>
0x0000000000001350 <+10>:        shr    $0x1f,%ecx
<em>// cx +=ax</em>
0x0000000000001353 <+13>:        add    %eax,%ecx
<em>// 算术右移一位cx</em>
0x0000000000001355 <+15>:        sar    %ecx
<em>//cx ++si</em>
0x0000000000001357 <+17>:        add    %esi,%ecx
<em>// ecx>edi?</em>
0x0000000000001359 <+19>:        cmp    %edi,%ecx
0x000000000000135b <+21>:        jg     0x136b <func4+37>
0x000000000000135d <+23>:        mov    $0x0,%eax
0x0000000000001362 <+28>:        cmp    %edi,%ecx
0x0000000000001364 <+30>:        jl     0x1377 <func4+49>
0x0000000000001366 <+32>:        add    $0x8,%rsp
0x000000000000136a <+36>:        retq

0x000000000000136b <+37>:        lea    -0x1(%rcx),%edx
0x000000000000136e <+40>:        callq  0x1346 <func4>
0x0000000000001373 <+45>:        add    %eax,%eax
0x0000000000001375 <+47>:        jmp    0x1366 <func4+32>
0x0000000000001377 <+49>:        lea    0x1(%rcx),%esi
0x000000000000137a <+52>:        callq  0x1346 <func4>

观察代码可以发现这里做了个运算,cx = (ax-si)/2+ax

代入式子 cx = (ax-si)/2+ax

得(14-0)/2 +0 = 7

  1. 如果满足条件 1,就要进入递归

Retq 2*func4(edx,esi,ecx-1)

  1. 不然就到下一步骤 retq 2 * func4(edx, (ecx + 1), edx) + 1
  2. 已知最后 phase_4 需要递归函数结束后返回值为 3,可以写出代码模拟程序进行破解。
#include <iostream>

using namespace std;

int func4(int a1, int a2, int a3) {
    int ecx;
    <em>// rax</em>
<em>    </em>int result; 

<em>    </em>ecx = a2 + (a3 - a2) / 2;
    if (ecx > a1)
        return 2 * func4(a1, a2, (ecx - 1));
    result = 0;
    if (ecx < a1)
        return 2 * func4(a1, (ecx + 1), a3) + 1;
    return result;
}

int main() {
    int v2 = 1, v3 = 3;
    while (v2 <= 14) {
        if (func4(v2, 0, 14) == 3) {
            //打印递归函数返回为3的v2
            cout << v2;
            break;
        } else {
            v2++;
        }
    }
}

枚举出第一个参数应该是 12。

  1. 我们回到 phase_4,可以看到,他要求我们第二个参数必须为 3。

  1. 所以输入 12 3。phase_4 通过

phase_5

13fa:   53                      push   %rbx
    13fb:   48 89 fb                mov    %rdi,%rbx
    13fe:   e8 9d 02 00 00          callq  16a0 <string_length>

    1403:   83 f8 06                cmp    $0x6,%eax
    1406:   75 31                   jne    1439 <phase_5+0x3f>
    1408:   48 89 d8                mov    %rbx,%rax
    140b:   48 8d 7b 06             lea    0x6(%rbx),%rdi
    140f:   b9 00 00 00 00          mov    $0x0,%ecx
    1414:   48 8d 35 25 14 00 00    lea    0x1425(%rip),%rsi        # 2840 <array.3415>
    141b:   0f b6 10                movzbl (%rax),%edx
    //dx and 0xf保留后四位
    141e:   83 e2 0f                and    $0xf,%edx
    //ecx += 4rdx +rsi
    1421:   03 0c 96                add    (%rsi,%rdx,4),%ecx
    // 取下标
    1424:   48 83 c0 01             add    $0x1,%rax
    //i<6? 回到循环:跳出
    1428:   48 39 f8                cmp    %rdi,%rax
    142b:   75 ee                   jne    141b <phase_5+0x21>
    //比72
    142d:   83 f9 48                cmp    $0x48,%ecx
    1430:   74 05                   je     1437 <phase_5+0x3d>
    1432:   e8 92 03 00 00          callq  17c9 <explode_bomb>
    1437:   5b                      pop    %rbx
    1438:   c3                      retq   
    1439:   e8 8b 03 00 00          callq  17c9 <explode_bomb>
    143e:   eb c8                   jmp    1408 <phase_5+0xe>
  1. 反汇编代码,显然是输入长度为 6 的字符串

  1. 在反汇编代码里面查看一下那个数组 array3415

数组应该是这样的

array_3415[16] = { 2, 10, 6, 1, 12, 16, 9, 3, 4, 7, 14, 5, 11, 8, 15, 13 }

  1. 这个题的关键是比较 ecx 是否等于 0x48(10 进制就是 72),不相等就爆炸
  2. and $0xf,%edx,这里是保留 edx 也就是每一位输入的值的下标值二进制的后四位。
  3. 可以读出这里的意思是:拿每一个输入元素的值对 15 做与后的值取到数组下标对应元素的值的和等于 72,这里我取下标 4

array_3415[4] = 12

12+12+12+12+12+12=72

所以输入 444444,phase_5 通过

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LMAO6688

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值