发新话题
打印

[转载]C-Free V3.5.2 注册算法分析

[转载]C-Free V3.5.2 注册算法分析

  【Cracker】: prince
【E-mail】 : Cracker_prince@163.com
【来源】:tx7do.blogchina.com
引用:
C-Free是一款基于Windows的C/C++集成化开发软件(IDE)。利用本软件,使用者可以轻松地编辑、编译、连接、运行、调试C/C++程序。特别地,这款软件对于C/C++的学习者非常容易使用,是迅速提高C/C++水平的好帮手。当然,C/C++高手也会在其中找到许多惊喜的功能。
C-Free包含下列主要特征:

  支持MinGW编译器和C/C++解释器Ch
  集成化的调试环境
  工程管理
  可定制的语法加亮编辑器
  智能输入(大大地提高代码输入效率)
  函数列表
  集成化的C/C++库函数帮助
  快速创建控制台、窗口和DLL应用
  借助工程模板创建自己想要的工程类型
  完善的查找替换功能
  可定制的代码模板
  支持Window图形界面应用的开发
  对话框资源编辑器

以上是软件的应用信息,下面是破解所获取软件内部的信息:
[保护方式]  : 机器码 + 序列号

[限制方式]  : 次数限制 (10 次试用 )

[外壳保护]  : ASPack 2.12

[编译器/语言]: Borland C++ 1999 / C++

ASPack 2.12 脱壳很简单,ASPackDie也可以轻松对付。无自校验,脱壳后可直接运行。注册情况:机器码给出,输入用户名prince和序列号8764321,确定,提示重启验证。

说到重启验证,最简单最直接的就想到注册表,确认一下,打开注册表搜索用户名prince,果然找到在HKEY_LOCAL_MACHINESOFTWAREC-Free3.5下,同样列在其中的还有我们输入的假码87654321和我机器上的机器码(MachineCode)2781318776。这下我们就可以确定了软件确实是通过注册表来进行重启验证的。

目标如此明确,载入脱壳后的程序,下断点RegQueryValueA,恩?没有,再下RegQueryValueExA,呵呵,可以了。F9运行,马上被断下,看堆栈,ValueName = "layout text",不是我们想要的,继续F9,注意断点不能取消,因为后面的对注册表的读取还是要靠这个函数,再次断下,还不是,再运行...,大约81次,堆栈中显示ValueName = "MachineCode",这就是要读取机器码了,注意。再次F9,断在读取RegistryCode也就是假码的地方,呵呵,敏感。

再接下来是读取UserName,即用户名。到这里,计算注册码的准备工作就做完了,可是在那里计算的呢?作者在软件启动的时候将所有的配置信息连同机器码,用户名和注册码一起读出,而且也没有读出后立即计算注册码继续比较,这就给我们定位注册码计算造成了困难。

这个时候我们该怎么办?
两个办法,
一个就是下面都进行单步跟踪,直到找到关键函数为止,毕竟软件在启动前肯定会计算注册码的;
另外一个办法就是在内存中搜索假码然后下内存断点。
这个方法倒是即快又方便,但是要掌握时机,具体什么时候搜内存要看代码的动作。我通常都是先搜内存,不行的话只好一步一步的单跟了,做Cracker要有耐心。当你在堆栈中看到ValueName = "EditorTabWidth"的时候。
呵呵,我们到了藏有宝藏的秘密入口了。

