〖软件名称〗极品私人密盘Build 050915
〖运行平台〗XP
〖下载地址〗http://www.sharebank.com.cn/soft/soft_view.php?id=12934
〖软件功能〗在硬盘上建立一个密盘,大小可以调整,将私人需要保密的文件存入密盘。当密盘关闭时,程序会自动将密盘中的文件加密,无密码者无法对密盘进行访问,杀毒程序也无法访问,方便又安全。有了密盘你的HGame和武藤兰就不会给你带来麻烦咯!呵呵。
〖破解目标〗该软件此前已被暴破过但不彻底,双击密盘时仍然有注册界面跳出。目标找出算法,写注册机。
〖破解声明〗业余爱好,无商业企图。

破解过程:

一、第一次亲密接触:
软件无壳,编程语言Borland Delphi 6.0 - 7.0
软件主界面上方Title显示“极品私人密盘Build 050915(未注册)”字样。
如果不注册,可以试用30次,试用次数达到25次开始提示剩余的次数,达到30次就不给用了,卸载重安装也不能继续试用。
注册与硬盘序列号有关,一机一码。
注册码错误不报错,重启校验。


二、关于试用次数:
用注册表工具比对运行前后发现——HKEY_LOCAL_MACHINE\software\class\.panz这个键值里放的是试用次数。
试用次数满了之后,我改过这个键值,又可以继续试用了,至于有无其他影响就不知道了,反正破解的目标不是“继续试用”。


三、填写注册码后的部分:
工具:OD
1、OD载入,运行程序。
2、打开注册界面,有两个编辑框“机器码”和“注册码”,两个按钮“确定”“返回”。
3、填入87878787,回OD,暂停,显示窗口(W图标),找到输入注册码对话框的控件“确定”,设置WM_LBUTTONUP消息断点。
注:刚开始学习还不知道更好的断点方法,因为该软件不for 98,所以TRW搞不了,hmemcpy也就用不上;曾看过一篇文章,是说明Delphi写的程序,对GetDlgItemTextA之类的断点都免疫的原因,这次也不例外,断不下来。最后决定用WM_LBUTTONUP。
4、继续,设置好断点,运行,回到输入注册码对话框点确定,程序断下,跟踪一段回到程序领空(过程冗长省略)。
5、分析代码(摘录)
004AA79D   .  E8 2ABCFAFF   call    004563CC------------------取机器码"WD-WMAJ71258689"
004AA7A2   .  837D F4 00    cmp     dword ptr [ebp-C], 0------比较是否为空
004AA7A6   .  74 17         je      short 004AA7BF------------是就跳死
004AA7A8   .  8D55 F0       lea     edx, [ebp-10]
004AA7AB   .  8B45 FC       mov     eax, [ebp-4]
004AA7AE   .  8B80 FC020000 mov     eax, [eax+2FC]
004AA7B4   .  E8 13BCFAFF   call    004563CC------------------取试码"87878787"
004AA7B9   .  837D F0 00    cmp     dword ptr [ebp-10], 0-----是否为空
004AA7BD   .  75 14         jnz     short 004AA7D3------------不跳就死
004AA7BF   >  B8 78A94A00   mov     eax, 004AA978
004AA7C4   .  E8 2770F8FF   call    004317F0
004AA7C9   .  E8 5E98F5FF   call    0040402C
004AA7CE   .  E9 56010000   jmp     004AA929
004AA7D3   >  8D45 F8       lea     eax, [ebp-8]--------------跳转到这里
004AA7D6   .  50            push    eax
004AA7D7   .  8D55 EC       lea     edx, [ebp-14]
004AA7DA   .  8B45 FC       mov     eax, [ebp-4]
004AA7DD   .  8B80 FC020000 mov     eax, [eax+2FC]
004AA7E3   .  E8 E4BBFAFF   call    004563CC
004AA7E8   .  8B45 EC       mov     eax, [ebp-14]-------------试码放入EAX
004AA7EB   .  B9 06000000   mov     ecx, 6
004AA7F0   .  BA 01000000   mov     edx, 1
004AA7F5   .  E8 6AA2F5FF   call    00404A64------------------取试码前6位
004AA7FA   .  33C0          xor     eax, eax
004AA7FC   .  55            push    ebp
004AA7FD   .  68 BAA84A00   push    004AA8BA
004AA802   .  64:FF30       push    dword ptr fs:[eax]
004AA805   .  64:8920       mov     fs:[eax], esp
004AA808   .  8B45 F8       mov     eax, [ebp-8]---------------前6位放入EAX
004AA80B   .  E8 B8E3F5FF   call    00408BC8-------------------前6位通过算法一得出一个临时数放入EAX
004AA810   .  B9 03000000   mov     ecx, 3
004AA815   .  99            cdq
004AA816   .  F7F9          idiv    ecx------------------------EAX中的数除3取商
004AA818   .  8D55 E8       lea     edx, [ebp-18]
004AA81B   .  E8 6CE2F5FF   call    00408A8C-------------------EAX中的数通过算法二换算成一个“变形码”
004AA820   .  8B45 E8       mov     eax, [ebp-18]
004AA823   .  E8 74FCFFFF   call    004AA49C-------------------将变形码通过算法三转换成一个12位字串与"66FFMJRXJELR"比较
004AA828   .  84C0          test    al, al
004AA82A      74 62         je      short 004AA88E

看到这里,有必要把算法一和算法二做一下交代:

算法一:
基数    乘数  对应位数  得数
0     *  A   +   8   =   8  --------将得数作为下一次的基数
8     *  A   +   7   =   57
57    *  A   +   8   =   36E
36E   *  A   +   7   =   2253
2253  *  A   +   8   =   15746
15746 *  A   +   7   =   D68C3------这个临时数在4AA816时被除以3,EAX的值成为47841
算法一在004AA80B行 call 00408BC8----代码冗长,不贴出来了。

算法二:
基数   被除数    商   余数
47841 /  A   =  726C   9------------将商作为下一次的基数
726C  /  A   =  B71    2
B71   /  A   =  124    9
124   /  A   =  1D     2
1D    /  A   =  2      9
2     /  A   =  0      2------------"292929"就是我的试码前6位转换成的变形码
算法二在004AA81B行 call 00408A8C----代码冗长,不贴了。

至于算法三就是把变形码的每一位取出来通过两次运算,得出两个字符,然后连在一起就成了12位的字符串。
"292929"得出的字符串是"77JJFCTZGBRX",显然和"66FFMJRXJELR"不同,接下来就是al=0,判断之后跳走,程序弹出MessageBox"感谢您的注册,请重启本软件"。
由4AA823处的call跟进,至4AA4E0处,该处的call 404804里就是算法三,有兴趣的朋友可以跟进去看一下。

当然重启后依然是未注册版本,但是既然看懂了代码,那么就逆推出正确的前6位吧。

算法三逆推:
"66FFMJRXJELR"逆推出的变形码是"159753"

算法二逆推:
基数   乘数   变形码 得数
0    *  A   +   1  =  1
1    *  A   +   5  =  F
F    *  A   +   9  =  9F
9F   *  A   +   7  =  63D
63D  *  A   +   5  =  3E67
3E67 *  A   +   3  =  27009---------27009*3=7501B这个就是正确的临时数

算法一逆推:
基数   被除数    商   余数
7501B /  A   =  BB35   9
BB35  /  A   =  12B8   5
12B8  /  A   =  1DF    2
1DF   /  A   =  2F     9
2F    /  A   =  4      7
4     /  A   =  0      4------------"479259"就是注册码正确的前6位

用"47925987878787"这个假码试一次。
当004AA823处的 call 004AA49C比较过两个12位字符串之后,如果相同,程序在system32下的driveset.dll写入如下内容:
[edia]
t=25
zcm=47925987878787
jqm=WD-WMAJ71258689
呵呵 假码和机器码都写在这里备用了。
接下来,程序弹出MessageBox“感谢您的注册,请重启本软件”。

既然前6位是固定的,而且机器码也没有用到,那就不可能这么简单啦,果然重启后依然是未注册版本。还好我有预见性,一点都没有失望,欲将剩勇追穷寇!


四、重启校验部分

OD加载后程序停在4B56B4
这次我用的断点是bpx GetSystemDirectoryA,改断点有两处4B2294和4B25F9
F9运行,OD断下,一路F8步过,可以看到程序取得了路径"d:\windows\system32"和文件"driveset.dll"

