-
-
[原创][分享]VeryPDF PDF2Word v3.0 算法分析详细过程以及注册机汇编源码关键部分
-
发表于: 2011-5-20 16:40 2784
-
对于本软件注册算法的分析坛友已经发布过,本来没必要再行发帖,不过本人所写的分析更为详细,对于入门级的爱好者或许是一篇不错的引领入门的帖子。
【破文标题】VeryPDF PDF2Word v3.0 算法分析详细过程+注册机汇编源码关键部分
【破文作者】网络浪子(netprodiag)
【作者邮箱】netprodiag@163.com
【破解平台】Win7 SP1
【破解工具】PEiD0.95、OllyICE
【作者邮箱】piaoyun04@163.com
【软件名称】VeryPDF PDF Editor v3.0
【原版下载】http://dl.verypdf.net/pdf2word.exe
一、准备工作
用 PEiD v0.95 査壳,显示 UPX 0.89.6 - 1.02 / 1.05 - 2.90 -> Markus & Laszlo,用 Pexplorer 打开后直接保存就可以完美脱壳。再次用 PEiD v0.95 査壳,显示 Microsoft Visual C++ 6.0,查
看节段以及用 OllyICE 载入,确定再无其它壳。启动脱壳后的程序,提示输入 E-mail 以及 Registration Key,任意输入符合 E-mail 格式的 E-mail 以及注册码,弹出“Your registration key is
wrong……”,既然有错误提示的对话框,可以采用“查找所有参考的字符串法、F12 暂停调用栈法以及对创建对话框和消息框相关的下断点的方法,至于选择哪一种取决于要看哪种能适用并快速定位关键处以
及你能适用的前提下个人的喜好而定。
二、定位关键 call
1、用 OllyICE 载入程序,输入试炼注册信息,我这里采用 F12 暂停调用栈法然后采用回溯定位关键处:
00406676 > \8BB424 E80000>mov esi, dword ptr [esp+E8] ; Case 1 of switch 004065D8
0040667D . 68 C8000000 push 0C8 ; /Count = C8 (200.)
00406682 . B9 32000000 mov ecx, 32 ; |
00406687 . 33C0 xor eax, eax ; |
00406689 . BF F0617F00 mov edi, 007F61F0 ; |ASCII "cracker987654321"
0040668E . 68 F0617F00 push 007F61F0 ; |Buffer = pdf2word.007F61F0
00406693 . 68 FB030000 push 3FB ; |ControlID = 3FB (1019.)
00406698 . 56 push esi ; |hWnd = 00B55F00
00406699 . F3:AB rep stos dword ptr es:[edi] ; |
0040669B . FF15 F8855B00 call dword ptr [<&USER32.GetDlgItemTe>; \GetDlgItemTextA
004066A1 . 68 F0617F00 push 007F61F0 ; ASCII "cracker987654321"
004066A6 . E8 95F8FFFF call 00405F40
004066AB . 83C4 04 add esp, 4
004066AE . 85C0 test eax, eax
004066B0 . 74 44 je short 004066F6
004066B2 . 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004066B4 . 68 B42A5E00 push 005E2AB4 ; |Title = "Thank you."
004066B9 . 68 882A5E00 push 005E2A88 ; |Text = "Thank you registered VeryPDF PDF2Word v3.0."
004066BE . 56 push esi ; |hOwner = 00B55F00
由上面的代码片段分析可知,在地址 0040669B 通过调用 API 函数 GetDlgItemTextA 获取输入的注册信息,仅此一处获取输入的试炼注册码,说明本程序的注册验证仅与注册码有关,与 E-mail 无关
,即只要注册码正确,E-mail 可以任意。再看地址 004066B9 处有提示注册成功的字符串信息“Thank you registered VeryPDF PDF2Word v3.0.”以及综合其上面地址 004066B0 处得跳转指令 je 可
知,这是一个关键的跳转,其上一句地址 004066AE 处的指令为 test eax,eax,说明 下一句跳转指令 je 是根据 eax 的值来判断,那 eax 的值来自哪里,就是通过地址 004066A6 处的指令 call
00405F40 来返回 eax 的值,最后看地址 00406689 处的指令 push 007F61F0(虚拟内存地址 007F61F0 就是 GetDlgItemTextA 函数获取注册窗口中静态文本框 Registration Key 所对应的注册码编辑
框内容的存放地址,而又在地址 004066A1 处使用 push 007F61F0 紧接着使用指令 call 00405F40,即存放获取的注册码的内容的内存地址 007F61F0 是作为注册验证过程的参数传入的),由此可知,
地址 004066A6 处的指令 call 00405F40 是注册码的验证 call,至此,我们已经确定了 call 00405F40 是关键的 call.
2、注册码验证分析
经过上面 “1”的分析,我们用 F7 单步进入验证 call 分析其算法
00405F40 /$ 83EC 18 sub esp, 18 ; 验证算法入口,预留栈空间 4*24(0x18=24)=96 字节,因为 Win32 程序的栈结构决定单位大小为 4 字节。
00405F43 |. 83C9 FF or ecx, FFFFFFFF ; ecx=-1(典型的通过置 ecx=-1 并结合 scas 指令计算字串长度的指令片段法)
00405F46 |. 33C0 xor eax, eax ; eax=0
00405F48 |. 53 push ebx
00405F49 |. 56 push esi
00405F4A |. 8B7424 24 mov esi, dword ptr [esp+24] ; 输入注册码的首址,即通过代码片段“1”中地址 004066A1 处的指令 push 007F61F0 传入的参数
00405F4E |. 57 push edi ; pdf2word.007F62B8
00405F4F |. 8BFE mov edi, esi ; 输入注册码的首址赋给 edi,结果 edi 也指向了输入的注册码的缓冲区首址
00405F51 |. F2:AE repne scas byte ptr es:[edi] ; 当 edi 指向的内存中的字符串尚未结束时,因为 scas 的作用是取出 edi 指向的字符串的一个字符并与 eax 比较,,如果与
eax 的值不等,则继续检测下一个字符,由于通过上面的 xor eax,eax,已经将 eax 清零,所以相当于检测字符串是否结束
00405F53 |. F7D1 not ecx
00405F55 |. 49 dec ecx ; 求出输入注册码的长度,上面的指令段就是计算字串长度的一种方法
00405F56 |. 83F9 14 cmp ecx, 14 ; 与0x14,即与十进制的 20 比较
00405F59 |. 74 07 je short 00405F62 ; 不跳则注册失败,说明注册码长度必须为 20 位
00405F5B |. 5F pop edi ; pdf2word.007F62B8
00405F5C |. 5E pop esi
00405F5D |. 5B pop ebx
00405F5E |. 83C4 18 add esp, 18
00405F61 |. C3 retn
00405F62 |> 8A06 mov al, byte ptr [esi] ; 取 Key[0] 到 al 中
00405F64 |. 8A4E 01 mov cl, byte ptr [esi+1] ; 取 Key[1] 到 cl 中
00405F67 |. 8D5424 0C lea edx, dword ptr [esp+C]
00405F6B |. 32DB xor bl, bl
00405F6D |. 52 push edx
00405F6E |. 884424 1C mov byte ptr [esp+1C], al
00405F72 |. 885C24 1D mov byte ptr [esp+1D], bl
00405F76 |. 884C24 10 mov byte ptr [esp+10], cl
00405F7A |. 885C24 11 mov byte ptr [esp+11], bl
00405F7E |. E8 C4A61800 call 00590647
00405F83 |. 8BF8 mov edi, eax
00405F85 |. 8D4424 1C lea eax, dword ptr [esp+1C]
00405F89 |. 50 push eax
00405F8A |. E8 B8A61800 call 00590647
00405F8F |. 03F8 add edi, eax ; edi=key[0]+Key[1]
00405F91 |. 83C4 08 add esp, 8
00405F94 |. 83FF 0B cmp edi, 0B ; key[0]+Key[1]=11,0xB=11
00405F97 |. 74 09 je short 00405FA2
00405F99 |. 5F pop edi ; pdf2word.007F62B8
00405F9A |. 5E pop esi
00405F9B |. 33C0 xor eax, eax
00405F9D |. 5B pop ebx
00405F9E |. 83C4 18 add esp, 18
00405FA1 |. C3 retn
00405FA2 |> 8A4E 12 mov cl, byte ptr [esi+12] ; cl=Key[18],0x12=18
00405FA5 |. 8A56 13 mov dl, byte ptr [esi+13] ; dl=Key[19],0x13=19
00405FA8 |. 8D4424 0C lea eax, dword ptr [esp+C]
00405FAC |. 884C24 18 mov byte ptr [esp+18], cl
00405FB0 |. 50 push eax
00405FB1 |. 885C24 1D mov byte ptr [esp+1D], bl
00405FB5 |. 885424 10 mov byte ptr [esp+10], dl
00405FB9 |. 885C24 11 mov byte ptr [esp+11], bl
00405FBD |. E8 85A61800 call 00590647
00405FC2 |. 8D4C24 1C lea ecx, dword ptr [esp+1C]
00405FC6 |. 8BF8 mov edi, eax
00405FC8 |. 51 push ecx
00405FC9 |. E8 79A61800 call 00590647
00405FCE |. 03F8 add edi, eax ; edi=Key[18]+Key[19]
00405FD0 |. 83C4 08 add esp, 8
00405FD3 |. 83FF 0D cmp edi, 0D ; key[18]+Key[19]=13,0xD=13
00405FD6 |. 74 09 je short 00405FE1
00405FD8 |. 5F pop edi ; pdf2word.007F62B8
00405FD9 |. 5E pop esi
00405FDA |. 33C0 xor eax, eax
00405FDC |. 5B pop ebx
00405FDD |. 83C4 18 add esp, 18
00405FE0 |. C3 retn
00405FE1 |> 8A56 05 mov dl, byte ptr [esi+5] ; dl=Key[5]
00405FE4 |. 8A46 0D mov al, byte ptr [esi+D] ; al=Key[13]
00405FE7 |. 8D4C24 0C lea ecx, dword ptr [esp+C]
00405FEB |. 885424 18 mov byte ptr [esp+18], dl
00405FEF |. 51 push ecx
00405FF0 |. 885C24 1D mov byte ptr [esp+1D], bl
00405FF4 |. 884424 10 mov byte ptr [esp+10], al
00405FF8 |. 885C24 11 mov byte ptr [esp+11], bl
00405FFC |. E8 46A61800 call 00590647
00406001 |. 8D5424 1C lea edx, dword ptr [esp+1C]
00406005 |. 8BF8 mov edi, eax
00406007 |. 52 push edx
00406008 |. E8 3AA61800 call 00590647
0040600D |. 03F8 add edi, eax ; edi=Key[5]+Key[13]
0040600F |. 83C4 08 add esp, 8
00406012 |. 83FF 09 cmp edi, 9 ; Key[5]+Key[13]=9
00406015 |. 74 09 je short 00406020
00406017 |. 5F pop edi ; pdf2word.007F62B8
00406018 |. 5E pop esi
00406019 |. 33C0 xor eax, eax
0040601B |. 5B pop ebx
0040601C |. 83C4 18 add esp, 18
0040601F |. C3 retn
00406020 |> 807E 0C 56 cmp byte ptr [esi+C], 56 ; Key[12]='V',大写的字母 V,因为 56 表示字符时代表大写的字母 V
00406024 |. 74 09 je short 0040602F
00406026 |. 5F pop edi ; pdf2word.007F62B8
00406027 |. 5E pop esi
00406028 |. 33C0 xor eax, eax
0040602A |. 5B pop ebx
0040602B |. 83C4 18 add esp, 18
0040602E |. C3 retn
0040602F |> 807E 0E 33 cmp byte ptr [esi+E], 33 ; Key[14]='3',因为 33 表示字符时代表数字 3
00406033 |. 74 09 je short 0040603E
00406035 |. 5F pop edi ; pdf2word.007F62B8
00406036 |. 5E pop esi
00406037 |. 33C0 xor eax, eax
00406039 |. 5B pop ebx
0040603A |. 83C4 18 add esp, 18
0040603D |. C3 retn
0040603E |> 8A4E 0F mov cl, byte ptr [esi+F] ; cl=Key[15]
00406041 |. 33C0 xor eax, eax
00406043 |. 80F9 31 cmp cl, 31 ; Key[15]='1'
00406046 |. 5F pop edi ; pdf2word.007F62B8
00406047 |. 5E pop esi
00406048 |. 5B pop ebx
00406049 |. 0F94C0 sete al ; 如果满足以上条件则将 al 的值置为 1
0040604C |. 83C4 18 add esp, 18
0040604F \. C3 retn ; 验证完毕返回 al 的值来确定跳转到注册成功或失败的流程处理模块处
【算法总结】
注册码长度必须为 20 位并满足以下条件:
1、key[0]+Key[1]=11
2、key[18]+Key[19]=13
3、Key[5]+Key[13]=9
4、Key[12]='V'
5、Key[14]='3'
6、Key[15]='1'
6.其他位为任意字符
注册成功会在安装文件夹下的 config.ini 中写入 Regcode=正确的注册码字符串,如果想重新注册可以删除 Regcode 那行或删除=后正确的注册码字符串;如果想以试用模式使用并无限次使用试用模式,
只需在 config.ini 中写入一行,Used=0,=后面的数表示已试用的次数,最大试用次数为 100。
【注册机汇编源码】
.const
MAXSIZE equ 20
.data
szFormat db '%s',0 ;注册码输出格式为字符串格式
szConstTable db '0123456789abcdefghijklmnopqrstuvwxyz',0 ;限定注册码中可以使用的字符
RegCodeBuffer db MAXSIZE dup(0),0 ;存放注册码缓冲区,20 位注册码再加上一个字符串结束符 0
;##########定义结构开始##################
_LARGE_INTEGER struct
LowPart dd ?
HighPart dd ?
_LARGE_INTEGER ends
;##########定义结构结束##################
.code
GenRandProc proc uses ecx edx First:DWORD,Second:DWORD
Local c1:_LARGE_INTEGER,c2:_LARGE_INTEGER
;rdtsc ;(多核处理器中已经不准确,因此不再使用)
;invoke GetTickCount ; 取得随机数种子,当然,可用别的方法代替
invoke QueryPerformanceCounter,addr c1
mov eax,c2.LowPart
sub eax,c1.LowPart
mov edx,c2.HighPart
sbb edx,c1.HighPart
sub eax,edx ;eax 中返回随机数种子
mov ecx,23
mul ecx
add eax,7
mov ecx,Second
sub ecx,First
inc ecx
xor edx,edx
div ecx
add edx,First
mov eax,edx
ret
GenRandProc endp
;=================================================
;注册算法:
注册码长度必须为 20 位并满足以下条件:
1、key[0]+Key[1]=11
2、key[18]+Key[19]=13
3、Key[5]+Key[13]=9
4、Key[12]='V'
5、Key[14]='3'
6、Key[15]='1'
6.其他位为任意字符
;代码编写:网络浪子(netprodiag@163.com)
;=================================================
KeyGenProc proc
LOCAL @szKey[MAXSIZE+1]:BYTE;多定义一个字节空间,确保在注册码缓冲区中最后插入一个结束符 0,~ 否则出问题
LOCAL @szOut[MAXSIZE+1]:BYTE
invoke RtlZeroMemory,addr @szOut,sizeof @szOut ;使用局部变量前一定要先初始化后再使用,否则出现意想不到的严重后果。通过 RtlZeroMemory API 函数将局部变量指向的内存域清空为零
invoke RtlZeroMemory,addr @szKey,sizeof @szKey ;相当于将局部变量初始化为零
xor eax,eax
xor ecx,ecx
xor edx,edx
;KEY[0]
invoke _Rand,2,9
movzx edx,byte ptr [szConstTable+eax]
mov byte ptr[@szKey + 0],dl
;计算KEY[1]
mov edx,11
sub edx,eax
movzx edx,byte ptr [szConstTable+edx]
mov byte ptr[@szKey + 1],dl
;KEY[18]
invoke _Rand,4,9
movzx edx,byte ptr [szConstTable+eax]
mov byte ptr[@szKey + 18],dl
;计算KEY[19]
mov edx,13
sub edx,eax
movzx edx,byte ptr [szConstTable+edx]
mov byte ptr[@szKey + 19],dl
;KEY[5]
invoke _Rand,0,9
movzx edx,byte ptr [szConstTable+eax]
mov byte ptr[@szKey + 5],dl
;计算KEY[13]
mov edx,9
sub edx,eax
movzx edx,byte ptr [szConstTable+edx]
mov byte ptr[@szKey + 13],dl
;计算 Key[12]、Key[14]、Key[15]
mov byte ptr[@szKey + 12],50h ;'V'
mov byte ptr[@szKey + 14],44h ;'3'
mov byte ptr[@szKey + 15],46h ;'1'
;计算 Key[3]、Key[4]、Key[6]、Key[7]、Key[8]、Key[9]、Key[10]、Key[11]、Key[16]、Key[17]
mov ecx,2 ;直接通过 ecx=2 排除掉 Key[0]、Key[1]
LConcalculate:
invoke _Rand,0,sizeof szConstTable-2;sizeof szConstTable 得到 szConstTable 的字节大小为 21(包含字符串定义结束符 0),然后-2得到 szConstTable 数组的最大索引号为 19
movzx edx,byte ptr [szConstTable+eax] ;本身应该通过求字符串长度的方法来确定索引号,但由于数组 szConstTable 被定义为 db 类型,因此字符串长度与字节数一致,所以可以替代。
;这里采用排除法来间接计算上面注释中提及的 Key 组,即排除掉 Key 中索引号对应的位置字符为非任意字符的情形,其它位置用 szConstTable 数据中的随机获取的字符填充。
cmp edx,5 ;如果为 key[5],即注册码中的第 6 个位置,则直接跳过继续下一位
je @f
cmp edx,12
je @f
cmp edx,13
je @f
cmp edx,14
je @f
cmp edx,15
je @f
cmp edx,18
je @f
cmp edx,19
je @f
mov byte ptr[@szKey + ecx],dl
@@:
inc ecx
cmp ecx,21
jl LConcalculate ;如果 Key 位尚未填充完则跳回继续填充
invoke lstrcat,addr @szOut,addr @szKey ;连接字符串
lea eax,@szOut
invoke wsprintf,addr RegCodeBuffer,addr szFormat,eax ;格式化注册码字符串
lea eax,RegCodeBuffer
ret
KeyGenProc endp
【破文标题】VeryPDF PDF2Word v3.0 算法分析详细过程+注册机汇编源码关键部分
【破文作者】网络浪子(netprodiag)
【作者邮箱】netprodiag@163.com
【破解平台】Win7 SP1
【破解工具】PEiD0.95、OllyICE
【作者邮箱】piaoyun04@163.com
【软件名称】VeryPDF PDF Editor v3.0
【原版下载】http://dl.verypdf.net/pdf2word.exe
一、准备工作
用 PEiD v0.95 査壳,显示 UPX 0.89.6 - 1.02 / 1.05 - 2.90 -> Markus & Laszlo,用 Pexplorer 打开后直接保存就可以完美脱壳。再次用 PEiD v0.95 査壳,显示 Microsoft Visual C++ 6.0,查
看节段以及用 OllyICE 载入,确定再无其它壳。启动脱壳后的程序,提示输入 E-mail 以及 Registration Key,任意输入符合 E-mail 格式的 E-mail 以及注册码,弹出“Your registration key is
wrong……”,既然有错误提示的对话框,可以采用“查找所有参考的字符串法、F12 暂停调用栈法以及对创建对话框和消息框相关的下断点的方法,至于选择哪一种取决于要看哪种能适用并快速定位关键处以
及你能适用的前提下个人的喜好而定。
二、定位关键 call
1、用 OllyICE 载入程序,输入试炼注册信息,我这里采用 F12 暂停调用栈法然后采用回溯定位关键处:
00406676 > \8BB424 E80000>mov esi, dword ptr [esp+E8] ; Case 1 of switch 004065D8
0040667D . 68 C8000000 push 0C8 ; /Count = C8 (200.)
00406682 . B9 32000000 mov ecx, 32 ; |
00406687 . 33C0 xor eax, eax ; |
00406689 . BF F0617F00 mov edi, 007F61F0 ; |ASCII "cracker987654321"
0040668E . 68 F0617F00 push 007F61F0 ; |Buffer = pdf2word.007F61F0
00406693 . 68 FB030000 push 3FB ; |ControlID = 3FB (1019.)
00406698 . 56 push esi ; |hWnd = 00B55F00
00406699 . F3:AB rep stos dword ptr es:[edi] ; |
0040669B . FF15 F8855B00 call dword ptr [<&USER32.GetDlgItemTe>; \GetDlgItemTextA
004066A1 . 68 F0617F00 push 007F61F0 ; ASCII "cracker987654321"
004066A6 . E8 95F8FFFF call 00405F40
004066AB . 83C4 04 add esp, 4
004066AE . 85C0 test eax, eax
004066B0 . 74 44 je short 004066F6
004066B2 . 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004066B4 . 68 B42A5E00 push 005E2AB4 ; |Title = "Thank you."
004066B9 . 68 882A5E00 push 005E2A88 ; |Text = "Thank you registered VeryPDF PDF2Word v3.0."
004066BE . 56 push esi ; |hOwner = 00B55F00
由上面的代码片段分析可知,在地址 0040669B 通过调用 API 函数 GetDlgItemTextA 获取输入的注册信息,仅此一处获取输入的试炼注册码,说明本程序的注册验证仅与注册码有关,与 E-mail 无关
,即只要注册码正确,E-mail 可以任意。再看地址 004066B9 处有提示注册成功的字符串信息“Thank you registered VeryPDF PDF2Word v3.0.”以及综合其上面地址 004066B0 处得跳转指令 je 可
知,这是一个关键的跳转,其上一句地址 004066AE 处的指令为 test eax,eax,说明 下一句跳转指令 je 是根据 eax 的值来判断,那 eax 的值来自哪里,就是通过地址 004066A6 处的指令 call
00405F40 来返回 eax 的值,最后看地址 00406689 处的指令 push 007F61F0(虚拟内存地址 007F61F0 就是 GetDlgItemTextA 函数获取注册窗口中静态文本框 Registration Key 所对应的注册码编辑
框内容的存放地址,而又在地址 004066A1 处使用 push 007F61F0 紧接着使用指令 call 00405F40,即存放获取的注册码的内容的内存地址 007F61F0 是作为注册验证过程的参数传入的),由此可知,
地址 004066A6 处的指令 call 00405F40 是注册码的验证 call,至此,我们已经确定了 call 00405F40 是关键的 call.
2、注册码验证分析
经过上面 “1”的分析,我们用 F7 单步进入验证 call 分析其算法
00405F40 /$ 83EC 18 sub esp, 18 ; 验证算法入口,预留栈空间 4*24(0x18=24)=96 字节,因为 Win32 程序的栈结构决定单位大小为 4 字节。
00405F43 |. 83C9 FF or ecx, FFFFFFFF ; ecx=-1(典型的通过置 ecx=-1 并结合 scas 指令计算字串长度的指令片段法)
00405F46 |. 33C0 xor eax, eax ; eax=0
00405F48 |. 53 push ebx
00405F49 |. 56 push esi
00405F4A |. 8B7424 24 mov esi, dword ptr [esp+24] ; 输入注册码的首址,即通过代码片段“1”中地址 004066A1 处的指令 push 007F61F0 传入的参数
00405F4E |. 57 push edi ; pdf2word.007F62B8
00405F4F |. 8BFE mov edi, esi ; 输入注册码的首址赋给 edi,结果 edi 也指向了输入的注册码的缓冲区首址
00405F51 |. F2:AE repne scas byte ptr es:[edi] ; 当 edi 指向的内存中的字符串尚未结束时,因为 scas 的作用是取出 edi 指向的字符串的一个字符并与 eax 比较,,如果与
eax 的值不等,则继续检测下一个字符,由于通过上面的 xor eax,eax,已经将 eax 清零,所以相当于检测字符串是否结束
00405F53 |. F7D1 not ecx
00405F55 |. 49 dec ecx ; 求出输入注册码的长度,上面的指令段就是计算字串长度的一种方法
00405F56 |. 83F9 14 cmp ecx, 14 ; 与0x14,即与十进制的 20 比较
00405F59 |. 74 07 je short 00405F62 ; 不跳则注册失败,说明注册码长度必须为 20 位
00405F5B |. 5F pop edi ; pdf2word.007F62B8
00405F5C |. 5E pop esi
00405F5D |. 5B pop ebx
00405F5E |. 83C4 18 add esp, 18
00405F61 |. C3 retn
00405F62 |> 8A06 mov al, byte ptr [esi] ; 取 Key[0] 到 al 中
00405F64 |. 8A4E 01 mov cl, byte ptr [esi+1] ; 取 Key[1] 到 cl 中
00405F67 |. 8D5424 0C lea edx, dword ptr [esp+C]
00405F6B |. 32DB xor bl, bl
00405F6D |. 52 push edx
00405F6E |. 884424 1C mov byte ptr [esp+1C], al
00405F72 |. 885C24 1D mov byte ptr [esp+1D], bl
00405F76 |. 884C24 10 mov byte ptr [esp+10], cl
00405F7A |. 885C24 11 mov byte ptr [esp+11], bl
00405F7E |. E8 C4A61800 call 00590647
00405F83 |. 8BF8 mov edi, eax
00405F85 |. 8D4424 1C lea eax, dword ptr [esp+1C]
00405F89 |. 50 push eax
00405F8A |. E8 B8A61800 call 00590647
00405F8F |. 03F8 add edi, eax ; edi=key[0]+Key[1]
00405F91 |. 83C4 08 add esp, 8
00405F94 |. 83FF 0B cmp edi, 0B ; key[0]+Key[1]=11,0xB=11
00405F97 |. 74 09 je short 00405FA2
00405F99 |. 5F pop edi ; pdf2word.007F62B8
00405F9A |. 5E pop esi
00405F9B |. 33C0 xor eax, eax
00405F9D |. 5B pop ebx
00405F9E |. 83C4 18 add esp, 18
00405FA1 |. C3 retn
00405FA2 |> 8A4E 12 mov cl, byte ptr [esi+12] ; cl=Key[18],0x12=18
00405FA5 |. 8A56 13 mov dl, byte ptr [esi+13] ; dl=Key[19],0x13=19
00405FA8 |. 8D4424 0C lea eax, dword ptr [esp+C]
00405FAC |. 884C24 18 mov byte ptr [esp+18], cl
00405FB0 |. 50 push eax
00405FB1 |. 885C24 1D mov byte ptr [esp+1D], bl
00405FB5 |. 885424 10 mov byte ptr [esp+10], dl
00405FB9 |. 885C24 11 mov byte ptr [esp+11], bl
00405FBD |. E8 85A61800 call 00590647
00405FC2 |. 8D4C24 1C lea ecx, dword ptr [esp+1C]
00405FC6 |. 8BF8 mov edi, eax
00405FC8 |. 51 push ecx
00405FC9 |. E8 79A61800 call 00590647
00405FCE |. 03F8 add edi, eax ; edi=Key[18]+Key[19]
00405FD0 |. 83C4 08 add esp, 8
00405FD3 |. 83FF 0D cmp edi, 0D ; key[18]+Key[19]=13,0xD=13
00405FD6 |. 74 09 je short 00405FE1
00405FD8 |. 5F pop edi ; pdf2word.007F62B8
00405FD9 |. 5E pop esi
00405FDA |. 33C0 xor eax, eax
00405FDC |. 5B pop ebx
00405FDD |. 83C4 18 add esp, 18
00405FE0 |. C3 retn
00405FE1 |> 8A56 05 mov dl, byte ptr [esi+5] ; dl=Key[5]
00405FE4 |. 8A46 0D mov al, byte ptr [esi+D] ; al=Key[13]
00405FE7 |. 8D4C24 0C lea ecx, dword ptr [esp+C]
00405FEB |. 885424 18 mov byte ptr [esp+18], dl
00405FEF |. 51 push ecx
00405FF0 |. 885C24 1D mov byte ptr [esp+1D], bl
00405FF4 |. 884424 10 mov byte ptr [esp+10], al
00405FF8 |. 885C24 11 mov byte ptr [esp+11], bl
00405FFC |. E8 46A61800 call 00590647
00406001 |. 8D5424 1C lea edx, dword ptr [esp+1C]
00406005 |. 8BF8 mov edi, eax
00406007 |. 52 push edx
00406008 |. E8 3AA61800 call 00590647
0040600D |. 03F8 add edi, eax ; edi=Key[5]+Key[13]
0040600F |. 83C4 08 add esp, 8
00406012 |. 83FF 09 cmp edi, 9 ; Key[5]+Key[13]=9
00406015 |. 74 09 je short 00406020
00406017 |. 5F pop edi ; pdf2word.007F62B8
00406018 |. 5E pop esi
00406019 |. 33C0 xor eax, eax
0040601B |. 5B pop ebx
0040601C |. 83C4 18 add esp, 18
0040601F |. C3 retn
00406020 |> 807E 0C 56 cmp byte ptr [esi+C], 56 ; Key[12]='V',大写的字母 V,因为 56 表示字符时代表大写的字母 V
00406024 |. 74 09 je short 0040602F
00406026 |. 5F pop edi ; pdf2word.007F62B8
00406027 |. 5E pop esi
00406028 |. 33C0 xor eax, eax
0040602A |. 5B pop ebx
0040602B |. 83C4 18 add esp, 18
0040602E |. C3 retn
0040602F |> 807E 0E 33 cmp byte ptr [esi+E], 33 ; Key[14]='3',因为 33 表示字符时代表数字 3
00406033 |. 74 09 je short 0040603E
00406035 |. 5F pop edi ; pdf2word.007F62B8
00406036 |. 5E pop esi
00406037 |. 33C0 xor eax, eax
00406039 |. 5B pop ebx
0040603A |. 83C4 18 add esp, 18
0040603D |. C3 retn
0040603E |> 8A4E 0F mov cl, byte ptr [esi+F] ; cl=Key[15]
00406041 |. 33C0 xor eax, eax
00406043 |. 80F9 31 cmp cl, 31 ; Key[15]='1'
00406046 |. 5F pop edi ; pdf2word.007F62B8
00406047 |. 5E pop esi
00406048 |. 5B pop ebx
00406049 |. 0F94C0 sete al ; 如果满足以上条件则将 al 的值置为 1
0040604C |. 83C4 18 add esp, 18
0040604F \. C3 retn ; 验证完毕返回 al 的值来确定跳转到注册成功或失败的流程处理模块处
【算法总结】
注册码长度必须为 20 位并满足以下条件:
1、key[0]+Key[1]=11
2、key[18]+Key[19]=13
3、Key[5]+Key[13]=9
4、Key[12]='V'
5、Key[14]='3'
6、Key[15]='1'
6.其他位为任意字符
注册成功会在安装文件夹下的 config.ini 中写入 Regcode=正确的注册码字符串,如果想重新注册可以删除 Regcode 那行或删除=后正确的注册码字符串;如果想以试用模式使用并无限次使用试用模式,
只需在 config.ini 中写入一行,Used=0,=后面的数表示已试用的次数,最大试用次数为 100。
【注册机汇编源码】
.const
MAXSIZE equ 20
.data
szFormat db '%s',0 ;注册码输出格式为字符串格式
szConstTable db '0123456789abcdefghijklmnopqrstuvwxyz',0 ;限定注册码中可以使用的字符
RegCodeBuffer db MAXSIZE dup(0),0 ;存放注册码缓冲区,20 位注册码再加上一个字符串结束符 0
;##########定义结构开始##################
_LARGE_INTEGER struct
LowPart dd ?
HighPart dd ?
_LARGE_INTEGER ends
;##########定义结构结束##################
.code
GenRandProc proc uses ecx edx First:DWORD,Second:DWORD
Local c1:_LARGE_INTEGER,c2:_LARGE_INTEGER
;rdtsc ;(多核处理器中已经不准确,因此不再使用)
;invoke GetTickCount ; 取得随机数种子,当然,可用别的方法代替
invoke QueryPerformanceCounter,addr c1
mov eax,c2.LowPart
sub eax,c1.LowPart
mov edx,c2.HighPart
sbb edx,c1.HighPart
sub eax,edx ;eax 中返回随机数种子
mov ecx,23
mul ecx
add eax,7
mov ecx,Second
sub ecx,First
inc ecx
xor edx,edx
div ecx
add edx,First
mov eax,edx
ret
GenRandProc endp
;=================================================
;注册算法:
注册码长度必须为 20 位并满足以下条件:
1、key[0]+Key[1]=11
2、key[18]+Key[19]=13
3、Key[5]+Key[13]=9
4、Key[12]='V'
5、Key[14]='3'
6、Key[15]='1'
6.其他位为任意字符
;代码编写:网络浪子(netprodiag@163.com)
;=================================================
KeyGenProc proc
LOCAL @szKey[MAXSIZE+1]:BYTE;多定义一个字节空间,确保在注册码缓冲区中最后插入一个结束符 0,~ 否则出问题
LOCAL @szOut[MAXSIZE+1]:BYTE
invoke RtlZeroMemory,addr @szOut,sizeof @szOut ;使用局部变量前一定要先初始化后再使用,否则出现意想不到的严重后果。通过 RtlZeroMemory API 函数将局部变量指向的内存域清空为零
invoke RtlZeroMemory,addr @szKey,sizeof @szKey ;相当于将局部变量初始化为零
xor eax,eax
xor ecx,ecx
xor edx,edx
;KEY[0]
invoke _Rand,2,9
movzx edx,byte ptr [szConstTable+eax]
mov byte ptr[@szKey + 0],dl
;计算KEY[1]
mov edx,11
sub edx,eax
movzx edx,byte ptr [szConstTable+edx]
mov byte ptr[@szKey + 1],dl
;KEY[18]
invoke _Rand,4,9
movzx edx,byte ptr [szConstTable+eax]
mov byte ptr[@szKey + 18],dl
;计算KEY[19]
mov edx,13
sub edx,eax
movzx edx,byte ptr [szConstTable+edx]
mov byte ptr[@szKey + 19],dl
;KEY[5]
invoke _Rand,0,9
movzx edx,byte ptr [szConstTable+eax]
mov byte ptr[@szKey + 5],dl
;计算KEY[13]
mov edx,9
sub edx,eax
movzx edx,byte ptr [szConstTable+edx]
mov byte ptr[@szKey + 13],dl
;计算 Key[12]、Key[14]、Key[15]
mov byte ptr[@szKey + 12],50h ;'V'
mov byte ptr[@szKey + 14],44h ;'3'
mov byte ptr[@szKey + 15],46h ;'1'
;计算 Key[3]、Key[4]、Key[6]、Key[7]、Key[8]、Key[9]、Key[10]、Key[11]、Key[16]、Key[17]
mov ecx,2 ;直接通过 ecx=2 排除掉 Key[0]、Key[1]
LConcalculate:
invoke _Rand,0,sizeof szConstTable-2;sizeof szConstTable 得到 szConstTable 的字节大小为 21(包含字符串定义结束符 0),然后-2得到 szConstTable 数组的最大索引号为 19
movzx edx,byte ptr [szConstTable+eax] ;本身应该通过求字符串长度的方法来确定索引号,但由于数组 szConstTable 被定义为 db 类型,因此字符串长度与字节数一致,所以可以替代。
;这里采用排除法来间接计算上面注释中提及的 Key 组,即排除掉 Key 中索引号对应的位置字符为非任意字符的情形,其它位置用 szConstTable 数据中的随机获取的字符填充。
cmp edx,5 ;如果为 key[5],即注册码中的第 6 个位置,则直接跳过继续下一位
je @f
cmp edx,12
je @f
cmp edx,13
je @f
cmp edx,14
je @f
cmp edx,15
je @f
cmp edx,18
je @f
cmp edx,19
je @f
mov byte ptr[@szKey + ecx],dl
@@:
inc ecx
cmp ecx,21
jl LConcalculate ;如果 Key 位尚未填充完则跳回继续填充
invoke lstrcat,addr @szOut,addr @szKey ;连接字符串
lea eax,@szOut
invoke wsprintf,addr RegCodeBuffer,addr szFormat,eax ;格式化注册码字符串
lea eax,RegCodeBuffer
ret
KeyGenProc endp
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
看原图
赞赏
雪币:
留言: