首页
社区
课程
招聘
[旧帖] [转帖]先知起名大师 2009 超强版破解及算法分析 0.00雪花
发表于: 2009-8-6 14:58 5729

[旧帖] [转帖]先知起名大师 2009 超强版破解及算法分析 0.00雪花

2009-8-6 14:58
5729
萧萧黄叶大牛的文章 非常好的分析 附注册机源码 大家一起学习一下 高亮处理了一下

【破文标题】先知起名大师 2009 超强版破解及算法分析
【破文作者】萧萧黄叶
【作者邮箱】
【作者主页】
【破解工具】OllyICE,PEiD v0.94,C32Asm
【破解平台】WinXP
【软件名称】先知起名大师 2009 超强版
【软件大小】2703KB
【原版下载】http://www.newhua.com/soft/79200.htm
【保护方式】
【软件简介】名字影响性格,能力,人缘,最终影响命运。
好的合适的名字给孩子一个自信,光明的未来。
给孩子起个好名字是父母最基本最重要的责任。
《先知起名大师 2009》是目前市场上最简单易用,最快速,而又免费试用的起名软件。
软件运行后,用户输入父母的姓名,出生年份,小孩的性别,出生日期后几分钟即可得到小孩的最佳中

文名和最佳英文名。
起名是免费的!
用户如果注册成为正式版,就可以知道为什么要起这个名,起这个名有什么好处,这个名字为什么最适

合。

本软件是先知计算机智能工作室的年度巨献,各方专家倾力合作,集成了中国古代名著的智慧,包括《

易经》,《论语》,《尔雅》,《说文解字》等著作,必将给您惊喜!

【破解声明】高手请飘过~~~
------------------------------------------------------------------------
【破解过程】安装好了程序运行看看,使用说明中说“注册的好处是能看到名字背后蕴含的意义”,寻

就注册一下了。
任意码注册,确定:“注册码长度不对,请仔细核对!”
先用PEiD v0.94探壳:什么都没找到  *
好像没有加壳。
再用C32Asm分析汇编了,查看字符串,没有相关的内容,再使用Unicode分析字符串,找到了几个:
004054F5  PUSH 41142C                                 \->: 注册成功!谢谢!祝你好运!

004054EA  PUSH 411448                                 \->: 注册码长度不对,请仔细核对

0040550B  PUSH 411414                                 \->: 注册失败!请仔细核对

这些正是我们需要的,用OllyICE载入吧,在上面地址的附近下断。
这里是程序入口处:
0040CEAA > $  6A 74         PUSH 74
0040CEAC   .  68 F8304100   PUSH SuperNam.004130F8
0040CEB1   .  E8 CE040000   CALL SuperNam.0040D384

F9运行程序,用123456789注册看看,断在这里了:
00405460   .  6A FF         PUSH -1
00405462   .  68 82DF4000   PUSH SuperNam.0040DF82                   ;  SE 处理程序安装
00405467   .  64:A1 0000000>MOV EAX,DWORD PTR FS:[0]

F8单步向下走:
004054A2   .  E8 F1790000   CALL <JMP.&MFC71U.#3756>
004054A7   .  8B4C24 08     MOV ECX,DWORD PTR SS:[ESP+8]             ;  经过上面的CALL之后

,我们的假码出现在堆栈中,将被移送到ECX上。
004054AB   .  51            PUSH ECX
004054AC   .  8D4C24 10     LEA ECX,DWORD PTR SS:[ESP+10]
004054B0   .  FF15 34004100 CALL DWORD PTR DS:[<&ApolloPlan.HString:>;  

ApolloPl.HString::HString
004054B6   .  8D4C24 0C     LEA ECX,DWORD PTR SS:[ESP+C]
004054BA   .  C64424 38 01  MOV BYTE PTR SS:[ESP+38],1
004054BF   .  FF15 CC004100 CALL DWORD PTR DS:[<&ApolloPlan.HString:>;  

ApolloPl.HString::empty
004054C5   .  84C0          TEST AL,AL
004054C7   .  74 09         JE SHORT SuperNam.004054D2               ;  这里是判断有没有填

写注册码,如果没有就不跳,然后下面就JMP了。
004054C9   .  53            PUSH EBX
004054CA   .  53            PUSH EBX
004054CB   .  68 64144100   PUSH SuperNam.00411464
004054D0   .  EB 3E         JMP SHORT SuperNam.00405510
004054D2   >  8D5424 0C     LEA EDX,DWORD PTR SS:[ESP+C]
004054D6   .  52            PUSH EDX
004054D7   .  E8 84360000   CALL SuperNam.00408B60
004054DC   .  8BC8          MOV ECX,EAX                              ; |
004054DE   .  E8 5D3A0000   CALL SuperNam.00408F40                   ; \SuperNam.00408F40
004054E3   .  83F8 FF       CMP EAX,-1
004054E6   .  53            PUSH EBX
004054E7   .  53            PUSH EBX
004054E8   .  75 07         JNZ SHORT SuperNam.004054F1              ;  很明显要注册成功就

必须要跳,不跳就是注册码长度不对!所以上面的CALL是关键了
004054EA   .  68 48144100   PUSH SuperNam.00411448                   ;  注册码长度不对,请

仔细核对

004054EF   .  EB 1F         JMP SHORT SuperNam.00405510
004054F1   >  3BC3          CMP EAX,EBX
004054F3      75 16         JNZ SHORT SuperNam.0040550B              ;  很明显要注册成功就

不能跳,一跳就死!所以上面的CALL是关键了
004054F5   .  68 2C144100   PUSH SuperNam.0041142C                   ;  注册成功!谢谢!祝

你好运!

004054FA   .  E8 9F790000   CALL <JMP.&MFC71U.#1118>
004054FF   .  8B06          MOV EAX,DWORD PTR DS:[ESI]
00405501   .  8BCE          MOV ECX,ESI
00405503   .  FF90 54010000 CALL DWORD PTR DS:[EAX+154]
00405509   .  EB 0A         JMP SHORT SuperNam.00405515
0040550B   >  68 14144100   PUSH SuperNam.00411414                   ;   注册失败!请仔细核



00405510   >  E8 89790000   CALL <JMP.&MFC71U.#1118>
00405515   >  8D4C24 0C     LEA ECX,DWORD PTR SS:[ESP+C]

重新来一次,要着重分析004054DE   .  E8 5D3A0000   CALL SuperNam.00408F40                  

; \SuperNam.00408F40
先看看到底要多少位的注册码才行,
004054E3   .  83F8 FF       CMP EAX,-1这一句提示要使下面的JNZ跳转成功,EAX就不能等于-1,也

就是FFFFFFFF。
跟进关键CALL
00408F40  /$  6A FF         PUSH -1
00408F42  |.  68 91E54000   PUSH SuperNam.0040E591                   ;  SE 处理程序安装
00408F47  |.  64:A1 0000000>MOV EAX,DWORD PTR FS:[0]

向下单步到:
00408FB7  |.  57            PUSH EDI                                 ; /Arg1
00408FB8  |.  8D4C24 28     LEA ECX,DWORD PTR SS:[ESP+28]            ; |
00408FBC  |.  E8 8F040000   CALL SuperNam.00409450                   ; \SuperNam.00409450
00408FC1  |.  8BD8          MOV EBX,EAX
00408FC3  |.  85DB          TEST EBX,EBX
00408FC5      0F85 C6000000 JNZ SuperNam.00409091                    ;  走到这里时跳转了,

中间忽略了一大片,很是可疑,是EBX决定的,EBX的值是上面的CALL计算出来的,想不让它跳就跟进上

面的CALL看看。
00408FCB  |.  8D4C24 48     LEA ECX,DWORD PTR SS:[ESP+48]

再来一次跟进00408FBC的CALL SuperNam.00409450
00409450  /$  6A FF         PUSH -1
00409452  |.  68 3BE64000   PUSH SuperNam.0040E63B                   ;  SE 处理程序安装
00409457  |.  64:A1 0000000>MOV EAX,DWORD PTR FS:[0]

继续单步:
00409507  |.  894424 10     MOV DWORD PTR SS:[ESP+10],EAX
0040950B  |.  FFD3          CALL EBX                                 ;  这个CALL计算出了假

码的位数。现在为9。
0040950D  |.  8B4C24 10     MOV ECX,DWORD PTR SS:[ESP+10]            ;  将一个为24的数移到

ECX
00409511  |.  3BC1          CMP EAX,ECX
00409513      0F85 22010000 JNZ SuperNam.0040963B                    ;  两者相比,不相等就

跳走。所以24就是注册码的长度,要注册成功首先得注册码的位数为&H24。继续重新来过。
00409519  |.  6A 00         PUSH 0

再来一次,用24(十六进制)位字符注册,还到上面的地儿,这一次不跳转了,继续单步:
00409519  |.  6A 00         PUSH 0
0040951B  |.  8BCF          MOV ECX,EDI
0040951D  |.  FFD3          CALL EBX
0040951F  |.  50            PUSH EAX
00409520  |.  57            PUSH EDI
00409521  |.  8D8C24 A00000>LEA ECX,DWORD PTR SS:[ESP+A0]
00409528  |.  FF15 4C014100 CALL DWORD PTR DS:[<&ApolloPlan.HString:>;  

ApolloPl.HString::compare_first_n
0040952E  |.  85C0          TEST EAX,EAX
00409530      0F85 EA000000 JNZ SuperNam.00409620                    ;  这里又跳走了,结合

上面的经验分析,应该是上面某个CALL又进行了一次注册码真假的判断,使EAX没有等于00000000,所以

就跳走了。
00409536  |.  8B55 00       MOV EDX,DWORD PTR SS:[EBP]

继续再来,这一次要跟进00409528的CALL DWORD PTR DS:[<&ApolloPlan.HString:>:
10022C00 >  8A4424 0C       MOV AL,BYTE PTR SS:[ESP+C]
10022C04    84C0            TEST AL,AL
10022C06    8B4424 04       MOV EAX,DWORD PTR SS:[ESP+4]

继续单步:
10022C54    3BF2            CMP ESI,EDX
10022C56    72 05           JB SHORT ApolloPl.10022C5D
10022C58    8B40 08         MOV EAX,DWORD PTR DS:[EAX+8]
10022C5B    EB 03           JMP SHORT ApolloPl.10022C60
10022C5D    83C0 08         ADD EAX,8
10022C60    3951 1C         CMP DWORD PTR DS:[ECX+1C],EDX            ; 在这里注意一下EAX出

现了字符“QM”
10022C63    72 17           JB SHORT ApolloPl.10022C7C
10022C65    8B5424 0C       MOV EDX,DWORD PTR SS:[ESP+C]
10022C69    8B49 08         MOV ECX,DWORD PTR DS:[ECX+8]             ; 将假码也请出来了,放

ECX上。
10022C6C    52              PUSH EDX
10022C6D    50              PUSH EAX
10022C6E    51              PUSH ECX                                 ; EAX和ECX的东东都将进

入下面的CALL进行某一种动作。当然要跟进了。
10022C6F    FF15 EC340510   CALL DWORD PTR DS:[<&MSVCR71._wcsnicmp>] ; MSVCR71._wcsnicmp
10022C75    83C4 0C         ADD ESP,0C

跟进10022C6F的CALL DWORD PTR DS:[<&MSVCR71._wcsnicmp>]:
7C36FCBB >  55              PUSH EBP
7C36FCBC    8BEC            MOV EBP,ESP
7C36FCBE    51              PUSH ECX

继续单步:
7C36FCE6   /75 48           JNZ SHORT MSVCR71.7C36FD30
7C36FCE8   |8B55 0C         MOV EDX,DWORD PTR SS:[EBP+C]             ; 将“QM”移到EDX。
7C36FCEB   |8B4D 08         MOV ECX,DWORD PTR SS:[EBP+8]             ; 将假码移到ECX
7C36FCEE   |33C0            XOR EAX,EAX                              ; EAX清零。
7C36FCF0   |66:8B01         MOV AX,WORD PTR DS:[ECX]                 ; 取假码第一位,现在为

1,ASCII码为31。
7C36FCF3   |66:3D 4100      CMP AX,41
7C36FCF7   |72 09           JB SHORT MSVCR71.7C36FD02
7C36FCF9   |66:3D 5A00      CMP AX,5A
7C36FCFD   |77 03           JA SHORT MSVCR71.7C36FD02
7C36FCFF   |83C0 20         ADD EAX,20
7C36FD02   |8945 FC         MOV DWORD PTR SS:[EBP-4],EAX             ; 由于31没有41大,故而

跳转到这里。并将31存放到堆栈 SS:[0012DFF4]=00B699D8中。
7C36FD05   |33C0            XOR EAX,EAX                              ; 再次将EAX清零。
7C36FD07   |66:8B02         MOV AX,WORD PTR DS:[EDX]                 ; 取“QM”的第一位Q的

ASCII码,51,放到AX上。
7C36FD0A   |66:3D 4100      CMP AX,41
7C36FD0E   |72 09           JB SHORT MSVCR71.7C36FD19
7C36FD10   |66:3D 5A00      CMP AX,5A
7C36FD14   |77 03           JA SHORT MSVCR71.7C36FD19
7C36FD16   |83C0 20         ADD EAX,20                               ; EAX=EAX+20=51+20=71


7C36FD19   |41              INC ECX
7C36FD1A   |41              INC ECX
7C36FD1B   |42              INC EDX
7C36FD1C   |42              INC EDX
7C36FD1D   |FF4D 10         DEC DWORD PTR SS:[EBP+10]
7C36FD20   |74 4A           JE SHORT MSVCR71.7C36FD6C
7C36FD22   |66:397D FC      CMP WORD PTR SS:[EBP-4],DI
7C36FD26   |74 44           JE SHORT MSVCR71.7C36FD6C
7C36FD28   |66:3945 FC      CMP WORD PTR SS:[EBP-4],AX               ; 刚才的两个ASCII码进

行比较,相等则返回继续比较,不相等则下面的JE不跳,不规则下面就JMP了。
7C36FD2C  ^|74 C0           JE SHORT MSVCR71.7C36FCEE                ; 所以这里一定要跳。所

以注册码的前两位一定要为“QM”。QM正是“起名”两个字的第一个汉语拼音字母。应该是了!
7C36FD2E   |EB 3C           JMP SHORT MSVCR71.7C36FD6C

下面再来一次,假码的第一、二位为“QM”,还走到上面,这一次由7C36FD20   /74 4A           JE

SHORT MSVCR71.7C36FD6C

跳到了这里7C36FD6C    0FB77D FC       MOVZX EDI,WORD PTR SS:[EBP-4]

走到返回处时EAX=00000000
这一次
00409530     /0F85 EA000000 JNZ SuperNam.00409620                    ;  

没有跳转,继续单步,下面很多的CALL,而且我们已经知道这里很可能就是算法的中心,所以只好先一

个个的跟进看看了。
下面这个CALL跟进后发现很可疑:
0040954E  |.  FF15 48014100 CALL DWORD PTR DS:[<&ApolloPlan.HString:>;  

ApolloPl.HString::substr

跟进:
10022B20 >  6A FF           PUSH -1
10022B22    68 C2E40410     PUSH ApolloPl.1004E4C2
10022B27    64:A1 00000000  MOV EAX,DWORD PTR FS:[0]

10022B59    8B7424 34       MOV ESI,DWORD PTR SS:[ESP+34]            ; 取出了假码的第三位到

第十位,看看用来干嘛!
10022B5D    50              PUSH EAX
10022B5E    8BCE            MOV ECX,ESI

继续下一个CALL
跟进0040956C CALL SuperNam.00409290

00409290  /$  6A FF         PUSH -1
00409292  |.  68 E4E54000   PUSH SuperNam.0040E5E4                   ;  SE 处理程序安装
00409297  |.  64:A1 0000000>MOV EAX,DWORD PTR FS:[0]

走到下面这个CALL时问题已经明了,可能是用来进行了MD5的加密算法
004092F2  |.  FF15 18014100 CALL DWORD PTR DS:[<&ApolloPlan.HIEUtil:>;  

ApolloPl.HIEUtil::MD5::MD5

跟进:
100477A0 >  56              PUSH ESI
100477A1    6A 58           PUSH 58
100477A3    8BF1            MOV ESI,ECX
100477A5    E8 292E0000     CALL ApolloPl.1004A5D3
100477AA    50              PUSH EAX
100477AB    8906            MOV DWORD PTR DS:[ESI],EAX
100477AD    E8 1E0A0000     CALL ApolloPl.100481D0
100477B2    83C4 08         ADD ESP,8
100477B5    8BC6            MOV EAX,ESI
100477B7    5E              POP ESI
100477B8    C3              RETN

再跟进100477AD的CALL ApolloPl.100481D0:

100481D0    8B4424 04       MOV EAX,DWORD PTR SS:[ESP+4]
100481D4    C740 04 0000000>MOV DWORD PTR DS:[EAX+4],0
100481DB    C700 00000000   MOV DWORD PTR DS:[EAX],0
100481E1    C740 08 0123456>MOV DWORD PTR DS:[EAX+8],67452301
100481E8    C740 0C 89ABCDE>MOV DWORD PTR DS:[EAX+C],EFCDAB89
100481EF    C740 10 FEDCBA9>MOV DWORD PTR DS:[EAX+10],98BADCFE
100481F6    C740 14 7654321>MOV DWORD PTR DS:[EAX+14],10325476
100481FD    C3              RETN

至此应该能够基本认为是用注册假码的第三位到第十位进行了MD5的加密计算,下面就应该能看到结果了

,我们何妨先计算出来看看符不符合。
34567890 MD5加密后 3AAD95D46A1CE1D2D1DD0CDB347604D9

继续单步:
跟进00409348  |.  FF15 0C014100 CALL DWORD PTR DS:[<&ApolloPlan.HIEUtil:>;  

ApolloPl.HIEUtil::MD5::getDigest

10047810 >  8B4424 04       MOV EAX,DWORD PTR SS:[ESP+4]
10047814    83C1 04         ADD ECX,4
10047817    8B11            MOV EDX,DWORD PTR DS:[ECX]
10047819    8910            MOV DWORD PTR DS:[EAX],EDX
1004781B    8B51 04         MOV EDX,DWORD PTR DS:[ECX+4]
1004781E    8950 04         MOV DWORD PTR DS:[EAX+4],EDX
10047821    8B51 08         MOV EDX,DWORD PTR DS:[ECX+8]
10047824    8950 08         MOV DWORD PTR DS:[EAX+8],EDX
10047827    8B49 0C         MOV ECX,DWORD PTR DS:[ECX+C]
1004782A    8948 0C         MOV DWORD PTR DS:[EAX+C],ECX
1004782D    C2 0400         RETN 4

这里是将一系列的数值往定的位置上,与我们上面的得数很相似,看看堆栈 DS:[0012DF70]=D495AD3A在

数据窗口跟随:
0012DF70  3A AD 95 D4 6A 1C E1 D2 D1 DD 0C DB 34 76 04 D9  :瓡詊嵋演.?v

不正是MD5加密后的结果吗!

继续单步,跟进00409375  |.  E8 76FDFFFF   CALL SuperNam.004090F0

004090F0  /$  83EC 14       SUB ESP,14
004090F3  |.  A1 24714100   MOV EAX,DWORD PTR DS:[417124]
004090F8  |.  33C4          XOR EAX,ESP

这个CALL里面有一大片都是来循环计算的。

00409120  |>  8B5424 10     /MOV EDX,DWORD PTR SS:[ESP+10]           ;  看第一次循环
00409124  |. |0FB6042A      |MOVZX EAX,BYTE PTR DS:[EDX+EBP]         ;  先取MD5值的前两位,

3A
00409128  |. |33C9          |XOR ECX,ECX
0040912A  |. |894C24 15     |MOV DWORD PTR SS:[ESP+15],ECX
0040912E  |. |894C24 19     |MOV DWORD PTR SS:[ESP+19],ECX
00409132  |. |8BC8          |MOV ECX,EAX                             ;  3A移到ECX上。
00409134  |. |C1E9 04       |SHR ECX,4                               ;  ECX位移一下。结果为

3。
00409137  |. |8B148D E07041>|MOV EDX,DWORD PTR DS:[ECX*4+4170E0]     ;  对应的结果为“0011

”,不就是3的二进制形式吗!
0040913E  |. |8B0A          |MOV ECX,DWORD PTR DS:[EDX]              ;  将“0011”的ASCII码

移到ECX
00409140  |. |83E0 0F       |AND EAX,0F                              ;  EAX=EAX AND 0F=3A

AND 0F=A
00409143  |. |8B1485 E07041>|MOV EDX,DWORD PTR DS:[EAX*4+4170E0]     ;  对应的值为“1010”

,正是十六进制数A的十进制形式!
0040914A  |. |8B02          |MOV EAX,DWORD PTR DS:[EDX]              ;  “1010”的ASCII码放

EAX上。
0040914C  |. |894424 18     |MOV DWORD PTR SS:[ESP+18],EAX           ;  EAX的值存放到堆栈

SS:[0012DF38]
00409150  |. |8D4424 14     |LEA EAX,DWORD PTR SS:[ESP+14]
00409154  |. |894C24 14     |MOV DWORD PTR SS:[ESP+14],ECX           ;  ECX的值存放到堆栈

SS:[0012DF34]
00409158  |. |8BC8          |MOV ECX,EAX
0040915A  |. |8D9B 00000000 |LEA EBX,DWORD PTR DS:[EBX]
00409160  |> |8A10          |/MOV DL,BYTE PTR DS:[EAX]
00409162  |. |40            ||INC EAX
00409163  |. |84D2          ||TEST DL,DL
00409165  |.^|75 F9         |\JNZ SHORT SuperNam.00409160
00409167  |. |8BFB          |MOV EDI,EBX
00409169  |. |2BC1          |SUB EAX,ECX
0040916B  |. |8BF1          |MOV ESI,ECX
0040916D  |. |4F            |DEC EDI
0040916E  |. |8BFF          |MOV EDI,EDI
00409170  |> |8A4F 01       |/MOV CL,BYTE PTR DS:[EDI+1]
00409173  |. |47            ||INC EDI
00409174  |. |84C9          ||TEST CL,CL
00409176  |.^|75 F8         |\JNZ SHORT SuperNam.00409170
00409178  |. |8BC8          |MOV ECX,EAX
0040917A  |. |C1E9 02       |SHR ECX,2
0040917D  |. |F3:A5         |REP MOVS DWORD PTR ES:[EDI],DWORD PTR D>
0040917F  |. |8BC8          |MOV ECX,EAX
00409181  |. |8B4424 2C     |MOV EAX,DWORD PTR SS:[ESP+2C]
00409185  |. |83E1 03       |AND ECX,3
00409188  |. |45            |INC EBP
00409189  |. |3BE8          |CMP EBP,EAX
0040918B  |. |F3:A4         |REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:>
0040918D  |.^\7C 91         \JL SHORT SuperNam.00409120              ;  计算的结果就是将加

密后的字符作为十六进制数转换为二进制数并相连在一起。
0040918F      5F            POP EDI

循环结束后看堆栈:
0012DF24   00B69B50  ASCII

"001110101010110110010101110101000110101000011100111000011101001011010001110111010000110011

01101100110100011101100000010011011001"


返回后继续单步:
我们注意一下,在刚才返回后在这里
0040937A  |.  8D9424 880000>LEA EDX,DWORD PTR SS:[ESP+88]

EDX上有一大串字符
堆栈地址=0012DFD0
EDX=00412500 (SuperNam.00412500), ASCII "678C1-

1FD08C8669F7FF1324ED26FEACBAC0DC5DEF8F_JKLJLFKKXXX-2C5B-4549-95E3-50C12260F836-5307DB9D-

7BE1-41ff-817E-8A664C13CC19"


下面的00409383 CALL SuperNam.004091B0跟进:
004091B0  /$  8B4424 08     MOV EAX,DWORD PTR SS:[ESP+8]
004091B4  |.  C600 00       MOV BYTE PTR DS:[EAX],0
004091B7  |.  8B4424 04     MOV EAX,DWORD PTR SS:[ESP+4]

看看这个CALL中又有一大片计算。

00409237  |.  8BF8          MOV EDI,EAX
00409239  |.  8DA424 000000>LEA ESP,DWORD PTR SS:[ESP]        ;  看第一次循环
00409240  |>  0FBE59 FF     /MOVSX EBX,BYTE PTR DS:[ECX-1]    ;  先取第二位的。放到EBX上。

30
00409244  |.  0FBE51 FE     |MOVSX EDX,BYTE PTR DS:[ECX-2]    ;  取第一位的,放在EDX上。30
00409248  |.  8D9453 46FFFF>|LEA EDX,DWORD PTR DS:[EBX+EDX*2->;  EDX=EBX+EDX*2-BA=30+30*2-

BA=FFFFFFD6
0040924F  |.  0FBE19        |MOVSX EBX,BYTE PTR DS:[ECX]      ;  取第三位放到EBX上。31
00409252  |.  8D1453        |LEA EDX,DWORD PTR DS:[EBX+EDX*2] ;  

EDX=EBX+EDX*2=31+FFFFFFD6*2=FFFFFFDD
00409255  |.  0FBE59 01     |MOVSX EBX,BYTE PTR DS:[ECX+1]    ;  取第四位,放到EBX上,31
00409259  |.  8D1453        |LEA EDX,DWORD PTR DS:[EBX+EDX*2] ;  

EDX=EBX+EDX*2=31+FFFFFFDD*2=FFFFFFEB
0040925C  |.  0FBE59 02     |MOVSX EBX,BYTE PTR DS:[ECX+2]    ;  取第五位,放到EBX上,31
00409260  |.  031D 20714100 |ADD EBX,DWORD PTR DS:[417120]    ;  EBX=EBX+00412584=004125B5
00409266  |.  46            |INC ESI                          ;  计数器加1
00409267  |.  8A1453        |MOV DL,BYTE PTR DS:[EBX+EDX*2]   ;  

DL=EBX+EDX*2=004125B5+FFFFFFEB*2=0041258B,取值为39,数据窗口跟随看看。
0040926A  |.  8B5C24 18     |MOV EBX,DWORD PTR SS:[ESP+18]
0040926E  |.  88541E FF     |MOV BYTE PTR DS:[ESI+EBX-1],DL   ;  将刚才取出来的数放到堆栈

DS:[0012E394],跟踪堆栈 DS:[0012E394]
00409272  |.  83C1 05       |ADD ECX,5
00409275  |.  3BF0          |CMP ESI,EAX                      ;  一共要循环1A次,也就是十进

制26次。
00409277  |.^ 7C C7         \JL SHORT SuperNam.00409240
00409279  |>  8B4424 18     MOV EAX,DWORD PTR SS:[ESP+18]     ;  运行到这里时堆栈中出现了刚

才循环的结果。堆栈 SS:[0012E308]=0012E394, (ASCII "9CQTDP5C5MJX7NGX3MFMAXJ6V6")
0040927D  |.  55            PUSH EBP                          ; /block[/CODE]

数据窗口跟随:
[CODE]00412500  36 37 38 43 31 2D 31 46 44 30 38 43 38 36 36 39  678C1-1FD08C8669
00412510  46 37 46 46 31 33 32 34 45 44 32 36 46 45 41 43  F7FF1324ED26FEAC
00412520  42 41 43 30 44 43 35 44 45 46 38 46 5F 4A 4B 4C  BAC0DC5DEF8F_JKL
00412530  4A 4C 46 4B 4B 58 58 58 2D 32 43 35 42 2D 34 35  JLFKKXXX-2C5B-45
00412540  34 39 2D 39 35 45 33 2D 35 30 43 31 32 32 36 30  49-95E3-50C12260
00412550  46 38 33 36 2D 35 33 30 37 44 42 39 44 2D 37 42  F836-5307DB9D-7B
00412560  45 31 2D 34 31 66 66 2D 38 31 37 45 2D 38 41 36  E1-41ff-817E-8A6
00412570  36 34 43 31 33 43 43 31 39 00 00 00 A0 8C 40 00  64C13CC19...爩@.
00412580  C0 8C 40 00 32 33 34 35 36 37 38 39 41 42 43 44  缹@.23456789ABCD
00412590  45 46 47 48 4A 4B 4C 4D 4E 50 51 52 53 54 55 56  EFGHJKLMNPQRSTUV
004125A0  57 58 59 5A 00 00 00 00 31 31 31 31 00 00 00 00  WXYZ....1111....

不正好是从上一个CALL出来后出现的一大串字符吗!

而计算出来的数的们数(9CQTDP5C5MJX7NGX3MFMAXJ6V6)又正好是26位,真码要36位(十六进制数24的十

进制),36-2-8=26。
好的方法当然是继续跟了,偷懒的方法就是来试试看能不能注册成功。
教程够长的了,偷一下懒了,看看现在注册码应该是多少:
QM 34567890 9CQTDP5C5MJX7NGX3MFMAXJ6V6
连在一起注册成功了!!!

【算法总结】
1、先判断注册码是否为36位;
2、再判断注册码的前两位是否为字符“QM”,这是注册码的第一部分;
3、再将注册码的第三位到第十位共八个数进行MD5加密计算,结果设为X,这八个数为注册码的第二部分


4、将X作为十六进制数转换为十进制数,设为Y;
5、将Y中的字符的ASCII码每五个作为一组,进行循环计算,每一次的结果在一个固定的字符表中取字符

,所有的字符连在一起作为注册码的第三部分;
6、三者相连就是正确的注册码了。
------------------------------------------------------------------------
【破解总结】
1、该软件没有加壳。
2、不是明码比较,而是分段对比,一处不对,下一处就走不到了,所以很难做出内存注册机。
3、算法中采取了以前流行的MD5加密算法。
4、在MD5加密算法时用的是注册码的一部分,结果是注册码可能与机器无关,做不到一机一码。
------------------------------------------------------------------------
【版权声明】本文只是出于学习和交流目的,请勿用于商业用途,否则后果自负。软件版权归作者所有


附VB注册机源码:

Private Const OFFSET_4 = 4294967296#
Private Const MAXINT_4 = 2147483647
Private State(4) As Long
Private ByteCounter As Long
Private ByteBuffer(63) As Byte
Private Const S11 = 7
Private Const S12 = 12
Private Const S13 = 17
Private Const S14 = 22
Private Const S21 = 5
Private Const S22 = 9
Private Const S23 = 14
Private Const S24 = 20
Private Const S31 = 4
Private Const S32 = 11
Private Const S33 = 16
Private Const S34 = 23
Private Const S41 = 6
Private Const S42 = 10
Private Const S43 = 15
Private Const S44 = 21
Property Get RegisterA() As String
RegisterA = State(1)
End Property
Property Get RegisterB() As String
RegisterB = State(2)
End Property

Property Get RegisterC() As String
RegisterC = State(3)
End Property

Property Get RegisterD() As String
RegisterD = State(4)
End Property
Public Function Md5_String_Calc(SourceString As String) As String
MD5Init
MD5Update LenB(StrConv(SourceString, vbFromUnicode)), StringToArray(SourceString)
MD5Final
Md5_String_Calc = GetValues
End Function
Public Function Md5_File_Calc(InFile As String) As String
On Error GoTo errorhandler
GoSub begin

errorhandler:
Md5_File_Calc = ""
Exit Function

begin:
Dim FileO As Integer
FileO = FreeFile
Call FileLen(InFile)
Open InFile For Binary Access Read As #FileO
MD5Init
Do While Not EOF(FileO)
Get #FileO, , ByteBuffer
If Loc(FileO) < LOF(FileO) Then
ByteCounter = ByteCounter + 64
MD5Transform ByteBuffer
End If
Loop
ByteCounter = ByteCounter + (LOF(FileO) Mod 64)
Close #FileO
MD5Final
Md5_File_Calc = GetValues
End Function
Private Function StringToArray(InString As String) As Byte()
Dim I As Integer, bytBuffer() As Byte
ReDim bytBuffer(LenB(StrConv(InString, vbFromUnicode)))
bytBuffer = StrConv(InString, vbFromUnicode)
StringToArray = bytBuffer
End Function
Public Function GetValues() As String
GetValues = LongToString(State(1)) & LongToString(State(2)) & LongToString(State(3)) & LongToString(State(4))
End Function
Private Function LongToString(Num As Long) As String
Dim A As Byte, B As Byte, C As Byte, d As Byte
A = Num And &HFF&
If A < 16 Then LongToString = "0" & Hex(A) Else LongToString = Hex(A)
B = (Num And &HFF00&) \ 256
If B < 16 Then LongToString = LongToString & "0" & Hex(B) Else LongToString = LongToString & Hex(B)
C = (Num And &HFF0000) \ 65536
If C < 16 Then LongToString = LongToString & "0" & Hex(C) Else LongToString = LongToString & Hex(C)
If Num < 0 Then d = ((Num And &H7F000000) \ 16777216) Or &H80& Else d = (Num And &HFF000000) \ 16777216
If d < 16 Then LongToString = LongToString & "0" & Hex(d) Else LongToString = LongToString & Hex(d)
End Function

Public Sub MD5Init()
ByteCounter = 0
State(1) = UnsignedToLong(1732584193#)
State(2) = UnsignedToLong(4023233417#)
State(3) = UnsignedToLong(2562383102#)
State(4) = UnsignedToLong(271733878#)
End Sub

Public Sub MD5Final()
Dim dblBits As Double, padding(72) As Byte, lngBytesBuffered As Long
padding(0) = &H80
dblBits = ByteCounter * 8
lngBytesBuffered = ByteCounter Mod 64
If lngBytesBuffered <= 56 Then MD5Update 56 - lngBytesBuffered, padding Else MD5Update 120 - ByteCounter, padding
padding(0) = UnsignedToLong(dblBits) And &HFF&
padding(1) = UnsignedToLong(dblBits) \ 256 And &HFF&
padding(2) = UnsignedToLong(dblBits) \ 65536 And &HFF&
padding(3) = UnsignedToLong(dblBits) \ 16777216 And &HFF&
padding(4) = 0
padding(5) = 0
padding(6) = 0
padding(7) = 0
MD5Update 8, padding
End Sub
Public Sub MD5Update(InputLen As Long, InputBuffer() As Byte)
Dim II As Integer, I As Integer, J As Integer, K As Integer, lngBufferedBytes As Long, lngBufferRemaining As Long, lngRem As Long

lngBufferedBytes = ByteCounter Mod 64
lngBufferRemaining = 64 - lngBufferedBytes
ByteCounter = ByteCounter + InputLen

If InputLen >= lngBufferRemaining Then
For II = 0 To lngBufferRemaining - 1
ByteBuffer(lngBufferedBytes + II) = InputBuffer(II)
Next II
MD5Transform ByteBuffer
lngRem = (InputLen) Mod 64
For I = lngBufferRemaining To InputLen - II - lngRem Step 64
For J = 0 To 63
ByteBuffer(J) = InputBuffer(I + J)
Next J
MD5Transform ByteBuffer
Next I
lngBufferedBytes = 0
Else
I = 0
End If
For K = 0 To InputLen - I - 1
ByteBuffer(lngBufferedBytes + K) = InputBuffer(I + K)
Next K
End Sub
Private Sub MD5Transform(Buffer() As Byte)
Dim X(16) As Long, A As Long, B As Long, C As Long, d As Long

A = State(1)
B = State(2)
C = State(3)
d = State(4)
Decode 64, X, Buffer
FF A, B, C, d, X(0), S11, -680876936
FF d, A, B, C, X(1), S12, -389564586
FF C, d, A, B, X(2), S13, 606105819
FF B, C, d, A, X(3), S14, -1044525330
FF A, B, C, d, X(4), S11, -176418897
FF d, A, B, C, X(5), S12, 1200080426
FF C, d, A, B, X(6), S13, -1473231341
FF B, C, d, A, X(7), S14, -45705983
FF A, B, C, d, X(8), S11, 1770035416
FF d, A, B, C, X(9), S12, -1958414417
FF C, d, A, B, X(10), S13, -42063
FF B, C, d, A, X(11), S14, -1990404162
FF A, B, C, d, X(12), S11, 1804603682
FF d, A, B, C, X(13), S12, -40341101
FF C, d, A, B, X(14), S13, -1502002290
FF B, C, d, A, X(15), S14, 1236535329

GG A, B, C, d, X(1), S21, -165796510
GG d, A, B, C, X(6), S22, -1069501632
GG C, d, A, B, X(11), S23, 643717713
GG B, C, d, A, X(0), S24, -373897302
GG A, B, C, d, X(5), S21, -701558691
GG d, A, B, C, X(10), S22, 38016083
GG C, d, A, B, X(15), S23, -660478335
GG B, C, d, A, X(4), S24, -405537848
GG A, B, C, d, X(9), S21, 568446438
GG d, A, B, C, X(14), S22, -1019803690
GG C, d, A, B, X(3), S23, -187363961
GG B, C, d, A, X(8), S24, 1163531501
GG A, B, C, d, X(13), S21, -1444681467
GG d, A, B, C, X(2), S22, -51403784
GG C, d, A, B, X(7), S23, 1735328473
GG B, C, d, A, X(12), S24, -1926607734

HH A, B, C, d, X(5), S31, -378558
HH d, A, B, C, X(8), S32, -2022574463
HH C, d, A, B, X(11), S33, 1839030562
HH B, C, d, A, X(14), S34, -35309556
HH A, B, C, d, X(1), S31, -1530992060
HH d, A, B, C, X(4), S32, 1272893353
HH C, d, A, B, X(7), S33, -155497632
HH B, C, d, A, X(10), S34, -1094730640
HH A, B, C, d, X(13), S31, 681279174
HH d, A, B, C, X(0), S32, -358537222
HH C, d, A, B, X(3), S33, -722521979
HH B, C, d, A, X(6), S34, 76029189
HH A, B, C, d, X(9), S31, -640364487
HH d, A, B, C, X(12), S32, -421815835
HH C, d, A, B, X(15), S33, 530742520
HH B, C, d, A, X(2), S34, -995338651

II A, B, C, d, X(0), S41, -198630844
II d, A, B, C, X(7), S42, 1126891415
II C, d, A, B, X(14), S43, -1416354905
II B, C, d, A, X(5), S44, -57434055
II A, B, C, d, X(12), S41, 1700485571
II d, A, B, C, X(3), S42, -1894986606
II C, d, A, B, X(10), S43, -1051523
II B, C, d, A, X(1), S44, -2054922799
II A, B, C, d, X(8), S41, 1873313359
II d, A, B, C, X(15), S42, -30611744
II C, d, A, B, X(6), S43, -1560198380
II B, C, d, A, X(13), S44, 1309151649
II A, B, C, d, X(4), S41, -145523070
II d, A, B, C, X(11), S42, -1120210379
II C, d, A, B, X(2), S43, 718787259
II B, C, d, A, X(9), S44, -343485551

State(1) = LongOverflowAdd(State(1), A)
State(2) = LongOverflowAdd(State(2), B)
State(3) = LongOverflowAdd(State(3), C)
State(4) = LongOverflowAdd(State(4), d)
End Sub

Private Sub Decode(Length As Integer, OutputBuffer() As Long, InputBuffer() As Byte)
Dim intDblIndex As Integer, intByteIndex As Integer, dblSum As Double
For intByteIndex = 0 To Length - 1 Step 4
dblSum = InputBuffer(intByteIndex) + InputBuffer(intByteIndex + 1) * 256# + InputBuffer(intByteIndex + 2) * 65536# + InputBuffer(intByteIndex + 3) * 16777216#
OutputBuffer(intDblIndex) = UnsignedToLong(dblSum)
intDblIndex = intDblIndex + 1
Next intByteIndex
End Sub
Private Function FF(A As Long, B As Long, C As Long, d As Long, X As Long, S As Long, ac As Long) As Long
A = LongOverflowAdd4(A, (B And C) Or (Not (B) And d), X, ac)
A = LongLeftRotate(A, S)
A = LongOverflowAdd(A, B)
End Function
Private Function GG(A As Long, B As Long, C As Long, d As Long, X As Long, S As Long, ac As Long) As Long
A = LongOverflowAdd4(A, (B And d) Or (C And Not (d)), X, ac)
A = LongLeftRotate(A, S)
A = LongOverflowAdd(A, B)
End Function
Private Function HH(A As Long, B As Long, C As Long, d As Long, X As Long, S As Long, ac As Long) As Long
A = LongOverflowAdd4(A, B Xor C Xor d, X, ac)
A = LongLeftRotate(A, S)
A = LongOverflowAdd(A, B)
End Function
Private Function II(A As Long, B As Long, C As Long, d As Long, X As Long, S As Long, ac As Long) As Long
A = LongOverflowAdd4(A, C Xor (B Or Not (d)), X, ac)
A = LongLeftRotate(A, S)
A = LongOverflowAdd(A, B)
End Function

Function LongLeftRotate(value As Long, Bits As Long) As Long
Dim lngSign As Long, lngI As Long
Bits = Bits Mod 32
If Bits = 0 Then LongLeftRotate = value: Exit Function
For lngI = 1 To Bits
lngSign = value And &HC0000000
value = (value And &H3FFFFFFF) * 2
value = value Or ((lngSign < 0) And 1) Or (CBool(lngSign And &H40000000) And &H80000000)
Next
LongLeftRotate = value
End Function
Private Function LongOverflowAdd(Val1 As Long, Val2 As Long) As Long
Dim lngHighWord As Long, lngLowWord As Long, lngOverflow As Long
lngLowWord = (Val1 And &HFFFF&) + (Val2 And &HFFFF&)
lngOverflow = lngLowWord \ 65536
lngHighWord = (((Val1 And &HFFFF0000) \ 65536) + ((Val2 And &HFFFF0000) \ 65536) + lngOverflow) And &HFFFF&
LongOverflowAdd = UnsignedToLong((lngHighWord * 65536#) + (lngLowWord And &HFFFF&))
End Function
Private Function LongOverflowAdd4(Val1 As Long, Val2 As Long, val3 As Long, val4 As Long) As Long
Dim lngHighWord As Long, lngLowWord As Long, lngOverflow As Long
lngLowWord = (Val1 And &HFFFF&) + (Val2 And &HFFFF&) + (val3 And &HFFFF&) + (val4 And &HFFFF&)
lngOverflow = lngLowWord \ 65536
lngHighWord = (((Val1 And &HFFFF0000) \ 65536) + ((Val2 And &HFFFF0000) \ 65536) + ((val3 And &HFFFF0000) \ 65536) + ((val4 And &HFFFF0000) \ 65536) + lngOverflow) And &HFFFF&
LongOverflowAdd4 = UnsignedToLong((lngHighWord * 65536#) + (lngLowWord And &HFFFF&))
End Function

Private Function UnsignedToLong(value As Double) As Long
If value < 0 Or value >= OFFSET_4 Then Error 6
If value <= MAXINT_4 Then UnsignedToLong = value Else UnsignedToLong = value - OFFSET_4
End Function
Private Function LongToUnsigned(value As Long) As Double
If value < 0 Then LongToUnsigned = value + OFFSET_4 Else LongToUnsigned = value
End Function

Private Sub Command1_Click()
Hex1 = Md5_String_Calc(Text1)
Hex1 = UCase(Hex1)
    For I = 1 To Len(Hex1)
        Select Case Mid(Hex1, I, 1)
            Case "0": B = B & "0000"
            Case "1": B = B & "0001"
            Case "2": B = B & "0010"
            Case "3": B = B & "0011"
            Case "4": B = B & "0100"
            Case "5": B = B & "0101"
            Case "6": B = B & "0110"
            Case "7": B = B & "0111"
            Case "8": B = B & "1000"
            Case "9": B = B & "1001"
            Case "A": B = B & "1010"
            Case "B": B = B & "1011"
            Case "C": B = B & "1100"
            Case "D": B = B & "1101"
            Case "E": B = B & "1110"
            Case "F": B = B & "1111"
        End Select
    Next I
    If Len(B) Mod 4 = 3 Then
        HEX_to_BIN = "0" & B & "00"
    ElseIf Len(B) Mod 4 = 2 Then
        HEX_to_BIN = "00" & B & "00"
    ElseIf Len(B) Mod 4 = 1 Then
        HEX_to_BIN = "000" & B & "00"
    Else
    HEX_to_BIN = B & "00"
    End If
    'B = 0
   
    For S = 1 To Len(HEX_to_BIN) Step 5
    I = S
    str1 = Asc(Mid(HEX_to_BIN, I, 1))
    I = I + 1
    str2 = Asc(Mid(HEX_to_BIN, I, 1))
    I = I + 1
    str3 = Asc(Mid(HEX_to_BIN, I, 1))
    I = I + 1
    str4 = Asc(Mid(HEX_to_BIN, I, 1))
    I = I + 1
    str5 = Asc(Mid(HEX_to_BIN, I, 1))
   
  int1 = (str1 * 2 + str2) - 186
   int1 = int1 * 2 + str3
    int1 = int1 * 2 + str4

    n = int1 * 2 + str5 + 131
   
    str_gdm = "678C1-1FD08C8669F7FF1324ED26FEACBAC0DC5DEF8F_JKLJLFKKXXX-2C5B-4549-95E3-50C12260F836-5307DB9D-7BE1-41ff-817E-8A664C13CC19...爩@.缹@.23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
   
    str_zcm1 = Mid(str_gdm, n, 1)
   
    str_zcm = str_zcm & str_zcm1
   
    Next
   
   
   
   
    If Len(Text1) = 8 Then
   
   

    Text2.Text = "QM" & UCase(Text1) & str_zcm

    End If

End Sub

Private Sub Command2_Click()
Form1.Hide
Form2.Show
End Sub
Private Sub Command3_Click()
MsgBox "请不要输入中文字符或不常用字符,否则可能出错。如果出错请换其他常用数字再试试!"
End Sub

Private Sub Form_Load()
MsgBox "请不要输入中文字符或不常用字符,否则可能出错。如果出错请换其他常用数字再试试!"
End Sub

Private Sub Text1_Change()
Text1 = UCase(Text1)
End Sub


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 401
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
汗 真是牛人
2009-8-6 15:06
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
我是新手,顶礼膜拜了。。。
2009-8-6 17:40
0
雪    币: 246
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
学习  
收藏了
2009-8-6 17:58
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
5
随意散发注册机已违反论坛规则, 尤其是国产软件.

最好不要提供可编译注册机源代码 .
2009-8-6 20:19
0
雪    币: 421
活跃值: (83)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
分析的超级详细。好文
2009-8-7 08:23
0
游客
登录 | 注册 方可回帖
返回
//