Articles

TextPad 4.7.3序列号算法分析

用朴素的语言分析了该软件序列号的算法,不涉及到具体代码,人人都可以看懂。

几个月以前下载的一个软件,从名字就可以看出来它是一个文本编辑器。 个人感觉看起来要比UltraEdit-32顺眼得多,功能上也还凑合,可惜当时我一直没找到序列号,所以只能试用。 近来闲着无聊,决定自己写一个算号器。下面我就详细分析一下这个软件序列号的算法。

Content: 下面的内容基本不涉及程序的代码,那些反汇编出来的东西,写出来了也没几个人看,所以我只讲算法。 首先我给出一个正确序列号的模样,给大家一个整体的印象:

BEGIN LICENSE
lionel
nku
59 9999CHJXXLK3X6Z01ZPYZXW
4B5E3405 A8DA500D 904F2655 C7EDBB2B E0D91457 93B78BF4
95B3FC43 2A56BDA5 A09C9F3F 2FB5A165 00F73C72 27FFEE20
E0D91457 93B78BF4 95B3FC43 2A56BDA5 E0D91457 93B78BF4
95B3FC43 2A56BDA5 D536376A 0025D966 4C03D12F 8507E6E1
END LICENSE

看起来挺恐怖的吧!呵呵,其中BEGIN LICENSE与END LICENSE是必须的,不能变。 第二行 lionel 就是注册的用户名,最大长度45字节,我们记作:

char name[45] = "lionel";

第三行 nku就是注册的单位,最大长度同样是45字节,我们记作:

char company[45] = "nku";

第三行刚开始两个字符 59,必须是数字,而且两个字符不能相等,而且也不能等于 90。我们把这两个字符记作:

char s2[2] = "59";

紧接着是 9999,这个表示最大用户的数量,如果是9999则为unlimited,即没有使用人数限制,最小应该为 1,不过我没有验证过。我们把它记为:

char max_users[4] = "9999";

在接下来是CHJXXLK3X6Z01ZPYZXW,总共19位,这19位中不能有大写英文字母”O”,也许是容易被看作 0的缘故。其实这19位只有前16位比较重要,我们把这前16位记作:

char sn[16] = "CHJXXLK3X6Z01ZPY";

再接下来的 4行,每行有 6个字符串,每个字符串有 8个字符。而且所有的字符中只有0-9,A-F,所以很明显每一个字符串就代表一个 DWORD,32位,总共有24组数据,也就是96个字节。我们把它们记作:

char CT[96];

我们再仔细分析一下:

struct
{
  char name[45];
  char company[45];
  char s2[2];
  char max_user[4];
} PT;

上面这个结构长度也刚好是96个字节,这不是巧合,呵呵,因为 CT就是通过 PT算出来的。而用的加密算法就是 Twofish。Twofish每次只能加密 128-bit,也就是 16 字节,所以需要将这 96 字节的 PT 分为 6组,分别加密。下面我们再分析一下 Twofish中所使用的密钥是什么:

sn[16] = "CHJXXLK3X6Z01ZPY";

总共16字节,每一个字节 8-bit,总共 128-bit,这刚好就是 Twofish所支持的最短的密钥长度。所以:

CT = twofish_encrypt(sn, PT);

怎么样?简单吧?利用上面我所说到的这些你写出来的算号器应该 99.9%正确,那剩下的那0.1%呢?那部分就是我分析失误的地方啦!你看我说才说了不到 100行,但我分析却整整分析了 2天,再加上研究 Twofish算法的时间,差不多 5天了。所以有一些细节的东西我就没太仔细看。令我郁闷的是我写完算号器,休息的时候竟然在网上找到了 ORiON的注册机,不过这个注册机算出来的号没我的多!哈哈。他的这个算号器里,

s2[2] = "51"

是不变的,而且序列号都是英文,不知道为什么。我用我的算号器试了一下,序列号是数字也没问题,可能是他们为了方便吧,毕竟有一个能用的序列号就可以了。而且人家写的算号器界面特漂亮,不像我只会写console的… 如果哪位好心人能给我一个 VC的完全用 API写的界面比较漂亮的 keygen模版,我将不胜感激!哈哈。