文章目录

  • 所需要使用的调试工具
  • 开始进入拆弹过程
    • phase_1
    • phase_2
    • pahse_3
    • phase_4
    • phase_5
    • phase_6
    • secret_phase

所需要使用的调试工具

1. gdb工具

  1. 使用 break *地址来设置断点,使用c指令从断点继续执行
  2. 使用 info registers 指令观察寄存器状态
  3. 使用 x/s 指令用字符串类型显示内存中值*

2.objdump工具
使用 objdump -d execfile > exfiles.s 对可执行文件进行反汇编并输入到一个文件中
使用objdump -t execfile 对可执行文件中符号表进行提取

Strings工具
使用strings bomb 可以将可执行文件中的所有可见字符打印出来

开始进入拆弹过程

phase_1

  input = read_line();             /* Get input                   */phase_1(input);                  /* Run the phase               */phase_defused();                 /* Drat!  They figured it out!* Let me know how they did it. */printf("Phase 1 defused. How about the next one?\n");

可以看到phase_1的C代码要求我们首先输入一个字符串,然后再进行比较
所以我们可以使用gdb在phase_1开始处设置断点并进行一次操作、查看寄存器的值

(gdb) break *0x400ee0
Breakpoint 1 at 0x400ee0
(gdb) run
Starting program: /home/legend/demo/bomb/bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
My first try!

My first try!就是随便打的,主要看它存入了哪个寄存器(不出意外是%rdi)

Breakpoint 1, 0x0000000000400ee0 in phase_1 ()
(gdb) info registers
rsi            0x603780 6305664
rdi            0x603780 6305664
(gdb) x/s 0x603780
0x603780 <input_strings>:       "My first try!"

因为后面程序中改变了%rsi。所以可以推断,输入的字符串确实存入了%rdi 寄存器
可以看到在后续代码里%rsi的值被改变,此刻我们再使用x/s查看其值发现是一个字符串

(gdb) x/s 0x402400
0x402400:       "Border relations with Canada have never been better."

接下来我们要进行对phase_1的分析
对应的汇编程序

0000000000400ee0 <phase_1>:400ee0: 48 83 ec 08             sub    $0x8,%rsp400ee4: be 00 24 40 00          mov    $0x402400,%esi400ee9:    e8 4a 04 00 00          callq  401338 <strings_not_equal>400eee:  85 c0                   test   %eax,%eax400ef0: 74 05                   je     400ef7 <phase_1+0x17>400ef2:  e8 43 05 00 00          callq  40143a <explode_bomb>400ef7:   48 83 c4 08             add    $0x8,%rsp400efb: c3                      retq

看到它调用了<string_not_equal>
截取一个重要部分

0000000000401338 <strings_not_equal>:401338:   41 54                   push   %r1240133a:  55                      push   %rbp40133b:  53                      push   %rbx40133c:  48 89 fb                mov    %rdi,%rbx40133f: 48 89 f5                mov    %rsi,%rbp401342: e8 d4 ff ff ff          callq  40131b <string_length>401347:  41 89 c4                mov    %eax,%r12d40134a:    48 89 ef                mov    %rbp,%rdi40134d: e8 c9 ff ff ff          callq  40131b <string_length>401352:  ba 01 00 00 00          mov    $0x1,%edx401357: 41 39 c4                cmp    %eax,%r12d40135a:    75 3f                   jne    40139b <strings_not_equal+0x63>40139b:    89 d0                   mov    %edx,%eax40139d: 5b                      pop    %rbx40139e:  5d                      pop    %rbp40139f:  41 5c                   pop    %r124013a1:  c3                      retq

对stringlength分析会得出该函数是用来返回字符串长度的
可以看到在not_equal函数里当我们键入的字符串长度与%rsi不同时,可以看到函数返回1;
可以推测出当两字符串相同时返回0

test设置条件码后je根据ZF条件码可以跳过炸弹启动程序
即只有我们键入的string和程序存入%rsi的string相同时才会执行je

所以可以得到我们看到的%rsi中的字符串就是keys

Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?

解决!Yep!

phase_2

该阶段的问题主要是理解代码中的循环

0000000000400efc <phase_2>:400efc: 55                      push   %rbp400efd:  53                      push   %rbx400efe:  48 83 ec 28             sub    $0x28,%rsp400f02:    48 89 e6                mov    %rsp,%rsi400f05: e8 52 05 00 00          callq  40145c <read_six_numbers>

先看函数中调用的<read_six_numbers>

