• 标 题:某国产软件 - XX E-mail 邮差 的算法分析,感兴趣者请进! (32千字)
  • 作 者:crack007
  • 时 间:2002-8-16 18:39:08
  • 链 接:http://bbs.pediy.com

某国产软件 - XX E-mail 邮差 的算法分析

这篇文章可以说是受人之托,基本上可以有所交待了。不过看过了ppp621等大侠写的文章后,发表得有点心虚,和那些文章相比,这片太小儿科了!:)

该软件无壳无反无防,是典型的“三无产品”,这东西分析起来简直是太爽了。:)跟踪流程基本上没费多大劲,主要是写注册机时想了好一会儿.....


由 fi 得知是采用 delphi 编写,那么理所当然的就用 DeDe 喽。

我的机器码为572463 = $8BC2F
假定我们填的注册码为 WWWWW-XXXXX-YYYYY-ZZZZZ (至于为什么这么填,跟到后面就全知道了)

我们很 EZ 地来到这里:

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048ED3D  E8E2A0F7FF            call    00408E24
0048ED42  8BD0                  mov    edx, eax
0048ED44  B98D000000            mov    ecx, $0000008D
0048ED49  8B45FC                mov    eax, [ebp-$04]

* Reference to : TRegisterDlg._PROC_0048E36C()
|
0048ED4C  E81BF6FFFF            call    0048E36C        //关键Call。跟踪时要注意注册标志 bl 的赋值情况
0048ED51  8BD8                  mov    ebx, eax

* Reference to pointer to GlobalVar_0049D9A8
|
0048ED53  A148CB4900            mov    eax, dword ptr [$0049CB48]

* Reference to field GlobalVar_0049D9A8.OFFS_0054
|
0048ED58  885854                mov    [eax+$54], bl

* Reference to pointer to GlobalVar_0049D9A8
|
0048ED5B  A148CB4900            mov    eax, dword ptr [$0049CB48]
0048ED60  84DB                  test    bl, bl
0048ED62  752C                  jnz    0048ED90              //这意味着什么大家都清楚吧? *^_^*
0048ED64  8D45F8                lea    eax, [ebp-$08]

* Possible String Reference to: '无效的注册码!  '
|
0048ED67  BA04EE4800            mov    edx, $0048EE04

* Reference to: system.@LStrLAsg;
|
0048ED6C  E8AF4FF7FF            call    00403D20
0048ED71  6A30                  push    $30
0048ED73  8B45F8                mov    eax, [ebp-$08]


于是乎,又很 EZ 地来到这里:
////////////////////////////////////////////////////////////////////////////////
////////////////          0048E36C  call  Start                ////////////////
////////////////////////////////////////////////////////////////////////////////
0048E36C  55                    push    ebp
0048E36D  8BEC                  mov    ebp, esp
0048E36F  51                    push    ecx
0048E370  B90E000000            mov    ecx, $0000000E
0048E375  6A00                  push    $00
0048E377  6A00                  push    $00
0048E379  49                    dec    ecx
0048E37A  75F9                  jnz    0048E375
0048E37C  874DFC                xchg    [ebp-$04], ecx
0048E37F  53                    push    ebx
0048E380  56                    push    esi
0048E381  57                    push    edi
0048E382  894DF4                mov    [ebp-$0C], ecx
0048E385  8955F8                mov    [ebp-$08], edx
0048E388  8945FC                mov    [ebp-$04], eax
0048E38B  8B45FC                mov    eax, [ebp-$04]

* Reference to: system.@LStrAddRef;
|
0048E38E  E8295DF7FF            call    004040BC
0048E393  33C0                  xor    eax, eax
0048E395  55                    push    ebp

* Possible String Reference to: '閚N?胫奅骭^[嬪]?
|
0048E396  6829E84800            push    $0048E829

***** TRY
|
0048E39B  64FF30                push    dword ptr fs:[eax]
0048E39E  648920                mov    fs:[eax], esp
0048E3A1  C645F300              mov    byte ptr [ebp-$0D], $00
0048E3A5  8B45FC                mov    eax, [ebp-$04]

* Reference to: system.@LStrLen:Integer;
|
0048E3A8  E85B5BF7FF            call    00403F08
0048E3AD  83F814                cmp    eax, +$14          //注册码是否填写完整(20位)
0048E3B0  0F8543040000          jnz    0048E7F9
0048E3B6  8D45DC                lea    eax, [ebp-$24]
0048E3B9  8B55FC                mov    edx, [ebp-$04]

* Reference to: system.@LStrLAsg;
|
0048E3BC  E85F59F7FF            call    00403D20
-----------------------------------------------------------------------------
* Reference to: sysutils.Now:System.TDateTime;          //有一点反跟踪意思。但太简单,故不算在反跟踪里面。:)
|
0048E3C1  E8BABAF7FF            call    00409E80
0048E3C6  83C4F8                add    esp, -$08
0048E3C9  DD1C24                fstp    qword ptr [esp]
0048E3CC  9B                    wait
0048E3CD  8D55CC                lea    edx, [ebp-$34]

* Possible String Reference to: 'hhnnss'              //取得系统时间 20:00:35 --> 200035
|
0048E3D0  B844E84800            mov    eax, $0048E844

* Reference to: Unit_00407C78.Proc_0040AAC0
|
0048E3D5  E8E6C6F7FF            call    0040AAC0
0048E3DA  8B45CC                mov    eax, [ebp-$34]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E3DD  E842AAF7FF            call    00408E24
0048E3E2  8BF0                  mov    esi, eax
0048E3E4  BB01000000            mov    ebx, $00000001
0048E3E9  83FE0A                cmp    esi, +$0A   
0048E3EC  7C59                  jl      0048E447
0048E3EE  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrLen:Integer;
|
0048E3F1  E8125BF7FF            call    00403F08
0048E3F6  85C0                  test    eax, eax
0048E3F8  7E2E                  jle    0048E428

* Reference to: sysutils.Now:System.TDateTime;
|
0048E3FA  E881BAF7FF            call    00409E80
0048E3FF  83C4F8                add    esp, -$08
0048E402  DD1C24                fstp    qword ptr [esp]
0048E405  9B                    wait
0048E406  8D55C8                lea    edx, [ebp-$38]

* Possible String Reference to: 'hhnnss'            //再次取得系统时间 20:00:37 --> 200037
|
0048E409  B844E84800            mov    eax, $0048E844

* Reference to: Unit_00407C78.Proc_0040AAC0
|
0048E40E  E8ADC6F7FF            call    0040AAC0
0048E413  8B45C8                mov    eax, [ebp-$38]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E416  E809AAF7FF            call    00408E24
0048E41B  2BC6                  sub    eax, esi
0048E41D  83F80A                cmp    eax, +$0A      //计算运行时间,不得大于 10 秒
0048E420  0F8FD3030000          jnle    0048E7F9        //这是绝对不能跳的
0048E426  EB1F                  jmp    0048E447
0048E428  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrLen:Integer;
|
0048E42B  E8D85AF7FF            call    00403F08
0048E430  3BD8                  cmp    ebx, eax
0048E432  7D13                  jnl    0048E447
0048E434  8D45D8                lea    eax, [ebp-$28]
0048E437  50                    push    eax
0048E438  B901000000            mov    ecx, $00000001
0048E43D  8BD3                  mov    edx, ebx
0048E43F  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E442  E8C95CF7FF            call    00404110
0048E447  43                    inc    ebx
0048E448  81FBF5010000          cmp    ebx, $000001F5    //将以上时间比较过程重复 500 次
0048E44E  7599                  jnz    0048E3E9          //可 r fl z 跳过
0048E450  BB01000000            mov    ebx, $00000001

--------------------- 注册码应在 'A' - 'Z' 范围内 ---------------------
0048E455  8D45C4                lea    eax, [ebp-$3C]
0048E458  50                    push    eax
0048E459  B901000000            mov    ecx, $00000001
0048E45E  8BD3                  mov    edx, ebx
0048E460  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E463  E8A85CF7FF            call    00404110
0048E468  8B45C4                mov    eax, [ebp-$3C]
0048E46B  BA54E84800            mov    edx, $0048E854

* Reference to: system.@LStrCmp;
|
0048E470  E8A35BF7FF            call    00404018
0048E475  0F877E030000          jnbe    0048E7F9
0048E47B  8D45C0                lea    eax, [ebp-$40]
0048E47E  50                    push    eax
0048E47F  B901000000            mov    ecx, $00000001
0048E484  8BD3                  mov    edx, ebx
0048E486  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E489  E8825CF7FF            call    00404110
0048E48E  8B45C0                mov    eax, [ebp-$40]
0048E491  BA60E84800            mov    edx, $0048E860

* Reference to: system.@LStrCmp;
|
0048E496  E87D5BF7FF            call    00404018
0048E49B  0F8258030000          jb      0048E7F9
0048E4A1  43                    inc    ebx
0048E4A2  83FB15                cmp    ebx, +$15
0048E4A5  75AE                  jnz    0048E455
0048E4A7  8D45D8                lea    eax, [ebp-$28]
0048E4AA  8B55FC                mov    edx, [ebp-$04]

