【破文作者】   rdsnow[BCG][PYG][D.4s]
【作者主页】   http://rdsnow.ys168.com
【 E-mail 】   rdsnow@163.com
【 作者QQ 】   83757177
【文章题目】   HDNTV2005的算法分析
【软件名称】   雷神高清晰度网络电视3.55.5104
【下载地址】   http://hdntv.com/download/HDNTV.exe

----------------------------------------------------------------------------------------
【加密方式】   序列号
【破解工具】   ODbyDYK v1.10[05.09]
【软件限制】   功能限制
【破解平台】   Microsoft Windows Professional Server Pack 2

----------------------------------------------------------------------------------------
【文章简介】

脱壳就不多说了:UPX 0.89.6 - 1.02 / 1.05 - 1.24 (Delphi) stub -> Markus & Laszlo的壳,可能作者修改了标志,用UPX -d脱不掉,ESP定律搞定。脱壳后Borland Delphi 6.0 - 7.0。

这个程序跟很多共享软件差不多,采用了流行的非明码比较,重启验证,分段式注册码。注册码跟用户名无关。

校验过程中用到了两个功能函数F1( )和F2( ),会在后面介绍。

其中F2( )中采用了128位数据运算。就是注释中的大数运算,^_^,具体情况跟进去看看吧!

----------------------------------------------------------------------------------------
【破解过程】

输入假码,启动监视程序,检测注册码存在安装目录下config.lss文件中,可用记事本查看:

[reg]
user=rdsnow[BCG][PYG][D.4s]
serial=123456789-7654321-8765432-9876543

『一』、字符串user,serial,config.lss等都是突破口,根据这些信息来到:

00504D9D    6A 00           PUSH 0
00504D9F    8D45 E0         LEA EAX,DWORD PTR SS:[EBP-20]
00504DA2    50              PUSH EAX
00504DA3    B9 704F5000     MOV ECX,Dump.00504F70             ; ASCII "user"
00504DA8    BA 804F5000     MOV EDX,Dump.00504F80             ; ASCII "reg"
00504DAD    8BC3            MOV EAX,EBX
00504DAF    8B30            MOV ESI,DWORD PTR DS:[EAX]
00504DB1    FF16            CALL NEAR DWORD PTR DS:[ESI]      ; 取用户名user
00504DB3    8B55 E0         MOV EDX,DWORD PTR SS:[EBP-20]
00504DB6    B8 68F35300     MOV EAX,Dump.0053F368
00504DBB    E8 2CF5EFFF     CALL Dump.004042EC
00504DC0    6A 00           PUSH 0
00504DC2    8D45 DC         LEA EAX,DWORD PTR SS:[EBP-24]
00504DC5    50              PUSH EAX
00504DC6    B9 8C4F5000     MOV ECX,Dump.00504F8C             ; ASCII "serial"
00504DCB    BA 804F5000     MOV EDX,Dump.00504F80             ; ASCII "reg"
00504DD0    8BC3            MOV EAX,EBX
00504DD2    8B30            MOV ESI,DWORD PTR DS:[EAX]
00504DD4    FF16            CALL NEAR DWORD PTR DS:[ESI]      ; 取注册码serial
00504DD6    8B55 DC         MOV EDX,DWORD PTR SS:[EBP-24]
00504DD9    B8 6CF35300     MOV EAX,Dump.0053F36C
00504DDE    E8 09F5EFFF     CALL Dump.004042EC
00504DE3    833D 6CF35300 0>CMP DWORD PTR DS:[53F36C],0       ; 判断取注册码是否成功
00504DEA    0F84 05010000   JE Dump.00504EF5
00504DF0    A1 6CF35300     MOV EAX,DWORD PTR DS:[53F36C]
00504DF5    E8 62090000     CALL Dump.0050575C                ; 关键call,跟进
00504DFA    A3 60F35300     MOV DWORD PTR DS:[53F360],EAX
00504DFF    A1 60F35300     MOV EAX,DWORD PTR DS:[53F360]     ; 取注册标志
00504E04    83E8 01         SUB EAX,1
00504E07    72 10           JB SHORT Dump.00504E19            ; 不是1或3小就跳向试用版
00504E09    74 35           JE SHORT Dump.00504E40            ; 注册标志是1,跳向标准版
00504E0B    83E8 02         SUB EAX,2
00504E0E    0F84 84000000   JE Dump.00504E98                  ; 注册标志是3,跳向钻石版
00504E14    E9 D5000000     JMP Dump.00504EEE
00504E19    B9 704F5000     MOV ECX,Dump.00504F70             ; ASCII "user"
00504E1E    BA 804F5000     MOV EDX,Dump.00504F80             ; ASCII "reg"
00504E23    8BC3            MOV EAX,EBX
00504E25    8B30            MOV ESI,DWORD PTR DS:[EAX]
00504E27    FF56 50         CALL NEAR DWORD PTR DS:[ESI+50]
00504E2A    B9 8C4F5000     MOV ECX,Dump.00504F8C             ; ASCII "serial"
00504E2F    BA 804F5000     MOV EDX,Dump.00504F80             ; ASCII "reg"
00504E34    8BC3            MOV EAX,EBX
00504E36    8B30            MOV ESI,DWORD PTR DS:[EAX]
00504E38    FF56 50         CALL NEAR DWORD PTR DS:[ESI+50]   ; 检验不成功就删除保存的注册信息
00504E3B    E9 AE000000     JMP Dump.00504EEE
00504E40    A1 3CF35300     MOV EAX,DWORD PTR DS:[53F33C]

【小结】

关键Call的下面的几个跳转就是爆破点,[53F360]存放注册标志,不过跟进关键Call会发现还有防暴破的暗桩。

----------------------------------------------------------------------------------------
『二』、程序的主要验证部分(关键Call内)

