• 标 题: 逆向Microsoft.Windows.Server.2003.x64.Edition.VOL.Keymaker.Only-ZWT
  • 作 者:ylp1332
  • 时 间:2007-02-21 14:04
    附 件: http://bbs.pediy.com/attachment.php?attachmentid=4513
  • 链 接:http://bbs.pediy.com/showthread.php?t=39892

【原创】逆向Microsoft.Windows.Server.2003.x64.Edition.VOL.FIXED.Keymaker.Only-ZWT

一直以来对Windows的注册算法很感兴趣,谁叫它那么有名呢,呵呵。不过并不是一开始就选
择ZWT的这个keygen作为逆向的目标的。我最早见到的windows keygen是由YAG在2004年发布的
Microsoft.Windows.XP.2003.Enterprise.Server.Keygen-YAG,在该包中包含有2个keygen和
一份文档。这两个keygen在网上流行很广,不过由于它是基于OpenSSL的大数库开发,而我又
对那个库不熟,所以一直也没什么想法。倒是那份文档,让我对windows的注册算法有了初步
认识,使我总想自己动手实现这套算法。后来见到ZWT的这个keygen:
Microsoft.Windows.Server.2003.x64.Edition.VOL.FIXED.Keymaker.Only-ZWT。拿它动手有
三个原因:它没有加壳,它是用Visual C++开发的,它使用的是miracl大数库。

写作本文的主要目的,其实是为了介绍实现算法的过程,算法才是重点,而不是逆向。为什么
呢?因为我觉得仅仅通过逆向一个keygen而找到算法的正确实现太难了,我就深受折磨。只有
结合相关文档资料理解算法,再通过逆向和动态跟踪调试来验证才能正确实现算法。所以逆向
在我所做的工作中其实只是小部分,含有算法的学习和理解,以及动态跟踪和调试。

所有的这些工作都是去年暑假完成的,现在才有时间给整理出来。

1、关于Windows注册和验证算法
请参考以下三篇文档:
MSKey4in1 Read Me.doc
Microsoft的25位CDKey里有什么.TXT
恢复原版XP.TXT
网上有下载,附件中也有。
文档中算法描述基本都是对的,不过也有一些很明显的错误,需要自己多注意。

2、逆向ZWT的keygen
IDA加载,载入miracl.sig。
IDA基本不能识别miracl的API调用,但在string窗口中可以看到很多熟悉的字符串,可断定
确实使用了miracl库。推测是采用c++ wrapper的方式调用miracl库函数。
采用BlackEye提出的方法手动识别主要的miracl函数。
由于附件中提供了源码,这里不再给出反汇编分析的结果。
对照文档和汇编代码可整理出算法的流程,并写出主要的C++代码。

3、实现keyGenerator和KeyVerifier
在逆向的基础上进一步细化,可得到我们自己的keyGenerator。
为了验证所逆向的keygen的正确性,同时还写了一个KeyVerifier,以实现验证算法。
从文档中就可以看出来,ECC算法的验证算法比注册(签名)算法更容易实现。因而开发一个
KeyVerifier既是必要的,也是可行的。

附件中的代码使用c++ wrapper的方式调用miracl库函数。用c++ wrapper方式能够发挥c++语
言的优点,使得代码更加精炼,也更不容易出错。同时也方便将自己写的keyGenerator的反
汇编代码与逆向分析得到的结果进行对比分析。

调试注意事项:
求解二次方程所用到的函数sqroot()或sqrt(),其失败的几率是相当高的,必须要对其返回的
结果进行分析。这个地方让我多花了一整天的时间。

附件中包含了本文所用到的文档和相关的源代码。
所有资料均来自于Internet,请勿用于非法用途,否则后果自负!


在逆向ZWT的keygen的过程中,也顺便找到其中3处错误:

.text:0040285D                 call    _rand
.text:00402862                 cdq
.text:00402863                 mov     ecx, 400
.text:00402868                 idiv    ecx             ; rand()%400
.text:0040286A                 push    0

错误1:调用伪随机数生成函数rand()之前没有调用srand()初始化随机数种子。以致每次运
行keygen时rand()返回相同的随机数序列:0x29,0x4823,...
错误2:这里对随机数取400的模。但我在别的地方看到的是取0x400的模。
错误3:每生成一个key都调用一次irand((unsigned)time(NULL)),使得随机数与时间紧密相
关,随机性很差。

这些错误在附件代码中已经得到更正。

附件中的代码也好像有问题,就是用ZWT的keygen生成的部分key可能通不过验证,我调试了
半天也没有找到原因,只好暂时先搁置,看哪天灵感来了再搞定它。