CS:APP Bomb Lab

来做大名鼎鼎的Bomb Lab了。
实验材料在http://csapp.cs.cmu.edu/3e/labs.html

bomb

准备

Bomb Lab handout

一开始我们手上的材料,README文件里面没有内容,.c文件中是炸弹的源代码和一些补充说明,缺少两个头文件导致无法编译,还有一个可执行文件,作为逆向工程的对象。

使用命令

objdump -d bomb > bomb.asm

得到bomb可执行代码段的汇编代码。

bomb.asm

粗略浏览一遍整个汇编代码,找到main中和我们实验有关的一段:

  400e32:   e8 67 06 00 00          callq  40149e <read_line>
  400e37:   48 89 c7                mov    %rax,%rdi
  400e3a:   e8 a1 00 00 00          callq  400ee0 <phase_1>
  400e3f:   e8 80 07 00 00          callq  4015c4 <phase_defused>
  400e44:   bf a8 23 40 00          mov    $0x4023a8,%edi
  400e49:   e8 c2 fc ff ff          callq  400b10 <puts@plt>
  400e4e:   e8 4b 06 00 00          callq  40149e <read_line>
  400e53:   48 89 c7                mov    %rax,%rdi
  400e56:   e8 a1 00 00 00          callq  400efc <phase_2>
  400e5b:   e8 64 07 00 00          callq  4015c4 <phase_defused>
  400e60:   bf ed 22 40 00          mov    $0x4022ed,%edi
  400e65:   e8 a6 fc ff ff          callq  400b10 <puts@plt>
  400e6a:   e8 2f 06 00 00          callq  40149e <read_line>
  400e6f:   48 89 c7                mov    %rax,%rdi
  400e72:   e8 cc 00 00 00          callq  400f43 <phase_3>
  400e77:   e8 48 07 00 00          callq  4015c4 <phase_defused>
  400e7c:   bf 0b 23 40 00          mov    $0x40230b,%edi
  400e81:   e8 8a fc ff ff          callq  400b10 <puts@plt>
  400e86:   e8 13 06 00 00          callq  40149e <read_line>
  400e8b:   48 89 c7                mov    %rax,%rdi
  400e8e:   e8 79 01 00 00          callq  40100c <phase_4>
  400e93:   e8 2c 07 00 00          callq  4015c4 <phase_defused>
  400e98:   bf d8 23 40 00          mov    $0x4023d8,%edi
  400e9d:   e8 6e fc ff ff          callq  400b10 <puts@plt>
  400ea2:   e8 f7 05 00 00          callq  40149e <read_line>
  400ea7:   48 89 c7                mov    %rax,%rdi
  400eaa:   e8 b3 01 00 00          callq  401062 <phase_5>
  400eaf:   e8 10 07 00 00          callq  4015c4 <phase_defused>
  400eb4:   bf 1a 23 40 00          mov    $0x40231a,%edi
  400eb9:   e8 52 fc ff ff          callq  400b10 <puts@plt>
  400ebe:   e8 db 05 00 00          callq  40149e <read_line>
  400ec3:   48 89 c7                mov    %rax,%rdi
  400ec6:   e8 29 02 00 00          callq  4010f4 <phase_6>
  400ecb:   e8 f4 06 00 00          callq  4015c4 <phase_defused>
  400ed0:   b8 00 00 00 00          mov    $0x0,%eax

这里的意思是每次读一行,然后执行对应阶段的函数,判断是否成功解除。

Phase 1

找到phase1的代码:

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

可以看到这里调用了<strings_not_equal>函数,根据结果来选择是否调用<explode_bomb>函数,而传入的两个参数为rsirdirsi是通过mov设置的立即数0x402400,而rdi从主函数中可以看到是<read_line>返回的结果。
这里我们可以合理猜测,phase 1读取一行字符串,传入字符串的地址和地址0x402400,两者进行比较,如果不相等则引爆炸弹。查看<strings_not_equal><string_length>的内部逻辑后佐证了想法。
<string_legnth>判断字符串长度是否相等,<strings_not_equal>判断两个字符串是否相等。

000000000040131b <string_length>:
  40131b:   80 3f 00                cmpb   $0x0,(%rdi)
  40131e:   74 12                   je     401332 <string_length+0x17>
  401320:   48 89 fa                mov    %rdi,%rdx
  401323:   48 83 c2 01             add    $0x1,%rdx
  401327:   89 d0                   mov    %edx,%eax
  401329:   29 f8                   sub    %edi,%eax
  40132b:   80 3a 00                cmpb   $0x0,(%rdx)
  40132e:   75 f3                   jne    401323 <string_length+0x8>
  401330:   f3 c3                   repz retq 
  401332:   b8 00 00 00 00          mov    $0x0,%eax
  401337:   c3                      retq   

0000000000401338 <strings_not_equal>:
  401338:   41 54                   push   %r12
  40133a:   55                      push   %rbp
  40133b:   53                      push   %rbx
  40133c:   48 89 fb                mov    %rdi,%rbx
  40133f:   48 89 f5                mov    %rsi,%rbp
  401342:   e8 d4 ff ff ff          callq  40131b <string_length>
  401347:   41 89 c4                mov    %eax,%r12d
  40134a:   48 89 ef                mov    %rbp,%rdi
  40134d:   e8 c9 ff ff ff          callq  40131b <string_length>
  401352:   ba 01 00 00 00          mov    $0x1,%edx
  401357:   41 39 c4                cmp    %eax,%r12d
  40135a:   75 3f                   jne    40139b <strings_not_equal+0x63>
  40135c:   0f b6 03                movzbl (%rbx),%eax
  40135f:   84 c0                   test   %al,%al
  401361:   74 25                   je     401388 <strings_not_equal+0x50>
  401363:   3a 45 00                cmp    0x0(%rbp),%al
  401366:   74 0a                   je     401372 <strings_not_equal+0x3a>
  401368:   eb 25                   jmp    40138f <strings_not_equal+0x57>
  40136a:   3a 45 00                cmp    0x0(%rbp),%al
  40136d:   0f 1f 00                nopl   (%rax)
  401370:   75 24                   jne    401396 <strings_not_equal+0x5e>
  401372:   48 83 c3 01             add    $0x1,%rbx
  401376:   48 83 c5 01             add    $0x1,%rbp
  40137a:   0f b6 03                movzbl (%rbx),%eax
  40137d:   84 c0                   test   %al,%al
  40137f:   75 e9                   jne    40136a <strings_not_equal+0x32>
  401381:   ba 00 00 00 00          mov    $0x0,%edx
  401386:   eb 13                   jmp    40139b <strings_not_equal+0x63>
  401388:   ba 00 00 00 00          mov    $0x0,%edx
  40138d:   eb 0c                   jmp    40139b <strings_not_equal+0x63>
  40138f:   ba 01 00 00 00          mov    $0x1,%edx
  401394:   eb 05                   jmp    40139b <strings_not_equal+0x63>
  401396:   ba 01 00 00 00          mov    $0x1,%edx
  40139b:   89 d0                   mov    %edx,%eax
  40139d:   5b                      pop    %rbx
  40139e:   5d                      pop    %rbp
  40139f:   41 5c                   pop    %r12
  4013a1:   c3                      retq   

