【笔记】CSAPP - Bomb Lab

bomb1

in main

  4012df:	bf 88 30 40 00       	mov    $0x403088,%edi       # "Welcome to my fiendish little bomb. You have 6 phases with"
  4012e4:   e8 77 fd ff ff          callq  401060 <puts@plt>
  4012e9:   bf c8 30 40 00          mov    $0x4030c8,%edi       # "which to blow yourself up. Have a nice day!"
  4012ee:	e8 6d fd ff ff       	callq  401060 <puts@plt>
  4012f3:	e8 18 07 00 00       	callq  401a10 <read_line>
  4012f8:	48 89 c7             	mov    %rax,%rdi            # %rdi <- *(my_password)
  4012fb:	e8 ec 00 00 00       	callq  4013ec <phase_1>
  401300:	e8 39 08 00 00       	callq  401b3e <phase_defused>

in phase_1

00000000004013ec <phase_1>:
  4013ec:	48 83 ec 08          	sub    $0x8,%rsp
  4013f0:   be 50 31 40 00          mov    $0x403150,%esi       # %esi <- *("Why make trillions when we could make... billions?")
  4013f5:	e8 d1 04 00 00       	callq  4018cb <strings_not_equal>
  4013fa:	85 c0                	test   %eax,%eax
  4013fc:	75 05                	jne    401403 <phase_1+0x17># if <strings_not_equal> not euqal 0 then call <explode_bomb>
  4013fe:	48 83 c4 08          	add    $0x8,%rsp
  401402:	c3                   	retq   
  401403:	e8 a5 05 00 00       	callq  4019ad <explode_bomb>
  401408:	eb f4                	jmp    4013fe <phase_1+0x12>

in strings_not_equal

00000000004018cb <strings_not_equal>:       # return 1 if (%rdi) and (%rsi) not equal, otherwise return 0

password : Why make trillions when we could make... billions?

bomb2

in main

  401305:	bf f8 30 40 00       	mov    $0x4030f8,%edi       # "Phase 1 defused. How about the next one?"
  40130a:	e8 51 fd ff ff       	callq  401060 <puts@plt>
  40130f:	e8 fc 06 00 00       	callq  401a10 <read_line>
  401314:	48 89 c7             	mov    %rax,%rdi		    # %rdi <- *(my_password)
  401317:	e8 ee 00 00 00       	callq  40140a <phase_2>
  40131c:	e8 1d 08 00 00       	callq  401b3e <phase_defused>

in phase_2

000000000040140a <phase_2>:
  40140a:	53                   	push   %rbx
  40140b:	48 83 ec 20          	sub    $0x20,%rsp
  40140f:   48 89 e6                mov    %rsp,%rsi
  401412:   e8 ba 05 00 00          callq  4019d1 <read_six_numbers>
  401417:   83 3c 24 01             cmpl   $0x1,(%rsp)
  40141b:	75 07                	jne    401424 <phase_2+0x1a>
  40141d:	bb 01 00 00 00       	mov    $0x1,%ebx
  401422:   eb 0f                   jmp    401433 <phase_2+0x29>
  401424:   e8 84 05 00 00          callq  4019ad <explode_bomb>
  401429:   eb f2                   jmp    40141d <phase_2+0x13>
  40142b:   e8 7d 05 00 00          callq  4019ad <explode_bomb>
  401430:   83 c3 01                add    $0x1,%ebx
  401433:   83 fb 05                cmp    $0x5,%ebx
  401436:   7f 14                   jg     40144c <phase_2+0x42>
  401438:   48 63 d3                movslq %ebx,%rdx
  40143b:   8d 43 ff                lea    -0x1(%rbx),%eax
  40143e:   48 98                   cltq   
  401440:   8b 04 84                mov    (%rsp,%rax,4),%eax
  401443:   01 c0                   add    %eax,%eax
  401445:   39 04 94                cmp    %eax,(%rsp,%rdx,4)
  401448:   74 e6                   je     401430 <phase_2+0x26>
  40144a:   eb df                   jmp    40142b <phase_2+0x21>
  40144c:   48 83 c4 20             add    $0x20,%rsp
  401450:   5b                      pop    %rbx
  401451:   c3                      retq

观察到 <read_six_numbers>,所以在 bomb2 随便输入 6 个数字 1 2 3 4 5 6
运行 gdb,在 phase_2 设置断点,逐步执行到 <read_six_numbers> 刚好结束:

(gdb) b phase_2
Breakpoint 1 at 0x40140a: file phases.c, line 35.
(gdb) r
Starting program: /mnt/d/CSAPPLab/lab2/bomb496/bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Why make trillions when we could make... billions?
Phase 1 defused. How about the next one?
1 2 3 4 5 6

Breakpoint 1, phase_2 (input=0x4057d0 <input_strings+80> "1 2 3 4 5 6") at phases.c:35
35      phases.c: No such file or directory.
(gdb) x/20i $rip
=> 0x40140a <phase_2>:  push   %rbx
   0x40140b <phase_2+1>:        sub    $0x20,%rsp
   0x40140f <phase_2+5>:        mov    %rsp,%rsi
   0x401412 <phase_2+8>:        callq  0x4019d1 <read_six_numbers>
   0x401417 <phase_2+13>:       cmpl   $0x1,(%rsp)
   0x40141b <phase_2+17>:       jne    0x401424 <phase_2+26>
   ...
   0x401445 <phase_2+59>:       cmp    %eax,(%rsp,%rdx,4)
(gdb) n
40      in phases.c
(gdb) x/i $rip
=> 0x40140f <phase_2+5>:        mov    %rsp,%rsi
(gdb) n
42      in phases.c
(gdb) x/i $rip
=> 0x401417 <phase_2+13>:       cmpl   $0x1,(%rsp)
(gdb)

查看栈帧:

(gdb) x/10wd $rsp
0x7ffffffedf90: 1       2       3       4
0x7ffffffedfa0: 5       6       4200990 0
0x7ffffffedfb0: 4204464 0
(gdb)

栈顶顺次就是刚才读入的 6 个数字,查看接下来的程序:

(gdb) x/30i $rip
=> 0x401417 <phase_2+13>:       cmpl   $0x1,(%rsp)              # if M[%rsp] not equal 1
   0x40141b <phase_2+17>:       jne    0x401424 <phase_2+26>    # then call <explode_bomb>
   0x40141d <phase_2+19>:       mov    $0x1,%ebx                # ebx <- 0x1
   0x401422 <phase_2+24>:       jmp    0x401433 <phase_2+41>    # goto L3
   0x401424 <phase_2+26>:       callq  0x4019ad <explode_bomb>
   0x401429 <phase_2+31>:       jmp    0x40141d <phase_2+19>
   0x40142b <phase_2+33>:       callq  0x4019ad <explode_bomb>
# .L1:
   0x401430 <phase_2+38>:       add    $0x1,%ebx                # %ebx <- %ebx + 1
# .L3:
   0x401433 <phase_2+41>:       cmp    $0x5,%ebx                # if %ebx > 0x5
   0x401436 <phase_2+44>:       jg     0x40144c <phase_2+66>    # then goto L2
   0x401438 <phase_2+46>:       movslq %ebx,%rdx                # %rdx <- %ebx
   0x40143b <phase_2+49>:       lea    -0x1(%rbx),%eax          # %eax <- %rbx - 0x1
   0x40143e <phase_2+52>:       cltq
   0x401440 <phase_2+54>:       mov    (%rsp,%rax,4),%eax
   0x401443 <phase_2+57>:       add    %eax,%eax                # %eax <- M[%rsp + %rax * 4] * 2
                                                                # now , %eax = M[%rsp + (%rdx - 1) * 4] * 2
   0x401445 <phase_2+59>:       cmp    %eax,(%rsp,%rdx,4)       # if %eax equal M[%rsp + %rdx * 4]
   0x401448 <phase_2+62>:       je     0x401430 <phase_2+38>    # then goto L1
   0x40144a <phase_2+64>:       jmp    0x40142b <phase_2+33>    # else call <explode_bomb>
# .L2:
   0x40144c <phase_2+66>:       add    $0x20,%rsp               # return safely !
   0x401450 <phase_2+70>:       pop    %rbx
   0x401451 <phase_2+71>:       retq

分析程序(见注释),得知这 6 个数应满足的条件是:第 1 个数是 1,且每个数都是前一个的 2 倍
password : 1 2 4 8 16 32

bomb3

in main

  401321:	bf 3d 30 40 00       	mov    $0x40303d,%edi       # "That's number 2.  Keep going!"
  401326:	e8 35 fd ff ff       	callq  401060 <puts@plt>
  40132b:	e8 e0 06 00 00       	callq  401a10 <read_line>
  401330:	48 89 c7             	mov    %rax,%rdi            # %rdi <- *(my_password)
  401333:	e8 1a 01 00 00       	callq  401452 <phase_3>
  401338:	e8 01 08 00 00       	callq  401b3e <phase_defused>

in phase_3

观察输入函数附近,有:

   0x401465 <phase_3+19>:       mov    $0x4031ae,%esi
   0x40146a <phase_3+24>:       mov    $0x0,%eax
   0x40146f <phase_3+29>:       callq  0x401110 <__isoc99_sscanf@plt>

输入格式:

(gdb) x/s 0x4031ae
0x4031ae:       "%d %c %d"

随便输入 1 a 3,在 phase_3 设置断点:

That's number 2.  Keep going!
1 a 3

Breakpoint 3, phase_3 (input=0x405820 <input_strings+160> "1 a 2") at phases.c:62
62      in phases.c
(gdb) x/5i $rip
=> 0x401452 <phase_3>:  sub    $0x18,%rsp
   0x401456 <phase_3+4>:        lea    0x8(%rsp),%r8
   0x40145b <phase_3+9>:        lea    0x7(%rsp),%rcx
   0x401460 <phase_3+14>:       lea    0xc(%rsp),%rdx
   0x401465 <phase_3+19>:       mov    $0x4031ae,%esi
   ...

执行完 <__isoc99_sscanf@plt>,用不同长度输出栈:

(gdb) x/10gx $rsp
0x7ffffffedfa0: 0x61000000004027b0      0x0000000100000003
0x7ffffffedfb0: 0x0000000000000000      0x0000000000401338
0x7ffffffedfc0: 0x00000000004027b0      0x00007fffff5d40b3
0x7ffffffedfd0: 0x00007fffff7dd620      0x00007ffffffee0b8
0x7ffffffedfe0: 0x0000000100000000      0x00000000004012a6
(gdb) x/10wx $rsp
0x7ffffffedfa0: 0x004027b0      0x61000000      0x00000003      0x00000001
0x7ffffffedfb0: 0x00000000      0x00000000      0x00401338      0x00000000
0x7ffffffedfc0: 0x004027b0      0x00000000
(gdb) x/10hx $rsp
0x7ffffffedfa0: 0x27b0  0x0040  0x0000  0x6100  0x0003  0x0000  0x0001  0x0000
0x7ffffffedfb0: 0x0000  0x0000
(gdb) x/16bx $rsp
0x7ffffffedfa0: 0xb0    0x27    0x40    0x00    0x00    0x00    0x00    0x61
0x7ffffffedfa8: 0x03    0x00    0x00    0x00    0x01    0x00    0x00    0x00