不忙跟进关键Call,先把假码换成qoke]SGH-hd^VL@B-ie_WMAC-jf`XNBD

这个假码怎么得到的,要跟下去几步才知道。简介一下,程序首先会根据一些位置的字符做一些替换,然后再运用下面『三』中提到的解密函数F1( )对各段注册码的每个字符转换,转换后的字符一定要是数字,否则在将字符串转为十六进制数值时会发生异常,然后直接跳到试用版本。

可以先写一个F1( )的逆函数转换一下。具体情况参考『三』

上面的这个假码经过转化后会得到12345678-7654321-8765432-9876543

好了,现在跟进00504DF5 CALL Dump.0050575C,再跟进0050577D CALL Dump.00501E58
00501E58    55              PUSH EBP
00501E59    8BEC            MOV EBP,ESP
00501E5B    B9 18000000     MOV ECX,18
00501E60    6A 00           PUSH 0
00501E62    6A 00           PUSH 0
00501E64    49              DEC ECX
00501E65  ^ 75 F9           JNZ SHORT Dump.00501E60
00501E67    53              PUSH EBX
00501E68    56              PUSH ESI
00501E69    57              PUSH EDI
00501E6A    8945 FC         MOV DWORD PTR SS:[EBP-4],EAX
00501E6D    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
00501E70    E8 E328F0FF     CALL Dump.00404758
00501E75    33C0            XOR EAX,EAX
00501E77    55              PUSH EBP
00501E78    68 7B285000     PUSH Dump.0050287B
00501E7D    64:FF30         PUSH DWORD PTR FS:[EAX]
00501E80    64:8920         MOV DWORD PTR FS:[EAX],ESP
00501E83    33C0            XOR EAX,EAX
00501E85    8945 F8         MOV DWORD PTR SS:[EBP-8],EAX
00501E88    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
00501E8B    E8 D826F0FF     CALL Dump.00404568                ; 取注册码长度
00501E90    83F8 1E         CMP EAX,1E                        ; 注册码的长度不小于30
00501E93    0F8C BC090000   JL Dump.00502855
00501E99    8B55 FC         MOV EDX,DWORD PTR SS:[EBP-4]
00501E9C    B8 94285000     MOV EAX,OFFSET <Dump."-">
00501EA1    E8 062AF0FF     CALL Dump.004048AC                ; 返回注册码中"-"的位置
00501EA6    85C0            TEST EAX,EAX
00501EA8    0F84 A7090000   JE Dump.00502855
00501EAE    33D2            XOR EDX,EDX
00501EB0    55              PUSH EBP
00501EB1    68 46285000     PUSH Dump.00502846
00501EB6    64:FF32         PUSH DWORD PTR FS:[EDX]
00501EB9    64:8922         MOV DWORD PTR FS:[EDX],ESP
00501EBC    8D45 E0         LEA EAX,DWORD PTR SS:[EBP-20]
00501EBF    E8 D423F0FF     CALL Dump.00404298
00501EC4    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
00501EC7    8078 04 41      CMP BYTE PTR DS:[EAX+4],41        ; 第5个字符是不是"A"
00501ECB    75 35           JNZ SHORT Dump.00501F02           ; 不是"A"就跳
00501ECD    8D45 DC         LEA EAX,DWORD PTR SS:[EBP-24]
00501ED0    50              PUSH EAX
00501ED1    B9 05000000     MOV ECX,5
00501ED6    BA 01000000     MOV EDX,1
00501EDB    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
00501EDE    E8 E528F0FF     CALL Dump.004047C8                ; 取注册码的前5位
00501EE3    8B45 DC         MOV EAX,DWORD PTR SS:[EBP-24]
00501EE6    8D55 EC         LEA EDX,DWORD PTR SS:[EBP-14]
00501EE9    E8 1E6CF0FF     CALL Dump.00408B0C                ; 大写转小写
00501EEE    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00501EF1    B9 05000000     MOV ECX,5
00501EF6    BA 01000000     MOV EDX,1
00501EFB    E8 0829F0FF     CALL Dump.00404808
00501F00    EB 33           JMP SHORT Dump.00501F35
00501F02    8D45 D8         LEA EAX,DWORD PTR SS:[EBP-28]     ; 注册码第5位不是"A"就跳到这里继续
00501F05    50              PUSH EAX
00501F06    B9 04000000     MOV ECX,4
00501F0B    BA 01000000     MOV EDX,1
00501F10    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
00501F13    E8 B028F0FF     CALL Dump.004047C8                ; 取注册码的前4位
00501F18    8B45 D8         MOV EAX,DWORD PTR SS:[EBP-28]
00501F1B    8D55 EC         LEA EDX,DWORD PTR SS:[EBP-14]
00501F1E    E8 E96BF0FF     CALL Dump.00408B0C                ; 大写转小写
00501F23    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00501F26    B9 04000000     MOV ECX,4
00501F2B    BA 01000000     MOV EDX,1
00501F30    E8 D328F0FF     CALL Dump.00404808
00501F35    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]      ; 注册码前4位或前5位转小写后到这里继续
00501F38    8B4D FC         MOV ECX,DWORD PTR SS:[EBP-4]
00501F3B    8B55 EC         MOV EDX,DWORD PTR SS:[EBP-14]
00501F3E    E8 7126F0FF     CALL Dump.004045B4                ; 替换注册码的前4位或前5位为小写
00501F43    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
00501F46    0FB640 07       MOVZX EAX,BYTE PTR DS:[EAX+7]     ; 注册码的第8位
00501F4A    83C0 BF         ADD EAX,-41
00501F4D    83F8 19         CMP EAX,19
00501F50    0F87 DD000000   JA Dump.00502033                  ; 第8位不是大写字母就跳
00501F56    8A80 631F5000   MOV AL,BYTE PTR DS:[EAX+501F63]
00501F5C    FF2485 7D1F5000 JMP NEAR DWORD PTR DS:[EAX*4+501F>
00501F63    0102            ADD DWORD PTR DS:[EDX],EAX        ; 这里不是指令
00501F65    030405 0608090A ADD EAX,DWORD PTR DS:[EAX+A090806>
00501F6C    0000            ADD BYTE PTR DS:[EAX],AL          ; 而是26个byte
00501F6E    0000            ADD BYTE PTR DS:[EAX],AL
00501F70    0000            ADD BYTE PTR DS:[EAX],AL          ; 用于替换注册码的第8位
00501F72    0000            ADD BYTE PTR DS:[EAX],AL
00501F74    0000            ADD BYTE PTR DS:[EAX],AL          ; 对应了26个字母的替换表
00501F76    0000            ADD BYTE PTR DS:[EAX],AL
00501F78    0000            ADD BYTE PTR DS:[EAX],AL          ; 0表示不替换
00501F7A    0000            ADD BYTE PTR DS:[EAX],AL
00501F7C    07              POP ES                            ; 替换表到这里结束
00501F7D    3320            XOR ESP,DWORD PTR DS:[EAX]        ; 这里也不是指令
00501F7F    50              PUSH EAX
00501F80    00A9 1F5000B7   ADD BYTE PTR DS:[ECX+B700501F],CH ; 而是11个DWORD
00501F86    1F              POP DS
00501F87    50              PUSH EAX                          ; 保存的是11个跳转地址
00501F88    00C5            ADD CH,AL
00501F8A    1F              POP DS                            ; 第1个是不是A-J时的跳转地址
00501F8B    50              PUSH EAX
00501F8C    00D3            ADD BL,DL
00501F8E    1F              POP DS
00501F8F    50              PUSH EAX                          ; 其他10个分别对应了A-J时的跳转地址
00501F90    00E1            ADD CL,AH
00501F92    1F              POP DS
00501F93    50              PUSH EAX
00501F94    00EF            ADD BH,CH
00501F96    1F              POP DS                            ; 对应与注册码后几段的最后一个字符的替换
00501F97    50              PUSH EAX
00501F98    00FD            ADD CH,BH
00501F9A    1F              POP DS
00501F9B    50              PUSH EAX
00501F9C    000B            ADD BYTE PTR DS:[EBX],CL
00501F9E    2050 00         AND BYTE PTR DS:[EAX],DL
00501FA1    1920            SBB DWORD PTR DS:[EAX],ESP
00501FA3    50              PUSH EAX                          ; 到这里11个DWORD结束
00501FA4    0027            ADD BYTE PTR DS:[EDI],AH
00501FA6    2050 00         AND BYTE PTR DS:[EAX],DL
00501FA9    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]      ; 第8位是"A"就用"1"替换
00501FAC    E8 0F28F0FF     CALL Dump.004047C0
00501FB1    C640 07 31      MOV BYTE PTR DS:[EAX+7],31
00501FB5    EB 7C           JMP SHORT Dump.00502033
00501FB7    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00501FBA    E8 0128F0FF     CALL Dump.004047C0
00501FBF    C640 07 32      MOV BYTE PTR DS:[EAX+7],32        ; 第8位是"B"就用"2"替换
00501FC3    EB 6E           JMP SHORT Dump.00502033
00501FC5    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00501FC8    E8 F327F0FF     CALL Dump.004047C0
00501FCD    C640 07 33      MOV BYTE PTR DS:[EAX+7],33        ; 第8位是"C"就用"3"替换
00501FD1    EB 60           JMP SHORT Dump.00502033
00501FD3    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00501FD6    E8 E527F0FF     CALL Dump.004047C0
00501FDB    C640 07 34      MOV BYTE PTR DS:[EAX+7],34        ; 第8位是"D"就用"4"替换
00501FDF    EB 52           JMP SHORT Dump.00502033
00501FE1    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00501FE4    E8 D727F0FF     CALL Dump.004047C0
00501FE9    C640 07 35      MOV BYTE PTR DS:[EAX+7],35        ; 第8位是"E"就用"5"替换
00501FED    EB 44           JMP SHORT Dump.00502033
00501FEF    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00501FF2    E8 C927F0FF     CALL Dump.004047C0
00501FF7    C640 07 36      MOV BYTE PTR DS:[EAX+7],36        ; 第8位是"F"就用"6"替换
00501FFB    EB 36           JMP SHORT Dump.00502033
00501FFD    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00502000    E8 BB27F0FF     CALL Dump.004047C0
00502005    C640 07 37      MOV BYTE PTR DS:[EAX+7],37        ; 第8位是"Z"就用"7"替换
00502009    EB 28           JMP SHORT Dump.00502033
0050200B    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
0050200E    E8 AD27F0FF     CALL Dump.004047C0
00502013    C640 07 38      MOV BYTE PTR DS:[EAX+7],38        ; 第8位是"G"就用"8"替换
00502017    EB 1A           JMP SHORT Dump.00502033
00502019    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
0050201C    E8 9F27F0FF     CALL Dump.004047C0
00502021    C640 07 39      MOV BYTE PTR DS:[EAX+7],39        ; 第8位是"H"就用"9"替换
00502025    EB 0C           JMP SHORT Dump.00502033
00502027    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]      ; 第8位是"I"就用"0"替换
0050202A    E8 9127F0FF     CALL Dump.004047C0
0050202F    C640 07 30      MOV BYTE PTR DS:[EAX+7],30
00502033    8D45 D4         LEA EAX,DWORD PTR SS:[EBP-2C]     ; 第8位不是A-J或Z就不替换跳到这里继续
00502036    50              PUSH EAX
00502037    8B55 FC         MOV EDX,DWORD PTR SS:[EBP-4]
0050203A    B8 94285000     MOV EAX,OFFSET <Dump."-">
0050203F    E8 6828F0FF     CALL Dump.004048AC                ; 返回注册码中"-"的位置
00502044    8BC8            MOV ECX,EAX
00502046    49              DEC ECX
00502047    BA 01000000     MOV EDX,1
0050204C    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
0050204F    E8 7427F0FF     CALL Dump.004047C8                ; 取注册码"-"前的部分
00502054    8B45 D4         MOV EAX,DWORD PTR SS:[EBP-2C]
00502057    8D55 E4         LEA EDX,DWORD PTR SS:[EBP-1C]
0050205A    E8 21D6FFFF     CALL Dump.004FF680                ; F1(Sn1)="12345678"
0050205F    8D45 D0         LEA EAX,DWORD PTR SS:[EBP-30]
00502062    50              PUSH EAX
00502063    B9 06000000     MOV ECX,6
00502068    BA 02000000     MOV EDX,2
0050206D    8B45 E4         MOV EAX,DWORD PTR SS:[EBP-1C]
00502070    E8 5327F0FF     CALL Dump.004047C8                ; 取F1( )结果的2到7位"234567"
00502075    8B45 D0         MOV EAX,DWORD PTR SS:[EBP-30]
00502078    E8 7B73F0FF     CALL Dump.004093F8                ; 字符串"234567"转为数值,X=234567
0050207D    8BF0            MOV ESI,EAX
0050207F    8B55 FC         MOV EDX,DWORD PTR SS:[EBP-4]
00502082    B8 94285000     MOV EAX,OFFSET <Dump."-">
00502087    E8 2028F0FF     CALL Dump.004048AC                ; 返回注册码中"-"的位置
0050208C    8BC8            MOV ECX,EAX
0050208E    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00502091    BA 01000000     MOV EDX,1
00502096    E8 6D27F0FF     CALL Dump.00404808                ; 取"-"后的字符串
0050209B    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
0050209E    8B55 FC         MOV EDX,DWORD PTR SS:[EBP-4]
005020A1    E8 8A22F0FF     CALL Dump.00404330                ; ?
005020A6    E9 B9010000     JMP Dump.00502264
005020AB    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]     ; 如果后面还有"-",就从这里继续循环
005020AE    50              PUSH EAX
005020AF    8B55 EC         MOV EDX,DWORD PTR SS:[EBP-14]
005020B2    B8 94285000     MOV EAX,OFFSET <Dump."-">
005020B7    E8 F027F0FF     CALL Dump.004048AC                ; 返回注册码中"-"的位置
005020BC    8BC8            MOV ECX,EAX
005020BE    49              DEC ECX
005020BF    BA 01000000     MOV EDX,1
005020C4    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-14]
005020C7    E8 FC26F0FF     CALL Dump.004047C8                ; 取"-"前的字符串
005020CC    8B45 E8         MOV EAX,DWORD PTR SS:[EBP-18]
005020CF    E8 9424F0FF     CALL Dump.00404568                ; 取字符串长度
005020D4    8BD8            MOV EBX,EAX
005020D6    8BFB            MOV EDI,EBX
005020D8    81E7 FF000000   AND EDI,0FF
005020DE    8B45 E8         MOV EAX,DWORD PTR SS:[EBP-18]
005020E1    0FB64438 FF     MOVZX EAX,BYTE PTR DS:[EAX+EDI-1] ; 取得最后一位
005020E6    83C0 BF         ADD EAX,-41
005020E9    83F8 09         CMP EAX,9
005020EC    0F87 C6000000   JA Dump.005021B8                  ; 不是A-J就跳
005020F2    FF2485 F9205000 JMP NEAR DWORD PTR DS:[EAX*4+5020>
005020F9    2121            AND DWORD PTR DS:[ECX],ESP
005020FB    50              PUSH EAX
005020FC    0033            ADD BYTE PTR DS:[EBX],DH
005020FE    2150 00         AND DWORD PTR DS:[EAX],EDX
00502101    42              INC EDX
00502102    2150 00         AND DWORD PTR DS:[EAX],EDX
00502105    51              PUSH ECX
00502106    2150 00         AND DWORD PTR DS:[EAX],EDX
00502109    60              PUSHAD
0050210A    2150 00         AND DWORD PTR DS:[EAX],EDX
0050210D    6F              OUTS DX,DWORD PTR ES:[EDI]
0050210E    2150 00         AND DWORD PTR DS:[EAX],EDX
00502111    7E 21           JLE SHORT Dump.00502134
00502113    50              PUSH EAX
00502114    008D 2150009C   ADD BYTE PTR SS:[EBP+9C005021],CL
0050211A    2150 00         AND DWORD PTR DS:[EAX],EDX
0050211D    AB              STOS DWORD PTR ES:[EDI]
0050211E    2150 00         AND DWORD PTR DS:[EAX],EDX
00502121    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
00502124    E8 9726F0FF     CALL Dump.004047C0
00502129    C64438 FF 31    MOV BYTE PTR DS:[EAX+EDI-1],31    ; 最后一位是"A"用"1"替换
0050212E    E9 85000000     JMP Dump.005021B8
00502133    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
00502136    E8 8526F0FF     CALL Dump.004047C0
0050213B    C64438 FF 32    MOV BYTE PTR DS:[EAX+EDI-1],32    ; 最后一位是"B"用"2"替换
00502140    EB 76           JMP SHORT Dump.005021B8
00502142    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
00502145    E8 7626F0FF     CALL Dump.004047C0
0050214A    C64438 FF 33    MOV BYTE PTR DS:[EAX+EDI-1],33    ; 最后一位是"C"用"3"替换
0050214F    EB 67           JMP SHORT Dump.005021B8
00502151    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
00502154    E8 6726F0FF     CALL Dump.004047C0
00502159    C64438 FF 34    MOV BYTE PTR DS:[EAX+EDI-1],34    ; 最后一位是"D"用"4"替换
0050215E    EB 58           JMP SHORT Dump.005021B8
00502160    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
00502163    E8 5826F0FF     CALL Dump.004047C0
00502168    C64438 FF 35    MOV BYTE PTR DS:[EAX+EDI-1],35    ; 最后一位是"E"用"5"替换
0050216D    EB 49           JMP SHORT Dump.005021B8
0050216F    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
00502172    E8 4926F0FF     CALL Dump.004047C0
00502177    C64438 FF 36    MOV BYTE PTR DS:[EAX+EDI-1],36    ; 最后一位是"F"用"6"替换
0050217C    EB 3A           JMP SHORT Dump.005021B8
0050217E    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
00502181    E8 3A26F0FF     CALL Dump.004047C0
00502186    C64438 FF 37    MOV BYTE PTR DS:[EAX+EDI-1],37    ; 最后一位是"G"用"7"替换
0050218B    EB 2B           JMP SHORT Dump.005021B8
0050218D    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
00502190    E8 2B26F0FF     CALL Dump.004047C0
00502195    C64438 FF 38    MOV BYTE PTR DS:[EAX+EDI-1],38    ; 最后一位是"H"用"8"替换
0050219A    EB 1C           JMP SHORT Dump.005021B8
0050219C    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
0050219F    E8 1C26F0FF     CALL Dump.004047C0
005021A4    C64438 FF 39    MOV BYTE PTR DS:[EAX+EDI-1],39    ; 最后一位是"I"用"9"替换
005021A9    EB 0D           JMP SHORT Dump.005021B8
005021AB    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
005021AE    E8 0D26F0FF     CALL Dump.004047C0
005021B3    C64438 FF 30    MOV BYTE PTR DS:[EAX+EDI-1],30    ; 最后一位是"J"用"0"替换
005021B8    8D55 CC         LEA EDX,DWORD PTR SS:[EBP-34]     ; 最后一位不是A-J就不替换,跳到这里继续
005021BB    8B45 E8         MOV EAX,DWORD PTR SS:[EBP-18]
005021BE    E8 BDD4FFFF     CALL Dump.004FF680                ; F1(Sni),(i从2到4)
005021C3    8B55 CC         MOV EDX,DWORD PTR SS:[EBP-34]
005021C6    8D45 E8         LEA EAX,DWORD PTR SS:[EBP-18]
005021C9    E8 6221F0FF     CALL Dump.00404330                ; ?
005021CE    8B45 E8         MOV EAX,DWORD PTR SS:[EBP-18]
005021D1    E8 9672F0FF     CALL Dump.0040946C                ; 数字字符串转成数据
005021D6    52              PUSH EDX
005021D7    50              PUSH EAX
005021D8    8BC6            MOV EAX,ESI
005021DA    99              CDQ
005021DB    290424          SUB DWORD PTR SS:[ESP],EAX        ; 扩展为64位,减去X,结果设为a
005021DE    195424 04       SBB DWORD PTR SS:[ESP+4],EDX      ; 扩展是为了准备参与下面的大数运算
005021E2    58              POP EAX
005021E3    5A              POP EDX
005021E4    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
005021E7    8955 F4         MOV DWORD PTR SS:[EBP-C],EDX
005021EA    8B55 EC         MOV EDX,DWORD PTR SS:[EBP-14]
005021ED    B8 94285000     MOV EAX,OFFSET <Dump."-">
005021F2    E8 B526F0FF     CALL Dump.004048AC                ; 返回注册码中"-"的位置
005021F7    8BC8            MOV ECX,EAX
005021F9    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
005021FC    BA 01000000     MOV EDX,1
00502201    E8 0226F0FF     CALL Dump.00404808                ; 取"-"后的字符串
00502206    FF75 F4         PUSH DWORD PTR SS:[EBP-C]
00502209    FF75 F0         PUSH DWORD PTR SS:[EBP-10]
0050220C    FF35 44F35300   PUSH DWORD PTR DS:[53F344]
00502212    FF35 40F35300   PUSH DWORD PTR DS:[53F340]
00502218    FF35 4CF35300   PUSH DWORD PTR DS:[53F34C]
0050221E    FF35 48F35300   PUSH DWORD PTR DS:[53F348]        ; 取运算次数0x1385B
00502224    E8 1BEFFFFF     CALL Dump.00501144                ; a=F2(a),跟进分析实际上是a的0x1385B次方%0x8908D
00502229    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
0050222C    8955 F4         MOV DWORD PTR SS:[EBP-C],EDX
0050222F    FF75 F4         PUSH DWORD PTR SS:[EBP-C]
00502232    FF75 F0         PUSH DWORD PTR SS:[EBP-10]
00502235    8D45 C8         LEA EAX,DWORD PTR SS:[EBP-38]
00502238    E8 6B71F0FF     CALL Dump.004093A8                ; 结果转十进制字符串
0050223D    8B55 C8         MOV EDX,DWORD PTR SS:[EBP-38]
00502240    8D45 E0         LEA EAX,DWORD PTR SS:[EBP-20]
00502243    E8 2823F0FF     CALL Dump.00404570                ; a=与上轮得到的a相连
00502248    8B55 E4         MOV EDX,DWORD PTR SS:[EBP-1C]
0050224B    8B45 E0         MOV EAX,DWORD PTR SS:[EBP-20]
0050224E    E8 5926F0FF     CALL Dump.004048AC                ; F1(Sn1)中有没有上面得到的字符串a
00502253    85C0            TEST EAX,EAX
00502255    75 0D           JNZ SHORT Dump.00502264           ; 有就跳下继续
00502257    33C0            XOR EAX,EAX
00502259    5A              POP EDX
0050225A    59              POP ECX
0050225B    59              POP ECX
0050225C    64:8910         MOV DWORD PTR FS:[EAX],EDX
0050225F    E9 F1050000     JMP Dump.00502855                 ; 没有就跳向试用版
00502264    8B55 EC         MOV EDX,DWORD PTR SS:[EBP-14]
00502267    B8 94285000     MOV EAX,OFFSET <Dump."-">
0050226C    E8 3B26F0FF     CALL Dump.004048AC                ; 返回注册码中"-"的位置
00502271    85C0            TEST EAX,EAX
00502273  ^ 0F8F 32FEFFFF   JG Dump.005020AB                  ; 判断字符串中还有没有"-",有就跳上去循环
00502279    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-14]
0050227C    E8 E722F0FF     CALL Dump.00404568                ; 取字符串长度
00502281    85C0            TEST EAX,EAX
00502283    0F84 8C050000   JE Dump.00502815
00502289    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-14]
0050228C    E8 D722F0FF     CALL Dump.00404568                ; 取字符串长度
00502291    8BD8            MOV EBX,EAX
00502293    8BFB            MOV EDI,EBX
00502295    81E7 FF000000   AND EDI,0FF
0050229B    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-14]
0050229E    0FB64438 FF     MOVZX EAX,BYTE PTR DS:[EAX+EDI-1] ; 取得字符串的最后一位
005022A3    83C0 BF         ADD EAX,-41
005022A6    83F8 09         CMP EAX,9
005022A9    0F87 C6000000   JA Dump.00502375                  ; 不是A-J就跳
005022AF    FF2485 B6225000 JMP NEAR DWORD PTR DS:[EAX*4+5022>
005022B6    DE22            FISUB WORD PTR DS:[EDX]
005022B8    50              PUSH EAX
005022B9    00F0            ADD AL,DH
005022BB    2250 00         AND DL,BYTE PTR DS:[EAX]
005022BE    FF22            JMP NEAR DWORD PTR DS:[EDX]
005022C0    50              PUSH EAX
005022C1    000E            ADD BYTE PTR DS:[ESI],CL
005022C3    2350 00         AND EDX,DWORD PTR DS:[EAX]
005022C6    1D 2350002C     SBB EAX,2C005023
005022CB    2350 00         AND EDX,DWORD PTR DS:[EAX]
005022CE    3B23            CMP ESP,DWORD PTR DS:[EBX]
005022D0    50              PUSH EAX
005022D1    004A 23         ADD BYTE PTR DS:[EDX+23],CL
005022D4    50              PUSH EAX
005022D5    0059 23         ADD BYTE PTR DS:[ECX+23],BL
005022D8    50              PUSH EAX
005022D9    0068 23         ADD BYTE PTR DS:[EAX+23],CH
005022DC    50              PUSH EAX
005022DD    008D 45ECE8DA   ADD BYTE PTR SS:[EBP+DAE8EC45],CL
005022E3    24 F0           AND AL,0F0
005022E5    FFC6            INC ESI
005022E7    44              INC ESP
005022E8    38FF            CMP BH,BH
005022EA    31E9            XOR ECX,EBP
005022EC    8500            TEST DWORD PTR DS:[EAX],EAX
005022EE    0000            ADD BYTE PTR DS:[EAX],AL
005022F0    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
005022F3    E8 C824F0FF     CALL Dump.004047C0
005022F8    C64438 FF 32    MOV BYTE PTR DS:[EAX+EDI-1],32    ; 最后一位是"B"用"2"替换
005022FD    EB 76           JMP SHORT Dump.00502375
005022FF    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
00502302    E8 B924F0FF     CALL Dump.004047C0
00502307    C64438 FF 33    MOV BYTE PTR DS:[EAX+EDI-1],33    ; 最后一位是"C"用"3"替换
0050230C    EB 67           JMP SHORT Dump.00502375
0050230E    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
00502311    E8 AA24F0FF     CALL Dump.004047C0
00502316    C64438 FF 34    MOV BYTE PTR DS:[EAX+EDI-1],34    ; 最后一位是"D"用"4"替换
0050231B    EB 58           JMP SHORT Dump.00502375
0050231D    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
00502320    E8 9B24F0FF     CALL Dump.004047C0
00502325    C64438 FF 35    MOV BYTE PTR DS:[EAX+EDI-1],35    ; 最后一位是"E"用"5"替换
0050232A    EB 49           JMP SHORT Dump.00502375
0050232C    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
0050232F    E8 8C24F0FF     CALL Dump.004047C0
00502334    C64438 FF 36    MOV BYTE PTR DS:[EAX+EDI-1],36    ; 最后一位是"F"用"6"替换
00502339    EB 3A           JMP SHORT Dump.00502375
0050233B    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
0050233E    E8 7D24F0FF     CALL Dump.004047C0
00502343    C64438 FF 37    MOV BYTE PTR DS:[EAX+EDI-1],37    ; 最后一位是"G"用"7"替换
00502348    EB 2B           JMP SHORT Dump.00502375
0050234A    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
0050234D    E8 6E24F0FF     CALL Dump.004047C0
00502352    C64438 FF 38    MOV BYTE PTR DS:[EAX+EDI-1],38    ; 最后一位是"H"用"8"替换
00502357    EB 1C           JMP SHORT Dump.00502375
00502359    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
0050235C    E8 5F24F0FF     CALL Dump.004047C0
00502361    C64438 FF 39    MOV BYTE PTR DS:[EAX+EDI-1],39    ; 最后一位是"I"用"9"替换
00502366    EB 0D           JMP SHORT Dump.00502375
00502368    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
0050236B    E8 5024F0FF     CALL Dump.004047C0
00502370    C64438 FF 30    MOV BYTE PTR DS:[EAX+EDI-1],30    ; 最后一位是"J"用"0"替换
00502375    8D55 C4         LEA EDX,DWORD PTR SS:[EBP-3C]
00502378    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-14]
0050237B    E8 00D3FFFF     CALL Dump.004FF680                ; F1( )
00502380    8B55 C4         MOV EDX,DWORD PTR SS:[EBP-3C]
00502383    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
00502386    E8 A51FF0FF     CALL Dump.00404330                ; ?
0050238B    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-14]
0050238E    E8 D970F0FF     CALL Dump.0040946C                ; 十进制字符串转十六进制数据
00502393    52              PUSH EDX
00502394    50              PUSH EAX
00502395    8BC6            MOV EAX,ESI
00502397    99              CDQ
00502398    290424          SUB DWORD PTR SS:[ESP],EAX        ; 扩展为64位,减去X,结果设为a
0050239B    195424 04       SBB DWORD PTR SS:[ESP+4],EDX      ; 扩展是为了准备参与下面的大数运算
0050239F    58              POP EAX
005023A0    5A              POP EDX
005023A1    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
005023A4    8955 F4         MOV DWORD PTR SS:[EBP-C],EDX
005023A7    A0 ACF35300     MOV AL,BYTE PTR DS:[53F3AC]
005023AC    FEC8            DEC AL
005023AE    74 0D           JE SHORT Dump.005023BD
005023B0    FEC8            DEC AL
005023B2    0F84 DA000000   JE Dump.00502492
005023B8    E9 AA010000     JMP Dump.00502567
005023BD    8D55 C0         LEA EDX,DWORD PTR SS:[EBP-40]
005023C0    B8 A0285000     MOV EAX,Dump.005028A0
005023C5    E8 B6D2FFFF     CALL Dump.004FF680                ; F1( ),解密一些字符串

………………(这里实际是释放一些网络电视的链接地址,有很多,就省略了)

00502637    8D95 64FFFFFF   LEA EDX,DWORD PTR SS:[EBP-9C]
0050263D    B8 14295000     MOV EAX,Dump.00502914
00502642    E8 39D0FFFF     CALL Dump.004FF680                ; F1( ),解密一些字符串
00502647    FFB5 64FFFFFF   PUSH DWORD PTR SS:[EBP-9C]
0050264D    68 D8285000     PUSH Dump.005028D8
00502652    B8 A4F35300     MOV EAX,Dump.0053F3A4
00502657    BA 03000000     MOV EDX,3
0050265C    E8 C71FF0FF     CALL Dump.00404628
00502661    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]      ; 下面就是一个防止爆破的暗桩
00502664    E8 FF1EF0FF     CALL Dump.00404568                ; 取注册码长度
00502669    85C0            TEST EAX,EAX
0050266B    0F8E 43010000   JLE Dump.005027B4
00502671    BB 01000000     MOV EBX,1
00502676    8B55 FC         MOV EDX,DWORD PTR SS:[EBP-4]      ; 开始循环
00502679    8A541A FF       MOV DL,BYTE PTR DS:[EDX+EBX-1]    ; 取注册码的ASC[i]
0050267D    80EA 2D         SUB DL,2D                         ; ASC[i]-0x2D
00502680    0F84 26010000   JE Dump.005027AC                  ; 是"-"就跳
00502686    80C2 FD         ADD DL,0FD
00502689    80EA 0A         SUB DL,0A
0050268C    0F82 1A010000   JB Dump.005027AC                  ; 是数字就跳
00502692    80C2 F9         ADD DL,0F9
00502695    80EA 1A         SUB DL,1A
00502698    0F82 0E010000   JB Dump.005027AC                  ; 是大写字母就跳
0050269E    80C2 FA         ADD DL,0FA
005026A1    80EA 1A         SUB DL,1A
005026A4    0F82 02010000   JB Dump.005027AC                  ; 是小写字母就跳
005026AA    8D95 60FFFFFF   LEA EDX,DWORD PTR SS:[EBP-A0]     ; 注册码中出现上述字符外的其他字符
005026B0    B8 A0285000     MOV EAX,Dump.005028A0             ; 才会跳到下面继续解压字符
005026B5    E8 C6CFFFFF     CALL Dump.004FF680                ; F1( ),解密一些字符串
005026BA    FFB5 60FFFFFF   PUSH DWORD PTR SS:[EBP-A0]
005026C0    8D95 5CFFFFFF   LEA EDX,DWORD PTR SS:[EBP-A4]
005026C6    B8 68295000     MOV EAX,Dump.00502968
005026CB    E8 B0CFFFFF     CALL Dump.004FF680                ; F1( ),解密一些字符串

………………(这里实际是释放一些网络电视的链接地址,有很多,就省略了)
………………(如注册码全是字母,数字和"-",就不释放下面一些链接地址造成网络电视无法正常播放)
………………(如果爆破时忽略这里,即使暴成钻石版,功能依然不全)

0050277A    FFB5 48FFFFFF   PUSH DWORD PTR SS:[EBP-B8]
00502780    8D95 44FFFFFF   LEA EDX,DWORD PTR SS:[EBP-BC]
00502786    B8 B0295000     MOV EAX,Dump.005029B0
0050278B    E8 F0CEFFFF     CALL Dump.004FF680                ; F1( ),解密一些字符串
00502790    FFB5 44FFFFFF   PUSH DWORD PTR SS:[EBP-BC]
00502796    68 D8285000     PUSH Dump.005028D8
0050279B    B8 A4F35300     MOV EAX,Dump.0053F3A4
005027A0    BA 03000000     MOV EDX,3
005027A5    E8 7E1EF0FF     CALL Dump.00404628
005027AA    EB 08           JMP SHORT Dump.005027B4
005027AC    43              INC EBX
005027AD    48              DEC EAX
005027AE  ^ 0F85 C2FEFFFF   JNZ Dump.00502676
005027B4    FF75 F4         PUSH DWORD PTR SS:[EBP-C]
005027B7    FF75 F0         PUSH DWORD PTR SS:[EBP-10]
005027BA    FF35 44F35300   PUSH DWORD PTR DS:[53F344]
005027C0    FF35 40F35300   PUSH DWORD PTR DS:[53F340]
005027C6    FF35 4CF35300   PUSH DWORD PTR DS:[53F34C]
005027CC    FF35 48F35300   PUSH DWORD PTR DS:[53F348]
005027D2    E8 6DE9FFFF     CALL Dump.00501144                ; a=F2(a),大数运算
005027D7    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
005027DA    8955 F4         MOV DWORD PTR SS:[EBP-C],EDX
005027DD    FF75 F4         PUSH DWORD PTR SS:[EBP-C]
005027E0    FF75 F0         PUSH DWORD PTR SS:[EBP-10]
005027E3    8D85 40FFFFFF   LEA EAX,DWORD PTR SS:[EBP-C0]
005027E9    E8 BA6BF0FF     CALL Dump.004093A8                ; 结果转十进制字符串
005027EE    8B95 40FFFFFF   MOV EDX,DWORD PTR SS:[EBP-C0]
005027F4    8D45 E0         LEA EAX,DWORD PTR SS:[EBP-20]
005027F7    E8 741DF0FF     CALL Dump.00404570                ; a=与前面得到的a连接
005027FC    8B55 E4         MOV EDX,DWORD PTR SS:[EBP-1C]
005027FF    8B45 E0         MOV EAX,DWORD PTR SS:[EBP-20]
00502802    E8 A520F0FF     CALL Dump.004048AC                ; F1(Sn1)中有没有上面得到的字符串a
00502807    85C0            TEST EAX,EAX
00502809    75 0A           JNZ SHORT Dump.00502815           ; 有就跳向标准版本或钻石版
0050280B    33C0            XOR EAX,EAX
0050280D    5A              POP EDX
0050280E    59              POP ECX
0050280F    59              POP ECX
00502810    64:8910         MOV DWORD PTR FS:[EAX],EDX
00502813    EB 40           JMP SHORT Dump.00502855           ; 没有就跳向试用版
00502815    8B45 E0         MOV EAX,DWORD PTR SS:[EBP-20]     ; 取得连接得到的a
00502818    8B55 E4         MOV EDX,DWORD PTR SS:[EBP-1C]     ; 取F1(Sn1)
0050281B    E8 941EF0FF     CALL Dump.004046B4                ; 比较是否相同
00502820    75 1A           JNZ SHORT Dump.0050283C           ; 不相同跳向试用版
00502822    8B45 E4         MOV EAX,DWORD PTR SS:[EBP-1C]
00502825    8A40 07         MOV AL,BYTE PTR DS:[EAX+7]        ; F(Sn1)的第8位
00502828    2C 36           SUB AL,36
0050282A    75 09           JNZ SHORT Dump.00502835           ; 不是"6"就跳向标准版
0050282C    C745 F8 0300000>MOV DWORD PTR SS:[EBP-8],3        ; 返回3,钻石版
00502833    EB 07           JMP SHORT Dump.0050283C
00502835    C745 F8 0100000>MOV DWORD PTR SS:[EBP-8],1        ; 返回1,标准版
0050283C    33C0            XOR EAX,EAX
0050283E    5A              POP EDX
0050283F    59              POP ECX
00502840    59              POP ECX
00502841    64:8910         MOV DWORD PTR FS:[EAX],EDX
00502844    EB 0F           JMP SHORT Dump.00502855
00502846  ^ E9 DD10F0FF     JMP Dump.00403928
0050284B    33C0            XOR EAX,EAX
0050284D    8945 F8         MOV DWORD PTR SS:[EBP-8],EAX
00502850    E8 3B14F0FF     CALL Dump.00403C90
00502855    33C0            XOR EAX,EAX                       ; 不经过50282C或502835直接跳到这里就返回0
00502857    5A              POP EDX
00502858    59              POP ECX
00502859    59              POP ECX
0050285A    64:8910         MOV DWORD PTR FS:[EAX],EDX
0050285D    68 82285000     PUSH Dump.00502882
00502862    8D85 40FFFFFF   LEA EAX,DWORD PTR SS:[EBP-C0]
00502868    BA 2C000000     MOV EDX,2C
0050286D    E8 4A1AF0FF     CALL Dump.004042BC
00502872    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
00502875    E8 1E1AF0FF     CALL Dump.00404298
0050287A    C3              RETN

【小结】

因为程序中的跳转比较多,跳转比较远,再加上偶的表达能力很烂,注释写的太乱了,下面把校验流程重写一下了:

注册码不低于30位,分几段,每段长度都没有要求,但是如果一段长度大于8,写F1( )的逆函数会麻烦一些,所以我就分成四段了!

首先将四段假码qoke]SGH-hd^VL@B-ie_WMAC-jf`XNBD的一些位置的字符替换
如果第一段的第5位是"A",第一段的第8位,第2、3、4段的最后一位如果是大写字符,就会进行替换,具体看注释