----------------------------------------------------------------------------------------
复制内容到剪贴板
代码:
00419654  |.>MOV WORD PTR DS:[EBX+10],4B8
0041965A  |.>MOV EDX,unpacked.005DAA4C      ;  ASCII "EditorTabWidth"
0041965F  |.>LEA EAX,DWORD PTR SS:[EBP-620]
00419665  |.>CALL unpacked.0058D308
0041966A  |.>INC DWORD PTR DS:[EBX+1C]
0041966D  |.>MOV EDX,DWORD PTR DS:[EAX]
0041966F  |.>MOV EAX,ESI
00419671  |.>CALL unpacked.004E936C
00419676  |.>MOV ECX,DWORD PTR DS:[EDI]
00419678  |.>MOV EDX,2
0041967D  |.>MOV DWORD PTR DS:[ECX+A0C],EAX
00419683  |.>LEA EAX,DWORD PTR SS:[EBP-620]
00419689  |.>DEC DWORD PTR DS:[EBX+1C]
0041968C  |.>CALL unpacked.0058D520
00419691  |.>MOV ECX,DWORD PTR DS:[EDI]
00419693  |.>MOV BYTE PTR DS:[ECX+8F4],0
0041969A  |.>MOV EAX,DWORD PTR DS:[EDI]
0041969C  |.>INC DWORD PTR DS:[EAX+8F0]
004196A2  |.>CALL unpacked.00462F18        ;  取机器码送EAX
004196A7  |.>MOV DWORD PTR SS:[EBP-764],EAX
004196AD  |.>MOV WORD PTR DS:[EBX+10],98
004196B3  |.>MOV EDX,DWORD PTR DS:[EDI]
004196B5  |.>MOV ECX,DWORD PTR DS:[EDX+8E4]
004196BB  |.>CMP ECX,DWORD PTR SS:[EBP-764]
004196C1  |.>JNZ unpacked.00419772
004196C7  |.>LEA EAX,DWORD PTR SS:[EBP-884]
004196CD  |.>PUSH EAX                 ; /Arg2
004196CE  |.>MOV EDX,DWORD PTR SS:[EBP-764]  ; |[EBP-764]==机器码
004196D4  |.>PUSH EDX                 ; |Arg1
004196D5  |.>CALL unpacked.00462F70        ; 关键CALL,跟进
004196DA  |.>MOV WORD PTR DS:[EBX+10],4C4    ;  上面的这个CALL计算真码,存放在EAX中(哎!又是明文)
004196E0  |.>ADD ESP,8
004196E3  |.>LEA EDX,DWORD PTR SS:[EBP-884]  ;  真码地址送入EDX
004196E9  |.>LEA EAX,DWORD PTR SS:[EBP-624]
004196EF  |.>CALL unpacked.0058D308
004196F4  |.>INC DWORD PTR DS:[EBX+1C]
004196F7  |.>MOV EDX,DWORD PTR DS:[EAX]
004196F9  |.>MOV EAX,DWORD PTR DS:[EDI]
004196FB  |.>MOV EAX,DWORD PTR DS:[EAX+8E8]  ;  假码送入EAX,呵呵,准备比较了哦
00419701  |.>CALL unpacked.004ECED4        ;  比较函数,嘿嘿。
00419706  |.>TEST EAX,EAX
00419708  |.>LEA EAX,DWORD PTR SS:[EBP-624]
----------------------------------------------------------------------------------------

我们要找算法的计算过程,所以004196D5 处跟进:

----------------------------------------------------------------------------------------
复制内容到剪贴板
代码:
00462F70  /$>PUSH EBP
00462F71  |.>MOV EBP,ESP
00462F73  |.>ADD ESP,-0C
00462F76  |.>XOR EDX,EDX
00462F78  |.>PUSH EBX
00462F79  |.>PUSH ESI
00462F7A  |.>PUSH EDI
00462F7B  |.>MOV EBX,25                ;  EBX=0x25
00462F80  |.>MOV ECX,DWORD PTR SS:[EBP+8]    ;  [EBP+8]==机器码
00462F83  |.>XOR ECX,90909090            ;  机器码异或90909090,ECX==35571EE8
00462F89  |.>MOV EAX,ECX
00462F8B  |.>DIV EBX                  ;  上面异或的结果除以25
00462F8D  |.>MOV EAX,EDX               ;  余数送EAX
00462F8F  |.>CMP EAX,11                ;  余数同0x11比较
00462F92  |.>JGE SHORT unpacked.00462F97    ;  大于等于就直接压栈准备函数调用
00462F94  |.>ADD EAX,11                ;  否则余数+0x11,然后再入栈
00462F97  |>>PUSH EAX                 ; /Arg3 余数入栈
00462F98  |.>LEA EDX,DWORD PTR SS:[EBP-C]    ; |
00462F9B  |.>PUSH EDX                 ; |Arg2
00462F9C  |.>PUSH ECX                 ; |Arg1 上面异或结果入栈
00462F9D  |.>CALL unpacked.005861F0        ; 跟进
00462FA2  |.>MOV ECX,DWORD PTR SS:[EBP+C]
00462FA5  |.>ADD ESP,0C
00462FA8  |.>MOV ESI,ECX
00462FAA  |.>XOR EAX,EAX
00462FAC  |.>LEA EDI,DWORD PTR SS:[EBP-C]
----------------------------------------------------------------------------------------


00462F9D 处继续跟进:

----------------------------------------------------------------------------------------
复制内容到剪贴板
代码:
005861F0  /$>PUSH EBP
005861F1  |.>MOV EBP,ESP
005861F3  |.>MOV EAX,DWORD PTR SS:[EBP+10]
005861F6  |.>MOV EDX,DWORD PTR SS:[EBP+8]
005861F9  |.>CMP EAX,0A                ;  余数同0A比较
005861FC  |.>PUSH 61
005861FE  |.>SETE CL                  ;  条件为假,所以CL清零
00586201  |.>AND ECX,1
00586204  |.>CMP EAX,0A                ;  仍然同0A比较
00586207  |.>PUSH ECX
00586208  |.>PUSH EAX
00586209  |.>MOV ECX,DWORD PTR SS:[EBP+C]
0058620C  |.>PUSH ECX
0058620D  |.>JNZ SHORT unpacked.00586213
0058620F  |.>MOV EAX,EDX
00586211  |.>JMP SHORT unpacked.00586215
00586213  |>>MOV EAX,EDX
00586215  |>>PUSH EAX                 ; |Arg1
00586216  |.>CALL unpacked.00586160        ; 跟进
0058621B  |.>ADD ESP,14
0058621E  |.>POP EBP
0058621F  .>RETN
----------------------------------------------------------------------------------------



没有结果,00586216处继续跟进:

----------------------------------------------------------------------------------------
复制内容到剪贴板
代码:
00586160  /$>PUSH EBP
00586161  |.>MOV EBP,ESP
00586163  |.>ADD ESP,-24
00586166  |.>PUSH EBX
00586167  |.>PUSH ESI
00586168  |.>PUSH EDI
00586169  |.>MOV EDI,DWORD PTR SS:[EBP+10]   ;  [EBP+10]为前面压栈的余数
0058616C  |.>MOV ESI,DWORD PTR SS:[EBP+8]    ;  [EBP+8]为机器码异或90909090的结果
0058616F  |.>MOV EBX,DWORD PTR SS:[EBP+C]
00586172  |.>CMP EDI,2                ;  余数同0x2比较
00586175  |.>JL SHORT unpacked.005861C4     ;  小于跳
00586177  |.>CMP EDI,24                ;  同0x24比较
0058617A  |.>JG SHORT unpacked.005861C4     ;  大于则跳
0058617C  |.>TEST ESI,ESI
0058617E  |.>JGE SHORT unpacked.0058618C
00586180  |.>CMP BYTE PTR SS:[EBP+14],0
00586184  |.>JE SHORT unpacked.0058618C
00586186  |.>MOV BYTE PTR DS:[EBX],2D
00586189  |.>INC EBX
0058618A  |.>NEG ESI
0058618C  |>>LEA ECX,DWORD PTR SS:[EBP-24]   ;  下面为关键循环
0058618F  |>>/MOV EAX,ESI              ;  ESI==机器码异或结果
00586191  |.>|XOR EDX,EDX              ;  EDX清零
00586193  |.>|DIV EDI                 ;  将上面异或结果除以压栈的余数
00586195  |.>|MOV BYTE PTR DS:[ECX],DL      ;  上面计算的余数的一个字节写入内存
00586197  |.>|INC ECX
00586198  |.>|MOV EAX,ESI
0058619A  |.>|XOR EDX,EDX
0058619C  |.>|DIV EDI
0058619E  |.>|MOV ESI,EAX              ;  又做了一次相同的计算,商送入ESI
005861A0  |.>|TEST EAX,EAX              ;  直到EAX==0为止
005861A2  |.>JNZ SHORT unpacked.0058618F    ;  不为0则继续循环
005861A4  |.>JMP SHORT unpacked.005861BD
005861A6  |>>/DEC ECX
005861A7  |.>|MOV AL,BYTE PTR DS:[ECX]      ;  内存[ECX]的值送入AL
005861A9  |.>|CMP AL,0A                ;  同0A比较
005861AB  |.>|JGE SHORT unpacked.005861B5    ;  大于等于跳到下面进行另外的计算
005861AD  |.>|ADD EAX,30               ;  该值加上0x30
005861B0  |.>|MOV BYTE PTR DS:[EBX],AL      ;  这个值就是注册码的第i个值,写入内存保存起来
005861B2  |.>|INC EBX                 ;  继续下一步
005861B3  |.>|JMP SHORT unpacked.005861BD
005861B5  |>>|ADD AL,BYTE PTR SS:[EBP+18]    ;  上面如果大于0A,则加上[EBP+18]==61,
005861B8  |.>|ADD AL,0F6               ;  再加上0F6
005861BA  |.>|MOV BYTE PTR DS:[EBX],AL      ;  作为注册码的第i个值写入内存
005861BC  |.>|INC EBX
005861BD  |>> LEA EDX,DWORD PTR SS:[EBP-24]  ;  取地址[EBP-24]
005861C0  |.>|CMP ECX,EDX              ;  比较是否结束循环
005861C2  |.>JNZ SHORT unpacked.005861A6    ;  没有结束则继续
005861C4  |>>MOV BYTE PTR DS:[EBX],0
005861C7  |.>MOV EAX,DWORD PTR SS:[EBP+C]
005861CA  |.>POP EDI
005861CB  |.>POP ESI
005861CC  |.>POP EBX
005861CD  |.>MOV ESP,EBP
005861CF  |.>POP EBP
005861D0  .>RETN
----------------------------------------------------------------------------------------


呵呵,过程清晰明了吧?
第一次循环:机器码异或0x90909090的结果除以前面求得的压栈的余数,然后这个过程的余数写入内存保留,商作为下一次循环的变量继续循环。

第二次循环:将第一次循环中写入内存的值逆序读取出来,同0xA比较,小于就直接加上0x30,作为注册码的第i个字符写入内存;大于等于则加上61,再加0xF6,取低字节作为注册码的第i个字符写入内存。用户名没有参与计算。也不知道我说明白了没有,还是看程序来得直接——

C源码的注册机:

-----------------------------------------------------------------------------------------
复制内容到剪贴板
代码:
#include "stdafx.h"
#include "stdlib.h"
#include "stdio.h"


int main(int argc, char* argv[])
{
char chKey[128] = {0};
unsigned int unXORCode, unRemainder, unQuotient, unTmp, unMachineCode;
printf("Please Key in the Machine Code: ");
scanf("%d", &unMachineCode);

unXORCode  = unMachineCode ^ 0x90909090;
unRemainder = unXORCode % 0x25;
unQuotient  = unXORCode;
if (unRemainder < 0x11)
{
  unRemainder += 0x11;
}

int i;
i = 0;
while (unQuotient != 0)
{
  unTmp  = unQuotient % unRemainder;
  unQuotient /= unRemainder;
  if (unTmp >= 0xa)
  {
  unTmp = unTmp + 0x61 + 0xf6;
  unTmp &= 0x0ff;
  chKey[i] = unTmp;
  }
  else
  {
  chKey[i] = unTmp + 0x30;
  }
  i++;
}
printf("Key is: ");
while (i >= 0)
{
  printf("%c", chKey[i]);
  i--;
}
printf(" ");

return 0;
}/
-----------------------------------------------------------------------------------------
文章赶的比较紧,有失误的地方请来信告知。

菜鸟写菜文,请高手指教。

     prince 2005.01.28

VC写的WIN32算法注册机,请大家测试,有问题请告之。

TOP

编译器 C-Free V3.5.2 注册算法分析(重启验证)

今天在DFCG论坛上闲逛时无意中看到一个国产C/C++编译器,C-Free V3.5.2,随手下载只是想看看注

册算法,没有使用,不知道功能如何。

[Cracker]   : prince

[时间]    : 2005.01.28

[声明]    : 只做技术交流,不做商业用途,如果你手头宽裕并喜欢这个软件的话请支持正版软件。

[E-mail]    : Cracker_prince@163.com

附件[C-FreeKeyGen.rar]:
http://blog.blogchina.com/upload ... 331193810758358.rar

TOP

曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

注册机

附件

cfree.rar (18 KB)

2005-12-27 15:29, 下载次数: 184

我没头像了。。。

TOP

发新话题