-
-
[原创]看雪CTF2016 第四题分析-4-JoenChen
-
发表于: 2016-11-9 11:54 2554
-
说真的,很喜欢这个CM,不过很不喜欢CM中的VM,:-(,最终没能搞明白VM里的算法,能解出来也有一定的运气.
OD载入,GetWindowTextA下断,输入注册码,确定后被断下,来到这里:
00401474 |. 68 00020000 push 200 ; /MaxCount = 512.
00401479 |. 8D85 FCFDFFFF lea eax, [ebp-204] ; |
0040147F |. 50 push eax ; |String
00401480 |. 68 E8030000 push 3E8 ; |ItemID = 1000.
00401485 |. 56 push esi ; |hDialog
00401486 |. FF15 04D14000 call ds:[<&USER32.GetDlgItemTextA>] ; \USER32.GetDlgItemTextA, //取注册码
0040148C |. 83F8 1E .cmp eax, 1E ; //长度一定要为0x1e
0040148F |. 75 25 .jne short 004014B6
00401491 |. 8BD0 .mov edx, eax
00401493 |. 8D8D FCFDFFFF .lea ecx, [ebp-204]
00401499 |. E8 62FBFFFF .call 00401000 ; [CrackMe.00401000, //调用核心算法,返回1为成功
0040149E |. 83F8 01 .cmp eax, 1
004014A1 |. 75 13 .jne short 004014B6
004014A3 |. 6A 00 .push 0
004014A5 |. 68 80374100 .push 00413780 ; ASCII "information"
004014AA |. 68 8C374100 .push 0041378C
004014AF |. 56 .push esi
004014B0 |. FF15 00D14000 .call ds:[<&USER32.MessageBoxA>]
004014B6 |> 8B4D FC .mov ecx, ss:[ebp-4] ; Default case of switch CrackMe.40143A
004014B9 |. 33C0 .xor eax, eax
004014BB |. 33CD .xor ecx, ebp
004014BD |. 5E .pop esi
004014BE |. E8 F3080000 .call 00401DB6
004014C3 |. 8BE5 .mov esp, ebp
004014C5 |. 5D .pop ebp
004014C6 \. C2 1000 .retn 10
看401000
00401000 /$ 53 .push ebx ; CrackMe.00401000(guessed void)
00401001 |. 8BDC .mov ebx, esp
00401003 |. 83EC 08 .sub esp, 8
00401006 |. 83E4 F0 .and esp, FFFFFFF0 ; dqword (16.-byte) stack alignment
00401009 |. 83C4 04 .add esp, 4
0040100C |. 55 .push ebp
0040100D |. 8B6B 04 .mov ebp, ds:[ebx+4]
00401010 |. 896C24 04 .mov ss:[local.1], ebp
00401014 |. 8BEC .mov ebp, esp
00401016 |. 81EC 24040000 .sub esp, 424
0040101C |. A1 04304100 .mov eax, ds:[413004]
00401021 |. 33C5 .xor eax, ebp
00401023 |. 8945 FC .mov ss:[local.3], eax
00401026 |. 56 .push esi
00401027 |. 57 .push edi
00401028 |. 6A 40 .push 40 ; /Arg3 = 40
0040102A |. 8D45 90 .lea eax, [local.30] ; |
0040102D |. C785 14FCFFFF 44AD5CCC .mov dword ptr ss:[local.253], CC5CAD44 ; |//23字节常量KEY,后面要用
00401037 |. 8BF9 .mov edi, ecx ; |
00401039 |. C785 18FCFFFF 1290738D .mov dword ptr ss:[local.252], 8D739012 ; |
00401043 |. 6A 00 .push 0 ; |Arg2 = 0
00401045 |. 50 .push eax ; |Arg1 => offset LOCAL.30
00401046 |. 8BF2 .mov esi, edx ; |
00401048 |. 89BD 2CFCFFFF .mov ss:[local.247], edi ; |
0040104E |. C785 1CFCFFFF 4781E389 .mov dword ptr ss:[local.251], 89E38147 ; |
00401058 |. C785 20FCFFFF 849CDFF9 .mov dword ptr ss:[local.250], F9DF9C84 ; |
00401062 |. C785 24FCFFFF 476AB69E .mov dword ptr ss:[local.249], 9EB66A47 ; |
0040106C |. 66:C785 28FCFFFF 1130 .mov word ptr ss:[local.248], 3011 ; |
00401075 |. C685 2AFCFFFF 27 .mov byte ptr ss:[local.248+2], 27 ; |
0040107C |. E8 CF1B0000 .call memset ; \CrackMe.memset
00401081 |. 68 00020000 .push 200 ; /Arg3 = 200
00401086 |. 8D85 90FDFFFF .lea eax, [local.158] ; |
0040108C |. 6A 00 .push 0 ; |Arg2 = 0
0040108E |. 50 .push eax ; |Arg1 => offset LOCAL.158
0040108F |. E8 BC1B0000 .call memset ; \CrackMe.memset
00401094 |. 83C4 18 .add esp, 18
00401097 |. 81FE 00020000 .cmp esi, 200
0040109D |. 0F8D 36030000 .jge 004013D9
004010A3 |. 8B07 .mov eax, ds:[edi] ; //取注册码前7个字符,用于计算MD5
004010A5 |. 8945 90 .mov ss:[local.30], eax
004010A8 |. 0FB747 04 .movzx eax, word ptr ds:[edi+4]
004010AC |. 66:8945 94 .mov ss:[local.29], ax
004010B0 |. 0FB647 06 .movzx eax, byte ptr ds:[edi+6]
004010B4 |. 8845 96 .mov ss:[local.29+2], al
004010B7 \. E9 7CDF0200 .jmp 0042F038 ; //进入VM,进去就看得头晕:-(,所以还是不进了
直接在前7个字符下内存断点,断下后回溯,找到MD5运算:
004015C0 /. 55 .push ebp ; //CMD5::Final(OUT BYTE buf[0x10])
004015C1 |. 8BEC .mov ebp, esp
004015C3 |. 83EC 0C .sub esp, 0C
004015C6 |. A1 04304100 .mov eax, ds:[413004]
004015CB |. 33C5 .xor eax, ebp
004015CD |. 8945 FC .mov ss:[local.1], eax
004015D0 |. 53 .push ebx
004015D1 |. 56 .push esi
004015D2 |. 57 .push edi
004015D3 |. 8BFA .mov edi, edx
004015D5 |. 8BD9 .mov ebx, ecx
004015D7 |. 33F6 .xor esi, esi
004015D9 |. 8D57 12 .lea edx, [edi+12]
004015DC |. 0F1F40 00 .nop ds:[eax]
004015E0 |> 0FB642 FE ./movzx eax, byte ptr ds:[edx-2]
004015E4 |. 8D52 04 .|lea edx, [edx+4]
004015E7 |. 884435 F4 .|mov ss:[esi+ebp-0C], al
004015EB |. 0FB642 FB .|movzx eax, byte ptr ds:[edx-5]
004015EF |. 884435 F5 .|mov ss:[esi+ebp-0B], al
004015F3 |. 0FB642 FC .|movzx eax, byte ptr ds:[edx-4]
004015F7 |. 884435 F6 .|mov ss:[esi+ebp-0A], al
004015FB |. 0FB642 FD .|movzx eax, byte ptr ds:[edx-3]
004015FF |. 884435 F7 .|mov ss:[esi+ebp-9], al
00401603 |. 83C6 04 .|add esi, 4
00401606 |. 83FE 08 .|cmp esi, 8
00401609 |.^ 72 D5 .\jb short 004015E0
0040160B |. 8B57 10 .mov edx, ds:[edi+10]
0040160E |. B9 38000000 .mov ecx, 38
00401613 |. C1EA 03 .shr edx, 3
00401616 |. B8 78000000 .mov eax, 78
0040161B |. 83E2 3F .and edx, 0000003F
0040161E |. 2BCA .sub ecx, edx
00401620 |. 2BC2 .sub eax, edx
00401622 |. 83FA 38 .cmp edx, 38
00401625 |. BA 98394100 .mov edx, 00413998
0040162A |. 0F42C1 .cmovb eax, ecx
0040162D |. 8BCF .mov ecx, edi
0040162F |. 50 .push eax
00401630 |. E8 BBFEFFFF .call 004014F0
00401635 |. 6A 08 .push 8
00401637 |. 8D55 F4 .lea edx, [local.3]
0040163A |. 8BCF .mov ecx, edi
0040163C |. E8 AFFEFFFF .call 004014F0
00401641 |. 83C4 08 .add esp, 8
00401644 |. 8D53 01 .lea edx, [ebx+1]
00401647 |. 8D47 02 .lea eax, [edi+2]
0040164A |. BE 04000000 .mov esi, 4
0040164F |. 90 .nop
00401650 |> 0FB648 FE ./movzx ecx, byte ptr ds:[eax-2]
00401654 |. 8D40 04 .|lea eax, [eax+4]
00401657 |. 884A FF .|mov ds:[edx-1], cl
0040165A |. 8D52 04 .|lea edx, [edx+4]
0040165D |. 0FB648 FB .|movzx ecx, byte ptr ds:[eax-5]
00401661 |. 884A FC .|mov ds:[edx-4], cl
00401664 |. 0FB648 FC .|movzx ecx, byte ptr ds:[eax-4]
00401668 |. 884A FD .|mov ds:[edx-3], cl
0040166B |. 0FB648 FD .|movzx ecx, byte ptr ds:[eax-3]
0040166F |. 884A FE .|mov ds:[edx-2], cl
00401672 |. 83EE 01 .|sub esi, 1
00401675 |.^ 75 D9 .\jnz short 00401650
00401677 |. 8B4D FC .mov ecx, ss:[local.1]
0040167A |. 0F57C0 .xorps xmm0, xmm0
0040167D |. 0F1107 .movups ds:[edi], xmm0
00401680 |. 33CD .xor ecx, ebp
00401682 |. 0F1147 10 .movups ds:[edi+10], xmm0
00401686 |. 0F1147 20 .movups ds:[edi+20], xmm0
0040168A |. 0F1147 30 .movups ds:[edi+30], xmm0
0040168E |. 0F1147 40 .movups ds:[edi+40], xmm0
00401692 |. 660FD647 50 .movq ds:[edi+50], xmm0
00401697 |. 5F .pop edi
00401698 |. 5E .pop esi
00401699 |. 5B .pop ebx
0040169A |. E8 17070000 .call 00401DB6
0040169F |. 8BE5 .mov esp, ebp
004016A1 |. 5D .pop ebp
004016A2 \. C3 .retn
在返回的MD5地址下内存断点,会中断到这儿,慢慢的跟,会看到后面的代码:
0040115E 8B8D 2CFCFFFF mov ecx, ss:[ebp-3D4] ; //复制注册码后23位
00401164 8B41 17 mov eax, ds:[ecx+17]
00401167 0F1041 07 movups xmm0, ds:[ecx+7]
0040116B 8945 E0 mov ss:[ebp-20], eax
0040116E 0FB741 1B movzx eax, word ptr ds:[ecx+1B]
00401172 66:8945 E4 mov ss:[ebp-1C], ax
00401176 0FB641 1D movzx eax, byte ptr ds:[ecx+1D]
0040117A 33C9 xor ecx, ecx
0040117C 0F1145 D0 movups ss:[ebp-30], xmm0
00401180 8845 E6 mov ss:[ebp-1A], al
00401183 8A440D D0 mov al, ss:[ecx+ebp-30]
00401187 32840D 14FCFFFF xor al, ss:[ecx+ebp-3EC] ; //注册码后23字节 XOR 之前的 23字节常量KEY
0040118E 88840D E8FBFFFF mov ss:[ecx+ebp-418], al
00401195 83F9 17 cmp ecx, 17
00401198 0F83 68020000 jae 00401406
0040119E C6440D D0 00 mov byte ptr ss:[ecx+ebp-30], 0
004011A3 C6840D 14FCFFFF 00 mov byte ptr ss:[ecx+ebp-3EC], 0
004011AB 41 inc ecx
004011AC 83F9 17 cmp ecx, 17
004011AF ^ 7C D2 jl short 00401183
004011B1 33C9 xor ecx, ecx
004011B3 0F1F40 00 nop ds:[eax]
004011B7 66:0F1F8400 00000000 nop ds:[eax+eax]
004011C0 /> 8A840D 90FDFFFF /mov al, ss:[ecx+ebp-270] ; //前面XOR的23字节结果再次 XOR 注册码前7位的MD5(16字节,不足从头补够)
004011C7 |. 32840D E8FBFFFF |xor al, ss:[ecx+ebp-418]
004011CE |. 88440D D0 |mov ss:[ecx+ebp-30], al
004011D2 |. 83F9 17 |cmp ecx, 17
004011D5 |. 0F83 2B020000 |jae 00401406
004011DB |. C6840D E8FBFFFF 00 |mov byte ptr ss:[ecx+ebp-418], 0
004011E3 |. C6840D 90FDFFFF 00 |mov byte ptr ss:[ecx+ebp-270], 0
004011EB |. 41 |inc ecx
004011EC |. 83F9 17 |cmp ecx, 17
004011EF |.^ 7C CF \jl short 004011C0
004011F1 |. B9 40000000 .mov ecx, 40
004011F6 |. 8DBD 90FCFFFF .lea edi, [ebp-370]
004011FC |. BE 98374100 .mov esi, 00413798
00401201 |. 33C0 .xor eax, eax
00401203 |. F3:A5 .rep movs dword ptr es:[edi], dword ptr ds:[esi] ; //复制256字节常量表记作T1,256字节表示16*16迷宫,同后面的T2运算后表示墙或目标点
00401205 |. B9 40000000 .mov ecx, 40 ; //计算结果为0x20,0x30为墙,0x58为目标点,其他值为路
0040120A |. 8985 30FCFFFF .mov ss:[ebp-3D0], eax
00401210 |. BE 98384100 .mov esi, 00413898
00401215 |. 8DBD 90FEFFFF .lea edi, [ebp-170]
0040121B |. F3:A5 .rep movs dword ptr es:[edi], dword ptr ds:[esi] ; //复制256字节常量表记作 T2
0040121D |. 33C9 .xor ecx, ecx
0040121F |. 898D 2CFCFFFF .mov ss:[ebp-3D4], ecx
00401225 |> 8A4C0D D0 .mov cl, ss:[ecx+ebp-30]
00401229 |. 0FB6C9 .movzx ecx, cl
0040122C |. C785 0CFCFFFF 06000000 .mov dword ptr ss:[ebp-3F4], 6 ; //从高位取起,每次2BIT,0-3代表每步方向上,右,下,左
00401236 |. 898D 00FCFFFF .mov ss:[ebp-400], ecx
0040123C |. 0F1F40 00 .nop ds:[eax]
00401240 |> 8BD1 .mov edx, ecx
00401242 |. 8985 10FCFFFF .mov ss:[ebp-3F0], eax
00401248 |. 8A8D 0CFCFFFF .mov cl, ss:[ebp-3F4]
0040124E |. D3EA .shr edx, cl
00401250 |. 83E2 03 .and edx, 00000003
00401253 \. FF2495 0C144000 .jmp ds:[edx*4+40140C]
0040125A /> 83E8 10 .sub eax, 10 ; //0代表向上走一步,行减少1,(1行16字节,所以减0x10)
0040125D \. EB 09 .jmp short 00401268
0040125F /> 40 .inc eax ; //1代表向右走一步,列增加1
00401260 \. EB 06 .jmp short 00401268
00401262 /> 83C0 10 .add eax, 10 ; //2代表向下走一步,行增加1,(1行16字节,所以加0x10)
00401265 \. EB 01 .jmp short 00401268
00401267 /> 48 .dec eax ; //3代表向左走一步,列减少1
00401268 |> 8985 30FCFFFF .mov ss:[ebp-3D0], eax
0040126E |. 99 .cdq
0040126F |. 83E2 0F .and edx, 0000000F
00401272 |. 03C2 .add eax, edx
00401274 |. C1F8 04 .sar eax, 4
00401277 |. 8985 08FCFFFF .mov ss:[ebp-3F8], eax
0040127D |. 8B85 30FCFFFF .mov eax, ss:[ebp-3D0]
00401283 |. 25 0F000080 .and eax, 8000000F
00401288 |. 79 05 .jns short 0040128F
0040128A |. 48 dec eax
0040128B |. 83C8 F0 or eax, FFFFFFF0
0040128E |. 40 inc eax
0040128F |> 8985 04FCFFFF .mov ss:[ebp-3FC], eax
00401295 \. /E9 DBB10300 .jmp 0043C475 ; //再次到VM去了,再次晕...,再次不管它
不知什么时候又从VM跳回来了
004012B5 /. 8B8D 08FCFFFF mov ecx, ss:[ebp-3F8] ; //取Y
004012BB |. 8D95 90FEFFFF lea edx, [ebp-170]
004012C1 |. 8B85 04FCFFFF mov eax, ss:[ebp-3FC] ; //取X
004012C7 |. C1E1 04 shl ecx, 4
004012CA |. 03C1 add eax, ecx ; //变换成在256字节表中的位置,设为 idx
004012CC |. 03D0 add edx, eax
004012CE |. 8995 04FCFFFF mov ss:[ebp-3FC], edx
004012D4 |. 8A8C05 90FCFFFF mov cl, ss:[eax+ebp-370]
004012DB |. 8AC1 mov al, cl
004012DD |. 888D 37FCFFFF mov ss:[ebp-3C9], cl
004012E3 |. C0C8 02 ror al, 2
004012E6 |. 0FB6C8 movzx ecx, al
004012E9 |. 0FB602 movzx eax, byte ptr ds:[edx]
004012EC |. 33C8 xor ecx, eax ; //取状态 c = T1[idx] ^ ROR(T2[idx])
004012EE |. 83F9 30 cmp ecx, 30 ; //墙,死了
004012F1 |. 0F84 E2000000 je 004013D9
004012F7 |. 83F9 20 cmp ecx, 20 ; //墙,死了
004012FA |. 0F84 D9000000 je 004013D9
00401300 |. 83F9 58 cmp ecx, 58 ; //出口,成功
00401303 |. 0F84 E5000000 je 004013EE
00401309 |. 8B8D 10FCFFFF mov ecx, ss:[ebp-3F0]
0040130F |. 8BC1 mov eax, ecx
00401311 |. 99 cdq
00401312 |. 83E2 0F and edx, 0000000F
00401315 |. 03C2 add eax, edx
00401317 |. C1F8 04 sar eax, 4
0040131A |. 8985 08FCFFFF mov ss:[ebp-3F8], eax
00401320 |. 81E1 0F000080 and ecx, 8000000F
00401326 |. 79 05 jns short 0040132D
00401328 |. 49 dec ecx
00401329 |. 83C9 F0 or ecx, FFFFFFF0
0040132C |. 41 inc ecx
0040132D |> 898D 10FCFFFF mov ss:[ebp-3F0], ecx
00401333 \. E9 DD790300 jmp 00438D15 ; //再再次到VM去了,再再次晕...,再再次不管它
又从VM中跳回来了
004013AA /. 83AD 0CFCFFFF 02 sub dword ptr ss:[ebp-3F4], 2 ; //准备取下一步的数据,2BIT
004013B1 |. 8B85 30FCFFFF mov eax, ss:[ebp-3D0]
004013B7 |. 8B8D 00FCFFFF mov ecx, ss:[ebp-400]
004013BD |.^ 0F89 7DFEFFFF jns 00401240 ; //一字节还没用完,继续取
004013C3 |. 8B8D 2CFCFFFF .mov ecx, ss:[ebp-3D4]
004013C9 |. 41 .inc ecx ; //取下一字节
004013CA |. 898D 2CFCFFFF .mov ss:[ebp-3D4], ecx
004013D0 |. 83F9 17 .cmp ecx, 17 ; //>=23取完了也没走出去,出错
004013D3 |.^ 0F8C 4CFEFFFF .jl 00401225
004013D9 |> 33C0 .xor eax, eax ; //出错,返回0
004013DB |. 5F .pop edi
004013DC |. 5E .pop esi
004013DD |. 8B4D FC .mov ecx, ss:[ebp-4]
004013E0 |. 33CD .xor ecx, ebp
004013E2 |. E8 CF090000 .call 00401DB6
004013E7 |. 8BE5 .mov esp, ebp
004013E9 |. 5D .pop ebp
004013EA |. 8BE3 .mov esp, ebx
004013EC |. 5B .pop ebx
004013ED |. C3 .retn
004013EE |> 8B4D FC mov ecx, ss:[ebp-4] ; //成功,返回1
004013F1 |. B8 01000000 mov eax, 1
004013F6 |. 5F pop edi
004013F7 |. 33CD xor ecx, ebp
004013F9 |. 5E pop esi
004013FA |. E8 B7090000 call 00401DB6
004013FF |. 8BE5 mov esp, ebp
00401401 |. 5D pop ebp
00401402 |. 8BE3 mov esp, ebx
00401404 |. 5B pop ebx
00401405 \. C3 retn
分析上面的代码以及动态查看内存中的值,可以明显看出这就是一个迷宫算法,不过其间还有转到VM去的时候,不知道还干了什么坏事,先不管了,根据墙算法和判断,打印出迷宫图:
const BYTE T1[256];
const BYTE T2[256];
const BYTE KEY[23];
以上三个都是程序中的常量(前面代码中有注释),复制出来。
CString s;
BYTE T3[256]; //这个后面要用,一并算了
for (int i = 0 ; i < sizeof(T1) ; i++)
{
BYTE c = T3[i] = T1 ^ ((T2[i] << 6) | (T2[i] >> 2));
if(c == 0x20 || c == 0x30 || c == 0x58){
s.AppendFormat(" %02X" , c);
}else{
s += " ";
}
if(i % 16 == 15){
s.Append("\r\n");
}
}
OutputDebugString(s);
得到:
30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 58 30 30
由程序中走路算法,人肉得到走路数据:
0代表向上走一步,行减少1
1代表向右走一步,列增加1
2代表向下走一步,行增加1
3代表向左走一步,列减少1
BYTE steps[] = {2,2,2,1,1,1,2,2,2,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,1,1,0,0,0,0,0,0,0,0,3,3,2,2,2,3,3,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,3,3,3,3,3,2,2,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,2,2,2,1,1};
步数不能多于上面这个,不过下面迷宫变了时走法也变了,步数可以少于上面这个.
设输入注册码为:BYTE SN[30];
SN[0-6] = 随便你喜欢,由于它的MD5后面运算需要,不是所有的串都行,因为第一步不能变,只能为2.要没有乱码就要多试几个了,后面的有可能可以调到没有乱码(加步数回走,不过长度不能超过上面的),也可能调不到。
BYTE snMD5[23] = md5(SN[0-6]) //md5长度不够从头补
for(i = 0 ; i < sizeof(steps) ; i += 4)
{
BYTE c = steps[i] << 6;
if(i + 1 < sizeof(steps)) c |= steps[i+1] << 4;
if(i + 2 < sizeof(steps)) c |= steps[i+2] << 2;
if(i + 3 < sizeof(steps)) c |= steps[i+3] << 0;
SN[7 + i / 4] = c ^ T3 ^ snMD5[i / 4]; //T3是前面用T1,T2算出来的
}
如果SN填充不够就随便加字符(现在步数应该刚刚够,不能加,steps变短才要加)
如果SN[0-6]用作者所选的值,现在算出的SN就应该是唯一的了,因为步数刚用完(不知道T2还会不会变成下面的,如果会,那也不是唯一的,因为步数少了)
算了一个SN出来,测试了一下,不过可惜,走到一个位置时,撞墙死了。
再回来找原因,看到那个T2变了,动态跟了一下,这才知道VM里干了坏事.对VM,偶还是只有一句话:再再再次晕...,再再再次不管它
用新的T2重新打印了一个迷宫数据:
30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 20 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 58 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 20 30 58 30 30
这时发现另一个出口,还在进去走不了多远的地方,所以减少步数,在另一出口来回走几下(如果直接走到那儿就停,不成功,因为那时还没有那个出口),由于步数少了,还可以根据所选SN[0-6]算的MD5值,在之前的步子上来回走一下,以调整注册码中不出现乱码.
BYTE steps[] = {2,2,2,1,1,1,2,2,2,3,3,2,2,2,2,2,2,2,1,1,1,3,1,3,1,3,1,3}
由T1,新的T2,新的steps,用前面的算法,步数可以重新算N个SN出来,下面给一个解(不过不是全数字,字母):
ctf2016#hl1$[i1W11111111111111
本来很好一个CM,可惜设计上有点问题,算法上SN[0-6]不定,MD5(SN[0-6])也就不定,再同另一个不定的值SN[7-30]计算成一个定值,本身就可以多解(之前有个CM也是差不多这样),再密宫有另一路程较短的出口,步路也成了不定值,更是多解.
OD载入,GetWindowTextA下断,输入注册码,确定后被断下,来到这里:
00401474 |. 68 00020000 push 200 ; /MaxCount = 512.
00401479 |. 8D85 FCFDFFFF lea eax, [ebp-204] ; |
0040147F |. 50 push eax ; |String
00401480 |. 68 E8030000 push 3E8 ; |ItemID = 1000.
00401485 |. 56 push esi ; |hDialog
00401486 |. FF15 04D14000 call ds:[<&USER32.GetDlgItemTextA>] ; \USER32.GetDlgItemTextA, //取注册码
0040148C |. 83F8 1E .cmp eax, 1E ; //长度一定要为0x1e
0040148F |. 75 25 .jne short 004014B6
00401491 |. 8BD0 .mov edx, eax
00401493 |. 8D8D FCFDFFFF .lea ecx, [ebp-204]
00401499 |. E8 62FBFFFF .call 00401000 ; [CrackMe.00401000, //调用核心算法,返回1为成功
0040149E |. 83F8 01 .cmp eax, 1
004014A1 |. 75 13 .jne short 004014B6
004014A3 |. 6A 00 .push 0
004014A5 |. 68 80374100 .push 00413780 ; ASCII "information"
004014AA |. 68 8C374100 .push 0041378C
004014AF |. 56 .push esi
004014B0 |. FF15 00D14000 .call ds:[<&USER32.MessageBoxA>]
004014B6 |> 8B4D FC .mov ecx, ss:[ebp-4] ; Default case of switch CrackMe.40143A
004014B9 |. 33C0 .xor eax, eax
004014BB |. 33CD .xor ecx, ebp
004014BD |. 5E .pop esi
004014BE |. E8 F3080000 .call 00401DB6
004014C3 |. 8BE5 .mov esp, ebp
004014C5 |. 5D .pop ebp
004014C6 \. C2 1000 .retn 10
看401000
00401000 /$ 53 .push ebx ; CrackMe.00401000(guessed void)
00401001 |. 8BDC .mov ebx, esp
00401003 |. 83EC 08 .sub esp, 8
00401006 |. 83E4 F0 .and esp, FFFFFFF0 ; dqword (16.-byte) stack alignment
00401009 |. 83C4 04 .add esp, 4
0040100C |. 55 .push ebp
0040100D |. 8B6B 04 .mov ebp, ds:[ebx+4]
00401010 |. 896C24 04 .mov ss:[local.1], ebp
00401014 |. 8BEC .mov ebp, esp
00401016 |. 81EC 24040000 .sub esp, 424
0040101C |. A1 04304100 .mov eax, ds:[413004]
00401021 |. 33C5 .xor eax, ebp
00401023 |. 8945 FC .mov ss:[local.3], eax
00401026 |. 56 .push esi
00401027 |. 57 .push edi
00401028 |. 6A 40 .push 40 ; /Arg3 = 40
0040102A |. 8D45 90 .lea eax, [local.30] ; |
0040102D |. C785 14FCFFFF 44AD5CCC .mov dword ptr ss:[local.253], CC5CAD44 ; |//23字节常量KEY,后面要用
00401037 |. 8BF9 .mov edi, ecx ; |
00401039 |. C785 18FCFFFF 1290738D .mov dword ptr ss:[local.252], 8D739012 ; |
00401043 |. 6A 00 .push 0 ; |Arg2 = 0
00401045 |. 50 .push eax ; |Arg1 => offset LOCAL.30
00401046 |. 8BF2 .mov esi, edx ; |
00401048 |. 89BD 2CFCFFFF .mov ss:[local.247], edi ; |
0040104E |. C785 1CFCFFFF 4781E389 .mov dword ptr ss:[local.251], 89E38147 ; |
00401058 |. C785 20FCFFFF 849CDFF9 .mov dword ptr ss:[local.250], F9DF9C84 ; |
00401062 |. C785 24FCFFFF 476AB69E .mov dword ptr ss:[local.249], 9EB66A47 ; |
0040106C |. 66:C785 28FCFFFF 1130 .mov word ptr ss:[local.248], 3011 ; |
00401075 |. C685 2AFCFFFF 27 .mov byte ptr ss:[local.248+2], 27 ; |
0040107C |. E8 CF1B0000 .call memset ; \CrackMe.memset
00401081 |. 68 00020000 .push 200 ; /Arg3 = 200
00401086 |. 8D85 90FDFFFF .lea eax, [local.158] ; |
0040108C |. 6A 00 .push 0 ; |Arg2 = 0
0040108E |. 50 .push eax ; |Arg1 => offset LOCAL.158
0040108F |. E8 BC1B0000 .call memset ; \CrackMe.memset
00401094 |. 83C4 18 .add esp, 18
00401097 |. 81FE 00020000 .cmp esi, 200
0040109D |. 0F8D 36030000 .jge 004013D9
004010A3 |. 8B07 .mov eax, ds:[edi] ; //取注册码前7个字符,用于计算MD5
004010A5 |. 8945 90 .mov ss:[local.30], eax
004010A8 |. 0FB747 04 .movzx eax, word ptr ds:[edi+4]
004010AC |. 66:8945 94 .mov ss:[local.29], ax
004010B0 |. 0FB647 06 .movzx eax, byte ptr ds:[edi+6]
004010B4 |. 8845 96 .mov ss:[local.29+2], al
004010B7 \. E9 7CDF0200 .jmp 0042F038 ; //进入VM,进去就看得头晕:-(,所以还是不进了
直接在前7个字符下内存断点,断下后回溯,找到MD5运算:
004015C0 /. 55 .push ebp ; //CMD5::Final(OUT BYTE buf[0x10])
004015C1 |. 8BEC .mov ebp, esp
004015C3 |. 83EC 0C .sub esp, 0C
004015C6 |. A1 04304100 .mov eax, ds:[413004]
004015CB |. 33C5 .xor eax, ebp
004015CD |. 8945 FC .mov ss:[local.1], eax
004015D0 |. 53 .push ebx
004015D1 |. 56 .push esi
004015D2 |. 57 .push edi
004015D3 |. 8BFA .mov edi, edx
004015D5 |. 8BD9 .mov ebx, ecx
004015D7 |. 33F6 .xor esi, esi
004015D9 |. 8D57 12 .lea edx, [edi+12]
004015DC |. 0F1F40 00 .nop ds:[eax]
004015E0 |> 0FB642 FE ./movzx eax, byte ptr ds:[edx-2]
004015E4 |. 8D52 04 .|lea edx, [edx+4]
004015E7 |. 884435 F4 .|mov ss:[esi+ebp-0C], al
004015EB |. 0FB642 FB .|movzx eax, byte ptr ds:[edx-5]
004015EF |. 884435 F5 .|mov ss:[esi+ebp-0B], al
004015F3 |. 0FB642 FC .|movzx eax, byte ptr ds:[edx-4]
004015F7 |. 884435 F6 .|mov ss:[esi+ebp-0A], al
004015FB |. 0FB642 FD .|movzx eax, byte ptr ds:[edx-3]
004015FF |. 884435 F7 .|mov ss:[esi+ebp-9], al
00401603 |. 83C6 04 .|add esi, 4
00401606 |. 83FE 08 .|cmp esi, 8
00401609 |.^ 72 D5 .\jb short 004015E0
0040160B |. 8B57 10 .mov edx, ds:[edi+10]
0040160E |. B9 38000000 .mov ecx, 38
00401613 |. C1EA 03 .shr edx, 3
00401616 |. B8 78000000 .mov eax, 78
0040161B |. 83E2 3F .and edx, 0000003F
0040161E |. 2BCA .sub ecx, edx
00401620 |. 2BC2 .sub eax, edx
00401622 |. 83FA 38 .cmp edx, 38
00401625 |. BA 98394100 .mov edx, 00413998
0040162A |. 0F42C1 .cmovb eax, ecx
0040162D |. 8BCF .mov ecx, edi
0040162F |. 50 .push eax
00401630 |. E8 BBFEFFFF .call 004014F0
00401635 |. 6A 08 .push 8
00401637 |. 8D55 F4 .lea edx, [local.3]
0040163A |. 8BCF .mov ecx, edi
0040163C |. E8 AFFEFFFF .call 004014F0
00401641 |. 83C4 08 .add esp, 8
00401644 |. 8D53 01 .lea edx, [ebx+1]
00401647 |. 8D47 02 .lea eax, [edi+2]
0040164A |. BE 04000000 .mov esi, 4
0040164F |. 90 .nop
00401650 |> 0FB648 FE ./movzx ecx, byte ptr ds:[eax-2]
00401654 |. 8D40 04 .|lea eax, [eax+4]
00401657 |. 884A FF .|mov ds:[edx-1], cl
0040165A |. 8D52 04 .|lea edx, [edx+4]
0040165D |. 0FB648 FB .|movzx ecx, byte ptr ds:[eax-5]
00401661 |. 884A FC .|mov ds:[edx-4], cl
00401664 |. 0FB648 FC .|movzx ecx, byte ptr ds:[eax-4]
00401668 |. 884A FD .|mov ds:[edx-3], cl
0040166B |. 0FB648 FD .|movzx ecx, byte ptr ds:[eax-3]
0040166F |. 884A FE .|mov ds:[edx-2], cl
00401672 |. 83EE 01 .|sub esi, 1
00401675 |.^ 75 D9 .\jnz short 00401650
00401677 |. 8B4D FC .mov ecx, ss:[local.1]
0040167A |. 0F57C0 .xorps xmm0, xmm0
0040167D |. 0F1107 .movups ds:[edi], xmm0
00401680 |. 33CD .xor ecx, ebp
00401682 |. 0F1147 10 .movups ds:[edi+10], xmm0
00401686 |. 0F1147 20 .movups ds:[edi+20], xmm0
0040168A |. 0F1147 30 .movups ds:[edi+30], xmm0
0040168E |. 0F1147 40 .movups ds:[edi+40], xmm0
00401692 |. 660FD647 50 .movq ds:[edi+50], xmm0
00401697 |. 5F .pop edi
00401698 |. 5E .pop esi
00401699 |. 5B .pop ebx
0040169A |. E8 17070000 .call 00401DB6
0040169F |. 8BE5 .mov esp, ebp
004016A1 |. 5D .pop ebp
004016A2 \. C3 .retn
在返回的MD5地址下内存断点,会中断到这儿,慢慢的跟,会看到后面的代码:
0040115E 8B8D 2CFCFFFF mov ecx, ss:[ebp-3D4] ; //复制注册码后23位
00401164 8B41 17 mov eax, ds:[ecx+17]
00401167 0F1041 07 movups xmm0, ds:[ecx+7]
0040116B 8945 E0 mov ss:[ebp-20], eax
0040116E 0FB741 1B movzx eax, word ptr ds:[ecx+1B]
00401172 66:8945 E4 mov ss:[ebp-1C], ax
00401176 0FB641 1D movzx eax, byte ptr ds:[ecx+1D]
0040117A 33C9 xor ecx, ecx
0040117C 0F1145 D0 movups ss:[ebp-30], xmm0
00401180 8845 E6 mov ss:[ebp-1A], al
00401183 8A440D D0 mov al, ss:[ecx+ebp-30]
00401187 32840D 14FCFFFF xor al, ss:[ecx+ebp-3EC] ; //注册码后23字节 XOR 之前的 23字节常量KEY
0040118E 88840D E8FBFFFF mov ss:[ecx+ebp-418], al
00401195 83F9 17 cmp ecx, 17
00401198 0F83 68020000 jae 00401406
0040119E C6440D D0 00 mov byte ptr ss:[ecx+ebp-30], 0
004011A3 C6840D 14FCFFFF 00 mov byte ptr ss:[ecx+ebp-3EC], 0
004011AB 41 inc ecx
004011AC 83F9 17 cmp ecx, 17
004011AF ^ 7C D2 jl short 00401183
004011B1 33C9 xor ecx, ecx
004011B3 0F1F40 00 nop ds:[eax]
004011B7 66:0F1F8400 00000000 nop ds:[eax+eax]
004011C0 /> 8A840D 90FDFFFF /mov al, ss:[ecx+ebp-270] ; //前面XOR的23字节结果再次 XOR 注册码前7位的MD5(16字节,不足从头补够)
004011C7 |. 32840D E8FBFFFF |xor al, ss:[ecx+ebp-418]
004011CE |. 88440D D0 |mov ss:[ecx+ebp-30], al
004011D2 |. 83F9 17 |cmp ecx, 17
004011D5 |. 0F83 2B020000 |jae 00401406
004011DB |. C6840D E8FBFFFF 00 |mov byte ptr ss:[ecx+ebp-418], 0
004011E3 |. C6840D 90FDFFFF 00 |mov byte ptr ss:[ecx+ebp-270], 0
004011EB |. 41 |inc ecx
004011EC |. 83F9 17 |cmp ecx, 17
004011EF |.^ 7C CF \jl short 004011C0
004011F1 |. B9 40000000 .mov ecx, 40
004011F6 |. 8DBD 90FCFFFF .lea edi, [ebp-370]
004011FC |. BE 98374100 .mov esi, 00413798
00401201 |. 33C0 .xor eax, eax
00401203 |. F3:A5 .rep movs dword ptr es:[edi], dword ptr ds:[esi] ; //复制256字节常量表记作T1,256字节表示16*16迷宫,同后面的T2运算后表示墙或目标点
00401205 |. B9 40000000 .mov ecx, 40 ; //计算结果为0x20,0x30为墙,0x58为目标点,其他值为路
0040120A |. 8985 30FCFFFF .mov ss:[ebp-3D0], eax
00401210 |. BE 98384100 .mov esi, 00413898
00401215 |. 8DBD 90FEFFFF .lea edi, [ebp-170]
0040121B |. F3:A5 .rep movs dword ptr es:[edi], dword ptr ds:[esi] ; //复制256字节常量表记作 T2
0040121D |. 33C9 .xor ecx, ecx
0040121F |. 898D 2CFCFFFF .mov ss:[ebp-3D4], ecx
00401225 |> 8A4C0D D0 .mov cl, ss:[ecx+ebp-30]
00401229 |. 0FB6C9 .movzx ecx, cl
0040122C |. C785 0CFCFFFF 06000000 .mov dword ptr ss:[ebp-3F4], 6 ; //从高位取起,每次2BIT,0-3代表每步方向上,右,下,左
00401236 |. 898D 00FCFFFF .mov ss:[ebp-400], ecx
0040123C |. 0F1F40 00 .nop ds:[eax]
00401240 |> 8BD1 .mov edx, ecx
00401242 |. 8985 10FCFFFF .mov ss:[ebp-3F0], eax
00401248 |. 8A8D 0CFCFFFF .mov cl, ss:[ebp-3F4]
0040124E |. D3EA .shr edx, cl
00401250 |. 83E2 03 .and edx, 00000003
00401253 \. FF2495 0C144000 .jmp ds:[edx*4+40140C]
0040125A /> 83E8 10 .sub eax, 10 ; //0代表向上走一步,行减少1,(1行16字节,所以减0x10)
0040125D \. EB 09 .jmp short 00401268
0040125F /> 40 .inc eax ; //1代表向右走一步,列增加1
00401260 \. EB 06 .jmp short 00401268
00401262 /> 83C0 10 .add eax, 10 ; //2代表向下走一步,行增加1,(1行16字节,所以加0x10)
00401265 \. EB 01 .jmp short 00401268
00401267 /> 48 .dec eax ; //3代表向左走一步,列减少1
00401268 |> 8985 30FCFFFF .mov ss:[ebp-3D0], eax
0040126E |. 99 .cdq
0040126F |. 83E2 0F .and edx, 0000000F
00401272 |. 03C2 .add eax, edx
00401274 |. C1F8 04 .sar eax, 4
00401277 |. 8985 08FCFFFF .mov ss:[ebp-3F8], eax
0040127D |. 8B85 30FCFFFF .mov eax, ss:[ebp-3D0]
00401283 |. 25 0F000080 .and eax, 8000000F
00401288 |. 79 05 .jns short 0040128F
0040128A |. 48 dec eax
0040128B |. 83C8 F0 or eax, FFFFFFF0
0040128E |. 40 inc eax
0040128F |> 8985 04FCFFFF .mov ss:[ebp-3FC], eax
00401295 \. /E9 DBB10300 .jmp 0043C475 ; //再次到VM去了,再次晕...,再次不管它
不知什么时候又从VM跳回来了
004012B5 /. 8B8D 08FCFFFF mov ecx, ss:[ebp-3F8] ; //取Y
004012BB |. 8D95 90FEFFFF lea edx, [ebp-170]
004012C1 |. 8B85 04FCFFFF mov eax, ss:[ebp-3FC] ; //取X
004012C7 |. C1E1 04 shl ecx, 4
004012CA |. 03C1 add eax, ecx ; //变换成在256字节表中的位置,设为 idx
004012CC |. 03D0 add edx, eax
004012CE |. 8995 04FCFFFF mov ss:[ebp-3FC], edx
004012D4 |. 8A8C05 90FCFFFF mov cl, ss:[eax+ebp-370]
004012DB |. 8AC1 mov al, cl
004012DD |. 888D 37FCFFFF mov ss:[ebp-3C9], cl
004012E3 |. C0C8 02 ror al, 2
004012E6 |. 0FB6C8 movzx ecx, al
004012E9 |. 0FB602 movzx eax, byte ptr ds:[edx]
004012EC |. 33C8 xor ecx, eax ; //取状态 c = T1[idx] ^ ROR(T2[idx])
004012EE |. 83F9 30 cmp ecx, 30 ; //墙,死了
004012F1 |. 0F84 E2000000 je 004013D9
004012F7 |. 83F9 20 cmp ecx, 20 ; //墙,死了
004012FA |. 0F84 D9000000 je 004013D9
00401300 |. 83F9 58 cmp ecx, 58 ; //出口,成功
00401303 |. 0F84 E5000000 je 004013EE
00401309 |. 8B8D 10FCFFFF mov ecx, ss:[ebp-3F0]
0040130F |. 8BC1 mov eax, ecx
00401311 |. 99 cdq
00401312 |. 83E2 0F and edx, 0000000F
00401315 |. 03C2 add eax, edx
00401317 |. C1F8 04 sar eax, 4
0040131A |. 8985 08FCFFFF mov ss:[ebp-3F8], eax
00401320 |. 81E1 0F000080 and ecx, 8000000F
00401326 |. 79 05 jns short 0040132D
00401328 |. 49 dec ecx
00401329 |. 83C9 F0 or ecx, FFFFFFF0
0040132C |. 41 inc ecx
0040132D |> 898D 10FCFFFF mov ss:[ebp-3F0], ecx
00401333 \. E9 DD790300 jmp 00438D15 ; //再再次到VM去了,再再次晕...,再再次不管它
又从VM中跳回来了
004013AA /. 83AD 0CFCFFFF 02 sub dword ptr ss:[ebp-3F4], 2 ; //准备取下一步的数据,2BIT
004013B1 |. 8B85 30FCFFFF mov eax, ss:[ebp-3D0]
004013B7 |. 8B8D 00FCFFFF mov ecx, ss:[ebp-400]
004013BD |.^ 0F89 7DFEFFFF jns 00401240 ; //一字节还没用完,继续取
004013C3 |. 8B8D 2CFCFFFF .mov ecx, ss:[ebp-3D4]
004013C9 |. 41 .inc ecx ; //取下一字节
004013CA |. 898D 2CFCFFFF .mov ss:[ebp-3D4], ecx
004013D0 |. 83F9 17 .cmp ecx, 17 ; //>=23取完了也没走出去,出错
004013D3 |.^ 0F8C 4CFEFFFF .jl 00401225
004013D9 |> 33C0 .xor eax, eax ; //出错,返回0
004013DB |. 5F .pop edi
004013DC |. 5E .pop esi
004013DD |. 8B4D FC .mov ecx, ss:[ebp-4]
004013E0 |. 33CD .xor ecx, ebp
004013E2 |. E8 CF090000 .call 00401DB6
004013E7 |. 8BE5 .mov esp, ebp
004013E9 |. 5D .pop ebp
004013EA |. 8BE3 .mov esp, ebx
004013EC |. 5B .pop ebx
004013ED |. C3 .retn
004013EE |> 8B4D FC mov ecx, ss:[ebp-4] ; //成功,返回1
004013F1 |. B8 01000000 mov eax, 1
004013F6 |. 5F pop edi
004013F7 |. 33CD xor ecx, ebp
004013F9 |. 5E pop esi
004013FA |. E8 B7090000 call 00401DB6
004013FF |. 8BE5 mov esp, ebp
00401401 |. 5D pop ebp
00401402 |. 8BE3 mov esp, ebx
00401404 |. 5B pop ebx
00401405 \. C3 retn
分析上面的代码以及动态查看内存中的值,可以明显看出这就是一个迷宫算法,不过其间还有转到VM去的时候,不知道还干了什么坏事,先不管了,根据墙算法和判断,打印出迷宫图:
const BYTE T1[256];
const BYTE T2[256];
const BYTE KEY[23];
以上三个都是程序中的常量(前面代码中有注释),复制出来。
CString s;
BYTE T3[256]; //这个后面要用,一并算了
for (int i = 0 ; i < sizeof(T1) ; i++)
{
BYTE c = T3[i] = T1 ^ ((T2[i] << 6) | (T2[i] >> 2));
if(c == 0x20 || c == 0x30 || c == 0x58){
s.AppendFormat(" %02X" , c);
}else{
s += " ";
}
if(i % 16 == 15){
s.Append("\r\n");
}
}
OutputDebugString(s);
得到:
30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 58 30 30
由程序中走路算法,人肉得到走路数据:
0代表向上走一步,行减少1
1代表向右走一步,列增加1
2代表向下走一步,行增加1
3代表向左走一步,列减少1
BYTE steps[] = {2,2,2,1,1,1,2,2,2,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,1,1,0,0,0,0,0,0,0,0,3,3,2,2,2,3,3,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,3,3,3,3,3,2,2,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,2,2,2,1,1};
步数不能多于上面这个,不过下面迷宫变了时走法也变了,步数可以少于上面这个.
设输入注册码为:BYTE SN[30];
SN[0-6] = 随便你喜欢,由于它的MD5后面运算需要,不是所有的串都行,因为第一步不能变,只能为2.要没有乱码就要多试几个了,后面的有可能可以调到没有乱码(加步数回走,不过长度不能超过上面的),也可能调不到。
BYTE snMD5[23] = md5(SN[0-6]) //md5长度不够从头补
for(i = 0 ; i < sizeof(steps) ; i += 4)
{
BYTE c = steps[i] << 6;
if(i + 1 < sizeof(steps)) c |= steps[i+1] << 4;
if(i + 2 < sizeof(steps)) c |= steps[i+2] << 2;
if(i + 3 < sizeof(steps)) c |= steps[i+3] << 0;
SN[7 + i / 4] = c ^ T3 ^ snMD5[i / 4]; //T3是前面用T1,T2算出来的
}
如果SN填充不够就随便加字符(现在步数应该刚刚够,不能加,steps变短才要加)
如果SN[0-6]用作者所选的值,现在算出的SN就应该是唯一的了,因为步数刚用完(不知道T2还会不会变成下面的,如果会,那也不是唯一的,因为步数少了)
算了一个SN出来,测试了一下,不过可惜,走到一个位置时,撞墙死了。
再回来找原因,看到那个T2变了,动态跟了一下,这才知道VM里干了坏事.对VM,偶还是只有一句话:再再再次晕...,再再再次不管它
用新的T2重新打印了一个迷宫数据:
30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 20 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30
30 58 30 30 30 30 30 30
30 30 30 30 30 30 30 30 30 30 30 30 30
30 30 30 30 30 30 30 20 30 58 30 30
这时发现另一个出口,还在进去走不了多远的地方,所以减少步数,在另一出口来回走几下(如果直接走到那儿就停,不成功,因为那时还没有那个出口),由于步数少了,还可以根据所选SN[0-6]算的MD5值,在之前的步子上来回走一下,以调整注册码中不出现乱码.
BYTE steps[] = {2,2,2,1,1,1,2,2,2,3,3,2,2,2,2,2,2,2,1,1,1,3,1,3,1,3,1,3}
由T1,新的T2,新的steps,用前面的算法,步数可以重新算N个SN出来,下面给一个解(不过不是全数字,字母):
ctf2016#hl1$[i1W11111111111111
本来很好一个CM,可惜设计上有点问题,算法上SN[0-6]不定,MD5(SN[0-6])也就不定,再同另一个不定的值SN[7-30]计算成一个定值,本身就可以多解(之前有个CM也是差不多这样),再密宫有另一路程较短的出口,步路也成了不定值,更是多解.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
看原图
赞赏
雪币:
留言: