寒假学的时候没做,现在补票来做一下这个(看似)六阶段的炸弹程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| 00000000004015c4 <phase_defused>: 4015c4: 48 83 ec 78 sub $0x78,%rsp 4015c8: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 4015cf: 00 00 4015d1: 48 89 44 24 68 mov %rax,0x68(%rsp) 4015d6: 31 c0 xor %eax,%eax 4015d8: 83 3d 81 21 20 00 06 cmpl $0x6,0x202181(%rip) # 603760 <num_input_strings> 4015df: 75 5e jne 40163f <phase_defused+0x7b> 4015e1: 4c 8d 44 24 10 lea 0x10(%rsp),%r8 4015e6: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx 4015eb: 48 8d 54 24 08 lea 0x8(%rsp),%rdx 4015f0: be 19 26 40 00 mov $0x402619,%esi 4015f5: bf 70 38 60 00 mov $0x603870,%edi 4015fa: e8 f1 f5 ff ff callq 400bf0 <__isoc99_sscanf@plt> 4015ff: 83 f8 03 cmp $0x3,%eax 401602: 75 31 jne 401635 <phase_defused+0x71> 401604: be 22 26 40 00 mov $0x402622,%esi 401609: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi 40160e: e8 25 fd ff ff callq 401338 <strings_not_equal> 401613: 85 c0 test %eax,%eax 401615: 75 1e jne 401635 <phase_defused+0x71> 401617: bf f8 24 40 00 mov $0x4024f8,%edi 40161c: e8 ef f4 ff ff callq 400b10 <puts@plt> 401621: bf 20 25 40 00 mov $0x402520,%edi 401626: e8 e5 f4 ff ff callq 400b10 <puts@plt> 40162b: b8 00 00 00 00 mov $0x0,%eax 401630: e8 0d fc ff ff callq 401242 <secret_phase> 401635: bf 58 25 40 00 mov $0x402558,%edi 40163a: e8 d1 f4 ff ff callq 400b10 <puts@plt> 40163f: 48 8b 44 24 68 mov 0x68(%rsp),%rax 401644: 64 48 33 04 25 28 00 xor %fs:0x28,%rax 40164b: 00 00 40164d: 74 05 je 401654 <phase_defused+0x90> 40164f: e8 dc f4 ff ff callq 400b30 <__stack_chk_fail@plt> 401654: 48 83 c4 78 add $0x78,%rsp 401658: c3 retq 401659: 90 nop 40165a: 90 nop 40165b: 90 nop 40165c: 90 nop 40165d: 90 nop 40165e: 90 nop 40165f: 90 nop
|
Phase 1
1 2 3 4 5 6 7 8 9
| 0000000000400ee0 <phase_1>: 400ee0: 48 83 ec 08 sub $0x8,%rsp 400ee4: be 00 24 40 00 mov $0x402400,%esi 400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal> 400eee: 85 c0 test %eax,%eax 400ef0: 74 05 je 400ef7 <phase_1+0x17> 400ef2: e8 43 05 00 00 callq 40143a <explode_bomb> 400ef7: 48 83 c4 08 add $0x8,%rsp 400efb: c3 retq
|
似乎是和位于0x402400的一个字符串进行比较。
用 strings -t x ./bomb
打印所有字符串,找到如下一条:
1
| 2400 Border relations with Canada have never been better.
|
于是通过本阶段。
Phase 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 0000000000400efc <phase_2>: 400efc: 55 push %rbp 400efd: 53 push %rbx 400efe: 48 83 ec 28 sub $0x28,%rsp 400f02: 48 89 e6 mov %rsp,%rsi 400f05: e8 52 05 00 00 callq 40145c <read_six_numbers> 400f0a: 83 3c 24 01 cmpl $0x1,(%rsp) 400f0e: 74 20 je 400f30 <phase_2+0x34> 400f10: e8 25 05 00 00 callq 40143a <explode_bomb> 400f15: eb 19 jmp 400f30 <phase_2+0x34> 400f17: 8b 43 fc mov -0x4(%rbx),%eax 400f1a: 01 c0 add %eax,%eax 400f1c: 39 03 cmp %eax,(%rbx) 400f1e: 74 05 je 400f25 <phase_2+0x29> 400f20: e8 15 05 00 00 callq 40143a <explode_bomb> 400f25: 48 83 c3 04 add $0x4,%rbx 400f29: 48 39 eb cmp %rbp,%rbx 400f2c: 75 e9 jne 400f17 <phase_2+0x1b> 400f2e: eb 0c jmp 400f3c <phase_2+0x40> 400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx 400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp 400f3a: eb db jmp 400f17 <phase_2+0x1b> 400f3c: 48 83 c4 28 add $0x28,%rsp 400f40: 5b pop %rbx 400f41: 5d pop %rbp 400f42: c3 retq
|
似乎是先在栈上读入六个数字,然后首先检查第一个数字是不是1,然后进行一个循环。
循环初始条件在0x400f30处设置,%rbx为第二个数字地址,%rbp为第七个数字地址(实际上没有)。
循环体是0x400f17到0x400f20,检查%rbx的前一个数字乘以2后是否与%rbx当前所指数字相等。如果不相等就引爆,相等就进入循环条件判断部分。
循环条件判断部分是0x400f25到0x400f2e,让%rbx指向下一个数字以后和%rbp比较,如果一样说明循环结束,跳到函数结尾(0x400f3c);不一样说明循环继续,再次跳到循环体的开头0x400f17。
所以输入数字:1 2 4 8 16 32,通过本阶段。
Phase 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| 0000000000400f43 <phase_3>: 400f43: 48 83 ec 18 sub $0x18,%rsp 400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx 400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx 400f51: be cf 25 40 00 mov $0x4025cf,%esi 400f56: b8 00 00 00 00 mov $0x0,%eax 400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt> 400f60: 83 f8 01 cmp $0x1,%eax 400f63: 7f 05 jg 400f6a <phase_3+0x27> 400f65: e8 d0 04 00 00 callq 40143a <explode_bomb> 400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp) 400f6f: 77 3c ja 400fad <phase_3+0x6a> 400f71: 8b 44 24 08 mov 0x8(%rsp),%eax 400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8) 400f7c: b8 cf 00 00 00 mov $0xcf,%eax 400f81: eb 3b jmp 400fbe <phase_3+0x7b> 400f83: b8 c3 02 00 00 mov $0x2c3,%eax 400f88: eb 34 jmp 400fbe <phase_3+0x7b> 400f8a: b8 00 01 00 00 mov $0x100,%eax 400f8f: eb 2d jmp 400fbe <phase_3+0x7b> 400f91: b8 85 01 00 00 mov $0x185,%eax 400f96: eb 26 jmp 400fbe <phase_3+0x7b> 400f98: b8 ce 00 00 00 mov $0xce,%eax 400f9d: eb 1f jmp 400fbe <phase_3+0x7b> 400f9f: b8 aa 02 00 00 mov $0x2aa,%eax 400fa4: eb 18 jmp 400fbe <phase_3+0x7b> 400fa6: b8 47 01 00 00 mov $0x147,%eax 400fab: eb 11 jmp 400fbe <phase_3+0x7b> 400fad: e8 88 04 00 00 callq 40143a <explode_bomb> 400fb2: b8 00 00 00 00 mov $0x0,%eax 400fb7: eb 05 jmp 400fbe <phase_3+0x7b> 400fb9: b8 37 01 00 00 mov $0x137,%eax 400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax 400fc2: 74 05 je 400fc9 <phase_3+0x86> 400fc4: e8 71 04 00 00 callq 40143a <explode_bomb> 400fc9: 48 83 c4 18 add $0x18,%rsp 400fcd: c3 retq
|
开头先scanf(“%d %d”, %rsp+8, %rsp+c),读入两个数字到栈上。如果读取成功数小于2个则立刻引爆。(其实是调用了sscanf,但是差不多)
然后检查第一个数,如果作为无符号数大于7的话立刻引爆。
然后尝试跳转到 qword ptr \[rax\*8 + 0x402470]
,用gdb查看此处是啥:
1 2 3 4 5
| pwndbg> x/7gx 0x402470 0x402470: 0x0000000000400f7c 0x0000000000400fb9 0x402480: 0x0000000000400f83 0x0000000000400f8a 0x402490: 0x0000000000400f91 0x0000000000400f98 0x4024a0: 0x0000000000400f9f
|
可以发现是一些phase_3函数的地址。这些地址对应的指令都是一个格式,给%rax赋个值然后跳转到0x400fbe,把这个值和读入的第二个数进行比较,相同就正常ret(过关)。
所以这个阶段有8种解法(应该要换成十进制数):
0 0xcf
1 0x137
2 0x2c3
3 0x100
4 0x185
5 0xce
6 0x2aa
7 0x147
Phase 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| 000000000040100c <phase_4>: 40100c: 48 83 ec 18 sub $0x18,%rsp 401010: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx 401015: 48 8d 54 24 08 lea 0x8(%rsp),%rdx 40101a: be cf 25 40 00 mov $0x4025cf,%esi 40101f: b8 00 00 00 00 mov $0x0,%eax 401024: e8 c7 fb ff ff callq 400bf0 <__isoc99_sscanf@plt> 401029: 83 f8 02 cmp $0x2,%eax 40102c: 75 07 jne 401035 <phase_4+0x29> 40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp) 401033: 76 05 jbe 40103a <phase_4+0x2e> 401035: e8 00 04 00 00 callq 40143a <explode_bomb> 40103a: ba 0e 00 00 00 mov $0xe,%edx 40103f: be 00 00 00 00 mov $0x0,%esi 401044: 8b 7c 24 08 mov 0x8(%rsp),%edi 401048: e8 81 ff ff ff callq 400fce <func4> 40104d: 85 c0 test %eax,%eax 40104f: 75 07 jne 401058 <phase_4+0x4c> 401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp) 401056: 74 05 je 40105d <phase_4+0x51> 401058: e8 dd 03 00 00 callq 40143a <explode_bomb> 40105d: 48 83 c4 18 add $0x18,%rsp 401061: c3 retq 0000000000400fce <func4>: 400fce: 48 83 ec 08 sub $0x8,%rsp 400fd2: 89 d0 mov %edx,%eax 400fd4: 29 f0 sub %esi,%eax 400fd6: 89 c1 mov %eax,%ecx 400fd8: c1 e9 1f shr $0x1f,%ecx 400fdb: 01 c8 add %ecx,%eax 400fdd: d1 f8 sar %eax 400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx 400fe2: 39 f9 cmp %edi,%ecx 400fe4: 7e 0c jle 400ff2 <func4+0x24> 400fe6: 8d 51 ff lea -0x1(%rcx),%edx 400fe9: e8 e0 ff ff ff callq 400fce <func4> 400fee: 01 c0 add %eax,%eax 400ff0: eb 15 jmp 401007 <func4+0x39> 400ff2: b8 00 00 00 00 mov $0x0,%eax 400ff7: 39 f9 cmp %edi,%ecx 400ff9: 7d 0c jge 401007 <func4+0x39> 400ffb: 8d 71 01 lea 0x1(%rcx),%esi 400ffe: e8 cb ff ff ff callq 400fce <func4> 401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax 401007: 48 83 c4 08 add $0x8,%rsp 40100b: c3 retq
|
首先还是先scanf(“%d %d”, %rsp+8, %rsp+c),读入两个数字到栈上。如果读取成功数不是2个则立刻引爆。
然后比较第一个数和0xe,要小于等于0xe,否则立即引爆。
然后调用了func4((%rsp+8), 0, 0xe)并检查返回值是否为0,不是就引爆。
想要让func4返回值为0,则必须在0x400fe4处成功跳转到0x400ff2。这就要求:
(edx-esi最高位 + edx-esi) / 2 + esi == edi
其中只有edi是由我们自己控制的,所以计算上式得到edi应该为7。
返回后,比较第二个参数是否为0,不是就引爆。
然后本阶段就结束了,答案是7 0。
Phase 5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| pwndbg> disassemble phase_5 Dump of assembler code for function phase_5: 0x0000000000401062 <+0>: push rbx 0x0000000000401063 <+1>: sub rsp,0x20 0x0000000000401067 <+5>: mov rbx,rdi 0x000000000040106a <+8>: mov rax,QWORD PTR fs:0x28 0x0000000000401073 <+17>: mov QWORD PTR [rsp+0x18],rax 0x0000000000401078 <+22>: xor eax,eax 0x000000000040107a <+24>: call 0x40131b <string_length> 0x000000000040107f <+29>: cmp eax,0x6 0x0000000000401082 <+32>: je 0x4010d2 <phase_5+112> 0x0000000000401084 <+34>: call 0x40143a <explode_bomb> 0x0000000000401089 <+39>: jmp 0x4010d2 <phase_5+112> 0x000000000040108b <+41>: movzx ecx,BYTE PTR [rbx+rax*1] 0x000000000040108f <+45>: mov BYTE PTR [rsp],cl 0x0000000000401092 <+48>: mov rdx,QWORD PTR [rsp] 0x0000000000401096 <+52>: and edx,0xf 0x0000000000401099 <+55>: movzx edx,BYTE PTR [rdx+0x4024b0] 0x00000000004010a0 <+62>: mov BYTE PTR [rsp+rax*1+0x10],dl 0x00000000004010a4 <+66>: add rax,0x1 0x00000000004010a8 <+70>: cmp rax,0x6 0x00000000004010ac <+74>: jne 0x40108b <phase_5+41> 0x00000000004010ae <+76>: mov BYTE PTR [rsp+0x16],0x0 0x00000000004010b3 <+81>: mov esi,0x40245e 0x00000000004010b8 <+86>: lea rdi,[rsp+0x10] 0x00000000004010bd <+91>: call 0x401338 <strings_not_equal> 0x00000000004010c2 <+96>: test eax,eax 0x00000000004010c4 <+98>: je 0x4010d9 <phase_5+119> 0x00000000004010c6 <+100>: call 0x40143a <explode_bomb> 0x00000000004010cb <+105>: nop DWORD PTR [rax+rax*1+0x0] 0x00000000004010d0 <+110>: jmp 0x4010d9 <phase_5+119> 0x00000000004010d2 <+112>: mov eax,0x0 0x00000000004010d7 <+117>: jmp 0x40108b <phase_5+41> 0x00000000004010d9 <+119>: mov rax,QWORD PTR [rsp+0x18] 0x00000000004010de <+124>: xor rax,QWORD PTR fs:0x28 0x00000000004010e7 <+133>: je 0x4010ee <phase_5+140> 0x00000000004010e9 <+135>: call 0x400b30 <__stack_chk_fail@plt> 0x00000000004010ee <+140>: add rsp,0x20 0x00000000004010f2 <+144>: pop rbx 0x00000000004010f3 <+145>: ret
|
(pwndgb使用Intel语法汇编,对本人人性化一些)
首先检查输入长度是否为6,不是就爆炸,是的话跳转到0x4010d2。
然后开始一个循环,执行6次,每次把输入的第i个字符&0xf后,将[rdx+0x4024b0]读到[rsp+i+0x10]的位置。
1 2 3 4 5 6 7 8 9
| pwndbg> x/15gx 0x4024b0 0x4024b0: 0x737265697564616d 0x6c796276746f666e 0x4024c0: 0x7420756f79206f53 0x756f79206b6e6968 0x4024d0: 0x6f7473206e616320 0x6f62206568742070 0x4024e0: 0x206874697720626d 0x202c632d6c727463 0x4024f0: 0x003f756f79206f64 0x202c736573727543 0x402500: 0x6620657627756f79 0x65687420646e756f 0x402510: 0x2074657263657320 0x0000216573616870 0x402520: 0x646e696620747542
|
循环结束后,把[rsp+0x16]置为0,然后比较rsp+0x10处的字符串和0x40245e处的字符串,相同则通过。
1 2
| $ strings -t x ./bomb | grep 245e 245e flyers
|
对应16进制为:66 6c 79 65 72 73
对应偏移为(手动对照计算,注意小端法):9 f e 5 6 7
再前面补上一个0x6,让这些字符变成可读字符:69 6f 6e 65 66 67
对应ascii编码:ionefg
Phase 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| pwndbg> disassemble phase_6 Dump of assembler code for function phase_6: 0x00000000004010f4 <+0>: push r14 0x00000000004010f6 <+2>: push r13 0x00000000004010f8 <+4>: push r12 0x00000000004010fa <+6>: push rbp 0x00000000004010fb <+7>: push rbx 0x00000000004010fc <+8>: sub rsp,0x50 0x0000000000401100 <+12>: mov r13,rsp 0x0000000000401103 <+15>: mov rsi,rsp 0x0000000000401106 <+18>: call 0x40145c <read_six_numbers> 0x000000000040110b <+23>: mov r14,rsp 0x000000000040110e <+26>: mov r12d,0x0 0x0000000000401114 <+32>: mov rbp,r13 0x0000000000401117 <+35>: mov eax,DWORD PTR [r13+0x0] 0x000000000040111b <+39>: sub eax,0x1 0x000000000040111e <+42>: cmp eax,0x5 0x0000000000401121 <+45>: jbe 0x401128 <phase_6+52> 0x0000000000401123 <+47>: call 0x40143a <explode_bomb> 0x0000000000401128 <+52>: add r12d,0x1 0x000000000040112c <+56>: cmp r12d,0x6 0x0000000000401130 <+60>: je 0x401153 <phase_6+95> 0x0000000000401132 <+62>: mov ebx,r12d 0x0000000000401135 <+65>: movsxd rax,ebx 0x0000000000401138 <+68>: mov eax,DWORD PTR [rsp+rax*4] 0x000000000040113b <+71>: cmp DWORD PTR [rbp+0x0],eax 0x000000000040113e <+74>: jne 0x401145 <phase_6+81> 0x0000000000401140 <+76>: call 0x40143a <explode_bomb> 0x0000000000401145 <+81>: add ebx,0x1 0x0000000000401148 <+84>: cmp ebx,0x5 0x000000000040114b <+87>: jle 0x401135 <phase_6+65> 0x000000000040114d <+89>: add r13,0x4 0x0000000000401151 <+93>: jmp 0x401114 <phase_6+32> 0x0000000000401153 <+95>: lea rsi,[rsp+0x18] 0x0000000000401158 <+100>: mov rax,r14 0x000000000040115b <+103>: mov ecx,0x7 0x0000000000401160 <+108>: mov edx,ecx 0x0000000000401162 <+110>: sub edx,DWORD PTR [rax] 0x0000000000401164 <+112>: mov DWORD PTR [rax],edx 0x0000000000401166 <+114>: add rax,0x4 0x000000000040116a <+118>: cmp rax,rsi 0x000000000040116d <+121>: jne 0x401160 <phase_6+108> 0x000000000040116f <+123>: mov esi,0x0 0x0000000000401174 <+128>: jmp 0x401197 <phase_6+163> 0x0000000000401176 <+130>: mov rdx,QWORD PTR [rdx+0x8] 0x000000000040117a <+134>: add eax,0x1 0x000000000040117d <+137>: cmp eax,ecx 0x000000000040117f <+139>: jne 0x401176 <phase_6+130> 0x0000000000401181 <+141>: jmp 0x401188 <phase_6+148> 0x0000000000401183 <+143>: mov edx,0x6032d0 0x0000000000401188 <+148>: mov QWORD PTR [rsp+rsi*2+0x20],rdx 0x000000000040118d <+153>: add rsi,0x4 0x0000000000401191 <+157>: cmp rsi,0x18 0x0000000000401195 <+161>: je 0x4011ab <phase_6+183> 0x0000000000401197 <+163>: mov ecx,DWORD PTR [rsp+rsi*1] 0x000000000040119a <+166>: cmp ecx,0x1 0x000000000040119d <+169>: jle 0x401183 <phase_6+143> 0x000000000040119f <+171>: mov eax,0x1 0x00000000004011a4 <+176>: mov edx,0x6032d0 0x00000000004011a9 <+181>: jmp 0x401176 <phase_6+130> 0x00000000004011ab <+183>: mov rbx,QWORD PTR [rsp+0x20] 0x00000000004011b0 <+188>: lea rax,[rsp+0x28] 0x00000000004011b5 <+193>: lea rsi,[rsp+0x50] 0x00000000004011ba <+198>: mov rcx,rbx 0x00000000004011bd <+201>: mov rdx,QWORD PTR [rax] 0x00000000004011c0 <+204>: mov QWORD PTR [rcx+0x8],rdx 0x00000000004011c4 <+208>: add rax,0x8 0x00000000004011c8 <+212>: cmp rax,rsi 0x00000000004011cb <+215>: je 0x4011d2 <phase_6+222> 0x00000000004011cd <+217>: mov rcx,rdx 0x00000000004011d0 <+220>: jmp 0x4011bd <phase_6+201> 0x00000000004011d2 <+222>: mov QWORD PTR [rdx+0x8],0x0 0x00000000004011da <+230>: mov ebp,0x5 0x00000000004011df <+235>: mov rax,QWORD PTR [rbx+0x8] 0x00000000004011e3 <+239>: mov eax,DWORD PTR [rax] 0x00000000004011e5 <+241>: cmp DWORD PTR [rbx],eax 0x00000000004011e7 <+243>: jge 0x4011ee <phase_6+250> 0x00000000004011e9 <+245>: call 0x40143a <explode_bomb> 0x00000000004011ee <+250>: mov rbx,QWORD PTR [rbx+0x8] 0x00000000004011f2 <+254>: sub ebp,0x1 0x00000000004011f5 <+257>: jne 0x4011df <phase_6+235> 0x00000000004011f7 <+259>: add rsp,0x50 0x00000000004011fb <+263>: pop rbx 0x00000000004011fc <+264>: pop rbp 0x00000000004011fd <+265>: pop r12 0x00000000004011ff <+267>: pop r13 0x0000000000401201 <+269>: pop r14 0x0000000000401203 <+271>: ret
|
首先向%rsp读入6个数字。
然后检查第一个数字是否小于等于6,不是则爆炸。
然后是一个嵌套循环:
首先依次检查剩下的5个数字是否与第一个相等(相等则爆炸),然后检查后4个和第二个是否相等……以此类推。
循环结束后来到0x401153。
首先一个循环(0x401153 - 0x40116d)让六个数字都有 n = 7 - n
然后进行一个循环,依据第n个数字的值,把0x6032d0的一个奇怪的八字节数组的值移到栈上rsp+0x20的地方。
1 2 3 4 5 6 7
| pwndbg> x/20gx 0x6032d0 0x6032d0 <node1>: 0x000000010000014c 0x00000000006032e0 0x6032e0 <node2>: 0x00000002000000a8 0x00000000006032f0 0x6032f0 <node3>: 0x000000030000039c 0x0000000000603300 0x603300 <node4>: 0x00000004000002b3 0x0000000000603310 0x603310 <node5>: 0x00000005000001dd 0x0000000000603320 0x603320 <node6>: 0x00000006000001bb
|
具体对应关系是:
<=1 0x6032d0
2 0x6032e0
3 0x6032f0
4 0x603300
5 0x603310
6 0x603320
7 0
可以发现这些大部分都是地址。
然后对于读到栈上的地址进行一个循环,将上一个地址+8对应的值修改成下一个地址,如此执行5次。(如此拗口,不是我说不清楚,是题目逻辑就难懂……)
循环结束后,把最后一个地址+8的值设成0。
最后,进行一次循环比较:
要求对于前五个栈上的地址,它指向的值都要大于等于该地址+8所指向的值(int32)。
由于该地址+8在刚刚那轮里面其实已经全部修改成下一个地址了,所以实际上就是比较该地址和下个地址哪个指向的值更大而已。
可以看出,按照大到小排序的话,应该是3,4,5,6,1,2(注意由于取值是int32类型,所以是这样,否则就是654321),然后进行一下逆推(之前有个n=7-n),变成4,3,2,1,6,5。
答案就是这个。
Secret Phase
在phase_defused里可以发现有一个secret_phase,做法是在第四阶段后面加上一个DrEvil字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 0000000000401242 <secret_phase>: 401242: 53 push %rbx 401243: e8 56 02 00 00 callq 40149e <read_line> 401248: ba 0a 00 00 00 mov $0xa,%edx 40124d: be 00 00 00 00 mov $0x0,%esi 401252: 48 89 c7 mov %rax,%rdi 401255: e8 76 f9 ff ff callq 400bd0 <strtol@plt> 40125a: 48 89 c3 mov %rax,%rbx 40125d: 8d 40 ff lea -0x1(%rax),%eax 401260: 3d e8 03 00 00 cmp $0x3e8,%eax 401265: 76 05 jbe 40126c <secret_phase+0x2a> 401267: e8 ce 01 00 00 callq 40143a <explode_bomb> 40126c: 89 de mov %ebx,%esi 40126e: bf f0 30 60 00 mov $0x6030f0,%edi 401273: e8 8c ff ff ff callq 401204 <fun7> 401278: 83 f8 02 cmp $0x2,%eax 40127b: 74 05 je 401282 <secret_phase+0x40> 40127d: e8 b8 01 00 00 callq 40143a <explode_bomb> 401282: bf 38 24 40 00 mov $0x402438,%edi 401287: e8 84 f8 ff ff callq 400b10 <puts@plt> 40128c: e8 33 03 00 00 callq 4015c4 <phase_defused> 401291: 5b pop %rbx 401292: c3 retq
|
在secret_phase中,首先会读入一个长整数(strtol可以从字符串里读取一个long)(10进制),如果大于1001的话就会爆炸(并且是无符号判断)。
然后执行了fun7(0x6030f0, 读入的数字),并要求其返回值为2。0x6030f0位置有一些程序自带的值,并且程序除了这里以外,没有任何地方使用过(在IDA PRO中用xref可以查找)。
fun7是一个非常搞人的递归函数,我概括一下它的逻辑:
- arg1指向的int为0:返回0xFFFFFFFF
- arg1指向的int大于arg2:返回 2 * fun7(*(arg1+8), arg2)
- arg1指向的int小于arg2:返回 2 * fun7(*(arg1+16), arg2) + 1
- arg1指向的int等于arg2:返回0
接下来就是想办法构造一个arg2使得最终结果返回为2。
为了方便,我把数据以人类友好的方式抄在了纸上,这里我放一个用IDA看的完整列表(人类不友好):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| 00000000006030E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006030F0 24 00 00 00 00 00 00 00 10 31 60 00 00 00 00 00 0000000000603100 30 31 60 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603110 08 00 00 00 00 00 00 00 90 31 60 00 00 00 00 00 0000000000603120 50 31 60 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603130 32 00 00 00 00 00 00 00 70 31 60 00 00 00 00 00 0000000000603140 B0 31 60 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603150 16 00 00 00 00 00 00 00 70 32 60 00 00 00 00 00 0000000000603160 30 32 60 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603170 2D 00 00 00 00 00 00 00 D0 31 60 00 00 00 00 00 0000000000603180 90 32 60 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603190 06 00 00 00 00 00 00 00 F0 31 60 00 00 00 00 00 00000000006031A0 50 32 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006031B0 6B 00 00 00 00 00 00 00 10 32 60 00 00 00 00 00 00000000006031C0 B0 32 60 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006031D0 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006031E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006031F0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603210 63 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603230 23 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603250 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603270 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603280 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000000000603290 2F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006032A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006032B0 E9 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006032C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000000006032D0 4C 01 00 00 01 00 00 00 E0 32 60 00 00 00 00 00 00000000006032E0 A8 00 00 00 02 00 00 00 F0 32 60 00 00 00 00 00 00000000006032F0 9C 03 00 00 03 00 00 00 00 33 60 00 00 00 00 00 0000000000603300 B3 02 00 00 04 00 00 00 10 33 60 00 00 00 00 00 0000000000603310 DD 01 00 00 05 00 00 00 20 33 60 00 00 00 00 00 0000000000603320 BB 01 00 00 06 00 00 00 00 00 00 00 00 00 00 00
|
我首先假设arg2<0x24,返回2 * fun7(0x603110, arg2)。
在fun7(0x603110, arg2)中,我想要引发第三种情况,又*0x603110 = 0x8,所以我假设arg2>0x8,于是返回2 * fun7(0x603150, arg2) + 1。
在fun7(0x603150, arg2)中,我想要引发第四种情况,又*0x60311=50 = 0x16 = 22,所以我令arg2=22。
然后就解决了,上述所有假设全都非常巧合地成立!(看来老师没想为难我们哈哈)
最终,题目答案如下:
1 2 3 4 5 6 7
| Border relations with Canada have never been better. 1 2 4 8 16 32 0 207 7 0 DrEvil ionefg 4 3 2 1 6 5 22
|
结语
我一开始都是挑战自己,一行一行看汇编做的。但是后来(具体来说是Phase6)我有点窒息了,于是就非常不争气地打开了我的IDA PRO……
然后发现IDA PRO虽好,但是有的地方反而比原始的汇编难懂,比如说 %rsp+0x20
,在IDA PRO的汇编里显示为 %rsp + 0x58 + var_38
,属于是美中不足了。
最后放一张拆弹成功图片:
