【笔记】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)
一些值得一提的点:
x/[NUM][SIZE][FORMAT] 0xbf
显示的是地址0xbf
存的值(Examine (4-byte) word starting at address
0xbf)x/w $rsp
显示的是$rsp
存的地址存的值(Examine (4-byte) word starting at address in $rsp)g
、w
、h
、b
分别表示 8、4、2、1 byte;1 byte 的对应显示长度是 0x00 (4*2=8);- 靠近栈顶为低位,例如两个 byte
0xb0 0x27
的连接表示是0x27b0
%rsp
的单位是 byte,例如0xc(%rsp)
存的地址存的值是 0x01(从 0 开始往后数到 12,即第 13 个byte)- 不同的数据类型在栈上的位置当然不一定是均匀且有序的,例如此处输入的
1 a 3
分别存储在0xc($rsp) 0x7($rsp) 0x8($rsp)
- 若要查看输入数据的实际存储地址,可以通过查看栈找到输入数据,再通过查看对应位置栈存储的值得到实际地址;或者在执行
<ssanf>
之前,查看寄存器%rdx
、%rcx
、r8
等调用者保存寄存器,其顺次对应保存着输入数据将要放置的地址
# 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] = 31
且 A[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 y
,x
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 y
,x
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...