【文章标题】: CrackMe6#分析 附注册机
【文章作者】: lifestill
【作者邮箱】: zhong_sf@sina.com
【软件名称】: CrackMe6#
【保护方式】: 加壳+机器码
【编写语言】: VC++
【使用工具】: OD LordPE importREC PEID
【操作平台】: win7
【详细过程】:
1.PEID查壳,发现在:什么都没找到 [覆盖] ,其实是加了壳的,具体什么壳我也不清楚。
2.OD载入,壳的入口代码如下:
00405001 > E8 03000000 call crackme6.00405009
00405006 - E9 EB045D45 jmp 459D54F6
0040500B 55 push ebp
接下来就是手动脱壳,首先ALT+m 在资源段下内在写断点,F9 断下后,再次ALT+M在代码段下内存读断点,F9 后便来到了,我们要的OEP处,记下OEP:11CB(rva)。OEP处部分代码如下:
004011CB . 64:A1 0100000>mov eax,dword ptr fs:[0x1]
004011D1 /. 55 push ebp
004011D2 |. 89E5 mov ebp,esp
004011D4 |. 6A FF push -0x1
004011D6 |. 68 1C204000 push crackme6.0040201C
004011DB |. 68 9A104000 push crackme6.0040109A
004011E0 |. 50 push eax
004011E1 |. 64:8925 00000>mov dword ptr fs:[0],esp
3.打开LordPE,在OEP处DUMP,得到dumped.exe,
4.找开importREC 重建输入表,但不知道为什么importREC的自己搜索功能此时只能搜索一个导入的DLL(crtdll.dll),如图:
。只有这一个DLL是不可能的,至少USER32,KERNEL等几个就应该有,剩下的只能手动获取了,方法如下:
来到OEP处时,随便找一个API的调用,我这里选 crdll.dll.GetMainArgs:
, 来到crdll.dll.GetMainArgs 调用这句F7跟进,来到:
,用d 0x40313C 查找IAT,发现在:
,现在得到了IAT, 接下来就是手动 获取输入表了,再次打开importREC, 填写OEP后,1.获取KERNEL32.DLL :如图填写:
,获取成功。
2。获取USER32.DLL ,如图,
,此时就有问题了,部分函数显示为无效,这是因为user32.dll的IAT中有另一个dll中的函数 ntdll_1A.NtdllDialogWndProc_A
00403114 75C5CB0C user32.DialogBoxParamA
00403118 75C3B99C user32.EndDialog
0040311C 77ABE659 ntdll_1A.NtdllDialogWndProc_A
00403120 75C76B36 user32.GetDlgItemTextA
00403124 75C1DAD5 user32.LoadCursorA
00403128 75C2434B user32.RegisterClassA
0040312C 75C6FD1E user32.MessageBoxA
00403130 75C2AE5F user32.wsprintfA
可能就是因为这个原因,使得importREC无法定位这个DLL,现在对IAT更改为:
,其中原来ntdll_1A.NtdllDialogWndProc_A 的位置得乱写了一个地址(这个地址只要不是API就行),将ntdll_1A.NtdllDialogWndProc_A地址放在一个新的IAT中。
现在次用importREC,
,将无效的地址剪切了就行。
这样将全部的dll 获取后再FIXDUMP 便新建好了输入表。得dumped_.exe,运行正常,脱壳完成。
下面开始算法分析:
1.来到OEP处时,先删除前面下的内存断点后,bp GetDlgItemTextA, F9跑起来,输入name与SERIAL 后check,来到断点处,回溯后便找到了CALL:
00401528 |. 68 00010000 push 0x100 ; /Count = 100 (256.)
0040152D |. 8D85 00FFFFFF lea eax,[local.64] ; |
00401533 |. 50 push eax ; |Buffer
00401534 |. 6A 65 push 0x65 ; |ControlID = 65 (101.)
00401536 |. FF75 08 push [arg.1] ; |hWnd
00401539 |. E8 FA010000 call crackme6.00401738 ; \GetDlgItemTextA
0040153E |. 89C3 mov ebx,eax
00401540 |. 09DB or ebx,ebx
00401542 |. 75 04 jnz Xcrackme6.00401548
00401544 |. 31C0 xor eax,eax
00401546 |. EB 50 jmp Xcrackme6.00401598
00401548 |> BF BC020000 mov edi,0x2BC
0040154D |. BE 30000000 mov esi,0x30
00401552 |. B8 48000000 mov eax,0x48
00401557 |. 99 cdq
00401558 |. F7FB idiv ebx
0040155A |. 29C6 sub esi,eax ; esi = esi - (eax / Length)
0040155C |. 8D34B6 lea esi,dword ptr ds:[esi+esi*4] ; esi *= 5
0040155F |. 29F7 sub edi,esi
00401561 |. 6BFF 6B imul edi,edi,0x6B
00401564 |. 81EF 6CCF0000 sub edi,0xCF6C ; edi = (edi - esi)*0x6b - 0xCF6C
0040156A |. 81FF 00230000 cmp edi,0x2300 ; if (edi > 0x2300) return 0
00401570 |. 7F 08 jg Xcrackme6.0040157A
00401572 |. 81FF 90010000 cmp edi,0x190
00401578 |. 7D 04 jge Xcrackme6.0040157E ; if (edi >= 0x190 && edi < 0x2300 ) 调用_SubProc (Argc1,AcctLength ,lpAcct)
0040157A |> 31C0 xor eax,eax
0040157C |. EB 1A jmp Xcrackme6.00401598
0040157E |> 8D85 00FFFFFF lea eax,[local.64]
00401584 |. 50 push eax
00401585 |. 53 push ebx
00401586 |. FF75 08 push [arg.1]
00401589 |. E8 77FDFFFF call crackme6.00401305 ; _SubProc (Argc1 ,AcctLength ,lpAcct)
0040158E |. 83C4 0C add esp,0xC
00401591 |. 09C0 or eax,eax
00401593 |. 74 03 je Xcrackme6.00401598
00401595 |. 31C0 xor eax,eax
00401597 |. 40 inc eax
00401598 |> 5F pop edi
00401599 |. 5E pop esi
0040159A |. 5B pop ebx
0040159B |. C9 leave
0040159C \. C3 retn
上面获得NAME后进行了一个检查,若条件不成立则退出,成立则调用 _SubProc (Argc1 ,AcctLength ,lpAcct );
其中 AcctLength 表示name的长度,lpacct表示得到的name的字符数组,Argc1,是上一层调用的参数,其实在后面也没什么用处,
现在跟进_SubProc (...)来到:
00401305 /$ 55 push ebp ; _SubProc (Argc1 ,AcctLength ,lpAcct) {==================
00401306 |. 89E5 mov ebp,esp
00401308 |. 81EC 2C040000 sub esp,0x42C
0040130E |. 53 push ebx
0040130F |. 56 push esi
00401310 |. 57 push edi
00401311 |. 8DBD FCFEFFFF lea edi,[local.65] ; -----------------------------------------
00401317 |. 8D35 38204000 lea esi,dword ptr ds:[0x402038]
0040131D |. B9 40000000 mov ecx,0x40
00401322 |. F3:A5 rep movs dword ptr es:[edi],dword ptr ds>
00401324 |. 8DBD E1FBFFFF lea edi,dword ptr ss:[ebp-0x41F]
0040132A |. 8D35 38214000 lea esi,dword ptr ds:[0x402138]
00401330 |. B9 40000000 mov ecx,0x40
00401335 |. F3:A5 rep movs dword ptr es:[edi],dword ptr ds>
00401337 |. 8DBD E1FDFFFF lea edi,dword ptr ss:[ebp-0x21F] ; 中间这一段都是局部变量初始化为0,部分,不用理会
0040133D |. 8D35 38224000 lea esi,dword ptr ds:[0x402238]
00401343 |. B9 40000000 mov ecx,0x40
00401348 |. F3:A5 rep movs dword ptr es:[edi],dword ptr ds>
0040134A |. 8DBD E1FCFFFF lea edi,dword ptr ss:[ebp-0x31F]
00401350 |. 8D35 38234000 lea esi,dword ptr ds:[0x402338]
00401356 |. B9 40000000 mov ecx,0x40
0040135B |. F3:A5 rep movs dword ptr es:[edi],dword ptr ds>; ----------------------------------------
0040135D |. 8DBD DCFBFFFF lea edi,[local.265]
00401363 |. 8D35 38244000 lea esi,dword ptr ds:[0x402438] ; 这段需要注意:
00401369 |. B9 05000000 mov ecx,0x5
0040136E |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[>; 在local.265 放入字符"%c%s" ,后面要用
00401370 |. 8DBD D6FBFFFF lea edi,dword ptr ss:[ebp-0x42A]
00401376 |. 8D35 3D244000 lea esi,dword ptr ds:[0x40243D]
0040137C |. B9 03000000 mov ecx,0x3
00401381 |. F3:66:A5 rep movs word ptr es:[edi],word ptr ds:[>; 在ebp-0x42A 处放入字符"%s-%d"
00401384 |. 8DBD E1FEFFFF lea edi,dword ptr ss:[ebp-0x11F]
0040138A |. 8D35 43244000 lea esi,dword ptr ds:[0x402443]
00401390 |. B9 1B000000 mov ecx,0x1B
00401395 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[>; 在ebp-0x11f处放入字母表“ABCDEF....Z”
00401397 |. C745 FC 00000>mov [local.1],0x0 ; -------------------------------------------
0040139E |. 68 00010000 push 0x100 ; /Count = 100 (256.)
004013A3 |. 8D85 E1FCFFFF lea eax,dword ptr ss:[ebp-0x31F] ; |
004013A9 |. 50 push eax ; |Buffer = lpPsw = ebp - 0x31F
004013AA |. 6A 66 push 0x66 ; |ControlID = 66 (102.)
004013AC |. FF75 08 push [arg.1] ; |hWnd
004013AF |. E8 84030000 call crackme6.00401738 ; \GetDlgItemTextA
004013B4 |. 09C0 or eax,eax
004013B6 |. 0F84 48010000 je crackme6.00401504
004013BC |. B8 CF110000 mov eax,0x11CF ; -----------------
004013C1 |. 0FB68D E1FCFF>movzx ecx,byte ptr ss:[ebp-0x31F]
004013C8 |. 99 cdq ; if (0x11CF % lpPsw[0] != 0x17) return 0
004013C9 |. F7F9 idiv ecx ; 获取SERIAL后,首先判断首字符是否为“T”,不是则退出
004013CB |. 83FA 17 cmp edx,0x17
004013CE 74 07 je Xcrackme6.004013D7 ; -----------------
004013D0 31C0 xor eax,eax
004013D2 E9 2D010000 jmp crackme6.00401504
004013D7 |> 31DB xor ebx,ebx ; ebx = Counter0 = 0
004013D9 |. EB 0B jmp Xcrackme6.004013E6
004013DB |> 8B45 10 /mov eax,[arg.3] ; ------------------
004013DE |. 0FBE0418 |movsx eax,byte ptr ds:[eax+ebx] ; 循环求name各个字符的和 放入AcctSum
004013E2 |. 0145 FC |add [local.1],eax ; While (Counter0 < AcctLength){
004013E5 |. 43 |inc ebx ; AcctSum += lpAcct[Counter0];
004013E6 |> 3B5D 0C cmp ebx,[arg.2] ; }
004013E9 |.^ 7C F0 \jl Xcrackme6.004013DB ; --------------------
004013EB |. 31DB xor ebx,ebx ; 循环处理各个NAME字符
004013ED |. E9 83000000 jmp crackme6.00401475 ; While (ebx < AcctLength) {
004013F2 |> 8B55 10 /mov edx,[arg.3] ; edx = lpAcct(name字符数组)
004013F5 |. 0FBE3C1A |movsx edi,byte ptr ds:[edx+ebx] ; edi = ActChar(依次取得的各个name字符)
004013F9 |. 8B75 FC |mov esi,[local.1] ; esi = AcctSum
004013FC |. 89D9 |mov ecx,ebx ; -----------
004013FE |. C1E1 02 |shl ecx,0x2
00401401 |. 89DA |mov edx,ebx ; 从字母表中获得字母放入-->ecx
00401403 |. 42 |inc edx
00401404 |. 29D1 |sub ecx,edx
00401406 |. 0FB68C0D E1FE>|movzx ecx,byte ptr ss:[ebp+ecx-0x11F] ; -----------
0040140E |. 89FA |mov edx,edi ; Char为从字母表中取得的字符
00401410 |. 31CA |xor edx,ecx ; edx = AcctChar ^ Char(ecx)
00401412 |. 89F1 |mov ecx,esi ; -----------
00401414 |. 0FAFCB |imul ecx,ebx
00401417 |. 29F1 |sub ecx,esi ; esi = AcctSum(ebx - 1) ^ 0xFFFFFFFF
00401419 |. 89CE |mov esi,ecx
0040141B |. 83F6 FF |xor esi,0xFFFFFFFF ; -----------
0040141E |. 8DB432 4D0100>|lea esi,dword ptr ds:[edx+esi+0x14D] ; esi = (AcctChar ^ Char) + (AcctSum(ebx - 1) ^ 0xFFFFFFFF) + 0x14D
00401425 |. 8B4D 0C |mov ecx,[arg.2]
00401428 |. 89DA |mov edx,ebx
0040142A |. 83C2 03 |add edx,0x3
0040142D |. 0FAFCA |imul ecx,edx
00401430 |. 0FAFCF |imul ecx,edi ; ecx = ( length*(ebx + 3)) * AcctChar
00401433 |. 89F0 |mov eax,esi
00401435 |. 01C8 |add eax,ecx ; eax = esi + ecx
00401437 |. B9 0A000000 |mov ecx,0xA
0040143C |. 31D2 |xor edx,edx
0040143E |. F7F1 |div ecx
00401440 |. 83C2 30 |add edx,0x30 ; edx = ((esi + ecx) % 0xA) + 0x30
00401443 |. 88941D FCFEFF>|mov byte ptr ss:[ebp+ebx-0x104],dl
0040144A |. 0FB6BC1D FCFE>|movzx edi,byte ptr ss:[ebp+ebx-0x104]
00401452 |. 81F7 ACAD0000 |xor edi,0xADAC ; edi = edx ^ 0xADAC
00401458 |. 89DE |mov esi,ebx
0040145A |. 83C6 02 |add esi,0x2
0040145D |. 89F8 |mov eax,edi
0040145F |. 0FAFC6 |imul eax,esi ; eax = (edx ^ 0xADAC) * (ebx+2)
00401462 |. B9 0A000000 |mov ecx,0xA
00401467 |. 99 |cdq
00401468 |. F7F9 |idiv ecx
0040146A |. 83C2 30 |add edx,0x30 ; 交处理后的字符放入新的缓冲区-----szBuffer
0040146D |. 88941D FCFEFF>|mov byte ptr ss:[ebp+ebx-0x104],dl ; ((eax % 0xA)+0x30)-------->szBuffer
00401474 |. 43 |inc ebx
00401475 |> 3B5D 0C cmp ebx,[arg.2]
00401478 |.^ 0F8C 74FFFFFF \jl crackme6.004013F2 ; }
0040147E |. 8D85 FCFEFFFF lea eax,[local.65]
00401484 |. 50 push eax
00401485 |. 6A 54 push 0x54
00401487 |. 8D85 DCFBFFFF lea eax,[local.265] ; 格式化处理过的字符串(其中0x54为"T")得Buff
0040148D |. 50 push eax ; |Format
0040148E |. 8D85 E1FBFFFF lea eax,dword ptr ss:[ebp-0x41F] ; |
00401494 |. 50 push eax ; |Buff = ebp - 0x41f
00401495 |. E8 CE020000 call crackme6.00401768 ; \wsprintf (Buff ,"%c%s" ,0x54 ,szBuffer)
0040149A |. 8B7D 0C mov edi,[arg.2]
0040149D |. 89F8 mov eax,edi
0040149F |. 0FAF45 FC imul eax,[local.1] ; eax = length * AcctSum
004014A3 |. B9 64000000 mov ecx,0x64
004014A8 |. 99 cdq
004014A9 |. F7F9 idiv ecx
004014AB |. 89D7 mov edi,edx ; edi = (length * AcctSum) % 0x64 + 0x30
004014AD |. 83C7 30 add edi,0x30
004014B0 |. 57 push edi
004014B1 |. 8DBD E1FBFFFF lea edi,dword ptr ss:[ebp-0x41F]
004014B7 |. 57 push edi
004014B8 |. 8DBD D6FBFFFF lea edi,dword ptr ss:[ebp-0x42A] ; 再次格式化(新加入一个计算得来数edi)Buff2
004014BE |. 57 push edi ; |Format
004014BF |. 8DBD E1FDFFFF lea edi,dword ptr ss:[ebp-0x21F] ; |
004014C5 |. 57 push edi ; |Buff2 = ebp - 0x21F
004014C6 |. E8 9D020000 call crackme6.00401768 ; \wsprintf (Buff2 ,"%s-%d" ,Buff ,edi)
004014CB |. 83C4 20 add esp,0x20
004014CE |. 8D8D E1FDFFFF lea ecx,dword ptr ss:[ebp-0x21F]
004014D4 |. 83C8 FF or eax,0xFFFFFFFF ; eax = -1
004014D7 |> 40 /inc eax
004014D8 |. 803C01 00 |cmp byte ptr ds:[ecx+eax],0x0
004014DC |.^ 75 F9 \jnz Xcrackme6.004014D7 ; eax = strlen(Buff2)
004014DE |. 50 push eax
004014DF |. 8D85 E1FCFFFF lea eax,dword ptr ss:[ebp-0x31F] ; lpPsw =ebp - 0x31F
004014E5 |. 50 push eax
004014E6 |. 8D85 E1FDFFFF lea eax,dword ptr ss:[ebp-0x21F]
004014EC |. 50 push eax ; 再次调用子函数(_SsubProc (....))
004014ED |. E8 D0FDFFFF call crackme6.004012C2 ; _SsubProc (Buff2 ,lpPsw ,strlen(Buff2))
004014F2 |. 83C4 0C add esp,0xC
004014F5 |. 83F8 00 cmp eax,0x0
004014F8 |. 75 07 jnz Xcrackme6.00401501
004014FA |. B8 00000000 mov eax,0x0
004014FF |. EB 03 jmp Xcrackme6.00401504
00401501 |> 31C0 xor eax,eax
00401503 |. 40 inc eax
00401504 |> 5F pop edi
00401505 |. 5E pop esi
00401506 |. 5B pop ebx
00401507 |. C9 leave
00401508 \. C3 retn
再次跟进_SsubProc (Buff2 ,lpPsw ,strlen(Buff2))
其中lpPs为输入的serial ,来到:
004012C2 /$ 55 push ebp ; ----_SsubProc (Buff2 ,lpPsw ,strlen(Buff2)){
004012C3 |. 89E5 mov ebp,esp
004012C5 |. 53 push ebx
004012C6 |. 56 push esi
004012C7 |. 57 push edi
004012C8 |. 8B5D 10 mov ebx,[arg.3]
004012CB |. 31F6 xor esi,esi
004012CD |. 46 inc esi ; Counter = esi = 1
004012CE |. EB 29 jmp Xcrackme6.004012F9
004012D0 |> 8B55 08 /mov edx,[arg.1] ; While (Counter < strlen(Buff2) ){
004012D3 |. 0FBE3C32 |movsx edi,byte ptr ds:[edx+esi] ; 循环处理Buff2中的各个字符 放入edi
004012D7 |. 89F8 |mov eax,edi
004012D9 |. 83F0 20 |xor eax,0x20 ; eax = Buff2[Counter] ^ 0x20
004012DC |. B9 0A000000 |mov ecx,0xA
004012E1 |. 99 |cdq
004012E2 |. F7F9 |idiv ecx
004012E4 |. 89D7 |mov edi,edx
004012E6 |. 83C7 30 |add edi,0x30 ; edi = (eax % 0xA) + 0x30
004012E9 |. 8B55 0C |mov edx,[arg.2]
004012EC |. 0FBE1432 |movsx edx,byte ptr ds:[edx+esi] ; 将处理过的字符edi 与输入的serial比较,不等则退出
004012F0 |. 39D7 |cmp edi,edx ; if (edi != lpPsw[Counter]) retuen 0
004012F2 74 04 je Xcrackme6.004012F8
004012F4 31C0 xor eax,eax
004012F6 EB 08 jmp Xcrackme6.00401300
004012F8 |> 46 |inc esi
004012F9 |> 39DE cmp esi,ebx
004012FB |.^ 7C D3 \jl Xcrackme6.004012D0 ; }
004012FD |. 31C0 xor eax,eax
004012FF |. 40 inc eax
00401300 |> 5F pop edi
00401301 |. 5E pop esi
00401302 |. 5B pop ebx
00401303 |. 5D pop ebp
00401304 \. C3 retn
算法分析完成,现在开始写注册机,代码如下:
#include <stdio.h>
#include <string.h>
#include <windows.h>
char szBuffer[30] = {0};
char Buff[30] = {0} ,Buff2[30] = {0};
char* _SubProc (int Argc1 ,int length ,char* lpAcct);
int main()
{
char lpAct[30] = {0};
int Length;
printf ("\nPlease Enter The UserName:");
scanf ("%s" ,lpAct);
Length = strlen (lpAct);
int edi = 0x2bc ,esi = 0x30 ,eax = 0x48;
esi = esi - (eax/Length);
esi *= 5;
edi = (edi - esi)*0x6b - 0xcf6c;
if (edi > 0x190 && edi <= 0x2300)
printf ("\n%s\n" ,_SubProc(0 ,Length ,lpAct));
else
printf ("Wrong UserName!!!");
return 0;
}
char* _SubProc(int Argc1 ,int length ,char* lpAcct){
char lpChar[30];
int i ,AcctSum ,esi ,ecx ,eax;
char Rchar;
//填充字符表
for (i = 0 ;i < 26 ; i++)
lpChar[i] = i + 65;
//计算用户名字符和;
for (AcctSum = 0 ,i = 0 ;i < length ;i++)
AcctSum += lpAcct[i];
for (i = 0 ;i < length ;i++){
Rchar = lpChar[i*4 - i -1];
esi = (lpAcct[i] ^Rchar) + (AcctSum*(i - 1)^0xFFFFFFFF) + 0x14D;
ecx = length*(i+3) * lpAcct[i];
eax = esi + ecx;
eax = ((eax%10 +0x30)^0xADAC) * (i+2);
szBuffer[i] = eax % 10 + 0x30;
}
wsprintf (Buff ,"%c%s" ,0x54 ,szBuffer);
eax = (length * AcctSum) % 0x64 + 0x30;
wsprintf (Buff2 ,"%s-%d" ,Buff ,eax);
for (i = 1 ;i < strlen(Buff2) ;i++)
Buff2[i] = (Buff2[i]^0x20) % 10 +0x30;
return Buff2;
}
[课程]Linux pwn 探索篇!