然后用F1( )转换一下得到12345678-7654321-8765432-9876543

取第一段"12345678"的2到7位"234567"转成数值X(如果转换时有字符不是数字当然会出错)

第二段"7654321"转成数值7654321,然后 F2(7654321-X)=28920,再转成字符串"282920"
第三段"8765432"转成数值8765432,然后 F2(8765432-X)=267072,再转成字符串"267072"
第四段"9876543"转成数值9876543,然后 F2(9876543-X)=336652,再转成字符串"336652"

将上面三个结果连接得到"282920267072336652"再跟第一段"12345678"比较是否相同。

不同就是试用版,相同但第一段的第八位不是"6"则是标准版,是"6"则是钻石版

另外:00502661——005026A4这段代码中有很多跳转,下面的解密一些字符串,其实是释放出一些网络电视的链接地址,如果没有注册码或注册码全是数字,字符,"-"而没有其他字符,就不释放这些链接地址,那么电视当让不能观看。

偶把他解释成防止爆破的暗桩,因为爆破一般是修改跳转或者注册标志,没有注册码或注册码是随意的一些字符数字,不释放出链接地址,即使爆破成钻石版,也看不到网络电视。

----------------------------------------------------------------------------------------
『三』、程序中多次用到的解密函数,即注释中的F1( )

跟进005021BE CALL Dump.004FF680  走几步来到:

004FF6B5    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]
004FF6B8    E8 AB4EF0FF     CALL Dump.00404568                ; 取字符串长度:Len
004FF6BD    8BF0            MOV ESI,EAX
004FF6BF    8BFE            MOV EDI,ESI
004FF6C1    85FF            TEST EDI,EDI
004FF6C3    7E 36           JLE SHORT Dump.004FF6FB
004FF6C5    BB 01000000     MOV EBX,1
004FF6CA    8BC6            MOV EAX,ESI                       ; 循环开始
004FF6CC    F7EE            IMUL ESI                          ; 字符串长度的平方
004FF6CE    8BD3            MOV EDX,EBX
004FF6D0    0FAFD3          IMUL EDX,EBX                      ; i的平方
004FF6D3    2BC2            SUB EAX,EDX                       ; 两个平方结果相减
004FF6D5    40              INC EAX                           ; 加1
004FF6D6    8945 F4         MOV DWORD PTR SS:[EBP-C],EAX
004FF6D9    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
004FF6DC    8B55 FC         MOV EDX,DWORD PTR SS:[EBP-4]
004FF6DF    0FB6541A FF     MOVZX EDX,BYTE PTR DS:[EDX+EBX-1]
004FF6E4    2B55 F4         SUB EDX,DWORD PTR SS:[EBP-C]      ; Asc[i]-上面的结果
004FF6E7    E8 944DF0FF     CALL Dump.00404480                ; 取结果的低8位
004FF6EC    8B55 EC         MOV EDX,DWORD PTR SS:[EBP-14]
004FF6EF    8D45 F0         LEA EAX,DWORD PTR SS:[EBP-10]
004FF6F2    E8 794EF0FF     CALL Dump.00404570
004FF6F7    43              INC EBX
004FF6F8    4F              DEC EDI
004FF6F9  ^ 75 CF           JNZ SHORT Dump.004FF6CA
004FF6FB    8B45 F8         MOV EAX,DWORD PTR SS:[EBP-8]
004FF6FE    8B55 F0         MOV EDX,DWORD PTR SS:[EBP-10]
004FF701    E8 E64BF0FF     CALL Dump.004042EC
004FF706    33C0            XOR EAX,EAX
004FF708    5A              POP EDX
004FF709    59              POP ECX
004FF70A    59              POP ECX
004FF70B    64:8910         MOV DWORD PTR FS:[EAX],EDX
004FF70E    68 30F74F00     PUSH Dump.004FF730
004FF713    8D45 EC         LEA EAX,DWORD PTR SS:[EBP-14]
004FF716    BA 02000000     MOV EDX,2
004FF71B    E8 9C4BF0FF     CALL Dump.004042BC
004FF720    8D45 FC         LEA EAX,DWORD PTR SS:[EBP-4]
004FF723    E8 704BF0FF     CALL Dump.00404298
004FF728    C3              RETN

【小结】

分别对4段注册码的每个字符转换,得到Sn1-Sn2-Sn3-Sn4

Len:各段注册码的长度,i从1到Len

Sn[i]=ASC[i]-(Len*Len-i*i+1);

那么逆过来就是:ASC[i]=Sn[i]+(Len*Len-i*i+1);

另外Len不要超过8位,否则Len*Len太大,导致算号出错。

----------------------------------------------------------------------------------------
『四』、下面看看大数运算部分,即注释中的F2( )

跟进00502224 CALL Dump.00501144

00501180    6A 00           PUSH 0
00501182    6A 02           PUSH 2
00501184    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
00501187    8B55 0C         MOV EDX,DWORD PTR SS:[EBP+C]
0050118A    E8 2D43F0FF     CALL Dump.004054BC                ; 0x1385B/2=0x9C2D
0050118F    8BD8            MOV EBX,EAX
00501191    85DB            TEST EBX,EBX
00501193    76 47           JBE SHORT Dump.005011DC
00501195    FF75 14         PUSH DWORD PTR SS:[EBP+14]
00501198    FF75 10         PUSH DWORD PTR SS:[EBP+10]
0050119B    FF75 1C         PUSH DWORD PTR SS:[EBP+1C]
0050119E    FF75 18         PUSH DWORD PTR SS:[EBP+18]
005011A1    8B45 18         MOV EAX,DWORD PTR SS:[EBP+18]
005011A4    8B55 1C         MOV EDX,DWORD PTR SS:[EBP+1C]
005011A7    E8 EC42F0FF     CALL Dump.00405498                ; b=a*a(大数相乘)