* Reference to: system.@LStrLAsg;
|
0048E4AD  E86E58F7FF            call    00403D20
0048E4B2  8D45DC                lea    eax, [ebp-$24]

* Reference to: system.@LStrClr(String);
|
0048E4B5  E8CE57F7FF            call    00403C88
0048E4BA  BB01000000            mov    ebx, $00000001

--------------------  将注册码倒置 ----------------------
最终效果: WWWWWXXXXXYYYYYZZZZZ  -->  ZZZZZYYYYYXXXXXWWWWW

0048E4BF  8D45BC                lea    eax, [ebp-$44]
0048E4C2  50                    push    eax
0048E4C3  BA14000000            mov    edx, $00000014
0048E4C8  2BD3                  sub    edx, ebx
0048E4CA  42                    inc    edx
0048E4CB  B901000000            mov    ecx, $00000001
0048E4D0  8B45D8                mov    eax, [ebp-$28]

* Reference to: system.@LStrCopy;
|
0048E4D3  E8385CF7FF            call    00404110
0048E4D8  8B55BC                mov    edx, [ebp-$44]
0048E4DB  8D45DC                lea    eax, [ebp-$24]

* Reference to: system.@LStrCat;
|
0048E4DE  E82D5AF7FF            call    00403F10
0048E4E3  43                    inc    ebx
0048E4E4  83FB15                cmp    ebx, +$15
0048E4E7  75D6                  jnz    0048E4BF
0048E4E9  8D45D8                lea    eax, [ebp-$28]
0048E4EC  8B55DC                mov    edx, [ebp-$24]

* Reference to: system.@LStrLAsg;
|
0048E4EF  E82C58F7FF            call    00403D20
0048E4F4  8D45DC                lea    eax, [ebp-$24]

* Reference to: system.@LStrClr(String);
|
0048E4F7  E88C57F7FF            call    00403C88
0048E4FC  BB01000000            mov    ebx, $00000001

--------------------  将字符串首尾交叉 ----------------------
最终效果: ZZZZZYYYYYXXXXXWWWWW  -->  ZXZXZXZXZXYWYWYWYWYW
如果填入的字母都不相同,效果会更强烈些。 :-)

0048E501  FF75DC                push    dword ptr [ebp-$24]
0048E504  8D45B8                lea    eax, [ebp-$48]
0048E507  50                    push    eax
0048E508  B901000000            mov    ecx, $00000001
0048E50D  8BD3                  mov    edx, ebx
0048E50F  8B45D8                mov    eax, [ebp-$28]

* Reference to: system.@LStrCopy;
|
0048E512  E8F95BF7FF            call    00404110
0048E517  FF75B8                push    dword ptr [ebp-$48]
0048E51A  8D45B4                lea    eax, [ebp-$4C]
0048E51D  50                    push    eax
0048E51E  8D530A                lea    edx, [ebx+$0A]
0048E521  B901000000            mov    ecx, $00000001
0048E526  8B45D8                mov    eax, [ebp-$28]

* Reference to: system.@LStrCopy;
|
0048E529  E8E25BF7FF            call    00404110
0048E52E  FF75B4                push    dword ptr [ebp-$4C]
0048E531  8D45DC                lea    eax, [ebp-$24]
0048E534  BA03000000            mov    edx, $00000003

* Reference to: system.@LStrCatN;
|
0048E539  E88A5AF7FF            call    00403FC8
0048E53E  43                    inc    ebx
0048E53F  83FB0B                cmp    ebx, +$0B
0048E542  75BD                  jnz    0048E501
0048E544  8D45D8                lea    eax, [ebp-$28]

* Reference to: system.@LStrClr(String);
|
0048E547  E83C57F7FF            call    00403C88
0048E54C  BB01000000            mov    ebx, $00000001

------------  Sorry,我不知道该怎么概括,只好细说了 ---------------
最终效果:ZXZXZXZXZXYWYWYWYWYW  -->  '2522232021181916171414111291078212219'

0048E551  8D7B40                lea    edi, [ebx+$40]
0048E554  83FF51                cmp    edi, +$51
0048E557  7E03                  jle    0048E55C
0048E559  83EF10                sub    edi, +$10
0048E55C  8D45D4                lea    eax, [ebp-$2C]
0048E55F  50                    push    eax
0048E560  B901000000            mov    ecx, $00000001
0048E565  8BD3                  mov    edx, ebx
0048E567  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;            //下面这个Call是从字符串里取出一个字符
|
0048E56A  E8A15BF7FF            call    00404110
0048E56F  8B45D4                mov    eax, [ebp-$2C]
0048E572  8A00                  mov    al, byte ptr [eax]
0048E574  8BF0                  mov    esi, eax
0048E576  81E6FF000000          and    esi, $000000FF      //得到字符的ASCII值
0048E57C  8D55B0                lea    edx, [ebp-$50]
0048E57F  8BC6                  mov    eax, esi
0048E581  2BC7                  sub    eax, edi          // 这里注意 EDI 的变化规律:
                                                              从 $41 - $51  依次循环
* Reference to: sysutils.IntToStr(System.Integer):System.AnsiString;overload;  //数字变字符
|
0048E583  E830A8F7FF            call    00408DB8
0048E588  8B55B0                mov    edx, [ebp-$50]
0048E58B  8D45D8                lea    eax, [ebp-$28]

* Reference to: system.@LStrCat;              //看看名字就知道,下面的这个Call是连接字符串的
|
0048E58E  E87D59F7FF            call    00403F10
0048E593  43                    inc    ebx
0048E594  83FB15                cmp    ebx, +$15      // 循环取完字符串的每一位
0048E597  75B8                  jnz    0048E551
0048E599  8D45DC                lea    eax, [ebp-$24]
0048E59C  8B55D8                mov    edx, [ebp-$28]

* Reference to: system.@LStrLAsg;
|
0048E59F  E87C57F7FF            call    00403D20
0048E5A4  BB01000000            mov    ebx, $00000001

----------------  连接后的字串每一位应在 '0' - '9' 范围内 ----------------------
这就要求我们输入的注册码为了减少麻烦应该都取靠后的字母。
如果比较靠前,则字串可能会含有负数,导致无法通过检测。

0048E5A9  8D45AC                lea    eax, [ebp-$54]
0048E5AC  50                    push    eax
0048E5AD  B901000000            mov    ecx, $00000001
0048E5B2  8BD3                  mov    edx, ebx
0048E5B4  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E5B7  E8545BF7FF            call    00404110
0048E5BC  8B45AC                mov    eax, [ebp-$54]
0048E5BF  BA6CE84800            mov    edx, $0048E86C

* Reference to: system.@LStrCmp;
|
0048E5C4  E84F5AF7FF            call    00404018
0048E5C9  0F872A020000          jnbe    0048E7F9              //一跳就玩完了
0048E5CF  8D45A8                lea    eax, [ebp-$58]
0048E5D2  50                    push    eax
0048E5D3  B901000000            mov    ecx, $00000001
0048E5D8  8BD3                  mov    edx, ebx
0048E5DA  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E5DD  E82E5BF7FF            call    00404110
0048E5E2  8B45A8                mov    eax, [ebp-$58]
0048E5E5  BA78E84800            mov    edx, $0048E878

* Reference to: system.@LStrCmp;
|
0048E5EA  E8295AF7FF            call    00404018
0048E5EF  0F8204020000          jb      0048E7F9
0048E5F5  43                    inc    ebx
0048E5F6  83FB15                cmp    ebx, +$15            //只取前 20 个字符
0048E5F9  75AE                  jnz    0048E5A9
0048E5FB  33F6                  xor    esi, esi
0048E5FD  BB01000000            mov    ebx, $00000001

0048E602  8D45A4                lea    eax, [ebp-$5C]
0048E605  50                    push    eax
0048E606  B901000000            mov    ecx, $00000001
0048E60B  8BD3                  mov    edx, ebx
0048E60D  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E610  E8FB5AF7FF            call    00404110
0048E615  8B45A4                mov    eax, [ebp-$5C]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;  //字符变数字
|
0048E618  E807A8F7FF            call    00408E24
0048E61D  03F0                  add    esi, eax              //将前18个字符累加至ESI
0048E61F  43                    inc    ebx
0048E620  83FB13                cmp    ebx, +$13
0048E623  75DD                  jnz    0048E602
0048E625  8BDE                  mov    ebx, esi
0048E627  81E301000080          and    ebx, $80000001      //除极端情况(数字字符全为0)外,EBX大都等于1
0048E62D  7905                  jns    0048E634   
0048E62F  4B                    dec    ebx
0048E630  83CBFE                or      ebx, -$02
0048E633  43                    inc    ebx
0048E634  8D45A0                lea    eax, [ebp-$60]
0048E637  50                    push    eax
0048E638  B901000000            mov    ecx, $00000001    //传入 Lstrcopy 的三个参数
0048E63D  BA13000000            mov    edx, $00000013
0048E642  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E645  E8C65AF7FF            call    00404110
0048E64A  8B45A0                mov    eax, [ebp-$60]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E64D  E8D2A7F7FF            call    00408E24
0048E652  3BD8                  cmp    ebx, eax          //这一句也就基本上要求了数字串的第19位'1' 
0048E654  0F859F010000          jnz    0048E7F9
0048E65A  33F6                  xor    esi, esi
0048E65C  BB01000000            mov    ebx, $00000001

----------------  将数字串中前 18 位每个数字 3 倍的个位数进行累加 ----------------------
最终效果:'2522232021181916171414111291078212219'  --> '252223202118191617'  -->
(2 * 3) mod 10 + (5 * 3) mod 10 +(2 * 3) mod 10 + .... + (7 * 3) mod 10 = 85

0048E661  8D459C                lea    eax, [ebp-$64]
0048E664  50                    push    eax
0048E665  B901000000            mov    ecx, $00000001
0048E66A  8BD3                  mov    edx, ebx
0048E66C  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E66F  E89C5AF7FF            call    00404110
0048E674  8B459C                mov    eax, [ebp-$64]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E677  E8A8A7F7FF            call    00408E24
0048E67C  8D0440                lea    eax, [eax+eax*2]    //  X * 3
0048E67F  B90A000000            mov    ecx, $0000000A
0048E684  99                    cdq
0048E685  F7F9                  idiv    ecx
0048E687  03F2                  add    esi, edx    // 个位数相加
0048E689  43                    inc    ebx
0048E68A  83FB13                cmp    ebx, +$13    // 取前18位
0048E68D  75D2                  jnz    0048E661

------------------------  再求累加和的个位数  --------------------------
最终效果:85 mod 10 = 5

0048E68F  8BC6                  mov    eax, esi
0048E691  B90A000000            mov    ecx, $0000000A
0048E696  99                    cdq
0048E697  F7F9                  idiv    ecx
0048E699  8BDA                  mov    ebx, edx
0048E69B  8D4598                lea    eax, [ebp-$68]
0048E69E  50                    push    eax


0048E69F  B901000000            mov    ecx, $00000001
0048E6A4  BA14000000            mov    edx, $00000014
0048E6A9  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E6AC  E85F5AF7FF            call    00404110
0048E6B1  8B4598                mov    eax, [ebp-$68]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E6B4  E86BA7F7FF            call    00408E24
0048E6B9  3BD8                  cmp    ebx, eax      //累加和的个位数('5')应和数字串的第20位相等
0048E6BB  0F8538010000          jnz    0048E7F9
0048E6C1  8D45E0                lea    eax, [ebp-$20]
0048E6C4  50                    push    eax
0048E6C5  B903000000            mov    ecx, $00000003
0048E6CA  BA10000000            mov    edx, $00000010
0048E6CF  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;                        //  Lstrcopy(string,10,3) = '617'
|                                                            不过根据后来的跟踪,
0048E6D2  E8395AF7FF            call    00404110          好像这次取出的字符串无关紧要
0048E6D7  8D45EC                lea    eax, [ebp-$14]

* Reference to: system.@LStrClr(String);
|
0048E6DA  E8A955F7FF            call    00403C88
0048E6DF  8D45E8                lea    eax, [ebp-$18]

* Reference to: system.@LStrClr(String);
|
0048E6E2  E8A155F7FF            call    00403C88
0048E6E7  8D45E4                lea    eax, [ebp-$1C]

* Reference to: system.@LStrClr(String);
|
0048E6EA  E89955F7FF            call    00403C88
0048E6EF  BB01000000            mov    ebx, $00000001

------------  Sorry,我又不知道该怎么说了,看最终效果吧 ---------------
最终效果:'2522232021181916171414111291078212219'  --> 
          '252' + '223' + '202' + '118' + '191'    -->
          '22211'(第一位) + '52019'(第二位) + '23281' (第三位)   

0048E6F4  8D4594                lea    eax, [ebp-$6C]
0048E6F7  50                    push    eax
0048E6F8  8BC3                  mov    eax, ebx
0048E6FA  48                    dec    eax
0048E6FB  8D3440                lea    esi, [eax+eax*2]
0048E6FE  8BD6                  mov    edx, esi
0048E700  42                    inc    edx
0048E701  B901000000            mov    ecx, $00000001
0048E706  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;                       
|                                                         
0048E709  E8025AF7FF            call    00404110         
0048E70E  8B5594                mov    edx, [ebp-$6C]
0048E711  8D45EC                lea    eax, [ebp-$14]

* Reference to: system.@LStrCat;
|
0048E714  E8F757F7FF            call    00403F10
0048E719  8D4590                lea    eax, [ebp-$70]
0048E71C  50                    push    eax
0048E71D  8BD6                  mov    edx, esi
0048E71F  83C202                add    edx, +$02
0048E722  B901000000            mov    ecx, $00000001
0048E727  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E72A  E8E159F7FF            call    00404110
0048E72F  8B5590                mov    edx, [ebp-$70]
0048E732  8D45E8                lea    eax, [ebp-$18]

* Reference to: system.@LStrCat;
|
0048E735  E8D657F7FF            call    00403F10
0048E73A  8D458C                lea    eax, [ebp-$74]
0048E73D  50                    push    eax
0048E73E  8BD6                  mov    edx, esi
0048E740  83C203                add    edx, +$03
0048E743  B901000000            mov    ecx, $00000001
0048E748  8B45DC                mov    eax, [ebp-$24]

* Reference to: system.@LStrCopy;
|
0048E74B  E8C059F7FF            call    00404110
0048E750  8B558C                mov    edx, [ebp-$74]
0048E753  8D45E4                lea    eax, [ebp-$1C]

* Reference to: system.@LStrCat;
|
0048E756  E8B557F7FF            call    00403F10
0048E75B  43                    inc    ebx
0048E75C  83FB06                cmp    ebx, +$06                //共循环5次,每次取出3个字符
0048E75F  7593                  jnz    0048E6F4
0048E761  8B45E0                mov    eax, [ebp-$20]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;   
|
0048E764  E8BBA6F7FF            call    00408E24
0048E769  BEE7030000            mov    esi, $000003E7
0048E76E  2BF0                  sub    esi, eax                //  999 - 617 = 382 = $17E
0048E770  8B45EC                mov    eax, [ebp-$14]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E773  E8ACA6F7FF            call    00408E24
0048E778  BF9F860100            mov    edi, $0001869F
0048E77D  2BF8                  sub    edi, eax              //  99999 - 22211 = 77788 = $12FDC
0048E77F  8B45E8                mov    eax, [ebp-$18]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E782  E89DA6F7FF            call    00408E24
0048E787  BB9F860100            mov    ebx, $0001869F
0048E78C  2BD8                  sub    ebx, eax              //  99999 - 52019 = 47980 = $BB6C
0048E78E  8B45E4                mov    eax, [ebp-$1C]

* Reference to: sysutils.StrToInt(System.AnsiString):System.Integer;
|
0048E791  E88EA6F7FF            call    00408E24
0048E796  BA9F860100            mov    edx, $0001869F
0048E79B  2BD0                  sub    edx, eax              //  99999 - 23281 = 76718 = $12BAE
0048E79D  8955D0                mov    [ebp-$30], edx
0048E7A0  8BC3                  mov    eax, ebx
0048E7A2  B964000000            mov    ecx, $00000064
0048E7A7  99                    cdq
0048E7A8  F7F9                  idiv    ecx
0048E7AA  8BCA                  mov    ecx, edx
0048E7AC  2BF1                  sub    esi, ecx
0048E7AE  8BC3                  mov    eax, ebx
0048E7B0  BE64000000            mov    esi, $00000064
0048E7B5  99                    cdq
0048E7B6  F7FE                  idiv    esi                // 47980 ÷ 100 = 479 ... 80
0048E7B8  8BF0                  mov    esi, eax
0048E7BA  8BC6                  mov    eax, esi
0048E7BC  2BC1                  sub    eax, ecx
0048E7BE  7906                  jns    0048E7C6          // 若商小于余数,则商+1000(反正不能出现负数)
0048E7C0  81C6E8030000          add    esi, $000003E8
0048E7C6  2BF1                  sub    esi, ecx
0048E7C8  3B75F4                cmp    esi, [ebp-$0C]    //关键判断:比较399(= 479 - 80)和$8D(常量)
0048E7CB  752C                  jnz    0048E7F9          //跳则死,不跳则活。
0048E7CD  8BF7                  mov    esi, edi
0048E7CF  8BC6                  mov    eax, esi
0048E7D1  2BC3                  sub    eax, ebx          // $12FDC - $BB6C = $7470
0048E7D3  7906                  jns    0048E7DB          // 若商小于余数,则商+100000(反正不能出现负数)
0048E7D5  81C6A0860100          add    esi, $000186A0
0048E7DB  2BF3                  sub    esi, ebx
0048E7DD  8B45F8                mov    eax, [ebp-$08]
0048E7E0  B90A000000            mov    ecx, $0000000A
0048E7E5  99                    cdq
0048E7E6  F7F9                  idiv    ecx
0048E7E8  8945F8                mov    [ebp-$08], eax    //机器码:572463 idiv 10 = 57246 =$DF9E
0048E7EB  3B75F8                cmp    esi, [ebp-$08]    //关键判断:比较$7470(= $12FDC - $BB6C)和$DF9E
0048E7EE  7509                  jnz    0048E7F9          //跳则死,不跳则活。 
0048E7F0  8B45D0                mov    eax, [ebp-$30]
0048E7F3  2BC7                  sub    eax, edi
0048E7F5  C645F301              mov    byte ptr [ebp-$0D], $01  //到此处写入注册成功标志
0048E7F9  33C0                  xor    eax, eax
0048E7FB  5A                    pop    edx
0048E7FC  59                    pop    ecx
0048E7FD  59                    pop    ecx
0048E7FE  648910                mov    fs:[eax], edx

****** FINALLY                          //异常处理,释放单元,不去管它。
|

* Possible String Reference to: '奅骭^[嬪]?
|
0048E801  6830E84800            push    $0048E830
0048E806  8D458C                lea    eax, [ebp-$74]
0048E809  BA11000000            mov    edx, $00000011

* Reference to: system.@LStrArrayClr;
|
0048E80E  E89954F7FF            call    00403CAC
0048E813  8D45D4                lea    eax, [ebp-$2C]
0048E816  BA07000000            mov    edx, $00000007

* Reference to: system.@LStrArrayClr;
|
0048E81B  E88C54F7FF            call    00403CAC
0048E820  8D45FC                lea    eax, [ebp-$04]

* Reference to: system.@LStrClr(String);
|
0048E823  E86054F7FF            call    00403C88
0048E828  C3                    ret

0048E829  E96E4EF7FF            jmp    0040369C
0048E82E  EBD6                  jmp    0048E806

****** END
|
0048E830  8A45F3                mov    al, byte ptr [ebp-$0D]    //将注册标志赋予AL,返回供后面调用
0048E833  5F                    pop    edi
0048E834  5E                    pop    esi
0048E835  5B                    pop    ebx
0048E836  8BE5                  mov    esp, ebp
0048E838  5D                    pop    ebp
0048E839  C3                    ret



-------------------------0048E36C  call  End-----------------------------------------


写得挺长,但分析的确是比较快的。现在总结一下注册码比较流程:
机器码:572463 =$8BC2F
注册码:WWWWW-XXXXX-YYYYY-ZZZZZ

WWWWWXXXXXYYYYYZZZZZ  --->  ZZZZZYYYYYXXXXXWWWWW  --->  ZXZXZXZXZXYWYWYWYWYW  --->
'2522232021181916171414111291078212219'  ---> '252223202118191617'  --->
'252' + '223' + '202' + '118' + '191'  ---> '22211' + '52019' + '23281'  --->
1、99999 - 52019 = 47980  ÷ 100 = 479 ... 80  --->  要求 479 - 80 等于常量 141 = &8D
  99999 - 85798 = 14201 
2、99999 - 22211 = 77788  - 47980 = 29808  ---> 要求与机器码:572463 idiv 10 = 57246相等
 

下面该写注册机了:
首先应该知道,对注册码的 20 位进行穷举是不太现实的。那么我们是不是有办法减少穷举的位数呢。我想了一些办法,去掉了些无关紧要的

位数,但还是比较大,效率很低,估计软件的作者是不会使用的。:)我们必须另辟蹊径。

由上面的注册流程可知,最重要的部分是那个数字串('2522232021181916171414111291078212219')。一般情况下,该串的长度是大于20位的,

除非在极端情况(比如'11111111111111111111',此时注册码反转交叉后应该是类似这个样子:'BCDEFGHIJKLMNOPQRSTU')下。而最核心的只

有15位数字,用7、8位注册码就可产生。这就意味着注册码的某些位数可以忽略不计。而在这15位数字中,又有5位没有参与关键判断(指的是

0048E7C8、0048E7EB两处判断),这样我们又可舍弃 5 位数字。

假设我们需要的两个 5 位数分别为 M(对应例子中的22211) 和 N(对应例子中的52019)。由流程我们可以看到,真正的注册码要求:(

99999 - N )  ÷ 100 = P ... Q  , P - Q = 141 ,
∴ P = Q + 141

∴ 99999 - N = 100 * P + Q = 101 * Q + 14100
∴ N = 99999 - ( 101 * Q + 14100 ) = 85899 - 101 * Q

又∵ 99999 - M - (99999 - N) = 99999 - 14100 - 101 * Q - M = 57246
∴ M =  99999 - 14100 - 101 * Q - 57246 = 28653 - 101 * Q

这样,我们用一位变量和机器码便表示出了两个 5 位数。第三个 5 位数由于没起什么作用,所以我们不妨设它为 11111。

例如:
令Q = 1,则
N = 85899 - 101 * 1 = 85798
M = 28653 - 101 * 1 = 28552

于是15位的字串就是 281851571591281;
又∵ 第16-18位没有什么限制,所以就取随便取个212;
第19位通常状况下为1(见0048E627);
第20位的值等于数字串前18位('281851571591281212')每个数字三倍和的个位数(∵((a mod n) +(b mod n)) mod n = (a+b) mod n),此

时为7;

∴该数字串为 '28185157159128121217'
然后,我们对数字分组。分组的原则就是,让后面的数尽量的小。因为 'Z' 的 ASCII 值为90,而到后面加上的数会很大(比如83、84等),

容易超出界限。不够20 组可再补齐。补齐原则同上。再分别对每一组数字一次加上65、66、67、……、85,如下:

2  8  18  5  15  7  15  9  12  8  12  12  1    7    1      1    1    1    1    1
65  66  67  68  69  70  71  72  73  74  75  76  77    78    79    80    81  82    83    84
67  74  85  73  84  77  86  81  85  82  87  88  78    85    80    81    82  83    84    85
C  J  U  I  T    M  V    Q  U    R  W    X    N    U    P      Q    R    S    T    U

这样,CJUITMVQURWXNUPQRSTU  ---> CUTVUWNPRTJIMQRXUQSU  ---> USQUX-RQMIJ-TRPNW-UVTUC

再附上注册机源码(Delphi 6 + WinXP Pro 下调试通过),一切OK。

procedure TForm1.Button1Click(Sender: TObject);
var
  Machinecode,N,Tmp,i:Integer;
  Tmpstr,tmpstr1,tmpstr2:Str

  • 标 题:注册机源代码!(Delphi 6 + WinXP Pro 下调试通过),未作特殊情况处理. (1千字)
  • 作 者:crack007
  • 时 间:2002-8-16 18:43:45
  • 链 接:http://bbs.pediy.com

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Label1: TLabel;
    Button1: TButton;
    Button2: TButton;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  Machinecode,N,Tmp,i:Integer;
  Tmpstr,tmpstr1,tmpstr2:String;
begin

Machinecode:=StrToInt(Edit1.Text);
Tmpstr1:=IntToStr(85798-(Machinecode - Machinecode mod 10) div 10);
Tmpstr2:='85798';

for i:=1 to 5 do
  Tmpstr:=Tmpstr+Tmpstr1[i]+Tmpstr2[i]+'1';

Tmpstr:=Tmpstr+'212';
Tmp:=0;

for i:=1 to 18 do
  Tmp:=Tmp+StrToInt(Tmpstr[i]) *3;

Tmpstr:=Tmpstr+'1'+IntToStr(Tmp mod 10)+'11111111111';
N:=1;
Tmpstr1:='';

for i:=65 to 84 do
  if StrToInt(copy(Tmpstr,N,2))+i<=90 then
  begin
    Tmpstr1:=Tmpstr1+chr(StrToInt(copy(Tmpstr,N,2))+i);
    N:=N+2;
  end
  else begin
    Tmpstr1:=Tmpstr1+chr(StrToInt(copy(Tmpstr,N,1))+i);
    N:=N+1;
  end;
edit2.text:=Tmpstr1[20]+Tmpstr1[18]+Tmpstr1[16]+Tmpstr1[14]+Tmpstr1[12]+'-'
          +Tmpstr1[10]+Tmpstr1[8]+Tmpstr1[6]+Tmpstr1[4]+Tmpstr1[2]+'-'
          +Tmpstr1[19]+Tmpstr1[17]+Tmpstr1[15]+Tmpstr1[13]+Tmpstr1[11]+'-'
          +Tmpstr1[9]+Tmpstr1[7]+Tmpstr1[5]+Tmpstr1[3]+Tmpstr1[1];
end;

end.