菜鸟看懂算法以后之二___几点其它收获
作者:jney2
日期:14:26 2005-4-26

一、研究64位的除法函数汇编代码时,我在精华收藏版中搜索该算法的特征码“D1D2”,发现完整列出并分析该算法汇编代码的文章有8篇:
1、超级电脑伴侣 V1.12  
2、新概念英语句霸 2    
3、《网络警察》V2.4    
4、英语会话精灵        
5、家庭银行家 v2b53   
6、商舟@广告直邮群发大师2002 
7、极速传真[SpeedFax] 2.4 
8、HomeBankerV2.0 b53 

估计在算法中使用该函数的程序应是数不胜数。而这几篇文章都没觉察得这只不过是日常中简单的除法,均以“转换”、“左移”等字眼带过,当然我也是花了相当的时间才搞清楚。
所以,弄清楚除法函数就显得蛮重要了!

二、注册算法也“盗版”
中华压缩10.8的注册算法与家庭银行家 v2b53的注册算法除了被除数不同外,其它一模一样。中华压缩:0x33FAB9386=13953110918 (作者的手机?这可是重要的隐私哦!),家庭银行家 v2b53:0x25CC7BC0D36=2597511236918
关于算法:在家庭银行家 v2b53 注册机(MASM32)中,发信人:lq7972 写到:
【总结】
这个软件还是耍了蛮多把戏的
注册算法
1. 注册用户名的长度在(3~25)间
2. 从注册用户名最末向前取,计算出一个中间值,然后把它转为元素是十进制值的整数数组;有两个值要注意:0xC7BC0D36、0x0000025C
3. 利用第2步中的结果计算真正的注册码,这个码长须为12位,计算结果若小了就在前面补0,若超过了12位,取前面12个字符

在中华压缩10.8中,baby2008写到:
【算法总结】:
算法比较简单,怪不得很多教程都以它的前期版本为教程,注册算法是:
1、用户名Name要求:  3<用户名长度<25
2、Name后面开始取字符,
3、用常数$33FAB9386 / Name[i] 的ASCII 取余数,并转换成10进制字符串 
4、连接上述的10进制字符串,记为Serail
5、取Name[i]字符到<用户名长度-6结束
6、将Serail转换成int64,并以12位16进制字符串输出,如果长度超过12位,截取12后的所有字符即为注册码。

看来天下程序一大抄呀!

三、指出这几篇文章中的几个错误,免得比我还菜的菜鸟看了误入岐途:
1、在《超级电脑伴侣 V1.12算法流程,另有问题请教大家! 》中   发信人:PowerBoy
00405985  |. B9 40000000    MOV ECX,40 
0040598A  |. 57            PUSH EDI 
0040598B  |. 31FF          XOR EDI,EDI 
0040598D  |. 31F6          XOR ESI,ESI            //循环计算64次 
0040598F  |> D1E0          /SHL EAX,1            //EAX=EAX SHL 1 
00405991  |. D1D2          |RCL EDX,1            //EDX=EDX RCL 1 
00405993  |. D1D6          |RCL ESI,1            //ESI=ESI RCL 1  
00405995  |. D1D7          |RCL EDI,1            //EDI=EDI RCL 1 
00405997  |. 39EF          |CMP EDI,EBP          //EBP=28363 
00405999  |. 72 0B          |JB SHORT 1.004059A6 
0040599B  |. 77 04          |JA SHORT 1.004059A1 
0040599D  |. 39DE          |CMP ESI,EBX 
0040599F  |. 72 05          |JB SHORT 1.004059A6 
004059A1  |> 29DE          |SUB ESI,EBX          //ESI=ESI-EBX 
004059A3  |. 19EF          |SBB EDI,EBP 
004059A5  |. 40            |INC EAX 
004059A6  |>^E2 E7          \LOOPD SHORT 1.0040598F//EBX作为循环的标志         **********
004059A8  |. 89F0          MOV EAX,ESI            //EAX=ESI 

 更正:EBX在此处不是作为循环的标志,ECX才是循环的计数器,LOOPD循环指令是与ECX配合使用的;

2、在《商舟@广告直邮群发大师2002》中, 发信人:fly
##############################################
呵呵,看看TRW犯的“小错误”!^-^
?EAX
DEC=-1717838278
HEX=999BDE3A

##############################################

更正:TRW是没有犯“小错误”的,是fly把本应是四字的数据截成了双字,HEX=999BDE3A如果按32位算,它的最高位为1,就应该是负整数,所以这不是TRW犯的“小错误”。


3、在《商舟@广告直邮群发大师2002》中, 发信人:fly
:0050DDBB 6945EC851A0000          imul eax, dword ptr [ebp-14], 00001A85               ********
                                 ====>EAX=1A85

更正:这条指令的解释是:EAX=1A85×dword ptr [ebp-14]。所以dword ptr [ebp-14]也是参数,只不过调试时dword ptr [ebp-14]的值刚好为1罢了。


4、在《商舟@广告直邮群发大师2002》中, 发信人:fly

【总       结】:


程序对自给的44030620021284410进行运算得出999BDE3A,            ********
999BDE3A-我的硬盘序列号-自给的1A85=758EA8AF。                  ********

758EA8AF算术左移64次=456C93E
456C93E+1=456C93F  —— 这就是真码的16进制值!


奇怪了!难道每次都要重新注册?

更正:44030620021284410换算成十六进制就是:0x9C6D9D999BDE3A,这才是完整的64位整数。

由于我找不到原软件,只能推测算法:(44030620021284410-硬盘序列号-参数A×6789)/参数B=注册码 (均是十进制)


5、在《英语会话精灵 2.0 --谨以此文献给初学破解的爱好者》中,发信人:youth[chat001]


0040916B  |> 51            /PUSH ECX 
0040916C  |. 6A 00          |PUSH 0 
0040916E  |. 51            |PUSH ECX 
0040916F  |. 8B03          |MOV EAX,DWORD PTR DS:[EBX]        ;/初始值为:(UserNo-0x1f6171f)*0x1b,见0047A083-0047A08B 
00409171  |. 8B53 04        |MOV EDX,DWORD PTR DS:[EBX+4]      ;\ 
00409174  |. E8 DCD5FFFF    |CALL untopbar.00406755 
00409179  |. 59            |POP ECX 
0040917A  |. 92            |XCHG EAX,EDX 
0040917B  |. 80C2 30        |ADD DL,30 
0040917E  |. 80FA 3A        |CMP DL,3A  
00409181  |. 72 03          |JB SHORT untopbar.00409186 
00409183  |. 80C2 07        |ADD DL,7  
00409186  |> 4E            |DEC ESI 
00409187  |. 8816          |MOV BYTE PTR DS:[ESI],DL  
00409189  |. 51            |PUSH ECX 
0040918A  |. 6A 00          |PUSH 0 
0040918C  |. 51            |PUSH ECX 
0040918D  |. 8B03          |MOV EAX,DWORD PTR DS:[EBX]  
0040918F  |. 8B53 04        |MOV EDX,DWORD PTR DS:[EBX+4] 
00409192  |. E8 C9D4FFFF    |CALL untopbar.00406660 
00409197  |. 59            |POP ECX 
00409198  |. 8903          |MOV DWORD PTR DS:[EBX],EAX 
0040919A  |. 8953 04        |MOV DWORD PTR DS:[EBX+4],EDX 
0040919D  |. 09D0          |OR EAX,EDX 
0040919F  |.^75 CA          \JNZ SHORT untopbar.0040916B 

=VV==<<由00409174调用>>==VV=============================================================== 
(此过程很简单,就是将16进制转化为10进制后输出)                                                ***********
00406755  /$ 55            PUSH EBP 
00406756  |. 53            PUSH EBX 
00406757  |. 56            PUSH ESI 
00406758  |. 57            PUSH EDI 
00406759  |. 8B5C24 14      MOV EBX,DWORD PTR SS:[ESP+14] 
0040675D  |. 8B4C24 18      MOV ECX,DWORD PTR SS:[ESP+18] 
00406761  |. 0BC9          OR ECX,ECX 
00406763  |. 75 08          JNZ SHORT untopbar.0040676D 
00406765  |. 0BD2          OR EDX,EDX 
00406767  |. 74 33          JE SHORT untopbar.0040679C 
00406769  |. 0BDB          OR EBX,EBX 
0040676B  |. 74 2F          JE SHORT untopbar.0040679C 
0040676D  |> 8BE9          MOV EBP,ECX 
0040676F  |. B9 40000000    MOV ECX,40 
00406774  |. 33FF          XOR EDI,EDI 
00406776  |. 33F6          XOR ESI,ESI 
00406778  |> D1E0          /SHL EAX,1 
0040677A  |. D1D2          |RCL EDX,1 
0040677C  |. D1D6          |RCL ESI,1 
0040677E  


更正:这篇文章的算法是对的,因为它可以根据CALL的值逆推,此处的注释却是错的,因为此处除法函数,真正的16进制转化为10进制函数应该是CALL untopbar.00406660。

备注:1、标有*号的是错误的地方,这几个错误均是因为研究除法函数才发现的。我因为受其中的误导而浪费了不少功夫。所以特地指出来,其它的错误我可就管不着罗!

      2、jney2提示:看本文前,请你看一下第一篇:菜鸟看懂算法以后之一__头痛的64次左移。

本文完。