[表格算法]Easy PDF to Word Converter 2.0 的算法分析 + delphi(kol/mck)注册机源代码
在 http://www.unpack.cn/thread-12944-1-1.html 上,看到 xss517 兄弟在讨论这个软件,我也下来看了看,发现又是个用了表格算法的,所以把它写了出来。
又因为下载的是个汉化版,我怕版本有点老,不适用,所以我在它的官方主页:http://www.pdf-to-html-word.com/download.htm 下载了个原装版本来分析。
这是我分析的第三个与这种算法相关的程序,估计也是写这种类型的最后一个了。下次再遇上这种[表格算法]的话,估计可以'小时杀'了,呵呵('秒杀'还办不到)。
好的,我们开始:
在注册框中输入注册名和假码后,会有提示:‘the registration code is wrong. please check it and try again.’,顺着这个提示,将程序拖入OD中,先不运行,使用字符串参考,找到了提示所在的位置: 超级字符串参考 , 条目 851
地址=00428E6B
反汇编地址=push pdf2rtf.0049A1B8
字符内容=the registration code is wrong. please check it and try again. 而在它的上面便是注册成功的提示:‘thanks for your registration! easy pdf to word converter.’
超级字符串参考 , 条目 848
地址=00428DB0
反汇编地址=push pdf2rtf.0049A1F8
字符内容=thanks for your registration! easy pdf to word converter. 双击错误提示、成功提示的字符串后,分别来到了如下的地方(当然,你也可以使用GetDlgItemTextA下断,来到这里):
》》》》》》》》
00428E69 > \6A 00 push 0 ; 跳转来自 00428DA5
00428E6B . 68 B8A14900 push pdf2rtf.0049A1B8 ; |the registration code is wrong. please check it and try again.
00428E70 . 56 push esi ; |hOwner
00428E71 . FF15 F4344700 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
00428E77 . 68 FB030000 push 3FB ; /ControlID = 3FB (1019.)
00428E7C . 56 push esi ; |hWnd
00428E7D . FF15 F8344700 call dword ptr [<&USER32.GetDlgItem>] ; \GetDlgItem
00428E83 . 50 push eax ; /hWnd
00428E84 . FF15 FC344700 call dword ptr [<&USER32.SetFocus>] ; \SetFocus
00428E8A . E9 A4000000 jmp pdf2rtf.00428F33
》》》》》》》》
00428DAB . 68 34A24900 push pdf2rtf.0049A234 ; |thanks for your registration!
00428DB0 . 68 F8A14900 push pdf2rtf.0049A1F8 ; |thanks for your registration! easy pdf to word converter.
00428DB5 . 56 push esi ; |hOwner
00428DB6 . FF15 F4344700 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
00428DBC . 8B0D F0D64900 mov ecx, dword ptr [49D6F0] ; pdf2rtf.0049D704
00428DC2 . 894C24 18 mov dword ptr [esp+18], ecx
00428DC6 . 68 1C1A4A00 push pdf2rtf.004A1A1C
》》》》》》》》 顺着它们它们跳转来的地方,往上查看,来到这里:
》》》》》》》》
00428D6C > \8B7424 18 mov esi, dword ptr [esp+18] ; Case 1 of switch 00428D3F
00428D70 . 68 C8000000 push 0C8 ; /Count = C8 (200.)
00428D75 . B9 32000000 mov ecx, 32 ; |
00428D7A . 33C0 xor eax, eax ; |
00428D7C . BF 1C1A4A00 mov edi, pdf2rtf.004A1A1C ; |
00428D81 . 68 1C1A4A00 push pdf2rtf.004A1A1C ; |Buffer = pdf2rtf.004A1A1C
00428D86 . 68 FB030000 push 3FB ; |ControlID = 3FB (1019.)
00428D8B . 56 push esi ; |hWnd
00428D8C . F3:AB rep stos dword ptr es:[edi] ; |
00428D8E . FF15 F0344700 call dword ptr [<&USER32.GetDlgItemTe>; \GetDlgItemTextA
00428D94 . 68 1C1A4A00 push pdf2rtf.004A1A1C
00428D99 . E8 E2FBFFFF call pdf2rtf.00428980
00428D9E . 83C4 04 add esp, 4
00428DA1 . 85C0 test eax, eax
00428DA3 . 6A 20 push 20 ; /Style = MB_OK|MB_ICONQUESTION|MB_APPLMODAL
00428DA5 . 0F84 BE000000 je pdf2rtf.00428E69 ; |不跳,便OK了!
00428DAB . 68 34A24900 push pdf2rtf.0049A234 ; |thanks for your registration!
00428DB0 . 68 F8A14900 push pdf2rtf.0049A1F8 ; |thanks for your registration! easy pdf to word converter.
00428DB5 . 56 push esi ; |hOwner
00428DB6 . FF15 F4344700 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
00428DBC . 8B0D F0D64900 mov ecx, dword ptr [49D6F0] ; pdf2rtf.0049D704
》》》》》》》》 因此,我们在00428D6C这个地方按F2键下断点,然后Ctrl+F2重新载入程序,F9运行,然后打开注册输入窗口,输入一组实验码:
name:aCaFeeL
code:1111-2222-3333-4444(为什么是这种格式呐?看下面进入算法后的反编代码,便明白了) 点击‘OK’按钮,程序便被中断在了如下位置(开始分析):
》》》》》》》》
『以上代码省略』
00428D6C > \8B7424 18 mov esi, dword ptr [esp+18] ; Case 1 of switch 00428D3F
00428D70 . 68 C8000000 push 0C8 ; /Count = C8 (200.)
00428D75 . B9 32000000 mov ecx, 32 ; |
00428D7A . 33C0 xor eax, eax ; |
00428D7C . BF 1C1A4A00 mov edi, pdf2rtf.004A1A1C ; |
00428D81 . 68 1C1A4A00 push pdf2rtf.004A1A1C ; |Buffer = pdf2rtf.004A1A1C
00428D86 . 68 FB030000 push 3FB ; |ControlID = 3FB (1019.)
00428D8B . 56 push esi ; |hWnd
00428D8C . F3:AB rep stos dword ptr es:[edi] ; |
00428D8E . FF15 F0344700 call dword ptr [<&USER32.GetDlgItemTe>; \得到注册码
00428D94 . 68 1C1A4A00 push pdf2rtf.004A1A1C
00428D99 . E8 E2FBFFFF call pdf2rtf.00428980 ; 关键算法,决定eax值,F7进入
00428D9E . 83C4 04 add esp, 4
00428DA1 . 85C0 test eax, eax ; eax and eax = 0 ???
00428DA3 . 6A 20 push 20 ; /;
00428DA5 . 0F84 BE000000 je pdf2rtf.00428E69 ; |eax and eax不为0,便OK了!
00428DAB . 68 34A24900 push pdf2rtf.0049A234 ; |;
00428DB0 . 68 F8A14900 push pdf2rtf.0049A1F8 ; |thanks for your registration! easy pdf to word converter.
00428DB5 . 56 push esi ; |hOwner
00428DB6 . FF15 F4344700 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
00428DBC . 8B0D F0D64900 mov ecx, dword ptr [49D6F0] ; pdf2rtf.0049D704
00428DC2 . 894C24 18 mov dword ptr [esp+18], ecx
『以下代码省略』
》》》》》》》》 毫无疑问,上面这段代码显示了,当
00428DA1 . 85C0 test eax, eax
处的 eax and eax = 0时,便注册成功了,而决定eax数值的便是00428D99处的:
00428D99 . E8 E2FBFFFF call pdf2rtf.00428980
因此,我们自然应该F7键进入其中,重新来过后,中断在00428D99,然后进入到call pdf2rtf.00428980中,走过一些代码后,来到这里:
》》》》》》》》
『以上代码省略』
00428A99 |. 8D4C24 24 lea ecx, dword ptr [esp+24]
00428A9D |. 885C24 30 mov byte ptr [esp+30], bl
00428AA1 |. E8 C68E0300 call pdf2rtf.0046196C
00428AA6 |. 8B4424 1C mov eax, dword ptr [esp+1C] ; 注册码中的 1~4位
00428AAA |. 8D4C24 1C lea ecx, dword ptr [esp+1C]
00428AAE |. 8B40 F8 mov eax, dword ptr [eax-8]
00428AB1 |. 50 push eax
00428AB2 |. E8 E5920300 call pdf2rtf.00461D9C
00428AB7 |. 50 push eax
00428AB8 |. E8 E3480200 call pdf2rtf.0044D3A0 ; eax计算::F7进入 (eax为最终所要的结果)
00428ABD |. 8B4C24 1C mov ecx, dword ptr [esp+1C] ; 注册码中的 6~9位
00428AC1 |. 83C4 04 add esp, 4
00428AC4 |. 8BF0 mov esi, eax ; esi = eax *注意:esi赋值了*
00428AC6 |. 8B41 F8 mov eax, dword ptr [ecx-8]
00428AC9 |. 8D4C24 18 lea ecx, dword ptr [esp+18]
00428ACD |. 50 push eax
00428ACE |. E8 C9920300 call pdf2rtf.00461D9C
00428AD3 |. 50 push eax
00428AD4 |. E8 C7480200 call pdf2rtf.0044D3A0 ; eax计算::F7进入 (eax为最终所要的结果)
00428AD9 |. 8B5424 18 mov edx, dword ptr [esp+18] ; 注册码中的 11~14位
00428ADD |. 83C4 04 add esp, 4
00428AE0 |. 8BF8 mov edi, eax ; edi = eax *注意:edi赋值了*
00428AE2 |. 8D4C24 14 lea ecx, dword ptr [esp+14]
00428AE6 |. 8B42 F8 mov eax, dword ptr [edx-8]
00428AE9 |. 50 push eax
00428AEA |. E8 AD920300 call pdf2rtf.00461D9C
00428AEF |. 50 push eax
00428AF0 |. E8 AB480200 call pdf2rtf.0044D3A0 ; eax计算::F7进入 (eax为最终所要的结果)
00428AF5 |. 8BD8 mov ebx, eax ; ebx = eax *注意:ebx赋值了*
00428AF7 |. 8B4424 3C mov eax, dword ptr [esp+3C] ; 注册码中的 16~19位
00428AFB |. 83C4 04 add esp, 4
00428AFE |. 8D4C24 38 lea ecx, dword ptr [esp+38]
00428B02 |. 8B40 F8 mov eax, dword ptr [eax-8]
00428B05 |. 50 push eax
00428B06 |. E8 91920300 call pdf2rtf.00461D9C
00428B0B |. 50 push eax
00428B0C |. E8 8F480200 call pdf2rtf.0044D3A0 ; eax计算::F7进入 (eax为最终所要的结果)
00428B11 |. 83C4 04 add esp, 4
00428B14 |. 8D4C24 1C lea ecx, dword ptr [esp+1C]
00428B18 |. 8BE8 mov ebp, eax ; ebp = eax *注意:ebp赋值了*
00428B1A |. 6A FF push -1
00428B1C |. E8 CA920300 call pdf2rtf.00461DEB
00428B21 |. 6A FF push -1
00428B23 |. 8D4C24 1C lea ecx, dword ptr [esp+1C]
00428B27 |. E8 BF920300 call pdf2rtf.00461DEB
00428B2C |. 6A FF push -1
00428B2E |. 8D4C24 18 lea ecx, dword ptr [esp+18]
00428B32 |. E8 B4920300 call pdf2rtf.00461DEB
00428B37 |. 6A FF push -1
00428B39 |. 8D4C24 3C lea ecx, dword ptr [esp+3C]
00428B3D |. E8 A9920300 call pdf2rtf.00461DEB ; //下面是第一部份的算法
00428B42 |. 8D8CB6 E4C000>lea ecx, dword ptr [esi+esi*4+C0E4] ; ecx := esi * $5 + $C0E4;
00428B49 |. 8D844E 942600>lea eax, dword ptr [esi+ecx*2+2694] ; eax := esi + ecx * $2 + $2694;
00428B50 |. B9 10270000 mov ecx, 2710 ; ecx := $2710;
00428B55 |. D1E0 shl eax, 1 ; eax := eax shl $1;
00428B57 |. 99 cdq
00428B58 |. F7F9 idiv ecx ; edx := eax mod ecx;
00428B5A |. 3BFA cmp edi, edx ; edi = edx ?
00428B5C 74 0B je short pdf2rtf.00428B69 ; 相等便OK!
00428B5E |. C64424 30 04 mov byte ptr [esp+30], 4
00428B63 |. 8D4C24 38 lea ecx, dword ptr [esp+38]
00428B67 |. EB 29 jmp short pdf2rtf.00428B92 ; //下面是第二部份的算法
00428B69 |> 8D83 FEE5FFFF lea eax, dword ptr [ebx-1A02] ; eax := ebx - $1A02;
00428B6F |. 81C3 E8080000 add ebx, 8E8 ; ebx := ebx + $8E8;
00428B75 |. 99 cdq ; edx 接受 eax 的扩展
00428B76 |. 33C2 xor eax, edx ; eax := eax xor edx;
00428B78 |. B9 10270000 mov ecx, 2710 ; ecx := $2710;
00428B7D |. 2BC2 sub eax, edx ; eax := eax - edx;
00428B7F |. C64424 30 04 mov byte ptr [esp+30], 4
00428B84 |. 0FAFC3 imul eax, ebx ; eax := eax * ebx;
00428B87 |. 99 cdq ; edx 接受 eax 的扩展
00428B88 |. F7F9 idiv ecx ; edx := eax mod ecx;
00428B8A |. 8D4C24 38 lea ecx, dword ptr [esp+38]
00428B8E |. 3BEA cmp ebp, edx ; ebp = edx ?
00428B90 |. 74 63 je short pdf2rtf.00428BF5 ; 相等便OK!
00428B92 |> E8 D58D0300 call pdf2rtf.0046196C
00428B97 |. 8D4C24 14 lea ecx, dword ptr [esp+14]
00428B9B |. C64424 30 03 mov byte ptr [esp+30], 3
00428BA0 |. E8 C78D0300 call pdf2rtf.0046196C
『以下代码省略』
》》》》》》》》 通过上面的代码,自然发现,决定注册成功与否的esi、edi、ebx和ebp中的数值都是首先由call pdf2rtf.0044D3A0这个子程序决定,自然,F7进入后,来到了这里:
》》》》》》》》
0044D3A0 /$ FF7424 04 push dword ptr [esp+4]
0044D3A4 |. E8 6CFFFFFF call pdf2rtf.0044D315 ; F7再次进入
0044D3A9 |. 59 pop ecx
0044D3AA \. C3 retn
》》》》》》》》 再次,F7键进入:
0044D3A4 |. E8 6CFFFFFF call pdf2rtf.0044D315
后,便来到了这个子算法的开始处:
》》》》》》》》
0044D315 /$ 53 push ebx ; 其中的一部分算法
0044D316 |. 55 push ebp
0044D317 |. 56 push esi
0044D318 |. 57 push edi
0044D319 |. 8B7C24 14 mov edi, dword ptr [esp+14]
0044D31D |> 833D A00E4A00>/cmp dword ptr [4A0EA0], 1
0044D324 |. 7E 0F |jle short pdf2rtf.0044D335
0044D326 |. 0FB607 |movzx eax, byte ptr [edi]
0044D329 |. 6A 08 |push 8
0044D32B |. 50 |push eax
0044D32C |. E8 8D790000 |call pdf2rtf.00454CBE
0044D331 |. 59 |pop ecx
0044D332 |. 59 |pop ecx
0044D333 |. EB 0F |jmp short pdf2rtf.0044D344
0044D335 |> 0FB607 |movzx eax, byte ptr [edi] ; 如循环,依次取字符 -> eax
0044D338 |. 8B0D 940C4A00 |mov ecx, dword ptr [4A0C94] ; 注意内存窗口中 $004A0C9E~$004A0D9D 的一张Key表
0044D33E |. 8A0441 |mov al, byte ptr [ecx+eax*2] ; 取的字符码*2 在key表中的对应值 -> al
0044D341 |. 83E0 08 |and eax, 8 ; eax := eax and $8;
0044D344 |> 85C0 |test eax, eax ; eax and eax = 0 ???
0044D346 74 03 je short pdf2rtf.0044D34B ; =0,跳
0044D348 |. 47 |inc edi
0044D349 |.^ EB D2 \jmp short pdf2rtf.0044D31D
0044D34B |> 0FB637 movzx esi, byte ptr [edi] ; 取每组的第一个字符 -> esi
0044D34E |. 47 inc edi ; 取下一个字符
0044D34F |. 83FE 2D cmp esi, 2D ; 是否为:-
0044D352 |. 8BEE mov ebp, esi
0044D354 |. 74 05 je short pdf2rtf.0044D35B
0044D356 |. 83FE 2B cmp esi, 2B ; 是否为:+
0044D359 |. 75 04 jnz short pdf2rtf.0044D35F
0044D35B |> 0FB637 movzx esi, byte ptr [edi]
0044D35E |. 47 inc edi
0044D35F |> 33DB xor ebx, ebx ; ebx 清零
0044D361 |> 833D A00E4A00>/cmp dword ptr [4A0EA0], 1
0044D368 |. 7E 0C |jle short pdf2rtf.0044D376
0044D36A |. 6A 04 |push 4
0044D36C |. 56 |push esi
0044D36D |. E8 4C790000 |call pdf2rtf.00454CBE
0044D372 |. 59 |pop ecx
0044D373 |. 59 |pop ecx
0044D374 |. EB 0B |jmp short pdf2rtf.0044D381
0044D376 |> A1 940C4A00 |mov eax, dword ptr [4A0C94] ; $004A0C9E -> eax
0044D37B |. 8A0470 |mov al, byte ptr [eax+esi*2] ; 取的字符码*2 在key表中的对应值 -> al
0044D37E |. 83E0 04 |and eax, 4 ; eax := eax and $4;
0044D381 |> 85C0 |test eax, eax ; eax and eax = 0 ???
0044D383 |. 74 0D |je short pdf2rtf.0044D392 ; =0,跳
0044D385 |. 8D049B |lea eax, dword ptr [ebx+ebx*4] ; eax := ebx*5;
0044D388 |. 8D5C46 D0 |lea ebx, dword ptr [esi+eax*2-30] ; ebx := esi + eax * $2 - $30;
0044D38C |. 0FB637 |movzx esi, byte ptr [edi] ; 取得下一个字符 -> esi
0044D38F |. 47 |inc edi ; 再依次取下一个字符
0044D390 |.^ EB CF \jmp short pdf2rtf.0044D361
0044D392 |> 83FD 2D cmp ebp, 2D ; 是否为符号:-
0044D395 |. 8BC3 mov eax, ebx ; eax := ebx; //注意
0044D397 |. 75 02 jnz short pdf2rtf.0044D39B
0044D399 |. F7D8 neg eax ; 反相
0044D39B |> 5F pop edi
0044D39C |. 5E pop esi
0044D39D |. 5D pop ebp
0044D39E |. 5B pop ebx
0044D39F \. C3 retn
》》》》》》》》 注意:0044D338 |. 8B0D 940C4A00 |mov ecx, dword ptr [4A0C94] 这处; 通过上面代码的分析,我们知道了其算法主要是由一张表的结果累加,再配上不等的逻辑和算术运算的结果决定的,而这张表可从:
0044D338 |. 8B0D 940C4A00 |mov ecx, dword ptr [4A0C94]
这里的dword ptr [4A0C94]获得,在内存窗口中抓出来后,便是如下的格式: [$004A0C9E~$004A0D9D 的这张表]:
004A0C9E 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 . . . . . . . .
004A0CAE 20 00 28 00 28 00 28 00 28 00 28 00 20 00 20 00 .(.(.(.(.(. . .
004A0CBE 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 . . . . . . . .
004A0CCE 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 . . . . . . . .
004A0CDE 48 00 10 00 10 00 10 00 10 00 10 00 10 00 10 00 H........
004A0CEE 10 00 10 00 10 00 10 00 10 00 10 00 10 00 10 00 ........
004A0CFE 84 00 84 00 84 00 84 00 84 00 84 00 84 00 84 00 ????????
004A0D0E 84 00 84 00 10 00 10 00 10 00 10 00 10 00 10 00 ??......
004A0D1E 10 00 81 00 81 00 81 00 81 00 81 00 81 00 01 00 .??????.
004A0D2E 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 ........
004A0D3E 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 ........
004A0D4E 01 00 01 00 01 00 10 00 10 00 10 00 10 00 10 00 ........
004A0D5E 10 00 82 00 82 00 82 00 82 00 82 00 82 00 02 00 .??????.
004A0D6E 02 00 02 00 02 00 02 00 02 00 02 00 02 00 02 00 ........
004A0D7E 02 00 02 00 02 00 02 00 02 00 02 00 02 00 02 00 ........
004A0D8E 02 00 02 00 02 00 10 00 10 00 10 00 10 00 20 00 ....... . 将其转换后,便是如下的一组 KEY 数据了,共(4x4)x16=256组:
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$20,$00,$28,$00,$28,$00,$28,$00,$28,$00,$28,$00,$20,$00,$20,$00,
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$48,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,
$84,$00,$84,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$81,$00,$81,$00,$81,$00,$81,$00,$81,$00,$81,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$82,$00,$82,$00,$82,$00,$82,$00,$82,$00,$82,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$10,$00,$10,$00,$10,$00,$10,$00,$20,$00 而上面这个子程序的算法,我用 Delphi + KOL/MCK 写出的大致框架为如下形式:(已写成为一个string函数格式,但我没有将有 + - 符号的情况写进去)
//EasyPDFtoRTF子call算法
function EasyPDFtoRTF_call(cz: string): integer; //定义integer函数
var
eax, ebx, edi : integer;
Seax, Sal : string;
const
key: array[0 .. 255] of byte = //密文表全部数据,共256组
($20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$20,$00,$28,$00,$28,$00,$28,$00,$28,$00,$28,$00,$20,$00,$20,$00,
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$48,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,
$84,$00,$84,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$81,$00,$81,$00,$81,$00,$81,$00,$81,$00,$81,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$82,$00,$82,$00,$82,$00,$82,$00,$82,$00,$82,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$10,$00,$10,$00,$10,$00,$10,$00,$20,$00);
begin
//////// 1 ///////循环
edi := 1;//初始化i变量
Seax := '000000';
Sal := int2hex(key[ord(cz[edi]) * 2], 2);
Seax := Seax + Sal;
eax := hex2int('$' + Seax);
eax := eax and $8;
while ((eax and eax) <> 0) do
begin
edi := edi + 1;
Seax := '000000';
Sal := int2hex(key[ord(cz[edi]) * 2], 2);
Seax := Seax + Sal;
eax := hex2int('$' + Seax);
eax := eax and $8;
end;
//////// 2 ///////循环
//edi := 1;//edi应继承前面的结果,不能再赋值了!
ebx := 0; //初始化ebx为0
Seax := '004A0C';
Sal := int2hex(key[ord(cz[edi]) * 2], 2);
Seax := Seax + Sal;
eax := hex2int('$' + Seax);
eax := eax and $4;
while ((eax and eax) <> 0) do
begin
eax := ebx * $5;
ebx := ord(cz[edi]) + eax * $2 - $30;
edi := edi + 1;
Seax := '004A0C';
Sal := int2hex(key[ord(cz[edi]) * 2], 2);
Seax := Seax + Sal;
eax := hex2int('$' + Seax);
eax := eax and $4;
end;
result := ebx;
end; 然后,我们再回到主算法的代码,并来到这里:
》》》》》》》》
『以上代码省略』
00428B2C |. 6A FF push -1
00428B2E |. 8D4C24 18 lea ecx, dword ptr [esp+18]
00428B32 |. E8 B4920300 call pdf2rtf.00461DEB
00428B37 |. 6A FF push -1
00428B39 |. 8D4C24 3C lea ecx, dword ptr [esp+3C]
00428B3D |. E8 A9920300 call pdf2rtf.00461DEB ; //下面是第一部份的算法
00428B42 |. 8D8CB6 E4C000>lea ecx, dword ptr [esi+esi*4+C0E4] ; ecx := esi * $5 + $C0E4;
00428B49 |. 8D844E 942600>lea eax, dword ptr [esi+ecx*2+2694] ; eax := esi + ecx * $2 + $2694;
00428B50 |. B9 10270000 mov ecx, 2710 ; ecx := $2710;
00428B55 |. D1E0 shl eax, 1 ; eax := eax shl $1;
00428B57 |. 99 cdq
00428B58 |. F7F9 idiv ecx ; edx := eax mod ecx;
00428B5A |. 3BFA cmp edi, edx ; edi = edx ?
00428B5C 74 0B je short pdf2rtf.00428B69 ; 相等便OK!
00428B5E |. C64424 30 04 mov byte ptr [esp+30], 4
00428B63 |. 8D4C24 38 lea ecx, dword ptr [esp+38]
00428B67 |. EB 29 jmp short pdf2rtf.00428B92 ; //下面是第二部份的算法
00428B69 |> 8D83 FEE5FFFF lea eax, dword ptr [ebx-1A02] ; eax := ebx - $1A02;
00428B6F |. 81C3 E8080000 add ebx, 8E8 ; ebx := ebx + $8E8;
00428B75 |. 99 cdq ; edx 接受 eax 的扩展
00428B76 |. 33C2 xor eax, edx ; eax := eax xor edx;
00428B78 |. B9 10270000 mov ecx, 2710 ; ecx := $2710;
00428B7D |. 2BC2 sub eax, edx ; eax := eax - edx;
00428B7F |. C64424 30 04 mov byte ptr [esp+30], 4
00428B84 |. 0FAFC3 imul eax, ebx ; eax := eax * ebx;
00428B87 |. 99 cdq ; edx 接受 eax 的扩展
00428B88 |. F7F9 idiv ecx ; edx := eax mod ecx;
00428B8A |. 8D4C24 38 lea ecx, dword ptr [esp+38]
00428B8E |. 3BEA cmp ebp, edx ; ebp = edx ?
00428B90 |. 74 63 je short pdf2rtf.00428BF5 ; 相等便OK!
00428B92 |> E8 D58D0300 call pdf2rtf.0046196C
00428B97 |. 8D4C24 14 lea ecx, dword ptr [esp+14]
00428B9B |. C64424 30 03 mov byte ptr [esp+30], 3
00428BA0 |. E8 C78D0300 call pdf2rtf.0046196C
『以下代码省略』
》》》》》》》》 通过上面的代码,我们清晰的知道了,两部分的算法分别为:
//第一部份外部算法
edx := ((esi + (esi * $5 + $C0E4) * 2 + $2694) shl $1) mod $2710; //6_9
//第二部份外部算法
edx := ((((ebx - $1A02) xor edx) - edx) * (ebx + $8E8)) mod $2710;
然后,将两部分的结果,分别与edi和ebp的结果比较,相等,便注册成功了! 好,得到上面这些有用的信息后,现在我就把它具体算法的思路给理一下吧:
1。注册名在其中没有起到任何的作用, 程序先得到注册码,然后带入到运算中;
2。取注册码的1~4位数,带入子程序call 0044D3A0中运算,结果送到-> esi中;
3。取注册码的6~9位数,带入子程序call 0044D3A0中运算,结果送到-> edi中;
4。取注册码的11~14位数,带入子程序call 0044D3A0中运算,结果送到-> ebx中;
5。取注册码的16~19位数,带入子程序call 0044D3A0中运算,结果送到-> ebp中;
6。然后用上面的‘第一部份外部算法’,将得到的结果edx 与 第‘2’步骤中得到的结果edi比较,两者相等,便OK;
7。用上面的‘第二部份外部算法’,将得到的结果edx 与 第‘5’步骤中得到的结果ebp比较,如若相等,便成功了。 也许我无法表示清楚,还是看相关的源代码吧!转换成用 Delphi + KOL/MCK 写的代码即是如下形式: { KOL MCK } // Do not remove this line!
{$DEFINE KOL_MCK}
unit Main1;
interface
{$IFDEF KOL_MCK}
uses Windows, KOL {$IFNDEF KOL_MCK},
Classes, Controls, mckCtrls, mirror {$ENDIF (place your units here->)};
{$ENDIF}
type
{$IFDEF KOL_MCK}
{$I MCKfakeClasses.inc}
{$IFDEF KOLCLASSES} TForm1 = class; PForm1 = TForm1;
{$ELSE OBJECTS} PForm1 = ^TForm1;
{$ENDIF CLASSES/OBJECTS}
{$IFDEF KOLCLASSES}{$I TForm1.inc}{$ELSE} TForm1 = object(TObj) {$ENDIF}
Form: PControl;
{$ELSE not_KOL_MCK}
TForm1 = class(TForm)
{$ENDIF KOL_MCK}
KOLProject1: TKOLProject;
KOLForm1: TKOLForm;
GroupBox: TKOLGroupBox;
EditName: TKOLEditBox;
LabelName: TKOLLabel;
LabelInfo: TKOLLabel;
ButtonReg: TKOLButton;
ButtonExit: TKOLButton;
ProgressBar: TKOLProgressBar;
procedure ButtonExitClick(Sender: PObj);
procedure ButtonRegClick(Sender: PObj);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1 {$IFDEF KOL_MCK} : PForm1 {$ELSE} : TForm1 {$ENDIF} ;
{$IFDEF KOL_MCK}
procedure NewForm1( var Result: PForm1; AParent: PControl );
{$ENDIF}
implementation
{$IFNDEF KOL_MCK} {$R *.DFM} {$ENDIF}
{$IFDEF KOL_MCK}
{$I main_1.inc}
{$ENDIF}
//****************************************************************************//
//EasyPDFtoRTF子call算法
function EasyPDFtoRTF_call(cz: string): integer; //定义integer函数
var
eax, ebx, edi : integer;
Seax, Sal : string;
const
key: array[0 .. 255] of byte = //密文表全部数据,共256组
($20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$20,$00,$28,$00,$28,$00,$28,$00,$28,$00,$28,$00,$20,$00,$20,$00,
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,$20,$00,
$48,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,$84,$00,
$84,$00,$84,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$81,$00,$81,$00,$81,$00,$81,$00,$81,$00,$81,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,$01,$00,
$01,$00,$01,$00,$01,$00,$10,$00,$10,$00,$10,$00,$10,$00,$10,$00,
$10,$00,$82,$00,$82,$00,$82,$00,$82,$00,$82,$00,$82,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,$02,$00,
$02,$00,$02,$00,$02,$00,$10,$00,$10,$00,$10,$00,$10,$00,$20,$00);
begin
//////// 1 ///////循环
edi := 1;//初始化i变量
Seax := '000000';
Sal := int2hex(key[ord(cz[edi]) * 2], 2);
Seax := Seax + Sal;
eax := hex2int('$' + Seax);
eax := eax and $8;
while ((eax and eax) <> 0) do
begin
edi := edi + 1;
Seax := '000000';
Sal := int2hex(key[ord(cz[edi]) * 2], 2);
Seax := Seax + Sal;
eax := hex2int('$' + Seax);
eax := eax and $8;
end;
//////// 2 ///////循环
//edi := 1;//edi应继承前面的结果,不能再赋值了!
ebx := 0; //初始化ebx为0
Seax := '004A0C';
Sal := int2hex(key[ord(cz[edi]) * 2], 2);
Seax := Seax + Sal;
eax := hex2int('$' + Seax);
eax := eax and $4;
while ((eax and eax) <> 0) do
begin
eax := ebx * $5;
ebx := ord(cz[edi]) + eax * $2 - $30;
edi := edi + 1;
Seax := '004A0C';
Sal := int2hex(key[ord(cz[edi]) * 2], 2);
Seax := Seax + Sal;
eax := hex2int('$' + Seax);
eax := eax and $4;
end;
result := ebx;
end;
//****************************************************************************//
//穷举6_9位数 //第一部份外部算法
function QJ6_9(code1_4 : string): string;
var
i, pos : integer;
cz, code6_9 : string;
begin
for i:=1000 to 9999 do
begin
code6_9 := int2hex(i,0);
if EasyPDFtoRTF_call(code6_9) = ((EasyPDFtoRTF_call(code1_4) + (EasyPDFtoRTF_call(code1_4) * $5 + $C0E4) * 2 + $2694) shl $1) mod $2710
then Result := code6_9 //正确结果回送
else if Form1.ProgressBar.Progress>9
then Form1.ProgressBar.Progress:=0
else Form1.ProgressBar.Progress := Form1.ProgressBar.Progress + 1;
end;
end;
//****************************************************************************//
//穷举16_19位数 //第二部份外部算法
function QJ16_19(code11_14 : string): string;
var
i, pos : integer;
cz, code16_19 : string;
begin
for i:=1000 to 9999 do
begin
code16_19 := int2hex(i,0);
if EasyPDFtoRTF_call(code16_19) = ((((EasyPDFtoRTF_call(code11_14) - $1A02) xor $0) - $0) * (EasyPDFtoRTF_call(code11_14) + $8E8)) mod $2710
then Result := code16_19 //正确结果回送
else if Form1.ProgressBar.Progress>9
then Form1.ProgressBar.Progress:=0
else Form1.ProgressBar.Progress := Form1.ProgressBar.Progress + 1;
end;
end;
//****************************************************************************//
//EasyPDFtoRTF注册算法
function EasyPDFtoRTF_sn(): string;//定义string函数
var
code1_4, code6_9, code11_14, code16_19, RegCode : string;
eax, ebx, ebp, ecx, edx, edi, esi : integer;
begin
{
//注册码的格式应为:
RegCode := '1111-1714-6666-1568';
esi := EasyPDFtoRTF_call(copy(RegCode, 1, 4)); //1_4
edi := EasyPDFtoRTF_call(copy(RegCode, 6, 9));
ebx := EasyPDFtoRTF_call(copy(RegCode, 11, 14)); //11_14
ebp := EasyPDFtoRTF_call(copy(RegCode, 16, 19));
//第一部份外部算法
//edx := ((esi + (esi * $5 + $C0E4) * 2 + $2694) shl $1) mod $2710; //6_9
//第二部份外部算法
//edx := $0;
//edx := ((((ebx - $1A02) xor edx) - edx) * (ebx + $8E8)) mod $2710;
showmessage(int2hex(ebp,0));
showmessage(int2hex(edx,0));
}
code1_4 := '1111'; //任意 4 位数//这里我定义的为:1111,你可自己修改,但必须满足能被穷举出来哟!
code6_9 := QJ6_9(code1_4); //穷举 6_9 位数
code11_14 := '6666'; //任意 4 位数//这里我定义的为:6666,你可自己修改,但必须满足能被穷举出来哟!
code16_19 := QJ16_19(code11_14);//穷举16_19位数
Result := code1_4 +'-'+ code6_9 +'-'+ code11_14 +'-'+ code16_19; //最终结果
end;
//****************************************************************************//
procedure TForm1.ButtonRegClick(Sender: PObj);
begin
EditName.Text := EasyPDFtoRTF_sn();//EasyPDFtoRTF注册算法
end;
//****************************************************************************//
procedure TForm1.ButtonExitClick(Sender: PObj);
begin
Form.Close;
end;
//****************************************************************************//
end. 好的,就到这里结束吧!分析难免有不当之处,还望大家给我指出来! 放上几组可用的Key:
name: [任意注册名]
code: 1111-1714-6666-1568
name: [任意注册名]
code: 2020-1712-8080-1920
name: [任意注册名]
code: 2000-1272-7033-2375
name: [任意注册名]
code: 1122-1956-6665-2615
name: [任意注册名]
code: 1144-2440-7040-240F
name: [任意注册名]
code: 1111-1714-8086-2648 因为想偷懒,注册机的部分算法使用了穷举的方式,应该不存在bug的问题,附件中为我打包后的注册机源代码。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: