【破文标题】CR-Game vXO crackme 0.7 算法分析
【破文作者】cAtEyE[DFCG][BCG]
【破解工具】Ollydbg 1.10a
【破解平台】 Win2000/XP
【软件名称】CR-Game vXO crackme 0.7
【破解声明】我是一只小小流浪猫,所学知识甚微,若有失误请大侠们多多指教!
=====================================================================================
运行CR-Game0.7,可以看到左下角Level 001,那里是设置破解的难度,CTRL+SHIFT+ALT+E来设定.
我们直接跳到Level 007.
OD载入CR-Game0.7,搜索字符参考,来到:
0040221C |> \E8>call CR-Game0.00401967 //关键CALL,我们跟进
00402221 |. 83>cmp eax,0
00402224 |. 0F>je CR-Game0.004022B3
0040222A |. EB>jmp short CR-Game0.00402248
0040222C |. 59>ascii "You have passed "
0040223C |. 61>ascii "all levels.",0
00402248 |> EB>jmp short CR-Game0.00402259
0040224A |. 43>ascii "Congratulation",0
00402259 |> 68>push 1000 ; /Style = MB_OK|MB_SYSTEMMODAL
0040225E |. 68>push CR-Game0.0040224A ; |Title = "Congratulation"
00402263 |. 68>push CR-Game0.0040222C ; |Text = "You have passed all levels."
00402268 |. FF>push dword ptr ss:[ebp+8] ; |hOwner
....
跟进0040221C关键CALL后来到:
00401971 |. 50 push eax ; /lParam
00401972 |. 6A>push 21 ; |wParam = 21
00401974 |. 6A>push 0D ; |Message = WM_GETTEXT 取注册码
00401976 |. FF>push dword ptr ds:[404074] ; |hWnd = 2017A
0040197C |. E8>call <jmp.&user32.SendMessageA> ; \SendMessageA
00401981 |. 83>cmp eax,10
00401984 |. 75>jnz short CR-Game0.00401A05 //长度必须为16位
00401986 |. 6A>push 11 ; /Length = 11 (17.)
00401988 |. 8D>lea eax,dword ptr ss:[ebp-43] ; |
0040198B |. 50 push eax ; |Destination
0040198C |. E8>call <jmp.&kernel32.RtlZeroMemory> ; \RtlZeroMemory
00401991 |. 8D>lea eax,dword ptr ss:[ebp-43]
00401994 |. 50 push eax ; /Arg2 注册假码1234567890123456
00401995 |. 8D>lea eax,dword ptr ss:[ebp-21] ; |
00401998 |. 50 push eax ; |Arg1
00401999 |. E8>call CR-Game0.004012E8 ; \CR-Game0.004012E8 注册码算法,跟进后,算法还是比较清晰:
eax=0040401C (CR-Game0.0040401C), ASCII
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
ebx=0012FAFD
1-取第一位注册码,与上面的表中字符相比较,判断其位置,数值然后左移6位,得到Data1
2-取第二位注册码,与上面的表中字符相比较,判断其位置,数值加上Data1,再左移6位,得到Data2
3-取第三位注册码,与上面的表中字符相比较,判断其位置,数值加上Data2,再左移6位,得到Data3
4-取第四位注册码,与上面的表中字符相比较,判断其位置,数值加上Data3,得到Data4,Data4就是第一组加密后的数值
5-重复1~4得到第二,第三组加密后的数值
0040199E |. 8D>lea eax,dword ptr ss:[ebp-32]
004019A1 |. 50 push eax ; /lParam
004019A2 |. 6A>push 11 ; |wParam = 11
004019A4 |. 6A>push 0D ; |Message = WM_GETTEXT 取公司名
004019A6 |. FF>push dword ptr ds:[404070] ; |hWnd = 901C4
004019AC |. E8>call <jmp.&user32.SendMessageA> ; \SendMessageA
004019B1 |. 83>cmp eax,1 //公司名不能为空
004019B4 |. 72>jb short CR-Game0.00401A05
004019B6 |. 83>cmp eax,10 //公司名大于16位时,取左边16位
004019B9 |. 77>ja short CR-Game0.00401A05
004019BB |. 8D>lea eax,dword ptr ss:[ebp-21]
004019BE |. 50 push eax ; /lParam
004019BF |. 6A>push 21 ; |wParam = 21
004019C1 |. 6A>push 0D ; |Message = WM_GETTEXT 取用户名
004019C3 |. FF>push dword ptr ds:[40406C] ; |hWnd = 200CE
004019C9 |. E8>call <jmp.&user32.SendMessageA> ; \SendMessageA
004019CE |. 83>cmp eax,1
004019D1 |. 72>jb short CR-Game0.00401A05
004019D3 |. 83>cmp eax,10
004019D6 |. 77>ja short CR-Game0.00401A05 //用户名必须小于等于16位
004019D8 |. 8D>lea eax,dword ptr ss:[ebp-32]
004019DB |. 50 push eax
004019DC |. 8D>lea eax,dword ptr ss:[ebp-21]
004019DF |. 50 push eax
004019E0 |. E8>call CR-Game0.004011AE //跟进发现里面是用户名和公司名相连接
004019E5 |. 8D>lea esi,dword ptr ss:[ebp-21] ; //堆栈地址=0012FB1F, (ASCII
"cAtEyEBCGDFCGEXETOOLES")
004019E8 |. C6>mov byte ptr ds:[esi+C],0 ; //Stack ds:[0012FB2B]=47 ('G'),取左边12位
004019EC |. 8D>lea eax,dword ptr ss:[ebp-43] ; //cAtEyEBCGDFC
004019EF |. 50 push eax
004019F0 |. 8D>lea eax,dword ptr ss:[ebp-21] ; //堆栈地址=0012FB1F, (ASCII
"cAtEyEBCGDFC")
004019F3 |. 50 push eax
004019F4 |. E8>call CR-Game0.00401146 //关键CALL,跟进
004019F9 |. 83>cmp eax,0
004019FC |. 75>jnz short CR-Game0.00401A05
004019FE |. B8>mov eax,7
00401A03 |. EB>jmp short CR-Game0.00401A07
00401A05 |> 33>xor eax,eax
00401A07 |> 5E pop esi
00401A08 |. C9 leave
00401A09 \. C3 retn
---
跟进004019E0 CALL:
004011AE /$ 55 push ebp
004011AF |. 8B>mov ebp,esp
004011B1 |. 57 push edi
004011B2 |. FF>push dword ptr ss:[ebp+8]
004011B5 |. E8>call CR-Game0.00401128 //取用户名"cAtEyE"长度6
004011BA |. 8B>mov edi,dword ptr ss:[ebp+8] //ss:[0012FAF0]=0012FB1F, ("cAtEyE")
004011BD |. 8B>mov ecx,dword ptr ss:[ebp+C] //ss:[0012FAF4]=0012FB0E,
("BCGDFCGEXETOOLES")
004011C0 |. 03>add edi,eax
004011C2 |. 33>xor edx,edx
004011C4 |. 33>xor eax,eax
004011C6 |> 8A>/mov al,byte ptr ds:[edx+ecx] /////////////////////////
004011C9 |. 88>|mov byte ptr ds:[edx+edi],al //RegName & ComName 连接
004011CC |. 83>|add edx,1
004011CF |. 84>|test al,al
004011D1 |.^ 75>\jnz short CR-Game0.004011C6 /////////////////////////
004011D3 |. 5F pop edi
004011D4 |. 8B>mov eax,dword ptr ss:[ebp+8] //ss:[0012FAF0]=0012FB1F,
("cAtEyEBCGDFCGEXETOOLES")
004011D7 |. C9 leave
004011D8 \. C2>retn 8
...
跟进 004019F4的关键CALL:
0040114C |. 8B>mov edi,dword ptr ss:[ebp+8] ; //"cAtEyEBCGDFC"
0040114F |. 8B>mov esi,dword ptr ss:[ebp+C] ; //"cAtEyEBCGDFC"
00401152 |. 8A>mov al,byte ptr ds:[edi]
00401154 |. 33>xor ecx,ecx
00401156 |. EB>jmp short CR-Game0.0040115C
00401158 |> 41 /inc ecx
00401159 |. 8A>|mov al,byte ptr ds:[ecx+edi]
0040115C |> 0A> or al,al
0040115E |.^ 75>\jnz short CR-Game0.00401158 ; //取"cAtEyEBCGDFC"的长度
00401160 |. EB>jmp short CR-Game0.0040116F
00401162 |> 8A>/mov al,byte ptr ds:[ecx+edi] ; //Stack ds:[0012FB2B]=00,"cAtEyEBCGDFC"的末尾开始取
00401165 |. 3A>|cmp al,byte ptr ds:[ecx+esi] ; //注册码按算法生成的中间码必须是用户名和公司名相连后的左边12位,注册才成功
00401168 |. 74>|je short CR-Game0.0040116E
0040116A |. 7F>|jg short CR-Game0.0040117E
0040116C |. 7C>|jl short CR-Game0.00401177
0040116E |> 49 |dec ecx
0040116F |> 0B> or ecx,ecx ; //长度为12
00401171 |.^ 75>\jnz short CR-Game0.00401162
00401173 |. 33>xor eax,eax //清注册标记eax
00401175 |. EB>jmp short CR-Game0.00401183
00401177 |> B8>mov eax,-1
0040117C |. EB>jmp short CR-Game0.00401183
0040117E |> B8>mov eax,1 //注册失败标记eax=1
00401183 |> 59 pop ecx
00401184 |. 5E pop esi
00401185 |. 5F pop edi
00401186 |. C9 leave
00401187 \. C2>retn 8
注册机算法:
1- 取用户名长度,判断是否在1~16位
2- 取公司名长度,判断是否大于1位
3- 连接用户名和公司名并取左边12位,参加解密
4- 取这12位字符的ASCCII码,这就是00401165中注册成功的中间生成码
5- 按照如下加密逆运算,生成注册码.
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
ebx=0012FAFD
1-取第一位注册码,与上面的表中字符相比较,判断其位置,数值然后左移6位,得到Data1
2-取第二位注册码,与上面的表中字符相比较,判断其位置,数值加上Data1,再左移6位,得到Data2
3-取第三位注册码,与上面的表中字符相比较,判断其位置,数值加上Data2,再左移6位,得到Data3
4-取第四位注册码,与上面的表中字符相比较,判断其位置,数值加上Data3,得到Data4,Data4就是第一组加密后的数值
5-重复1~4得到第二,第三组加密后的数值
其中左右移转换时,要保证CF = 0
to moon:
你的注册机有BUG:用户名,公司名小于6位时试试.:D :D
测试下我的这个:
附件:Keygen.rar
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)