那么我们要做的就是找到地址为0x402400处的字符串就行了。

使用命令:

objdump -h bomb

查看各个段的信息如下:


bomb:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000400238  0000000000400238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000400254  0000000000400254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000400274  0000000000400274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     00000030  0000000000400298  0000000000400298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000300  00000000004002c8  00000000004002c8  000002c8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       0000016d  00000000004005c8  00000000004005c8  000005c8  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  00000040  0000000000400736  0000000000400736  00000736  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000060  0000000000400778  0000000000400778  00000778  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     00000060  00000000004007d8  00000000004007d8  000007d8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rela.plt     00000288  0000000000400838  0000000000400838  00000838  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         0000000e  0000000000400ac0  0000000000400ac0  00000ac0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          000001c0  0000000000400ad0  0000000000400ad0  00000ad0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         00001614  0000000000400c90  0000000000400c90  00000c90  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .fini         00000009  00000000004022a4  00000000004022a4  000022a4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .rodata       000004e5  00000000004022b0  00000000004022b0  000022b0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame_hdr 00000104  0000000000402798  0000000000402798  00002798  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     00000454  00000000004028a0  00000000004028a0  000028a0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .init_array   00000008  0000000000602df8  0000000000602df8  00002df8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 18 .fini_array   00000008  0000000000602e00  0000000000602e00  00002e00  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .jcr          00000008  0000000000602e08  0000000000602e08  00002e08  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .dynamic      000001d0  0000000000602e10  0000000000602e10  00002e10  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 21 .got          00000008  0000000000602fe0  0000000000602fe0  00002fe0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got.plt      000000f0  0000000000602fe8  0000000000602fe8  00002fe8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000660  00000000006030e0  00000000006030e0  000030e0  2**5
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          000006d0  0000000000603740  0000000000603740  00003740  2**5
                  ALLOC
 25 .comment      00000053  0000000000000000  0000000000000000  00003740  2**0
                  CONTENTS, READONLY
 26 .debug_aranges 00000030  0000000000000000  0000000000000000  00003793  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 27 .debug_info   000007a3  0000000000000000  0000000000000000  000037c3  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 28 .debug_abbrev 0000021f  0000000000000000  0000000000000000  00003f66  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 29 .debug_line   00000161  0000000000000000  0000000000000000  00004185  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 30 .debug_str    000002f3  0000000000000000  0000000000000000  000042e6  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 31 .debug_loc    00000188  0000000000000000  0000000000000000  000045d9  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS

发现我们要找的0x402400.rodata段,再使用命令:

objdump -j .rodata -S bomb

单独查看.rodata的源代码。


bomb:     file format elf64-x86-64


Disassembly of section .rodata:

00000000004022b0 <_IO_stdin_used>:
  4022b0:       01 00 02 00 72 00 25 73 3a 20 45 72 72 6f 72 3a     ....r.%s: Error:
  4022c0:       20 43 6f 75 6c 64 6e 27 74 20 6f 70 65 6e 20 25      Couldn't open %
  4022d0:       73 0a 00 55 73 61 67 65 3a 20 25 73 20 5b 3c 69     s..Usage: %s [<i
  4022e0:       6e 70 75 74 5f 66 69 6c 65 3e 5d 0a 00 54 68 61     nput_file>]..Tha
  4022f0:       74 27 73 20 6e 75 6d 62 65 72 20 32 2e 20 20 4b     t's number 2.  K
  402300:       65 65 70 20 67 6f 69 6e 67 21 00 48 61 6c 66 77     eep going!.Halfw
  402310:       61 79 20 74 68 65 72 65 21 00 47 6f 6f 64 20 77     ay there!.Good w
  402320:       6f 72 6b 21 20 20 4f 6e 20 74 6f 20 74 68 65 20     ork!  On to the
  402330:       6e 65 78 74 2e 2e 2e 00 57 65 6c 63 6f 6d 65 20     next....Welcome
  402340:       74 6f 20 6d 79 20 66 69 65 6e 64 69 73 68 20 6c     to my fiendish l
  402350:       69 74 74 6c 65 20 62 6f 6d 62 2e 20 59 6f 75 20     ittle bomb. You
  402360:       68 61 76 65 20 36 20 70 68 61 73 65 73 20 77 69     have 6 phases wi
  402370:       74 68 00 00 00 00 00 00 77 68 69 63 68 20 74 6f     th......which to
  402380:       20 62 6c 6f 77 20 79 6f 75 72 73 65 6c 66 20 75      blow yourself u
  402390:       70 2e 20 48 61 76 65 20 61 20 6e 69 63 65 20 64     p. Have a nice d
  4023a0:       61 79 21 00 00 00 00 00 50 68 61 73 65 20 31 20     ay!.....Phase 1
  4023b0:       64 65 66 75 73 65 64 2e 20 48 6f 77 20 61 62 6f     defused. How abo
  4023c0:       75 74 20 74 68 65 20 6e 65 78 74 20 6f 6e 65 3f     ut the next one?
        ...
  4023d8:       53 6f 20 79 6f 75 20 67 6f 74 20 74 68 61 74 20     So you got that
  4023e8:       6f 6e 65 2e 20 20 54 72 79 20 74 68 69 73 20 6f     one.  Try this o
  4023f8:       6e 65 2e 00 00 00 00 00 42 6f 72 64 65 72 20 72     ne......Border r
  402408:       65 6c 61 74 69 6f 6e 73 20 77 69 74 68 20 43 61     elations with Ca
  402418:       6e 61 64 61 20 68 61 76 65 20 6e 65 76 65 72 20     nada have never
  402428:       62 65 65 6e 20 62 65 74 74 65 72 2e 00 00 00 00     been better.....
  402438:       57 6f 77 21 20 59 6f 75 27 76 65 20 64 65 66 75     Wow! You've defu
  402448:       73 65 64 20 74 68 65 20 73 65 63 72 65 74 20 73     sed the secret s
  402458:       74 61 67 65 21 00 66 6c 79 65 72 73 00 00 00 00     tage!.flyers....
        ...
  402470:       7c 0f 40 00 00 00 00 00 b9 0f 40 00 00 00 00 00     |.@.......@.....
  402480:       83 0f 40 00 00 00 00 00 8a 0f 40 00 00 00 00 00     ..@.......@.....
  402490:       91 0f 40 00 00 00 00 00 98 0f 40 00 00 00 00 00     ..@.......@.....
  4024a0:       9f 0f 40 00 00 00 00 00 a6 0f 40 00 00 00 00 00     ..@.......@.....

00000000004024b0 <array.3449>:
  4024b0:       6d 61 64 75 69 65 72 73 6e 66 6f 74 76 62 79 6c     maduiersnfotvbyl
  4024c0:       53 6f 20 79 6f 75 20 74 68 69 6e 6b 20 79 6f 75     So you think you
  4024d0:       20 63 61 6e 20 73 74 6f 70 20 74 68 65 20 62 6f      can stop the bo
  4024e0:       6d 62 20 77 69 74 68 20 63 74 72 6c 2d 63 2c 20     mb with ctrl-c,
  4024f0:       64 6f 20 79 6f 75 3f 00 43 75 72 73 65 73 2c 20     do you?.Curses,
  402500:       79 6f 75 27 76 65 20 66 6f 75 6e 64 20 74 68 65     you've found the
  402510:       20 73 65 63 72 65 74 20 70 68 61 73 65 21 00 00      secret phase!..
  402520:       42 75 74 20 66 69 6e 64 69 6e 67 20 69 74 20 61     But finding it a
  402530:       6e 64 20 73 6f 6c 76 69 6e 67 20 69 74 20 61 72     nd solving it ar
  402540:       65 20 71 75 69 74 65 20 64 69 66 66 65 72 65 6e     e quite differen
  402550:       74 2e 2e 2e 00 00 00 00 43 6f 6e 67 72 61 74 75     t.......Congratu
  402560:       6c 61 74 69 6f 6e 73 21 20 59 6f 75 27 76 65 20     lations! You've
  402570:       64 65 66 75 73 65 64 20 74 68 65 20 62 6f 6d 62     defused the bomb
  402580:       21 00 57 65 6c 6c 2e 2e 2e 00 4f 4b 2e 20 3a 2d     !.Well....OK. :-
  402590:       29 00 49 6e 76 61 6c 69 64 20 70 68 61 73 65 25     ).Invalid phase%
  4025a0:       73 0a 00 0a 42 4f 4f 4d 21 21 21 00 54 68 65 20     s...BOOM!!!.The
  4025b0:       62 6f 6d 62 20 68 61 73 20 62 6c 6f 77 6e 20 75     bomb has blown u
  4025c0:       70 2e 00 25 64 20 25 64 20 25 64 20 25 64 20 25     p..%d %d %d %d %
  4025d0:       64 20 25 64 00 45 72 72 6f 72 3a 20 50 72 65 6d     d %d.Error: Prem
  4025e0:       61 74 75 72 65 20 45 4f 46 20 6f 6e 20 73 74 64     ature EOF on std
  4025f0:       69 6e 00 47 52 41 44 45 5f 42 4f 4d 42 00 45 72     in.GRADE_BOMB.Er
  402600:       72 6f 72 3a 20 49 6e 70 75 74 20 6c 69 6e 65 20     ror: Input line
  402610:       74 6f 6f 20 6c 6f 6e 67 00 25 64 20 25 64 20 25     too long.%d %d %
  402620:       73 00 44 72 45 76 69 6c 00 67 72 65 61 74 77 68     s.DrEvil.greatwh
  402630:       69 74 65 2e 69 63 73 2e 63 73 2e 63 6d 75 2e 65     ite.ics.cs.cmu.e
  402640:       64 75 00 61 6e 67 65 6c 73 68 61 72 6b 2e 69 63     du.angelshark.ic
  402650:       73 2e 63 73 2e 63 6d 75 2e 65 64 75 00 6d 61 6b     s.cs.cmu.edu.mak
  402660:       6f 73 68 61 72 6b 2e 69 63 73 2e 63 73 2e 63 6d     oshark.ics.cs.cm
  402670:       75 2e 65 64 75 00 00 00 50 72 6f 67 72 61 6d 20     u.edu...Program
  402680:       74 69 6d 65 64 20 6f 75 74 20 61 66 74 65 72 20     timed out after
  402690:       25 64 20 73 65 63 6f 6e 64 73 0a 00 00 00 00 00     %d seconds......
  4026a0:       45 72 72 6f 72 3a 20 48 54 54 50 20 72 65 71 75     Error: HTTP requ
  4026b0:       65 73 74 20 66 61 69 6c 65 64 20 77 69 74 68 20     est failed with
  4026c0:       65 72 72 6f 72 20 25 64 3a 20 25 73 00 00 00 00     error %d: %s....
  4026d0:       47 45 54 20 2f 25 73 2f 73 75 62 6d 69 74 72 2e     GET /%s/submitr.
  4026e0:       70 6c 2f 3f 75 73 65 72 69 64 3d 25 73 26 6c 61     pl/?userid=%s&la
  4026f0:       62 3d 25 73 26 72 65 73 75 6c 74 3d 25 73 26 73     b=%s&result=%s&s
  402700:       75 62 6d 69 74 3d 73 75 62 6d 69 74 20 48 54 54     ubmit=submit HTT
  402710:       50 2f 31 2e 30 0d 0a 0d 0a 00 00 00 00 00 00 00     P/1.0...........
  402720:       45 72 72 6f 72 3a 20 55 6e 61 62 6c 65 20 74 6f     Error: Unable to
  402730:       20 63 6f 6e 6e 65 63 74 20 74 6f 20 73 65 72 76      connect to serv
  402740:       65 72 20 25 73 00 00 00 25 25 25 30 32 58 00 25     er %s...%%%02X.%
  402750:       73 20 25 64 20 25 5b 61 2d 7a 41 2d 7a 20 5d 00     s %d %[a-zA-z ].
  402760:       63 68 61 6e 67 65 6d 65 2e 69 63 73 2e 63 73 2e     changeme.ics.cs.
  402770:       63 6d 75 2e 65 64 75 00 0a 41 55 54 4f 52 45 53     cmu.edu..AUTORES
  402780:       55 4c 54 5f 53 54 52 49 4e 47 3d 25 73 0a 00 63     ULT_STRING=%s..c
  402790:       73 61 70 70 00                                      sapp.

找到地址0x402400开始的字符串就得到了答案:Border relations with Canada have never been better.

当然有更简单的方法:在gdb中使用x/s 0x402400直接就能得到答案,上面的做法能够对整个程序各段有个粗略的了解,后面的题目会使用gdb直接查看所需要的信息。

phase 2

0000000000400efc <phase_2>:
  400efc:   55                      push   %rbp
  400efd:   53                      push   %rbx
  400efe:   48 83 ec 28             sub    $0x28,%rsp
  400f02:   48 89 e6                mov    %rsp,%rsi
  400f05:   e8 52 05 00 00          callq  40145c <read_six_numbers>
  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),%eax
  400f1a:   01 c0                   add    %eax,%eax
  400f1c:   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,%rbx
  400f29:   48 39 eb                cmp    %rbp,%rbx
  400f2c:   75 e9                   jne    400f17 <phase_2+0x1b>
  400f2e:   eb 0c                   jmp    400f3c <phase_2+0x40>
  400f30:   48 8d 5c 24 04          lea    0x4(%rsp),%rbx
  400f35:   48 8d 6c 24 18          lea    0x18(%rsp),%rbp
  400f3a:   eb db                   jmp    400f17 <phase_2+0x1b>
  400f3c:   48 83 c4 28             add    $0x28,%rsp
  400f40:   5b                      pop    %rbx
  400f41:   5d                      pop    %rbp
  400f42:   c3                      retq   

主要逻辑就是:首先读入六个数字存入栈中,然后第一个和0x1进行比较,如果不等直接结束。
如果相等,那么栈指针向高地址移动八个字节,和前一个的两倍进行比较,如果不等就直接结束,以此类推。
那么答案就是以1为首,公比为2的等比数列:1 2 4 8 16 32

phase 3

首先贴出汇编代码:

0000000000400f43 <phase_3>:
  400f43:   48 83 ec 18             sub    $0x18,%rsp
  400f47:   48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
  400f4c:   48 8d 54 24 08          lea    0x8(%rsp),%rdx
  400f51:   be cf 25 40 00          mov    $0x4025cf,%esi
  400f56:   b8 00 00 00 00          mov    $0x0,%eax
  400f5b:   e8 90 fc ff ff          callq  400bf0 <__isoc99_sscanf@plt>
  400f60:   83 f8 01                cmp    $0x1,%eax
  400f63:   7f 05                   jg     400f6a <phase_3+0x27>
  400f65:   e8 d0 04 00 00          callq  40143a <explode_bomb>
  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
  400f75:   ff 24 c5 70 24 40 00    jmpq   *0x402470(,%rax,8)
  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
  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    

看到满屏幕的jmp,我的直觉就是这可能是个多分支结构,如switch或者是if...elseif...

运行后随意输入字符串,在400f5b也就是sscanf处打断点,观察返回值,汇编代码中的逻辑是如果返回值小于等于一,则结束。使用命令

man sscanf

查看sscanf函数的声明和注释,节选得到:

SYNOPSIS
       #include <stdio.h>

       int scanf(const char *format, ...);
       int fscanf(FILE *stream, const char *format, ...);
       int sscanf(const char *str, const char *format, ...);

DESCRIPTION
       The scanf() function reads input from the standard input stream stdin, fscanf() reads input  from  the  stream
       pointer stream, and sscanf() reads its input from the character string pointed to by str.

RETURN VALUE
       On success, these functions return the number of input items successfully matched and assigned;  this  can  be
       fewer than provided for, or even zero, in the event of an early matching failure.

意思是sscanf接受两个字符串,第一个是输入的字符串,第二个是读取的格式,就像我们平常使用的scanf的第一个格式字符串那样。
gdb中用x/s $rdix/s $rsi查看sscanf接受的两个字符串参数,第一个是我们的输入,第二个则是:

(gdb) x/s $rsi
0x4025cf:       "%d %d"

显然意思就是读两个整数。

继续往下看,发现两个整数分别存在了$rsp+0x8$rsp+0xc的位置。

  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
  400f75:   ff 24 c5 70 24 40 00    jmpq   *0x402470(,%rax,8)

这四行的逻辑是:首先用第一个输入数和0x7进行比较,如果大于的话,跳到0x400fad也就是引爆炸弹的位置,否则跳到0x402470+0x8*%rax的位置中的那个值,注意这里是一个间接寻址,因为前面有个*
假设我们输入的第一个数是1,那么跳转的会是地址为0x402478处的值,用x/8 0x402478查看该位置的八个字节,结果为:

(gdb) x/8 0x402478
0x402478:       0xb9    0x0f    0x40    0x00    0x00    0x00    0x00    0x00

由于是小端,容易发现前三个字节形成一个跳转的地址:0x4000b9,查看附近的汇编代码:

  400fb9:   b8 37 01 00 00          mov    $0x137,%eax
  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   

这几行的逻辑是:用第二个数和0x137进行比较,如果不等就爆炸,等于就成功返回。那么答案已经很显然了,就是:1 311
当然这道题有多个解,因为是switch结构,大概第一个数从17都行吧,只要第二个数按照他的要求给出就成功了。

phase 4

汇编源码:

0000000000400fce <func4>:
  400fce:   48 83 ec 08             sub    $0x8,%rsp
  400fd2:   89 d0                   mov    %edx,%eax
  400fd4:   29 f0                   sub    %esi,%eax
  400fd6:   89 c1                   mov    %eax,%ecx
  400fd8:   c1 e9 1f                shr    $0x1f,%ecx
  400fdb:   01 c8                   add    %ecx,%eax
  400fdd:   d1 f8                   sar    %eax
  400fdf:   8d 0c 30                lea    (%rax,%rsi,1),%ecx
  400fe2:   39 f9                   cmp    %edi,%ecx
  400fe4:   7e 0c                   jle    400ff2 <func4+0x24>
  400fe6:   8d 51 ff                lea    -0x1(%rcx),%edx
  400fe9:   e8 e0 ff ff ff          callq  400fce <func4>
  400fee:   01 c0                   add    %eax,%eax
  400ff0:   eb 15                   jmp    401007 <func4+0x39>
  400ff2:   b8 00 00 00 00          mov    $0x0,%eax
  400ff7:   39 f9                   cmp    %edi,%ecx
  400ff9:   7d 0c                   jge    401007 <func4+0x39>
  400ffb:   8d 71 01                lea    0x1(%rcx),%esi
  400ffe:   e8 cb ff ff ff          callq  400fce <func4>
  401003:   8d 44 00 01             lea    0x1(%rax,%rax,1),%eax
  401007:   48 83 c4 08             add    $0x8,%rsp
  40100b:   c3                      retq   

000000000040100c <phase_4>:
  40100c:   48 83 ec 18             sub    $0x18,%rsp
  401010:   48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
  401015:   48 8d 54 24 08          lea    0x8(%rsp),%rdx
  40101a:   be cf 25 40 00          mov    $0x4025cf,%esi
  40101f:   b8 00 00 00 00          mov    $0x0,%eax
  401024:   e8 c7 fb ff ff          callq  400bf0 <__isoc99_sscanf@plt>
  401029:   83 f8 02                cmp    $0x2,%eax
  40102c:   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,%edx
  40103f:   be 00 00 00 00          mov    $0x0,%esi
  401044:   8b 7c 24 08             mov    0x8(%rsp),%edi
  401048:   e8 81 ff ff ff          callq  400fce <func4>
  40104d:   85 c0                   test   %eax,%eax
  40104f:   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,%rsp
  401061:   c3                      retq   

首先浏览了一下,发现phase_4调用了func4,然后fun4里面又调用了自己,这必然是个递归函数。
然后与上一题类似,在sscanf处读取他的第二个参数,发现同样也是"%d %d"读取两个整数,这两个整数的位置也是和上一题相同,分别在%rsp+0x8%rsp+0xc,然后看这几句:

  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,%edx
  40103f:   be 00 00 00 00          mov    $0x0,%esi
  401044:   8b 7c 24 08             mov    0x8(%rsp),%edi
  401048:   e8 81 ff ff ff          callq  400fce <func4>

将第一个数和0xe进行无符号的比较,只有小于或等于才继续进行,注意这里是无符号的比较,那么就将第一个数的范围限定为0x00xe,排除了较大的数和负数。然后设置了%edx%esi%edi,分别是fun4的三个参数,发现这里%rsp+0xc也就是第二个输入数并没有参与运算,继续往后看:

  40104d:   85 c0                   test   %eax,%eax
  40104f:   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,%rsp
  401061:   c3                      retq   

容易看出将fun4的返回值和0x0进行了比较,将%rsp+0xc也和0x0进行了比较,两者都相等时才正常返回,那么这里第二个输入数已经确定为0了,第一个输入数需要使得fun4返回0

回过头来看fun4,输入的三个参数已经确定分别为输入数100xe,这里一段杂乱无章的递归程序我没看出什么特征,只能仔细翻译为c语言如下:

int fun4(int a, int b, int c)
{
    int d = (int((unsigned(c - b) >> 15) + (c - b)) >> 1) + b;
    if (a < d)
        return 2 * fun4(a, b, d - 1);
    else if (d < a)
        return 2 * fun4(a, d + 1, c) + 1;
    return 0;
}

注意这里的逻辑右移和算数右移,由于数据范围过小,直接暴力跑出答案为0137。逐个试验后发现都成功了。

ps:

把这段c代码编译后和原汇编代码长得还挺像的。

phase 5

汇编代码:

0000000000401062 <phase_5>:
  401062:   53                      push   %rbx
  401063:   48 83 ec 20             sub    $0x20,%rsp
  401067:   48 89 fb                mov    %rdi,%rbx
  40106a:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  401071:   00 00 
  401073:   48 89 44 24 18          mov    %rax,0x18(%rsp)
  401078:   31 c0                   xor    %eax,%eax
  40107a:   e8 9c 02 00 00          callq  40131b <string_length>
  40107f:   83 f8 06                cmp    $0x6,%eax
  401082:   74 4e                   je     4010d2 <phase_5+0x70>
  401084:   e8 b1 03 00 00          callq  40143a <explode_bomb>
  401089:   eb 47                   jmp    4010d2 <phase_5+0x70>
  40108b:   0f b6 0c 03             movzbl (%rbx,%rax,1),%ecx
  40108f:   88 0c 24                mov    %cl,(%rsp)
  401092:   48 8b 14 24             mov    (%rsp),%rdx
  401096:   83 e2 0f                and    $0xf,%edx
  401099:   0f b6 92 b0 24 40 00    movzbl 0x4024b0(%rdx),%edx
  4010a0:   88 54 04 10             mov    %dl,0x10(%rsp,%rax,1)
  4010a4:   48 83 c0 01             add    $0x1,%rax
  4010a8:   48 83 f8 06             cmp    $0x6,%rax
  4010ac:   75 dd                   jne    40108b <phase_5+0x29>
  4010ae:   c6 44 24 16 00          movb   $0x0,0x16(%rsp)
  4010b3:   be 5e 24 40 00          mov    $0x40245e,%esi
  4010b8:   48 8d 7c 24 10          lea    0x10(%rsp),%rdi
  4010bd:   e8 76 02 00 00          callq  401338 <strings_not_equal>
  4010c2:   85 c0                   test   %eax,%eax
  4010c4:   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,%eax
  4010d7:   eb b2                   jmp    40108b <phase_5+0x29>
  4010d9:   48 8b 44 24 18          mov    0x18(%rsp),%rax
  4010de:   64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  4010e5:   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,%rsp
  4010f2:   5b                      pop    %rbx
  4010f3:   c3                      retq   

看到<strings_not_equal>后面跟着<explode_bomb>大概就猜到又是要比较两个字符串了。

  40107a:   e8 9c 02 00 00          callq  40131b <string_length>
  40107f:   83 f8 06                cmp    $0x6,%eax
  401082:   74 4e                   je     4010d2 <phase_5+0x70>
  401084:   e8 b1 03 00 00          callq  40143a <explode_bomb>

首先判断读入的字符串长度是否为6,不是的话引爆。

  40108b:   0f b6 0c 03             movzbl (%rbx,%rax,1),%ecx
  40108f:   88 0c 24                mov    %cl,(%rsp)
  401092:   48 8b 14 24             mov    (%rsp),%rdx
  401096:   83 e2 0f                and    $0xf,%edx
  401099:   0f b6 92 b0 24 40 00    movzbl 0x4024b0(%rdx),%edx
  4010a0:   88 54 04 10             mov    %dl,0x10(%rsp,%rax,1)
  4010a4:   48 83 c0 01             add    $0x1,%rax
  4010a8:   48 83 f8 06             cmp    $0x6,%rax
  4010ac:   75 dd                   jne    40108b <phase_5+0x29>

这里是一个循环,可以看出循环变量%rax16,每次将输入字符串中的一位取最低4位,找到栈中地址为0x4024b0+%rax的地方,将其中的值edx放入栈中%rsp+%rax+0x10的位置,也就是通过一个映射,将输入的字符最低4位作为偏移量,变换成另外一个字符串。

  4010ae:   c6 44 24 16 00          movb   $0x0,0x16(%rsp)
  4010b3:   be 5e 24 40 00          mov    $0x40245e,%esi
  4010b8:   48 8d 7c 24 10          lea    0x10(%rsp),%rdi
  4010bd:   e8 76 02 00 00          callq  401338 <strings_not_equal>
  4010c2:   85 c0                   test   %eax,%eax
  4010c4:   74 13                   je     4010d9 <phase_5+0x77>
  4010c6:   e8 6f 03 00 00          callq  40143a <explode_bomb>

最后再和0x40245e处的字符串进行比较,这一部分在前面的阶段中也出现过。我们可以先用x/s 0x40245e获取进行比较的常量字符串为:

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

然后同样用x/s 0x4024b0找到映射的那个数组:

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

逐个寻找每个字母的偏移量,并且使得我们输入的字符串最低四位与这个偏移量相等即可,一个可行的答案是:ionefg

phase 6

代码:

00000000004010f4 <phase_6>:
  4010f4:   41 56                   push   %r14
  4010f6:   41 55                   push   %r13
  4010f8:   41 54                   push   %r12
  4010fa:   55                      push   %rbp
  4010fb:   53                      push   %rbx
  4010fc:   48 83 ec 50             sub    $0x50,%rsp
  401100:   49 89 e5                mov    %rsp,%r13
  401103:   48 89 e6                mov    %rsp,%rsi
  401106:   e8 51 03 00 00          callq  40145c <read_six_numbers>
  40110b:   49 89 e6                mov    %rsp,%r14
  40110e:   41 bc 00 00 00 00       mov    $0x0,%r12d
  401114:   4c 89 ed                mov    %r13,%rbp
  401117:   41 8b 45 00             mov    0x0(%r13),%eax
  40111b:   83 e8 01                sub    $0x1,%eax
  40111e:   83 f8 05                cmp    $0x5,%eax
  401121:   76 05                   jbe    401128 <phase_6+0x34>
  401123:   e8 12 03 00 00          callq  40143a <explode_bomb>
  401128:   41 83 c4 01             add    $0x1,%r12d
  40112c:   41 83 fc 06             cmp    $0x6,%r12d
  401130:   74 21                   je     401153 <phase_6+0x5f>
  401132:   44 89 e3                mov    %r12d,%ebx
  401135:   48 63 c3                movslq %ebx,%rax
  401138:   8b 04 84                mov    (%rsp,%rax,4),%eax
  40113b:   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,%ebx
  401148:   83 fb 05                cmp    $0x5,%ebx
  40114b:   7e e8                   jle    401135 <phase_6+0x41>
  40114d:   49 83 c5 04             add    $0x4,%r13
  401151:   eb c1                   jmp    401114 <phase_6+0x20>
  401153:   48 8d 74 24 18          lea    0x18(%rsp),%rsi
  401158:   4c 89 f0                mov    %r14,%rax
  40115b:   b9 07 00 00 00          mov    $0x7,%ecx
  401160:   89 ca                   mov    %ecx,%edx
  401162:   2b 10                   sub    (%rax),%edx
  401164:   89 10                   mov    %edx,(%rax)
  401166:   48 83 c0 04             add    $0x4,%rax
  40116a:   48 39 f0                cmp    %rsi,%rax
  40116d:   75 f1                   jne    401160 <phase_6+0x6c>
  40116f:   be 00 00 00 00          mov    $0x0,%esi
  401174:   eb 21                   jmp    401197 <phase_6+0xa3>
  401176:   48 8b 52 08             mov    0x8(%rdx),%rdx
  40117a:   83 c0 01                add    $0x1,%eax
  40117d:   39 c8                   cmp    %ecx,%eax
  40117f:   75 f5                   jne    401176 <phase_6+0x82>
  401181:   eb 05                   jmp    401188 <phase_6+0x94>
  401183:   ba d0 32 60 00          mov    $0x6032d0,%edx
  401188:   48 89 54 74 20          mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:   48 83 c6 04             add    $0x4,%rsi
  401191:   48 83 fe 18             cmp    $0x18,%rsi
  401195:   74 14                   je     4011ab <phase_6+0xb7>
  401197:   8b 0c 34                mov    (%rsp,%rsi,1),%ecx
  40119a:   83 f9 01                cmp    $0x1,%ecx
  40119d:   7e e4                   jle    401183 <phase_6+0x8f>
  40119f:   b8 01 00 00 00          mov    $0x1,%eax
  4011a4:   ba d0 32 60 00          mov    $0x6032d0,%edx
  4011a9:   eb cb                   jmp    401176 <phase_6+0x82>
  4011ab:   48 8b 5c 24 20          mov    0x20(%rsp),%rbx
  4011b0:   48 8d 44 24 28          lea    0x28(%rsp),%rax
  4011b5:   48 8d 74 24 50          lea    0x50(%rsp),%rsi
  4011ba:   48 89 d9                mov    %rbx,%rcx
  4011bd:   48 8b 10                mov    (%rax),%rdx
  4011c0:   48 89 51 08             mov    %rdx,0x8(%rcx)
  4011c4:   48 83 c0 08             add    $0x8,%rax
  4011c8:   48 39 f0                cmp    %rsi,%rax
  4011cb:   74 05                   je     4011d2 <phase_6+0xde>
  4011cd:   48 89 d1                mov    %rdx,%rcx
  4011d0:   eb eb                   jmp    4011bd <phase_6+0xc9>
  4011d2:   48 c7 42 08 00 00 00    movq   $0x0,0x8(%rdx)
  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   

最后一个阶段太长了,于是偷了个懒,很多地方靠猜也猜出来了,整个流程分为许多过程:
一开始是读入6个数字,和之前一样,存在栈中,地址分别从%rsp%rsp+0x14

首先是一段二重循环,先看内循环:

  401135:   48 63 c3                movslq %ebx,%rax
  401138:   8b 04 84                mov    (%rsp,%rax,4),%eax
  40113b:   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,%ebx
  401148:   83 fb 05                cmp    $0x5,%ebx

这里是一段内部循环,每次将%rsp+4*%rax%rbp进行比较,这里的%rsp+4*%rax就是我们读入的数组,%rbp是当前遍历的数字。

  401114:   4c 89 ed                mov    %r13,%rbp
  401117:   41 8b 45 00             mov    0x0(%r13),%eax
  40111b:   83 e8 01                sub    $0x1,%eax
  40111e:   83 f8 05                cmp    $0x5,%eax
  401121:   76 05                   jbe    401128 <phase_6+0x34>
  401123:   e8 12 03 00 00          callq  40143a <explode_bomb>
  401128:   41 83 c4 01             add    $0x1,%r12d
  40112c:   41 83 fc 06             cmp    $0x6,%r12d
  401130:   74 21                   je     401153 <phase_6+0x5f>
  401132:   44 89 e3                mov    %r12d,%ebx
  401135:   48 63 c3                movslq %ebx,%rax
  401138:   8b 04 84                mov    (%rsp,%rax,4),%eax
  40113b:   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,%ebx
  401148:   83 fb 05                cmp    $0x5,%ebx
  40114b:   7e e8                   jle    401135 <phase_6+0x41>
  40114d:   49 83 c5 04             add    $0x4,%r13
  401151:   eb c1                   jmp    401114 <phase_6+0x20>

外层循环不断改变%rbp,结合在一起就是用一个二重循环判断输入的数字中必须两两不同,而且还要范围在16之间。

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

这里一段的作用是用常数7减去输入的各个数字。

再继续往下看:

  401176:   48 8b 52 08             mov    0x8(%rdx),%rdx
  40117a:   83 c0 01                add    $0x1,%eax
  40117d:   39 c8                   cmp    %ecx,%eax
  40117f:   75 f5                   jne    401176 <phase_6+0x82>
  401181:   eb 05                   jmp    401188 <phase_6+0x94>
  401183:   ba d0 32 60 00          mov    $0x6032d0,%edx
  401188:   48 89 54 74 20          mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:   48 83 c6 04             add    $0x4,%rsi
  401191:   48 83 fe 18             cmp    $0x18,%rsi
  401195:   74 14                   je     4011ab <phase_6+0xb7>
  401197:   8b 0c 34                mov    (%rsp,%rsi,1),%ecx
  40119a:   83 f9 01                cmp    $0x1,%ecx
  40119d:   7e e4                   jle    401183 <phase_6+0x8f>
  40119f:   b8 01 00 00 00          mov    $0x1,%eax
  4011a4:   ba d0 32 60 00          mov    $0x6032d0,%edx

第一行到第四行是一个小循环,每次将%eax加一,直到等于%ecx为止,同时还执行了mov 0x8(%rdx),%rdx的操作,这里非常重要,因为这句的意思是用自己位置偏移8后所指向的值代替自己,也就是这是一个指向下一个的指针,使用命令查看数据:

(gdb) x/16 0x6032d0
0x6032d0 <node1>:       0x4c    0x01    0x00    0x00    0x01    0x00    0x00    0x00
0x6032d8 <node1+8>:     0xe0    0x32    0x60    0x00    0x00    0x00    0x00    0x00

变量名<node1>和指向下一个地址的0x6032e0验证了猜想:这是一个链表。
再观察整个结构,发现%rcx是从%rsp所指向的位置开始,也就是我们输入的第一个数,遍历整个输入的六个数的。
在找到链表的第%rcx个数后,会放到栈上的0x20(%rsp,%rsi,2)处。
那么这段代码的意思就很明显了,根据我们的输入数字,依次暴力找到链表的那个位置,依次放到栈上连续的一些位置。
其实做到这里,已经猜到了一些答案了,既然我们的输入得是一到六,又两两不能相同,再结合上面的操作,不难猜到是要用这些数字对链表进行一个排序。

然后我直接跳到最后看:

  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>

这里也比较简单,依次对链表的前后两个元素进行比较,如果前者更大则继续。
查看链表各个元素的值:

(gdb) x/96 0x6032d0
0x6032d0 <node1>:       0x4c    0x01    0x00    0x00    0x01    0x00    0x00    0x00
0x6032d8 <node1+8>:     0xe0    0x32    0x60    0x00    0x00    0x00    0x00    0x00
0x6032e0 <node2>:       0xa8    0x00    0x00    0x00    0x02    0x00    0x00    0x00
0x6032e8 <node2+8>:     0xf0    0x32    0x60    0x00    0x00    0x00    0x00    0x00
0x6032f0 <node3>:       0x9c    0x03    0x00    0x00    0x03    0x00    0x00    0x00
0x6032f8 <node3+8>:     0x00    0x33    0x60    0x00    0x00    0x00    0x00    0x00
0x603300 <node4>:       0xb3    0x02    0x00    0x00    0x04    0x00    0x00    0x00
0x603308 <node4+8>:     0x10    0x33    0x60    0x00    0x00    0x00    0x00    0x00
0x603310 <node5>:       0xdd    0x01    0x00    0x00    0x05    0x00    0x00    0x00
0x603318 <node5+8>:     0x20    0x33    0x60    0x00    0x00    0x00    0x00    0x00
0x603320 <node6>:       0xbb    0x01    0x00    0x00    0x06    0x00    0x00    0x00
0x603328 <node6+8>:     0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00

按照从大到小的排序,答案应是3 4 5 6 1 2,因为前面被7减过,继续反推得到答案4 3 2 1 6 5

secret phase

最后还有一个秘密关卡,首先要找到进入这个密码关卡的方式。
直接在代码中搜索<secret_phase>,发现在<phase_defused>中调用到了这个函数。
而每次通过一关,都会调用这个<phase_defused>
代码:

00000000004015c4 <phase_defused>:
  4015c4:   48 83 ec 78             sub    $0x78,%rsp
  4015c8:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  4015cf:   00 00 
  4015d1:   48 89 44 24 68          mov    %rax,0x68(%rsp)
  4015d6:   31 c0                   xor    %eax,%eax
  4015d8:   83 3d 81 21 20 00 06    cmpl   $0x6,0x202181(%rip)        # 603760 <num_input_strings>
  4015df:   75 5e                   jne    40163f <phase_defused+0x7b>
  4015e1:   4c 8d 44 24 10          lea    0x10(%rsp),%r8
  4015e6:   48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
  4015eb:   48 8d 54 24 08          lea    0x8(%rsp),%rdx
  4015f0:   be 19 26 40 00          mov    $0x402619,%esi
  4015f5:   bf 70 38 60 00          mov    $0x603870,%edi
  4015fa:   e8 f1 f5 ff ff          callq  400bf0 <__isoc99_sscanf@plt>
  4015ff:   83 f8 03                cmp    $0x3,%eax
  401602:   75 31                   jne    401635 <phase_defused+0x71>
  401604:   be 22 26 40 00          mov    $0x402622,%esi
  401609:   48 8d 7c 24 10          lea    0x10(%rsp),%rdi
  40160e:   e8 25 fd ff ff          callq  401338 <strings_not_equal>
  401613:   85 c0                   test   %eax,%eax
  401615:   75 1e                   jne    401635 <phase_defused+0x71>
  401617:   bf f8 24 40 00          mov    $0x4024f8,%edi
  40161c:   e8 ef f4 ff ff          callq  400b10 <puts@plt>
  401621:   bf 20 25 40 00          mov    $0x402520,%edi
  401626:   e8 e5 f4 ff ff          callq  400b10 <puts@plt>
  40162b:   b8 00 00 00 00          mov    $0x0,%eax
  401630:   e8 0d fc ff ff          callq  401242 <secret_phase>
  401635:   bf 58 25 40 00          mov    $0x402558,%edi
  40163a:   e8 d1 f4 ff ff          callq  400b10 <puts@plt>
  40163f:   48 8b 44 24 68          mov    0x68(%rsp),%rax
  401644:   64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  40164b:   00 00 
  40164d:   74 05                   je     401654 <phase_defused+0x90>
  40164f:   e8 dc f4 ff ff          callq  400b30 <__stack_chk_fail@plt>
  401654:   48 83 c4 78             add    $0x78,%rsp
  401658:   c3                      retq  

