拆除csapp二进制炸弹超详细的解析之phase_3

概述

接着 拆除csapp二进制炸弹超详细的解析之phase_2 继续解析phase_3 。

phase_3解析

cgdb3截图

同样地首先执行si命令:

112│ bomb.c:
113│ 88          input = read_line();
114├──> 0x0000000000400e6a <+202>:   callq  0x40149e <read_line>
115│
116│ 89          phase_3(input);
117│    0x0000000000400e6f <+207>:   mov    %rax,%rdi
118│    0x0000000000400e72 <+210>:   callq  0x400f43 <phase_3>
119│
120│ 90          phase_defused();
121│    0x0000000000400e77 <+215>:   callq  0x4015c4 <phase_defused>



                     Figure 3.1

Figure 3.1 中第114行读取我们的输入,返回值rax在第117行被复制给rdi.可以查看我们输入的内容:

(gdb) x /s $rax
0x603820 <input_strings+160>:   "I'm in phase_3 for test"

我们输入的内容是 I’m in phase_3 for test ,就是这个,没错。

接下来si命令进入第118行:

 1│ Dump of assembler code for function phase_3:
 2├──> 0x0000000000400f43 <+0>:     sub    $0x18,%rsp
 3│    0x0000000000400f47 <+4>:     lea    0xc(%rsp),%rcx
 4│    0x0000000000400f4c <+9>:     lea    0x8(%rsp),%rdx
 5│    0x0000000000400f51 <+14>:    mov    $0x4025cf,%esi
 6│    0x0000000000400f56 <+19>:    mov    $0x0,%eax
 7│    0x0000000000400f5b <+24>:    callq  0x400bf0 <__isoc99_sscanf@plt>
 8│    0x0000000000400f60 <+29>:    cmp    $0x1,%eax
 9│    0x0000000000400f63 <+32>:    jg     0x400f6a <phase_3+39>
10│    0x0000000000400f65 <+34>:    callq  0x40143a <explode_bomb>
11│    0x0000000000400f6a <+39>:    cmpl   $0x7,0x8(%rsp)
12│    0x0000000000400f6f <+44>:    ja     0x400fad <phase_3+106>
13│    0x0000000000400f71 <+46>:    mov    0x8(%rsp),%eax
14│    0x0000000000400f75 <+50>:    jmpq   *0x402470(,%rax,8)
15│    0x0000000000400f7c <+57>:    mov    $0xcf,%eax
16│    0x0000000000400f81 <+62>:    jmp    0x400fbe <phase_3+123>
17│    0x0000000000400f83 <+64>:    mov    $0x2c3,%eax
18│    0x0000000000400f88 <+69>:    jmp    0x400fbe <phase_3+123>
19│    0x0000000000400f8a <+71>:    mov    $0x100,%eax
20│    0x0000000000400f8f <+76>:    jmp    0x400fbe <phase_3+123>
21│    0x0000000000400f91 <+78>:    mov    $0x185,%eax
22│    0x0000000000400f96 <+83>:    jmp    0x400fbe <phase_3+123>
23│    0x0000000000400f98 <+85>:    mov    $0xce,%eax
24│    0x0000000000400f9d <+90>:    jmp    0x400fbe <phase_3+123>
25│    0x0000000000400f9f <+92>:    mov    $0x2aa,%eax
26│    0x0000000000400fa4 <+97>:    jmp    0x400fbe <phase_3+123>
27│    0x0000000000400fa6 <+99>:    mov    $0x147,%eax
28│    0x0000000000400fab <+104>:   jmp    0x400fbe <phase_3+123>
29│    0x0000000000400fad <+106>:   callq  0x40143a <explode_bomb>
30│    0x0000000000400fb2 <+111>:   mov    $0x0,%eax
31│    0x0000000000400fb7 <+116>:   jmp    0x400fbe <phase_3+123>
32│    0x0000000000400fb9 <+118>:   mov    $0x137,%eax
33│    0x0000000000400fbe <+123>:   cmp    0xc(%rsp),%eax
34│    0x0000000000400fc2 <+127>:   je     0x400fc9 <phase_3+134>
35│    0x0000000000400fc4 <+129>:   callq  0x40143a <explode_bomb>
36│    0x0000000000400fc9 <+134>:   add    $0x18,%rsp
37│    0x0000000000400fcd <+138>:   retq   
38│ End of assembler dump.



                   Figure 3.2

在 Figure 3.2 中第1行十六进制0x18等于十进制24, 所以第1行的结果是在栈中开辟24字节的空间。

接下来的第3行lea指令把rsp地址加十六进制c(十进制12)的结果放入rcx,注意是把地址编号放入rcx中,不是把地址编号里面的值放入rcx。
同样地第4行把rsp地址的值加上8的结果放入rdx中。

接下来的第5行 mov $0x4025cf,%esi ,又一次出现了常量地址,出现常量地址尤其要注意,看一下0x4025cf里面的内容:

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

第6行把eax的值置为0,第7行出现了sscanf调用,刚好和第5行的地址为$0x4025cf里面的内容相对应。

接下来的第8行,第9行,第10行比较重要了,因为牵涉到炸弹爆炸。第9行的jg在eax的值大于1时跳转到第10行explode_bomb函数的下一
行,刚好完美地跳过炸弹爆炸函数。结合第5行地址0x4025cf里面的两个%d,eax的值已经在第6行设置为0了,我们可以猜测sscanf的返回
值eax表示输入的数字个数,如果输入的数字个数少于1个就触发炸弹爆炸机制。

第11行的 cmpl $0x7,0x8(%rsp) ,比较第1个参数和7的大小,第12行的ja在第1个参数超过7时跳转到第29行执行炸弹爆炸函数,所以
第1个输入的数大小不能超过7,当小于7时执行第13行 mov 0x8(%rsp),%eax ,把第1个参数的值复制到eax中,第14行执行间接跳转
jmpq *0x402470(,%rax,8) ,跳转的地址根据公式计算,即dst = 0x402470 + 8 * rax 。

接下来的行到结尾出现了8次 jmp 0x400fbe <phase_3+123> ,很明显这就是c语言switch中的case语句,多路选择,只执行其中的一个。

结合前面说的第1个参数不能大于7,所以我们有了获取本关卡的答案思路,具体如下:

首先检查以0x402470处为起始地址的连续8个内存地址里面的内容:

(gdb) x /8g 0x402470
0x402470:       0x0000000000400f7c      0x0000000000400fb9
0x402480:       0x0000000000400f83      0x0000000000400f8a
0x402490:       0x0000000000400f91      0x0000000000400f98
0x4024a0:       0x0000000000400f9f      0x0000000000400fa6
(gdb)

输出的8个十六进制刚好对应下面的mov指令前的地址:

14│    0x0000000000400f75 <+50>:    jmpq   *0x402470(,%rax,8)
15│    0x0000000000400f7c <+57>:    mov    $0xcf,%eax              <<<----------- 0x402470的值,即第一个参数为0
16│    0x0000000000400f81 <+62>:    jmp    0x400fbe <phase_3+123>
17│    0x0000000000400f83 <+64>:    mov    $0x2c3,%eax             <<<------------0x402480的值,即第一个参数为2
18│    0x0000000000400f88 <+69>:    jmp    0x400fbe <phase_3+123>
19│    0x0000000000400f8a <+71>:    mov    $0x100,%eax             <<<------------0x402488的值,即第一个参数为3
20│    0x0000000000400f8f <+76>:    jmp    0x400fbe <phase_3+123>
21│    0x0000000000400f91 <+78>:    mov    $0x185,%eax             <<<------------0x402490的值,即第一个参数为4
22│    0x0000000000400f96 <+83>:    jmp    0x400fbe <phase_3+123>
23│    0x0000000000400f98 <+85>:    mov    $0xce,%eax              <<<------------0x402498的值,即第一个参数为5
24│    0x0000000000400f9d <+90>:    jmp    0x400fbe <phase_3+123>
25│    0x0000000000400f9f <+92>:    mov    $0x2aa,%eax             <<<------------0x4024a0的值,即第一个参数为6
26│    0x0000000000400fa4 <+97>:    jmp    0x400fbe <phase_3+123>
27│    0x0000000000400fa6 <+99>:    mov    $0x147,%eax             <<<------------0x4024a8的值,即第一个参数为7
28│    0x0000000000400fab <+104>:   jmp    0x400fbe <phase_3+123>
29│    0x0000000000400fad <+106>:   callq  0x40143a <explode_bomb>
30│    0x0000000000400fb2 <+111>:   mov    $0x0,%eax
31│    0x0000000000400fb7 <+116>:   jmp    0x400fbe <phase_3+123>
32│    0x0000000000400fb9 <+118>:   mov    $0x137,%eax             <<<----------- 0x402470的值,即第一个参数为1
33│    0x0000000000400fbe <+123>:   cmp    0xc(%rsp),%eax
34│    0x0000000000400fc2 <+127>:   je     0x400fc9 <phase_3+134>
35│    0x0000000000400fc4 <+129>:   callq  0x40143a <explode_bomb>
36│    0x0000000000400fc9 <+134>:   add    $0x18,%rsp
37│    0x0000000000400fcd <+138>:   retq
38│ End of assembler dump.

第15行0xcf十进制为207, 第32行0x137十进制为311, 第17行0x2c3十进制为707, 第19行0x100十进制为256,
第21行0x185十进制为389, 第23行0xce十进制为206, 第25行0x2aa十进制为682, 第27行0x147十进制为327。

所以可以得到本关卡的答案了:

一共是8组: (0,207), (1,311), (2,707), (3,256), (4,389), (5,206), (6,682),(7,327)

以上任意一组组合就是答案了,比如 3 256