000000000040145c <read_six_numbers>:40145c:    48 83 ec 18             sub    $0x18,%rsp401460:    48 89 f2                mov    %rsi,%rdx401463: 48 8d 4e 04             lea    0x4(%rsi),%rcx401467:    48 8d 46 14             lea    0x14(%rsi),%rax40146b:   48 89 44 24 08          mov    %rax,0x8(%rsp)401470:    48 8d 46 10             lea    0x10(%rsi),%rax401474:   48 89 04 24             mov    %rax,(%rsp)401478:   4c 8d 4e 0c             lea    0xc(%rsi),%r940147c: 4c 8d 46 08             lea    0x8(%rsi),%r8401480: be c3 25 40 00          mov    $0x4025c3,%esi401485:    b8 00 00 00 00          mov    $0x0,%eax40148a: e8 61 f7 ff ff          callq  400bf0 <__isoc99_sscanf@plt>40148f:   83 f8 05                cmp    $0x5,%eax401492: 7f 05                   jg     401499 <read_six_numbers+0x3d>401494: e8 a1 ff ff ff          callq  40143a <explode_bomb>401499:   48 83 c4 18             add    $0x18,%rsp40149d:    c3                      retq

可直接从<read_six_numbers>的后面开始看。

不难得到当输入字符数量少于6个时<read_six_numbers>会直接引爆炸弹。
所以keys的长度应该要大于等于6个字符。

再回头看<phase_2>中的主体代码

400f0a:  83 3c 24 01             cmpl   $0x1,(%rsp)400f0e:   74 20                   je     400f30 <phase_2+0x34>400f10:  e8 25 05 00 00          callq  40143a <explode_bomb>400f15:   eb 19                   jmp    400f30 <phase_2+0x34>400f17:  8b 43 fc                mov    -0x4(%rbx),%eax400f1a:   01 c0                   add    %eax,%eax400f1c: 39 03                   cmp    %eax,(%rbx)400f1e:   74 05                   je     400f25 <phase_2+0x29>400f20:  e8 15 05 00 00          callq  40143a <explode_bomb>400f25:   48 83 c3 04             add    $0x4,%rbx400f29: 48 39 eb                cmp    %rbp,%rbx400f2c: 75 e9                   jne    400f17 <phase_2+0x1b>400f2e:  eb 0c                   jmp    400f3c <phase_2+0x40>400f30:  48 8d 5c 24 04          lea    0x4(%rsp),%rbx400f35:    48 8d 6c 24 18          lea    0x18(%rsp),%rbp400f3a:   eb db                   jmp    400f17 <phase_2+0x1b>400f3c:  48 83 c4 28             add    $0x28,%rsp400f40:    5b                      pop    %rbx400f41:  5d                      pop    %rbp400f42:  c3                      retq

因为我们的目的是要得到keys
所以这里的一个处理技巧是:
我们不去管引爆炸弹的情况,只按照可以jump的条件分析。

只要我们遵循着它的跳跃进行一轮就会发现
这个循环的条件为输入的keys中后一位是前一位的2倍,且第一位为1,数据为int型
可从如下代码得出

  400f0a:    83 3c 24 01             cmpl   $0x1,(%rsp)//可以看出rsp即栈顶中存的为数字1,400f17:   8b 43 fc                mov    -0x4(%rbx),%eax400f1a:   01 c0                   add    %eax,%eax400f1c: 39 03                   cmp    %eax,(%rbx)400f1e:   74 05                   je     400f25 <phase_2+0x29>400f20:  e8 15 05 00 00          callq  40143a <explode_bomb>

并且要求长度至少为6
可从我们对<read_six_numbers>得出
或者从如下截取的两段代码得出

400f30:  48 8d 5c 24 04          lea    0x4(%rsp),%rbx
400f35: 48 8d 6c 24 18          lea    0x18(%rsp),%rbp
//rbp为rsp+24,rbx为rsp+4400f25:  48 83 c3 04             add    $0x4,%rbx
400f29: 48 39 eb                cmp    %rbp,%rbx
//再根据比较条件,可以看出至少要24/4位的keys

结果
可以看到长度大于6后就不再进行判断了(255也过了)

Phase 1 defused. How about the next one?
1 2 4 8 16 32 64 128 255
That's number 2.  Keep going!

phase_2解决!Yep!

pahse_3

该部分考查对switch的理解

0000000000400f43 <phase_3>:400f43: 48 83 ec 18             sub    $0x18,%rsp400f47:    48 8d 4c 24 0c          lea    0xc(%rsp),%rcx400f4c:    48 8d 54 24 08          lea    0x8(%rsp),%rdx400f51:    be cf 25 40 00          mov    $0x4025cf,%esi400f56:    b8 00 00 00 00          mov    $0x0,%eax400f5b: e8 90 fc ff ff          callq  400bf0 <__isoc99_sscanf@plt>400f60:   83 f8 01                cmp    $0x1,%eax400f63: 7f 05                   jg     400f6a <phase_3+0x27>400f65:  e8 d0 04 00 00          callq  40143a <explode_bomb>

从上面这一部分中可以看到我们输入的keys的长度不能少于两位,否则引爆炸弹

 400f6a: 83 7c 24 08 07          cmpl   $0x7,0x8(%rsp)400f6f:    77 3c                   ja     400fad <phase_3+0x6a>400f71:  8b 44 24 08             mov    0x8(%rsp),%eax

再对上述代码主体进行分析,发现代码将%rax的值变成了我们第一个输入进的数字,且这个数字不能大于7

400f75:  ff 24 c5 70 24 40 00    jmpq   *0x402470(,%rax,8)

%rax会影响我们跳转的地址。
接下来使用gdb工具对%rax不同值对应内存地址中的值取出,对应下面的各个情况

在此只举%rax=2的例子,其余6个值也可行
发现对应地址

(gdb) x/u *0x402480
0x400f83 <phase_3+64>:  184
400f7c:  b8 cf 00 00 00          mov    $0xcf,%eax
400f81: eb 3b                   jmp    400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00          mov    $0x2c3,%eax
400f88: eb 34                   jmp    400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00          mov    $0x100,%eax
400f8f: eb 2d                   jmp    400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00          mov    $0x185,%eax
400f96: eb 26                   jmp    400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00          mov    $0xce,%eax
400f9d: eb 1f                   jmp    400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00          mov    $0x2aa,%eax
400fa4: eb 18                   jmp    400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00          mov    $0x147,%eax
400fab: eb 11                   jmp    400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00          callq  40143a <explode_bomb>
400fb2: b8 00 00 00 00          mov    $0x0,%eax
400fb7: eb 05                   jmp    400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00          mov    $0x137,%eax

在我们的举例中,%rax=0x2c3,十进制707

400fbe:  3b 44 24 0c             cmp    0xc(%rsp),%eax
400fc2: 74 05                   je     400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00          callq  40143a <explode_bomb>
400fc9: 48 83 c4 18             add    $0x18,%rsp
400fcd: c3                      retq

再看上述代码,可以发现,当%rax的值与我们输入的第二个数字相同时,就得到了keys
所以该phase共有7个keys可供选择

结果

That's number 2.  Keep going!
2 707
Halfway there!

phase_3完成!Yep!

phase_4

这个阶段考查的是递归函数

先看phase_4在调用fun_4前的代码

000000000040100c <phase_4>:40100c: 48 83 ec 18             sub    $0x18,%rsp401010:    48 8d 4c 24 0c          lea    0xc(%rsp),%rcx401015:    48 8d 54 24 08          lea    0x8(%rsp),%rdx40101a:    be cf 25 40 00          mov    $0x4025cf,%esi40101f:    b8 00 00 00 00          mov    $0x0,%eax401024: e8 c7 fb ff ff          callq  400bf0 <__isoc99_sscanf@plt>401029:   83 f8 02                cmp    $0x2,%eax40102c: 75 07                   jne    401035 <phase_4+0x29>40102e:  83 7c 24 08 0e          cmpl   $0xe,0x8(%rsp)401033:    76 05                   jbe    40103a <phase_4+0x2e>401035:  e8 00 04 00 00          callq  40143a <explode_bomb>40103a:   ba 0e 00 00 00          mov    $0xe,%edx40103f: be 00 00 00 00          mov    $0x0,%esi401044: 8b 7c 24 08             mov    0x8(%rsp),%edi401048:    e8 81 ff ff ff          callq  400fce <func4>

这段代码比较简单,从phase_4中看到我们输入的keys是两个数字
且第一个输入的数字应该小于等于14
现在主要是去分析fun_4的功能
此时传入的%rdx=14,%rsi=0,%rdi=我们输入的第一个数字

0000000000400fce <func4>:400fce:   48 83 ec 08             sub    $0x8,%rsp400fd2: 89 d0                   mov    %edx,%eax400fd4: 29 f0                   sub    %esi,%eax400fd6: 89 c1                   mov    %eax,%ecx400fd8: c1 e9 1f                shr    $0x1f,%ecx400fdb:    01 c8                   add    %ecx,%eax400fdd: d1 f8                   sar    %eax400fdf:  8d 0c 30                lea    (%rax,%rsi,1),%ecx400fe2:    39 f9                   cmp    %edi,%ecx400fe4: 7e 0c                   jle    400ff2 <func4+0x24>400fe6:    8d 51 ff                lea    -0x1(%rcx),%edx400fe9:   e8 e0 ff ff ff          callq  400fce <func4>400fee:  01 c0                   add    %eax,%eax400ff0: eb 15                   jmp    401007 <func4+0x39>400ff2:    b8 00 00 00 00          mov    $0x0,%eax400ff7: 39 f9                   cmp    %edi,%ecx400ff9: 7d 0c                   jge    401007 <func4+0x39>400ffb:    8d 71 01                lea    0x1(%rcx),%esi400ffe:    e8 cb ff ff ff          callq  400fce <func4>401003:  8d 44 00 01             lea    0x1(%rax,%rax,1),%eax401007: 48 83 c4 08             add    $0x8,%rsp40100b: c3                      retq

此时我们一直跟随着可跳转的代码,发现当rdi==1时,就可以直接跳出递归,且此时%rax=0
继续看phase_4的后一段代码

 40104d: 85 c0                   test   %eax,%eax40104f: 75 07                   jne    401058 <phase_4+0x4c>401051:  83 7c 24 0c 00          cmpl   $0x0,0xc(%rsp)401056:    74 05                   je     40105d <phase_4+0x51>401058:  e8 dd 03 00 00          callq  40143a <explode_bomb>40105d:   48 83 c4 18             add    $0x18,%rsp401061:    c3                      retq

察看jne语句可知%rax=0不会引爆炸弹,所以第一个输入的数字可以为1
继续向下看,看到另一个cmpl语句,此时我们可以确定输入的第二个数字一定为0
所以我们的keys就是1 0

Halfway there!
1 0
So you got that one.  Try this one.

phase_4完成!Yep!

phase_5

感觉这段主要是考察寄存器的细节和栈的存储,特点并不是很鲜明,但很有趣,有种解密的感觉

0000000000401062 <phase_5>:401062: 53                      push   %rbx401063:  48 83 ec 20             sub    $0x20,%rsp401067:    48 89 fb                mov    %rdi,%rbx40106a: 64 48 8b 04 25 28 00    mov    %fs:0x28,%rax401071: 00 00 401073:   48 89 44 24 18          mov    %rax,0x18(%rsp)401078:   31 c0                   xor    %eax,%eax40107a: e8 9c 02 00 00          callq  40131b <string_length>40107f:  83 f8 06                cmp    $0x6,%eax401082: 74 4e                   je     4010d2 <phase_5+0x70>401084:  e8 b1 03 00 00          callq  40143a <explode_bomb>

可以看到我们输入的keys是六位的

 401089: eb 47                   jmp    4010d2 <phase_5+0x70>40108b:  0f b6 0c 03             movzbl (%rbx,%rax,1),%ecx40108f:    88 0c 24                mov    %cl,(%rsp)401092:    48 8b 14 24             mov    (%rsp),%rdx401096:   83 e2 0f                and    $0xf,%edx401099: 0f b6 92 b0 24 40 00    movzbl 0x4024b0(%rdx),%edx4010a0:   88 54 04 10             mov    %dl,0x10(%rsp,%rax,1)4010a4: 48 83 c0 01             add    $0x1,%rax4010a8: 48 83 f8 06             cmp    $0x6,%rax4010ac: 75 dd                   jne    40108b <phase_5+0x29>

可以看到在这段程序不断取我们输入keys的,并且将每一位的低4位写入%rdx
然后通过movzbl 0x4024b0(%rdx),%edx得到真正的keys
所以我们使用gdb工具查看0x4024b0中究竟存储的是什么

x/s 0x4024b0
0x4024b0 <array.3449>:"maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"

我们就是在这个字段中寻找六个字符,凑成keys

  4010ae:    c6 44 24 16 00          movb   $0x0,0x16(%rsp)4010b3:   be 5e 24 40 00          mov    $0x40245e,%esi4010b8:    48 8d 7c 24 10          lea    0x10(%rsp),%rdi4010bd:   e8 76 02 00 00          callq  401338 <strings_not_equal>4010c2:  85 c0                   test   %eax,%eax4010c4: 74 13                   je     4010d9 <phase_5+0x77>4010c6:  e8 6f 03 00 00          callq  40143a <explode_bomb>4010cb:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)4010d0:  eb 07                   jmp    4010d9 <phase_5+0x77>4010d2:  b8 00 00 00 00          mov    $0x0,%eax4010d7: eb b2                   jmp    40108b <phase_5+0x29>4010d9:  48 8b 44 24 18          mov    0x18(%rsp),%rax4010de:   64 48 33 04 25 28 00    xor    %fs:0x28,%rax4010e5: 00 00 4010e7:   74 05                   je     4010ee <phase_5+0x8c>4010e9:  e8 42 fa ff ff          callq  400b30 <__stack_chk_fail@plt>4010ee:  48 83 c4 20             add    $0x20,%rsp4010f2:    5b                      pop    %rbx4010f3:  c3                      retq

哈哈,可以看到出现了<string_not_equal>函数,那么0x40245e中存储的就是我们需要从上述字段中寻找的各个字符
使用gdb查看0x40245e中存储了什么

(gdb) x/s 0x40245e
0x40245e:       "flyers"

嗡嗡嗡,全是苍蝇啊
maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?
再看这里面的字符,我们分别发现在9,15,14,5,6,7这六个位置
所以我们输入字符的二进制低四位应该是:
1001
1111
1110
0101
0110
0111

再去找ASCII表

附一个 ASCII表的链接
可以得到我们输入的字符是:就字母区段来说应该是ionefg或者IONEFG,或者是这几个字母按顺序的大小写混写

当然还有可能是许多其他字符和数字的组合,这里不一一列举

哇哈哈哈,成功了!!!

phase_5完成!Yep!

phase_6

淦,好长啊!
这一部分是考察对链表的重新链接

00000000004010f4 <phase_6>:4010f4: 41 56                   push   %r144010f6:  41 55                   push   %r134010f8:  41 54                   push   %r124010fa:  55                      push   %rbp4010fb:  53                      push   %rbx4010fc:  48 83 ec 50             sub    $0x50,%rsp401100:    49 89 e5                mov    %rsp,%r13401103: 48 89 e6                mov    %rsp,%rsi401106: e8 51 03 00 00          callq  40145c <read_six_numbers>

由<read_six_numbers>可以得知我们的keys长度至少为6

  40110b:    49 89 e6                mov    %rsp,%r1440110e: 41 bc 00 00 00 00       mov    $0x0,%r12d401114:    4c 89 ed                mov    %r13,%rbp401117: 41 8b 45 00             mov    0x0(%r13),%eax40111b:    83 e8 01                sub    $0x1,%eax40111e: 83 f8 05                cmp    $0x5,%eax401121: 76 05                   jbe    401128 <phase_6+0x34>401123:  e8 12 03 00 00          callq  40143a <explode_bomb>401128:   41 83 c4 01             add    $0x1,%r12d40112c:    41 83 fc 06             cmp    $0x6,%r12d401130:    74 21                   je     401153 <phase_6+0x5f>401132:  44 89 e3                mov    %r12d,%ebx401135:    48 63 c3                movslq %ebx,%rax401138: 8b 04 84                mov    (%rsp,%rax,4),%eax40113b:    39 45 00                cmp    %eax,0x0(%rbp)40113e:    75 05                   jne    401145 <phase_6+0x51>401140:  e8 f5 02 00 00          callq  40143a <explode_bomb>401145:   83 c3 01                add    $0x1,%ebx401148: 83 fb 05                cmp    $0x5,%ebx40114b: 7e e8                   jle    401135 <phase_6+0x41>40114d:  49 83 c5 04             add    $0x4,%r13401151: eb c1                   jmp    401114 <phase_6+0x20>

阅读上述代码发现这是实现了确保每个数字都小于6且大于0

  401153:    48 8d 74 24 18          lea    0x18(%rsp),%rsi401158:   4c 89 f0                mov    %r14,%rax40115b: b9 07 00 00 00          mov    $0x7,%ecx401160: 89 ca                   mov    %ecx,%edx401162: 2b 10                   sub    (%rax),%edx401164:   89 10                   mov    %edx,(%rax)401166:   48 83 c0 04             add    $0x4,%rax40116a: 48 39 f0                cmp    %rsi,%rax40116d: 75 f1                   jne    401160 <phase_6+0x6c>

这段代码实现了7-每个数字的功能

  40116f:    be 00 00 00 00          mov    $0x0,%esi401174: eb 21                   jmp    401197 <phase_6+0xa3>401176:  48 8b 52 08             mov    0x8(%rdx),%rdx40117a:    83 c0 01                add    $0x1,%eax40117d: 39 c8                   cmp    %ecx,%eax40117f: 75 f5                   jne    401176 <phase_6+0x82>401181:  eb 05                   jmp    401188 <phase_6+0x94>401183:  ba d0 32 60 00          mov    $0x6032d0,%edx401188:    48 89 54 74 20          mov    %rdx,0x20(%rsp,%rsi,2)40118d:    48 83 c6 04             add    $0x4,%rsi401191: 48 83 fe 18             cmp    $0x18,%rsi401195:    74 14                   je     4011ab <phase_6+0xb7>401197:  8b 0c 34                mov    (%rsp,%rsi,1),%ecx40119a:    83 f9 01                cmp    $0x1,%ecx40119d: 7e e4                   jle    401183 <phase_6+0x8f>40119f:  b8 01 00 00 00          mov    $0x1,%eax4011a4: ba d0 32 60 00          mov    $0x6032d0,%edx4011a9:    eb cb                   jmp    401176 <phase_6+0x82>

相当于把一个链表中的不同值传入栈中
设 order为数字的次序, value为数字的值
这段代码实现了当value等于1时将0x6032d0传入rsp+32+(order-1) * 8
value大于1时,将0x6032d0+8 * (value-1)值传入rsp+32+(order-1) * 8

我们再看一看链表中的结点元素

(gdb) p/s *0x6032d0@24
$2 = {332, 1, 6304480, 0,  168, 2, 6304496, 0, 924, 3, 6304512, 0,  691, 4, 6304528, 0,477, 5, 6304544, 0,  443, 6, 0, 0}

现在可以看到这六个结点的值分别为332,168,924,691,477,443

 4011ab: 48 8b 5c 24 20          mov    0x20(%rsp),%rbx4011b0:   48 8d 44 24 28          lea    0x28(%rsp),%rax4011b5:   48 8d 74 24 50          lea    0x50(%rsp),%rsi4011ba:   48 89 d9                mov    %rbx,%rcx4011bd: 48 8b 10                mov    (%rax),%rdx4011c0:   48 89 51 08             mov    %rdx,0x8(%rcx)4011c4:    48 83 c0 08             add    $0x8,%rax4011c8: 48 39 f0                cmp    %rsi,%rax4011cb: 74 05                   je     4011d2 <phase_6+0xde>4011cd:  48 89 d1                mov    %rdx,%rcx4011d0: eb eb                   jmp    4011bd <phase_6+0xc9>4011d2:  48 c7 42 08 00 00 00    movq   $0x0,0x8(%rdx)

这段代码实现了将链表直接相连接,并且将最后的指针为0(NULL)

4011d9:  00
4011da: bd 05 00 00 00          mov    $0x5,%ebp
4011df: 48 8b 43 08             mov    0x8(%rbx),%rax
4011e3: 8b 00                   mov    (%rax),%eax
4011e5: 39 03                   cmp    %eax,(%rbx)
4011e7: 7d 05                   jge    4011ee <phase_6+0xfa>
4011e9: e8 4c 02 00 00          callq  40143a <explode_bomb>
4011ee: 48 8b 5b 08             mov    0x8(%rbx),%rbx
4011f2: 83 ed 01                sub    $0x1,%ebp
4011f5: 75 e8                   jne    4011df <phase_6+0xeb>
4011f7: 48 83 c4 50             add    $0x50,%rsp
4011fb: 5b                      pop    %rbx
4011fc: 5d                      pop    %rbp
4011fd: 41 5c                   pop    %r12
4011ff: 41 5d                   pop    %r13
401201: 41 5e                   pop    %r14
401203: c3                      retq

这段代码实现了判断rsp+32链表必须是递减的,否则直接引爆炸弹
现在我们可以知道排序应该为3 4 5 6 1 2
所以我们输入的值应该为4 3 2 1 6 5(因为前面的排序是用7-输入数字得到的顺序)

phase_6完成 ! Yep!

secret_phase

PDF中写道还有一个secret_phase,在汇编文件里先找了找,果真发现了secret_phase
看到这里我首先想到的是怎么进入这个secret,可以看到这里面并没有给我们提供接口

然后,嘿嘿,我就用了 ctrl+f 神器搜索了一下secret_phase这个词
没想到这个接口竟然藏在每个阶段都在使用的phase_defused里面

最危险的地方就是最安全的地方???
由于过长这里只截取了一段用于推出接口的代码

00000000004015c4 <phase_defused>:4015f0:   be 19 26 40 00          mov    $0x402619,%esi4015f5:    bf 70 38 60 00          mov    $0x603870,%edi4015fa:    e8 f1 f5 ff ff          callq  400bf0 <__isoc99_sscanf@plt>4015ff:   83 f8 03                cmp    $0x3,%eax401602: 75 31                   jne    401635 <phase_defused+0x71>401604:    be 22 26 40 00          mov    $0x402622,%esi401609:    48 8d 7c 24 10          lea    0x10(%rsp),%rdi40160e:   e8 25 fd ff ff          callq  401338 <strings_not_equal>401613:  85 c0                   test   %eax,%eax401615: 75 1e                   jne    401635 <phase_defused+0x71>401617:    bf f8 24 40 00          mov    $0x4024f8,%edi40161c:    e8 ef f4 ff ff          callq  400b10 <puts@plt>401621:  bf 20 25 40 00          mov    $0x402520,%edi401626:    e8 e5 f4 ff ff          callq  400b10 <puts@plt>40162b:  b8 00 00 00 00          mov    $0x0,%eax401630: e8 0d fc ff ff          callq  401242 <secret_phase>401635:   bf 58 25 40 00          mov    $0x402558,%edi
(gdb) x/s 0x603870
0x603870 <input_strings+240>:   "1 0"
(gdb) x/s 0x402619
0x402619:       "%d %d %s"

充满好奇地看了看这两个地址的内容,发现,淦,这不就是phase_4的keys吗!

(gdb) x/s 0x402622
0x402622:       "DrEvil"

这时向后看,它将0x402622的内容和0x10(%rsp)进行了比较
看一下里面的内容。啊,这就有那味了,应该是要我们输入的开关,那么在哪输入呢…

啊哈!phase_4的keys再加上这个DrEvil就是三个输入,那应该就可以打开这个隐藏过程了
嘿嘿,我们来试一试!

Halfway there!
1 0 DrEvil
So you got that one.  Try this one.
ionefg
Good work!  On to the next...
4 3 2 1 6 5
Curses, you've found the secret phase!
But finding it and solving it are quite different...

_看来我们已经成功进入了,接下来是解密的时候了!!!

先看secret_phase

0000000000401242 <secret_phase>:401242:    53                      push   %rbx401243:  e8 56 02 00 00          callq  40149e <read_line>
Curses, you've found the secret phase!
But finding it and solving it are quite different...
6(gdb) info registers
rax            0x603960 6306144(gdb) x/s 0x603960
0x603960 <input_strings+480>:   "6"

利用gdb工具得出read_line将我们的输入存入%rax返回

  401248:    ba 0a 00 00 00          mov    $0xa,%edx40124d: be 00 00 00 00          mov    $0x0,%esi401252: 48 89 c7                mov    %rax,%rdi401255: e8 76 f9 ff ff          callq  400bd0 <strtol@plt>、

再次通过gdb工具调查strtol@plt的功能

Curses, you've found the secret phase!
But finding it and solving it are quite different...
66Breakpoint 1, 0x000000000040125a in secret_phase ()
(gdb) info registers
rax            0x42     66

可以看到该函数是将输入的字符串变成常数返回

  40125a:    48 89 c3                mov    %rax,%rbx40125d: 8d 40 ff                lea    -0x1(%rax),%eax401260:   3d e8 03 00 00          cmp    $0x3e8,%eax401265:   76 05                   jbe    40126c <secret_phase+0x2a>401267: e8 ce 01 00 00          callq  40143a <explode_bomb>

从这段代码可以得知输入的数字应该小于1001

  40126c:    89 de                   mov    %ebx,%esi40126e: bf f0 30 60 00          mov    $0x6030f0,%edi401273:    e8 8c ff ff ff          callq  401204 <fun7>401278:   83 f8 02                cmp    $0x2,%eax40127b: 74 05                   je     401282 <secret_phase+0x40>40127d: e8 b8 01 00 00          callq  40143a <explode_bomb>401282:   bf 38 24 40 00          mov    $0x402438,%edi401287:    e8 84 f8 ff ff          callq  400b10 <puts@plt>40128c:  e8 33 03 00 00          callq  4015c4 <phase_defused>401291:  5b                      pop    %rbx401292:  c3                      retq

可以看到只有fun7的返回值为2才不会引爆炸弹,所以我们重点研究它

这是secret_phase中调用的fun7

0000000000401204 <fun7>:401204:    48 83 ec 08             sub    $0x8,%rsp401208: 48 85 ff                test   %rdi,%rdi40120b: 74 2b                   je     401238 <fun7+0x34>40120d: 8b 17                   mov    (%rdi),%edx40120f:   39 f2                   cmp    %esi,%edx401211: 7e 0d                   jle    401220 <fun7+0x1c>401213: 48 8b 7f 08             mov    0x8(%rdi),%rdi401217:    e8 e8 ff ff ff          callq  401204 <fun7>40121c:   01 c0                   add    %eax,%eax40121e: eb 1d                   jmp    40123d <fun7+0x39>401220: b8 00 00 00 00          mov    $0x0,%eax401225: 39 f2                   cmp    %esi,%edx401227: 74 14                   je     40123d <fun7+0x39>401229: 48 8b 7f 10             mov    0x10(%rdi),%rdi40122d:   e8 d2 ff ff ff          callq  401204 <fun7>401232:   8d 44 00 01             lea    0x1(%rax,%rax,1),%eax401236: eb 05                   jmp    40123d <fun7+0x39>401238: b8 ff ff ff ff          mov    $0xffffffff,%eax40123d:  48 83 c4 08             add    $0x8,%rsp401241: c3                      retq

可以看到对于不同情况,rdi只有两个选项,即+16或者+8,这时候还没有头绪,就先用gdb康康这里面存储的内容叭

(gdb) x/ 0x6030f0
0x6030f0 <n1>:  0x24
(gdb) x/ 0x6030f8
0x6030f8 <n1+8>:        0x603110 <n21>
(gdb) x/ 0x603100
0x603100 <n1+16>:       0x603130 <n22>
(gdb) x/ 0x603110
0x603110 <n21>: 0x8
(gdb) x/ 0x603130
0x603130 <n22>: 0x32
(gdb) x/ 0x603118
0x603118 <n21+8>:       0x603190 <n31>
(gdb) x/ 0x603120
0x603120 <n21+16>:      0x603150 <n32>
(gdb) x/ 0x603130
0x603130 <n22>: 0x32
(gdb) x/ 0x603138
0x603138 <n22+8>:       0x603170 <n33>
(gdb) x/ 0x603140
0x603140 <n22+16>:      0x6031b0 <n34>
(gdb) x/20a 0x6030f0

这… 貌似是一颗二叉树???<21>代表第二层第一个结点???
我们来画一画叭(均为10进制)

汇编可以改写为

int fun7(rdi,int input)
{int value=(%rdi);if(value==0)return -1;if(%rdi>input){%rdi=%rdi+8;fun7(%rdi,input);return_value=2*return_value;return return_value;}else{if(%rdi==input){return_value=0;return return_value;}%rdi=%rdi+16;fun7(%rdi,input);return_value=1+2*return_value;return return_value;}
}

要让返回值等于2,只有在最后出现2(1+2 * 0)才可以。即先返回0,再返回 1+2 * return,再返回2 * return。
所以最外层的0x24一定大于输入的值,而最内层一定是与输入相等
中间一层必须小于输入,我们可以在树中看到36,8,22这个序列正好符合
所以keys应该就是22,我们来试一试!

Curses, you've found the secret phase!
But finding it and solving it are quite different...
22
Wow! You've defused the secret stage!
Congratulations! You've defused the bomb!

NICE!!!
花费了数个夜晚,终于拆完了!
可惜我的头发啊啊啊啊!!!

二进制拆弹(炸弹炸掉了我的头发 T.T)相关推荐

  1. [逆向工程] 二进制拆弹Binary Bombs 快乐拆弹 详解

    二进制拆弹 binary bombs 教你最快速解题,成功拆弹 最近计算机基础课,的实验lab2,二进制拆弹,可以说是拆的我很快乐了(sub n, %hair) 此处头发减n 我刚开始做的时候很是懵逼 ...

  2. 二进制拆弹实验详解linux,拆解二进制炸弹

    拆解二进制炸弹 一.实验目的 1.理解C语言程序的机器级表示. 2.初步掌握GDB调试器的用法. 3.阅读C编译器生成的x86-64机器代码,理解不同控制结构生成的基本指令模式,过程的实现. 二. 实 ...

  3. 计算机系统二进制炸弹实验报告,二进制拿炸弹实验报告完整版.doc

    课程名称:计算机系统原理实验 实验课时:32课时 实验项目名称:BombLab二进制炸弹 实验材料:可执行文件bomb.源代码bomb.c.说明README 实验环境:Linux操作系统(安装虚拟机和 ...

  4. CSAPP lab2 二进制拆弹 binary bombs phase_6

    给出对应于7个阶段的7篇博客 phase_1  https://www.cnblogs.com/wkfvawl/p/10632044.html phase_2  https://www.cnblogs ...

  5. 汇编 二进制拆炸弹 r -t 3 -x 124

    文章目录 注 实验环境: 实验内容 实验步骤 调试过程及实验 总结 附录 注 QUT大二汇编最后一个作业:拆炸弹 通过两天中间隙来做这个实验,不能交个实验报告就完事了,毕竟是第一次接触逆向工程,老师为 ...

  6. 计算机系统基础实验:二进制拆弹实验

    一.实验目的: 学习并熟练使用 gdb 调试器和 objdump 理解汇编语言代码的行为或作用 提高阅读和理解汇编代码的能力 二.实验要求 实验共包括七个阶段,每个阶段考察机器级语言程序的不同方面,难 ...

  7. 二进制拆弹实验详解_Population Count算法-求二进制数中1的个数

    所谓Population Count算法,即是指计算一个二进制数中1的个数的算法.具体来说,就是任意给定一个无符号整数N,求N的二进制表示中1的个数,比如N = 5(0101)时,返回2:N = 15 ...

  8. 二进制炸弹(arm)

    x86上的二进制炸弹对于反汇编的练习来说还是比较经典的,由于网上有很多该程序的讲解,所以在此我打算写一下arm平台上的二进制拆炸弹这个游戏. 环境的搭建 由于是arm平台的环境,所以需要在linux环 ...

  9. 99. 激光炸弹(前缀和)

    题目:输入N个宝物的位置和价值,给出一个炸弹的炸弹范围(是一个正方形)的边长,找出一颗炸弹最多能炸掉的最大价值 题目中的宝物放在一个(x,y)的点上,而我们的炸弹是炸一个(r,r)的范围,所以如果一个 ...

最新文章

  1. Nginx网站常见的跳转配置实例
  2. 色彩缤纷的python(改变字体颜色及样式)
  3. 4.4 使用STM32控制MC20进行GPS帧数据解析
  4. undefined reference to '__gxx_personality_v0'
  5. Spring配置文件约束头
  6. 前端学习(2502):vue指令v-if
  7. Python中文编码 - Python零基础入门教程
  8. BlueIdea 7周年 北京欢天喜地大聚会
  9. 支付宝集五福下周一开始;iPhone 面世 13 周年;Laravel 6.10.0 发布 | 极客头条
  10. VS2015 vs2017 密钥
  11. 图像的上采样与下采样
  12. python适合创业吗-python创业
  13. 高质量程序设计指南(笔记)
  14. Zinc 全文搜索引擎Elasticsearch轻量级替代品
  15. ppt学习06——排版
  16. 使用飞桨PaddleHub实现将视频动作转化为皮影戏
  17. WPS画报的电脑壁纸怎么下载
  18. 嵌入式uClinux及其应用开发(1)
  19. 工作环境搭建CheckList
  20. 【机器学习开放项目】NBA统计数据分析

热门文章

  1. CAT实时监控预警系统
  2. PDPS软件:机器人行走轴虚拟仿真操作方法,即外部轴添加与配置
  3. BOSS直聘自动投简历聊天机器人的实现过程
  4. 计算机基础知识(下)(操作系统简介)
  5. 《Java工程师修炼之道》学习笔记
  6. MATLAB图像处理-图像增强之彩色图像直方图均衡化(RGB通道和HSV通道两种)
  7. Echarts地图自定义图标Symbol同时动态更改图标进行切换显示
  8. 3DMAX - 使用编辑多边形的小技巧
  9. Android笔记本处理器,惠普或推Android笔记本:配Tegra处理器
  10. Java使用Netty实现Modbus-RTU通信协议