接下来的代码摘录如下:
004B2331   .  B9 442A4B00   mov     ecx, 004B2A44                ;  ASCII "zcm"
004B2336   .  BA 502A4B00   mov     edx, 004B2A50                ;  ASCII "edia"
004B233B   .  8B30          mov     esi, [eax]
004B233D   .  FF16          call    [esi]                        ;取得机器码"WD-WMAJ71258689"
004B233F   .  6A 00         push    0
004B2341   .  8D45 A4       lea     eax, [ebp-5C]
004B2344   .  50            push    eax
004B2345   .  8B45 FC       mov     eax, [ebp-4]
004B2348   .  8B80 AC040000 mov     eax, [eax+4AC]
004B234E   .  B9 602A4B00   mov     ecx, 004B2A60                ;  ASCII "jqm"
004B2353   .  BA 502A4B00   mov     edx, 004B2A50                ;  ASCII "edia"
004B2358   .  8B30          mov     esi, [eax]
004B235A   .  FF16          call    [esi]                        ;取得试验码"47925987878787"
......
004B23B3   .  8BC8          mov     ecx, eax                     ;ECX=实验码长度
004B23B5   .  83E9 0A       sub     ecx, 0A
004B23B8   .  BA 0B000000   mov     edx, 0B
......
004B2402   .  8B80 A4040000 mov     eax, [eax+4A4]               ;实验码7-10位"8787"
004B2408   .  E8 BB67F5FF   call    00408BC8                     ;和前面的算法一一样,计算出一个临时数
004B240D   .  B9 03000000   mov     ecx, 3
004B2412   .  99            cdq
004B2413   .  F7F9          idiv    ecx                          ;临时数字除3
004B2415   .  8D55 9C       lea     edx, [ebp-64]
004B2418   .  E8 6F66F5FF   call    00408A8C                     ;转换出一个变形码
004B241D   .  8B45 9C       mov     eax, [ebp-64]
004B2420   .  E8 E7EAFFFF   call    004B0F0C                     ;不同的是这里,只验证中间四位是否为整型数字
004B2425   .  84C0          test    al, al
004B2427   >  837D D4 1D    cmp     dword ptr [ebp-2C], 1D
004B242B   .  0F8E 9D000000 jle     004B24CE                     ;跳死
004B2431   .  8B45 FC       mov     eax, [ebp-4]
004B2434   .  8B80 A0040000 mov     eax, [eax+4A0]               ;再一次取前6位
004B243A   .  E8 8967F5FF   call    00408BC8                     ;算法一,计算临时数字
004B243F   .  B9 03000000   mov     ecx, 3
004B2444   .  99            cdq
004B2445   .  F7F9          idiv    ecx                          ;临时数除3
004B2447   .  8D55 98       lea     edx, [ebp-68]
004B244A   .  E8 3D66F5FF   call    00408A8C                     ;计算变形码
004B244F   .  8B45 98       mov     eax, [ebp-68]
004B2452   .  E8 DDE7FFFF   call    004B0C34                     ;比较字串"66FFMJRXJELR"
004B2457   .  84C0          test    al, al
004B2459   .  74 73         je      short 004B24CE
004B245B   .  8D55 94       lea     edx, [ebp-6C]
004B245E   .  8B45 FC       mov     eax, [ebp-4]
004B2461   .  8B80 60040000 mov     eax, [eax+460]               ;EAX=机器码"WD-WMAJ71258689"终于用到了
004B2467   .  E8 78E6FFFF   call    004B0AE4                     ;机器码变形
004B246C   .  8B45 94       mov     eax, [ebp-6C]
004B246F   .  8B55 FC       mov     edx, [ebp-4]
004B2472   .  8B92 A8040000 mov     edx, [edx+4A8]
004B2478   .  E8 D324F5FF   call    00404950                     ;实验码第11位开始到最后与机器变形码比较
004B247D   .  74 36         je      short 004B24B5

关于7-10位的计算方法完全和前6位一样,但是却没有用到计算出来的值,我很迷惑,4B2420处的处理是检验这四位是否为数字,如果是字母、符号或者其他什么就报错,并且判定注册失败。有兴趣的朋友请跟进去看一看,如果不是这样请一定跟贴告诉我,谢谢。

4B2467处的CALL是对机器码进行了变形处理,由于代码冗长而且算法平淡,就不详述了。
方法是将机器码每一位的ASCII加1:例如我的机器吗"WD-WMAJ71258689"会成为这样——"XE.XNBK8236979:",然后把这个变形码中的1、3、5、7这四数字替代掉:
1------I
3------M
5------Q
7------N
我机器码的最后形态为"XE.XNBK82M69N9:"

五、最后总结:

注册码的组成分三个部分:
前6位(固定) 中4位(数字) 后N位
479259        0000          XE.XNBK82M69N9:

1、填写注册码后,程序对前六位进行验算,如果正确,就把这个注册码和机器码一起写入文件driveset.dll
2、验算中间四位是否为数字
3、后N位与变形机器码进行比较,相同就注册成功。

另:由于注册码分段校验,爆破的难度自然也就大了,这个软件已经出新版本了,注册码的计算方法也进行了改进,不过有趣的是如果注册了build 050915版后再安装新版本,新版本也承认我是注册用户。

这是第二篇破文,谢谢关注。