来看phase5的汇编
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>
rdi
中存放你输入的字符串的首地址,将其存到rbx
,调用string_length
函数,检查字符串长度是否为6,不为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>
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>
跳转到4010d2
将eax清零,跳到40108b
,也是解开这一阶段的关键代码。
40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx
之前已经将我们输入的字符串的首地址存到了rbx
,rax
也清零了,所以这里将我们输入的第一个字符送到ecx
。40108f-401096将该字符的ASCII值与上0xf
。
打印内存0x4024b0可得
重要的是maduiersnfotvbyl
。401099这句指令,就是以与运算的结果为下标,从这串字符中拿一个字符,存到栈上,起始地址为rsp+0x10
(即4010a0这句指令)。
重复上述过程直到我们输入的所有字符都处理完,那么在rsp+0x10
处,已经有了长度为6的字符串。继续往下,容易看出,函数将比较rsp+0x10
处字符串和内存地址为0x40245e
的字符,如相等,则phase5通过。
打印该地址,可得该字符串为flyers
。这些字符在上面所提的那个数组中的下标为9,15,14,5,6,7。因此,我们需要输入字符x1x2x3x4x5x6
,满足x1 & 0xf = 9
x2 & 0xf = 15
…
所以对照ascii表可知,应输入ionefg
。这就是phase5的密码。