-
-
[原创]czCrackme 09破解及注册源码
-
发表于: 2007-4-9 10:02 6458
-
【文章标题】: czCrackme 09破解及注册源码
【文章作者】: hud
【软件名称】: czCrackme.exe
【软件下载】: 见附件
【软件大小】: 96 KB
【加壳方式】: 无
【保护方式】: 序列号
【编写语言】: MASM32/TASM32
【使用工具】: Ollydbg
【操作平台】: Win32 XP
【作者声明】: 这是一个很旧的Crackme,之所以发出来,基于以下3点:
1. 练习时找到的旧crackme,中间曾有些疑惑,但网上搜了一下,好像还没人发过破文;
2. 这个crackme使用了一个API函数的尾地址作为初值,因此在不同的机上可能值不同。还有就是嵌套循环,没理清它的流程时容易迷,其它就没什么特别的地方了;
3. 我的注册机用的是最笨的穷举,应该会有不用穷举更直接的办法吧,借此抛砖引玉。
【详细过程】:
下断于GetWindowTextA,输入“pediy”和7654321,F9运行,断下后alt+F9到用户代码:
00401340 |. 6A 4>push 40 ; /Count = 40 (64.)
00401342 |. 68 3>push czCrackm.00403130 ; |Buffer = czCrackm.00403130
00401347 |. FF35>push dword ptr ds:[4030C3] ; |hWnd = 0037024A
(class='Edit',parent=006801CA)
0040134D |. E8 A>call <jmp.&USER32.GetWindowTextA> ; \GetWindowTextA
00401352 |. 83F8>cmp eax,4 ; Name长度要大于4
00401355 |. 0F8E>jle czCrackm.00401444
0040135B |. 6A 4>push 40 ; /Count = 40 (64.)
0040135D |. 68 7>push czCrackm.00403170 ; |Buffer = czCrackm.00403170
00401362 |. 68 B>push 0BB9 ; |ControlID = BB9 (3001.)
00401367 |. FF75>push dword ptr ss:[ebp+8] ; |hWnd
0040136A |. E8 7>call <jmp.&USER32.GetDlgItemTextA>; \GetDlgItemTextA
0040136F |. 83F8>cmp eax,4 ; 试练码要大于4
00401372 |. /0F8E>jle czCrackm.00401444 ; 小于4则跳死
00401378 |. |A3 B>mov dword ptr ds:[4030BF],eax
0040137D |. |FF35>push dword ptr ds:[4030C3] ; /hWnd = 0037024A
(class='Edit',parent=006801CA)
00401383 |. |E8 A>call <jmp.&USER32.SetFocus> ; \SetFocus
00401388 |. |BF 3>mov edi,czCrackm.00403130 ; ASCII "pediy"
0040138D |. |BE 3>mov esi,czCrackm.00403130 ; ASCII "pediy"
00401392 |> |AC /lods byte ptr ds:[esi]
00401393 |. |0C 0>|or al,0 ; 此循环确保字符不小于0x20
00401395 |. |74 0>|je short czCrackm.0040139C
00401397 |. |0C 2>|or al,20 ; Name[i] or 20,小于则+
00401399 |. |AA |stos byte ptr es:[edi] ; 结果放入edi
0040139A |.^|EB F>\jmp short czCrackm.00401392
0040139C |> \BF 7>mov edi,czCrackm.00403170 ; ASCII "7654321"
004013A1 |. BE 7>mov esi,czCrackm.00403170 ; ASCII "1654321"
004013A6 |. 8D1D>lea ebx,dword ptr ds:[403130]
下面循环:Name[i] – SN[i],若其中一个长度短于另一个,则取值为0,所得值设为val1:
004013AC |> /AC /lods byte ptr ds:[esi]
004013AD |. |0C>|or al,0
004013AF |. |74>|je short czCrackm.004013BB
004013B1 |. |8A>|mov dl,byte ptr ds:[ebx]
004013B3 |. |2A>|sub dl,al ; Name[i]-SN[i]
004013B5 |. |8A>|mov al,dl
004013B7 |. |AA |stos byte ptr es:[edi] ; 所得值设为val1
004013B8 |. |43 |inc ebx
004013B9 |.^\EB>\jmp short czCrackm.004013AC
004013BB |> \8B0D>mov ecx,dword ptr ds:[4030BF]
下面开始一个嵌套循环:
004013C1 |> /80>/or cl,0 ; For (i = Len(SN); i>0; --i)
004013C4 |. |74>|je short czCrackm.00401426
004013C6 |. |51 |push ecx
004013C7 |. |68>|push czCrackm.00403170 ; val1
004013CC |. |E8>|call czCrackm.00401654 ; 进入,详见下面,得val2
004013D1 |. |F7>|mul ecx ; i * val2
004013D3 |. |68>|push czCrackm.004031B0
004013D8 |. |50 |push eax
004013D9 |. |E8>|call czCrackm.0040169C ; 化成10进制字符串s
004013DE |. |BF>|mov edi,czCrackm.004031B0
004013E3 |. |BE>|mov esi,czCrackm.004031B0
下面这个循环中间的小循环取10进制字符串s各位的低1位:
004013E8 |> |AC |/lods byte ptr ds:[esi] ; 取s各位
004013E9 |. |0C>||or al,0
004013EB |. |74>||je short czCrackm.004013F3
004013ED |. |83>||and eax,0F ; 取s各位低1位
004013F0 |. |AA ||stos byte ptr es:[edi]
004013F1 |.^|EB>|\jmp short czCrackm.004013E8
004013F3 |> |8B>|mov ecx,dword ptr ds:[4030BF]
004013F9 |. |D1>|shr ecx,1 ; 试练码长度\2, 设为m
004013FB |. |BF>|mov edi,czCrackm.004030F0
00401400 |. |BE>|mov esi,czCrackm.004031B0
00401405 |. |8D>|lea ebx,dword ptr ds:[ecx+4031B0]
下面这个循环中的小循环形成最后的比较值v3:
0040140B |> |80>|/or cl,0 ; For i=1 to m
0040140E |. |74>||je short czCrackm.00401422
00401410 |. |AC ||lods byte ptr ds:[esi] ; s[i]
00401411 |. |33>||xor edx,edx
00401413 |. |8A>||mov dl,byte ptr ds:[ebx] ; s[i+m]
00401415 |. |02>||add al,dl ; v3[i] = s[i] + s[i+m]
00401417 |. |8A>||mov dl,byte ptr ds:[edi]
00401419 |. |02>||add al,dl
0040141B |. |24>||and al,0F ; 取v3[i]低1位
0040141D |. |AA ||stos byte ptr es:[edi]
0040141E |. |49 ||dec ecx
0040141F |. |43 ||inc ebx
00401420 |.^|EB>|\jmp short czCrackm.0040140B
00401422 |> |59 |pop ecx
00401423 |. |49 |dec ecx
00401424 |.^\EB>\jmp short czCrackm.004013C1 ; 大循环回去
00401426 |> BE>mov esi,czCrackm.004030F0
0040142B |. 8B>mov ebx,dword ptr ds:[4030BF]
00401431 |. 8B>mov ecx,ebx
00401433 |. D1>shr ecx,1
比较的循环,相当于:
for (i=0; i<m; ++i)
if (v3[i]!=SN长度)
失败
00401435 |> 8A>/mov al,byte ptr ds:[esi]
00401437 |. 80>|or cl,0
0040143A |. 74>|je short czCrackm.00401475
0040143C |. 38>|cmp al,bl
0040143E |. 75>|jnz short czCrackm.00401444
00401440 |. 46 |inc esi
00401441 |. 49 |dec ecx
00401442 |.^ EB>\jmp short czCrackm.00401435
如果v3从1到m (注册码长度整除2)位都等于SN长度,则成功。
进入004013C4处的Call (得到val2):
00401654 /$ 55 push ebp ; 外层循环
00401655 |. 8B>mov ebp,esp
00401657 |. 51 push ecx ; nLen
00401658 |. 57 push edi
00401659 |. 52 push edx
0040165A |. 56 push esi
0040165B |. 33>xor ecx,ecx
0040165D |. 8B>mov edi,[arg.1] ; val1,下面得出长度
00401660 |. FF>push [arg.1] ; /String
00401663 |. E8>call <jmp.&KERNEL32.lstrlenA>; \lstrlenA
00401668 |. EB>jmp short czCrackm.0040168D
0040166A |> >/xor edx,edx ; 循环
0040166C |. >|mov dl,byte ptr ds:[edi] ; val1[i]
0040166E |. >|sub dl,30 ; val1[i] - 30
00401671 |. >|mov esi,eax
00401673 |. >|dec esi ; --i
00401674 |. >|push eax
00401675 |. >|mov eax,edx
00401677 |. >|push ebx
00401678 |. >|mov ebx,0A ; 相当于:
for (i=nLen-1; i>0; --1)
For (j=0; j<i; ++j)
val1[i] * 10;
0040167D |. >|jmp short czCrackm.00401682
0040167F |> >|/mul ebx
00401681 |. >||dec esi
00401682 |> >| cmp esi,0
00401685 |.^ >|\ja short czCrackm.0040167F
00401687 |. >|pop ebx
00401688 |. >|add ecx,eax ; 累加(初值为函数lstrlenA末尾地址)
0040168A |. >|pop eax
0040168B |. >|inc edi
0040168C |. >|dec eax
0040168D |> > or eax,eax
0040168F |.^ >\jnz short czCrackm.0040166A ; 内层循环1回去
00401691 |. >mov eax,ecx
00401693 |. >pop esi
00401694 |. >pop edx
00401695 |. >pop edi
00401696 |. >pop ecx
00401697 |. >leave
00401698 \. >retn 4
/****************************************************************************
算法:
1. Name和注册码要5位以上;
2. Name各位-SN各位取低二位,得val1;
3. 从1到试练码长度循环 for(i=0; i<nSNLen; ++i);
4. val1各位减0x30取低2位*10的i-1次方相加;
3. 再加lstrlen函数的尾地址;
4. 乘以循环变量;
5. 化为10进制字符s;
6. 取s各位字符低1位为val2;
7. 从1至m(试练码长度\2);
8. v2各位+(v2+m)+v3各位,然后取低1位为v3,即:
v3[i] = ( v2[i] + v2[i+m] + v3[i] ) & 0x0F;
9. 上面v3循环使用,第一次各位为0。
10.如果v3的前(试练码长度\2)位都等于试练码长度则成功;
Name文本框最多只接受11位,SN文本框只接受16位;
******************************************************************************/
【注册机】: 见附件2
【VC++6.0注册源码】:
这里只是自已添加上去的代码,不包括自动生成的,写得很烂,高手见笑了。
一般在1、2分鉮内就能算出注册码,我算出来的注册码全部是7位长,hash值(v3)全部是:777
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年04月09日 8:47:06
【文章作者】: hud
【软件名称】: czCrackme.exe
【软件下载】: 见附件
【软件大小】: 96 KB
【加壳方式】: 无
【保护方式】: 序列号
【编写语言】: MASM32/TASM32
【使用工具】: Ollydbg
【操作平台】: Win32 XP
【作者声明】: 这是一个很旧的Crackme,之所以发出来,基于以下3点:
1. 练习时找到的旧crackme,中间曾有些疑惑,但网上搜了一下,好像还没人发过破文;
2. 这个crackme使用了一个API函数的尾地址作为初值,因此在不同的机上可能值不同。还有就是嵌套循环,没理清它的流程时容易迷,其它就没什么特别的地方了;
3. 我的注册机用的是最笨的穷举,应该会有不用穷举更直接的办法吧,借此抛砖引玉。
【详细过程】:
下断于GetWindowTextA,输入“pediy”和7654321,F9运行,断下后alt+F9到用户代码:
00401340 |. 6A 4>push 40 ; /Count = 40 (64.)
00401342 |. 68 3>push czCrackm.00403130 ; |Buffer = czCrackm.00403130
00401347 |. FF35>push dword ptr ds:[4030C3] ; |hWnd = 0037024A
(class='Edit',parent=006801CA)
0040134D |. E8 A>call <jmp.&USER32.GetWindowTextA> ; \GetWindowTextA
00401352 |. 83F8>cmp eax,4 ; Name长度要大于4
00401355 |. 0F8E>jle czCrackm.00401444
0040135B |. 6A 4>push 40 ; /Count = 40 (64.)
0040135D |. 68 7>push czCrackm.00403170 ; |Buffer = czCrackm.00403170
00401362 |. 68 B>push 0BB9 ; |ControlID = BB9 (3001.)
00401367 |. FF75>push dword ptr ss:[ebp+8] ; |hWnd
0040136A |. E8 7>call <jmp.&USER32.GetDlgItemTextA>; \GetDlgItemTextA
0040136F |. 83F8>cmp eax,4 ; 试练码要大于4
00401372 |. /0F8E>jle czCrackm.00401444 ; 小于4则跳死
00401378 |. |A3 B>mov dword ptr ds:[4030BF],eax
0040137D |. |FF35>push dword ptr ds:[4030C3] ; /hWnd = 0037024A
(class='Edit',parent=006801CA)
00401383 |. |E8 A>call <jmp.&USER32.SetFocus> ; \SetFocus
00401388 |. |BF 3>mov edi,czCrackm.00403130 ; ASCII "pediy"
0040138D |. |BE 3>mov esi,czCrackm.00403130 ; ASCII "pediy"
00401392 |> |AC /lods byte ptr ds:[esi]
00401393 |. |0C 0>|or al,0 ; 此循环确保字符不小于0x20
00401395 |. |74 0>|je short czCrackm.0040139C
00401397 |. |0C 2>|or al,20 ; Name[i] or 20,小于则+
00401399 |. |AA |stos byte ptr es:[edi] ; 结果放入edi
0040139A |.^|EB F>\jmp short czCrackm.00401392
0040139C |> \BF 7>mov edi,czCrackm.00403170 ; ASCII "7654321"
004013A1 |. BE 7>mov esi,czCrackm.00403170 ; ASCII "1654321"
004013A6 |. 8D1D>lea ebx,dword ptr ds:[403130]
下面循环:Name[i] – SN[i],若其中一个长度短于另一个,则取值为0,所得值设为val1:
004013AC |> /AC /lods byte ptr ds:[esi]
004013AD |. |0C>|or al,0
004013AF |. |74>|je short czCrackm.004013BB
004013B1 |. |8A>|mov dl,byte ptr ds:[ebx]
004013B3 |. |2A>|sub dl,al ; Name[i]-SN[i]
004013B5 |. |8A>|mov al,dl
004013B7 |. |AA |stos byte ptr es:[edi] ; 所得值设为val1
004013B8 |. |43 |inc ebx
004013B9 |.^\EB>\jmp short czCrackm.004013AC
004013BB |> \8B0D>mov ecx,dword ptr ds:[4030BF]
下面开始一个嵌套循环:
004013C1 |> /80>/or cl,0 ; For (i = Len(SN); i>0; --i)
004013C4 |. |74>|je short czCrackm.00401426
004013C6 |. |51 |push ecx
004013C7 |. |68>|push czCrackm.00403170 ; val1
004013CC |. |E8>|call czCrackm.00401654 ; 进入,详见下面,得val2
004013D1 |. |F7>|mul ecx ; i * val2
004013D3 |. |68>|push czCrackm.004031B0
004013D8 |. |50 |push eax
004013D9 |. |E8>|call czCrackm.0040169C ; 化成10进制字符串s
004013DE |. |BF>|mov edi,czCrackm.004031B0
004013E3 |. |BE>|mov esi,czCrackm.004031B0
下面这个循环中间的小循环取10进制字符串s各位的低1位:
004013E8 |> |AC |/lods byte ptr ds:[esi] ; 取s各位
004013E9 |. |0C>||or al,0
004013EB |. |74>||je short czCrackm.004013F3
004013ED |. |83>||and eax,0F ; 取s各位低1位
004013F0 |. |AA ||stos byte ptr es:[edi]
004013F1 |.^|EB>|\jmp short czCrackm.004013E8
004013F3 |> |8B>|mov ecx,dword ptr ds:[4030BF]
004013F9 |. |D1>|shr ecx,1 ; 试练码长度\2, 设为m
004013FB |. |BF>|mov edi,czCrackm.004030F0
00401400 |. |BE>|mov esi,czCrackm.004031B0
00401405 |. |8D>|lea ebx,dword ptr ds:[ecx+4031B0]
下面这个循环中的小循环形成最后的比较值v3:
0040140B |> |80>|/or cl,0 ; For i=1 to m
0040140E |. |74>||je short czCrackm.00401422
00401410 |. |AC ||lods byte ptr ds:[esi] ; s[i]
00401411 |. |33>||xor edx,edx
00401413 |. |8A>||mov dl,byte ptr ds:[ebx] ; s[i+m]
00401415 |. |02>||add al,dl ; v3[i] = s[i] + s[i+m]
00401417 |. |8A>||mov dl,byte ptr ds:[edi]
00401419 |. |02>||add al,dl
0040141B |. |24>||and al,0F ; 取v3[i]低1位
0040141D |. |AA ||stos byte ptr es:[edi]
0040141E |. |49 ||dec ecx
0040141F |. |43 ||inc ebx
00401420 |.^|EB>|\jmp short czCrackm.0040140B
00401422 |> |59 |pop ecx
00401423 |. |49 |dec ecx
00401424 |.^\EB>\jmp short czCrackm.004013C1 ; 大循环回去
00401426 |> BE>mov esi,czCrackm.004030F0
0040142B |. 8B>mov ebx,dword ptr ds:[4030BF]
00401431 |. 8B>mov ecx,ebx
00401433 |. D1>shr ecx,1
比较的循环,相当于:
for (i=0; i<m; ++i)
if (v3[i]!=SN长度)
失败
00401435 |> 8A>/mov al,byte ptr ds:[esi]
00401437 |. 80>|or cl,0
0040143A |. 74>|je short czCrackm.00401475
0040143C |. 38>|cmp al,bl
0040143E |. 75>|jnz short czCrackm.00401444
00401440 |. 46 |inc esi
00401441 |. 49 |dec ecx
00401442 |.^ EB>\jmp short czCrackm.00401435
如果v3从1到m (注册码长度整除2)位都等于SN长度,则成功。
进入004013C4处的Call (得到val2):
00401654 /$ 55 push ebp ; 外层循环
00401655 |. 8B>mov ebp,esp
00401657 |. 51 push ecx ; nLen
00401658 |. 57 push edi
00401659 |. 52 push edx
0040165A |. 56 push esi
0040165B |. 33>xor ecx,ecx
0040165D |. 8B>mov edi,[arg.1] ; val1,下面得出长度
00401660 |. FF>push [arg.1] ; /String
00401663 |. E8>call <jmp.&KERNEL32.lstrlenA>; \lstrlenA
00401668 |. EB>jmp short czCrackm.0040168D
0040166A |> >/xor edx,edx ; 循环
0040166C |. >|mov dl,byte ptr ds:[edi] ; val1[i]
0040166E |. >|sub dl,30 ; val1[i] - 30
00401671 |. >|mov esi,eax
00401673 |. >|dec esi ; --i
00401674 |. >|push eax
00401675 |. >|mov eax,edx
00401677 |. >|push ebx
00401678 |. >|mov ebx,0A ; 相当于:
for (i=nLen-1; i>0; --1)
For (j=0; j<i; ++j)
val1[i] * 10;
0040167D |. >|jmp short czCrackm.00401682
0040167F |> >|/mul ebx
00401681 |. >||dec esi
00401682 |> >| cmp esi,0
00401685 |.^ >|\ja short czCrackm.0040167F
00401687 |. >|pop ebx
00401688 |. >|add ecx,eax ; 累加(初值为函数lstrlenA末尾地址)
0040168A |. >|pop eax
0040168B |. >|inc edi
0040168C |. >|dec eax
0040168D |> > or eax,eax
0040168F |.^ >\jnz short czCrackm.0040166A ; 内层循环1回去
00401691 |. >mov eax,ecx
00401693 |. >pop esi
00401694 |. >pop edx
00401695 |. >pop edi
00401696 |. >pop ecx
00401697 |. >leave
00401698 \. >retn 4
/****************************************************************************
算法:
1. Name和注册码要5位以上;
2. Name各位-SN各位取低二位,得val1;
3. 从1到试练码长度循环 for(i=0; i<nSNLen; ++i);
4. val1各位减0x30取低2位*10的i-1次方相加;
3. 再加lstrlen函数的尾地址;
4. 乘以循环变量;
5. 化为10进制字符s;
6. 取s各位字符低1位为val2;
7. 从1至m(试练码长度\2);
8. v2各位+(v2+m)+v3各位,然后取低1位为v3,即:
v3[i] = ( v2[i] + v2[i+m] + v3[i] ) & 0x0F;
9. 上面v3循环使用,第一次各位为0。
10.如果v3的前(试练码长度\2)位都等于试练码长度则成功;
Name文本框最多只接受11位,SN文本框只接受16位;
******************************************************************************/
【注册机】: 见附件2
【VC++6.0注册源码】:
这里只是自已添加上去的代码,不包括自动生成的,写得很烂,高手见笑了。
#include <math.h> int nName, nSN; DWORD add; DWORD get_add() // 取得lstrlen函数的地址 { HINSTANCE hLib = LoadLibrary ("kernel32.dll"); FARPROC lfnProc = 0; if (hLib) { lfnProc = (FARPROC) GetProcAddress (hLib, "lstrlenA"); FreeLibrary (hLib); } return (DWORD) lfnProc + 0x30; } bool check_sn(const CString &name, const CString &sn, CString &hash) //检验sn是否正确 { int i, j, m, v1[16], v2[16], v3[16]; j = nName > nSN ? nName : nSN; for (i=0; i<j; ++i) { v1[i] = i<nName ? name[i] : 0; //name各位入v1 v2[i] = i<nSN ? sn[i] : 0; //sn各位入v2 v1[i] = ( v1[i] - v2[i] ) & 0xFF; //name[i] - sn[i] v3[i] = 0; } m = nSN/2; for (i=nSN; i>0; --i) { DWORD val = add; for (j=nSN-1; j>=0; --j) val += ( ( v1[nSN-j-1] - 0x30 ) & 0xFF ) * (DWORD) pow(10, j); val *= i; char s[11]; sprintf(s, "%lu", val); for (j=0; j<m; ++j) v3[j] = ( ( s[j] & 0x0F ) + ( s[j+m] & 0x0F ) + v3[j] ) & 0x0F; } hash.Empty(); for (i=0; i<m; ++i) hash.Insert(i, v3[i] + 0x30); for (i=0; i<m; ++i) if (v3[i]!=nSN) return false; return true; } void CKeygenDlg::OnOK() //穷举及检测 { UpdateData(true); nName = m_szName.GetLength(); if (nName<5) return; add = get_add(); char szSet[128] = "0123456789"; //候选字符集 CString name; const int nChar = strlen(szSet); //候选字符集长度 long idx[16]; //注册码下标 long j, i = 0; bool bNext; for (i=0; i<nName; ++i) name.Insert(i, m_szName.GetAt(i) | 0x20); //name各位和0x20作or运算 for (nSN=5; nSN<17; ++nSN) // 循环#1 { for (i=0; i<nSN; ++i) idx[i] = 0; bNext = true; while (bNext) // 循环#2 { m_szSN.Empty(); for (i=0; i<nSN; ++i) m_szSN.Insert(i, szSet[idx[i]]); if (check_sn(name, m_szSN, m_szHash)) { UpdateData(false); AfxMessageBox("Found!"); return; } for (j=nSN-1; j>=0; --j) // 循环#3 下标进位 { idx[j]++; if (idx[j]!=nChar) break; else { idx[j] = 0; if (j==0) bNext = false; } } // 循环#3 end } // 循环#2 end ++nSN; } // 循环#1 end AfxMessageBox("Not found!"); }
一般在1、2分鉮内就能算出注册码,我算出来的注册码全部是7位长,hash值(v3)全部是:777
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年04月09日 8:47:06
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
他的文章
- [求助]去除不了的断点 3511
- [求助]去除Timer 5060
- MFC Library 5461
- [原创]czCrackme 09破解及注册源码 6459
- 如何修改VB P-code程序 7819
看原图
赞赏
雪币:
留言: