防破解
易语言软件加密技术
“本文有点长,但全是干货,没耐心没毅力的小伙伴谨慎阅读”
《易语言软件加密技术》
易语言源码大全
雷锋的四句名言是:对待同志要象春天般的温暖(我在帮助易友们提高易语言水平);对待工作要象夏天般的火热(我是工作狂看我写这么多就知道了);对待个人主义要象秋风扫落叶一样(对支持破解的人要坚决反对);对待敌人要象严冬一样残酷无情(打击盗版是大家共同的责任)。
本文为全中文编写,不需要有PE文件格式知识,不需要掌握汇编或C语言的编程技巧,一些加密算法直接由易语言提供,特殊的加密算法大家可以翻译C语言代码、汇编代码或VB代码。
本文中将“Cracker”一词翻译为“奸人”,意为“奸邪小人”之义。本人对破解者一向深恶痛绝,有人说中国的软件发展中破解者有一份功劳,可我说这话不对,看看因盗版而产生的微软对操作系统及软件业的垄断,国内软件业在盗版的夹缝中生存……,如此下去,软件作者没有收益,将不再会有优秀的软件推出。防止盗版,匹夫有责,我想通过本书的推出可以加强易语言用户的加密能力,将盗版杀死在大家共同的手中。
随着采用易语言编制程序的人们越来越多,写一个软件易被奸人破解的情况也越来越多了,有个别用户甚至于怀疑易语言是否有安全性。从技术性上来说,我只能说加密技术与编程语言无关,一个编程语言的安全性一般指所生成的机器码是否稳定、可靠,而不是防破解方面,如果想要很好地防止破解,那么掌握一门加密技术是非常必要的。
本书考虑到使用易语言的用户大部分对PE文件结构不太熟悉,因此没有采用很底层的方法去教学,而是采用与易语言直接表达的方式试图说明如何加密。
本文基本上是按以下的顺序进行讲解的:
破解技术 | 反破解技术1 | 反破解技术2 | 反破解技术3 |
防改文件 | 文件名验证 | LOGO图片验证 | 窗口标题验证 |
防改文件大小暴破 | 加壳后数据签名验证 | 加壳后CRC验证 | 文件大小验证 |
防调试 | 花指令 | 反调试模块 | 反调试支持库 |
内存注册机 | 不进行判断,用循环代替 | 字符串打乱器 | 及时清内存 |
算法注册机 | RSA算法 | 数值计算支持库 | |
其他 | 多处验证点 | 随机验证 | 命名刻意隐蔽 |
一.易语言程序加密的目的
在此有必要说明一下为何要为自己的程序进行加密,初步认为有以下两点:
1.保持软件的完整性
这里包括了文件名不被更改,文件版权信息不被更改,文件尺寸不被更改。
很多时候有的奸人拿到您的软件,他可以将文件名更改,将文件版权信息的字符串或图片更改,然后放上自己的东西,如放上病毒可以对其他电脑造成破坏,如果放奸人的弹出广告收益的是奸人,而不是作者。相反,使用这些软件的用户反而将作者痛骂一通,造成声誉上的损失。因此处于保护自己的完整权益来说,也是有必要保护软件的完整性。
例如QQ软件,曾出现过多款个人行为的补丁版,更改了QQ的一些信息与界面,为此QQ公司十分头痛,以后的一些事大家也知道,现在看是破解QQ的很少了,而且在安装QQ新版本时,它会检查是否有破解补丁存在,如果存在就不运行。
2、保护软件开发者的权益
也许你会说,一个不被破解的软件一定是一个没有加密的软件,那么看看下文您就会知道,那只是一个理想中的事情,除非您是有钱了没有事干的人,否则您开发软件的目的是什么我是很难知道的。
无论是个人还是公司,如果生产一个软件得不到收益,以及后继开发资金的鼓励,那么无疑这个软件是很难再开发下去的。这样的例子很多很多,我不想举例,国内已出现了很多软件的破解版,而一旦出现了破解,那么所造成的损失是非常大的。
二.易语言程序加密的原则
早先人们的加密方法是通过在软盘上格式化一些非标准磁道,在这些磁道上写入一些数据,如软件的解密密钥等等。这种软盘成为“钥匙盘”。软件运行时用户将软盘插入,软件读取这些磁道中的数据,判断是否合法的“钥匙盘”。
软盘加密还有其它一些技术,如弱位加密等等。
随着近年来软盘的没落,这种方法基本上退出了历史舞台。新的软件加密技术也越来越多了。
1.加密前要考虑周到且严密
说实话,有很多人在易语言论坛上发贴,说自己用易语言编写的软件有了破解,还非常高兴,有人用才会被破解,但我想,如果是很高兴的这样子,除非你的软件技术含量很低,或你是微软,想被别人破解,您不应该高兴,这有点象别人打了你一耳光,你还很高兴,你的知识产权或著作权已被奸人侵犯了,性质很恶劣,后果很严重。除了拿起法律武器,劳命伤财,还有就是加强加密方式。
如果被制作出注册机,情况是最糟糕的,作者需要全部更换全部用户的注册KEY文件,工作量相当地相当地大。因此一个好的软件保护发布前必须考虑周到,而且是面面俱到,否则出一个新版,发现一个破解,再出一个新版去修正,那样的事情是极其弱智的。
2.需要加密的内容要制定一个计划
一开始不明白如何加密的易语言用户,一般就找一下论坛上关于注册的例程套用到自己的程序中,认为这样就是加密了,实际上本节所要讲的是制作一个学习计划,将所有需要用到的知识与软件都收集到,这个计划就是一个加密计划,也是本书所要讲述的。
3.加密时制作好文档,以备以后的修改
在加密中有可能使用了多处加密,因此需要将文档写好,以防止以后忘记,实际上您可以在易语言中使用备注的方式作以说明,这些备注在编译时是不会被编译进目标EXE文件中的,大家可以放心写,同时也节省了写外部文档的时间。以后如果找时,可以直接搜索找到加密的地方。
4.发布前问一下是否可以正式发布软件了
制定一个风险评估标准,以考验一下程序的风险性,被破解的可能性,如果你是破解者,在不知道如何加密的情况下会如何去破解这个软件。
有一个参考的评估标准在下面。
是否将注册码、安装时间记录在多个不同的地方?
是否在校验时故意加入冗余干扰代码来误导解密者?
是否有自己独特的防破解措施?
建议:得分在6分以上才可以正式发布软件!
三.防止程序内容被更改
现在开始,已进入讲解加密的正题,但可能章节不必这样划分,即按加密/破解的方法来划分,如防反调试,反跟踪,反……。但笔者觉得,从一个一个小的知识点的进入是非常重要的。
1.防止软件名称被更改
这里是极为简单的方法:
判断(到大写(取执行文件名() = “我的程序.EXE”)
在上述中,为何使用到“判断”命令,而不是“如果”命令呢,大家可以想一下,“判断”命令的代码安全性要比“如果”命令高,这里不会举出一个汇编的例子,只要说明一下即可。即“判断”命令是多重分支结构,这样就增加了被破解的难度,因此,大家一定要注意这样一件事情,就是在进行加密比较时一定不要使用比较的语句,那样很容易被奸人使用破解工具下断点,那么正确的做法应该是如何的呢,请看下面代码:
计次循环首(到数值(是否注册成功()),)
全局_注册成功 = 1
计次循环尾()
通过上面的代码可以看出,这里没有使用判断语句,而采用了一个循环命令去参与。其中“是否注册成功()”确实是返回了一个逻辑值,但通过“到数值()”命令后就会被为0或1之间的一个数字,会用易语言的人都知道,一个循环命令中,如果循环数为1,会执行循环中的命令,否则为0不进入循环。生成机器码后,奸人会很难找到判断的汇编码,大大加强了保护性。
上述的基本方法是有了,但请您将这个方法隐藏于您的程序代码行的某一深处,实际上加密是各种方法的综合,现在所教的只是其中的一种,大家要将多种加密方式用于一个软件之中。这需要大量的时间学习与体会。
加密第1定理:“如果()”语句一定不要出现在加密算法中。
加密第2定理:用“循环”类命令代替判断语句。
2.防止窗口标题被更改
窗口标题是否被别人更改这个也可以通过与上述同样的方法实现验证。
判断(_启动窗口.标题 = “我的程序.EXE”)
大家也许会说,这些好象没有必要吧,谁会这么无聊,将软件的名称与窗口标题更改呢,大家看这样一个例子吧:有一个电脑培训班,采用了明伦五笔练习打字软件进行电脑培训班,他们破解了,且修改了明伦打字软件的版权信息,改为自己电脑培训班的标志,产生的教学效果即:学生认为这家培训班的技术实力很强,自己可以开发打字软件,而且经常弹出电脑培训班的标志与广告,产生了很好的广告效果,学生介绍学生,更多的学生参与进来了。
从上述事件看,很显然明伦打字软件的作者一点好处也没有,全部被破解者侵占了。因此一个好的软件保护必须是全面而且周到的。
另外,我要提醒大家的是,这样的语句也是非常不保险的,这样的话很容易被奸人改了字符串,以致于字符串也被更改了,或很快能找到比较的地方,从而轻松跳过去。较为理想的是将字符串打乱,即将“我的程序.EXE”以“字符()”、“取代码()”、“取反()”、“异或()”等命令用字符串相加的方法加在一起成为一个字串后再比较。
判断(取数据签名(_启动窗口.标题) = 取数据签名(“我的程序.EXE”))
3.防止LOGO图片被更改
有的人怕程序信息被更改,采用了图片显示程序标题的方式,这样这种图片较不易被奸人修改,但可能也有个别高手进行修改,因此图片的大小是知道的,这样可以用以下语句进行判断:
计次循环首(到数值(取字节集长度(_启动窗口。底图)=342488)),)
其中上述的数字是您已知的图片大小尺寸字节数,而不是乱写得来的。
也可以将图片放在易语言的资源中,直接进行比较。
计次循环首(到数值(_启动窗口。底图)=#图片1),)
以上方法虽然软件的体积大了一些,但带来的直接好处是,程序量一大,为破解带来了更大的困难,虽然损失了体积,但保证了安全。
你的关于窗口也要这样保护起来哦。
使用数据操作支持库中的“加密数据()”、“解密数据()”命令加密图片后存放在图片资源中,用时再解密显示出来。例如您的一些口令就直接用这个加密就可以了。解密时注意直接放在一行代码中比较,不要存到一个变量中,这样在内存中是找不到明文的。
四.防止内存注册机
“内存注册机”的原理就是在不用分析原程序的加密算法,实现直接读取原程序在加密计算过程中内存里显示出的明文注册码。
很多易语言软件加密时,算法是足够复杂了,但是就是KEY文是存在内存中的,这样就极易为破解。破解者只要写一个小程序,将这个内存地址显示出来,就一切OK了。特别是现在还有自动生成此类内存注册机的软件,只要填入内存地址,一下就生成了。如下图所示。
解决这个问题的办法是推荐使用RSA注册法,如果你不想采用,那就要一些技巧了。
1.不要使用简单判断
不要使用如果这样简单的判断语句,使用循环命令进行判断。
在程序中与你的数据相结合进行判断最好。
2.采用MD5对比
你的注册码判断过程最好不要直接判断两个注册码文本的方法,正确的应该是取文本的MD5码,再用取到的这两个MD5码进行对比,即用户输入在注册编辑框中的文本信息与注册码文本信息进行MD5的直接对比。有时奸人会输入一个假的注册号,然后在内存中寻找这个数据后再进行分析,如果转换为MD5判断后,奸人在内存中是轻易找不到自己输入的数据的;
3.多注册码拷贝
即在内存中复制大量的注册码,在验证时随机取一个进行判断就可以。这样的好处是奸人要跟踪N多个注册码内存,不知在哪一处就验证了,这会让他烦死。
注册码分开放在N个地方也是个好方法。
五.防止文件被暴破
暴破是指破解者在模拟算法失败的情况下,恼羞成怒,狗急跳墙,一气之下暴力破解,将软件的壳脱掉,将要求注册的部分直接跳过去,这样直接产生的后果是文件大小被改变了。
首先要说的是:一般暴力破解前奸人都要跟踪查看你关于注册文字的一些关键字,请大家不要将注册信息的明文写在软件中,如“请注册”,“注册成功!”,“注册失败!”,这些文字请打乱后显示,有可能的话再加密,这样破解者不容易找到位置。奸人有时用一种简单的字符分析工具很容易找到这些敏感的字,因此尽量避免明文显示。
其次,不要使用信息框进行提示是否注册成功,这个信息框的API函数的使用情况很容易被奸人找到,可以单独制作一个提示窗口,上面显示注册成功与否加密后的文字,或直接在窗口中放一张提示是否注册成功的图片也行。
再次,你的注册码判断最好不要直接判断注册码,而是用两个MD5进行对比,即用户输入在注册编辑框中的文本信息与注册码文本信息进行MD5的直接对比。有时奸人会输入一个假的注册号,然后在内存中寻找这个数据,如果转换为MD5判断后,奸人在内存中是轻易找不到自己输入的数据的;
最后,你的注册判断不要使用“如果”这样简单的命令,而是使用前面所说的循环命令进行判断。
加壳软件的作用就是防止自己的程序被暴破。首先破解者会脱壳,如果有的壳很硬,或有加密算法,这为脱壳带来麻烦。其次,加壳后,在外部DLL中存一个MD5的校验,这将防止脱壳后运行,这样奸人就不能进行运行调试了。
加壳软件分为普通壳与加密壳。加壳可压缩文件大小,并且将一些本来清晰的字串进行了打乱的效果。
普通壳的作用是压缩资源,使文件尺寸变小,一般可使易语言缩小一半以上的尺寸,有的还可以减少系统资源占用。其他编程语言生成的EXE文件加壳后有可能变大,例如C语言生成的程序本来就小,压缩不了尺寸,这时再加上一个壳,尺寸反而会变大。
普通壳有:UPX,ASPACK,ASProtect,PKLITE,PECompact等。
加密的壳有:幻影,软件保护神等。
加密的壳可以提供直接的注册码功能。加密的壳由于是公用壳,很多人都去购买使用,一般容易被奸人看中脱壳,灵活性也差。如果被破解了,那么后果是十分严重的。因此推荐的就是一个普通壳,如UPX,然后进行MD5判断是否被脱壳就可以了。
下面,再介绍一下常用的加壳软件。
1.常用加壳软件介绍
下图是UPX Shell v3.10软件的运行界面:
下图是ASPACK软件的运行界面:
下图是PKLITE软件的运行界面:
下图是PECompact软件的运行界面:
下图是“幻影”加壳软件的运行界面:
下图是“软件保护神”加壳软件的运行界面:
壳加完后,余下的工作就是防止脱壳了,一般来说,很多人都想要一个很强的壳,但一方面任何壳都有可能被破解,另一方面壳的兼容性就有很大的问题。
如采用强壳的《系统管理》采用了一个国外出品的强壳,确实是很难脱掉的,但由于破解版的原因,在WIN98下运行时经常会死机。正式版的价格也非常高,基本上要1000元RMB左右。
而常用的普通壳虽然强度并不高,但通过易语言编程进行校验,可以保护您的壳不被轻易脱掉。
加密第3定理:用最普通的壳,让弱手们去脱脱看!我还有校验等着呢。
2.加壳后文件大小验证
加壳后一些数据安全得到了保证。这包括一些没有加工过的字符串,例如:数据库密码,加密算法密码。
加压缩壳后,易语言的EXE文件尺寸一般会变小,一般1.5MB的软件会变小为800KB左右。
那么最常用的文件大小验证可以用如下易语言代码:
判断(取文件尺寸(取执行文件名())= 843674)
上述代码中的数值是经过查看编译及加壳后文件属性大小生成的,但由此造成两种不方便的地方:一是由于易语言造成每次编译后的文件大小是不一样的,因此很难将这个数值取对,二是这个值放在哪里好,如果放在主程序中的话,那么每次生成的文件大小不一样,就会造成取不准,比较不了的现象。
建议大家在比较时可以将代码写成以下形式:
判断(取文件尺寸(取执行文件名())≥ 900000)
通过以上运算符的改变后,基本上可以知道是否被脱了壳了,因为脱了壳后程序的体积会增加很多。
3.加壳后数据签名验证
易语言自带一个“数据操作支持库”,基本可以满足安全加密的需要。如下图所示:
这里较为常用的命令是“取数据摘要()”,这个命令是采用了MD5算法,不同数据的MD5码都不一样,因此本命令可以用作保证重要数据不会被篡改。对于不同的数据,其得出的结果是不一样的。如果奸人将您的软件脱壳了、改动了,那么前后所取得的结果也是不一样的。
“取数据摘要()”得出的结果是返回一段字节集数据的MD5数据摘要编码文本。一般是32位字节的数据。
但这样带来了这样一个问题:即我们取得了加壳后软件的数据摘要,但是放在软件中后再编译再加壳再取数据摘要后,本次取值与前面所取的值是不一致的。
采取的办法一般是将数据摘要文本存放在外部。
一般会采用以下的方式:
第一种方式:加密后存放在一个文件中。
第二种方式:加密后存放在DLL中。
第一种方式可以直接存在一个文件中,也可以夹存在其他文件中,如图片文件中,或音乐文件中,或DLL文件中(硬写在DLL段中)。
第二种方式可取得主程序的数据摘要后,直接在DLL程序的源程序中写比较代码。然后编译为DLL文件,由主程序调用此比较DLL。这样保证了主程序的数据摘要与主程序分离从而加强了主程序的安全性。
4.加壳后CRC验证
我们很有必要给自己的软件加上更好的保护。CRC校验就是其中的一种不错的方法。
CRC是什么东西呢?其实我们大家都不应该会对它陌生,回忆一下?你用过RAR和ZIP等压缩软件吗?它们是不是常常会给你一个恼人的“CRC校验错误”信息呢?我想你应该明白了吧,CRC就是块数据的计算值,它的全称是“Cyclic Redundancy Check”,中文名是“循环冗余码”,“CRC校验”就是“循环冗余校验”。
CRC有什么用呢?它的应用范围很广泛,最常见的就是在网络传输中进行信息的校对。其实我们大可以把它应用到软件保护中去,因为它的计算是非常非常非常严格的。严格到什么程度呢?你的程序只要被改动了一个字节(甚至只是大小写的改动),它的值就会跟原来的不同。呵呵,是不是很厉害呢?所以只要给你的“原”程序计算好CRC值,储存在某个地方,然后在程序中随机地再对文件进行CRC校验,接着跟第一次生成并保存好的CRC值进行比较,如果相等的话就说明你的程序没有被修改/破解过,如果不等的话,那么很可能你的程序遭到了病毒的感染,或者被奸人用16进制工具暴力破解过了。
CRC的本质是进行XOR运算,运算的过程我们不用管它,因为运算过程对最后的结果没有意义;我们真正感兴趣的只是最终得到的余数,这个余数就是CRC值。
易语言用户林子深提供了一个CRC32.EC的易模块,这个模块可以在论坛上或资源网上搜索到。大家可以直接拿过来用,导入易语言后如下图所示:
调用方式可为如下代码:
判断(取循环风俗冗余校验和(读入文件(取执行文件名()))= 18293823767)
其中上述的数字为主程序的CRC码值。
大家可以利用上述特性,即结果是数值的特性,不用进行比较,而是用加减法的方法得出前后两个CRC验的差值,如果为0,那说明两个数字是相等的,主程序没有被改动过。否则就是被改过的。
例如下述代码:
程序被改 = 1
计次循环首(取绝对值(取循环风俗冗余校验和(读入文件(取执行文件名()))- 18293823767),)
程序被改 = 0-
跳出循环()
计次循环尾()
返回(程序被改)
上述代码中,“取绝对值()”是将负数也转换为正数,以方便进行计次循环。
上述代码中,数值型变量“程序被改”为1表示没有被改动过,如果为0表示被改动过。返回的数值就可以进行一些陷阱的计算了。
我的方案的缺点分析:
CRC-32的值其实可以由奸人自行计算得出后,重新写入到程序验证处。这样的话,我们做的工作岂不是没有意义了?
其实解决的方法还是有的,我们可以在计算CRC-32值之前,对参与转换的字符串加点手脚,例如对这个字符串进行移位、xor等操作,或者把自己的生日等信息加入到字符串中,随你的便什么都行,总之不是单纯的文件的内容就行了,然后在最后比较的时候,也用同样的方法反计算出CRC-32值。这样得到的CRC-32就不是由文件的内容计算出来的,相信对破解者的阻力也会加大不少。
总结:
以上的方法大家都可以在软件中采用,最好写到一个DLL文件中,然后多放几个需要验证的子程序,随时以备调用即可。
六.防调试方法
1.易语言的花指令
加花指令的方法有通用性,即所有的反汇编器都可以用这种方法来抵挡。这种方法主要是利用不同的机器指令包含的字节数并不相同,有的是单字节指令,有的是多字节指令。对于多字节指令来说,反汇编软件需要确定指令的第一个字节的起始位置,也就是操作码的位置,这样才能正确地反汇编这条指令,否则它就可能反汇编成另外一条指令了。并且,多字节,指令长度不定,使得反汇编器在错误译码一条指令后,接下来的许多条指令都会被错误译码。所以,这种方法是很有效的 。
易语言新版本中增加了自动插入花指令的功能,并且插入后虽然文件体积大了一些,但不会造成运行错误。大家可以点击菜单“工具”→“系统配置”。弹出的窗口如下图所示。
不采用花指令时,反编译出来的代码几乎是跟源代码一一对应的,这样一来我们的程序还有什么秘密可言呢?完全可以从反编译的结果中理解程序的功能。
其实花指令就是人为地构造一些“陷阱”和一些无用的字节,起到迷惑破解者和隐藏信息的作用。在这里,易语言为你构造了这些“陷阱”。大家只要将上述配置项打开就可以了。同时也提醒大家,在发布新版本时采用以下的方式:第一周发布的是花指令级别为1,第二周发布的是花指令级别为2,第三周发布的是花指令级别为3,第四周发布的是花指令级别为1……,周而复始,这样破解者根本跟不上你变换的速度。
加密第4定理:每周发布一个新版本,让破解的速度赶不上发布的速度。
2.反调试模块的使用
目前易语言论坛上出现了一些模块或支持库,带有反调试的功能,当启用后,就会查看进程中有无调试器,如SOFTICE等调试工具,对易语言的调试也同样有效。
由林子深提供的另一个模块:“星光灭绝”模块大家也可以尝试用一下,为何说是尝试呢,这些模块并不稳定,并且极易造成WIN98下程序死机。并且打开易语言也会认为是调试器,从而会自动退出。
大家自己在易语言论坛上搜索吧。不推荐大家使用。
3.反调试支持库的使用
海洋的支持库也提供了反调试的功能,具体是海洋增强支持库。
但要注意兼容性问题,一定要在多个操作系统下进行严格的测试后才能发布。
4.通过检查父进程得知是否被调试了
一般情况下,直接运行的程序的父进程是EXPLOER,在易语言中调试运行的父进度是易语言,而在破解人手中运行的父进程是用于破解的调试软件。因此我们就有必要判断程序的你进程是否是EXPLOER或易语言,如果不是,非常有很大的可能是在奸人的调试软件中被调用了,这时就好办了。哈哈。
易语言论坛的用户“笨笨啊”提供了一个取进程与父进程的模块,并且有模块源代码,程序主要是由API取得进程内容。
大家可以搜索易语言论坛,用户名为“笨笨啊”,或关键字为“父进程”可以找到这个源代码。
下图是在易语言中调试程序时,父进程为易语言:
下图是易语言编译后运行,其父进程是EXPLORER.EXE,编号为860:
加密第5定理:一个正常运行的EXE的父进程是EXPLORER.EXE
不过这里要注意的是:奸人有可能将调试程序的名称改为EXPLORER.EXE,这样可以伪装一下吗?不可以,你需要检查一下名称为EXPLORER.EXE的进程有几个,进程ID是不是一样的?如果有两个不同的进程ID,那么这时再判定就可以知道是不是被奸人调试了。
5.使用多线程
在Debug的手册里可以看到Debug工具的局限:第一个局限是只能下4个内存区域的断点,每个断点不能控制超过两个字节,这样内存断点不能控制超过16个字节的区域;第二个局限是对多线程只能同时跟踪一个线程。因此利用其的第二个弱点,大家可以多开几个线程进行来回验证。
多线程的编程方法参看易语言手册。
一般开5-8个线程就够奸人忙活的了。
加密第6定理:使用5个以上多线程来回验证注册。
七.注册机制
1.简单注册原理
在易语言安装后的程序“elibkrnlnsamples软件注册.e”就是演示了软件注册的原理。
其中有一个子程序是重复取硬件码的,存在取硬件码失败的情况,因此要重复多取几次,如果取失败就用一个默认的硬件码代替。这个大家一定要看一看,
注册机的原理就是:用户在使用过软件一段时间后,认为软件较为理想,要求向作者注册,而此软件中提供了用户本机上的硬件号,用户将此硬件号发给作者,作者给出一个注册码,用户拿到此注册码后填写,软件就注册成功。注册码的计算是由硬件号产生的,计算过程只有作者知道。
例如:用户机器上的硬件号为34,作者返回的注册码为1904。用户在注册码输入栏中输入1904,那么注册成功。作者是这样计算的,34X56=1904。那么软件中也是这样计算的。以上介绍的只是例子,大家也许会说,从1输到9999,总有一个会遇上的,但事实是硬件码不会这样简单,可以是16进制的,而计算也不会这么简单,可能会用上矩阵也说不定,因此相比较而言,靠猜测的方法去破解是愚蠢的。
下面看一下易语言自带例程中的程序代码,此为要求用户输入注册码时的判断语句:
此为判断语句调用的返回注册码的子程序:
通过以上检查是否输入的硬件码与注册码对映。
而软件作者手上有一个注册机,可以生成此硬件代码,大家可以在此例程上加一个按钮,此按钮的代码如下:
这样作者就可以很轻松地得到注册码,然后将这个注册码发给用户用于注册了。
上述只是在一个理想的状态中实现的,即没有奸人对你的软件进行破解。如果奸人看上了你的软件,只靠这么简单的方法,那么一定会吃大亏的。因此大家在注册码生成的计算上要想尽一切办法使之复杂化,如:采用位异,采用加上计算数值,采用……有些办法将在后面章节中进行介绍。
2.RSA算法注册
①RSA简介
使用RSA非对称密钥算法对指定字节集数据进行签署,支持32到4096之间任意合法的RSA位数,返回签署后的结果文本。
说明一,电子签名系统简要实现方法:
首先给所有具有签署权利的人员授予不同的RSA钥匙,RSA钥匙由“公钥”、“私钥”、“公共模数”三部分组成,为了生成符合要求的随机密钥,可以下载使用 http://dywt.com.cn/RSATool2v14.rar 第三方工具软件(内有操作说明)。然后将所有人员的“公钥”和“公共模数”成对向外公布,“私钥”由被授予人员自行妥善保管。
被授权人员使用“私钥”和“公共模数”对指定数据进行签署,然后将签署后的结果文本随同被签署数据一起发送,接收者收到后,使用该签署者公开的“公钥”和“公共模数”及签署结果文本对被签署数据进行验证,如验证通过则说明该数据必定是此签署者所认可的,且没有经过任何篡改。
说明二,数字签名用作软件注册系统的实现步骤:
1、欲注册用户提供注册信息(如硬件代码、用户姓名等);
2、软件作者使用自己的私钥对该注册信息进行数字签署得到签署结果文本;
3、将此签署结果文本作为注册钥匙文件发送给用户;
4、在用户端的软件使用相同的用户信息、注册钥匙文件及软件作者的公钥进行签名验证,如果通过表明已经注册,否则表示未注册。使用本方法在私钥未泄露的前提下,可以绝对避免破解者做出软件的注册机。
②RSA工具使用简介
RSATool工具运行界面如下图所示:
有很多人说RSA工具不会用,其实RSA工具的使用方法吴涛已说明得非常清楚了。下面引用吴涛说明书的原文:
吴涛写的RSATool工具使用说明书如下:
RSATool 2.14 工具软件使用指南: (软件下载地址:http://eyuyan.com/RSATool2v14.rar) 为了生成符合要求的随机RSA密钥,请类似如下操作: 1、在“Number Base”组合框中选择进制为 10 ; 2、单击“Start”按钮,然后随意移动鼠标直到提示信息框出现,以获取一个随机数种子; 3、在“KeySize(Bits)”编辑框中输入 32 ; 4、单击“Generate”按钮生成; 5、复制“Prime(P)”编辑框中的内容到“Public Exp.(E)”编辑框; 6、在“Number Base”组合框中选择进制为 16 ; 7、记录下“Prime(P)”编辑框中的十六进制文本内容。 8、再次重复第 2 步; 9、在“KeySize(Bits)”编辑框中输入您所希望的密钥位数,从32到4096,位数越多安全性也高,但运算速度越慢,一般选择1024位足够了; 10、单击“Generate”按钮生成; 11、单击“Test”按钮测试,在“Message to encrypt”编辑框中随意输入一段文本,然后单击“Encrypt”按钮加密,再单击“Decrypt”按钮解密,看解密后的结果是否和所输入的一致,如果一致表示所生成的RSA密钥可用,否则需要重新生成; 12、到此生成完成,“Private Exp.(D)”编辑框中的内容为私钥,第7步所记录的内容为公钥,“Modulus (N)”编辑框中的内容为公共模数,请将上述三段十六进制文本保存起来即可。 |
③一个简单的RSA注册机
例如:我们已通过上述RSA工具得到以下三个变量:
公钥:
20063
私钥:
7FC4638275AF6B27AFD040FED32A941D227154ECDE37ABFF73D72DB50F9FC70C75BC3AF0EC26016BC706D953A9C5D6831E0DDD27B42A182CB92A6E426693511E42EB0BF9D64459809D5EC305E13B2A85BA004BA934232305D3DA1205E7AD1D01744BBCF286B23D64CC68371FDD39DAA43861920DA3DE5F9335A77983BFD08A83
公共模数:
CEB774FCCE9DB84A4452A0774264FC55F35A8D8AA9D1FC5EBD3E0880B7B62A4EF834FD6E855CD84A4D04F3BBDE32180FC3EE45AB5582C2320A6575C6ECF923A24EAF59F22F930631347E0E3B0477A89FCE22FE741F5053EC5320AAF6489CC407056361F01E031A02DB52CB0CBDFBB11F72C340354C6CAB78D97630EB8A6A5431
初始化代码如下:
注册窗口设计界面如下:
注册按钮代码如下:
上面的程序窗口插在用户的程序中,当需要注册时即弹出注册。
作者手中的注册机软件界面如下:(注意保密)
生成按钮代码如下:(注意保密)
上述程序已在易语言4.0中运行通过。运行抓图如下所示:
加密第7定理:RSA算法虽然很强,但弱在钥匙文件如何保密上。
④算法实现中的注意事项
上述代码中取硬件码的命令没有采用重复取,而只取了一次,在实际操作中需要正规地多取几次,获取硬件码失败也要作相应的默认处理。并且硬件码好要转换为另一串字符串。
上述代码中所有字串均未作分解处理,实际编程中需要分解,且分别隐藏到程序各处。最好也加上密。
上述代码中注册码文本较长,可直接读取一个文本文件进行比较。即生成的注册码存在一个文本文件中,在点击注册按钮后,直接找这个文本文件的内容进行对比。文本文件的文件名可以是硬件号的名称。
上述是基本算法演示,其中的注册算法还可以再进行加工,变得更复杂一些。
上述中注有(注意保密)字样的代码与程序需要软件作者严格保密,不对外公开。
大家再看一个易语言大奖赛获奖作品:“家电维修”的例子,大家也可以在易语言新建窗口中找到这个程序,看看注册窗口的代码吧,如果您按这样的做法去发布软件,会有什么安全性可言呢。
⑤设计RSA的变形算法
重要提示:上述是对RSA整体进行一次性验证,虽说RSA是一个非常强的加密算法,但是这样的算法太简单,很容易被破解,那么需要通过以下的方法进行变形。以下所举的例子只是一个参考,你自己的方法越古怪越变态越好。
例如,可以采用分解RSA算法,每次只验证一小部分,以保证在程序的各个地方进行不同种类的验证,返回的值有的可设计为数值型,有的可设计为逻辑形,以利于在程序中不同地方调用,调用后可以根据数据进行运算,如果是破解版,那么使用破解版的人得出的结果一定是错误的。采用双RSA密匙、多RSA码也是个好办法,但最好两者之间再混合一下,采用RSA与数值计算支持库混合的方法可以加强加密强度。
另外,密匙字串需要分开存放,全局变量中放一些,程序集变最中放一些,局部变量中放一些,常量中放一些,字符串一定要打乱,不可存为一个变量中,还可以RSA之上再加密,如RSA密钥是加密格式的,验证完后立即清变量……要注意的事项还是很多,一定要考虑周密一些,即要达到加密的目的,也不要太复杂了,以免自己也被搞糊涂了。如果有错误,误将正版用户当盗版用户对待就不太好了。
3.数值计算支持库
易语言提供的数值计算支持库很有特色,其特点就是可以计算任意位数,因此大家可以根据这个特性来制作加密算法,考虑到奸人如果制作一个注册机就必须去研究易语言,及了解了易语言的数值计算支持库后才能去破解,但即使这样,也不能轻松就能写出注册机,试想一下,数值计算支持库本身就花了很长时间写出,因此奸人们是无论如何也是制造不出注册机的。并且一般来说,奸人如果出注册机,一般都希望文件小一些,从而也不会用易语言写注册机程序,一般采用C语言写,即使写了也要带上很大的系统支持库与数值计算支持库,太累了吧,哈哈。
在此建议的是将RSA算法与数值计算支持库相结合的办法,这样的注册机基本上就不会再有了,只要防止内存注册机出现即可。内存注册机的防止可以通过不进行判断的方式解决。而防止暴力破解是通过对软件加壳后,在外部CRC验证保证程序完整性,程序内部再多重检查,加上几个暗桩,这样通过层层把关,最终就可以确保万无一失了。
由于PE文件格式的局限性,任何加密程序都有可能被破解,我们所要做的仅仅是加强加密的复杂度,让奸人知难而退,耗费他们的时间与精力,浪费他的时间就是在杀他。
八.给奸人一些教训
实际上,我们的用户已区分为以下四种人:共享试用者、正版注册者、破解使用者、破解版使用者。
当我们需要给破解者一些教训时,一定要将正常用户区分开,否则正常用户有所损失,那么就根本不会来购买您的软件,您的声誉也会下降的。
1.给破解者的教训
有句名言:“软件很生气,后果很严重!”。
给破解者的教训要深刻一些,最好让他刻骨铭心,永世不忘。
对于一个破解新手来说,很草率地去破解一个成熟的软件,对他来说是灾难的开始,给破解者制造麻烦,让破解者知难而退是一件有乐趣的事。这事一定不要忘记做哦,否则我这文章就白写了。
但最好不要在软件中写有辱骂破解者的话,这样会将奸人狗急跳墙了,反过来会非常强烈地一定要破解你,反而得不偿失,技术上的比拼是正当的,人格侮辱就不太好了。
一个通常的教训如下:
但如果你想变态地去教训奸人,那么我也没有办法阻止你了,毕竟你已在授权文件中警告过用户不要乱动你的东西了。哈哈。
有时候,奸人是使用的虚拟机,你重启、死机什么的都对他有影响,唯一他比较可怜的就是硬盘中的一些资料了。下面是将文件删除到回收站,及清空回收站的代码:
2.给破解版使用者的教训
上面是对于奸人的教训,但对于一般破解使用者来说,也要给予配当的惩罚,但不能太过严厉,不能对他们的机器造成严重破坏。一般来说给予一次广告机会,数据错误,或设置一些小损失即可。
常见的有以下,其他的请你根据你自己软件的内容进行适当的创意吧。
第1种:建议发现是破解版使用者在用时,可为你的软件加一些贴面广告,这样您会有一些收益,以补充你的一些损失。
第2种:将一些数据搞错了,而且是非常明显的错误,让他有些损失。
第3种:建议开始一段时间让他正常用,查明破解版使用者如果保存较多的内容,说明他很在乎经常使用你这个软件,并且认为破解正常,已可以正常使用了,这时等他的数据量大时,将数据库锁定,他一定欲哭无泪,只好请你帮他解锁,购买您的软件了。
易表的作者就是用这种方法。
实际上这是一种暗桩操作,即在发布几个月后再检查是否是正版,或在数据库存储到一定时间后再检查是否是正版用户,这样的加密方法值得大家学习。
可能您很生气,想让破解版使用者得不到好的下场,最好不要删除重要数据。且我个人是不建议大家删除有用的数据的,毕竟这些都是国家的财富。
加密第8定理:加密的结果是双赢才行,用户真正认识到了来注册,同时也能用上正版了。
3.行为不要过火
作者给奸人一些教训是正当的,可是软件会存在BUG,写加密程序也会有BUG存在。如果将正版用户的数据损坏了就不太好了,毕竟大家还是要靠口碑生存的。即使您是对的,但如果盗版用户多,那么如果太严厉了,就没有人敢用你的软件了。
如江民事件,就是前车(JU)之鉴。
如果您能搞出一个即让破解者假象破解,为你作宜传,而又能争取到用户,那样是最皆大欢喜的了。易表就是一个例子,他的软件表面上被破解了,但实际上还存在暗桩,结果用了一段时间后,用户的重要数据被锁定了,只能乖乖注册。
加密第9定理:口碑好的软件才能传播得更广。
九.网络验证法
现在有的人说网络验证法是最可靠,且是从未被破解过的加密方法。确实这种方法很难破解,因为注册码始终是在作者手上的,这样怎么去破解呀。
加密第10定理:一个好的网络验证法至今没有人能破解。
1.实现的原理
网络验证法有些类似于网络游戏中的验证。
网络验证方法,即建立一个网络服务器程序,由软件作者自己保管,运行于服务器端,客户端通过编程放在共享软件中。客户所拿到的共享软件程序中带有客户端程序,当需要验证时,客户端的硬件码通过网络传送到服务器中,服务端程序将加密后的注册码通过网络传回给客户,客户软件中的客户端组件接收到后,在内存中解密进行判定,如果注册了就通过,否则就失败。作者的服务器端上保存了用户的注册码数据库,随时供验证之用。
在此可以避免以下被破解的事况:
首先,通过网络验证即使奸人拦截到了注册码,也是加密过的,如果去解密也很困难,并且服务器是由软件作者保管的,这样奸人可能始终接触不到注册码。或者他要去学习网络拦截也说不定。
其次可以预防暴力破解,软件作者可将重要数据直接放在服务器中,通过不停验证取得数据,从而被破解的客户端被暴力破解后立即成为无效软件。
再次,即使软件被破解了,软件的作者也可以较轻松地升级客户端程序,及升级服务器端的注册码数据库,从而减少破解造成的损失,让破解者阴谋失败。
最后,软件作者可以轻松看到监视客户端的使用情,如果发现有重复名称的验证,或不正常地取数据,就可以立即停止客户的使用。
2.存在的几个问题
用户的程序必须是需要通过上网才能使用的,不上网,将不能验证,也不能使用。
软件作者必须要保证服务器的稳定,如果服务器死机或掉线,那么客户机将不能使用,因此也要具备一定的防攻击能力。服务器维护人员技术要求较高,要有一定的服务器反黑经验。
网络验证也不能一次全部验证,这样并不保险,需要分段进行验证。并且给予暗桩的设计。
可能存在客户太多,一个服务器接收不过来,需要两个以上服务器的情况,或就直接架设两个以上服务器,用于备用。现在的电信与网通经常打架,可考虑一个接电信网,一个架网通网,以备不时之需。
十.加密狗加密
本文的目的是让大家了解加密狗,它并不是那样神密而可怕,大家一定要克服恐惧感哦。加密狗是个极其好用的工具,基本上如果用上一个好的型号的加密狗,可以为您省不少心,想想看吧,有一个技术团队在身后做支持呢。
易语言论坛上有人说:“不要花太多心思到加密上,而是要完善软件功能!”当然将心思放在加密上我也不想,这都是拜小人所赐呀。因此如果您想节约时间的话,只要买个好狗,加一个壳就可以了。
加密第11定理:如果您想不要花太多心思到加密上而想要一个很强的加密,加密狗是最好的选择。
说老实话,现在的狗都比以前好多了,以前还听说有狗被防制或模拟了,现在的狗呀,越做越好了。总之,大家放心用吧。
软件狗是一种智能型加密工具。它是一个安装在并口、串口等接口上的硬件电路,同时有一套使用于各种语言的接口软件和工具软件。当被狗保护的软件运行时,程序向插在计算机上的软件狗发出查询命令,软件狗迅速计算查询并给出响应,正确的响应保证软件继续运行。如果没有软件狗,程序将不能运行,复杂的软硬件技术结合在一起防止软件盗版。真正有商业价值得软件一般都用软件狗来保护。
平时常见的狗主要有“洋狗”(国外狗)和“土狗”(国产狗)。这里国外狗主要指美国的彩虹和以色列的HASP,国产狗主要有金天地(现在与美国彩虹合资,叫“彩虹天地”)、深思、尖石。总的说来,加密狗在软件接口、加壳、反跟踪等方面技术较好,基本上复制很困难。
1.加密狗的选用
加密狗一般分为串口狗与USB加密狗。
串口即打印口,为16针口可以同进串接多个串口型加密狗。如下图所示:
现在也已有一种微型加密狗的推出:
USB口为直接插入USB接口,每个接口只能插一个。如下图所示:
从目前的资料来看,一般加密狗产商都想淘汰并口型的加密狗,而主推USB口的加密狗。一只USB加密狗的批发价现在大50元左右。
USB设备是专门为多设备连接而设计,有着严格的规范,从接口本身就避免了设备间的冲突。所以USB狗不会与遵守USB标准的设备有任何冲突。而因为并口只是为单设备工作设计的,很多并口设备并没有考虑与其它外设公用并口的情况,为降低成本,往往独占了并口资源,使得并口的其它设备不能正常工作。因此建议使用USB狗较好。
USB接口本身具有电源线,可为外设提供稳定的工作电源,从而对USB狗的工作电压、功耗等要求大大降低,加密狗的工作条件得到很大改善。而并口本身没有电源线,并口狗要依靠并口的信号线或数据线提供电源,所以在因并口负载能力低等情况下,并口狗的芯片因得不到正常供电很难保证正常工作。因此建议使用USB狗较好。
2.加密狗加壳法
一般的加密狗软件都提供傻瓜加密工具:加壳工具。这种壳是针对加密狗进行的。
加密狗有内嵌和外壳两种加密方式。外壳加密就是对 exe 、 exp 、数据文件直接进行加密的方式;内嵌加密是在各个语言环境中直接以函数调用形式出现的加密方式。操作系统支持 Dos16/32 、Windows3x/9x/ME/NT/2000/XP 的各种版本,如有的狗提供有 37 种内嵌语言加密模块,四种外壳加密工具。
加壳式加密的软件运行界面与前述的普通壳的加密界面是类似的,也是要提交需要加密的原文件,然后会生成加密后的新文件,这个大家不认为太神密了。
内嵌一般采用供货商提供DLL,就是API调用,以达到调用加密模块的目的。各个狗的调用都不相同,一般会提供C语言或VB语言调用的实例,大家模仿这类程序即可。
有论坛人士说:“心思放太多到反破解上也不是一件好事啊!”,我觉得给别人破解了更不好,是吧!如果不想放太多心思在反破解上,建议还是采取加密狗加壳的办法,方便、快捷,其他时间就可以研究如何将软件完善就行了。因为有一个加密的团队在支持你呀。
3.加密狗写存储器法
有的加密狗带有存储器,大小不一,有的是1024字节,这样大家也可以将一些重要的信息放在这里面。实际上您也可以将RSA的一些数据放在这里,以供程序双重检查。同样也是通过DLL调用的。
十一.加密算法策略(暗桩)
本章所要讲述的是:加密不要拘泥于一种形式,要懂得变化之道,这样才能让破解者无从下手,这是我的软件加密之最精髓的一点。前文所说只是一些最基础的知识,大家还需要一点变通之法,加密方法越奇怪越好,变态一些也没有关系。看过《倚天屠龙记》的话,可以想想张三丰教张无忌太极拳时的那段对话,哈哈。
当然很多人喜欢暴破的,懒得研究写注册机,所以让他们多花费些时间,多浪费他们的生命,就要多打入一些暗桩,不要用简单的“如果”、“等于”判断,免得再精巧高深的加密算法成为华丽的摆设,破解与反破解是一场暗战,就算不能反破解,也要设计多一些迷局关卡,把破解者肥的拖瘦,把瘦的拖死,让他们痴迷、让他们上瘾、让他们欲罢不能,用代码吸光他们的精血。
1.易数据库密码怎么泻露了
易语言论坛上个别用户说自己的数据库密码被别人知道了,那么我们看一下他是如何加数据库密码的,代码如下:
打开 (取运行目录 () + “工资库.edb”, , , , , “K39DKEKD944”, )
好了,我们编译一下,编译成一个EXE文件,然后改文件后缀为TXT,这样我们就可以不用PE专业工具,而是直接用记事本打开了。
然后在记事本中搜索这个密码,大家看到了什么?看下图中反白的部分:
晕死,你这样编程,当然数据库密码会被别人知道了。
将前述代码改动一下,将密码分解为若干单个字符串,然后分别放于全局变量中定义一部分,再在程序集变量中放一部分,这样就不会有问题了。
如下面的试验,只改动一小部分:
口令 = “K” + 到文本 (13 × 3) + 字符 (68) + “K” + “E” + “K” + “D” + 到文本 (18 ÷ 2) + 到文本 (22 + 22)
打开 (取运行目录 () + “工资库.edb”, , , , , 口令, )
再按前述的查看方法,可以看到,数据库前后的密码被处理过的部分都看不到了,如下图所示:
大家应该明白了吧,如果上述代码全部处理好的话,一定不会让别人找到口令的。
实际上,对于重要的加密口令来说,都需要分开存放,并且用取字符,位移或取反的方法,以及加减乘除的方法都可以得到一个隐藏很深的字符串。
加密第12定理:相关加密的字符串一定要打乱加密。
制作一个“字符串搅乱器”,要求如下:输入一字符串或其他类型的内容,输出为经过“字符,取代码,取反,位或,位与,加减乘除,平方,开方”等命令随机配合相加的易语言源代码。界面基本如下:
制作一个内窥器,将你的密码或加密字存入,它可以自动分解,在编译好的EXE文件中查找是否有相同字符串。
这是自己用易语言制作的一个工具,怎么样,比专用的工具还要好用吧。
为了不给奸人创造温馨舒适的破解环境,我们要混乱我们的代码,将软件中所有的子程序名全部替换成随机生成的子程序名然后加上正常的备注。例如Func_3dfsa_fs32zlfv()这个函数是什么意思?恐怕只有天知道了。
可以用易语言写一个易语言“名称混乱器”,基本思路为:将易语言源代码复制为文本,然后用混乱器将名称一一对应进行混乱,然后粘贴回易语言中,这样子程序名称和变量名称等都变为不可预知的字符了,因此加强了保密性。但注意,只有当你要发布软件时才使用之,而且一定注意备份源代码。否则当你看不懂你自己的代码时可别怪我呀!
字符串位置内容 | 是否在EXE中找到 | 是否在资源骇客中找到 |
组件名称属性 | 可看到 | |
组件标记属性 | ||
组件内容属性 | ||
组件标题属性 | ||
菜单名称 | ||
组件列表项目属性 | 可看到 | |
全局变量名称 | 看不到 | |
全局变量值内容 | ||
程序集变量名称 | ||
程序集变量值内容 | ||
局部变量名称 | ||
局部变量值内容 | ||
常量名称 | ||
常量值内容 | 可看到 | |
自定义数据类型名称 | ||
DLL命令名称 | 可看到 | |
DLL库文件名 | ||
在DLL库中对应命令名 | ||
DLL参数名 | ||
图片资源名称 | ||
声音资源名称 | ||
程序集名称 | ||
子程序名称 | ||
子程序参数名称 | ||
子程序变量名称 | ||
模块引用名称 | ||
过滤器内容 | 可看到 | |
信息框文本 | 可看到 |
2.利用吴氏加密算法
我们将吴涛在易语言中提供的自有加密算法称之为吴氏算法。
吴涛提供了两种加自有加密算法:一种是易数据库的加密。还有一种是配置菜单中的易语言源代码口令保护。易语言的易用性就在这里了,大家一定要充分利用这些现成的东西。
使用易语言自带的易数据库的加密功能目前是非常可靠的,这是吴涛研制的自有算法,目前还没有破解易数据库的工具推出。这样就使得一些重要的东西存放在加密后的易数据库中十分安全。
易语言源代码口令保护也是一个吴涛自有算法,加密后的源代码连易语言公司也不能解密。因此我一般用它保护注册机和商业程序,所以我的注册机和商业程序的源代码在我用过的每台电脑中都有,但口令只有我知道,没有口令保证打不开,哈哈。
下图为使用配置菜单后弹出的窗口,大家可以为易语言源代码加上保护口令。
3.海岛挖宝
听过海盗船长的故事吧,故事中海盗将宝物分开存放,这样即使找到一处其他地方也没有损失,而且不仅如此,他们也将藏宝图也分成一块一块的存放。
金庸鹿鼎记的小说总看过吧,皇帝将藏宝图分八册存放,一一找到是非常困难的哦。韦小宝这个天才也花了两三年的时间才找到全部哦。
软件中一些比较重要的文本型字符的保护也是这样,你可以分开位置存放,分段、分开类型存放,用时再转换数据类型。分开存放是指分不同的全局变量、程序集变量与局部变量存放。
加密第13定理:相关加密的部分一定要分开存放。
对于RSA验证也要这样不要一次性地全部验证了,这样一点意义也没有。应该是软件启动时验证一部分,在软件运行中验证一部分。
在Debug的手册里可以看到Debug工具的局限:第一个局限是只能下4个内存区域的断点,每个断点不能控制超过两个字节,这样内存断点不能控制超过16个字节的区域。
假设你的注册部分有300行,你可以分成30个子程序调用或重复的子程序。放一些垃圾代码也不会损失什么。
将RSA验证的一次性验证改为分三次验证,并且每次返回不同的数据类型。
4.随机验证
随机验证很重要,例如你的一处验证是一直存在的,奸人就很容易地下断点跟踪了。因此在软件启动时进行一次正常验证外,其他情况下的验证最好是随机的,用30分之一或50分之一的机会进行验证,这样奸人会不停地试你的软件在哪一处进行了验证,因此破解的时间会相当地长。
加密第14定理:足够多的随机验证足以让破解者累死。
随机验证包括随机进入不同的验证子程序。
或随机中的最大数大一些,只有30分之一的机会验证。
或在窗口中放上一些颜色与底图一样的图片框,这样奸人不一定会点击这里,但用户万一点中了,就会触发验证。
我们假设所有软件都能被破解,包括易语言在内,那么如果他破解的速度跟不上你发布新软件的速度,那么他永远在破最新版而累死。或者说他破解的时间比你写一个软件的代价大,这时还不如他直接写这个软件来得合算。
反破解的任务之一就是让奸人累死,或浪费他的生命。
下面的办法也可以使用:你可以在读到待验证的注册码、公钥、注册文件后,通过定义10000个数组,存入上述同样的内容以备以后进行验证,这最多浪费一些内存。验证时随机使用其中的一个进行验证,由于奸人不知你用的是数组中的哪一个进行的比对,而且是随机的,每次验证的值都不一样,不让奸人吐血才怪呢。
计次循环首(10000,计次)
数组[计次] = “123456” ’ 复制一万个公开注册码或公钥,破解者知道也无所谓。
计次循环尾
数组[取随机数(1,10000)]
你不要立刻检查注册码,10000份拷贝你只要以后随机找一份用就行了,破解的人不知道你正在用的是那一个,同时你可以事先编好且运行时不断使用一些假的读取注册码数组的调用干扰破解者。这种方法对程序的性能影响微不足到,只是浪费一点内存。因为Debug对内存下断点的局限,这种情况他要下断点,累死的就是破解的人了。
5.不同权限验证
在启动时进行一次验证是非常必要的,这样让奸人知道确实是验证了,以让他心理放松警惕,而这次的验证只是一部分验证,并没有完全验证。
还有的建议在启动时将注册信息读入后不要进行验证,保不定在哪里进行验证,个人认为这样让破解者提高了警惕性,会认为软件作者很有经验。麻痹敌人也很重要呀。
例如,在启动时验证通过一次,验证级别加强一级,然后再在其他的地方再进行验证就可以了。
下面代码是确认了一个级别
计次循环首(到数值(验证1),)
已注册 = 1
计次循环尾()
……
……
在另一个触发子程序中再通过这个级别再验证:
计次循环首(已注册)
计次循环首(到数值(验证2),)
已注册 = 2
跳出循环()
计次循环尾()
跳出循环()
计次循环尾()
在其他触发子程序中再通过这个级别再验证:
计次循环首(已注册)
计次循环首(到数值(验证3),)
已注册 =3
跳出循环()
计次循环尾()
跳出循环()
计次循环尾()
有时也可以将级别降一降,怎么降,当然是不考虑级别直接验证了:
6.忽悠型的垃圾验证代码
前面已讲过花指令的原理,在程序中人为地再放一些垃圾代码以忽悠奸人也是一个好办法。垃圾代码就是一些假的验证代码,基本上是明文的,这样的代码上百上千,足以让奸人累死。
其实对付那些“根据跳转指令的爆破”高手来说,一个办法就够他们头疼的了,就是你在程序中不明显加入与判断是否正版有关的语句,也不做任何提示,以免让他们顺藤摸瓜,而是在判断为盗版后,跳转到另一个看似很合理的分支,而那个分支和正版的分支代码差不多,只是在计算公式或其它算法上稍动一下,使其运算结果不正确,这样,他们就在机器码级别上就分不清哪个是对的,哪个是错的了,即使他们认为破解成功,其实运行时,得的结果错误百出,他们就没兴趣了,呵呵,算损的吧!!!
加密第15定理:大量添加垃圾代码虽然是无奈之举,但很管用。
制作一个常量迷幻器
要求:制作一个常量代码自动生成器。可随机生成成百上千个易语言源代码形式,可直接拷贝到易语言中成为常量。变量也可以这样制作。
写好这样一个程序后,就可以自动生成垃圾代码,然后复制,粘贴到易语言的常量表中即可。如下图所示:
变量也可以这样生成,不过生成的变量可以任意拷贝为全局变量,或程序集变量,或局部变量。制作时的名称可以为中文名称,直接编译后不会在EXE文件中找到同名的中文名称。因此您可以放心地将这些名称定义为:“垃圾常量1”、“垃圾变量1”等等以示与正常代码进行区别。
制作一个代码迷乱器
本次作业性质同上,也是自动生成易语言的一些无用垃圾代码,以迷乱奸人的破解,让他找到的全是垃圾代码,从而大大延长了破解时间。
通过直接拷贝编辑框中的内容,粘贴到您的代码中,可自动完成任务,如下图所示:
上图所生成的是一些明文的加密方法的垃圾代码,让奸人去研究这些垃圾吧。
上述子程序名称最好也有时调用一下,反正不会真正产生作用的,用多线程调用最好。
或者您平时注意多收集一些别人用于加密时的子程序,拷贝到一个易语言程序中,保存,这样的代码作为垃圾代码放在你有用的程序中,虽然增加了一些程序的体积,但安全性是大大提高了。并且基本上没有牺牲软件性能与稳定性。
7.伪验证技术
还是先举一个例子说明吧,易表软件在10.0版本前已发现有大量的注册机存在,于是易表作者其后改变了加密方式,易表10.0推出后还是出现了注册机,并且这种注册机注册过的软件可以使用。于是有些用户用注册机取得的注册码使用了,过了一段时间,当盗版用户将重要数据存入易表后,突然有一天数据库被锁定了,于是只好注册易表,并且让易表作者为数据库解锁。
从这里可以基本上判定易表新版本采用了伪验证技术,即在较为明显的地方提供了一级验证,这种验证方式没有经过太强的加密,而二级验证在一定的条件下才触发,而这个条件是检查到了用户输入了重要的数据,或大量的数据,或使用次数较多。
基本原理是注册文件由前后两个注册码拼接而成。一般情况下只进行第一个注册码的验证,而当条件成熟时进行第二个注册码验证。
这是一种双赢的策略,易表作者即收到了注册费,付费的人还会道歉,并且感谢易表作者。哈哈,大家要学习这招哦。
但本办法对于数据库应用及数据量大时检查最好,而对于一些没有生成数据的用户无效。
发布软件的时候发布自己编写的注册机,弄个假破解版,那么想破解的就可能不来了,即使有真的破解,谁会有自己给自己写假破解快啊!可能假破解版中只破解一半,等用户使用了,有数据了再锁定,让他们注册后再给解锁,付了钱还要谢谢你,哈哈,损招,但有用!
加密第16定理:伪验证可以迷惑一般破解者,甚至自己发布一个伪注册机。
8.定时验证、延时验证、客户数据集累验证
过一段时间后再验证,如你在2005年1月发布一个软件,那么就内定2005年6月后触发验证机会。
或您的软件是一个数据库产品,那么您可以在程序中设置如果数据库大于5MB时就进行验证,并且最好您能确定这些数据是不重复的,刻意加入的。
如易表设置了伪验证,这时市场上出现了新的注册机,当用户用这个注册机后,提示是注册成功了,但当用户输入重要数据后的某个日子,突然打不开数据库了,用户很着急,因为以为是破解成功了,所以将重要的资料输入了,只能拿钱向易表作者进行注册了。而且还千恩万谢,后悔自己不该用破解。哈哈,一举两得呀。
这个方法对于数据库应用软件来说是绝好的办法。
作业:制作一个算法程序放在你的数据库软件中,这个子程序可以统计你的数据库软件使用时,用户输入的是否是拷贝的东西,还是正常的数据。当统计到1000时触发验证。方法思路为:可以通过查看用户有没有使用复制与粘贴快捷键,或资料进行排序,如果有大量重复的,就说明是奸人在拷贝数据破解,否则是一个资料一个资料的输入的,说明是正常使用的重要资料,这时进行对比就好了。
本方法对有资料的破解使用者有极好的控制作用,通过第6条的伪验证技术与本技术结合,那么就可以知道是不是正版用户,并且可以锁定数据库,等他注册后再给他解锁。
加密第17定理:加密的结果应该是双赢,伪验证是一个上策。
9.验证与专业知识相结合技术
将验证与专业知识相结合,让奸人必须学习专业知识后才能真正去破解,这样所花的功夫比自己写一个软件的代价还要大,而有的专业知识不是专家是不知道的,因此是一个较好的加密方法。
前述中采用了“到数值(验证1())”这样的代码返回的是0或1两者之间的一个数,可以用乘法进行混合计算,如:
音量 = 播放位置X到数值(验证1())
当验证正确时返回的是1,这时的结果是正确的,否则返回0,这时的结果为0,是错误的。
这样的代码可以混合到您的专业知识中,如:算命软件可将天干地支、生辰八字中的某个地方进行此类计算,计算类软件可以将某种特殊的计算过程如此结合计算,绘图类软件可将绘图中的算法部分加入此类计算,音响设计类、机床设计软件……
加密第18定理:你知道的专业知识,破解者不一定了解哦。让专业知识与验证相结合吧。
10.伪装,用易语言写自有支持库
大家可以将DLL文件的扩展名改为易语言的支持库文件FNE扩展名,这样进行非独立编译后,与其他FNE文件混合在一起,甚至您可以用易语言写一个支持库,将其中一部分作为验证部分。
易语言的支持库文件FNE文件其实就是一个DLL文件,只不过扩展名改变了而已,用易语言写支持库的方法金眼睛已发过一篇贴子,进行过说明,请大家在易语言论坛上搜索金眼睛的贴子就可以找到了。
作业:找到金眼睛关于用易语言写支持库的贴子,并且自己写一个支持库。
11.绝妙的暗桩设置
应该想到的用代码实现的暗桩前面都讲了不少,下面是一些特别的暗桩供奸人品味的。
大家可以在一些不起眼的地方再放一些暗桩,如:在窗口最小化事件中随机验证,如在某个组件鼠标被移动事件中验证,
有时需要将数据完整性验证放在更高一级的验证中,不要一上来就检查文件是否被更改。
同一验证可以使用多次,这样奸人认为你已经验证过了,没有必要会再验证一次,而相反这时又产生了验证,让奸人防不胜防。如启动时就立即检查程序完整性,如果发现被更改,那就立即退出程序,而在一些子程序中也随机放这样的验证。
更多的暗桩大家自己设计最好。
加密第19定理:加密重要的是暗桩的设置,破解不完全就是一个无效破解。
12.发布不完整版本
有的软件作者在发布共享软件时,放在外面的是不完整版本,将更多的数据资料在注册后提供。这样做也可以,只是麻烦一些而已。如有的图形制作软件,将图片资源另外打包,用户注册后再给完全版的图片。
也有的将DLL文件中的验证部分作了空处理,而在注册后提供真正的注册DLL文件及注册码。还有的直接将KEY文件放在了DLL文件中另外提供。
加密第20定理:不要发布完整版本,以静制动。
13.程序、数据结合加密技术
把程序运行所必需要的资源放到一个数据库文件中,给这个数据库设密码,密码是主程序的数据摘要变换后的结果。程序运行是先验证有没有注册,如果已经注册,就对运行程序本身(取执行文件名())取数据摘要,用自己设计的算法多次变换后形成一个字串,用该字串作为数据库的密码打开数据库文件。如果打开数据库失败,就说明主程序被人修改了,终止程序运行即可。(不终止也没戏,程序找不到运行所需的资源。)
另外设计一个程序,用同样的算法算出数据库密码,然后给数据库加密即可。
密码形成算法建议使用大数支持库。但如果是汇编高手用汇编写注册机的话,会直接将支持库的所有反汇编码抄进去就可以了,问题是他们有没有时间搞。
14.自定义算法
前面讲过采用RSA与数值计算支持库交叉计算的办法,这就是一种自有的算法,如果能用上数值计算支持库中的矩阵、傅丽叶变换等高级功能就更好了。
多重RSA交叉打乱:大家也可以多用一些RSA密钥,如用5个,10个都无所谓,重要的是将这些注册码都打乱,让奸人哭死。打乱的方法就是你自己独创的方法了。
更多的自有算法就要靠大家自己去研究了。祝大家好运。
加密第21定理:加密不反对古怪和变态的方法,鼓励哦。
15.加密框图
下面给出一个加密的设计框图,大家可以根据自己的实际情况改变加密的策略:
图中主程序外围进行了花指令编译,并且用加普通壳进行保护。脱壳了也无所谓,因为设置了暗桩,随机检查。
图中表示主程序运行后,首先进行了常规的注册码第一次验证,找有没有注册文件。如果这个被破解,注册码应该是一个短的RSA,而真正的注册码是三个RSA的叠加。会生成伪注册机也无所谓。
主程序中用暗桩的形式对窗口标题、版权信息进行验证,这是考虑到如果一启动就验证这些很容易被奸人看出来从而会跳过去。因此用一些随机,或分级,或条件法取得不固定的验证。
主程序中用暗桩的方式对加壳后主程序的完整性进行校验,这个也不要放在常规的验证中,否则很容易被跳过去。可以查文件长度,MD5或CRC32都可以上。
主程序中用暗桩的方式加入了反调试模块。
主程序中布满垃圾验证代码。并且源代码有备注,不会搞错的。
主程序在某个条件下随机进行第二级验证,从注册码中取第二段数据,如果注册码长度不够且取不到第二段数据,那么就说明已使用了伪注册机,将用户的数据库锁定,等他付钱来注册。
主程序在一个条件下再激活验证,从注册码文件中取第三段数据,如果注册码长度不够,且取不到第三段数据,那么就说明已使用了伪注册机,将用户的数据库锁定,等他付钱来注册。
编程中还注意将加密的字符串搅乱且分不同地方存放,用吴氏加密命令加密重要数据,也可加入数值计算支持库的算法,也可以加入一些惩罚手段,也可以再加入自己的一些算法。
以下是一些人的编程体会摘录,基本未改其中的内容,在此表示感谢!
附录1加密已形成密码学
我引用《应用密码学》作者的话:
世界上有两种密码:一种是防止你的小妹妹看你的文件;另一种是防止奸人阅读你的文件资料。
如果把一封信锁在保险柜中,把保险柜藏在纽约的某个地方…,然后告诉你去看这封信。这并不是安全,而是隐藏。相反,如果把一封信锁在保险柜中,然后把保险柜及其设计规范和许多同样的保险柜给你,以便你和世界上最好的开保险柜的专家能够研究锁的装置。而你还是无法打开保险柜去读这封信,这样才是安全的。
意思是说,一个密码系统的安全性只在于密钥的保密性,而不在算法的保密性。
对纯数据的加密的确是这样。对于你不愿意让他看到这些数据(数据的明文)的人,用可靠的加密算法,只要破解者不知道被加密数据的密码,他就不可解读这些数据。
但是,软件的加密不同于数据的加密,它只能是“隐藏”。不管你愿意不愿意让他(合法用户,或 Cracker)看见这些数据(软件的明文),软件最终总要在机器上运行,对机器,它就必须是明文。既然机器可以“看见”这些明文,那么 Cracker,通过一些技术,也可以看到这些明文。
于是,从理论上,任何软件加密技术都可以破解。只是破解的难度不同而已。有的要让最高明的 Cracker 忙上几个月,有的可能不费吹灰之力,就被破解了。
所以,反盗版的任务(技术上的反盗版,而非行政上的反盗版)就是增加 Cracker 的破解难度。让他们花费在破解软件上的成本,比他破解这个软件的获利还要高。这样 Cracker 的破解变得毫无意义——谁会花比正版软件更多的钱去买盗版软件 ?
然而,要做到“难破解”,何尝容易? Sony 曾宣称的超强反盗版(Key 2 Audio音乐 CD反盗版),使用了很尖端的技术,然而最近却被一枝记号笔破解了,成为人们的饭后笑料!
所以,很多看上去很好的技术,可能在 Cracker 面前的确不堪一击。就像马其诺防线一样,Cracker 不从你的防线入手,而是“绕道”。这样,让你的反盗版技术在你做梦也想不到的地方被 Crack 了。
为什么会这样呢 ?归根到底是因为软件在机器上运行,并且软件和机器是分离的——这一点是关键,如果软件和硬件完全绑定,不能分离,是可以做到象 IDEA 之类几乎不可破解的系统的。这将在后面谈传统软件保护技术时详细说明。
对我的这个解决方案,我不能保证Crack高手在几天之内不能破解它,我只能说:“在这个软件中,我尽量堵住了当前破解者普遍使用的方法以及“我想得到”的可能的缺口。”但是我相信,倾注了我 三个月心血的反盗版软件,决不是一个“玩具式”的反盗版软件。
附录2《如何用简单方法防止破解》
北极异型
在Debug的手册里可以看到Debug工具的局限:第一个局限是只能下4个内存区域的断点,每个断点不能控制超过两个字节,这样内存断点不能控制超过16个字节的区域;第二个局限是对多线程只能同时跟踪一个线程。
假设你的注册部分有300行,你可以分成30个子程序调用或重复的func1(),func2()... func30()。将他们随意放到程序的各个部分,一定不能放在一起(自己能找到就行了)。不要用Memcpy等常用系统调用拷贝注册码,尽可能自己写,像Memcpy很好写,性能差点无所谓。经过编译后inline函数展开,注册部分和其他代码混在一起,他要写出注册机就像大海里捞针,在几十万甚至上百万汇编代码里找出有用的注册部分。
利用Debug的第一个局限最重要的一点是:注册码也不要放在一起,假设你的注册码是12位,千万不要用一个12位的数组放注册码,你可以在程序的不同位置定义12个全局字符变量,每个放一位,这样注册码在内存就不连续了。最好再加密处理一下(简单的字符异或就可以),验证时再解密。也不要用连续内存保存验证用到的变量,尽量将用到的验证临时变量分散定义在程序的不同处,再在验证中,不断转移一些值到其他变量中,对付暴力和Loader会比较有效。
没有必要用复杂的加密算法,更容易成为追踪的目标。只要你将注册部分隐藏的足够好,也没有漏洞,你花1天写的加密算法,破解者可能会花100-1000倍的时间破解。大部分人都会放弃。
你将注册做在一起,就像将你的财宝放在现代保险箱里,虽然非常坚固难以解密,对于开锁高手两分钟就打开了。
而古代海盗用的方法是将财宝埋在海岛上,这样没有藏宝图,对所有高手和低手都只有一条路,拿一把铁撬挖,可能要挖一生。程序有那么多代码,反编译出来可能超过百万行,你将注册部分藏在里面,藏的好就如同将财宝埋在海岛里。那些所谓的Crackme只是给高手玩儿的现代保险箱而已,用原始的方法可以达到同样效果。
1.读完注册码后不要立刻检查注册码,因为读注册码肯定用到系统调用,系统调用附近很容易下断点。先放到内存作为全局变量,然后你可以在程序的任何部分,任何时候,读注册码,读内存是没有任何系统调用的。
2.两种办法处理在内存的注册码,
一种方法是在检查前分散隐藏注册码,这样他们无法从内存中搜索到注册码出现的位置,因为他们会在注册码出现位置附近下断点。
还有一种方法是正好相反,你可以在读到注册码后,多次将注册码在内存(用Malloc分配多处)的各个位置做大量拷贝,这最多浪费一些内存。16Bits的注册码做10000份拷贝也只用160K内存。如果不用Malloc分配这些内存,那么最好和其他程序使用的全局变量交互混在一起(这样即使破解者用HEX 编辑器打开并搜索你的程序中使用那部分内存的代码,也无法将正常程序数据和注册码区分出来). 你不要立刻检查注册码,10000份拷贝你只要以后随机找一份用就行了,破解的人不知道你正在用的是那一个. 同时你可以不断生成一些假的读取内存注册码的调用干扰破解者。这种方法对程序的性能影响微不足到,只是浪费一点内存。因为Debug对内存下断点的局限,这种情况他要下断点,累死的就是破解的人了。
3.程序多处做CRC校验文件大小检查,发现不对就退出。一定要多处检查,不能只检查一次。
4.用inline函数将注册部分分成许多小块,分散到程序各处运行。最好能放在不同的线程中运行. 检查结束不要给任何提示,在程序中的内存中做一个标志即可,提示信息要延迟一段时间出现,不要让破解者通过提示信息找到标志位置或检查结束位置,否则前功尽弃。当然也可以象上面那样做10000个标记,随机用一个,这时你不用担心破解者知道标记的位置.而且标记最好不要用0或1,可以用一个貌似随机的值作为注册成功的标记,如何产生这个随机值只有你自己知道。
什么算法无所谓,最终目的就是让破解者的作用发挥不出来。和古代海岛藏宝一样,你只要把检查痕迹很好擦掉分散,破解高手的用处就发挥不出来。破解者玩的Crackme就是保险箱,如果是开锁高手,目标明确总能打开,不行还可以用炸药。但到海盗的藏宝地点,任何开锁高手都没有用。
这种方法用的好的结果是你容易创造检查注册码的方法,自我创造发挥的余地很大,而对破解者会很麻烦,他搞不清楚你在干什么,你只要让破解者感觉象是蒙着眼睛走迷宫或者在猜没有谜题的谜语就行了.而且对你来说更换算法也很容易,因为可能根本没有算法,只有谜语和迷宫。要充分利用程序反汇编后代码多这个特点,除了读注册码的时刻,其他时候根本没有系统调用,除了内存,根本无处下断点.而你使用复杂的加密算法通常的结果是你麻烦,破解者很容易,因为各种加密算法都已经研究透了,而且用复杂的加密算法的调用或系统调用立刻暴露你检查注册码的位置,为暴力破解提供了方便。
我和很多人一样,也是不会汇编语言,而且程序一出来就被0day破解,而且几乎每一个版本它们都要破解.苦于不会汇编,也不太了解破解流程,只好去看SOFTICE的手册,想了这么一个简单的方法. 0day虽然它们经验丰富也能破解,而且似乎也逐渐了解和改进对我的程序的破解. 但许多破解是坏的,根本不能用. 而且就是被破解后,只要将这些inline调用和全局内存变量的位置稍微变一变(大概只需要2-3个小时),它们下一次的破解又是坏的. 而且我还没有完全使用上面的方法,例如我还没有做10000份的内存拷贝或10000份的标记. 因为只是简单的用inline和将注册信息与其他全局变量混在一起,现在就已经够了,0day的暴力破解就经常会破坏正常程序数据.
附录3代码与数据结合技术
于破解过招,保护你的共享软件
NEW
﹀
﹀
﹀
——此文曾作为连载刊登于《电脑报》2003年41、42期,如要转载,请注明出自《电脑报》
共享软件是软件业目前世界上比较热门的话题,国内更是如此。成千上万的中国程序员以极大的热情投入到这个领域来,都憧憬着用辛勤的劳动来获得丰厚的回报;但,实际并非如此,绝大多数的人都弑羽而归。值得注意的是:除了选题和技术上的原因外,最大的原因就是共享软件被破解(Crack)了。
破解见得多了,不免有些麻木。大部分作者都是新软件发布一个星期左右甚至一天之内就会在网上发现注册机或者被修改过的软件(行话称之为“爆破”)。破解者制作了英文、中文、俄文、德文等语种的注册机大肆发散不说,还常常给作者寄一份,外加一封挖苦辱骂的信。唉!我们得罪了谁?没日没夜地熬夜编码,难道得到的就是这连绵的挖苦和不尽的羞辱吗?
不!决不!我们有理由也有能力保护自己的劳动成果!但问题是:如何保护?关注国内,网上关于破解资料和教程俯拾皆是,而关于软件保护方面的资料则是凤毛麟角(大多都关系到什么技术垄断),这种畸形现状就导致了相当一部分朋友的加密非常脆弱甚至可以称得上是“弱智”!要知道,你要面对的是已经形成团伙的众多破解高手呀,国内的什么CCG、BCG,国外的eGis、King、Core、TNT、DAMN和TMG,皆为水平一流的破解组织。全球盗版软件不少于80%都是由他们的破解的,技术实力连大软件公司都不可小视。
看到这里,你是否已经已经灰心了?别怕,虽然我们理论上无法完全避免被破解,但如果能够有效地拖延被破解的时间,并充分打击破解者的自信心,是可以让破解者无法忍受这种折磨从而最终放弃的。
破解,通常的做法有两种——暴力破解(爆破)和写注册机。下面我就来依次讲解每种破解方法的原理和应对方法,这些都是鄙人积累的一些共享软件保护经验,某些关键地方还有例程讲解(Delphi代码,使用C++和VB的朋友可以自己稍微修改一下),希望能对新手们有些帮助,能够更有效地保护自己的劳动成果。
暴力破解(爆破)
这是最常见,也是最简单的破解的方法。该法最适合于对付没有CRC效验的软件,破解新手乐于采用。
大凡共享软件,验证是否注册大多数要采用if条件语句来进行判断,即使你采用了什么RSA或ECC等强力加密算法,也免不了使用if条件语句。呵呵,这里就是共享软件最为危险的地方哦,当然也是爆破手孜孜不倦所寻求的目标呀!
例如,你的注册子程序易语言代码类似如下:
.如果 (签名验证 (到字节集 (编辑框_硬件号.内容), 编辑框_注册码.内容, 公匙, 公共模数) = 真)
信息框 (“注册成功!”, 0, )
.否则
信息框 (“注册失败!”, 0, )
.如果结束
这个注册函数即使使用了强劲的RSA算法进行注册码验证,可是依然很容易被破解,我们只要把这里修改为:
.如果 (签名验证 (到字节集 (编辑框_硬件号.内容), 编辑框_注册码.内容, 公匙, 公共模数) =假)
或
.如果 (取反(签名验证 (到字节集 (编辑框_硬件号.内容), 编辑框_注册码.内容, 公匙, 公共模数) ) =真))
就可以破解成功了,这时戏剧性的结果会产生:随便输入任何注册码都可以注册通过,相反输入正确的注册码却无法通过注册。其具体操作是先反汇编或者跟踪你的程序,找到判断注册码的cmp、test等汇编指令后的关键跳转指令处,通常是je、jz之类的汇编指令,把它们修改为jne或jnz即可,这样常常只需要修改一个字节就可以完美破解之。
令人遗憾的是,目前大部分共享软件都是这样进行判断的,这也是为什么网上被破解的软件铺天盖地的主要原因。因为这样破解实在是太简单了……
难道没有什么可以防止的方法吗?当然有啊!只要把软件的关键代码嵌入到注册码或者注册文件中就可以充分防止破解。但现在问题是,怎么嵌入呢?
最简单的方法就是把关键代码(你的软件功能限制部分最关键而且最简单的一个函数)做成一个小Dll(动态链接库),用强力对称算法加密(密匙可以是主程序某一固定不变的部分或壳的特征值)后生成一个注册文件(License文件,呵呵,格式只有你知道哦!),或者Base64编码后生成一个注册表文件,用户可以双击导入注册表内。
效验流程如下:已注册用户验证注册码时,先验证有没有文件,没有文件者自然受限制的功能无法使用。如果有注册文件,解密之即生成一个小临时文件。如果主程序被脱壳或者被修改(爆破),自然特征值密码不符,解密出来的肯定都是垃圾码,没有一点用处。只有没有被修改的主程序才能正确的解码,而且当然只有解密正确的文件才是一个真正的Dll文件,才能被GetProcAddress函数找到欲调用的关键函数地址。这样只有已注册用户才可以享受到你软件的全部功能了。
如此一来,Cracker破解你的软件就变得很困难了:
首先,他如果没有注册文件,即使他把主程序脱壳了,由于受限制的部分和注册文件是关联的,他也根本无法修补完整。
第二,即使他得到了你的注册文件,由于是加密文件,他也无法直接利用之,这样就逼迫他去拆解你的算法,这可是他们最不愿意的碰到的事情哦!如果到了这一步,我想99%的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;
当然,你可以保护得更好一些:可以不采用临时Dll,而把解密后的关键代码用WriteProcessMemory这个API函数写入到主可执行文件自己进程被提交(Committed)的内存页面的指定位置去。这样由于磁盘上没有解密后的临时文件,破解更加困难。事实上,目前世界上最强劲的专业保护软件Armadillo就是用的这种方法。而且这种方法可以充分防止被调试器Dump。但实现起来比较困难,尤其是在WinNT 5以后的操作系统中。
由于这种方法将注册文件和受限制代码唯一关联,爆破手拿到你的软件也只有干瞪眼。建议大家都给共享软件加上功能限制,这样比时间和次数限制更加安全。
写注册机
顾名思义,这种方法就是模仿你的注册码生成算法或者逆向注册码验证算法而写出来的和你一模一样的注册机。这玩意威胁极大,被爆破了还可以升级。如果被写出注册机,呵呵,你的软件只好免费了。或者你必须更换算法,但以前注册过的合法用户都得被迫更换注册码了,累死你!呵呵……
上面的方法虽然可以避免爆破,但注册机的威胁还是存在的。Cracker要写注册机必须详细研究你软件的验证模块,这必须先将你的软件脱壳,再反汇编或者用调试器跟踪。市面上许多加壳和保护软件都吹嘘不可能被脱壳,令人可惜的是到目前为止没有一个软件兑现了它们的诺言。由于CPU最终执行的都是有效指令,所以等你的程序自解压完成后再从内存中Dump出来就可以实现脱壳。因此不要在壳上面花很多功夫,因为没有这个必要。
反汇编是和调试器跟踪也都是不可能防止的,因为所有的Win32程序都是必须通过API来调用Windows系统中的关键Dll的(如Kernel32.dll、GDI32.dll等),然而API是可以Hook的。我们只能从自己的代码着手来保护我们的劳动果实了。
为了自己调试和以后维护的方便,我们一般采用有意义的名字给我们的函数命名,可这给了Cracker可乘之机。例如这样的函数是什么意思大家应该是一目了然吧?IsRegistered(), IsLicensed(), LicenseVerify(), CheckReg()...这样Cracker就可以轻松地从数千个函数中找到他的目标---你的注册码效验函数!而且破解Delphi编写的软件还有一件TMG小组的破解利器---DeDe,它可以轻松看到你软件里的Form、Unit和函数名,还可以反汇编一部分代码,更是可以和Win32DASM合作反汇编更多的代码,对Delphi软件威胁极大。
为了不给Cracker创造温馨舒适的破解环境,我们要混乱(Obfuscate)我们的代码,将软件中所有的函数名全部替换成随机生成的函数名。例如Func_3dfsa_fs32zlfv()这个函数是什么意思?恐怕只有天知道了。网上有现成的代码混乱器,你按你使用的编程语言的种类可以找到一些。但注意,只有当你要发布软件时才使用之,而且一定注意备份源代码。否则当你看不懂你自己的代码时可别怪我呀!
另外一定要使用公开密匙算法保护你的软件,RSA、DSA和El Gamal之类的算法都可以从网上找到。但注意:将你算法单元中的所有涉及到算法名称的字符串全部改名。避免被Cracker发现你用的算法而模仿写出注册机来!你还可以张冠李戴,明明用的DSA,将名字全部替换成RSA,呵呵,让他模仿去吧!
其它算法如对称算法和Hash算法都也要注意改名,否则这样:
EncryptedCode = Blowfish(MD5(UserName), MD5(Key));
//你的加密算法,使用了Blowfish(对称算法)和MD5(Hash算法)
虽然我不了解Blowfish和MD5算法的原理,也不会逆向它们,但我了解你的效验算法的流程和算法名,我马上就可以从网上找到类似的Blowfish和MD5算法包,从而模拟你的软件仿造出注册机,啊?!真是……$&*&($#%@!
如果你用的什么其它不常见的算法(如Skipjack (NASA美国航天局标准算法), LOKI, 3-WAY, Safer之类不出名但强度很高的算法),并且全部改名,就让他们去研究软件中成堆的如下代码是什么加密算法吧!:)
0167:005B9F70 MOV EAX,[EBP-10]
0167:005B9F73 CALL 00404000
0167:005B9F78 PUSH EAX
0167:005B9F79 MOV EAX,[EBP-10]
0167:005B9F7C CALL 004041C4
0167:005B9F81 LEA ECX,[EBP-14]
0167:005B9F84 POP EDX
0167:005B9F85 CALL 004B860C
当然,最好把Hash算法也全部改名,给会给他们制造更多的困难。但注意,MD5和SHA之类的Hash的初始值会被Cracker从内存中找到,这样他就知道了你用的Hash了。所有建议同时使用MD5的变形算法Ripe-MD(RMD)128或160和其它的Hash,如Tiger, Haval等算法。
另外,请注意要经常效验你的程序是否被修改(Hash效验),如果被修改则退出。但请注意,有些病毒会修改进程的句柄表和它指向的内核对象,这样病毒就可以直接修改运行中的PE文件而感染之了,另外还有网络传输错误的问题也会导致软件CRC出错。因此请不要认为可执行文件的CRC不符而此时程序已被脱壳了。
其实,程序被脱壳最明显的标志是其大小明显大于脱壳前。1M的PE文件被UPX、ASPack之类的软件压缩后通常只有400左右。如果你的软件在运行中发现自己的大小大于800K,我想你应该知道如何做了吧?呵呵...
还有一点,调试器对我们的威胁很大,我们不会肯定让Cracker们舒舒服服地使用SoftICE、TRW和OllyDbg来调试我们的程序。除了常用的MeItICE方法外,这里我给一个我写的方法:
{ 检查自己的进程的父进程是否为Explorer.exe,否则是被调试器加载了 }
{ 不过注意,控制台程序的父进程在WinNT下是Cmd.exe哦!}
{ 注意加载TlHelp32.pas单元 }
procedure CheckParentProc;
var //检查自己的进程的父进程
Pn: TProcesseNtry32;
sHandle: THandle;
H, ExplProc, ParentProc: Hwnd;
Found: Boolean;
Buffer: array[0..1023] of Char;
Path: string;
begin
H := 0;
ExplProc := 0;
ParentProc := 0;
//得到Windows的目录
SetString(Path,
Buffer,
GetWindowsDirectory(Buffer, Sizeof(Buffer) - 1));
Path := UpperCase(Path) + 'EXPLORER.EXE'; //得到Explorer的路径
//得到所有进程的列表快照
sHandle := CreateToolHelp32SnapShot(TH32CS_SNAPALL, 0);
Found := Process32First(sHandle, Pn); //查找进程
while Found do //遍历所有进程
begin
if Pn.szExeFile = ParamStr(0) then //自己的进程
begin
ParentProc := Pn.th32ParentProcessID; //得到父进程的进程ID
//父进程的句柄
H := OpenProcess(PROCESS_ALL_ACCESS, True, Pn.th32ParentProcessID);
end
else if UpperCase(Pn.szExeFile) = Path then
ExplProc := Pn.th32ProcessID; //Explorer的PID
Found := Process32Next(sHandle, Pn); //查找下一个
end;
//嗯,父进程不是Explorer,是调试器……
if ParentProc <> ExplProc then
begin
TerminateProcess(H, 0); //杀之!除之而后快耶! :)
//你还可以加上其它什么死机代码来消遣消遣这位可爱的Cracker :)
end;
end;
你可以在Delphi或者VC中试试,呵呵,是不是把Delphi和VC杀掉了,因为你现在用的是Delphi和VC的内置调试器来运行你的程序的,当然它会六亲不认了,呵呵!调试的时候你还是把它注释掉吧,发布时别忘记激活哟!
最后一个问题,这也是一个非常重要的问题:保护你的字符串!!!字符串在注册模块中非常重要!当一个富有经验的Cracker破解你的软件时,首先做的就是摄取你的字符串。比如他会输入错误的注册码,得到你关于错误注册码的提示,通常是“无效的注册码,请重新输入!”或者“Invalid key, please input again!”等等,然后用OllyDbg下断点调试或者用WinDASM、IDA Pro等静态分析工具在被他脱壳后的程序中查找那个字符串,找到后进行分析。因此,请一定加密你的字符串!!!一定!!! 使用时再临时解密出来,而且要尽量少使用消息提示框 ,避免被Cracker找到漏洞。加密字符串不需要太复杂的算法,随便找一个快速的对称算法就可以了。
最后提醒你一句,不要在加密上花太多的功夫!你应该把更多的时间和精力都用来完善你的软件,这样会更合算。借用一位前辈的话来忠告大家吧:花点时间考虑你自己的软件,看看它是否值得保护?如果没人用你的软件,保护也就没有意义了,不要过高估计你的软件“对世界的重要性”!
【本文由“本公众号”发布,2018年7月20日】
写作不易,求关注
看了对你有帮助就赞赏一个呗