观察,得到 %d %c %d 存放的地址在栈上分别是 0xc($rsp) 0x7($rsp) 0x8($rsp)
一些值得一提的点:

  1. x/[NUM][SIZE][FORMAT] 0xbf 显示的是地址 0xbf 存的值(Examine (4-byte) word starting at address
    0xbf)
  2. x/w $rsp 显示的是 $rsp 存的地址存的值(Examine (4-byte) word starting at address in $rsp)
  3. gwhb 分别表示 8、4、2、1 byte;1 byte 的对应显示长度是 0x00 (4*2=8);
  4. 靠近栈顶为低位,例如两个 byte 0xb0 0x27 的连接表示是 0x27b0
  5. %rsp 的单位是 byte,例如 0xc(%rsp) 存的地址存的值是 0x01(从 0 开始往后数到 12,即第 13 个byte)
  6. 不同的数据类型在栈上的位置当然不一定是均匀且有序的,例如此处输入的 1 a 3 分别存储在 0xc($rsp) 0x7($rsp) 0x8($rsp)
  7. 若要查看输入数据的实际存储地址,可以通过查看栈找到输入数据,再通过查看对应位置栈存储的值得到实际地址;或者在执行 <ssanf> 之前,查看寄存器 %rdx%rcxr8 等调用者保存寄存器,其顺次对应保存着输入数据将要放置的地址
# solution 1
(gdb) print /x ($rsp+0xc)
$1 = 0x7ffffffedfac
(gdb) print *(int *) 0x7ffffffedfac
$2 = 1
(gdb) print /x ($rsp+0x7)
$3 = 0x7ffffffedfa7
(gdb) print (char *) 0x7ffffffedfa7
$4 = 0x7ffffffedfa7 "a\003"     # a 的后面刚好就是 3

# solution 2
(gdb) x/i $rip
=> 0x40146f <phase_3+29>:       callq  0x401110 <__isoc99_sscanf@plt>
(gdb) info register
...
rcx            0x7ffffffedfa7      140737488281511
rdx            0x7ffffffedfac      140737488281516
...
r8             0x7ffffffedfa8      140737488281512
...

分析接下来的程序:

   0x40146f <phase_3+29>:       callq  0x401110 <__isoc99_sscanf@plt>
=> 0x401474 <phase_3+34>:       cmp    $0x2,%eax                # if %eax <= 0x2, which is the value <sscanf> returns
   0x401477 <phase_3+37>:       jle    0x40148f <phase_3+61>    # then call <explode_bomb>
   0x401479 <phase_3+39>:       mov    0xc(%rsp),%eax           # %eax <- M[%rsp + 0xc] , which is the first input number
   0x40147d <phase_3+43>:       cmp    $0x7,%eax                # if %eax > 0x7
   0x401480 <phase_3+46>:       ja     0x401590 <phase_3+318>   # then call <explode_bomb>
                                                                # now , $eax <= 0x7 should hold
   0x401486 <phase_3+52>:       mov    %eax,%eax
   0x401488 <phase_3+54>:       jmpq   *0x4031c0(,%rax,8)
   0x40148f <phase_3+61>:       callq  0x4019ad <explode_bomb>
   ...

注意到:

   0x401486 <phase_3+52>:       mov    %eax,%eax
   0x401488 <phase_3+54>:       jmpq   *0x4031c0(,%rax,8)

应当是一个跳转表 jt,输出:

(gdb) x/20wx 0x4031c0
0x4031c0:       0x00401496      0x00000000      0x004014b9      0x00000000
0x4031d0:       0x004014d9      0x00000000      0x004014fc      0x00000000
0x4031e0:       0x0040151c      0x00000000      0x00401539      0x00000000
0x4031f0:       0x00401556      0x00000000      0x00401573      0x00000000
0x403200 <array.3404>:  0x0000000a      0x00000002      0x0000000e      0x00000007

跳转注释如下:

   0x401488 <phase_3+54>:       jmpq   *0x4031c0(,%rax,8)       # goto *jt[index]
   0x40148f <phase_3+61>:       callq  0x4019ad <explode_bomb>
   0x401494 <phase_3+66>:       jmp    0x401479 <phase_3+39>
# .L0: if %rax = 0
   0x401496 <phase_3+68>:       cmpl   $0x88,0x8(%rsp)
   0x40149e <phase_3+76>:       jne    0x4014aa <phase_3+88>
   0x4014a0 <phase_3+78>:       mov    $0x6f,%eax
   0x4014a5 <phase_3+83>:       jmpq   0x40159a <phase_3+328>
   0x4014aa <phase_3+88>:       callq  0x4019ad <explode_bomb>
   0x4014af <phase_3+93>:       mov    $0x6f,%eax
   0x4014b4 <phase_3+98>:       jmpq   0x40159a <phase_3+328>
# .L1: if %rax = 1 
   0x4014b9 <phase_3+103>:      cmpl   $0x4e,0x8(%rsp)
   0x4014be <phase_3+108>:      jne    0x4014ca <phase_3+120>
   0x4014c0 <phase_3+110>:      mov    $0x6f,%eax
   0x4014c5 <phase_3+115>:      jmpq   0x40159a <phase_3+328>
   0x4014ca <phase_3+120>:      callq  0x4019ad <explode_bomb>
   0x4014cf <phase_3+125>:      mov    $0x6f,%eax
   0x4014d4 <phase_3+130>:      jmpq   0x40159a <phase_3+328>
# .L2: if %rax = 2
   0x4014d9 <phase_3+135>:      cmpl   $0xfc,0x8(%rsp)
   0x4014e1 <phase_3+143>:      jne    0x4014ed <phase_3+155>
   0x4014e3 <phase_3+145>:      mov    $0x6a,%eax
   0x4014e8 <phase_3+150>:      jmpq   0x40159a <phase_3+328>
   0x4014ed <phase_3+155>:      callq  0x4019ad <explode_bomb>
   0x4014f2 <phase_3+160>:      mov    $0x6a,%eax
   0x4014f7 <phase_3+165>:      jmpq   0x40159a <phase_3+328>
# .L3: if %rax = 3
   0x4014fc <phase_3+170>:      cmpl   $0x25d,0x8(%rsp)
   0x401504 <phase_3+178>:      jne    0x401510 <phase_3+190>
   ...

观察 .L0 :(%d %c %d 分别位于 0xc($rsp) 0x7($rsp) 0x8($rsp),下记为 x y z

# %rax <- x
# .L0: if %rax = 0 , now x = 0
   0x401496 <phase_3+68>:       cmpl   $0x88,0x8(%rsp)          # if z not equal 0x88
   0x40149e <phase_3+76>:       jne    0x4014aa <phase_3+88>    # then call <explode_bomb>
                                                                # now z = 0x88 = 136
   0x4014a0 <phase_3+78>:       mov    $0x6f,%eax               # %eax <- 0x6f
   0x4014a5 <phase_3+83>:       jmpq   0x40159a <phase_3+328>   # goto *0x40159a
   0x4014aa <phase_3+88>:       callq  0x4019ad <explode_bomb>
   ...
  40159a:	38 44 24 07          	cmp    %al,0x7(%rsp)        # if y not equal %al , where %rax = 0x6f
  40159e:	75 05                	jne    4015a5 <phase_3+0x153> # then call <explode_bomb>
                                                                # now y = 0x6f = 'o'
  4015a0:	48 83 c4 18          	add    $0x18,%rsp
  4015a4:	c3                   	retq                        # return safely !
  4015a5:	e8 03 04 00 00       	callq  4019ad <explode_bomb>
  4015aa:	eb f4                	jmp    4015a0 <phase_3+0x14e>

综上,该密码的一种可行解是:%d %c %d = 0 o 136
password : 0 o 136

bomb4

in main

  40133d:	bf 5b 30 40 00       	mov    $0x40305b,%edi       # "Halfway there!"
  401342:	e8 19 fd ff ff       	callq  401060 <puts@plt>
  401347:	e8 c4 06 00 00       	callq  401a10 <read_line>
  40134c:	48 89 c7             	mov    %rax,%rdi
  40134f:	e8 8a 02 00 00       	callq  4015de <phase_4>
  401354:	e8 e5 07 00 00       	callq  401b3e <phase_defused>

in phase_4

00000000004015de <phase_4>:
  4015de:	48 83 ec 18          	sub    $0x18,%rsp
  4015e2:   48 8d 4c 24 08          lea    0x8(%rsp),%rcx
  4015e7:   48 8d 54 24 0c          lea    0xc(%rsp),%rdx
  4015ec:   be 4f 33 40 00          mov    $0x40334f,%esi
  4015f1:	b8 00 00 00 00       	mov    $0x0,%eax
  4015f6:	e8 15 fb ff ff       	callq  401110 <__isoc99_sscanf@plt>
(gdb) x/s 0x40334f
0x40334f:       "%d %d"

随便输入 1 2,在 phase_4 设置断点,逐步执行到 <__isoc99_sscanf@plt> 刚好结束:

1 2

Breakpoint 1, phase_4 (input=0x405870 <input_strings+240> "1 2") at phases.c:160
160     phases.c: No such file or directory.
...
(gdb) x/5i $rip
=> 0x4015f1 <phase_4+19>:       mov    $0x0,%eax
   0x4015f6 <phase_4+24>:       callq  0x401110 <__isoc99_sscanf@plt>
   0x4015fb <phase_4+29>:       cmp    $0x2,%eax
   0x4015fe <phase_4+32>:       jne    0x40160d <phase_4+47>
   0x401600 <phase_4+34>:       mov    0xc(%rsp),%eax
(gdb) si
0x00000000004015f6      164     in phases.c
(gdb) n
165     in phases.c
(gdb) x/i $rip
=> 0x4015fb <phase_4+29>:       cmp    $0x2,%eax
(gdb) print /d $eax
$1 = 2
(gdb) x/5wx $rsp
0x7ffffffedfa0: 0x004027b0      0x00000000      0x00000002      0x00000001
0x7ffffffedfb0: 0x00000000
(gdb) x/20bx $rsp
0x7ffffffedfa0: 0xb0    0x27    0x40    0x00    0x00    0x00    0x00    0x00
0x7ffffffedfa8: 0x02    0x00    0x00    0x00    0x01    0x00    0x00    0x00
0x7ffffffedfb0: 0x00    0x00    0x00    0x00

读入 %d %d 记为 x y,分别位于 0xc(%rsp) 0x8(%rsp)

  4015f6:	e8 15 fb ff ff       	callq  401110 <__isoc99_sscanf@plt>
  4015fb:	83 f8 02                cmp    $0x2,%eax            # the return value of <sscanf> should equal 2
  4015fe:   75 0d                   jne    40160d <phase_4+0x2f>
  401600:   8b 44 24 0c             mov    0xc(%rsp),%eax       # %eax <- x
  401604:   85 c0                   test   %eax,%eax            # x >= 0 should hold
  401606:   78 05                   js     40160d <phase_4+0x2f>
  401608:   83 f8 0e                cmp    $0xe,%eax            # x <= 0xe should hold
  40160b:   7e 05                   jle    401612 <phase_4+0x34>
  40160d:   e8 9b 03 00 00          callq  4019ad <explode_bomb>
                                                                # now 0 <= x <= 0xe
  401612:   ba 0e 00 00 00          mov    $0xe,%edx            # %edx <- 0xe
  401617:   be 00 00 00 00          mov    $0x0,%esi            # %esi <- 0x0
  40161c:   8b 7c 24 0c             mov    0xc(%rsp),%edi       # %edi <- x
  401620:   e8 87 ff ff ff          callq  4015ac <func4>       # call <func4>
  401625:   83 f8 12                cmp    $0x12,%eax           # if %eax not equal 0x12
  401628:   75 07                   jne    401631 <phase_4+0x53> # then call <explode_bomb>
  40162a:   83 7c 24 08 12          cmpl   $0x12,0x8(%rsp)      # if y not equal 0x12
  40162f:   74 05                   je     401636 <phase_4+0x58> # then call <explode_bomb>
  401631:   e8 77 03 00 00          callq  4019ad <explode_bomb>
  401636:   48 83 c4 18             add    $0x18,%rsp
  40163a:   c3                      retq                        # return safely !

in func4
(沿用上文 x y

# x in %rdi
# initially %edx = 0xe , %esi = 0x0
00000000004015ac <func4>:
  4015ac:	53                   	push   %rbx
  4015ad:	89 d0                	mov    %edx,%eax
  4015af:	29 f0                	sub    %esi,%eax
  4015b1:	89 c3                	mov    %eax,%ebx
  4015b3:	c1 eb 1f             	shr    $0x1f,%ebx
  4015b6:	01 c3                	add    %eax,%ebx
  4015b8:	d1 fb                	sar    %ebx
  4015ba:	01 f3                	add    %esi,%ebx
# %eax <- %edx - %esi
# %ebx <- (%eax divide 2 round to zero) + %esi
  4015bc:	39 fb                	cmp    %edi,%ebx
  4015be:	7f 06                	jg     4015c6 <func4+0x1a>
  4015c0:	7c 10                	jl     4015d2 <func4+0x26>
  4015c2:	89 d8                	mov    %ebx,%eax
  4015c4:	5b                   	pop    %rbx
  4015c5:	c3                   	retq   
  4015c6:	8d 53 ff             	lea    -0x1(%rbx),%edx
  4015c9:	e8 de ff ff ff       	callq  4015ac <func4>
  4015ce:	01 c3                	add    %eax,%ebx
  4015d0:	eb f0                	jmp    4015c2 <func4+0x16>
  4015d2:	8d 73 01             	lea    0x1(%rbx),%esi
  4015d5:	e8 d2 ff ff ff       	callq  4015ac <func4>
  4015da:	01 c3                	add    %eax,%ebx
  4015dc:	eb e4                	jmp    4015c2 <func4+0x16>

看起来是个二分。注意到 func4 是个递归,但是会发现 func4 的值仅和 x 有关;通过 phase_4 可知,应满足 0 <= x <= 0xe && func4(x) == 0x12 && y == 0x12
枚举 x 即可。
password : 11 18

bomb5

000000000040163b <phase_5>:
  40163b:	48 83 ec 18             sub    $0x18,%rsp
  40163f:   48 8d 4c 24 08          lea    0x8(%rsp),%rcx
  401644:   48 8d 54 24 0c          lea    0xc(%rsp),%rdx
  401649:   be 4f 33 40 00          mov    $0x40334f,%esi
  40164e:   b8 00 00 00 00          mov    $0x0,%eax
  401653:   e8 b8 fa ff ff          callq  401110 <__isoc99_sscanf@plt>
  401658:   83 f8 01                cmp    $0x1,%eax
  40165b:   7e 32                   jle    40168f <phase_5+0x54>
(gdb) x/s 0x40334f
0x40334f:       "%d %d"

随便输入 1 2,在 phase_5 设置断点,执行完 <sscanf> 后查看栈:

(gdb) x/5i $rip
=> 0x401658 <phase_5+29>:       cmp    $0x1,%eax
   0x40165b <phase_5+32>:       jle    0x40168f <phase_5+84>
   0x40165d <phase_5+34>:       mov    0xc(%rsp),%eax
   0x401661 <phase_5+38>:       and    $0xf,%eax
   0x401664 <phase_5+41>:       mov    %eax,0xc(%rsp)
(gdb) x/5wx $rsp
0x7ffffffedfa0: 0x004027b0      0x00000000      0x00000002      0x00000001
0x7ffffffedfb0: 0x00000000

记读入 %d %d 分别为 x y,分别位于 0xc(%rsp) 0x8(%rsp)
查看接下来的指令:

(gdb) x/30i $rip
=> 0x401658 <phase_5+29>:       cmp    $0x1,%eax
   0x40165b <phase_5+32>:       jle    0x40168f <phase_5+84>
   0x40165d <phase_5+34>:       mov    0xc(%rsp),%eax
   0x401661 <phase_5+38>:       and    $0xf,%eax
   0x401664 <phase_5+41>:       mov    %eax,0xc(%rsp)           # x <- x & 0xf
   0x401668 <phase_5+45>:       mov    $0x0,%ecx                # %ecx <- 0x0
   0x40166d <phase_5+50>:       mov    $0x0,%edx                # %edx <- 0x0
# .L2:
   0x401672 <phase_5+55>:       mov    0xc(%rsp),%eax           # %eax <- x
   0x401676 <phase_5+59>:       cmp    $0xf,%eax                # if %eax equal 0xf
   0x401679 <phase_5+62>:       je     0x401696 <phase_5+91>    # then goto L1
   0x40167b <phase_5+64>:       add    $0x1,%edx                # %edx <- %edx + 0x1
   0x40167e <phase_5+67>:       cltq
   0x401680 <phase_5+69>:       mov    0x403200(,%rax,4),%eax   # %eax <- array[%rax]
# at 0x403200 : array[16] = {10, 2, 14, 7, 8, 12, 15, 11, 0, 4, 1, 13, 3, 9, 6, 5}
   0x401687 <phase_5+76>:       mov    %eax,0xc(%rsp)           # x <- %eax
   0x40168b <phase_5+80>:       add    %eax,%ecx                # %ecx <- %ecx + %eax
   0x40168d <phase_5+82>:       jmp    0x401672 <phase_5+55>    # goto L2
   0x40168f <phase_5+84>:       callq  0x4019ad <explode_bomb>
   0x401694 <phase_5+89>:       jmp    0x40165d <phase_5+34>
# .L1:
   0x401696 <phase_5+91>:       cmp    $0xf,%edx                # if %edx not equal 0xf
   0x401699 <phase_5+94>:       jne    0x4016a1 <phase_5+102>   # then call <explode_bomb>
   0x40169b <phase_5+96>:       cmp    %ecx,0x8(%rsp)           # if y equal %ecx
   0x40169f <phase_5+100>:      je     0x4016a6 <phase_5+107>   # then return safely !
   0x4016a1 <phase_5+102>:      callq  0x4019ad <explode_bomb>
   0x4016a6 <phase_5+107>:      add    $0x18,%rsp
   0x4016aa <phase_5+111>:      retq
(gdb) x/20wd 0x403200
0x403200 <array.3404>:  10      2       14      7
0x403210 <array.3404+16>:       8       12      15      11
0x403220 <array.3404+32>:       0       4       1       13
0x403230 <array.3404+48>:       3       9       6       5
0x403240:       2032168787      1948284271      1802398056      1970239776

显然是一个简单的循环程序,我们可以将其翻译成类似 C 语言:

const int array[16] = {10, 2, 14, 7, 8, 12, 15, 11, 0, 4, 1, 13, 3, 9, 6, 5};
// t in %ecx , i in %edx
void phase_5(int x, int y)
{
    x &= 15, t = 0, i = 0;
    while (x != 15) {
        i++, x = array[x], t += x;
    }
    if (i <> 15 || y != t) explode_bomb();
    return;
}

答案呼之欲出...
不想算的话,在循环开头、最后的判断地方打个断点,输出来就知道了
password : 5 115

bomb6

得分已经够了,还有其他课的坑没填,挖坑(


附加拆炸弹,同样只拆了 5 个(
这玩意是 ARM-A64 汇编,反正要用时再查,希望赶紧忘掉这玩意,免得和 X86 记混了...

bomb1

0000000000400f54 <phase_1>:
  400f54:	f81f0ffe 	str	x30, [sp, #-16]!
  400f58:	d0000001 	adrp	x1, 402000 <init_driver+0x58>
  400f5c:	910ee021 	add	x1, x1, #0x3b8                        // x1 = 0x4023b8
  400f60:	9400014f 	bl	40149c <strings_not_equal>
  400f64:	35000060 	cbnz	w0, 400f70 <phase_1+0x1c>
  400f68:	f84107fe 	ldr	x30, [sp], #16
  400f6c:	d65f03c0 	ret
  400f70:	9400018e 	bl	4015a8 <explode_bomb>
  400f74:	17fffffd 	b	400f68 <phase_1+0x14>
(gdb) x/s 0x4023b8
0x4023b8:       "Verbosity leads to unclear, inarticulate things."

Verbosity leads to unclear, inarticulate things.

bomb2

0000000000400f78 <phase_2>:
  400f78:	a9bd7bf3 	stp	x19, x30, [sp, #-48]!
  400f7c:	910063e1 	add	x1, sp, #0x18
  400f80:	94000193 	bl	4015cc <read_six_numbers>

设读入 A[0], A[1], ..., A[5]

  400f84:	b9401be0 	ldr	w0, [sp, #24]			              // w0 <- a[0]
  400f88:	37f80060 	tbnz	w0, #31, 400f94 <phase_2+0x1c>    // w0 == 31
  400f8c:	52800033 	mov	w19, #0x1
  400f90:	14000005 	b	400fa4 <phase_2+0x2c>
  400f94:	94000185 	bl	4015a8 <explode_bomb>
  400f98:	17fffffd 	b	400f8c <phase_2+0x14>
  400f9c:	94000183 	bl	4015a8 <explode_bomb>
  400fa0:	11000673 	add	w19, w19, #0x1			              // w19 <- i : 1...5
  400fa4:	7100167f 	cmp	w19, #0x5
  400fa8:	5400012c 	b.gt	400fcc <phase_2+0x54>
  400fac:	910063e0 	add	x0, sp, #0x18			
  400fb0:	b873d801 	ldr	w1, [x0, w19, sxtw #2]		          // w1 <- a[i]
  400fb4:	51000662 	sub	w2, w19, #0x1			              // w2 <- i-1
  400fb8:	b862d800 	ldr	w0, [x0, w2, sxtw #2]		          // w0 <- a[i-1]
  400fbc:	0b130000 	add	w0, w0, w19			                  // w0 <- w0 + i
  400fc0:	6b00003f 	cmp	w1, w0				                  // w1 == w0
  400fc4:	54fffee0 	b.eq	400fa0 <phase_2+0x28>
  400fc8:	17fffff5 	b	400f9c <phase_2+0x24>
  400fcc:	a8c37bf3 	ldp	x19, x30, [sp], #48
  400fd0:	d65f03c0 	ret

可知,A[0] = 31A[i] = A[i-1] + i

31 32 34 37 41 46

bomb3

  400fe0:	d0000001 	adrp	x1, 402000 <init_driver+0x58>
  400fe4:	910fc021 	add	x1, x1, #0x3f0                        // x1 = 0x4023F0
  400fe8:	97ffff36 	bl	400cc0 <__isoc99_sscanf@plt>
(gdb) x/s 0x4023F0
0x4023f0:       "%d %d"

设读入 x y

  400fe8:	97ffff36 	bl	400cc0 <__isoc99_sscanf@plt>
  400fec:	7100041f 	cmp	w0, #0x1
  400ff0:	5400020d 	b.le	401030 <phase_3+0x5c>
  400ff4:	b9401fe0 	ldr	w0, [sp, #28]
(gdb) b *0x400ff4
Breakpoint 1 at 0x400ff4: file phases.c, line 73.
...
233 666
...
Breakpoint 1, phase_3 (input=<optimized out>) at phases.c:73
73      phases.c: No such file or directory.
(gdb) si
0x0000000000400ff8      73      in phases.c
(gdb) print /d $w0
$1 = 233

x in [sp, #28]y in [sp, #24]

  400ff4:	b9401fe0 	ldr	w0, [sp, #28]				          // w0 <- x
  400ff8:	7100101f 	cmp	w0, #0x4				              // if x == 4
  400ffc:	540005e0 	b.eq	4010b8 <phase_3+0xe4>

x == 4

  4010b8:	52800000 	mov	w0, #0x0                   	          // w0 = 0
  4010bc:	17ffffdb 	b	401028 <phase_3+0x54>

w0 = 0

  401028:	110a4c00 	add	w0, w0, #0x293				          // w0 <- w0 + 0x293
  40102c:	1400001b 	b	401098 <phase_3+0xc4>

w0 = 0x293

  401098:	510a4c00 	sub	w0, w0, #0x293				          // w0 <- w0 - 0x293
  40109c:	110a4c00 	add	w0, w0, #0x293				          // w0 <- w0 + 0x293
  4010a0:	17fffff1 	b	401064 <phase_3+0x90>

w0 = 0x293

  401064:	510a4c00 	sub	w0, w0, #0x293				          // w0 <- w0 - 0x293

w0 = 0

  401068:	b9401fe1 	ldr	w1, [sp, #28]				          // w1 <- x
  40106c:	7100143f 	cmp	w1, #0x5				              // if w1 > 5 explode
  401070:	5400008c 	b.gt	401080 <phase_3+0xac>

x <= 5

  401074:	b9401be1 	ldr	w1, [sp, #24]				          // w1 <- y
  401078:	6b00003f 	cmp	w1, w0					              // if w0 == w1
  40107c:	54000040 	b.eq	401084 <phase_3+0xb0>
  401080:	9400014a 	bl	4015a8 <explode_bomb>
  401084:	f84207fe 	ldr	x30, [sp], #32				          // then return safely
  401088:	d65f03c0 	ret

综上,x == 4, y == 0 即可

4 0

bomb4

  40112c:	b0000001 	adrp	x1, 402000 <init_driver+0x58>
  401130:	910fc021 	add	x1, x1, #0x3f0                        // x1 = 0x4023F0
  401134:	97fffee3 	bl	400cc0 <__isoc99_sscanf@plt>
(gdb) x/s 0x4023F0
0x4023f0:       "%d %d"

设读入 x yx in [sp, #28]y in [sp, #24]

0000000000401120 <phase_4>:
  401120:	f81e0ffe 	str	x30, [sp, #-32]!
  401124:	910063e3 	add	x3, sp, #0x18
  401128:	910073e2 	add	x2, sp, #0x1c
  40112c:	b0000001 	adrp	x1, 402000 <init_driver+0x58>
  401130:	910fc021 	add	x1, x1, #0x3f0
  401134:	97fffee3 	bl	400cc0 <__isoc99_sscanf@plt>
  401138:	7100081f 	cmp	w0, #0x2
  40113c:	540000a1 	b.ne	401150 <phase_4+0x30>
  401140:	b9401fe0 	ldr	w0, [sp, #28]				          // w0 <- x
  401144:	37f80060 	tbnz	w0, #31, 401150 <phase_4+0x30>    // x != 0x31
  401148:	7100381f 	cmp	w0, #0xe				              // x < 0xe
  40114c:	5400004d 	b.le	401154 <phase_4+0x34>
  401150:	94000116 	bl	4015a8 <explode_bomb>
  401154:	528001c2 	mov	w2, #0xe	                          // w2 <- 0xe
  401158:	52800001 	mov	w1, #0x0                              // w1 <- 0x0
  40115c:	b9401fe0 	ldr	w0, [sp, #28]				          // w0 <- x
  401160:	97ffffdd 	bl	4010d4 <func4>
  401164:	7100141f 	cmp	w0, #0x5				              // return == 0x5
  401168:	54000081 	b.ne	401178 <phase_4+0x58>
  40116c:	b9401be0 	ldr	w0, [sp, #24]				          // w0 <- y
  401170:	7100141f 	cmp	w0, #0x5				              // y == 0x5
  401174:	54000040 	b.eq	40117c <phase_4+0x5c>
  401178:	9400010c 	bl	4015a8 <explode_bomb>
  40117c:	f84207fe 	ldr	x30, [sp], #32
  401180:	d65f03c0 	ret
00000000004010d4 <func4>:
  4010d4:	f81f0ffe 	str	x30, [sp, #-16]!
  4010d8:	4b010043 	sub	w3, w2, w1
  4010dc:	0b437c63 	add	w3, w3, w3, lsr #31
  4010e0:	0b830423 	add	w3, w1, w3, asr #1
  4010e4:	6b00007f 	cmp	w3, w0
  4010e8:	540000ac 	b.gt	4010fc <func4+0x28>
  4010ec:	5400010b 	b.lt	40110c <func4+0x38>  // b.tstop
  4010f0:	52800000 	mov	w0, #0x0                   	// #0
  4010f4:	f84107fe 	ldr	x30, [sp], #16
  4010f8:	d65f03c0 	ret
  4010fc:	51000462 	sub	w2, w3, #0x1
  401100:	97fffff5 	bl	4010d4 <func4>
  401104:	531f7800 	lsl	w0, w0, #1
  401108:	17fffffb 	b	4010f4 <func4+0x20>
  40110c:	11000461 	add	w1, w3, #0x1
  401110:	97fffff1 	bl	4010d4 <func4>
  401114:	531f7800 	lsl	w0, w0, #1
  401118:	11000400 	add	w0, w0, #0x1
  40111c:	17fffff6 	b	4010f4 <func4+0x20>

x < 0xe, y == 5 → bruteforce

x = 10, y = 5

bomb5

0000000000401184 <phase_5>:
  401184:	f81e0ffe 	str	x30, [sp, #-32]!
  401188:	910063e3 	add	x3, sp, #0x18
  40118c:	910073e2 	add	x2, sp, #0x1c
  401190:	b0000001 	adrp	x1, 402000 <init_driver+0x58>
  401194:	910fc021 	add	x1, x1, #0x3f0
  401198:	97fffeca 	bl	400cc0 <__isoc99_sscanf@plt>
(gdb) x/s 0x4023f0
0x4023f0:       "%d %d"

设读入 x yx in [sp, #28]y in [sp, #24]

  4011a4:	b9401fe0 	ldr	w0, [sp, #28]				          // w0 <- x
  4011a8:	12000c00 	and	w0, w0, #0xf				          // w0 <- x & 0xf
  4011ac:	b9001fe0 	str	w0, [sp, #28]				          // [sp, #28] <- x & 0xf
  4011b0:	52800003 	mov	w3, #0x0                   	          // #0	// w3 <- 0x0
  4011b4:	52800002 	mov	w2, #0x0                              // w2 <- 0x0
.L2:
  4011b8:	b9401fe1 	ldr	w1, [sp, #28]				          // w1 <- x & 0xf
  4011bc:	71003c3f 	cmp	w1, #0xf				              // if w1 == 0xf
  4011c0:	54000140 	b.eq	4011e8 <phase_5+0x64>             // goto L1
  4011c4:	11000442 	add	w2, w2, #0x1				          // w2 <- w2 + 1
  4011c8:	b0000000 	adrp	x0, 402000 <init_driver+0x58>
  4011cc:	91108000 	add	x0, x0, #0x420				          // x0 <- 0x402420
  4011d0:	b861d800 	ldr	w0, [x0, w1, sxtw #2]			      // w0 <- A[w1]
  4011d4:	b9001fe0 	str	w0, [sp, #28]				          // [sp, #28] <- w0
  4011d8:	0b000063 	add	w3, w3, w0				              // w3 <- w3 + w0
  4011dc:	17fffff7 	b	4011b8 <phase_5+0x34>			      // goto L2
  4011e0:	940000f2 	bl	4015a8 <explode_bomb>
  4011e4:	17fffff0 	b	4011a4 <phase_5+0x20>
.L1:
  4011e8:	71003c5f 	cmp	w2, #0xf				              // if w2 != 0xf
  4011ec:	54000081 	b.ne	4011fc <phase_5+0x78>             // then explode
  4011f0:	b9401be0 	ldr	w0, [sp, #24]				          // w0 <- y
  4011f4:	6b03001f 	cmp	w0, w3					              // if w0 == w3
  4011f8:	54000040 	b.eq	401200 <phase_5+0x7c>             // then return safely
  4011fc:	940000eb 	bl	4015a8 <explode_bomb>
  401200:	f84207fe 	ldr	x30, [sp], #32
  401204:	d65f03c0 	ret
(gdb) x/20wd 0x402420
0x402420 <array.4949>:  10      2       14      7
0x402430 <array.4949+16>:       8       12      15      11
0x402440 <array.4949+32>:       0       4       1       13
0x402450 <array.4949+48>:       3       9       6       5
0x402460:       2032168787      1948284271      1802398056      1970239776

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

伪代码:

x &= 0xf;
w3 = 0, w2 = 0;
while (x != 0xf) {
    w2++, w3 += A[x], x = A[x];
}
if (w2 != 0xf || w3 != y) explode();

易知,当初始 x = 5 时,循环中 x 依次为:
\(5\to 12\to 3\to 7\to 11\to 13\to 9\to 4\to 8\to 0\to 10\to 1\to 2\to 14\to 6\to 15\)
最终 w2 = 0xf, w3 = (0+1+...+15-5=)115,故 y = 115

x = 5, y = 115

演示

(gdb) r
Starting program: /home/stu_120L021220/test/bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Verbosity leads to unclear, inarticulate things.
Phase 1 defused. How about the next one?
31 32 34 37 41 46
That's number 2.  Keep going!
4 0
Halfway there!
10 5
So you got that one.  Try this one.
5 115
Good work!  On to the next...
posted @ 2022-04-02 22:16  zrkc  阅读(271)  评论(0编辑  收藏  举报