第三个炸弹
phase_3
的汇编代码比较长,我们一段一段看:
1sub $0x18,%rsp ;400f43
2lea 0xc(%rsp),%rcx ;400f47
3lea 0x8(%rsp),%rdx ;400f4c
4mov $0x4025cf,%esi ;400f51
5mov $0x0,%eax ;400f56
6call 400bf0 <__isoc99_sscanf@plt> ;400f5b
7cmp $0x1,%eax ;400f60
8jg 400f6a <phase_3+0x27> ;400f63
9call 40143a <explode_bomb> ;400f65
这段和phase_2
的逻辑一致。用x /s 0x4025cf
看一下格式化字符串:%d %d
,说明这段代码就是读取两个int分别放到0x8(%rsp)
和0xc(%rsp)
的位置,sscanf
之后也校验了一下是否成功读取到两个数字。
接下来的两行代码:
10cmpl $0x7,0x8(%rsp) ;400f6a
11ja 400fad <phase_3+0x6a> ;400f6f
意思是第一个数字和数字7进行比较,如果第一个数字大于7,则跳转到400fad
引爆炸弹(ja
的意思是Jump if Above)。
接下来的两行代码:
12mov 0x8(%rsp),%eax ;400f71
13jmp *0x402470(,%rax,8) ;400f75
将第一个数字放到%eax
中,因为第一个数字是4字节的int,所以用了%eax
而不是%rax
,然后进行跳转。跳转指令中*
的含义的C语言中的取内容符含义一致,也就是跳转到指针0x402470(,%rax,8)
指向的地方。
0x402470(,%rax,8)
的含义是disp(base,index,scale)
,表示base + disp + index * scale
,base
缺省为0。在mov 0x8(%rsp),%eax
中,%rax
的高32位会被补0,所以在第一个数字非负的情况下,这里的%rax
保存的就是第一个数字。在64位系统中一个指针占8个字节,所以scale
是8。
也就是说,这条指令会根据第一个数字,跳转到不同的地方执行指令。这是一个很明显的switch case
语句。
我们已经知道第一个数字的取值范围是0-7,所以只需要查看从0x402470
开始的8个指针分别指向哪里,就知道这个8个case分别对应什么了(8gx
:以x(十六进制)形式查看8个元素,每个元素是一个giant word(8字节)):
(gdb) x/8gx 0x402470
0x402470: 0x0000000000400f7c 0x0000000000400fb9
0x402480: 0x0000000000400f83 0x0000000000400f8a
0x402490: 0x0000000000400f91 0x0000000000400f98
0x4024a0: 0x0000000000400f9f 0x0000000000400fa6
好巧(不巧才怪了),对应的就是phase_3
接下来的一些代码:
14mov $0xcf,%eax ;400f7c 对应0
15jmp 400fbe <phase_3+0x7b> ;400f81
16mov $0x2c3,%eax ;400f83 对应2
17jmp 400fbe <phase_3+0x7b> ;400f88
18mov $0x100,%eax ;400f8a 对应3
19jmp 400fbe <phase_3+0x7b> ;400f8f
20mov $0x185,%eax ;400f91 对应4
21jmp 400fbe <phase_3+0x7b> ;400f96
22mov $0xce,%eax ;400f98 对应5
23jmp 400fbe <phase_3+0x7b> ;400f9d
24mov $0x2aa,%eax ;400f9f 对应6
25jmp 400fbe <phase_3+0x7b> ;400fa4
26mov $0x147,%eax ;400fa6 对应7
27jmp 400fbe <phase_3+0x7b> ;400fab
28call 40143a <explode_bomb> ;400fad
29mov $0x0,%eax ;400fb2
30jmp 400fbe <phase_3+0x7b> ;400fb7
31mov $0x137,%eax ;400fb9 对应1
32cmp 0xc(%rsp),%eax ;400fbe
33je 400fc9 <phase_3+0x86> ;400fc2
34call 40143a <explode_bomb> ;400fc4
35add $0x18,%rsp ;400fc9
36ret ;400fcd
可以看到所有case都是把一个数字放到%eax
中,然后跳转到400fbe
这条指令(1对应的这个case下面一条指令就是400fbe
,所以它不用跳转,顺序执行就行了),而这条指令以及之后几条指令的意思是:如果%eax
的值和第二个数字相等,就跳过炸弹引爆函数。
结合每个case中放入%eax
的数字,我们很容易就可以得到第一个数字和第二个数字正确的对应关系:
第一个数字 | 第二个数字 |
---|---|
0 | 0xcf = 12 * 16 + 15 = 207 |
1 | 0x137 = 1 * 256 + 3 * 16 + 7 = 311 |
2 | 0x2c3 = 707 |
3 | 0x100 = 256 |
4 | 0x185 = 389 |
5 | 0xce = 206 |
6 | 0x2aa = 682 |
7 | 0x147 = 327 |
随便挑选一组(例如3 256
)放到answer.txt
的第三行,然后./bomb answer.txt
验证:
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Phase 1 defused. How about the next one?
That's number 2. Keep going!
Halfway there!
BOOM!!!
The bomb has blown up.