某國產軟體 - XX E-mail 郵差 的演算法分析,感興趣者請進! (32千字)

看雪資料發表於2002-08-16

某國產軟體 - 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: 'nN?脛E_^[]?
|
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: 'E_^[]?
|
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

相關文章