摘 要:软件安全是信息安全领域的重要内容,其中软件保护是关乎知识产权的一项重要工作,市场上虽然有大量现成的方案可选用,如基于软件的加密壳保护和基于硬件的加密锁保护,但这些优秀的保护方案由于太流行,造成大家对其研究太透彻,反而容易被破解。所以有必要实现相关的保护方法。
关键词:软件保护;注册码生成器;破解;算法
软件保护的目的是向正式注册用户提供完整的功能,所以软件保护必然要包括验证用户合法性的环节,而这一环节通常采用注册码验证的方式实现。
(1)使用者向软件开发方发送用户码U,要求注册。
(2)由软件开发方发出经过运算得到注册码R=f(U)。
(3)用户在软件注册界面输入U和R。
(4)软件通过检验函数F(U,R)来检测用户的合法性。
其中一些常用术语说明如下:
用户码U:用户身份ID。
注册码R:用于验证用户是否合法。
注册码生成器:把R=f(u)中的f称为注册码生成器算法,注册生成器算法可以针对任何用户码计算出一一对应的注册码。
检验函数:把F(U,R)称为检验函数,软件使用检验函数检验注册码是否合法,也就是只有R=f(u)成立时,F(U,R)才是合法的。
算法求逆:把破解者通过检验函数F推导注册码生成器算法的过程称为算法求逆。
1 堡垒战术
人们早就在各个领域开始研究身份检验的问题了,并研究开发出了散列加密和非对称加密等早已被人们认可的密码学算法,但真正适用于软件注册这一场合的算法恐怕只有MD5和RSA算法了。
MD5算法通常不能直接用来对消息进行加密,因为这种算法没有逆向算法,所以加密之后不能解密,这种加密是没有实用意义的,MD5算法的用途在于数字签名。例如张和李进行通信,张只将明文A加密为B传送给李是不够安全的,因为即使密文B的加密强度再高也只能防止在传输过程中被解密而泄露内容,却不能防止破坏者直接篡改密文B。李收到B后解密得到A,也无法判断A中内容的可靠性与安全性。所以张在发送B的同时通常会在A之后签名,然后计算一个校验码C=MD5(A),将B、C一起发送给李,李收到B、C后,首先解密B得到A,然后同样计算校验码C=MD5(A),若计算出的校验码与收到的校验码相同,则可判定A真实可靠。
同样的原因导致不能把MD5算法直接用做注册码生成器,假如使用R=MD5(U)做注册码生成器,因为MD5本身没有反函数,检验函数就必须包含注册码生成器。但是用以下办法间接使用MD5算法就可以:
(1)设注册码生成器为R=f(U)。
(2)设MD5(a)=b。
(3)令检验函数F为:F(U,R)=MD5[f-1(R)-U+a]
显然F的合法值应为b,只要U,R满足R=f(U),F一定等于b。因为MD5没有逆操作,破解者不能经由b知道f-1(R)-U+a应该等于a,也就不可能得到f-1的明确定义,更不会得到注册码生成器f。至于f-1(R)-U+a表达式中虽然含有a,但解密者无法判断a和f-1的关系。
实际上利用MD5算法构造F可以有很多方法,让企图破解者根本看不出F和f、f-1的关系,就更不用说去找逆运算了。但MD5算法的弱点是,由于MD5没有逆操作,所以a必须为常数,一旦破解者知道了一对可用的U、R,它们就可能追踪到可用的a、b值,从而知道f-1,并由此推测出注册码生成器f。
相比于MD5,RSA算法在软件保护中应用就要简单的多了:
(1)软件作者使用:R=Ud mod n作为注册码生成器。
(2)软件使用:U=Re mod n作为检验函数。
由于算法的复杂性,破解者是不可能知道d,也就无法破解注册码生成器。可以说利用RSA算法保护软件就是建造了一座坚固的堡垒,但是由于RSA算法是一种公开算法,所以利用RSA算法来进行软件保护也存在着一些问题。
(1)大多数的使用者对RSA算法的细节并不了解,这就为因为错误使用RSA埋下了隐患。例如,在不同的软件作品中,使用同样的参数导致莫名的异常攻击。
(2)有些函数本身的不完善性也会导致防线的崩溃,例如,在产生随机数时,会有当初始条件相同时,产生完全相同的随机数结果。破解者如果了解到这一点,就可以依据n值推断原始数据产生过程,RSA的防线也就岌岌可危了。
(3)函数库在产生随机素数时,应当淘汰那些容易被猜到的素数,否则会导致RSA算法中存在若干由各种特殊素数构造成的“弱密钥”,这样带来的后果就是当破解者稍有数论基础,就很容易攻破RSA。
2 游击战术
软件保护中的游击战术就是将检验函数F拆分成多个相异的Fi,然后将这些Fi的不规则的随机分布到程序的各个位置上。
经过这样的处理之后,通过任何一个Fi的验证都只是合法注册的必要非充分条件,而只有真正合法的注册码才能够通过所有的Fi的验证。解密者如果知道只找到Fi其中的一个部分,只要有任何一个Fi没找到,它就不能了解F的全体细节,也就不能算法求逆。
可能你会有疑问,如何将F分解成相异的并且是必要非充分的的Fi?这就需要比较扎实的数学功底了。
(1)将R切分成多段Ri。
(2)构造不同的f算法,使得:Ri=fi(U)。
(3)令Fi=fi-1。
这种看似繁琐的操作,是很有實际意义的。例如可以让F1使用X算法,F2使用Y算法,F3使用Z算法,这里的X、Y、Z可以MD5、RSA等成熟算法,也可以是用户自定义的算法。用户注册时程序只选择其中一个Fi进行验证,这里还要注意,注册码在传输过程中一定要使用自定义的文件格式进行封装,通过F1的验证即给用户注册成功的提示。但这时其实并没有给用户完整的软件使用权限,因为程序中的F2和F3只有使用者执行特定的操作时才被调用,例如,在用户使用某些高级功能的时候将封装的注册码再次使用F2和F3验证。如果发现任何一个Fi结果非法,就把软件恢复为非法使用状态。
对于软件保护这种新兴技术,其实应该多站在破解者的角度考虑,这样才能合理利用已有的知识库来解决不断出现的新问题,没有哪种解决方案是可以一成不变的解决过去与未来的所有问题。
参考文献
[1]Eldad Eliam. Secret of Reverse Engineering[M].Wiley,2005.
[2]看雪学院.软件加密技术内幕[M].北京:电子工业出版社,2004.
[3]段钢.加密与解密[M].北京:电子工业出版社,2013.
[4]谭明金.黑客反汇编揭秘[M].北京:电子工业出版社,2010.
作者简介:郁诺(1977-),男,上海崇明人,西安财经学院高职学院,工程师。