共享软件是现在世界上软件业比较热门的话题,国内更是如此。成千上万的中国程式员以极大的热情投入到这个领域来,都憧憬着用辛勤的劳动获得丰厚的回报;但,实际并非如此,绝大多数的人都铩羽而归。值得注意的是:除了软件设计和技术上的原因外,最大的原因就是共享软件被破解(Crack)了……

面对破解

一个做共享软件的作者,面对的是已形成团伙的众多破解高手,国内的什么CCG、BCG,外国的eGis、King、Core、TNT、DAMN和TMG,皆为水平一流的破解组织。全球盗版软件不少于80%都是由他们的破解的,技术实力连大软件公司都不可小视。

看到这里,您是否已灰心了?别怕,虽然现在我们理论上无法完全避免被破解,但假如能够有效地拖延被破解的时间,并充分打击破解者的自信心,是能够让破解者无法忍受这种折磨从而最终放弃的。

破解,通常的做法有两种——暴力破解(爆破)和写注册机。笔者就自己积累的经验来依次讲解每种破解方法的原理和应对方法,某些关键的例程讲解(Delphi代码),使用C 和VB的朋友能够自己稍微修改一下。希望这能对一些新手有些帮助,能够更有效地保护自己的劳动成果。

认识暴力破解

暴力破解简称“爆破”,这是破解手段中最常见的,也是最简单的破解方法。该法最适合于对付没有CRC校验的软件,破解新手乐于采用。

大凡共享软件,验证是否注册大多采用if条件语句来进行判断,即使您采用了什么RSA或ECC等强力加密算法,也免不了使用if条件语句。这里就是共享软件最为危险的地方,也是爆破手孜孜不倦所寻求的目标。

例如,您的注册函数类似如下:

{利用RSA进行注册码的数字签名验证}
if RSAVerify(MD5(Key),MD5(Code),e,n)then
ShowMessage('注册成功!')
else
ShowMessage('注册失败!');

{这里Key是用户输入的注册码,是由您发送给注册用户的,Code是根据用户输入的用户名自动计算出来的注册码,e是RSA算法的公匙,而n是RSA算法的模数。}

第一次过招

上例注册函数即使使用了强劲的RSA算法进行注册码验证,但依然很容易被破解,我们只要把这里修改为:

将逻辑判断改为否 
if not RSAVerify(MD5)Key),MD5(Code),e,n)then
ShowMessage('注册成功!')
else
ShowMessage('注册失败!');

这时戏剧性的结果会产生:随便输入任何注册码都能够注册通过,相反输入正确的注册码却无法通过注册。

要破解这样的软件就必须先反汇编或跟踪您的程式,找到判断注册码的cmp、test等汇编指令后的关键跳转指令处,通常是je、jz之类的汇编指令,把他们修改为jne或jnz即可,这样常常只需要修改一个字节就能够完美破解了。

现在大部分共享软件都是用以上方法进行判断,这也是为什么网上被破解的软件铺天盖地的主要原因。因为这样破解实在是太简单了……

第二次过招

其实只要把软件的关键代码嵌入到注册码或注册文档中就能够充分防止破解。

最简单的方法就是把关键代码(您的软件功能限制部分最关键而且最简单的一个函数)做成一个小DLL(动态链接库),用强力对称算法加密(密匙能够是主程式某一固定不变的部分或壳的特征Hash值)后生成一个注册文档(License文档,这格式只有您知道),或Base64编码后生成一个注册表文档,用户能够双击导入注册表内。

校验流程如下:已注册用户验证注册码时,先验证有没有文档,没有文档则自然受限制的功能无法使用。假如有注册文档,解密后即生成一个小临时文档。假如主程式被脱壳或被修改(爆破),自然Hash值密码不符,解密出来的肯定都是垃圾码,没有一点用处。只有没有被修改的主程式才能正确地解码,而且当然只有解密正确的文档才是个真正的DLL文档,才能被GetProcAddress函数找到欲调用的关键函数地址。这样只有已注册用户才能够享受到您的软件的全部功能了。如此一来,Cracker破解您的软件就变得很困难了。

首先,他假如没有注册文档,即使他把主程式脱壳了,由于受限制的部分和注册文档是关联的,他也根本无法修补完整。

第二,即使他得到了您的注册文档,由于是加密文档,他也无法直接利用,这样就逼迫他去拆解您的算法,这可是他们最不愿意碰到的事情啊!假如到了这一步,只有真正对加密算法有研究的Cracker高手才会继续破解下去。

第三,您是能够用些小技巧来使他的破解工作更加繁锁。这里我推荐大家使用DSA公开密匙加密算法,他和RSA相同,能够进行数字签名(RSA还能够加密,DSA则只能进行数字签名)。笔者这里选用他的原因就是他有一项很实用的特性:随机数填充机制。即DSA每次签名都要使用一个随机数K,正因为有这个K的存在,即使是相同的用户名和机器识别码,由DSA加密过的每份注册文档都不会相同。这对Cracker拆解您的注册文档来说是个极大的障碍。

第四,即使他得到了解密后的DLL文档,他也需要大幅度地修改主程式或把您的DLL部分的关键代码拆出来添到主可执行文档中。这就看他对PE文档格式理解得如何了。即使这样,假如您的程式中有大量的Hash校验和死机代码,您就耐心等着我们可爱的Cracker同志吐血吧……:)

最后还要记住:用完这个DLL临时文档后立即从内存中卸载此DLL并删掉,而且注意在解密之前探测一下,系统中有没有FileMon这个威胁极大的探测器:

{探测FileMon}
function DetectFileMon:Boolean;
begin
if CreateFile(PChar('//./FILEVXD'),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE
nil,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0<> INVALID_HANDLE_VALUE then
Result:= True //假如有,就Down机!
else
Result:= False;
end;

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!