rayicy 发表于 2006-11-16 19:29:35

对C-Free 注册码算法分析与想法

前不久我和网友聊天的时候,得知他也特别喜欢编程和破解,于是大家常常将自己收藏的一些编程和破解工具拿出来一同分享,这不,前几天这位网友给我推荐了一款相当不错的编程辅助工具——C-Free。


软件功能:
它是一款基于Windows的C/C++集成化开发软件(IDE)。它的操作相当的简单,初学编程的朋友可以轻松地编辑、编译、连接、运行、调试C/C++程序。特别地是这款软件对于C/C++的学习者非常容易使用,是迅速提高C/C++水平的好帮手,但美中不足的是,这款软件是需要注册的,如果我们不进行注册的话,只可以用十次。最后想了想,这么出色的软件只用十次,那可是太可惜了,再加上自己也号称“Cracker”多时了,索性就当一次破解练习吧,于是决定破解此软件。

破解思路:
在破解前,还是应该先搞清楚软件注册的思路,这样才有助于我们后面对软件的顺利破解。首先,运行要破解的程序,找到注册窗口。
我们看的很清楚,如果软件不能正确地注册,就只可以使用10次,而且调试功能和智能输入功能被自动禁止使用。那就注册吧,选择“输入注册”,在打开的注册窗口中输入:用户名:nyyuan;注册码:654321,然后确定,我们发现并不是弹出了注册失败之类的错误提示,而是保存注册信息,重启检测注册码的对话框。
这也就是我们常说的重启检测注册码的加密方法。一般是先将我们输入的错误的注册信息保存在注册表或是其它的一些文件中,然后在下一次程序启动后,和程序计算出的正确注册码进行比较,如果一样,那么显示注册成果,解除所有的功能上的限制;相反,如果我们输入的注册码和正确注册码进行比较后不相同的话,那就是注册失败。那我们就先在注册表中找找,看有没有我们刚才输入的注册信息,经过查找,果然是将注册信息保存在了注册表的
\HKEY_LOCAL_MACHINE\SOFTWARE\C-Free\3.5下。
我们可以很清楚的看到我们输入的用户名和注册码。
破解过程:
通过上面的分析,我们就可以开始下面的破解了,在进行破解前,我们还是用PEID来看一下软件是否被加壳,经过检测,发现软件果然被加了aspack2.12壳。
还好这个壳不算难脱,而且也有现成的脱壳工具,经过脱壳,得知软件是用Borland c++1999编译的。
接下来我们就可以用TRW2000或是Ollydbg对软件进行反跟踪了。但我还是喜欢用TRW2000。
我们知道,跟踪这种重启检测注册码的程序,要下一个RegQueryValueExA的断点,此断点可以很快很准确的定位注册码在注册表的保存位置;而且也可以很容易的找到注册码的算法。那就在加载程序后下断点RegQueryValueExA do “db *(esp+8)”,(其实这个断点在Ollydbg中有不同之处)接下来就是漫长地F5,大概是按下94次 F5键,便会在TRW2000窗口的右上角发现RegistryCode字样,其实文章的前面就说到,注册表下的RegistryCode键值就是我们输入的注册码。接下来我们下BC *, pmodule,来到程序的领空,然后接着是漫长地 F10,不久我们就来到了计算注册码的地方:

* Possible Reference to String Resource ID=00002: "Can't find the file"
|
:00419624 BA02000000 mov edx, 00000002
:00419629 89810C0A0000 mov dword ptr , eax
:0041962F 8D85E0F9FFFF lea eax, dword ptr
:00419635 FF4B1C dec
:00419638 E8C3291700 call 0058C000
:0041963D 8B0F mov ecx, dword ptr
:0041963F C681F408000000 mov byte ptr , 00
:00419646 8B07 mov eax, dword ptr
:00419648 FF80F0080000 inc dword ptr
:0041964E E8CD930400 call 00462A20 取出机器码放入EAX中
:00419653 89859CF8FFFF mov dword ptr , eax
:00419659 66C743109800 mov , 0098
:0041965F 8B17 mov edx, dword ptr
:00419661 8B8AE4080000 mov ecx, dword ptr
:00419667 3B8D9CF8FFFF cmp ecx, dword ptr
:0041966D 0F85AB000000 jne 0041971E 这里跳走将永远不能注册成功
:00419673 8D857CF7FFFF lea eax, dword ptr
:00419679 50 push eax
:0041967A 8B959CF8FFFF mov edx, dword ptr edx = 机器码
:00419680 52 push edx
:00419681 E8F2930400 call 00462A78 计算注册码的关键 CALL
:00419686 66C74310C404 mov , 04C4
:0041968C 83C408 add esp, 00000008
:0041968F 8D957CF7FFFF lea edx, dword ptr
:00419695 8D85DCF9FFFF lea eax, dword ptr eax中为正确的注册码
:0041969B E848271700 call 0058BDE8
:004196A0 FF431C inc
:004196A3 8B10 mov edx, dword ptr
:004196A5 8B07 mov eax, dword ptr
:004196A7 8B80E8080000 mov eax, dword ptr 将我们输入的注册码放入eax中
:004196AD E8CA320D00 call 004EC97C
:004196B2 85C0 test eax, eax 注册码进行比较
:004196B4 8D85DCF9FFFF lea eax, dword ptr
:004196BA 0F94C2 sete dl
:004196BD 83E201 and edx, 00000001
:004196C0 52 push edx
通过上面的代码,我们找到了注册码算法的重要CALL,而且意外的发现了正确的注册码,但是为了了解软件的注册方法,还是决定进入那个重要CALL,看看它的注册算法。那就在:00419681 E8F2930400 call 00462A78处按下F8跟进:

* Referenced by a CALL at Address:
|:00419681
|
:00462A78 55 push ebp
:00462A79 8BEC mov ebp, esp
:00462A7B 83C4F4 add esp, FFFFFFF4
:00462A7E 33D2 xor edx, edx
:00462A80 53 push ebx
:00462A81 56 push esi
:00462A82 57 push edi

* Possible Reference to String Resource ID=00037: "圅"%s"蛳(C-Free-S"
|
:00462A83 BB25000000 mov ebx, 00000025 ebx = 00000025
:00462A88 8B4D08 mov ecx, dword ptr ecx = 机器码
:00462A8B 81F190909090 xor ecx, 90909090 拿机器码和90909090进行异或
:00462A91 8BC1 mov eax, ecx
:00462A93 F7F3 div ebx 将异或后的结果与00000025相除
:00462A95 8BC2 mov eax, edx 将的到的余数放入eax中
:00462A97 83F811 cmp eax, 00000011 将余数和00000011进行比较
:00462A9A 7D03 jge 00462A9F 如果大于等于跳走
:00462A9C 83C011 add eax, 00000011 如果小于,则余数加上00000011
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00462A9A(C)
|
:00462A9F 50 push eax
:00462AA0 8D55F4 lea edx, dword ptr
:00462AA3 52 push edx
:00462AA4 51 push ecx ecx 为上面异或的结果
:00462AA5 E826221200 call 00584CD0 关键CALL
:00462AAA 8B4D0C mov ecx, dword ptr
:00462AAD 83C40C add esp, 0000000C
:00462AB0 8BF1 mov esi, ecx
:00462AB2 33C0 xor eax, eax
:00462AB4 8D7DF4 lea edi, dword ptr
:00462AB7 83C9FF or ecx, FFFFFFFF
通过对上面的代码分析,我们可以发现注册码是根据机器码计算出来的。先用机器码和90909090进行异或运算,然后将得到的结果再和00000025相除,接着将得到的余数和00000011进行比较,如果大于或是等于00000011则跳走,如果小于00000011,则将余数加上00000011,不过这只是注册算法的一部分,接下来我们进入:00462AA5 E826221200 call 00584CD0,继续注册码算法的分析。

:00584CD0 55 push ebp
:00584CD1 8BEC mov ebp, esp
:00584CD3 8B4510 mov eax, dword ptr
:00584CD6 8B5508 mov edx, dword ptr
:00584CD9 83F80A cmp eax, 0000000A 将余数同0000000A比较
:00584CDC 6A61 push 00000061
:00584CDE 0F94C1 sete cl
:00584CE1 83E101 and ecx, 00000001
:00584CE4 83F80A cmp eax, 0000000A
:00584CE7 51 push ecx
:00584CE8 50 push eax
:00584CE9 8B4D0C mov ecx, dword ptr
:00584CEC 51 push ecx
:00584CED 7504 jne 00584CF3
:00584CEF 8BC2 mov eax, edx
:00584CF1 EB02 jmp 00584CF5

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00584CED(C)
|
:00584CF3 8BC2 mov eax, edx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00584CF1(U)
|
:00584CF5 50 push eax
:00584CF6 E845FFFFFF call 00584C40 又一个关键CALL
:00584CFB 83C414 add esp, 00000014
:00584CFE 5D pop ebp
:00584CFF C3 ret
这段代码其实还是进行余数的比较,但是发现另外一个关键CALL,那继续跟进。

