[转帖] Windows产品激活技术内幕 [转帖] Windows产品激活技术内幕
Windows产品激活技术内幕
1.导言 当今公开广泛讨论的Windows产品激活技术(WPA),表现出不确定性和投机性。在这篇文章里,我们公开一些微软很早以前就应该公开的,并应用在Windows XP上的产品激活技术的细节。
我们强烈地认为每一个软件出版商,都有权利利用技术手段去增强对在许可期间正常使用软件的管理,我们也相信每个软件使用者都有权知道软件出版商使用的技术细节以及软件在使用过程中可能存在的局限性。 在这篇文章里,我们回答一些公认为关于Windows产品激活核技术的最重要的问题:
在激活过程中,究竟传送了什么信息? 当硬件配置发生变化的时候,对已经激活过的Windows XP系统有影响吗? 这些问题的答案,是基于Windows XP Release Candidate 1 (build 2505)?版本的,后面的版本,包括正式版Windows XP可能和这个版本有点不同。例如在使用的某些加密密匙或者某些数据结构方面。 无论如何,除了这些细微的变化之外,我们预期微软将会坚持使用一般的激活机制结构。因此,我们确信这篇文章所提供的答案,对于正式版的Windows XP仍然是有帮助的。 这篇文章提供一些关于WPA内部运行机制的深入技术细节。但是,在某些重要地方,我们还是描述得比较模糊,目的是为了让攻击者不会很容易地绕过激活机制。
2.安装ID的内幕 我们把焦点放在通过电话激活产品这个方法上,这样做的原因,是我们预期这个不同的激活方法,能够更直接地去分析Windows产品激活技术。 安装程序会引导用户完成整个激活过程。激活Windows XP的第一步就是通过电话把msoobe.exe生成的安装ID提供给客户服务中心。 安装ID是一组50个十进制数字组成,并分开成6个小组,例如: 002666-077894-484890-114573-XXXXXX-XXXXXX-XXXXXX-XXXXXX-XX 在这个真实的安装ID里,我们用X代替不想公开的数字。 msoobe.exe在每次运行时都会提供不同的安装ID. 作为回应,客户服务中心将会返回一个相对应于你提供的安装ID的确定ID,当你输入了正确的确定ID后,就完成了激活过程。 因为安装ID是一串在激活过程中出现的信息,这对于寻找上面关于在激活过程中传送信息的问题的答案有着相当的意义。
安装ID是怎样生成的?
为了找到问题的答案,我们找出每个安装ID的来源
2.1检验数字 每组最右的数字是一个检验数字,是为了防止一些简单的错误。例如在报告客户服务中心安装ID时出现的拼写错误。该检验位的值是同组五个数字的和,再次加上偶数位置的数字,除以7后得到的余数。在上面的例子里,第一组的检验数字(6)是这样计算得到的:
1 | 2 | 3 | 4 | 5 <-位置 ---+---+---+---+-- 0 | 0 | 2 | 6 | 6 <-数字
0 + 0 + 2 + 6 + 6 = 14 (第一步:将所有数字相加) 0 + 6 + 14 = 20 (第二步:再加上偶数数字) 20 / 7 = 2, 余数是 20 - (2 * 7) = 6 => 检验位是 6(第三步:除法) 将偶数位相加两次的目的是为了防止在输入过程中位置调换这一相对经常发生的错误。例如:00626写成00266,这将会产生不同的检验位。
2.2解码 除去检验码,就会得到一组41个的十进制数字。一个十进制数的长度一般来说相等于136bit的二进制数。实际上,这41个十进制数字就是由一个136bit的高精度二进制整数编码所得,并按照高字节序排成一个字节队列储存。因此,上面的安装ID也可以表示为下面的一系列长度为17字节的十六进制数字:
0xXX 0xXX 0xXX 0xXX 0xXX 0xXX 0xXX 0xXX 0x94 0xAA 0x46 0xD6 0x0F 0xBD 0x2C 0xC8 0x00 这上面的安装ID中,字符‘X’取代了我们不想显示的数字,前缀‘0x’表示十六进制。
2.3译码 当对任意安装ID进行解码时,可以发现最高有效字节通常是0x00 或者 0x01,其它部分的字节看起来好像是随机的。原因是低16位字节是经过加密的,而最高有效字节是明文。 对安装ID进行加密的密码算法,是一个专利的四轮Feistel密码算法。当数字序列输入到Feistel密码算法,被分为平均的两份,这种密码算法非常典型,它把偶数位的数字作为输入信息块(在这个情况中使用17位输入字节的低16位)。这一轮的密码运算是输入信息块与一个4字节序列进行SHA-1信息-摘要运算。 让+代表两个位组序列的联接,^为异或运算,L和R分别是第一轮输入的数字序列的左8字节和右8字节,L' 和R'是上述第一轮算法的结果的左8字节和右8字节。First-8()是一个返回SHA-1信息-摘要运算结果前8个字节的函数。则第一轮译码运算就如下: L' = R ^ First-8(SHA-1(L + Key)) R' = L 将16字节明文译码得到的结果,与17字节未译码的序列放在一起。从现在开始理解为将四个长度为双字的数按照低字节序对每个字节进行排序。如下: 名称 | 大小 | 偏移地址 -------+---------+------------ H1 |double word | 0 H2 |double word | 4 P1 |double word | 8 P2 |double word | 12 P3 | byte | 16 H1和H2规定为与安装ID有关的硬件配置。P1和P2以及P3包含了产品ID与安装ID的关联。
2.4产品ID 产品ID是由五组十进制数组成,如下: AAAAA-BBB-CCCCCCC-DDEEE 如果你用“ProductID”搜索注册表,你会发现一个与安装有关的ID。在Windows的IE浏览器里关于选项里,你也可以找到你的产品ID。
2.4.1解码 产品ID的十进制表示和二进制编码P1、P2(双字)、P3(字)之间的映射,可以总结成以下表格: 数字 | 长度 | 编码 -----+---------+--------------------------------------- AAAAA | 17 bits | bit 0 to bit 16 of P1 BBB | 10 bits | bit 17 to bit 26 of P1 CCCCCCC | 28 bits | bit 27 to bit 31 of P1 (低 5 bits) | | bit 0 to bit 22 of P2 (高 23 bits) DDEEE | 17 bits | bit 23 to bit 31 of P2 (低 9 bits) | | bit 0 to bit 7 of P3 (高 8 bits) 每组数字所代表的意义如下表: 数字 | 意义 ---------+------------------------------------------------- AAAAA | 产品编号,在这里通常为 55034 (Windows XP RC1) BBB | 初级产品序列号的最高有效三位数字 | (见下文) CCCCCCC |初级产品序列号的最低有效六位数字以及 | 校验数位的和 (见下文) DD | 用来验证产品序列号的公开密匙索引 | (见下文) EEE | 任意值 由此可见,初级产品序列号对于生成产品ID起了一个很重要的作用。
2.4.2产品序列号 初级产品序列号隐藏在印在标签上的,用来区分每份Windows XP产品的产品序列号里。产品序列号由五组被“-”分隔开,由字母数字混合编制的字符串组成,每组字符串是由五个字符组成,如下: FFFFF-GGGGG-HHHHH-JJJJJ-KKKKK
每个字符是取自于以下24个字母及数字之中的一个: B C D F G H J K M P Q R T V W X Y 2 3 4 6 7 8 9 和用十进制编码的安装ID很相似,这25个字符的产品序列号是由二进制表示产品序列号用base-24进行编码得到的。将产品ID译码,一般来说将会生成一个115bits的高精度二进制整数,同时按低字节序被储存为一个长度为15字节的十六进制数字序列中。将上面的产品序列号译码,就可以得到下面的数字序列:
0x6F 0xFA 0x95 0x45 0xFC 0x75 0xB5 0x52 0xBB 0xEF 0xB1 0x17 0xDA 0xCD 0x00
在这15字节的最低有效的四个字节里,包含有按低字节序排列的初级产品序列号。最低有效位是与这个32-bit值(0x4595FA6F –按低字节序排列储存)左移一位所得到的值是无关的,这就得到最初产品序列号0x22CAFD37,或者:583728439(用十进制表示)。 来自数字签名的剩余的17字节,允许通过使用一个硬编码公开密匙验证产品序列号的真实性。
2.4.3产品序列号 ->产品ID 三个最高有效位数字,例如:583,是九位初级产品序列号的十进制表示在产品ID中的在上面描述的BBB部分的直接映射。 为了获得CCCCCCC部分,将一个校验数位附加到剩余的六个数字728439中。校验数位是这样计算得到的:将所有数位相加,包含一个检验数位,可以被七整除。这上面的例子里,六个数位的和是 7 + 2 + 8 + 4 + 3 + 9 = 33 所以检验数位为2,因为 7 + 2 + 8 + 4 + 3 + 9 + 2 = 33 + 2 = 35 所得到的结果35可被七整除。所以产品ID中的CCCCCCC部分的结果为7284392。 为了可以验证一个产品序列号,使用多于一个的公开密匙是有必要的。如果第一个公开验证密匙失败了,第二个仍然是可靠的。产品ID中的DD部分,规定为可以成功验证产品序列号的公开密匙。 这个机制目的是为了可以让使用不同的个人私有序列号生成不同的有效的产品序列号。 然而,不同的私有序列号,可以代表不同版本的产品,一个“professional” release版的产品序列号,与一个'server' release版的产品序列号,会有所不同。DD部分就是代表产品的不同版本。 最后,从我们的范例产品序列号,我们可以得到一个有效的产品ID: 55034-583-7284392-00123 这表示第一个公开密匙(DD =索引= 0)与EEE的随机数字123是相配的。 随机选择的部分EEE是取决于msoobe.exe运行时所产生的不同的安装ID.。因为这少少的改变,经过适当的加密后,将会得到完全不同的安装ID。 所以,在激活过程中传送的产品ID的最后三位,可能会和你在IE或者在注册表中看到的产品ID是不同的。
2.5硬件信息 对于上面的讨论,硬件配置是与产品ID中的双字长的数H1和H2相关的。
2.5.1比特块 为了实现这个目的,将这个两字数分成12个比特块。电脑硬件和比特块之间的关系如下表:
双字 | 偏移 | 长度 | 比特块值所代表的意义 ---------+--------+-------+------------------------------ H1 | 0 | 10 | 盘卷序列号字符串 H1 | 10 | 10 | 网卡MAC地址字符串 H1 | 20 | 7 | CD-ROM 驱动器标识字符串 H1 | 27 | 5 | 显示卡标识字符串 H2 | 0 | 3 | 未使用,值设为 001 H2 | 3 | 6 | CPU 序列号字符串 H2 | 9 | 7 | 硬盘标识字符串 H2 | 16 | 5 | SCSI适配卡标识字符串 H2 | 21 | 4 | IDE 控制器标识字符串 H2 | 25 | 3 | 处理器型号字符串 H2 | 28 | 3 | 内存的大小 H2 | 31 | 1 | 1 =支持功能扩展底座 0 = 不支持功能扩展底座 H1中的第31bit定义为笔记本电脑是否支持功能扩展底座。如果系统支持功能扩展底座,激活机制将会放宽对硬件数量改变的限制。这里的意思是当笔记本电脑被插入到功能扩展底座后,将会导致其硬件配置发生变化。例如:功能扩展底座内建的SCSI适配器将会运行。 H2中的0bit到2bit是未用的,通常设为001。 如果系统中的硬件与这十个比特块相对应,那么相应的比特块描述该硬件的值不为0。如果某个比特块的值为0,那么该比特块所对应的硬件不存在。 所有的硬件都是由从注册表得到硬件标识字符串去识别。对这些字符串进行Hash算法后的值,就是该硬件相对应的比特块的值。
2.5.2Hash算法 Hash算法的结果是将硬件标识字符串经过MD5信息摘要算法运算后,再从预先决定的位置上按照比特块的需要对运算结果中的特定位进行选取得到的。不同的预先决定位置是用于不用的比特块。此外,Hash结果为0的,将不会用作运算。 Hash = (Hash % BitFieldMax) + 1 在这里,BitFieldMax是所涉及的比特块所能储存的最大值,例如:一个长度为10bit的比特块所能储存的最大值为1023。“x % y”代表x除于y的余数。这个结果的值是处于1到BitFieldMax之间。这里所得到的值就被储存到相应的比特块中。
2.5.3内存比特块 操作系统中可用内存与其相对应比特块的值的算法是与其它比特块是不同的。这里用七个有效值规定可用内存近似值,如下表:
有效值 | 可用的内存数量 ---------+--------------------------- 0 | (比特块未用) 1 | 32 MB以下 2 | 介于32 MB和63 MB之间 3 | 介于64 MB和127 MB之间 4 | 介于128 MB和255 MB之间 5 | 介于256 MB和511 MB之间 6 | 介于 512 MB和1023 MB之间 7 | 1023 MB以上 一个非常值得注意的地方就是通过调用GlobalMemoryStatus()函数返回的系统可用内存数目是比实际系统安装的内存数目要少几百K字节的。所以128MB内存被分类到“介于64MB和127MB之间”。
2.5.4一个真实的例子 让我们看一个真实的例子。在我们的一台测试系统上,硬件信息由下面的8个字节组成: 0xC5 0x95 0x12 0xAC 0x01 0x6E 0x2C 0x32 将这些字节转换成H1和H2,我们可以得到: H1 = 0xAC1295C5 and H2 = 0x322C6E01 将H1和H2的值分开,生成下面这个表,并把相应比特块的值和原来的值填入。 偏移 | Hash值| 原来的值 -------+-------+----------------------------------------------- H1 0 | 0x1C5 | -ABCD' H1 10 | 0x0A5 | ༼C0DF089E44' H1 20 | 0x37 | 'SCSI\CDROMPLEXTOR_CD-ROM_PX-32TS__1.01' H1 27 | 0x15 | 'PCI\VEN_102B&DEV_0519&SUBSYS_00000000&REV_01' H2 0 | 0x1 | (未使用,通常为0x1) H2 3 | 0x00 | (找不到CPU的序列号) H2 9 | 0x37 | 'SCSI\DISKIBM_____DCAS-34330______S65A' H2 16 | 0x0C | 'PCI\VEN_9004&DEV_7178&SUBSYS_00000000&REV_03' H2 21 | 0x1 | 'PCI\VEN_8086&DEV_7111&SUBSYS_00000000&REV_01' H2 25 | 0x1 | 'GenuineIntel Family 6 Model 3' H2 28 | 0x3 | (系统有128 MB内存) H2 31 | 0x0 | (支持功能扩展底座)
3. 硬件变化 在一个已经被激活的Windows XP里,当硬件发生变化时,'system32'里的文件'wpa.dbl'起了一个最重要的作用。在经过RC4简单加密的数据库里储存了一些信息,其中包括有终止使用信息和激活安装系统的确认ID。 a)比特块的值代表了当前系统的硬件配置。 b)比特块的值代表了产品激活时的硬件配置。 当硬件配置发生改变时,a)将会自动更新去反映硬件配置的变化,但b)仍然是不变的。因此,b)可以认为是产品激活时候硬件配置的快照。 这个快照在产品未激活之前,在数据库中是不存在的。如果我们对照一下产品激活前后'wpa.dbl'这个文件的大小,就会发现文件变大了,这是因为硬件配置快照被记录到数据库中。 当要判定产品是否需要重激活的时候,只需要比较a)和b)中比特块的值。也就是比较当前硬件配置和产品激活时候的硬件配置。 3.1不支持功能扩展底座的电脑 特别地,系统会用除了没有使用的比特块和'dockable'比特块之外的十个比特块进行比较。当十个比特块中,有超过三个比特块于系统激活后在a)中发生变化时,需要进行产品重激活。这就意味着,例如,在上面的真实例子里,我们可以替换硬盘,CD-ROM以及充分升级内存,而不需要重新激活我们的Windows XP。然而,如果我们完全重新安装Windows XP,储存在b)中的信息会丢失,我们将要重新激活我们的系统,尽管硬件并没有发生变化。
3.2 支持功能扩展底座的电脑 如果H2中的31bit表明我们的电脑支持功能扩展底座。无论如何,在十个比特块中,只有七个被用作比较。比特块中相对应的SCSI适配器,IDE控制器和显示卡会被排除在外。但是,在这剩下的七个比特块中,只有三个或三个以下的比特块在a)中发生变化时,系统不需要进行重新激活。
4. 结论 在这篇文章里,我们给出了一个关于Windows XP产品激活技术的概述。同时展示了在产品激活过程中传送的信息以及当硬件升级时对已激活系统的影响。 总观WPA技术的细节,我们认为不存在某些人所预期的问题。这样认为的原因是WPA技术相对于硬件改变是存在着一定的宽限度。另外,可能多于一个的硬件配件映射到一个给定比特块的特定值。从上面真实的例子我们可以知道PX-32TS经过映射后,得到的值为0x37 = 55。但是同时又有可能存在其它CD-ROM光驱的映射值与该值是一样的。因此,不可能从比特块中的值推算出我们正在使用的设备是否为PX-32TS 与许多对Windows产品激活技术批评相反,我们认为Windows产品激活技术并不对硬件更换产生影响。此外,还考虑到了使用者的正当私隐。
本文由龙卷风Artex翻译,如要转贴,请注明翻译者及出处.本人英文水平有限(5.99级)如有错漏的地方,敬请指出!如此文早已被人翻译,请告知! |