新CrackMe160之064 - CR - Game0
第一关:
OD载入程序, 搜索界面看到成功关键字,定位到0040148C, 向上看到了固定串"JPL-168-39", 输入验证提示成功, 接着又提示失败
所以这个固定串并不是真正的答案, 由IDA分析源码可知:
signed int sub_401403()
{
signed int result; // eax@5
LPARAM lParam; // [sp+0h] [bp-Ch]@1
char v2; // [sp+7h] [bp-5h]@2
char v3; // [sp+Ah] [bp-2h]@3
if ( SendMessageA(hWnd, 0xDu, 0xCu, (LPARAM)&lParam) <= 3 ) //4位以上
goto LABEL_11;
if ( v2 == 32 )
v3 += 31;
if ( !sub_401146(&lParam, &word_401436) ) // 字符串对比, &word_401436 = "JPL-168-39"
{
MessageBoxA(0, "Congratulation! You pass Level 0!", "CR-Game vXO", 0); //进这里就返回0失败,是个幌子
return 0;
}
if ( sub_401146(&lParam, &word_40149E) ) // &word_40149E = "CR-Game vXO"
LABEL_11:
result = 0;
else
result = 1; //需要到这里,所以word_40149E 这个应该才是关键
return result;
}
系列号得4位以上, 00401429处判断第8位如果是空格,那第11位就要加0x1F, 所以最终要与"CR-Game vXO"这个比,那正确的系列号就应该是最后一位反过来减去0x1F, 得到"CR-Game vX0"
输入"CR-Game vX0"这个,第一关过了, 这时界面显示 Level 002
第二关:
由上一关最后返回位置可知所有关的入口在004021B5 ~ 0040221C这些判断里, 直接在最开头(004021B5处)下断点, 这样每一关都可以直接停这里再进对应关
第二关的入口是: 004014C7, IDA对应查看源码:
signed int sub_4014C7()
{
signed int result; // eax@16
LPARAM lParam; // [sp+6h] [bp-Ah]@1
char v2; // [sp+Ah] [bp-6h]@6
char v3; // [sp+Bh] [bp-5h]@7
char v4; // [sp+Ch] [bp-4h]@8
char v5; // [sp+Dh] [bp-3h]@9
char v6; // [sp+Eh] [bp-2h]@10
if ( SendMessageA(hWnd, 0xDu, 0xAu, (LPARAM)&lParam) <= 8
|| (_BYTE)lParam == 67
|| BYTE1(lParam) != 108
|| BYTE2(lParam) == 71 && BYTE3(lParam) != 118
|| v2 != 101
|| v3 == 50 && v4 != 49
|| v5 != 71
|| v6 != 67
|| (v4 += 59, (_BYTE)lParam != 50)
|| BYTE2(lParam) != 101
|| BYTE3(lParam) != 118
|| v3 != 76
|| v4 != 108 )
result = 0;
else
result = 2;
return result;
}
这里看不出什么, 只能知道有个判断,还得看OD代码:
004014C7 /$ 55 push ebp
004014C8 |. 8BEC mov ebp,esp
004014CA |. 83C4 F4 add esp,-0xC
004014CD |. 53 push ebx ; CR-Game0.00401FDA
004014CE |. 8D45 F6 lea eax,dword ptr ss:[ebp-0xA]
004014D1 |. 50 push eax ; /lParam = 0x2
004014D2 |. 6A 0A push 0xA ; |wParam = 0xA
004014D4 |. 6A 0D push 0xD ; |Message = WM_GETTEXT
004014D6 |. FF35 74404000 push dword ptr ds:[0x404074] ; |hWnd = 0x143900
004014DC |. E8 25180000 call <jmp.&user32.SendMessageA> ; \SendMessageA
004014E1 |. 83F8 08 cmp eax,0x8 ; 是否<=8, 9位以上
004014E4 |. 7E 60 jle short CR-Game0.00401546
004014E6 |. 8D5D F6 lea ebx,dword ptr ss:[ebp-0xA]
004014E9 |. 803B 43 cmp byte ptr ds:[ebx],0x43 ; 第1位不能是0x43
004014EC |. 74 58 je short CR-Game0.00401546
004014EE |. 807B 01 6C cmp byte ptr ds:[ebx+0x1],0x6C ; 第2位是0x6C = 'l' (L)
004014F2 |. 75 52 jnz short CR-Game0.00401546
004014F4 |. 807B 02 47 cmp byte ptr ds:[ebx+0x2],0x47 ; 第3位是0x47 = 'G'
004014F8 |. 75 06 jnz short CR-Game0.00401500
004014FA |. 807B 03 76 cmp byte ptr ds:[ebx+0x3],0x76 ; 第4位是0x76 = 'v'
004014FE |. 75 46 jnz short CR-Game0.00401546
00401500 |> 807B 04 65 cmp byte ptr ds:[ebx+0x4],0x65 ; 第5位是0x65 = 'e'
00401504 |. 75 40 jnz short CR-Game0.00401546
00401506 |. 807B 05 32 cmp byte ptr ds:[ebx+0x5],0x32 ; 第6位是0x32 = '2'
0040150A |. 75 06 jnz short CR-Game0.00401512
0040150C |. 807B 06 31 cmp byte ptr ds:[ebx+0x6],0x31 ; 第7位是0x31 = '1'
00401510 |. 75 34 jnz short CR-Game0.00401546
00401512 |> 807B 07 47 cmp byte ptr ds:[ebx+0x7],0x47 ; 第8位是0x47 = 'G'
00401516 |. 75 2E jnz short CR-Game0.00401546
00401518 |. 807B 08 43 cmp byte ptr ds:[ebx+0x8],0x43 ; 第9位是0x43 = 'C'
0040151C |. 75 28 jnz short CR-Game0.00401546
0040151E |. 8043 06 3B add byte ptr ds:[ebx+0x6],0x3B ; 第7位+0x3B=0x6C = 'l' (L)
00401522 |. 803B 32 cmp byte ptr ds:[ebx],0x32 ; 第1位是0x32 = '2'
00401525 |. 75 1F jnz short CR-Game0.00401546
00401527 |. 807B 02 65 cmp byte ptr ds:[ebx+0x2],0x65 ; 第3位是0x65 = 'e'
0040152B |. 75 19 jnz short CR-Game0.00401546
0040152D |. 807B 03 76 cmp byte ptr ds:[ebx+0x3],0x76 ; 第4位是0x76 = 'v'
00401531 |. 75 13 jnz short CR-Game0.00401546
00401533 |. 807B 05 4C cmp byte ptr ds:[ebx+0x5],0x4C ; 第6位是0x4C = 'L'
00401537 |. 75 0D jnz short CR-Game0.00401546
00401539 |. 807B 06 6C cmp byte ptr ds:[ebx+0x6],0x6C ; 第7位是0x6C = 'l' (L)
0040153D |. 75 07 jnz short CR-Game0.00401546
0040153F |. B8 02000000 mov eax,0x2
00401544 |. EB 02 jmp short CR-Game0.00401548
00401546 |> 33C0 xor eax,eax
00401548 |> 5B pop ebx ; CR-Game0.004021CE
00401549 |. C9 leave
0040154A \. C3 retn
00401525 以上可得系列号为: 2lGve21GC, 00401527 ~ 00401539将第3467位换为evLl, 所以最终系列号为: 2leveL1GC (其中第7位还要反减0x3B)
第三关:
同理直接看IDA源码:
signed int sub_40154B()
{
LRESULT v0; // eax@1
int i; // ecx@4
int v2; // ecx@9
int j; // eax@9
signed int result; // eax@13
_BYTE v5[41]; // [sp+7h] [bp-59h]@3 //系列号
LPARAM lParam; // [sp+30h] [bp-30h]@1 //用户名
char v7[27]; // [sp+45h] [bp-1Bh]@4 //固定串 QWERTYUIOPASDFGHJKLZXCVBNM
v0 = SendMessageA(dword_40406C, 0xDu, 0x15u, (LPARAM)&lParam);
if ( (unsigned int)v0 < 5 || v0 > 20 || SendMessageA(hWnd, 0xDu, 0x29u, (LPARAM)v5) != v0 )
{ //用户名长度需要6~20位
LABEL_14:
result = 0;
}
else
{
sub_40118A(v7, "QWERTYUIOPASDFGHJKLZXCVBNM");
for ( i = 0; *((_BYTE *)&lParam + i); ++i )
{
if ( *((_BYTE *)&lParam + i) >= 0x61u ) // 将小写转大写
*((_BYTE *)&lParam + i) -= 32;
}
v2 = 0;
for ( j = (unsigned __int8)lParam; (_BYTE)j; LOBYTE(j) = *((_BYTE *)&lParam + v2) )
{
LOBYTE(j) = j - 65;
if ( v7[j] != v5[v2] ) // 固定串对应位置的值是否等于系列号
goto LABEL_14;
++v2;
}
result = 3;
}
return result;
}
由上代码分析可得, 用户名: abcdef => ABCDEF => 对应固定串 QWERTY, 所以系列号就是: QWERTY
第四关:
同理直接看IDA源码:
signed int sub_401602()
{
LRESULT v0; // eax@1
LPARAM *v1; // ebx@4
int v2; // ecx@4
int i; // eax@4
signed int result; // eax@26
_BYTE v5[41]; // [sp+4h] [bp-74h]@3 //系列号
LPARAM lParam; // [sp+2Dh] [bp-4Bh]@1 //用户名
char v7[27]; // [sp+42h] [bp-36h]@4 //固定串QWERTYUIOPASDFGHJKLZXCVBNM
char v8[27]; // [sp+5Dh] [bp-1Bh]@4 //固定串polkiujmnhytgbvfredcxswqaz
v0 = SendMessageA(dword_40406C, 0xDu, 0x15u, (LPARAM)&lParam); //用户名长度 6 ~ 20
if ( (unsigned int)v0 < 5 || v0 > 20 || SendMessageA(hWnd, 0xDu, 0x29u, (LPARAM)v5) != 2 * v0 )
{
LABEL_27:
result = 0;
}
else
{
v1 = &lParam;
sub_40118A(v8, "polkiujmnhytgbvfredcxswqaz");
sub_40118A(v7, "QWERTYUIOPASDFGHJKLZXCVBNM");
v2 = 0;
for ( i = (unsigned __int8)lParam; (_BYTE)i; LOBYTE(i) = *((_BYTE *)&lParam + v2) )
{
if ( (unsigned __int8)i < 0x61u || (unsigned __int8)i > 0x7Au )
{
if ( (unsigned __int8)i < 0x41u )
goto LABEL_27;
if ( (unsigned __int8)i > 0x5Au )
goto LABEL_27;
LOBYTE(i) = i - 65; //A~Z之间
if ( v7[i] != v5[v2] ) //用大写串
goto LABEL_27;
}
else //如果用户名在a~z之间
{
LOBYTE(i) = i - 97;
if ( v8[i] != v5[v2] ) //用小写串
goto LABEL_27;
}
++v2;
} //下面与上面同理,对比系列号后半部分,所以可知系列号长度应=2倍用户名长度
LOBYTE(i) = lParam;
while ( (_BYTE)i )
{
if ( (unsigned __int8)i < 0x61u || (unsigned __int8)i > 0x7Au )
{
if ( (unsigned __int8)i < 0x41u )
goto LABEL_27;
if ( (unsigned __int8)i > 0x5Au )
goto LABEL_27;
LOBYTE(i) = i - 65; //A~Z
if ( v8[i] != v5[v2] ) //用小写串 与上面不同处
goto LABEL_27;
}
else
{
LOBYTE(i) = i - 97; //a~z
if ( v7[i] != v5[v2] ) //用大写串 与上面不同处
goto LABEL_27;
}
++v2;
v1 = (LPARAM *)((char *)v1 + 1);
LOBYTE(i) = *(_BYTE *)v1;
}
result = 4;
}
return result;
}
固定串QWERTYUIOPASDFGHJKLZXCVBNM
固定串polkiujmnhytgbvfredcxswqaz
所以分析完就很明朗了, 用户名: aBcDeF => 系列号: pWlRiYQoEkTu
第五关:
继续看IDA源码:
signed int sub_40172D()
{
LRESULT v0; // eax@1
int i; // ecx@4
int v2; // ecx@9
char j; // al@9
int k; // ecx@10
signed int result; // eax@17
int v6; // [sp-14h] [bp-8Ch]@10
_BYTE v7[41]; // [sp+4h] [bp-74h]@3
LPARAM lParam; // [sp+2Dh] [bp-4Bh]@1
char v9[27]; // [sp+42h] [bp-36h]@4
char v10[27]; // [sp+5Dh] [bp-1Bh]@4
v0 = SendMessageA(dword_40406C, 0xDu, 0x15u, (LPARAM)&lParam);
if ( (unsigned int)v0 < 5 || v0 > 20 || SendMessageA(hWnd, 0xDu, 0x29u, (LPARAM)v7) != v0 )
{
LABEL_18:
result = 0;
}
else
{
sub_40118A(v10, "QWERTYUIOPASDFGHJKLZXCVBNM");
sub_40118A(v9, "pOlKiUjmnhytgbVfredCXSwqaZ");
for ( i = 0; *((_BYTE *)&lParam + i); ++i )
{
if ( *((_BYTE *)&lParam + i) >= 0x61u ) //小写转大写
*((_BYTE *)&lParam + i) -= 32;
}
v2 = 0;
for ( j = lParam; j; j = *((_BYTE *)&lParam + v6 + 1) )
{
v6 = v2;
for ( k = 0; v10[k] && j != v10[k]; ++k ) //在大写串中找到位置
;
if ( v9[k] != v7[v6] ) //用这个位置在V9串中找到值与系列号对比
goto LABEL_18;
v2 = v6 + 1;
}
result = 5;
}
return result;
}
这个就很明显了, 用户名: QWERTY => 系列号: pOlKiU
第六关:
还是继续直接看IDA源码:
signed int sub_401823()
{
unsigned int v0; // ecx@5
unsigned int v1; // ecx@9
unsigned int v2; // ecx@13
int i; // ecx@19
int v4; // ecx@24
int j; // eax@24
char v7[32]; // [sp+0h] [bp-80h]@24
LPARAM v8; // [sp+20h] [bp-60h]@3 //系列号
char v9; // [sp+24h] [bp-5Ch]@17
int v10; // [sp+25h] [bp-5Bh]@18
int v11; // [sp+29h] [bp-57h]@18
LPARAM v12; // [sp+40h] [bp-40h]@2 //公司名
LPARAM lParam; // [sp+60h] [bp-20h]@1 //用户名
if ( (unsigned int)SendMessageA(dword_40406C, 0xDu, 0x20u, (LPARAM)&lParam) < 5 //用户名5位以上
|| (unsigned int)SendMessageA(dword_404070, 0xDu, 0x20u, (LPARAM)&v12) < 1 //公司名不能空
|| (unsigned int)SendMessageA(hWnd, 0xDu, 0x20u, (LPARAM)&v8) < 0xA ) //系列号长度10位以上
return 0;
if ( (_BYTE)v8 != 74 ) //J
{
v0 = 0;
do
++v0;
while ( v0 < 0x64 );
return 0;
}
if ( BYTE1(v8) != 105 ) //i
{
v1 = 0;
do
++v1;
while ( v1 < 0xC8 );
return 0;
}
if ( BYTE2(v8) != 80 ) //P
{
v2 = 0;
do
++v2;
while ( v2 < 0x12C );
return 0;
}
if ( (v12 & 6) + (_BYTE)lParam != BYTE3(v8)
|| (lParam & 9) + (_BYTE)v12 != v9
|| v11 != lParam + ((v10 ^ lParam) & 0x9070503) )
return 0;
for ( i = 0; *((_BYTE *)&lParam + i); ++i )
{
if ( *((_BYTE *)&lParam + i) >= 0x61u ) // 小写转大写
*((_BYTE *)&lParam + i) -= 32;
}
sub_40118A(v7, "JiP4ZAQWSXCDERFVBGTYHNMJUIKLOP");
v4 = 0;
for ( j = (unsigned __int8)lParam; (_BYTE)j; LOBYTE(j) = *((_BYTE *)&lParam + v4) )
{
LOBYTE(j) = j - 61;
if ( v7[j] != *((_BYTE *)&v8 + v4 + 13) ) // 系列号与用户名转换后对比, 说明用户名长度与系列号长度也得一样
return 0;
++v4;
}
return 6;
}
用户名: abcde
公司名: 1
系列号第1位: 0x4D - 3 = 'J'
系列号第2位: 0x69 = 'i'
系列号第3位: 0x4D + 3 = 'P'
系列号第4位: 0x61 + (0x31 & 6) = 'a'
系列号第5位: ((0x61 & 9) + 0x31) & 0xFF = '2'
系列号第6~9位x: 6~9位 ^ 0x64636261 & 0x9070503 + 0x64636261 == 10~13位 OD测试结果 69:1234那1013则为:abcd
系列号第14~18位: ZAQWS (用户名在固定串对应位置的后4位)
最终:
系列号: JiPa21234abcdZAQWS
第七关:
IDA源码:
signed int sub_401967()
{
LRESULT v0; // eax@2
LRESULT v1; // eax@4
signed int result; // eax@7
char v3; // [sp+5h] [bp-43h]@2
LPARAM v4; // [sp+16h] [bp-32h]@2
LPARAM lParam; // [sp+27h] [bp-21h]@1
char v6; // [sp+33h] [bp-15h]@6
if ( SendMessageA(hWnd, 0xDu, 0x21u, (LPARAM)&lParam) != 16 //系列号长度16位
|| (RtlZeroMemory(&v3, 17),
sub_4012E8(&lParam, &v3),
v0 = SendMessageA(dword_404070, 0xDu, 0x11u, (LPARAM)&v4),
(unsigned int)v0 < 1)
|| (unsigned int)v0 > 0x10
|| (v1 = SendMessageA(dword_40406C, 0xDu, 0x21u, (LPARAM)&lParam), (unsigned int)v1 < 1)
|| (unsigned int)v1 > 0x10
|| (sub_4011AE(&lParam, &v4), v6 = 0, sub_401146(&lParam, &v3)) )
result = 0;
else
result = 7;
return result;
}
代码比较简单,看不出具体算法, 关键在这三个方法 sub_4012E8(base64加密), sub_4011AE(字符串连接), sub_401146(字符串对比)
系列号长度: 16位,
公司名长度: 16位以内,
用户名长度: 16位以内,
算法就是: 系列号 = base64(用户名+公司名)
用户名: abcde
公司名: 12345
系列号: base64("abcde12345") = YWJjZGUxMjM0NQ==
用户名+公司名 的长度需要为10~12位, 加密结果才会是16位
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载
下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~


浙公网安备 33010602011771号