仔细分析可以看到首先要将0x202181(%rip)0x6进行比较,在调试的过程中可以看出,这里的0x202181(%rip)其实就是关卡号。
然后调用了sscanf,有了前面的经验,直接找到两个字符串分别为:

(gdb) x/s 0x603870
0x603870 <input_strings+240>:   "1 0"
(gdb) x/s 0x402619
0x402619:       "%d %d %s"

这里需要读取三个,而第一个字符串中只有两个,怎么样使得变成三个呢。从地址入手,观察最先的那个表格,发现这一段地址在.bss段,而.bss段一般存放未初始化或者是初始化为0的全局变量。
gdb中观察附近的字符串,发现全是我们输入的字符串,那么就能猜出输入字符串就存放在这里,第四个输入的1 0和这里的结果对上了,验证了想法。

然后又是似曾相识的一个过程,调用<strings_not_equal>对两个字符串进行比较,其中一个可以用x/s 0x402622 直接得到:

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

另一个则是需要输入的字符串。
将答案的第四行修改为1 0 DrEvil成功进入秘密阶段。

0000000000401242 <secret_phase>:
  401242:   53                      push   %rbx
  401243:   e8 56 02 00 00          callq  40149e <read_line>
  401248:   ba 0a 00 00 00          mov    $0xa,%edx
  40124d:   be 00 00 00 00          mov    $0x0,%esi
  401252:   48 89 c7                mov    %rax,%rdi
  401255:   e8 76 f9 ff ff          callq  400bd0 <strtol@plt>
  40125a:   48 89 c3                mov    %rax,%rbx
  40125d:   8d 40 ff                lea    -0x1(%rax),%eax
  401260:   3d e8 03 00 00          cmp    $0x3e8,%eax
  401265:   76 05                   jbe    40126c <secret_phase+0x2a>
  401267:   e8 ce 01 00 00          callq  40143a <explode_bomb>
  40126c:   89 de                   mov    %ebx,%esi
  40126e:   bf f0 30 60 00          mov    $0x6030f0,%edi
  401273:   e8 8c ff ff ff          callq  401204 <fun7>
  401278:   83 f8 02                cmp    $0x2,%eax
  40127b:   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,%edi
  401287:   e8 84 f8 ff ff          callq  400b10 <puts@plt>
  40128c:   e8 33 03 00 00          callq  4015c4 <phase_defused>
  401291:   5b                      pop    %rbx
  401292:   c3                      retq   

进入后先是读取了一行字符串,然后调用了系统函数strtol将字符串转化为long,然后的要求是输入的数必须小于等于1001,设置参数%rdi0x6030f0%rsi为输入数后调用fun7,并且返回值必须为2不然就爆炸。

0000000000401204 <fun7>:
  401204:   48 83 ec 08             sub    $0x8,%rsp
  401208:   48 85 ff                test   %rdi,%rdi
  40120b:   74 2b                   je     401238 <fun7+0x34>
  40120d:   8b 17                   mov    (%rdi),%edx
  40120f:   39 f2                   cmp    %esi,%edx
  401211:   7e 0d                   jle    401220 <fun7+0x1c>
  401213:   48 8b 7f 08             mov    0x8(%rdi),%rdi
  401217:   e8 e8 ff ff ff          callq  401204 <fun7>
  40121c:   01 c0                   add    %eax,%eax
  40121e:   eb 1d                   jmp    40123d <fun7+0x39>
  401220:   b8 00 00 00 00          mov    $0x0,%eax
  401225:   39 f2                   cmp    %esi,%edx
  401227:   74 14                   je     40123d <fun7+0x39>
  401229:   48 8b 7f 10             mov    0x10(%rdi),%rdi
  40122d:   e8 d2 ff ff ff          callq  401204 <fun7>
  401232:   8d 44 00 01             lea    0x1(%rax,%rax,1),%eax
  401236:   eb 05                   jmp    40123d <fun7+0x39>
  401238:   b8 ff ff ff ff          mov    $0xffffffff,%eax
  40123d:   48 83 c4 08             add    $0x8,%rsp
  401241:   c3                      retq   

这一部分的代码比较短,也比较好读,下面调用了两次fun7说明这也是一个递归程序,而且观察得到%rsi的值在整个递归的过程中没有变化过,起到的只是一个比较的作用。
一开始还检测了一下%rdi是否为0,后面设置递归参数的时候用mov 0x8(%rdi),%rdi,自身加上一个偏移量的间接寻址代替自身,基本可以确定%rdi是一个指针,%rdi+0x8%rdi+0x10同样也是一个指针,看到这里基本已经猜出这个数据结构就是二叉树了,之后的寻找答案也就不难了,顺着左右儿子找一下就得到答案了:

(gdb) x/24x 0x6030f0
0x6030f0 <n1>:  0x24    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x6030f8 <n1+8>:        0x10    0x31    0x60    0x00    0x00    0x00    0x00    0x00
0x603100 <n1+16>:       0x30    0x31    0x60    0x00    0x00    0x00    0x00    0x00
(gdb) x/24x 0x603110
0x603110 <n21>: 0x08    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x603118 <n21+8>:       0x90    0x31    0x60    0x00    0x00    0x00    0x00    0x00
0x603120 <n21+16>:      0x50    0x31    0x60    0x00    0x00    0x00    0x00    0x00
(gdb) x/24x 0x603150
0x603150 <n32>: 0x16    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x603158 <n32+8>:       0x70    0x32    0x60    0x00    0x00    0x00    0x00    0x00
0x603160 <n32+16>:      0x30    0x32    0x60    0x00    0x00    0x00    0x00    0x00

答案是0x16,也就是22

总结

答案:

Border relations with Canada have never been better.
1 2 4 8 16 32
1 311
1 0 DrEvil
ionefg
4 3 2 1 6 5
22
成功通过.JPG

总体难度感觉没有上一章难,但是既有趣又有收获,不愧是cmu的实验。通过这几个实验不仅对程序的整个结构有了更多的了解,还通过逆向工程了解了许多变量和数据结构的机器级表示,熟悉了程序在实际运行时真实的情况,收获非常大。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容