* Referenced by a CALL at Addresses:
|:00584CC5 , :00584CF6 , :00584D13 , :00584D3B
|
:00584C40 55 push ebp
:00584C41 8BEC mov ebp, esp
:00584C43 83C4DC add esp, FFFFFFDC
:00584C46 53 push ebx
:00584C47 56 push esi
:00584C48 57 push edi
:00584C49 8B7D10 mov edi, dword ptr 这里的值为上面得到的余数
:00584C4C 8B7508 mov esi, dword ptr 这里的值为异或后的结果
:00584C4F 8B5D0C mov ebx, dword ptr
:00584C52 83FF02 cmp edi, 00000002 将余数同00000002进行比较
:00584C55 7C4D jl 00584CA4 如果小于00000002则跳
:00584C57 83FF24 cmp edi, 00000024 将余数同00000024进行比较
:00584C5A 7F48 jg 00584CA4 如果大于00000024则跳
:00584C5C 85F6 test esi, esi
:00584C5E 7D0C jge 00584C6C
:00584C60 807D1400 cmp byte ptr , 00
:00584C64 7406 je 00584C6C
:00584C66 C6032D mov byte ptr , 2D
:00584C69 43 inc ebx
:00584C6A F7DE neg esi
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00584C5E(C), :00584C64(C)
|
:00584C6C 8D4DDC lea ecx, dword ptr

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00584C82(C)
|
:00584C6F 8BC6 mov eax, esi 此为异或的结果
:00584C71 33D2 xor edx, edx
:00584C73 F7F7 div edi 将上面异或结果除以余数
:00584C75 8811 mov byte ptr , dl 将前面算出的余数的一个字节存入内存
:00584C77 41 inc ecx
:00584C78 8BC6 mov eax, esi
:00584C7A 33D2 xor edx, edx
:00584C7C F7F7 div edi
:00584C7E 8BF0 mov esi, eax
:00584C80 85C0 test eax, eax 比较eax,直到为0
:00584C82 75EB jne 00584C6F 如果不为0则继续循环
:00584C84 EB17 jmp 00584C9D

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00584CA2(C)
|
:00584C86 49 dec ecx
:00584C87 8A01 mov al, byte ptr 将内存中的值放入al中
:00584C89 3C0A cmp al, 0A al和0A进行比较
:00584C8B 7D08 jge 00584C95 如果大于等于0A则跳
:00584C8D 83C030 add eax, 00000030 将eax +00000030
:00584C90 8803 mov byte ptr , al 算出注册码的第X位上的值,然后存入内存
:00584C92 43 inc ebx
:00584C93 EB08 jmp 00584C9D
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00584C8B(C)
|
:00584C95 024518 add al, byte ptr 如果大于0A,则加61
:00584C98 04F6 add al, F6 加F6
:00584C9A 8803 mov byte ptr , al 将上面的值作为注册码的第X位存入内存
:00584C9C 43 inc ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00584C84(U), :00584C93(U)
|
:00584C9D 8D55DC lea edx, dword ptr
:00584CA0 3BCA cmp ecx, edx
:00584CA2 75E2 jne 00584C86
跳回去继续计算,直到循环结束。经过以上的分析,我们发现软件正确的注册码是通过机器码生成的,它和我们输入的用名无关,根据上面的分析,我们已了解注册码的算法,就算你还不太了解的话也不必着急,因为我们通过上面的分析,可以直接从代码中找到正确的注册码。现在用得到的注册码再次注册,我们发现已经注册成功了。

通过这款软件的破解,我们发现软件在注册算法上有一定的漏洞,虽然在注册算法上杜绝了当下对注册码的比较,但是注册码还是明文存放的,这样我们就可以在不经过算法分析的情况下直接得到正确的注册码,所以,希望每位软件作者注意一下,使自己的软件更加的安全。C-Free 下载地址: http://www.997.cn/SoftView/SoftView_3011.html
页: [1]
查看完整版本: 对C-Free 注册码算法分析与想法