跟进,并走几步
-> 00405498    52              PUSH EDX
-> 00405499    50              PUSH EAX
-> 0040549A    8B4424 10       MOV EAX,DWORD PTR SS:[ESP+10]
-> 0040549E    F72424          MUL DWORD PTR SS:[ESP]          ; 乘
-> 004054A1    89C1            MOV ECX,EAX
-> 004054A3    8B4424 04       MOV EAX,DWORD PTR SS:[ESP+4]
-> 004054A7    F76424 0C       MUL DWORD PTR SS:[ESP+C]        ; 乘
-> 004054AB    01C1            ADD ECX,EAX
-> 004054AD    8B0424          MOV EAX,DWORD PTR SS:[ESP]
-> 004054B0    F76424 0C       MUL DWORD PTR SS:[ESP+C]        ; 乘
-> 004054B4    01CA            ADD EDX,ECX
-> 004054B6    59              POP ECX
-> 004054B7    59              POP ECX
-> 004054B8    C2 0800         RETN 8

005011AC    E8 8743F0FF     CALL Dump.00405538                ; b*(2^64)%0x8908D0000000000000000/(2^64)
005011B1    8945 E8         MOV DWORD PTR SS:[EBP-18],EAX     ; 上面过程简化为:(b*b)%0x8908D
005011B4    8955 EC         MOV DWORD PTR SS:[EBP-14],EDX
005011B7    FF75 14         PUSH DWORD PTR SS:[EBP+14]
005011BA    FF75 10         PUSH DWORD PTR SS:[EBP+10]
005011BD    FF75 F4         PUSH DWORD PTR SS:[EBP-C]
005011C0    FF75 F0         PUSH DWORD PTR SS:[EBP-10]
005011C3    8B45 E8         MOV EAX,DWORD PTR SS:[EBP-18]
005011C6    8B55 EC         MOV EDX,DWORD PTR SS:[EBP-14]
005011C9    E8 CA42F0FF     CALL Dump.00405498                ; b=b*上轮b(大数相乘)
005011CE    E8 6543F0FF     CALL Dump.00405538                ; b=b*(2^64)%0x8908D0000000000000000/(2^64)

跟进,并走几步
-> 0040556B    89CD            MOV EBP,ECX
-> 0040556D    B9 40000000     MOV ECX,40                        ; 循环次数
-> 00405572    57              PUSH EDI
-> 00405573    31FF            XOR EDI,EDI
-> 00405575    31F6            XOR ESI,ESI
-> 00405577    D1E0            SHL EAX,1                         ; 循环开始
-> 00405579    D1D2            RCL EDX,1
-> 0040557B    D1D6            RCL ESI,1
-> 0040557D    D1D7            RCL EDI,1                         ; 用四个32位寄存器保存结果
-> 0040557F    39EF            CMP EDI,EBP
-> 00405581    72 0B           JB SHORT Dump.-> 0040558E
-> 00405583    77 04           JA SHORT Dump.-> 00405589
-> 00405585    39DE            CMP ESI,EBX
-> 00405587    72 05           JB SHORT Dump.-> 0040558E         ; 如果结果的高64位大于0x8908D
-> 00405589    29DE            SUB ESI,EBX
-> 0040558B    19EF            SBB EDI,EBP                       ; 高64位就减去0x8908D
-> 0040558D    40              INC EAX
-> 0040558E  ^ E2 E7           LOOPD SHORT Dump.-> 00405577      ; 64次移位,每次移动一位
-> 00405590    89F0            MOV EAX,ESI
-> 00405592    89FA            MOV EDX,EDI
-> 00405594    5B              POP EBX
-> 00405595    F7C3 01000000   TEST EBX,1
-> 0040559B    74 07           JE SHORT Dump.-> 004055A4
-> 0040559D    F7DA            NEG EDX
-> 0040559F    F7D8            NEG EAX
-> 004055A1    83DA 00         SBB EDX,0
-> 004055A4    5F              POP EDI
-> 004055A5    5E              POP ESI
-> 004055A6    5B              POP EBX
-> 004055A7    5D              POP EBP
-> 004055A8    C2 0800         RETN 8

005011D3    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX     ; 上面过程简化为:b=(b*上轮b)%0x8908D
005011D6    8955 F4         MOV DWORD PTR SS:[EBP-C],EDX      ; 每轮进行两次运算
005011D9    4B              DEC EBX
005011DA  ^ 75 B9           JNZ SHORT Dump.00501195           ; 共循环0x9C2D次
005011DC    8B45 F0         MOV EAX,DWORD PTR SS:[EBP-10]
005011DF    8945 F8         MOV DWORD PTR SS:[EBP-8],EAX
005011E2    8B45 F4         MOV EAX,DWORD PTR SS:[EBP-C]
005011E5    8945 FC         MOV DWORD PTR SS:[EBP-4],EAX
005011E8    8B45 F8         MOV EAX,DWORD PTR SS:[EBP-8]
005011EB    8B55 FC         MOV EDX,DWORD PTR SS:[EBP-4]
005011EE    5B              POP EBX
005011EF    8BE5            MOV ESP,EBP
005011F1    5D              POP EBP
005011F2    C2 1800         RETN 18

【小结】

这个过程是这样的,假设输入a

令b=0x8908D

N1=a ×a % b
N2=N1×a % b
N3=N2×a % b
…………
这样进行0x1385A次

最后结果等于(((a×a % b)×a % b)×a % b )×a % b ………………
共进行0x1385A次 ×a % b

偶经过推导认为这就是:a的0x1385B次方,再对b:0x8908D取余数,返回最后的余数

当让程序肯定不能直接计算 a 的0x1385B次方,数据肯定会溢出

对比一下偶写在算法注册机中的代码:

int CKeygenDlg::Function2(int Sn)
{
        //大数运算,计算Sn的0x1385B次方,然后对0x8908D取余
        int i;
        __int64 bigNum=Sn;
        for(i=0;i<0x1385A;i++){
                bigNum*=Sn;
                bigNum%=0x8908D;
        }
        Sn=(int)bigNum;
        return Sn;
}

另外有两个简单的 F2(0)=0、F2(1)=1,这两个可以在写注册机的时候用到

----------------------------------------------------------------------------------------
【解密过程】

按照『二』中的要求得到一个符合要求的注册码不容易,特别是F2( )不可能被逆向。

F2( )的结果位数不确定,一般都比较长,而注册码各段尽量不超过8位,F2(0)=0、F2(1)=1,可以被用一下。

把『二』中的验证这里再引用一下:

引用:
取第一段"12345678"的2到7位"234567"转成数值X(如果转换时有字符不是数字当然会出错)

第二段"7654321"转成数值7654321,然后 F2(7654321-X)=28920,再转成字符串"282920"
第三段"8765432"转成数值8765432,然后 F2(8765432-X)=267072,再转成字符串"267072"
第四段"9876543"转成数值9876543,然后 F2(9876543-X)=336652,再转成字符串"336652"

将上面三个结果连接得到"282920267072336652"再跟第一段"12345678"比较是否相同。

不同就是试用版,相同但第一段的第八位不是"6"则是标准版,是"6"则是钻石版



Sn3=rand()    ; Sn3取一个随机数
Sn1=Function2(Sn3)  ; Sn2=F2(Sn3),得到Sn1的2到7位
Sn2=Sn1      ; 如果Sn1的第一位是"0",Sn2就等于Sn1的2到7位
Sn3=Sn3+Sn1    ; 得到Sn3
Sn1=Sn2*10+6;    ; Sn1的第八位是"6",第一位是"0"

好了Sn1,Sn2,Sn3都有了,剩下Sn4

我们要找一位数Y,F2(Y)=6;这样才能得到钻石版,如果不要钻石版,F2(Y)=1好了

要得到6不容易啊,最后没法,写了个程序,让Y从1开始穷举,结果Athlon XP 1600+花了近一个小时找到一个279936。F2(279936)=6

哈哈,赶快Sn4=Sn2+279936;

然后分别把Sn1、Sn2、Sn3、Sn4转成字符串,一些位置的字符替换一下,用"-"连接得到注册码了。

----------------------------------------------------------------------------------------
【算法注册机】

Microsoft Visual C++ 6.0写的MFC程序

void CKeygenDlg::OnOK() 
{
        // TODO: Add extra validation here
        //CDialog::OnOK();
        
        char regCode[32];
        int i,Sn1,Sn2,Sn3,Sn4,codeLength;

        m_Edit2="";
        do{
        Sn3 =rand()+90;
        Sn2=Function2(Sn3);
        }while(Sn2<100000);
        Sn3+=Sn2;
        Sn1=Sn2*10+6;
        Sn4=Sn2+279936;

        //得到regCode1
        sprintf(regCode,"%08d",Sn1);
        codeLength=strlen(regCode);     
        for(i=1;i<=codeLength;i++){
                regCode[i-1]=regCode[i-1]+(codeLength*codeLength-i*i+1);
        }
        if(regCode[7]='7') regCode[7]='Z';
        m_Edit2=regCode;
        m_Edit2+="-";
        
        //得到regCode2
        sprintf(regCode,"%07d",Sn2);
        codeLength=strlen(regCode);     
        for(i=1;i<=codeLength;i++){
                regCode[i-1]=regCode[i-1]+(codeLength*codeLength-i*i+1);
        }
        if(regCode[6]>0x30 && regCode[6]<0x3A) regCode[6]+=0x10;
        if(regCode[6]=='0') regCode[6]='J';
        m_Edit2 += regCode;
        m_Edit2+="-";
        
        //得到regCode3
        sprintf(regCode,"%07d",Sn3);
        codeLength=strlen(regCode);     
        for(i=1;i<=codeLength;i++){
                regCode[i-1]=regCode[i-1]+(codeLength*codeLength-i*i+1);
        }
        if(regCode[6]>0x30 && regCode[6]<0x3A) regCode[6]+=0x10;
        if(regCode[6]=='0') regCode[6]='J';
        m_Edit2 += regCode;
        m_Edit2+="-";
        
        //得到regCode4
        sprintf(regCode,"%07d",Sn4);
        codeLength=strlen(regCode);     
        for(i=1;i<=codeLength;i++){
                regCode[i-1]=regCode[i-1]+(codeLength*codeLength-i*i+1);
        }
        if(regCode[6]>0x30 && regCode[6]<0x3A) regCode[6]+=0x10;
        if(regCode[6]=='0') regCode[6]='J';
        m_Edit2 += regCode;
        
        UpdateData(false);
}

int CKeygenDlg::Function2(int Sn)
{
        //大数运算,计算Sn的0x1385B次方,然后对0x8908D取余
        int i;
        __int64 bigNum=Sn;
        for(i=0;i<0x1385A;i++){
                bigNum*=Sn;
                bigNum%=0x8908D;
        }
        Sn=(int)bigNum;
        return Sn;
}

----------------------------------------------------------------------------------------
【破解心得】

程序中用到了128位数值运算,是非常常见得X^Y%Z运算,大数计算器中也有X^Y%Z,可见所有的大数计算在计算机中都是32位运算,这只是个简单的例子,还有很多更为复杂的。数学真是奇妙。

另外,程序中共有四处调用user、serial、config.lss等字符串,偶看了一下:

一处是保存注册码用
一处是取注册码验证用
一处是验证不成功删除保存的注册码用

还有一处,从来没有断下过,有什么用没看出来,会不会又是一个暗桩要等着我去发现。

----------------------------------------------------------------------------------------
【破解声明】

   我是一只小菜鸟,偶得一点心得,愿与大家分享:)

【版权声明】   本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢! 
----------------------------------------------------------------------------------------
                                                                 文章写于2005-11-1 12:07:34