最近分析了C……t(非国产)软件的注册验证算法,发现它的方法简单,未用加壳、反调试、反反汇编等手段,但似乎无法破解。希望能在这里跟各位高手探讨一下。

和很多共享软件一样,这款软件也是在用户输入正确的用户名/注册码后,才解除试用版的限制。

由于汇编代码很长很难读,这里就以图代话了。验证程序的核心是一个叫 Blowfish 的对称加密器(加密解密使用同一个密钥,加密后的数据和明文长度相同)。图中用圆圈表示这个加密器,上下端的箭头表示密钥,左面输入明文,右面输出密文。



用户名和注册码分别经过两个简单的散列(hash)函数,产生2字节的用户名散列值,和18字节的注册码散列值。

将用户名散列值作密钥,对注册码散列值的高16位字节进行加密,密文(图中蓝色)作为后面要用的密钥。

注册码散列值低2位必须在0-0A00h之间,否则说明注册码错误。用这个值作位移量,在一个事先硬编码的表中取出一个16字节码(图中绿色部分),再用上面得出的密钥(蓝色)对这个码进行两次加密,产生出的16字节码就是最后解密的密钥。

程序中负责解除时间限制、激活注册版的程序代码以加密方式存在,解密的密钥就是上面产生出的16字节码。解密过程包括两次解密,为了确保解密无误,在第一次解密后,要将解密后数据中的几个特定字节与正确值比较,如果有错,图中红色部分就不执行,直接报告注册码错误。如果通过验证,就进行第二步解密(红色部分),用解密结果改写原来加密的程序代码,并且跳转到那里执行,完成软件激活。

个人认为这种方法几乎无法攻破。用改变跳转的方法不行,因为最终完成注册的程序代码是加了密的,没有正确的密钥就无法还原和运行该段程序。用穷举法破解也不现实,因为密钥有16字节(128位)。此外这种方法多次加密所用的密钥都不相关,很难推算出它们之间的关系,无法写出注册机。破解的唯一方法只能是通过研究整个程序,找到激活的方法,然后自己构造一个功能类似原来程序中的激活程序。

如果真是这样,软件保护似乎变得很简单,破解的人也就无技可施了。这里所用的 Blowfish 加密软件是很简单的开源软件,可以方便地加到要保护的程序里。分析的是否正确,还请各位高人指正。

  • 标 题:答复
  • 作 者:sessiondiy
  • 时 间:2008-05-12 12:07

随便输入一组注册码    得到一HASH值(需符合规则,低2byte需介于0-0A00)  <=  HASH_1 (18 Byte)
所以 此时硬编码对照到的16Byte已固定.
HASH_1(高16byte) 也固定住

因为用户名的HASH只用2个byte而己. 
此用户名HASH由0给他跑到FFFF. 所以应该只要跑 65536 种吧.

  • 标 题:答复
  • 作 者:sessiondiy
  • 时 间:2008-05-12 12:24

若他可根据用户名称而给你注册码的话, 则 

1. 注册码 -> 18byte的HASH 应该不是外面公开的那些 (那些公开的都无法预测)
  亦即他无法预测该用第几组硬编码. (低2byte无法预测)

2. 高16byte无法预测
  所以最上面那个圈圈出来的东西他更是无法预测, 不可能光靠 2720 项硬编表

所以最上面那个圈圈很有可能不是用OpenSource的HASH

  • 标 题:答复
  • 作 者:kingdomer
  • 时 间:2008-05-12 23:56

感谢朋友们参与。

回复3、4楼:

这种保护手段的“门锁”,实际就是指向红圈的那个16字节密钥。

软件作者可以这样构造根据用户名生成注册码的程序:
1. 选定“门锁”,一个16字节的密钥,设它为 M。
2. 随机选 2720 个不同的 16 字节数,保存于一数组 R 中。
3. 用 R[i](i=0, ..., 2719)作密钥,对 M 进行两次解密,结果存于一数组中,设它为 H。这个数组就是放在软件中的硬编码表。
4. 有人来注册,先用他的用户名 hash 出一个2字节数,设为 N。
5. 随机取一小于 2720 的数,设其为 SL。以 N 为密钥,对 R[SL] 进行解码,得到的结果设为 SH。
6. 将 SH 作高16字节,SL 作低2字节,构造出18位的注册码散列值 S。
7. 将 S 进行反 hash,得到注册码,发给用户。本软件所用的 hash 函数不过是把0-9,A-F这几个字符转换成别的值而已。如果不对注册码进行变换,直接把 S 给客户就行。

破解者不知道 M,即使知道上面的步骤也找不到能产生 M 的用户名 N 和注册号 S。

回复6楼:

要正确解码那371字节,估计密钥是唯一的。即使有一错误密钥,能使解密的数据通过红圈左面的验证也没用,因为它只是验证那371字节中的前几个字节,后面解得不对,程序很可能会崩溃。