吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|pipinga.com

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 15423|回復: 184

[原創] [新春禮物]_0_1_0_Editor 注冊算法分析及全部版本注冊機、網絡在線驗證分析和驗證模擬

    [復制鏈接]
樓主
solly 發表于 2020-1-29 17:03 回帖獎勵
本帖最后由 solly 于 2020-1-30 22:27 編輯

外面疫情嚴重,窩家里沒事,對論壇中下手較多的 _010_Editor 進行完整和徹底的注冊算法分析。通過分析和測試,其所有版本的算法是一樣的(經測試,Windows 下從 v2.1.4 到 v10.0.0 的 x86 及 x64 版本是通用的,其它平臺,如 MacOS 和 Linux,沒有測試)。


下面以 v10.0.0 x86 版本為例進行分析。


慣例,首先看看文件信息:

是由 VS + QT5 編譯而來的,沒有加殼,是分析算法的良心軟件。節信息如下:

沒有什么不良信息,一切正常。


首先進入軟件看看,啟動該軟件,界面如下:

這個配色,有點騷,進行注冊看看(菜單 “Tools”->"Register"進入),輸入注冊假碼數據:


點擊 “Check License”,看到如下提示信息:


很良心地提示你下手的地點和方法了。


用 OD 載入軟件,顯示如下:

基于 QT 框架編譯的標準模式,也沒什么特別的地方。在 OD 中直接搜索字符串,定位 invalid name or password.“,如下圖所示:

雙擊該字符串,來到引用其的代碼處,如下圖所示:

再在該代碼指令上右鍵菜單,可以看到,有另一條指令跳轉到這里,我們”轉到“菜單,跳轉到該指令,如下圖所示:

可以看到,這里有3個比較,檢查注冊結果。上面(0x0123BA36,可能地址不一樣,但應該也是 0xnnnnBA36形式,最高2字節可能不同)有一個 jmp 指令,在其下一條指令處右鍵”轉到“,如下圖所示:

可以看到,這里也是從另一指令跳轉而來的,同樣方法,跳轉上一條指令,如下圖所示:

這里又是一條比較指令(cmp edi, 0xDB),先説一下,這個0xDB是成功注冊的標志。
再一次在這一條指令上右鍵”轉到“,如下圖所示:

可以看到有兩個地方的指令跳轉到這里了。我們先不跳轉,再往上看,又有一條JMP 指令(JMP 0x0123BBD9),我們在這條指令的下面一條指令上右鍵”轉到“,如下圖所示:

可以看到,也有一條指令跳轉到這里,這里跳轉過去,有一條JNZ指令,如下圖所示:


同樣方法繼續回溯,就會來到下面位置:

這里就是注冊算法調用處了,如上圖所示,這幾行代碼就是調用注冊算法的:
[Asm] 純文本查看 復制代碼
016FB7D3   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]                        ;  第三次引用[0371805C]
016FB7D9   .  68 3C470000         push    0x473C                                            ;  18236
016FB7DE   .  6A 0B               push    0xB                                               ;  11
016FB7E0   .  E8 07F350FF         call    00C0AAEC                                          ;  注冊碼檢查
016FB7E5   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]                        ;  第四次引用[0371805C]
016FB7EB   .  8BD8                mov     ebx, eax                                          ;  注冊標志 ebx == eax
016FB7ED   .  68 3C470000         push    0x473C                                            ;  18236
016FB7F2   .  6A 0B               push    0xB                                               ;  11
016FB7F4   .  E8 5FE650FF         call    00C09E58                                          ;  注冊碼檢查 及 試用期擴充的檢查
016FB7F9   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]                        ;  第五次引用[0371805C]
016FB7FF   .  8BF8                mov     edi, eax                                          ;  版本標識 edi == eax
016FB801   .  81FB E7000000       cmp     ebx, 0xE7                                         ;  成功標志3
016FB807   .  0F84 F3000000       je      016FB900
016FB80D   .  8379 2C 00          cmp     dword ptr [ecx+0x2C], 0x0                         ;  成功標志4,與3二選一, ds:[0384547C]
016FB811   .  0F84 E9000000       je      016FB900

注意:前面説了,由于系統重定位的原因,每次運行的指令地址和數據地址的高2字節是變化的,從上面代碼與截圖的對比就可以看出來,因此我們只看低2字節的偏移量即可。
另外,下面的位置也調用了注冊算法函數,我們前面也看過這個位置了,如下圖所示:

具體調用代碼如下:
[Asm] 純文本查看 復制代碼
016FB8E6   > \8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]        ;  全部檢查通過來到這里
016FB8EC   .  68 3C470000         push    0x473C                            ;  18236
016FB8F1   .  6A 0B               push    0xB                               ;  11
016FB8F3   .  E8 60E550FF         call    00C09E58
016FB8F8   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]
016FB8FE   .  8BF8                mov     edi, eax
016FB900   >  81FF DB000000       cmp     edi, 0xDB                         ;  成功標志2,edi==0xDB
016FB906   .  0F85 2C010000       jnz     016FBA38                          ;  不相等則去試用期過期檢查

下面我們開始跟蹤其注冊算法,先在這個位置下一個斷點,如下圖所示:


0xnnnnB7A7 位置下一個斷點。

按 F9 運行該軟件,在注冊界面,輸入注冊碼假碼信息,如下圖所示:


在上圖中也可以看到目前的注冊狀態:Evaluation Version - 30 Days Left。點 ”Check License“ 按鈕,OD 馬上斷了下來,如下圖所示:

這一段代碼如下所示:
[Asm] 純文本查看 復制代碼
016FB7A7   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]        ;  第一次引用[0371805C]
016FB7AD   .  50                  push    eax                               ;  [eax] ===> 用戶名
016FB7AE   .  C645 FC 08          mov     byte ptr [ebp-0x4], 0x8           ;  VC的資源計數
016FB7B2   .  E8 F8E450FF         call    00C09CAF                          ;  檢查名字是否由單、雙引號包含,有則去除單、雙引號
016FB7B7   .  8D4D D8             lea     ecx, dword ptr [ebp-0x28]         ;  [ecx] ===> 用戶名
016FB7BA   .  C645 FC 01          mov     byte ptr [ebp-0x4], 0x1
016FB7BE   .  FF15 B094BD03       call    dword ptr [<&Qt5Core.QString::~QS>;  用戶名字符串的引用計數減 1,為0時就釋放內存
016FB7C4   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]        ;  第二次引用[0371805C]
016FB7CA   .  8D45 E8             lea     eax, dword ptr [ebp-0x18]
016FB7CD   .  50                  push    eax
016FB7CE   .  E8 B07550FF         call    00C02D83                          ;  將注冊碼中的大寫'O'和小寫'o'換成數字'0',將小寫字母'l'換成數字'1'
016FB7D3   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]        ;  第三次引用[0371805C]
016FB7D9   .  68 3C470000         push    0x473C                            ;  18236
016FB7DE   .  6A 0B               push    0xB                               ;  11
016FB7E0   .  E8 07F350FF         call    00C0AAEC                          ;  注冊碼檢查
016FB7E5   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]        ;  第四次引用[0371805C]
016FB7EB   .  8BD8                mov     ebx, eax                          ;  注冊標志 ebx == eax
016FB7ED   .  68 3C470000         push    0x473C                            ;  18236
016FB7F2   .  6A 0B               push    0xB                               ;  11
016FB7F4   .  E8 5FE650FF         call    00C09E58                          ;  注冊碼檢查 及 試用期擴充的檢查
016FB7F9   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]        ;  第五次引用[0371805C]
016FB7FF   .  8BF8                mov     edi, eax                          ;  版本標識 edi == eax
016FB801   .  81FB E7000000       cmp     ebx, 0xE7                         ;  成功標志3
016FB807   .  0F84 F3000000       je      016FB900
016FB80D   .  8379 2C 00          cmp     dword ptr [ecx+0x2C], 0x0         ;  成功標志4,與3二選一, ds:[0384547C]
016FB811   .  0F84 E9000000       je      016FB900
016FB817   .  6A 00               push    0x0
016FB819   .  8BCE                mov     ecx, esi
016FB81B   .  E8 BB6D50FF         call    00C025DB
016FB820   .  85C0                test    eax, eax
016FB822   .  0F89 8C000000       jns     016FB8B4                          ;  eax非負,需要再次判斷(時長)
[/size][size=4]

按 F8 運行到如下位置:

這個調用就是調用注冊算法函數。不過,所有的 call 調用,都是調用一個 JMP 指令,通過JMP指令再跳轉到相應的函數。如下圖所示,就是注冊算法函數,但是其開始地址并不是 call 后面的地址。
按 F7 進入注冊算法函數。


該函數結尾如下圖所示,有三種退出方式:



我們回到函數前面,如下圖所示:

可以看到,最下面有一個調用(call 00749D0E),這是一個對注冊格式進行檢查的函數,先 F8 執行到該調用,再按 F7 進入調用,如下圖所示:


首先檢查長度,并進行內碼轉換,由 Unicode 碼轉換成 utf-8 編碼。轉換結果如下圖OD數據區所示:

下面説一下 QT 字符串(QString)在內存中保存的格式,定義如下:
[C++] 純文本查看 復制代碼
struct QString {
ULONG Reference_Count;
ULONG Length;
ULONG Capacity;
ULONG Unknow;      ////  附加屬性,總是 0x10,包括 isRightToLeft 等
char  Buffer[16];
};

從上圖中 OD 的數據區可以看到,保存的注冊碼數據存貯格式:引用次數為 1,長度為 0x18,字符串容量為 0x19,其它屬性為 0x00000010,內容為 "1111-2222-3333-4444-5555"
下面是注冊碼以 Unicode 格式保存時的存貯格式:
[Asm] 純文本查看 復制代碼
06D45538  01 00 00 00 18 00 00 00 38 00 00 00 10 00 00 00  ......8......
06D45548  31 00 31 00 31 00 31 00 2D 00 32 00 32 00 32 00  1.1.1.1.-.2.2.2.
06D45558  32 00 2D 00 33 00 33 00 33 00 33 00 2D 00 34 00  2.-.3.3.3.3.-.4.
06D45568  34 00 34 00 34 00 2D 00 35 00 35 00 35 00 35 00  4.4.4.-.5.5.5.5.
06D45578  00 00 AD BA 0D F0 AD BA                          ...瓠?瓠?

函數再檢查注冊碼的”-“號分隔符是否符合要求,并調用 call 0xnnnn984A 函數,將大寫”O“,小寫”o“字母轉換成數字”0“,將小寫”l“字母轉換成數字”1“,然后將字母按 36 進制(0~9,A~Z)轉換成數字。調用完成后,將這此轉換后成數字組合成一個字節數組 。
從該函數返回后,就會將字符串注冊碼全部轉換并組成一個字節數組了,如下圖OD的數據區所示:


然后就從注冊碼字節數組(sn_int[])中取出 sn_int[3],這個字節標示的是注冊類型,有3種類型,如下所示:

1、0x9C,這個是沒有免費技術支持,沒有免費升級的注冊類型,注冊碼中有版本號檢查,必須大于當前軟件的版本,否則提示注冊碼過期。注冊碼只有4段。
2、0xAC,這個是有免費技術支持、有免費升級的完整注冊類型,不過會檢查注冊碼中的過期時間(天數,從發布時間算起),這些免費支持是有期限的,會過期。注冊碼有5段,是最完整的注冊碼。
3、0xFC,這個不算正式注冊版本,是延長試用期版本,最長可延長為5年試用期(從發布日期算起),這個版本會有一些檢查(注冊表中的數據),保證延期合法。注冊碼只有4段。
具體見下圖,是對 0x9C 類型的注冊碼進行檢查:

上圖中,調用函數 call 0xnnnn7351,就是解碼版本數據,即解碼 sn_int[0] ^ sn_int[6] 的值,這個值在 v10.0.0 版中,要大于或等于 0x0B

注冊算法函數的完整代碼如下,其中加了注釋:
[Asm] 純文本查看 復制代碼
01DDCC20   > \55                   push    ebp
01DDCC21   .  8BEC                 mov     ebp, esp
01DDCC23   .  6A FF                push    -0x1
01DDCC25   .  68 898F3002          push    02308F89                                          ;  SEH
01DDCC2A   .  64:A1 00000000       mov     eax, dword ptr fs:[0]
01DDCC30   .  50                   push    eax
01DDCC31   .  83EC 18              sub     esp, 0x18
01DDCC34   .  53                   push    ebx
01DDCC35   .  56                   push    esi
01DDCC36   .  57                   push    edi
01DDCC37   .  A1 E039BD03          mov     eax, dword ptr [0x3BD39E0]
01DDCC3C   .  33C5                 xor     eax, ebp
01DDCC3E   .  50                   push    eax
01DDCC3F   .  8D45 F4              lea     eax, dword ptr [ebp-0xC]
01DDCC42   .  64:A3 00000000       mov     dword ptr fs:[0], eax                             ;  SEH
01DDCC48   .  8BF9                 mov     edi, ecx                                          ;  函數參數
01DDCC4A   .  8D5F 04              lea     ebx, dword ptr [edi+0x4]                          ;  ebx=edi+4
01DDCC4D   .  C745 F0 00000000     mov     dword ptr [ebp-0x10], 0x0
01DDCC54   .  8BCB                 mov     ecx, ebx                                          ;  [ecx] ===> 用戶名
01DDCC56   .  C747 30 00000000     mov     dword ptr [edi+0x30], 0x0
01DDCC5D   .  C747 18 00000000     mov     dword ptr [edi+0x18], 0x0
01DDCC64   .  C747 34 00000000     mov     dword ptr [edi+0x34], 0x0
01DDCC6B   .  FF15 C494BD03        call    dword ptr [<&Qt5Core.QString::isEmpty>]           ;  Qt5Core.QString::isEmpty
01DDCC71   .  84C0                 test    al, al                                            ;  al==0,非空
01DDCC73   .  0F85 75020000        jnz     01DDCEEE
01DDCC79   .  8D4F 08              lea     ecx, dword ptr [edi+0x8]                          ;  [ecx] ===> 注冊碼
01DDCC7C   .  FF15 C494BD03        call    dword ptr [<&Qt5Core.QString::isEmpty>]           ;  Qt5Core.QString::isEmpty
01DDCC82   .  84C0                 test    al, al                                            ;  al==0,非空
01DDCC84   .  0F85 64020000        jnz     01DDCEEE
01DDCC8A   .  8D45 DC              lea     eax, dword ptr [ebp-0x24]                         ;  [eax] ===> obj
01DDCC8D   .  8BCF                 mov     ecx, edi                                          ;  emptyString
01DDCC8F   .  50                   push    eax
01DDCC90   .  E8 79D0E2FE          call    00C09D0E                                          ;  將注冊碼轉換成字節數組(按36進制轉換)
01DDCC95   .  BE 74ADBC03          mov     esi, 03BCAD74                                     ;  [esi] ===> "999",黑名單列表
01DDCC9A   .  8D9B 00000000        lea     ebx, dword ptr [ebx]                              ;  [ebx] ===> 用戶名
01DDCCA0   >  FF36                 push    dword ptr [esi]                                   ;  "999"
01DDCCA2   .  8BCB                 mov     ecx, ebx
01DDCCA4   .  FF15 A09DBD03        call    dword ptr [<&Qt5Core.QString::operator==>]        ;  Qt5Core.QString::operator==
01DDCCAA   .  84C0                 test    al, al                                            ;  (initial cpu selection)
01DDCCAC   .  0F85 23020000        jnz     01DDCED5                                          ;  al == 1,則跳轉到注冊碼錯誤
01DDCCB2   .  83C6 04              add     esi, 0x4
01DDCCB5   .  81FE 78ADBC03        cmp     esi, 03BCAD78                                     ;  目前只有一組(黑名單)
01DDCCBB   .^ 7C E3                jl      short 01DDCCA0
01DDCCBD   .  8A5D DF              mov     bl, byte ptr [ebp-0x21]                           ;  sn_int[3]
01DDCCC0   .  8A7D E1              mov     bh, byte ptr [ebp-0x1F]                           ;  sn_int[5]
01DDCCC3   .  80FB 9C              cmp     bl, 0x9C                                          ;  Switch (cases 9C..FC)
01DDCCC6   .  75 70                jnz     short 01DDCD38
01DDCCC8   .  8A45 DC              mov     al, byte ptr [ebp-0x24]                           ;  Case 9C of switch 01DDCCC3
01DDCCCB   .  3245 E2              xor     al, byte ptr [ebp-0x1E]
01DDCCCE   .  8845 E8              mov     byte ptr [ebp-0x18], al                           ;  UCHAR ch = sn_int[0] ^ sn_int[6]
01DDCCD1   .  8A45 DD              mov     al, byte ptr [ebp-0x23]
01DDCCD4   .  3245 E3              xor     al, byte ptr [ebp-0x1D]
01DDCCD7   .  FF75 E8              push    dword ptr [ebp-0x18]                              ;  下面函數的參數:ch
01DDCCDA   .  0FB6C8               movzx   ecx, al                                           ;  UWORD c = sn_int[1] ^ sn_int[7]
01DDCCDD   .  B8 00010000          mov     eax, 0x100
01DDCCE2   .  66:0FAFC8            imul    cx, ax                                            ;  c *= 0x100
01DDCCE6   .  8A45 DE              mov     al, byte ptr [ebp-0x22]
01DDCCE9   .  32C7                 xor     al, bh
01DDCCEB   .  0FB6C0               movzx   eax, al                                           ;  UWORD a = sn_int[2] ^ sn_int[5]
01DDCCEE   .  66:03C8              add     cx, ax
01DDCCF1   .  0FB7F1               movzx   esi, cx                                           ;  ULONG s = a + c = 0xA93B = 0xA900 + 0x3B
01DDCCF4   .  E8 58A6E2FE          call    00C07351                                          ;  getCheck1(), a = ((ch ^ 0x18) + 0x3D) ^ 0xA7,解碼版本標識
01DDCCF9   .  0FB6C0               movzx   eax, al                                           ;  ULONG ver_id = a
01DDCCFC   .  56                   push    esi                                               ;  下面函數的參數:s, 0x5511
01DDCCFD   .  8947 1C              mov     dword ptr [edi+0x1C], eax                         ;  全局變量 ver_id == 0x2D, ds:[0x03F7218C] == 0x2D
01DDCD00   .  E8 A1B5E2FE          call    00C082A6                                          ;  call getCheck2(),解碼用戶數
01DDCD05   .  8B4F 1C              mov     ecx, dword ptr [edi+0x1C]                         ;  c = 0x2D, ver_id需要大于0x0B
01DDCD08   .  83C4 08              add     esp, 0x8
01DDCD0B   .  0FB7C0               movzx   eax, ax                                           ;  函數返回值 a
01DDCD0E   .  8947 20              mov     dword ptr [edi+0x20], eax                         ;  ULONG license_user_count = a, [0x03F72190] = 0x00000000
01DDCD11   .  85C9                 test    ecx, ecx                                          ;  ver_id == 0 ???
01DDCD13   .  0F84 BC010000        je      01DDCED5
01DDCD19   .  85C0                 test    eax, eax                                          ;  license_user_count == 0 ???
01DDCD1B   .  0F84 B4010000        je      01DDCED5
01DDCD21   .  3D E8030000          cmp     eax, 0x3E8                                        ;  license_user_count > 1000??
01DDCD26   .  0F87 A9010000        ja      01DDCED5
01DDCD2C   .  83F9 02              cmp     ecx, 0x2                                          ;  license_user_count < 2 ??
01DDCD2F   .  1BF6                 sbb     esi, esi                                          ;  esi = (ecx<2)?-1:0
01DDCD31   .  23F1                 and     esi, ecx                                          ;  esi &= ecx
01DDCD33   .  E9 B3000000          jmp     01DDCDEB
01DDCD38   >  80FB FC              cmp     bl, 0xFC
01DDCD3B   .  75 1F                jnz     short 01DDCD5C
01DDCD3D   .  C747 1C FF000000     mov     dword ptr [edi+0x1C], 0xFF                        ;  ver_id = -1, ds:[0384546C]; Case FC of switch 01DDCCC3
01DDCD44   .  BE FF000000          mov     esi, 0xFF                                         ;  free_upgrade_days = -1, days
01DDCD49   .  C747 20 01000000     mov     dword ptr [edi+0x20], 0x1                         ;  license_user_count = 1, ds:[03845470]
01DDCD50   .  C747 30 01000000     mov     dword ptr [edi+0x30], 0x1                         ;  flag3 = 1, ds:[03F721A0]
01DDCD57   .  E9 8F000000          jmp     01DDCDEB
01DDCD5C   >  80FB AC              cmp     bl, 0xAC
01DDCD5F   .  0F85 70010000        jnz     01DDCED5
01DDCD65   .  8A45 DD              mov     al, byte ptr [ebp-0x23]                           ;  sn_int[1]; Case AC of switch 01DDCCC3
01DDCD68   .  3245 E3              xor     al, byte ptr [ebp-0x1D]                           ;  sn_int[7]
01DDCD6B   .  0FB6C8               movzx   ecx, al                                           ;  c = sn_int[1] ^ sn_int[7]
01DDCD6E   .  B8 00010000          mov     eax, 0x100
01DDCD73   .  66:0FAFC8            imul    cx, ax
01DDCD77   .  8A45 DE              mov     al, byte ptr [ebp-0x22]                           ;  sn_int[2]
01DDCD7A   .  32C7                 xor     al, bh                                            ;  sn_int[5]
01DDCD7C   .  C747 1C 02000000     mov     dword ptr [edi+0x1C], 0x2                         ;  ver_id = 2
01DDCD83   .  0FB6C0               movzx   eax, al                                           ;  a = sn_int[2] ^ sn_int[5]
01DDCD86   .  66:03C8              add     cx, ax
01DDCD89   .  0FB7C1               movzx   eax, cx                                           ;  enc_lic_user_count = (c<<8) + a
01DDCD8C   .  50                   push    eax
01DDCD8D   .  E8 14B5E2FE          call    00C082A6                                          ;  call getCheck2(),解碼用戶數
01DDCD92   .  0FB7C0               movzx   eax, ax
01DDCD95   .  83C4 04              add     esp, 0x4
01DDCD98   .  8947 20              mov     dword ptr [edi+0x20], eax                         ;  license_user_count = eax
01DDCD9B   .  85C0                 test    eax, eax                                          ;  license_user_count > 0
01DDCD9D   .  0F84 32010000        je      01DDCED5
01DDCDA3   .  3D E8030000          cmp     eax, 0x3E8                                        ;  license_user_count <= 1000
01DDCDA8   .  0F87 27010000        ja      01DDCED5
01DDCDAE   .  0FB655 E5            movzx   edx, byte ptr [ebp-0x1B]                          ;  sn_int[9]
01DDCDB2   .  0FB64D E0            movzx   ecx, byte ptr [ebp-0x20]                          ;  sn_int[4]
01DDCDB6   .  0FB6C7               movzx   eax, bh
01DDCDB9   .  33D0                 xor     edx, eax                                          ;  ULONG a = sn_int[5] ^ sn_int[9]
01DDCDBB   .  0FB645 E4            movzx   eax, byte ptr [ebp-0x1C]                          ;  sn_int[8]
01DDCDBF   .  33C8                 xor     ecx, eax                                          ;  ULONG b = sn_int[4] ^ sn_int[8]
01DDCDC1   .  C1E2 08              shl     edx, 0x8
01DDCDC4   .  0FB645 E2            movzx   eax, byte ptr [ebp-0x1E]                          ;  sn_int[6]
01DDCDC8   .  03D1                 add     edx, ecx
01DDCDCA   .  0FB64D DC            movzx   ecx, byte ptr [ebp-0x24]                          ;  sn_int[0]
01DDCDCE   .  C1E2 08              shl     edx, 0x8
01DDCDD1   .  33C8                 xor     ecx, eax                                          ;  ULONG c = sn_int[0] ^ sn_int[6]
01DDCDD3   .  03D1                 add     edx, ecx                                          ;  ULONG d = (((a<<8) + b)<<8) + c;
01DDCDD5   .  68 278C5B00          push    0x5B8C27
01DDCDDA   .  52                   push    edx
01DDCDDB   .  E8 71DCE2FE          call    00C0AA51                                          ;  call getCheck3(edx),解碼免費升級時間
01DDCDE0   .  83C4 08              add     esp, 0x8
01DDCDE3   .  8945 F0              mov     dword ptr [ebp-0x10], eax                         ;  free upgrade days
01DDCDE6   .  8947 34              mov     dword ptr [edi+0x34], eax                         ;  free upgrade days
01DDCDE9   .  8BF0                 mov     esi, eax                                          ;  free upgrade days
01DDCDEB   >  8D45 EC              lea     eax, dword ptr [ebp-0x14]                         ;  上面 case 處理完都到這里
01DDCDEE   .  50                   push    eax
01DDCDEF   .  8D4F 04              lea     ecx, dword ptr [edi+0x4]                          ;  [ecx] ===> 用戶名
01DDCDF2   .  FF15 1C9CBD03        call    dword ptr [<&Qt5Core.QString::toUtf8>]            ;  call (Qt5Core.QString::toUtf8),Unicode2utf8
01DDCDF8   .  FF77 20              push    dword ptr [edi+0x20]                              ;  license_user_count
01DDCDFB   .  33C0                 xor     eax, eax
01DDCDFD   .  C745 FC 00000000     mov     dword ptr [ebp-0x4], 0x0
01DDCE04   .  80FB FC              cmp     bl, 0xFC                                          ;  bl == license_type
01DDCE07   .  8D4D EC              lea     ecx, dword ptr [ebp-0x14]                         ;  [ecx] ===> 用戶名(UTF8編碼)
01DDCE0A   .  56                   push    esi                                               ;  esi == upgrade days
01DDCE0B   .  0F95C0               setne   al                                                ;  bl != 0xFC
01DDCE0E   .  50                   push    eax                                               ;  al = (bl != 0xFC)?1:0,1-注冊版,0-評估版
01DDCE0F   .  FF15 9C94BD03        call    dword ptr [<&Qt5Core.QByteArray::data>]           ;  Qt5Core.QByteArray::data
01DDCE15   .  50                   push    eax                                               ;  eax ===>  用戶名,字符串 "solly"
01DDCE16   .  E8 D263E2FE          call    00C031ED                                          ;  getNameCheck(char * name, ULONG is_registered, ULONG free_upgrade_days, ULONG user_count)
01DDCE1B   .  8BD0                 mov     edx, eax                                          ;  nameCheck = 0xBAED7A3E
01DDCE1D   .  83C4 10              add     esp, 0x10                                         ;  下面將 nameCheck 分成 4 字節與 sn_int[] 中的字節比較
01DDCE20   .  3855 E0              cmp     byte ptr [ebp-0x20], dl                           ;  sn_int[4]
01DDCE23   .  0F85 81000000        jnz     01DDCEAA
01DDCE29   .  8BCA                 mov     ecx, edx
01DDCE2B   .  C1E9 08              shr     ecx, 0x8
01DDCE2E   .  3AF9                 cmp     bh, cl                                            ;  sn_int[5]
01DDCE30   .  75 78                jnz     short 01DDCEAA
01DDCE32   .  8BCA                 mov     ecx, edx
01DDCE34   .  C1E9 10              shr     ecx, 0x10
01DDCE37   .  384D E2              cmp     byte ptr [ebp-0x1E], cl                           ;  sn_int[6]
01DDCE3A   .  75 6E                jnz     short 01DDCEAA
01DDCE3C   .  C1E8 18              shr     eax, 0x18
01DDCE3F   .  3845 E3              cmp     byte ptr [ebp-0x1D], al                           ;  sn_int[7]
01DDCE42   .  75 66                jnz     short 01DDCEAA
01DDCE44   .  80FB 9C              cmp     bl, 0x9C                                          ;  Switch (cases 9C..FC)
01DDCE47   .  75 0F                jnz     short 01DDCE58
01DDCE49   .  8B45 08              mov     eax, dword ptr [ebp+0x8]                          ;  Case 9C of switch 01DDCE44
01DDCE4C   .  3B47 1C              cmp     eax, dword ptr [edi+0x1C]                         ;  0x0B(eax) <= version_id_in_sn,eax-函數參數1: 0x0B
01DDCE4F   .  76 52                jbe     short 01DDCEA3                                    ;  不高于跳轉(小于或等于)
01DDCE51   .  BE 4E000000          mov     esi, 0x4E                                         ;  過期,老版本的注冊碼
01DDCE56   .  EB 57                jmp     short 01DDCEAF
01DDCE58   >  80FB FC              cmp     bl, 0xFC
01DDCE5B   .  75 2E                jnz     short 01DDCE8B
01DDCE5D   .  0FB64D DE            movzx   ecx, byte ptr [ebp-0x22]                          ;  sn_int[2]; Case FC of switch 01DDCE44
01DDCE61   .  0FB645 DD            movzx   eax, byte ptr [ebp-0x23]                          ;  sn_int[1]
01DDCE65   .  C1E1 08              shl     ecx, 0x8
01DDCE68   .  03C8                 add     ecx, eax
01DDCE6A   .  0FB645 DC            movzx   eax, byte ptr [ebp-0x24]                          ;  sn_int[0]
01DDCE6E   .  C1E1 08              shl     ecx, 0x8
01DDCE71   .  52                   push    edx
01DDCE72   .  03C8                 add     ecx, eax                                          ;  ecx = sn_int[2]sn_int[1]sn_int[0]
01DDCE74   .  51                   push    ecx
01DDCE75   .  E8 D7DBE2FE          call    00C0AA51                                          ;  call getCheck3(ecx),解碼試用期延長的日期
01DDCE7A   .  83C4 08              add     esp, 0x8
01DDCE7D   .  85C0                 test    eax, eax
01DDCE7F   .  74 29                je      short 01DDCEAA
01DDCE81   .  8947 18              mov     dword ptr [edi+0x18], eax                         ;  evaluation extends days
01DDCE84   .  BE 93000000          mov     esi, 0x93
01DDCE89   .  EB 24                jmp     short 01DDCEAF
01DDCE8B   >  80FB AC              cmp     bl, 0xAC
01DDCE8E   .  75 1A                jnz     short 01DDCEAA
01DDCE90   .  8B45 F0              mov     eax, dword ptr [ebp-0x10]                         ;  free upgrade days; Case AC of switch 01DDCE44
01DDCE93   .  85C0                 test    eax, eax                                          ;  free upgrade days > 0
01DDCE95   .  74 13                je      short 01DDCEAA
01DDCE97   .  3945 0C              cmp     dword ptr [ebp+0xC], eax                          ;  free upgrade days >= release days(函數參數2:0x473C)
01DDCE9A   .  76 07                jbe     short 01DDCEA3
01DDCE9C   .  BE 4E000000          mov     esi, 0x4E                                         ;  過期
01DDCEA1   .  EB 0C                jmp     short 01DDCEAF
01DDCEA3   >  BE 2D000000          mov     esi, 0x2D                                         ;  注冊碼正確
01DDCEA8   .  EB 05                jmp     short 01DDCEAF
01DDCEAA   >  BE E7000000          mov     esi, 0xE7                                         ;  試用期已結束或注冊碼無效; Default case of switch 01DDCE44
01DDCEAF   >  8D4D EC              lea     ecx, dword ptr [ebp-0x14]                         ;  [ecx] ===> 用戶名
01DDCEB2   .  C745 FC FFFFFFFF     mov     dword ptr [ebp-0x4], -0x1
01DDCEB9   .  FF15 8C94BD03        call    dword ptr [<&Qt5Core.QByteArray::~QByteArray>]    ;  Qt5Core.QByteArray::~QByteArray
01DDCEBF   .  8BC6                 mov     eax, esi                                          ;  esi == 0xE7, 0x2D, 0x4E, 0x93 等, 0x2D 表示注冊碼正確
01DDCEC1   .  8B4D F4              mov     ecx, dword ptr [ebp-0xC]
01DDCEC4   .  64:890D 00000000     mov     dword ptr fs:[0], ecx
01DDCECB   .  59                   pop     ecx
01DDCECC   .  5F                   pop     edi
01DDCECD   .  5E                   pop     esi
01DDCECE   .  5B                   pop     ebx
01DDCECF   .  8BE5                 mov     esp, ebp
01DDCED1   .  5D                   pop     ebp
01DDCED2   .  C2 0800              retn    0x8
01DDCED5   >  B8 E7000000          mov     eax, 0xE7                                         ;  注冊碼無效; Default case of switch 01DDCCC3
01DDCEDA   .  8B4D F4              mov     ecx, dword ptr [ebp-0xC]
01DDCEDD   .  64:890D 00000000     mov     dword ptr fs:[0], ecx
01DDCEE4   .  59                   pop     ecx
01DDCEE5   .  5F                   pop     edi
01DDCEE6   .  5E                   pop     esi
01DDCEE7   .  5B                   pop     ebx
01DDCEE8   .  8BE5                 mov     esp, ebp
01DDCEEA   .  5D                   pop     ebp
01DDCEEB   .  C2 0800              retn    0x8
01DDCEEE   >  B8 93000000          mov     eax, 0x93                                         ;  用戶名或注冊碼為空到這里
01DDCEF3   .  8B4D F4              mov     ecx, dword ptr [ebp-0xC]
01DDCEF6   .  64:890D 00000000     mov     dword ptr fs:[0], ecx
01DDCEFD   .  59                   pop     ecx
01DDCEFE   .  5F                   pop     edi
01DDCEFF   .  5E                   pop     esi
01DDCF00   .  5B                   pop     ebx
01DDCF01   .  8BE5                 mov     esp, ebp
01DDCF03   .  5D                   pop     ebp
01DDCF04   .  C2 0800              retn    0x8

從上面函數返回后,我們馬上再進入另一個函數(call 0xnnnn9E58),這個函數還會再次調用上面的注冊算法函數,同時還會調另一個函數,對試用期延長的注冊碼進行檢查,如下圖所示:

從上圖可以看,首先再次調用注冊碼檢查函數(0xnnnnD55E  call 0xnnnnAAEC),然后再調用另一個函數(call 0xnnnn2CE8),這個函數對 0xFC 類型的注冊碼進行進一步的合法性檢查。下面我們"F7"再次進入注冊碼算法函數,看看函數內其它幾個調用,如下所示:
[Asm] 純文本查看 復制代碼
01DDCDF8   .  FF77 20             push    dword ptr [edi+0x20]                              ;  flag2
01DDCDFB   .  33C0                xor     eax, eax
01DDCDFD   .  C745 FC 00000000    mov     dword ptr [ebp-0x4], 0x0
01DDCE04   .  80FB FC             cmp     bl, 0xFC                                          ;  bl == license_type
01DDCE07   .  8D4D EC             lea     ecx, dword ptr [ebp-0x14]                         ;  [ecx] ===> 用戶名(UTF8編碼)
01DDCE0A   .  56                  push    esi                                               ;  esi == 0x00000000, upgrade days
01DDCE0B   .  0F95C0              setne   al                                                ;  bl != 0xFC
01DDCE0E   .  50                  push    eax                                               ;  al = (bl != 0xFC)?1:0,1-注冊版,0-評估版
01DDCE0F   .  FF15 9C94BD03       call    dword ptr [<&Qt5Core.QByteArray::data>]           ;  Qt5Core.QByteArray::data
01DDCE15   .  50                  push    eax                                               ;  eax ===>  用戶名,字符串 "solly"
01DDCE16   .  E8 D263E2FE         call    00C031ED                                          ;  getNameCheck(char * name, ULONG check1, ULONG check2, ULONG flag)
01DDCE1B   .  8BD0                mov     edx, eax                                          ;  check = 0xBAED7A3E


注冊算法函數調用了一個函數(call 0xnnnn31ED),對用戶名進行處理,該函數如下圖所示:


通過查表方式,對用戶名進行變換,生成一個32位的整數,如下圖所示:

循環對名字每個字符進行處理,如下圖所示:

用戶名處理函數具體代碼如下:
[Asm] 純文本查看 復制代碼
01DDC180  /> \55                  push    ebp
01DDC181  |.  8BEC                mov     ebp, esp
01DDC183  |.  83EC 10             sub     esp, 0x10
01DDC186  |.  8B55 08             mov     edx, dword ptr [ebp+0x8]                          ;  edx ===> 用戶名
01DDC189  |.  33C9                xor     ecx, ecx                                          ;  0
01DDC18B  |.  56                  push    esi
01DDC18C  |.  8BF2                mov     esi, edx
01DDC18E  |.  894D FC             mov     dword ptr [ebp-0x4], ecx                          ;  long name_check = 0;
01DDC191  |.  57                  push    edi
01DDC192  |.  8D7E 01             lea     edi, dword ptr [esi+0x1]                          ;  edi ===> name[1]
01DDC195  |>  8A06                /mov     al, byte ptr [esi]                               ;  char ch = (* name);
01DDC197  |.  46                  |inc     esi                                              ;  name++
01DDC198  |.  84C0                |test    al, al
01DDC19A  |.^ 75 F9               \jnz     short 01DDC195
01DDC19C  |.  2BF7                sub     esi, edi                                          ;  esi === length(name)
01DDC19E  |.  33FF                xor     edi, edi                                          ;  int i= 0;
01DDC1A0  |.  85F6                test    esi, esi
01DDC1A2  |.  0F8E F0000000       jle     01DDC298
01DDC1A8  |.  53                  push    ebx
01DDC1A9  |.  8B5D 14             mov     ebx, dword ptr [ebp+0x14]                         ;  參數: 0x000003E8
01DDC1AC  |.  894D F0             mov     dword ptr [ebp-0x10], ecx                         ;  0
01DDC1AF  |.  894D F4             mov     dword ptr [ebp-0xC], ecx                          ;  0
01DDC1B2  |.  8B4D 10             mov     ecx, dword ptr [ebp+0x10]                         ;  參數: 0x00000000
01DDC1B5  |.  C1E3 04             shl     ebx, 0x4
01DDC1B8  |.  2B5D 14             sub     ebx, dword ptr [ebp+0x14]                         ;  ebx = param4 * 15 = 0x03E8 * 0x0F = 0x00003A98
01DDC1BB  |.  C1E1 04             shl     ecx, 0x4
01DDC1BE  |.  034D 10             add     ecx, dword ptr [ebp+0x10]                         ;  ecx = param3 + param3 * 16
01DDC1C1  |.  894D F8             mov     dword ptr [ebp-0x8], ecx                          ;  ecx = param3 * 17
01DDC1C4  |>  0FB60417            /movzx   eax, byte ptr [edi+edx]                          ;  ULONG ch = name[i]
01DDC1C8  |.  50                  |push    eax                                              ; /c
01DDC1C9  |.  FF15 B092BD03       |call    dword ptr [<&MSVCR120.toupper>]                  ; \toupper
01DDC1CF  |.  8BD0                |mov     edx, eax                                         ;  long idx = uppcase(name[i])
01DDC1D1  |.  83C4 04             |add     esp, 0x4
01DDC1D4  |.  8B0C95 A8A8BC03     |mov     ecx, dword ptr [edx*4+0x3BCA8A8]                 ;  查表, name_tbl_check = name_table[idx];
01DDC1DB  |.  034D FC             |add     ecx, dword ptr [ebp-0x4]                         ;  name_check += name_tbl_check;
01DDC1DE  |.  837D 0C 00          |cmp     dword ptr [ebp+0xC], 0x0                         ;  參數:1
01DDC1E2  |.  74 4A               |je      short 01DDC22E
01DDC1E4  |.  8D42 0D             |lea     eax, dword ptr [edx+0xD]
01DDC1E7  |.  25 FF000000         |and     eax, 0xFF                                        ;  long a = (idx + 0x0D) & 0xFF;
01DDC1EC  |.  330C85 A8A8BC03     |xor     ecx, dword ptr [eax*4+0x3BCA8A8]                 ;  查表, name_check ^= name_table[a];
01DDC1F3  |.  8D42 2F             |lea     eax, dword ptr [edx+0x2F]
01DDC1F6  |.  25 FF000000         |and     eax, 0xFF                                        ;  long b = (idx + 0x2F) & 0xFF;
01DDC1FB  |.  0FAF0C85 A8A8BC03   |imul    ecx, dword ptr [eax*4+0x3BCA8A8]                 ;  查表, name_check *= name_table[ b ];
01DDC203  |.  8B45 F8             |mov     eax, dword ptr [ebp-0x8]
01DDC206  |.  0FB6C0              |movzx   eax, al                                          ;  long c = (UCHAR)local_var1
01DDC209  |.  030C85 A8A8BC03     |add     ecx, dword ptr [eax*4+0x3BCA8A8]                 ;  查表, name_check += name_table[c];
01DDC210  |.  0FB6C3              |movzx   eax, bl                                          ;  long d = (UCHAR)(sn_flag * 15) , 0x98
01DDC213  |.  030C85 A8A8BC03     |add     ecx, dword ptr [eax*4+0x3BCA8A8]                 ;  查表, name_check += name_table[d];
01DDC21A  |.  8B45 F4             |mov     eax, dword ptr [ebp-0xC]                         ;  local_var, (0)
01DDC21D  |.  0FB6C0              |movzx   eax, al                                          ;  long e = (UCHAR)(local_var2) , 0x98
01DDC220  |.  030C85 A8A8BC03     |add     ecx, dword ptr [eax*4+0x3BCA8A8]                 ;  查表, name_check += name_table[e];
01DDC227  |.  8BC1                |mov     eax, ecx                                         ;  保存返回值
01DDC229  |.  8945 FC             |mov     dword ptr [ebp-0x4], eax                         ;  保存 name_check
01DDC22C  |.  EB 48               |jmp     short 01DDC276
01DDC22E  |>  8D42 3F             |lea     eax, dword ptr [edx+0x3F]
01DDC231  |.  25 FF000000         |and     eax, 0xFF
01DDC236  |.  330C85 A8A8BC03     |xor     ecx, dword ptr [eax*4+0x3BCA8A8]
01DDC23D  |.  8D42 17             |lea     eax, dword ptr [edx+0x17]
01DDC240  |.  25 FF000000         |and     eax, 0xFF
01DDC245  |.  0FAF0C85 A8A8BC03   |imul    ecx, dword ptr [eax*4+0x3BCA8A8]
01DDC24D  |.  8B45 F8             |mov     eax, dword ptr [ebp-0x8]
01DDC250  |.  0FB6C0              |movzx   eax, al
01DDC253  |.  030C85 A8A8BC03     |add     ecx, dword ptr [eax*4+0x3BCA8A8]
01DDC25A  |.  0FB6C3              |movzx   eax, bl
01DDC25D  |.  030C85 A8A8BC03     |add     ecx, dword ptr [eax*4+0x3BCA8A8]
01DDC264  |.  8B45 F0             |mov     eax, dword ptr [ebp-0x10]                        ;  local_var3
01DDC267  |.  0FB6C0              |movzx   eax, al
01DDC26A  |.  030C85 A8A8BC03     |add     ecx, dword ptr [eax*4+0x3BCA8A8]
01DDC271  |.  8BC1                |mov     eax, ecx                                         ;  保存返回值
01DDC273  |.  894D FC             |mov     dword ptr [ebp-0x4], ecx                         ;  保存 name_check
01DDC276  |>  8345 F4 13          |add     dword ptr [ebp-0xC], 0x13                        ;  公共部分, local_var2 += 0x13;
01DDC27A  |.  47                  |inc     edi                                              ;  i++
01DDC27B  |.  8345 F8 09          |add     dword ptr [ebp-0x8], 0x9                         ;  local_var1 += 9;
01DDC27F  |.  83C3 0D             |add     ebx, 0xD                                         ;  參數 ebx += 0x0D;
01DDC282  |.  8345 F0 07          |add     dword ptr [ebp-0x10], 0x7                        ;  local_var3 += 0x07;
01DDC286  |.  8B55 08             |mov     edx, dword ptr [ebp+0x8]                         ;  edx ===> 用戶名,"solly"
01DDC289  |.  3BFE                |cmp     edi, esi                                         ;  esi == 0x05,用戶名長度
01DDC28B  |.^ 0F8C 33FFFFFF       \jl      01DDC1C4
01DDC291  |.  5B                  pop     ebx
01DDC292  |.  5F                  pop     edi
01DDC293  |.  5E                  pop     esi
01DDC294  |.  8BE5                mov     esp, ebp
01DDC296  |.  5D                  pop     ebp
01DDC297  |.  C3                  retn                                                      ;  ret_value = 0xBAED7A3E
01DDC298  |>  5F                  pop     edi
01DDC299  |.  8BC1                mov     eax, ecx
01DDC29B  |.  5E                  pop     esi
01DDC29C  |.  8BE5                mov     esp, ebp
01DDC29E  |.  5D                  pop     ebp
01DDC29F  \.  C3                  retn

另外,當注冊類型為 0xFC 時,會讀取注冊表中的數據進行檢查,如下圖所示的幾個注冊表鍵值:

不過數據都是編碼加密過的,需要解碼才能識別,包括試用剩余次數(0x09),版本標識(0x0B),發布(或安裝)日期,有效可用日期(試用期或正式版免費支持時間)等等數據。試用版有效時長檢查調用(call 0xnnnn2CE8)的代碼如下:
[Asm] 純文本查看 復制代碼
01DDC720   > \55                  push    ebp
01DDC721   .  8BEC                mov     ebp, esp
01DDC723   .  6A FF               push    -0x1
01DDC725   .  68 E98E3002         push    02308EE9
01DDC72A   .  64:A1 00000000      mov     eax, dword ptr fs:[0]
01DDC730   .  50                  push    eax
01DDC731   .  51                  push    ecx
01DDC732   .  57                  push    edi
01DDC733   .  A1 E039BD03         mov     eax, dword ptr [0x3BD39E0]                        ;  SEH Object handler
01DDC738   .  33C5                xor     eax, ebp
01DDC73A   .  50                  push    eax
01DDC73B   .  8D45 F4             lea     eax, dword ptr [ebp-0xC]
01DDC73E   .  64:A3 00000000      mov     dword ptr fs:[0], eax
01DDC744   .  8BF9                mov     edi, ecx
01DDC746   .  FF75 08             push    dword ptr [ebp+0x8]                               ;  0x0B
01DDC749   .  E8 DDEAE2FE         call    00C0B22B                                          ;  檢查注冊表中的 versiob_id 與軟件內置的verid是否一致
01DDC74E   .  FF75 08             push    dword ptr [ebp+0x8]                               ;  get 0x0B, (verid)
01DDC751   .  8BCF                mov     ecx, edi
01DDC753   .  E8 71B1E2FE         call    00C078C9                                          ;  get object
01DDC758   .  8BCF                mov     ecx, edi
01DDC75A   .  E8 3262E2FE         call    00C02991                                          ;  get object (0x0FE19483 ==> 0x4770),檢查是否存在??
01DDC75F   .  8D45 F0             lea     eax, dword ptr [ebp-0x10]
01DDC762   .  50                  push    eax
01DDC763   .  E8 AFC2E2FE         call    00C08A17                                          ;  get object, registry object or file object: "010Editor.dat"
01DDC768   .  8BC8                mov     ecx, eax
01DDC76A   .  E8 1EF2E2FE         call    00C0B98D                                          ;  get 0x4770, (上次成功注冊的日期)
01DDC76F   .  84C0                test    al, al                                            ;  al == 1,讀取成功
01DDC771   .  74 08               je      short 01DDC77B
01DDC773   .  8B45 F0             mov     eax, dword ptr [ebp-0x10]                         ;  0x4770
01DDC776   .  8947 10             mov     dword ptr [edi+0x10], eax                         ;  通過參數返回
01DDC779   .  EB 17               jmp     short 01DDC792
01DDC77B   >  E8 20BCE2FE         call    00C083A0
01DDC780   .  6A 01               push    0x1
01DDC782   .  50                  push    eax
01DDC783   .  8947 10             mov     dword ptr [edi+0x10], eax
01DDC786   .  E8 8CC2E2FE         call    00C08A17
01DDC78B   .  8BC8                mov     ecx, eax
01DDC78D   .  E8 81DAE2FE         call    00C0A213
01DDC792   >  837F 18 00          cmp     dword ptr [edi+0x18], 0x0                         ;  0x6F85,來自SN的值
01DDC796   .  76 0D               jbe     short 01DDC7A5
01DDC798   .  837F 30 00          cmp     dword ptr [edi+0x30], 0x0                         ;  0x01
01DDC79C   .  74 07               je      short 01DDC7A5
01DDC79E   .  8BCF                mov     ecx, edi
01DDC7A0   .  E8 04BDE2FE         call    00C084A9                                          ;  注冊表中的用戶名檢查
01DDC7A5   >  8B4F 10             mov     ecx, dword ptr [edi+0x10]                         ;  0x4770
01DDC7A8   .  8D45 F0             lea     eax, dword ptr [ebp-0x10]
01DDC7AB   .  83C1 1E             add     ecx, 0x1E                                         ;  ecx == 0x4770 + 0x1E, 0x1E==30,30天試用期
01DDC7AE   .  394F 18             cmp     dword ptr [edi+0x18], ecx                         ;  時間比較(0x7755 < 0x478E ??)
01DDC7B1   .  50                  push    eax
01DDC7B2   .  0F434F 18           cmovnb  ecx, dword ptr [edi+0x18]                         ;  不小于則取較大的時間值, ecx = (0x7755<ecx)?ecx:0x7755
01DDC7B6   .  894F 18             mov     dword ptr [edi+0x18], ecx
01DDC7B9   .  E8 59C2E2FE         call    00C08A17                                          ;  get object, registry object or file object: "010Editor.dat"
01DDC7BE   .  8BC8                mov     ecx, eax
01DDC7C0   .  E8 F09CE2FE         call    00C064B5                                          ;  get 0x7071 (上次成功注冊的最長有效日期)
01DDC7C5   .  84C0                test    al, al                                            ;  al == 1,表示成功
01DDC7C7   .  0F84 8F000000       je      01DDC85C
01DDC7CD   .  8B45 F0             mov     eax, dword ptr [ebp-0x10]                         ;  0x7071
01DDC7D0   .  8947 14             mov     dword ptr [edi+0x14], eax                         ;  0x7071
01DDC7D3   .  3B47 18             cmp     eax, dword ptr [edi+0x18]                         ;  時間比較(0x7071<0x7755)
01DDC7D6   .  0F83 95000000       jnb     01DDC871                                          ;  不低于跳轉,因此SN中的days應等于或小于0x7071
01DDC7DC   .  E8 BFBBE2FE         call    00C083A0                                          ;  生成當前日期,0x4771(2020/01/28)
01DDC7E1   .  8B4F 14             mov     ecx, dword ptr [edi+0x14]                         ;  0x7071, (max)
01DDC7E4   .  8BD0                mov     edx, eax                                          ;  current days, 0x4771
01DDC7E6   .  3BD1                cmp     edx, ecx                                          ;  當前日期 < 最后成功的有效日期
01DDC7E8   .  73 17               jnb     short 01DDC801                                    ;  需要跳轉(不低于跳轉)
01DDC7EA   .  B8 38010000         mov     eax, 0x138                                        ;  over???
01DDC7EF   .  8B4D F4             mov     ecx, dword ptr [ebp-0xC]
01DDC7F2   .  64:890D 00000000    mov     dword ptr fs:[0], ecx
01DDC7F9   .  59                  pop     ecx
01DDC7FA   .  5F                  pop     edi
01DDC7FB   .  8BE5                mov     esp, ebp
01DDC7FD   .  5D                  pop     ebp
01DDC7FE   .  C2 0400             retn    0x4
01DDC801   >  8B47 10             mov     eax, dword ptr [edi+0x10]                         ;  0x4770, (上次成功注冊的日期)
01DDC804   .  85C0                test    eax, eax
01DDC806   .  74 1E               je      short 01DDC826                                    ;  時間異常
01DDC808   .  85C9                test    ecx, ecx                                          ;  0x7071, (上次成功注冊的最長有效日期)
01DDC80A   .  74 1A               je      short 01DDC826                                    ;  時間異常
01DDC80C   .  3BC8                cmp     ecx, eax
01DDC80E   .  72 16               jb      short 01DDC826                                    ;  時間異常(低于跳轉)
01DDC810   .  8B47 18             mov     eax, dword ptr [edi+0x18]                         ;  sn中的日期
01DDC813   .  2BC1                sub     eax, ecx                                          ;  SN中的日期 - (上次成功注冊的最長有效日期)
01DDC815   .  3D 21070000         cmp     eax, 0x721                                        ;  最大試用期不能大于 0x721, 1825days(5年)
01DDC81A   .  77 0A               ja      short 01DDC826                                    ;  高于跳轉
01DDC81C   .  3BCA                cmp     ecx, edx
01DDC81E   .  73 51               jnb     short 01DDC871                                    ;  需要跳轉
01DDC820   .  8957 14             mov     dword ptr [edi+0x14], edx
01DDC823   .  52                  push    edx
01DDC824   .  EB 3F               jmp     short 01DDC865
01DDC826   >  68 38D16A03         push    036AD138                                          ;  ASCII "The system clock has been tampered with. Sorry, but this ends your trial period. Please register."
01DDC82B   .  8D4D 08             lea     ecx, dword ptr [ebp+0x8]
01DDC82E   .  FF15 AC9DBD03       call    dword ptr [<&Qt5Core.QString::QString>]           ;  Qt5Core.QString::QString
01DDC834   .  8D45 08             lea     eax, dword ptr [ebp+0x8]
01DDC837   .  C745 FC 00000000    mov     dword ptr [ebp-0x4], 0x0
01DDC83E   .  50                  push    eax
01DDC83F   .  E8 7151E2FE         call    00C019B5
01DDC844   .  83C4 04             add     esp, 0x4
01DDC847   .  C745 FC FFFFFFFF    mov     dword ptr [ebp-0x4], -0x1
01DDC84E   .  8D4D 08             lea     ecx, dword ptr [ebp+0x8]
01DDC851   .  FF15 B094BD03       call    dword ptr [<&Qt5Core.QString::~QString>]          ;  Qt5Core.QXmlStreamStringRef::~QXmlStreamStringRef
01DDC857   .  8B47 18             mov     eax, dword ptr [edi+0x18]
01DDC85A   .  EB 05               jmp     short 01DDC861
01DDC85C   >  E8 3FBBE2FE         call    00C083A0                                          ;  取當前日期時間
01DDC861   >  50                  push    eax
01DDC862   .  8947 14             mov     dword ptr [edi+0x14], eax
01DDC865   >  E8 ADC1E2FE         call    00C08A17                                          ;  讀取"010Editor.dat"的文件時間???
01DDC86A   .  8BC8                mov     ecx, eax
01DDC86C   .  E8 0D00E3FE         call    00C0C87E
01DDC871   >  8B47 14             mov     eax, dword ptr [edi+0x14]                         ;  0x7071
01DDC874   .  3B47 18             cmp     eax, dword ptr [edi+0x18]                         ;  時間比較(0x7071<0x7755)
01DDC877   .  1BC0                sbb     eax, eax                                          ;  eax == -1,才正確, 最大有效日期必須小于SN中日期
01DDC879   .  83E0 ED             and     eax, 0xFFFFFFED                                   ;  -19
01DDC87C   .  83C0 2A             add     eax, 0x2A                                         ;  42
01DDC87F   .  8B4D F4             mov     ecx, dword ptr [ebp-0xC]
01DDC882   .  64:890D 00000000    mov     dword ptr fs:[0], ecx
01DDC889   .  59                  pop     ecx
01DDC88A   .  5F                  pop     edi
01DDC88B   .  8BE5                mov     esp, ebp
01DDC88D   .  5D                  pop     ebp
01DDC88E   .  C2 0400             retn    0x4



上面説的調用注冊算法函數和試用期檢查函數的函數代碼如下:
[Asm] 純文本查看 復制代碼
01DDD540  /> \55                  push    ebp
01DDD541  |.  8BEC                mov     ebp, esp
01DDD543  |.  56                  push    esi
01DDD544  |.  8BF1                mov     esi, ecx
01DDD546  |.  837E 2C 00          cmp     dword ptr [esi+0x2C], 0x0                         ;  flag6
01DDD54A  |.  74 0A               je      short 01DDD556
01DDD54C  |.  B8 13010000         mov     eax, 0x113
01DDD551  |.  5E                  pop     esi
01DDD552  |.  5D                  pop     ebp
01DDD553  |.  C2 0800             retn    0x8
01DDD556  |>  57                  push    edi
01DDD557  |.  FF75 0C             push    dword ptr [ebp+0xC]                               ;  0x473C, release days
01DDD55A  |.  8B7D 08             mov     edi, dword ptr [ebp+0x8]                          ;  0x0B, version_id
01DDD55D  |.  57                  push    edi
01DDD55E  |.  E8 89D5E2FE         call    00C0AAEC                                          ;  注冊碼檢查(第二次檢查)
01DDD563  |.  83F8 2D             cmp     eax, 0x2D                                         ;  ‘-’; Switch (cases 2D..E7)
01DDD566  |.  0F84 A3000000       je      01DDD60F                                          ;  正確
01DDD56C  |.  83F8 4E             cmp     eax, 0x4E                                         ;  ‘N’
01DDD56F  |.  74 78               je      short 01DDD5E9
01DDD571  |.  3D E7000000         cmp     eax, 0xE7
01DDD576  |.  74 66               je      short 01DDD5DE
01DDD578  |.  57                  push    edi                                               ;  0x0B; Default case of switch 01DDD563
01DDD579  |.  8BCE                mov     ecx, esi
01DDD57B  |.  E8 6857E2FE         call    00C02CE8                                          ;  試用周期檢查
01DDD580  |.  83F8 17             cmp     eax, 0x17                                         ;  試用周期延長成功; Switch (cases 17..138)
01DDD583  |.  74 4E               je      short 01DDD5D3
01DDD585  |.  83F8 2A             cmp     eax, 0x2A                                         ;  在試用期內
01DDD588  |.  74 28               je      short 01DDD5B2
01DDD58A  |.  3D 38010000         cmp     eax, 0x138                                        ;  試用期已結束
01DDD58F  |.  75 4D               jnz     short 01DDD5DE
01DDD591  |.  8BCE                mov     ecx, esi                                          ;  Case 138 of switch 01DDD580
01DDD593  |.  E8 FBCEE2FE         call    00C0A493
01DDD598  |.  3D A3010000         cmp     eax, 0x1A3
01DDD59D  |.  B9 2F000000         mov     ecx, 0x2F
01DDD5A2  |.  BA F9000000         mov     edx, 0xF9
01DDD5A7  |.  0F44CA              cmove   ecx, edx
01DDD5AA  |.  5F                  pop     edi
01DDD5AB  |.  8BC1                mov     eax, ecx
01DDD5AD  |.  5E                  pop     esi
01DDD5AE  |.  5D                  pop     ebp
01DDD5AF  |.  C2 0800             retn    0x8
01DDD5B2  |>  8BCE                mov     ecx, esi                                          ;  Case 2A of switch 01DDD580
01DDD5B4  |.  E8 DACEE2FE         call    00C0A493
01DDD5B9  |.  3D A3010000         cmp     eax, 0x1A3
01DDD5BE  |.  B9 77010000         mov     ecx, 0x177
01DDD5C3  |.  BA F9000000         mov     edx, 0xF9
01DDD5C8  |.  0F44CA              cmove   ecx, edx
01DDD5CB  |.  5F                  pop     edi
01DDD5CC  |.  8BC1                mov     eax, ecx
01DDD5CE  |.  5E                  pop     esi
01DDD5CF  |.  5D                  pop     ebp
01DDD5D0  |.  C2 0800             retn    0x8
01DDD5D3  |>  5F                  pop     edi                                               ;  Case 17 of switch 01DDD580
01DDD5D4  |.  B8 71000000         mov     eax, 0x71                                         ;  試用期擴充
01DDD5D9  |.  5E                  pop     esi
01DDD5DA  |.  5D                  pop     ebp
01DDD5DB  |.  C2 0800             retn    0x8
01DDD5DE  |>  5F                  pop     edi                                               ;  Default case of switch 01DDD580
01DDD5DF  |.  B8 77010000         mov     eax, 0x177
01DDD5E4  |.  5E                  pop     esi
01DDD5E5  |.  5D                  pop     ebp
01DDD5E6  |.  C2 0800             retn    0x8
01DDD5E9  |>  57                  push    edi                                               ;  Case 4E of switch 01DDD563
01DDD5EA  |.  8BCE                mov     ecx, esi
01DDD5EC  |.  E8 F756E2FE         call    00C02CE8                                          ;  試用周期檢查
01DDD5F1  |.  83F8 17             cmp     eax, 0x17
01DDD5F4  |.  74 0E               je      short 01DDD604
01DDD5F6  |.  5F                  pop     edi
01DDD5F7  |.  83F8 2A             cmp     eax, 0x2A
01DDD5FA  |.  B8 ED000000         mov     eax, 0xED
01DDD5FF  |.  5E                  pop     esi
01DDD600  |.  5D                  pop     ebp
01DDD601  |.  C2 0800             retn    0x8
01DDD604  |>  5F                  pop     edi
01DDD605  |.  B8 0C020000         mov     eax, 0x20C
01DDD60A  |.  5E                  pop     esi
01DDD60B  |.  5D                  pop     ebp
01DDD60C  |.  C2 0800             retn    0x8
01DDD60F  |>  5F                  pop     edi                                               ;  Case 2D of switch 01DDD563
01DDD610  |.  B8 DB000000         mov     eax, 0xDB
01DDD615  |.  5E                  pop     esi
01DDD616  |.  5D                  pop     ebp
01DDD617  \.  C2 0800             retn    0x8


當試用周期過期,就會要求注冊,如下圖所示:


我們輸入一個延長試用期的注冊碼,注冊碼類型:0xFC,如下圖所示:


點 ”Check License“,如果正確,則提示如上圖所示,下圖的 "About" 中,會顯示延長了多少天數,如下圖所示,延長了 1825 天(從 2019/12/06 開始計算,所以還剩 1772 天的試用期)。



如果要換一注冊類型,先要移除原有注冊碼,如下圖所示:

在注冊界面,點 ”Remove my license from this machine“,再次確認”Remove“就可以了。

下面是輸入 0x9C 類型的注冊碼,可以看到,沒有任何免費支持和升級,一開始就顯示免費支持過期(1970/1/2過期)了:



下面是輸入 0xAC 類型的注冊碼,這個是有免費支持和升級的,我設置的過期日期為:2048-10-24,即20481024,程序員喜歡的數字!!!

提示框會顯示什么時候過期:十月 24,2048。注冊界面上也會顯示,如下圖所示:



上面都是單用戶的注冊授權,下面來一個多用戶的:999用戶

還有一種不限用戶數的:Site License。如下圖所示:



在v10.0.0 x64 位的版本上,也可以通過(界面與x86版一樣,不截圖了)。

下面看看老版本是否可用,在 Windows 7 下的 v3.2.2 版沒有問題:


在 Windows 98 下的 v2.1.4 也沒有問題:


經過幾個版本測試,表示其注冊碼算法沒有改變過。0x9C 類型因為版本標識檢查會過期(當然可以在SN中預設一個很大的版本號),不一定適于新版本。 但 0xAC 注冊類型是可能通用各版本的。

另外,除了30天試用期,還有一種對使用次數進行限制的試用,可使用次數保存在注冊表中。如下圖所示,還有9次可用:


以上就是該軟件的注冊分析,下面放出其注冊機源碼,可以生成以上3種類型(0x9C, 0xAC, 0xFC)的注冊碼,也可以更改注冊用戶數(1-single user license, 2~999-multiply user license, 1000-site license)。源碼通過 dev-c++ 調試通過,代碼如下:
[C++] 純文本查看 復制代碼
#include <iostream>
#include <string.h>
#include "name_tables.h"

typedef unsigned char  UCHAR;
typedef unsigned short UWORD;
typedef unsigned long  ULONG;
typedef unsigned int   UINT32;
typedef unsigned long long UINT64;

/*
v3.2.2:
release date: 0x3B20
version id: 0x04
*/ 

/*
v8.0.0:
release date: 0x4389
version id: 0x09 
*/ 

/*
v9.0.0:
release date: 
version id: 0x0A 
*/ 

/*
v10.0.0:
release date: 0x473C 
version id: 0x0B
*/ 
ULONG RLSDATE = 0x473C; //// 2019/12/06,免費升級開始日期,應該就是發布日期吧 
ULONG VERID = 0x0B;     //// 11,當前版本ID,可升級最高版本號,序列號的版本號要大于或等于此值 

/////////////////////////////////////////////////
//// 免費升級天數 (可修改)
ULONG FREE_UPGRADE_DAYS = 10549;  //// 免費升級天數:10549(截止至 2048/10/24)
/////////////////////////////////////////////////
//// SN最大可用版本,適于 0x9C 注冊類型。適配免費升級天數,設置28年。 
ULONG MAX_VERSION_ID = VERID + (FREE_UPGRADE_DAYS/365); 
/////////////////////////////////////////////////

int char36ToInt(char ch);
int stringToBytes(char * str, char * bytes);
int checkName(char * name);

ULONG getUncheck3(ULONG base, ULONG rlsdate);

ULONG calcSN_Date();
ULONG reverseSN_Date(ULONG sn_date);

UCHAR getUncheck1(char ch);
UWORD getUncheck2(ULONG ul);
ULONG getCheck3(ULONG sn_date, ULONG base);

///// 用戶名處理 
ULONG getNameCheck(char * name, ULONG is_registed, ULONG free_days, ULONG user_count);

int getDays(int base, int year2, int month2, int day2);
int getDate(int days, int * year, int * month, int * day);

ULONG decodeVersionID(ULONG encVerId);
ULONG decodeBeginDays(ULONG encDays);
ULONG decodeEndDays(ULONG encDays);
ULONG decodeUsesLeft(ULONG encUsesLeft);
ULONG encodeEndDays(ULONG days);
ULONG encodeUsesLeft(ULONG usesLeft);

#define RESULT0 0x93
#define RESULT1 0xE7

//// black name list
char * name_list[] = {"999", NULL};

UCHAR sn_int[] = {0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44, 0x55, 0x55};
//UCHAR sn_int[] = {0x11, 0x11, 0x22, 0x9C, 0x3E, 0x7A, 0xED, 0xBA, 0x55, 0x55};

int main(int argc, char** argv) {

        //// 注冊用戶名 
        char name[] = "solly";
        
        ////------------------------------------------------------------------------ 
        //// version type 
        //ULONG license_type = 0x9C;      //// 無免費升級,(注冊時會提示過期日期為1970/1/2) 
        ULONG license_type = 0xAC;        //// 有免費升級,注冊碼含有天數限制 
        //ULONG license_type = 0xFC;      //// 擴展評估版,注冊碼含有天數限制 
        
        //// License user count
        ULONG license_user_count = 1000;        //// Site License, 0x03E8 
        //ULONG license_user_count = 1;         //// single License, 0x01
        //ULONG license_user_count = 999;       //// multiply License (2~999)

        ////------------------------------------------------------------------------ 
        //// 注冊類型
        ULONG license_register_type = 1;             //// 正式注冊版 
        ULONG license_free_upgrage_end_of_date = 0;  //// 可免費升級的天數 

        ////------------------------------------------------------------------------ 
        int black = checkName(name);
        if(black == RESULT1) {
                printf("Your name is in the black names list.\n");

                return 0;
        }

        ////------------------------------------------------------------------------ 
        if(license_type == 0xAC) {   //// full version 
                license_free_upgrage_end_of_date = RLSDATE + FREE_UPGRADE_DAYS;   /// 可升級天數 
                printf("EndOf Date = 0x%08X\n", license_free_upgrage_end_of_date);
                //// name_check = 0x8134B8E5
        }
        
        if(license_type == 0xFC) {
                license_register_type = 0;       //// 擴展評估版 
                license_user_count    = 1;
                license_free_upgrage_end_of_date = 0xFF;
                ////
                FREE_UPGRADE_DAYS = 1825; //// evaluation extrends days <= 0x721(1825 days, 5 years)
        }

        ////------------------------------------------------------------------------ 
        //// save license type
        sn_int[3] = (UCHAR)license_type;  //// license type

        //// params: "solly", 1, 0, 0x03E8
        //// return: 0xBAED7A3E
        //// ------------------------------
        //// params: "solly', 0, 0xFF, 1
        //// return: 0x4E2AC9B1 
        int name_check = getNameCheck(name, license_register_type, license_free_upgrage_end_of_date, license_user_count);
        printf("name_check = 0x%08X\n", name_check);
        sn_int[4] = (UCHAR)(name_check    );   /// name check byte
        sn_int[5] = (UCHAR)(name_check>>8 );
        sn_int[6] = (UCHAR)(name_check>>16);
        sn_int[7] = (UCHAR)(name_check>>24);


        if(license_type == 0xFC) {  //// evaluation license
                //// 18000(0x4650) + 10549 == 0x6F85,  20000(0x4E20) + 10549 == 0x7755
                int eval_days_check = getUncheck3(name_check, RLSDATE);   
                printf("evaluation_days_encoded = 0x%08X\n", eval_days_check);
                sn_int[0] = (UCHAR)(eval_days_check    );
                sn_int[1] = (UCHAR)(eval_days_check>>8 );
                sn_int[2] = (UCHAR)(eval_days_check>>16);
                
                int eval_days = getCheck3(name_check, eval_days_check);
                printf("evaluation extends days = 0x%08X\n", eval_days);
                //// execute "Remove my license from this machine" first.
                //// 最后注冊日期 < eval_days < 最后注冊成功有效日期 
                //// 并且 最后注冊成功有效日期 < 當前日期
                //// 并且 eval_days < Release_date + 0x721(1825 days,5年) 
        } else {  //// registered license
                int user_count = getUncheck2(license_user_count);    //// 0xA93B
                printf("user_count = 0x%08X\n", user_count);
        
                sn_int[1] = (UCHAR)(user_count>>8) ^ sn_int[7];  //// hi
                sn_int[2] = (UCHAR)user_count ^ sn_int[5];       //// lo
        
                if(license_type == 0xAC) {
                        ULONG sn_date = getUncheck3(0x005B8C27, RLSDATE); /// days
                        sn_date &= 0x00FFFFFF;
                        printf("days_in_sn = 0x%08X\n", sn_date); //// 0xFF9EBF52
                        //reverseSN_Date(sn_date);  //// fill sn_int[0], sn_int[8], sn_int[9]
                        sn_int[0] = (UCHAR)(sn_date    ) ^ sn_int[6];
                        sn_int[8] = (UCHAR)(sn_date>>8 ) ^ sn_int[4];
                        sn_int[9] = (UCHAR)(sn_date>>16) ^ sn_int[5];
                        
                        //int check3 = getCheck3(sn_date, 0x005B8C27);
                        //printf("free upg days = 0x%08X\n", check3);
                } else {  //// license_type == 0x9C
                        //// version_id check
                        sn_int[0] = getUncheck1(MAX_VERSION_ID) ^ sn_int[6]; /// version_id limited
                        printf("version_id = 0x%08X\n", VERID);
                }
        }
        
        ////-------------------------------------------------------------------
        //// test
//        int a = char36ToInt('x');
//        printf("x = %d\n", a);
/*        
        int year2, month2, day2;
        int v10 = getDate(0x473C, &year2, &month2, &day2);
        printf("v10.0 rls date: %d-%02d-%02d\n", year2, month2, day2);
        
        int v10_1 = getDate(0x4770, &year2, &month2, &day2);   //// 2020-01-27
        printf("extends date1: %d-%02d-%02d\n", year2, month2, day2);

        int v10_2 = getDate(0x7071, &year2, &month2, &day2);   //// 2048-10-23
        printf("extends date2: %d-%02d-%02d\n", year2, month2, day2);

        int v08 = getDate(0x4389, &year2, &month2, &day2);
        printf("v08.0 rls date: %d-%02d-%02d\n", year2, month2, day2);

        int days1 = getDays(0, 2019, 12, 6);
        printf("days1: 0x%08X\n", days1);
        
        int days2 = getDays(0x473C+1, 2048, 10, 24);
        printf("days2: %d\n", days2);
        
        int days3 = getDays(0x0, 2020, 1, 28);
        printf("days3: 0x%08X\n", days3);
        
        /// {F73529D0-8362-B7A9-7B25-01538B3C632A}
        int decodedVerId = decodeVersionID(0x64B8E106);  //// 1689837830, return 0x0B
        printf("Decoded Ver Id: 0x%08X\n", decodedVerId);
        
        /// {E68B43C9-B732-8573-76A8-01AB75B3683A}
        int begin_days = decodeBeginDays(0x0FE19483);  /// 266441859, return 0x4770
        printf("Begin Days: 0x%08X\n", begin_days);

        //// {D75BD954-8B63-84BA-75B3-019654928EE7}
        int end_days = decodeEndDays(0xA627AA1E);  /// 2787617310, return 0x7071
        printf("End Days: 0x%08X\n", end_days);
        
        int enc_end_days = encodeEndDays(0x4770+0x1E); //// 30 days left 
        printf("Encoded End Days: %lu\n", enc_end_days);
        
        //// {F175B8C0-783C-8BA0-7045-014CA847B302}
        int usesLeft = decodeUsesLeft(0xA4CEFFB9); //// 2765029305, return 0x09
        printf("Evaluation Uses Left: 0x%08X\n", usesLeft);
        
        int encUsesLeft = encodeUsesLeft(100);
        printf("Encoded Evaluation Uses Left: %lu\n", encUsesLeft);
*/        
        ////-------------------------------------------------------------------
        //// output sn
        printf("\n\nName: %s\n\n", name);
        //// SN: 1113-3D22-3E7A-EDBA-5555
        if(license_type == 0xFC) {  //// evaluation license
                printf("  SN: %02X%02X-%02X%02X-%02X%02X-%02X%02X\n", 
                                sn_int[0], sn_int[1], sn_int[2], sn_int[3], sn_int[4], 
                                sn_int[5], sn_int[6], sn_int[7]);
        } else if(license_type == 0xAC) { //// full version
                printf("  SN: %02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X\n", 
                                sn_int[0], sn_int[1], sn_int[2], sn_int[3], sn_int[4], 
                                sn_int[5], sn_int[6], sn_int[7], sn_int[8], sn_int[9]);
        } else {  //// no free support, no free upgrade
                printf("  SN: %02X%02X-%02X%02X-%02X%02X-%02X%02X\n", 
                                sn_int[0], sn_int[1], sn_int[2], sn_int[3], sn_int[4], 
                                sn_int[5], sn_int[6], sn_int[7]);
        }
        
        return 0;
}

int checkName(char * name) {
        
        for(int i=0; ; i++) {
                if(name_list[i] == NULL) {
                        break;
                }
                if(strcmp(name, name_list[i])) {
                        continue;
                }
                return RESULT1;  /// 存在于黑名單中 
        }
        
        return 0;
}

int stringToBytes(char * str, char * bytes) {
        int idx = 0;
        for(int i=0; i<5; i++) {
                char ch_hi = str[idx++];
                char ch_lo = str[idx++];
                bytes[i*2] = (char36ToInt(ch_hi) << 4) + char36ToInt(ch_lo);
                ch_hi = str[idx++];
                ch_lo = str[idx++];
                bytes[i*2+1] = (char36ToInt(ch_hi) << 4) + char36ToInt(ch_lo);
                idx++;  //// 跳過 '-' 分隔符 
        }
        printf("SN_INT[] = (%02X %02X - %02X %02X - %02X %02X - %02X %02X - %02X %02X)\n",
                        bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], 
                        bytes[5], bytes[6], bytes[7], bytes[8], bytes[9]);
        return idx;
}

int char36ToInt(char ch) {
        //// 大寫字母 O ,小寫字母 o , 轉換成數字 0; 
        if((ch=='O') || (ch=='o')) {
                return 0;
        }
        //// 小寫字母 l , 轉換為數字 1; 
        if(ch == 'l') {
                return 1;
        }
        if((ch>='0') && (ch<='9')) {
                return ch - '0';
        }
        if((ch>='A') && (ch<='Z')) {
                return ch - 'A' + 10;
        }
        if((ch>='a') && (ch<='z')) {
                return ch - 'a' + 10;
        }
        
        return 0;
}

UCHAR getCheck1(char ch) {
        return (UCHAR)(((ch ^ 0x18) + 0x3D) ^ 0xA7);
}

UWORD getCheck2(ULONG ul) {
        ULONG a = (UWORD)(((ul ^ 0x7892) + 0x4D30) ^ 0x3421);

        if(a % 11) {
                return 0;
        }
        
        return (UWORD)a;
}

/// 0x002F6BFC, 0x005B8C27
ULONG getCheck3(ULONG sn_date, ULONG base) {
        //// check1 == 0xFF
        ULONG check1  = (((sn_date ^ base ^ 0x0022C078) - 0x0002C175) ^ 0xFFE53167) & 0X00FFFFFF;
        UINT64 check2 = (UINT64)check1 * 0xF0F0F0F1UL;
        ULONG check3 = (UINT64)(check2 >> (32+4));
        ULONG check4 = check3 << 4;
        ULONG check = check1 - (check4 + check3); 
        //printf("sn_date = 0x%08X\n", sn_date); 
        return (check == 0)?check3:0; //// check3 >= 0x473C 才正確 
}

/*
ULONG getUncheck3(ULONG base, ULONG rlsdate) {
        //ULONG check1 = 0x000000FF;
        //return ((check1 ^ 0xFFE53167) + 0x0002C175) ^ 0x0022C078 ^ base;
        ULONG check1_0 = 0;
        ULONG check3_0 = 0;
        ULONG check3_1 = rlsdate + FREE_UPGRADE_DAYS - 1;
        do {
                check3_1 ++;  //// test
                if(check3_1 < rlsdate) {
                        break;
                }

                //ULONG check4 = check3_1 << 4;   /// check3_1 * 0x10
                //check1_0 = check3_1 + check4;   /// check1_0 = check3_1 * 0x11; 
                check1_0 = check3_1 * 0x11;
        
                //UINT64 check2 = (UINT64)check1_0 * 0xF0F0F0F1UL;
                UINT64 check2 = (UINT64)check3_1 * 0x1000000001ULL; /// 0xF0F0F0F1UL * 0x11 
                check3_0 = (UINT64)(check2 >> (32+4)); //// (UINT64)check3_1 * 0x01;
        } while(check3_0 != check3_1);
        //printf("check3_0 = 0x%08X\n", check3_0);
        //printf("check3_1 = 0x%08X\n", check3_1);
        
        return ((check1_0 ^ 0xFFE53167) + 0x0002C175) ^ 0x0022C078 ^ base;
}
*/
ULONG getUncheck3(ULONG base, ULONG rlsdate) {
        ULONG end_of_date = rlsdate + FREE_UPGRADE_DAYS;
        return (((end_of_date * 0x11) ^ 0xFFE53167) + 0x0002C175) ^ 0x0022C078 ^ base;
}

ULONG calcSN_Date() {
        ULONG a = sn_int[5] ^ sn_int[9];
        ULONG b = sn_int[4] ^ sn_int[8];
        ULONG c = sn_int[6] ^ sn_int[0];
        
        ULONG d = (((a<<8) + b)<<8) + c; //// 0x002F6BFC
        
        return d;
}

ULONG reverseSN_Date(ULONG sn_date) {
    //// 0x002F6BFC
        sn_int[0] = (UCHAR)(sn_date    ) ^ sn_int[6];
        sn_int[8] = (UCHAR)(sn_date>>8 ) ^ sn_int[4];
        sn_int[9] = (UCHAR)(sn_date>>16) ^ sn_int[5];
        
        return 0;
}


ULONG getUncheck3(ULONG count) {
        /// no using
        return 0;        
} 

/// 0x3B
UCHAR getUncheck1(char ch) {
        return (UCHAR)(((ch ^ 0xA7) - 0x3D) ^ 0x18);
}

/// license count
/// 1-single user license, 2~999-multiply user license, 1000-site license
UWORD getUncheck2(ULONG ul) {
        ULONG a = ul * 11; //// ul <= 1745; /// 正常范圍為 1~0x03E8 (1~1000) 
        return (UWORD)(((a ^ 0x3421) - 0x4D30) ^ 0x7892);
}

//// params: "solly", 1, 0, 0x03E8 (edx, xxx, ecx, ebx)
//// return: 0xBAED7A3E
ULONG getNameCheck(char * name, ULONG is_registed, ULONG free_days, ULONG user_count) {
        ULONG name_check = 0;      //// [ebp-04]
        ULONG idx3 = 0;            //// [ebp-10]
        ULONG idx2 = 0;            //// [ebp-0C]
        
        int n = strlen(name);
        
        ULONG idx4 = user_count * 15;    //// ebx
        ULONG idx1 = free_days * 17;  //// [ebp-08]
        
        for(int i=0; i<n; i++) {
                ULONG idx0 = toupper((UCHAR)name[i]);
                name_check += name_tables[idx0];
                if(is_registed != 0) {  //// 正式注冊版 
                        name_check ^= name_tables[(idx0 + 0x0D) & 0xFF];
                        name_check *= name_tables[(idx0 + 0x2F) & 0xFF];
                        name_check += name_tables[(UCHAR)idx1];
                        name_check += name_tables[(UCHAR)idx4];
                        name_check += name_tables[(UCHAR)idx2];
                } else {           //// 擴展評估版 
                        name_check ^= name_tables[(idx0 + 0x3F) & 0xFF];
                        name_check *= name_tables[(idx0 + 0x17) & 0xFF];
                        name_check += name_tables[(UCHAR)idx1];
                        name_check += name_tables[(UCHAR)idx4];
                        name_check += name_tables[(UCHAR)idx3];
                }
                idx2 += 0x13;
                idx1 += 0x09;
                idx4 += 0x0D;
                idx3 += 0x07;
        }
        
        return name_check;
}

int monthdays[2][12] = { { 31,28,31,30,31,30,31,31,30,31,30,31 },{ 31,29,31,30,31,30,31,31,30,31,30,31 } };
int yeardays[2] = { 365,366 };

int isLearYear(int year)
{
        if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
                return 1;
        else
                return 0;
}

//// from 1970-01-01
int getDays(int base, int year2, int month2, int day2) {
        int sumdays = 0;
        int year1  = 1970;
        int month1 = 1;
        int day1   = 1;
        if (year1 == year2 && month1 == month2)
        {
                sumdays = day2 - day1;
        } else {
                if (year1 == year2)
                {
                        sumdays += monthdays[isLearYear(year1)][month1-1] - day1;
                        for (int i = month1; i < month2-1; i++) { 
                                sumdays += monthdays[isLearYear(year1)][i];
                        } 
                        sumdays += day2;
                } else {
                        sumdays += monthdays[isLearYear(year1)][month1-1] - day1;
                        
                        for (int i = month1; i < 12; i++) {
                                sumdays += monthdays[isLearYear(year1)][i];
                        } 

                        for (int i = year1 + 1; i < year2; i++) {
                                sumdays += yeardays[isLearYear(i)];
                        }

                        for (int i = 0; i < month2 - 1; i++) {
                                sumdays += monthdays[isLearYear(year2)][i];
                        }

                        sumdays += day2;
                }
        }
        return sumdays - base;
}

int getDate(int days, int * year, int * month, int * day) {
        int year1 = 1969;
        int month1= 0;
        int day1 = 0;
        
        int n = days;
        do {
                year1 ++;
                days = n;
                n = days - yeardays[isLearYear(year1)];
        } while(n>0);
        
        n = days;
        do {
                days = n;
                n = days - monthdays[isLearYear(year1)][month1];
                month1 ++; //// base on 1
        } while(n>0);

        day1 = days;
        day1 ++; //// base on 1
        
        ////
        *year = year1;
        *month= month1;
        *day  = day1;
        
        return 0;        
}

//// decode versin_id from registry
ULONG decodeVersionID(ULONG encVerId) {
//        ULONG  s = (((encVerId ^ 0xC7329CD4) - 0x2749B4FF) ^ 0x7C4280C0);
//        ULONG  d = (ULONG)(((UINT64)s * 0x34904333UL)>>32);  //// 881869619
//        int    c = ((int)(((int)(s - d)>>1) + d)>>13);    /// c = s / 0x3519
//        ULONG  a = c*0x3519;
//        printf("s = 0x%08X, d = 0x%08X\n", s, d);
//        return (s == a)?c:0;
    return (((encVerId ^ 0xC7329CD4) - 0x2749B4FF) ^ 0x7C4280C0) / 0x3519;
}

//// encode version_id to value of registry
ULONG encodeVersionID(ULONG VerId) {
        return (((VerId * 0x3519) ^ 0x7C4280C0) + 0x2749B4FF) ^ 0xC7329CD4;
}

//// decode begin of days from registry
ULONG decodeBeginDays(ULONG encDays) {
        ULONG c = (((encDays ^ 0x3F6197DA) - 0x656A0BB2) ^ 0xCB139CB7);
        ULONG d = (((UINT64)c * 0xB21642C9UL)>>36);
        ULONG a = d * 0x17;
        return (c == a)?d:0;
}

//// encode begin of days to value of registry
ULONG encodeBeginDays(ULONG days) {
        return ((((days * 0x17) ^ 0xCB139CB7) + 0x656A0BB2) ^ 0x3F6197DA);
}

//// decode end of days from registry
ULONG decodeEndDays(ULONG encDays) {
//        ULONG  s = (((encDays ^ 0x18C5B72) - 0x329BD55E) ^ 0x7521BDEF);
//        ULONG  d = (ULONG)(((UINT64)s * 0x21FB7813)>>32);  //// 881869619
//        int    c = ((int)(((int)(s - d)>>1) + d)>>6);    /// c = s / 0x71
//        ULONG  a = c*0x71;
//        printf("s = 0x%08X, d = 0x%08X\n", s, d);
//        return (s == a)?c:0;
        return ((((encDays ^ 0x18C5B72) - 0x329BD55E) ^ 0x7521BDEF) / 0x71);
}

//// encode end of days to value of registry
ULONG encodeEndDays(ULONG days) {
        return ((((days * 0x71) ^ 0x7521BDEF) + 0x329BD55E) ^ 0x18C5B72);
}

//// {F175B8C0-783C-8BA0-7045-014CA847B302}
ULONG decodeUsesLeft(ULONG encUsesLeft) {
//        ULONG  c = (((encUsesLeft ^ 0x7328B47A) - 0x18B3C906) ^ 0xBF32ABCE);
//        UINT64 a = (UINT64)c * 0x379609FD;
//        ULONG  d = (ULONG)(a>>(32+8));  /// d = c / 0x049B
//        ULONG  A = d * 0x049B;
//        return (c == A)?d:0;
        return (((encUsesLeft ^ 0x7328B47A) - 0x18B3C906) ^ 0xBF32ABCE) / 0x049B;
}

//// {F175B8C0-783C-8BA0-7045-014CA847B302}
//// 試用使用次數 
ULONG encodeUsesLeft(ULONG usesLeft) {
        return ((((usesLeft * 0x049B) ^ 0xBF32ABCE) + 0x18B3C906) ^ 0x7328B47A);
}

代碼內還有一些多余函數和代碼,是在跟蹤分析過程中進行測試或解碼用的,沒有刪除。

另外,還有一個文件是用戶名轉換時的查表數據,文件名為:name_tables.h,代碼如下:
[C++] 純文本查看 復制代碼
#ifndef __name_tables__
#define __name_tables__

long name_tables[] = {
    0x39CB44B8, 0x23754F67, 0x5F017211, 0x3EBB24DA, 0x351707C6, 0x63F9774B, 0x17827288, 0x0FE74821,
    0x5B5F670F, 0x48315AE8, 0x785B7769, 0x2B7A1547, 0x38D11292, 0x42A11B32, 0x35332244, 0x77437B60,
    0x1EAB3B10, 0x53810000, 0x1D0212AE, 0x6F0377A8, 0x43C03092, 0x2D3C0A8E, 0x62950CBF, 0x30F06FFA,
    0x34F710E0, 0x28F417FB, 0x350D2F95, 0x5A361D5A, 0x15CC060B, 0x0AFD13CC, 0x28603BCF, 0x3371066B,
    0x30CD14E4, 0x175D3A67, 0x6DD66A13, 0x2D3409F9, 0x581E7B82, 0x76526B99, 0x5C8D5188, 0x2C857971,
    0x15F51FC0, 0x68CC0D11, 0x49F55E5C, 0x275E4364, 0x2D1E0DBC, 0x4CEE7CE3, 0x32555840, 0x112E2E08,
    0x6978065A, 0x72921406, 0x314578E7, 0x175621B7, 0x40771DBF, 0x3FC238D6, 0x4A31128A, 0x2DAD036E,
    0x41A069D6, 0x25400192, 0x00DD4667, 0x6AFC1F4F, 0x571040CE, 0x62FE66DF, 0x41DB4B3E, 0x3582231F,
    0x55F6079A, 0x1CA70644, 0x1B1643D2, 0x3F7228C9, 0x5F141070, 0x3E1474AB, 0x444B256E, 0x537050D9,
    0x0F42094B, 0x2FD820E6, 0x778B2E5E, 0x71176D02, 0x7FEA7A69, 0x5BB54628, 0x19BA6C71, 0x39763A99,
    0x178D54CD, 0x01246E88, 0x3313537E, 0x2B8E2D17, 0x2A3D10BE, 0x59D10582, 0x37A163DB, 0x30D6489A,
    0x6A215C46, 0x0E1C7A76, 0x1FC760E7, 0x79B80C65, 0x27F459B4, 0x799A7326, 0x50BA1782, 0x2A116D5C,
    0x63866E1B, 0x3F920E3C, 0x55023490, 0x55B56089, 0x2C391FD1, 0x2F8035C2, 0x64FD2B7A, 0x4CE8759A,
    0x518504F0, 0x799501A8, 0x3F5B2CAD, 0x38E60160, 0x637641D8, 0x33352A42, 0x51A22C19, 0x085C5851,
    0x032917AB, 0x2B770AC7, 0x30AC77B3, 0x2BEC1907, 0x035202D0, 0x0FA933D3, 0x61255DF3, 0x22AD06BF,
    0x58B86971, 0x5FCA0DE5, 0x700D6456, 0x56A973DB, 0x5AB759FD, 0x330E0BE2, 0x5B3C0DDD, 0x495D3C60,
    0x53BD59A6, 0x4C5E6D91, 0x49D9318D, 0x103D5079, 0x61CE42E3, 0x7ED5121D, 0x14E160ED, 0x212D4EF2,
    0x270133F0, 0x62435A96, 0x1FA75E8B, 0x6F092FBE, 0x4A000D49, 0x57AE1C70, 0x004E2477, 0x561E7E72,
    0x468C0033, 0x5DCC2402, 0x78507AC6, 0x58AF24C7, 0x0DF62D34, 0x358A4708, 0x3CFB1E11, 0x2B71451C,
    0x77A75295, 0x56890721, 0x0FEF75F3, 0x120F24F1, 0x01990AE7, 0x339C4452, 0x27A15B8E, 0x0BA7276D,
    0x60DC1B7B, 0x4F4B7F82, 0x67DB7007, 0x4F4A57D9, 0x621252E8, 0x20532CFC, 0x6A390306, 0x18800423,
    0x19F3778A, 0x462316F0, 0x56AE0937, 0x43C2675C, 0x65CA45FD, 0x0D604FF2, 0x0BFD22CB, 0x3AFE643B,
    0x3BF67FA6, 0x44623579, 0x184031F8, 0x32174F97, 0x4C6A092A, 0x5FB50261, 0x01650174, 0x33634AF1,
    0x712D18F4, 0x6E997169, 0x5DAB7AFE, 0x7C2B2EE8, 0x6EDB75B4, 0x5F836FB6, 0x3C2A6DD6, 0x292D05C2,
    0x052244DB, 0x149A5F4F, 0x5D486540, 0x331D15EA, 0x4F456920, 0x483A699F, 0x3B450F05, 0x3B207C6C,
    0x749D70FE, 0x417461F6, 0x62B031F1, 0x2750577B, 0x29131533, 0x588C3808, 0x1AEF3456, 0x0F3C00EC,
    0x7DA74742, 0x4B797A6C, 0x5EBB3287, 0x786558B8, 0x00ED4FF2, 0x6269691E, 0x24A2255F, 0x62C11F7E,
    0x2F8A7DCD, 0x643B17FE, 0x778318B8, 0x253B60FE, 0x34BB63A3, 0x5B03214F, 0x5F1571F4, 0x1A316E9F,
    0x7ACF2704, 0x28896838, 0x18614677, 0x1BF569EB, 0x0BA85EC9, 0x6ACA6B46, 0x1E43422A, 0x514D5F0E,
    0x413E018C, 0x307626E9, 0x01ED1DFA, 0x49F46F5A, 0x461B642B, 0x7D7007F2, 0x13652657, 0x6B160BC5,
    0x65E04849, 0x1F526E1C, 0x5A0251B6, 0x2BD73F69, 0x2DBF7ACD, 0x51E63E80, 0x5CF2670F, 0x21CD0A03,
    0x5CFF0261, 0x33AE061E, 0x3BB6345F, 0x5D814A75, 0x257B5DF4, 0x0A5C2C5B, 0x16A45527, 0x16F23945
};
#endif


該軟件在注冊碼驗證時,還會進行網絡驗證,因此,還需要進行網絡驗證的處理,軟件會向其服務器發送一個如下的http字符串進行驗證:
[Shell] 純文本查看 復制代碼
#網絡驗證字符串
[url=http://www.sweetscape.com/cgibin/010editor_check_license_9b.php?t=2E65DB0868&sum=1F4BF35D3CFC5A59865F2CF44167FEC268EDB719D6CD0ADE&id=0&chk=14611&typ=0]http://www.sweetscape.com/cgibin ... d=0&chk=14611&typ=0[/url]


其中有幾個參數説明如下:
1、t=2E65DB0868,這個是由用戶名字符串編碼加密而來的。
2、sum=1F4BF35D3CFC5A59865F2CF44167FEC268EDB719D6CD0ADE,這個是由上面的 t 參數與注冊碼一起加密而來的。
3、id=0,這個 id 是每次驗證返回的驗證成功值,會保存到注冊表,不過第一次驗證時是 0,后面驗證時取的注冊表鍵值。如果驗證成功,id大于0了。
4、chk=14611,這個值也是由用戶名字符串編碼來的,16bits整數。
5、typ=0,這個是一個bool數據,當 typ=0,則進行網驗證,typ=1,則發送驗證已完成給服務器(發送字符串"1On_HttpCheckLicenseFinished(char*,int)"),并且也不再驗證返回的數據。


以上是在線網絡驗證參數分析,下面進行具體的驗證過程分析,另外,不對以上幾個用戶名和注冊碼的加密進行分析,因為那個不是客戶端的事,服務端完成的工作我們不必去多費心分析。我們要做就是不管其發送什么內容,我們都給他回復一個“驗證成功”的標志!

如下圖,先定位網絡驗證的入口:

其實就在我們前面注冊算法函數的后面一點點,如上圖所示,傳入網絡驗證函數參數只有一個:typ=0,表示需要進行驗證。代碼如下:
[Asm] 純文本查看 復制代碼
016FB7D3   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]         ;  第三次引用[0371805C]
016FB7D9   .  68 3C470000         push    0x473C                             ;  18236
016FB7DE   .  6A 0B               push    0xB                                ;  11
016FB7E0   .  E8 07F350FF         call    00C0AAEC                           ;  注冊碼檢查
016FB7E5   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]         ;  第四次引用[0371805C]
016FB7EB   .  8BD8                mov     ebx, eax                           ;  注冊標志 ebx == eax
016FB7ED   .  68 3C470000         push    0x473C                             ;  18236
016FB7F2   .  6A 0B               push    0xB                                ;  11
016FB7F4   .  E8 5FE650FF         call    00C09E58                           ;  注冊碼檢查 及 試用期擴充的檢查
016FB7F9   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]         ;  第五次引用[0371805C]
016FB7FF   .  8BF8                mov     edi, eax                           ;  版本標識 edi == eax
016FB801   .  81FB E7000000       cmp     ebx, 0xE7                          ;  成功標志3
016FB807   .  0F84 F3000000       je      016FB900
016FB80D   .  8379 2C 00          cmp     dword ptr [ecx+0x2C], 0x0          ;  是否進行網絡驗證,0-不驗證,1-驗證
016FB811   .  0F84 E9000000       je      016FB900
016FB817   .  6A 00               push    0x0
016FB819   .  8BCE                mov     ecx, esi
016FB81B   .  E8 BB6D50FF         call    00C025DB                           ;  網絡驗證
016FB820   .  85C0                test    eax, eax                           ;  eax 為返回驗證id
016FB822   .  0F89 8C000000       jns     016FB8B4                           ;  eax非負,跳轉再次判斷


進入該函數,如下圖所示:


首先取得用戶名,如下圖所示,取得界面上的用戶名字符串:


對用戶名字符串進行類型轉換并轉成字符數組,如下圖所示:

接下來取注冊碼,一樣也進行轉換成字符數組之類的操作,如下圖所示:


接下來,對用戶名進行編碼,得到一個整數,如下圖所示,編碼方法不管,這個編碼是 chk 參數:


接下一大段代碼就是將分而在軟件中不同位置的一些常量字符串進行拼接,拼接出一個 http 連接串,如下圖所示:

上圖中,OD 數據區顯示的就是拼接好的字符串的前面一部分。

接下來,又是對用戶名編碼,這次是編碼成一個字符串,作為 t 參數,如下圖所示:


上面完成后,然后將 t 參數與注冊碼進行一起編碼為一個更長的字符串,作為 sum 參數,如下圖所示:


如下圖所示,在 OD 的數據區顯示,已經將上面的編碼,添加到 http 連接串后面了:


接下來就是ID參數的處理,第一次驗證時,注冊表中沒有數據,默認就是 t=0,如下圖所示:


接下來,就是將最前面的用戶名編碼后的整數也添加上來,作為 chk 參數,如下圖所示:


這個操作完成,只有最后一個參數了,typ 參數是函數傳入的,當前傳入是的 0,如下圖所示:

這樣,整個 http 驗證字符串就拼接完成了,下面再轉換成 QString 類型 Unicode 字符串,如下圖所示:


我們先看看,手動發送一下,是什么效果,將這一串(沒有轉換成 unicode前的)字符串復制出來,在 IE 中直接連接,如下圖所示:

直接返回是的 <ss>invalid</ss>,表示驗證失敗,注冊碼無效。

下面我們進行破解,先在 hosts 文件中加上如下數據:
127.0.0.1

然后在管理員權限下,在命令行運行如下命令,刷新 DNS:
ipconfig /flushdns
切記不要錄錯了。

下面,從網上抓一段 http server 代碼,稍加改造,自己做一個驗證服務器,代碼如下:
[C++] 純文本查看 復制代碼
#include <iostream>
#include <stdio.h>
#include <winsock.h>
#pragma comment(lib,"WSock32.Lib") //GCC 需要指定庫 "libwsock32.a"

int main(int argc, char** argv)
{
        WSADATA wsaData;
        if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
                fprintf(stderr, "WSAStartup failed.\n");
                exit(1);
        }
        printf("WebServer started...\r\nvisit [url=http://127.0.0.1:80]http://127.0.0.1:80[/url]\r\n\r\n");
        printf("Exit the http server, visit [url=http://127.0.0.1:80/?quit=1]http://127.0.0.1:80/?quit=1[/url]\r\n");
        
        SOCKET server_socket;       //服務器的socket
        SOCKET acc_socket;          //接收到的用戶連接的socket
        int sock_size = sizeof(struct sockaddr_in);  
        struct sockaddr_in client_addr;    //客戶連接信息
        struct sockaddr_in server_addr;    //客戶連接信息

        server_socket = socket(PF_INET, SOCK_STREAM, 0);
        if (server_socket == -1) {         //如果返回值為-1 則出錯
                return -1;
        }
        /*
        * 填充服務器連接信息
        */
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(80);
        server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //本地地址
        memset(&(server_addr.sin_zero), '\0', 8);
        if (bind(server_socket, (struct sockaddr *)&server_addr,
                sizeof(server_addr)) == -1) {       //綁定服務 如果出錯 則返回-1
                printf("bind error!\n");
                return -1;
        }
        if (listen(server_socket, 10) == -1 ) { //開始監聽
                printf("listen error!\n");
                return -1;
        }
        if (server_socket == -1) {              //創建socket出錯
                printf("Server exception!\n");
                // exit(2);
        }
        while(true) {
                acc_socket = accept(server_socket, (struct sockaddr *)&client_addr, &sock_size); //接收連接
                int numbytes;
                char recv_buff[1000];
                if ((numbytes=recv(acc_socket, recv_buff, 999, 0)) == -1) {
                        perror("recv error!\n");
                        // exit(1);
                        numbytes = 0;
                }
                recv_buff[numbytes] = '\0'; 
                  printf("recv data:\n %s\n", recv_buff);    //show data
                  
                  ////////// send data
                char reponse[] = 
                        "HTTP/1.0 200 OK\r\n"\
                        "Content-type: text/html\r\n"\
                        "Content-length: 26\r\n\r\n"\
                        "<ss><id>78787878</id></ss>";          //// length == 26, content == "<ss><id>78787878</id></ss>"
                  printf("send data:\n %s\n", reponse);      //show data
                send(acc_socket, reponse, strlen(reponse), 0);
                
                //// close
                shutdown(acc_socket, 2);  /// 2-SD_BOTH
                closesocket(acc_socket);
                /////
                if(strstr(recv_buff, "?quit=1")) {
                        //closesocket(acc_socket);
                        break;
                }
                printf("\r\n\r\n");        
        }
        
        closesocket(server_socket); 
        WSACleanup();

        return 0;
}

注意,這只是一個簡單的驗證,不過很有效。另外,GCC 編譯時,要加上 libwsock32.a 庫。


啟動我們自己的驗證服務器后,就可以進入下一步了。

如上圖所示,發送了網絡連接字符串。如果 bl ==1,表示成功發送和接收了。這是成功的第一步。這一段關鍵代碼如下:
[Asm] 純文本查看 復制代碼
016FD601   .  8B0D 6C80BD03       mov     ecx, dword ptr [0x3BD806C]
016FD607   .  8D85 D8EFFFFF       lea     eax, dword ptr [ebp-0x1028]
016FD60D   .  53                  push    ebx
016FD60E   .  6A 01               push    0x1
016FD610   .  50                  push    eax
016FD611   .  8D85 E4EFFFFF       lea     eax, dword ptr [ebp-0x101C]
016FD617   .  C745 FC 05000000    mov     dword ptr [ebp-0x4], 0x5
016FD61E   .  50                  push    eax
016FD61F   .  8D85 ECEFFFFF       lea     eax, dword ptr [ebp-0x1014]
016FD625   .  50                  push    eax
016FD626   .  E8 1F7C50FF         call    00C0524A                                      ;  發送http數據
016FD62B   .  85C0                test    eax, eax                                      ;  eax==0 通訊正常
016FD62D   .  C745 FC FFFFFFFF    mov     dword ptr [ebp-0x4], -0x1
016FD634   .  8D8D ECEFFFFF       lea     ecx, dword ptr [ebp-0x1014]
016FD63A   .  0F94C3              sete    bl                                            ;  bl==1,發送接收正常
016FD63D   .  FF15 B094BD03       call    dword ptr [<&Qt5Core.QString::~QString>]      ;  Qt5Core.QXmlStreamStringRef::~QXmlStreamStringRef
016FD643   .  84DB                test    bl, bl
016FD645   .^ 0F84 ABF9FFFF       je      016FCFF6                                      ;  失敗則跳轉
016FD64B   .  FFB5 D8EFFFFF       push    dword ptr [ebp-0x1028]                        ;  length
016FD651   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]
016FD657   .  FFB5 E4EFFFFF       push    dword ptr [ebp-0x101C]                        ;  接收到的數據
016FD65D   .  E8 046F50FF         call    00C04566                                      ;  解析收到的數據
016FD662   .  FFB5 E4EFFFFF       push    dword ptr [ebp-0x101C]
016FD668   .  8BF0                mov     esi, eax
016FD66A   .  E8 6106A200         call    <jmp.&MSVCR120.operator delete[]>
016FD66F   .  83C4 04             add     esp, 0x4
016FD672   .  8BC6                mov     eax, esi
016FD674   .  EB 47               jmp     short 016FD6BD                                ;  結束了


如果驗證失敗,則收到如下數據(這是在改 hosts 文件 之前從官網接收的):


如果驗證正確,則接收到如下圖所示數據(這是從我的驗證服務器接收的):


驗證服務器顯示如下:

可以清楚的看到接收和發送的數據。

接收到數據后,就會對數據進行解析,調用如下函數:

如上圖所示,先解析<ss></ss>標簽。檢查接收到的字符串是不是 <ss>error</ss>和<ss>invalid</ss>,如果不是,則保存一個標志到注冊表,表示驗證成功:

這一段關鍵代碼如下:
[Asm] 純文本查看 復制代碼
01DDE870  |> \1BC0                sbb     eax, eax
01DDE872  |.  83C8 01             or      eax, 0x1
01DDE875  |>  85C0                test    eax, eax
01DDE877  |.  75 0B               jnz     short 01DDE884
01DDE879  |.  C746 2C 01000000    mov     dword ptr [esi+0x2C], 0x1
01DDE880  |.  6A 01               push    0x1                              ;  verId = 1,錯誤
01DDE882  |.  EB 09               jmp     short 01DDE88D
01DDE884  |>  C746 2C 00000000    mov     dword ptr [esi+0x2C], 0x0
01DDE88B  |.  6A 00               push    0x0                              ;  VerId = 0, 正確
01DDE88D  |>  E8 85A1E2FE         call    00C08A17                         ;  get registry object
01DDE892  |.  8BC8                mov     ecx, eax
01DDE894  |.  E8 E35FE2FE         call    00C0487C                         ;  寫注冊表數據(verId),保存在線驗證的結果
01DDE899  |.  837E 2C 01          cmp     dword ptr [esi+0x2C], 0x1
01DDE89D  |.  75 14               jnz     short 01DDE8B3                   ;  不等于1正確, 跳轉



具體的注冊表標志保存位置如下:

如果是 1690216811,表示成功,這個數字解碼后是 0,如果是 1690236428,則表示失敗,這個數字解碼后是 1。
保存完注冊表后,就對“<id>78787878</id>”解析,如下圖所示:

如果沒有發現問題,則將“<id>78787878</id>”中的數據“78787878”解析出來,如上圖所示。

如果解析成功,則將解析出來的 id 轉換成一個整數,并保存到注冊表中,并且是明文件保存的,沒有加密,如下圖所示:


解析函數完成后,返回我們前面的拼接函數,如果到這里還沒有錯誤,網絡就驗證就完成了,如下圖所示,要退出函數了:



至此,網絡驗證成功了。

注冊表中保存的ID數據如下圖所示:


因此,在注冊表中手動添加好這兩條注冊信息,就可以完成離線網絡驗證:
[Shell] 純文本查看 復制代碼
Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID]

[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID\{F531AB73-8493-A83D-7C94-016296B3CF17}]

[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID\{F531AB73-8493-A83D-7C94-016296B3CF17}\InProcServer32A]
"ThreadingModel"="78787878"

[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID\{FA1395FC-83C3-0732-7D11-0134937462A0}]

[HKEY_CURRENT_USER\Software\SweetScape\010 Editor\CLASSES\CLSID\{FA1395FC-83C3-0732-7D11-0134937462A0}\InProcServer32A]
"ThreadingModel"="1690216811"


前面説了,網絡驗證函數的參數為1時不會驗證,只會 post 一條字符串 "1On_HttpCheckLicenseFinished(char*,int)" 給服務器。typ=1的網絡驗證函數調用在如下位置:

好象這個驗證是界面顯示刷新或定時器里用到了,沒有深究,不一定準確。

另外,驗證完成后,就可以恢復 hosts 文件了。
全部分析完畢!!!!

免費評分

參與人數 63吾愛幣 +74 熱心值 +57 收起 理由
lhxsimon + 1 + 1 寫的真好,贊一個
新手12138 + 1 + 1 熱心回復!
不諳世事的騷年 + 1 + 1 我很贊同!
id1123 + 1 謝謝@Thanks!
star13 + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
iamcjsyr + 2 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
mayahua + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
klise + 1 + 1 非常感謝
耳食之輩 + 1 謝謝@Thanks!
Jumwan + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
CHK_ji + 1 + 1 用心討論,共獲提升!
洛城曼巴 + 1 + 1 用心討論,共獲提升!
lilei105 + 1 熱心回復!
shi128862 + 1 + 1 謝謝@Thanks!
paulan + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
absman1972 + 1 + 1 謝謝@Thanks!
RBS + 1 用心討論,共獲提升!
40m41h42t + 1 + 1 太強了!學習!
ttao88 + 1 + 1 謝謝@Thanks!
niufq + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
codelive + 3 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
xiong_online + 1 + 1 用心討論,共獲提升!
宇翾菌 + 1 用心討論,共獲提升!
aniu + 1 + 1 用心討論,共獲提升!
orgasmor + 1 謝謝@Thanks!膜拜大神!
liuxingtang1 + 1 + 1 今天的評分不給你,有點說不過去了
lyslxx + 1 + 1 我很贊同!
jnez112358 + 1 + 1 謝謝@Thanks!
你不是一個人 + 1 + 1 熱心回復!
kibaamor + 1 + 1 用心討論,共獲提升!
WarWolf + 1 + 1 我很贊同!
vison.v + 1 + 1 謝謝@Thanks!
yixi + 1 + 1 謝謝@Thanks!
whc2001 + 2 + 1 厲害
sdnyzjzx + 1 + 1 謝謝@Thanks!
eman613 + 1 + 1 看不懂系列,請問有成品嘛?
bqsyy + 1 + 1 謝謝@Thanks!
LOLQAQ + 1 + 1 我很贊同!
buzhifou01 + 1 + 1 厲害了!感謝分享
gaosld + 1 + 1 謝謝@Thanks!
lock3r + 1 + 1 謝謝@Thanks!
fsrank + 1 + 1 分析的很詳細,非常感謝
濤之雨 + 2 + 1 膜拜大佬,bc4我是靠自動reg清除機器碼。。。
逍遙一仙 + 3 + 1 用心討論,共獲提升!
飄緲孤鴻影 + 1 + 1 鼓勵轉貼優秀軟件安全工具和文檔!
frsoce + 1 用心討論,共獲提升!
zhangbaida + 3 + 1 鼓勵轉貼優秀軟件安全工具和文檔!
dfui + 1 + 1 謝謝@Thanks!
路過的小朋友 + 1 熱心回復!
生有涯知無涯 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
my1229 + 2 + 1 膜拜能分析算法的樓主,辛苦了!
chenjingyes + 1 + 1 謝謝@Thanks!
就是這么帥 + 1 + 1 謝謝@Thanks!
天空藍 + 1 + 1 又一篇精華(?)新年快樂,神分析。
topcookie + 2 + 1 膜拜一下
笙若 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
xiaolong23330 + 1 + 1 牛批
nj001 + 1 + 1 熱心回復!
多幸運遇見baby + 1 + 1 必須點贊
wtujoxk + 2 + 1 神一樣的分析文章
576626139 + 1 + 1 謝謝@Thanks!
朱朱你墮落了 + 3 + 1 你為何這么叼!!!
FleTime + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!

查看全部評分

發帖前要善用論壇搜索广西快三功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

推薦
 樓主| solly 發表于 2020-1-31 16:43 <
本帖最后由 solly 于 2020-1-31 16:51 編輯
Hmily 發表于 2020-1-31 09:34
寫host權限太高,還容易被殺軟攔截,并且影響升級,還是直接做個通殺劫持補丁方便點。

看來也只有patch了。
系統在界面刷新事件中,每5分鐘會驗證注冊碼是否正確,并在主界面右下角顯示注冊狀態:
[Asm] 純文本查看 復制代碼
00D19448   > \FF15 689CBD03       call    dword ptr [<&Qt5Core.QDateTime::currentDateTim>;  Qt5Core.QDateTime::currentDateTime
00D1944E   .  83C4 04             add     esp, 0x4
00D19451   .  50                  push    eax
00D19452   .  8D8F A0080000       lea     ecx, dword ptr [edi+0x8A0]
00D19458   .  C745 FC 00000000    mov     dword ptr [ebp-0x4], 0x0
00D1945F   .  FF15 6C9CBD03       call    dword ptr [<&Qt5Core.QDateTime::secsTo>]       ;  Qt5Core.QDateTime::secsTo
00D19465   .  8D4D F0             lea     ecx, dword ptr [ebp-0x10]
00D19468   .  C745 FC FFFFFFFF    mov     dword ptr [ebp-0x4], -0x1
00D1946F   .  8BF0                mov     esi, eax                                       ;  秒數
00D19471   .  FF15 809CBD03       call    dword ptr [<&Qt5Core.QDateTime::~QDateTime>]   ;  Qt5Core.QDateTime::~QDateTime
00D19477   .  81FE 2C010000       cmp     esi, 0x12C                                     ;  300秒, 小于 300 秒則不執行檢查
00D1947D   .  0F8C 5F010000       jl      00D195E2                                       ;  小于 300 秒則退出

超過 5分鐘就會執行包括下面指令的代碼:
[Asm] 純文本查看 復制代碼
00D194B0   .  E8 F4BDEEFF         call    00C052A9                                       ;  顯示主界面標簽
00D194B5   >  FF15 F8BDBD03       call    dword ptr [<&Qt5Widgets.QApplication::activeWi>;  Qt5Widge.QApplication::activeWindow


但上面不會聯網檢查。

但是,如果點了 “check update” 菜單,則會執行下面代碼:
[Asm] 純文本查看 復制代碼
00D0BA86   > \A1 6480BD03         mov     eax, dword ptr [0x3BD8064]                          ;  QTime Object?
00D0BA8B   .  8B40 38             mov     eax, dword ptr [eax+0x38]                           ;  5, 5 days,自動更新間隔,可設置
00D0BA8E   .  69C0 80510100       imul    eax, eax, 0x15180                                   ;  86400
00D0BA94   .  99                  cdq
00D0BA95   .  3BFA                cmp     edi, edx
00D0BA97   .  7F 28               jg      short 00D0BAC1                                      ;  edx!=0,長時間沒有更新
00D0BA99   .  7C 04               jl      short 00D0BA9F
00D0BA9B   .  3BF0                cmp     esi, eax
00D0BA9D   .  73 22               jnb     short 00D0BAC1                                      ;  不小于5天
00D0BA9F   >  85C9                test    ecx, ecx                                            ;  ecx == 1
00D0BAA1   .  74 0E               je      short 00D0BAB1
00D0BAA3   .  85FF                test    edi, edi
00D0BAA5   .  7F 1A               jg      short 00D0BAC1
00D0BAA7   .  7C 08               jl      short 00D0BAB1
00D0BAA9   .  81FE 80510100       cmp     esi, 0x15180                                        ;  86400, 檢查離上次更新有沒有一天時間
00D0BAAF   .  73 10               jnb     short 00D0BAC1                                      ;  不低于跳轉
00D0BAB1   >  8D8D E4FBFFFF       lea     ecx, dword ptr [ebp-0x41C]
00D0BAB7   .  FFD3                call    ebx                                                 ;  (Qt5Core.QDateTime::isValid)
00D0BAB9   .  84C0                test    al, al
00D0BABB   .  0F85 06030000       jnz     00D0BDC7                                            ;  跳過更新
00D0BAC1   >  8D85 E0FBFFFF       lea     eax, dword ptr [ebp-0x420]
00D0BAC7   .  50                  push    eax
00D0BAC8   .  8D8D ECFBFFFF       lea     ecx, dword ptr [ebp-0x414]
00D0BACE   .  FF15 849CBD03       call    dword ptr [<&Qt5Core.QDateTime::QDateTime>]         ;  Qt5Core.QUrlQuery::QUrlQuery
00D0BAD4   .  8B0D 6480BD03       mov     ecx, dword ptr [0x3BD8064]
00D0BADA   .  8D85 ECFBFFFF       lea     eax, dword ptr [ebp-0x414]
00D0BAE0   .  C645 FC 02          mov     byte ptr [ebp-0x4], 0x2
00D0BAE4   .  50                  push    eax
00D0BAE5   .  83C1 44             add     ecx, 0x44
00D0BAE8   .  FF15 789CBD03       call    dword ptr [<&Qt5Core.QDateTime::operator=>]         ;  Qt5Core.QDateTime::operator=
00D0BAEE   .  8B1D 809CBD03       mov     ebx, dword ptr [<&Qt5Core.QDateTime::~QDateTime>]   ;  Qt5Core.QDateTime::~QDateTime
00D0BAF4   .  8D8D ECFBFFFF       lea     ecx, dword ptr [ebp-0x414]
00D0BAFA   .  C645 FC 01          mov     byte ptr [ebp-0x4], 0x1
00D0BAFE   .  FFD3                call    ebx                                                 ;  <&Qt5Core.QDateTime::~QDateTime>
00D0BB00   .  A1 6480BD03         mov     eax, dword ptr [0x3BD8064]
00D0BB05   .  8B75 08             mov     esi, dword ptr [ebp+0x8]                            ;  參數 == 1
00D0BB08   .  C740 3C 01000000    mov     dword ptr [eax+0x3C], 0x1                           ;  改成1,表示進行了更新
00D0BB0F   .  85F6                test    esi, esi
00D0BB11   .  74 48               je      short 00D0BB5B
00D0BB13   .  68 6C4F4302         push    02434F6C                                            ;  checking for updates...

如果離上次更新1天內,不會執行檢查更新,直接顯示已是最新版,否則都會執行檢查更新,而在檢查更新前,會置一個標志為 1(00D0BB08:mov dword ptr [eax+0x3C], 0x1)。而在上面每5鐘執行一次的代碼中,有這個標志的檢查:
[Asm] 純文本查看 復制代碼
00D1952F   > \A1 6480BD03         mov     eax, dword ptr [0x3BD8064]
00D19534   .  8378 3C 00          cmp     dword ptr [eax+0x3C], 0x0                           ;  更新標志,1-表示執行了更新檢查,0-表示沒有
00D19538   .  0F84 8B000000       je      00D195C9                                            ;  為 0 則跳過注冊碼驗證和網絡驗證

如果為 1,就會進行注冊碼驗證和網絡驗證(typ==1):
[Asm] 純文本查看 復制代碼
00D195A0   > \33C0                xor     eax, eax
00D195A2   >  C745 FC FFFFFFFF    mov     dword ptr [ebp-0x4], -0x1
00D195A9   .  A3 2485BD03         mov     dword ptr [0x3BD8524], eax
00D195AE   >  6A 01               push    0x1                                                 ;  type == 1
00D195B0   .  8BC8                mov     ecx, eax
00D195B2   .  E8 2490EEFF         call    00C025DB                                            ;  連網驗證,typ=1,不會立即解析返回結果,新開線程解析。
00D195B7   .  8B4D F4             mov     ecx, dword ptr [ebp-0xC]

解析在下面代碼執行:
[Asm] 純文本查看 復制代碼
020BCBF2  |> \8B4D 14             mov     ecx, dword ptr [ebp+0x14]                           ;  Case 9 of switch 020BCB50
020BCBF5  |.  8B41 08             mov     eax, dword ptr [ecx+0x8]
020BCBF8  |.  FF30                push    dword ptr [eax]
020BCBFA  |.  8B41 04             mov     eax, dword ptr [ecx+0x4]
020BCBFD  |.  8B4D 08             mov     ecx, dword ptr [ebp+0x8]
020BCC00  |.  FF30                push    dword ptr [eax]
020BCC02  |.  E8 8A9EB4FE         call    00C06A91                                            ;  解析網絡驗證數據(在線檢查更新后的網絡驗證數據檢查)
020BCC07  |>  5D                  pop     ebp                                                 ;  Default case of switch 020BCB50
020BCC08  \.  C3                  retn




也就是不能執行在線更新或自動更新(5自動更新可在設置中關閉),也不能去其 store(需要id和注冊碼),只能執行離線更新了。跟 BC 也差不多一樣了。

也只有 dll 劫持補丁比較方便通用了。

點評

這么看起來那是一樣了,之前bc的劫持通殺補丁是寫入真key,然后把網絡驗證黑名單干掉,保證最大化的通用性,不過貌似最近版本網絡那塊改了,補丁已經失效了,也沒空跟進。  詳情 回復 發表于 2020-1-31 23:01

免費評分

參與人數 2吾愛幣 +2 熱心值 +2 收起 理由
hanyufei + 1 + 1 謝謝@Thanks!
Hmily + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!

查看全部評分

推薦
 樓主| solly 發表于 2020-2-2 15:40 <
Hmily 發表于 2020-2-1 19:31
挺好,如果我沒記錯,好像以前和bc一樣是delphi寫的,idr也能識別出符號。

今天發現,軟件自帶注冊機,分成3種情況分開寫的,大家可以看看官方注冊機:
[Asm] 純文本查看 復制代碼
0143C460  /> \55               push    ebp                                   ;  MakePasswordExtendsDate()
0143C461  |.  8BEC             mov     ebp, esp
0143C463  |.  53               push    ebx
0143C464  |.  6A 01            push    0x1
0143C466  |.  68 FF000000      push    0xFF
0143C46B  |.  6A 00            push    0x0
0143C46D  |.  FF75 08          push    dword ptr [ebp+0x8]
0143C470  |.  E8 786DE2FE      call    002631ED                              ;  EncodeName(name)
0143C475  |.  8B55 0C          mov     edx, dword ptr [ebp+0xC]
0143C478  |.  8BD8             mov     ebx, eax
0143C47A  |.  8B4D 10          mov     ecx, dword ptr [ebp+0x10]
0143C47D  |.  83C4 10          add     esp, 0x10
0143C480  |.  C1E2 04          shl     edx, 0x4
0143C483  |.  0355 0C          add     edx, dword ptr [ebp+0xC]
0143C486  |.  81F2 6731E5A8    xor     edx, 0xA8E53167
0143C48C  |.  81C2 75C10200    add     edx, 0x2C175
0143C492  |.  8859 04          mov     byte ptr [ecx+0x4], bl
0143C495  |.  33D3             xor     edx, ebx
0143C497  |.  C641 03 FC       mov     byte ptr [ecx+0x3], 0xFC              ;  授權類型:0xFC
0143C49B  |.  81F2 78C022FF    xor     edx, 0xFF22C078
0143C4A1  |.  8BC2             mov     eax, edx
0143C4A3  |.  8811             mov     byte ptr [ecx], dl
0143C4A5  |.  C1E8 08          shr     eax, 0x8
0143C4A8  |.  8841 01          mov     byte ptr [ecx+0x1], al
0143C4AB  |.  8BC3             mov     eax, ebx
0143C4AD  |.  C1E8 08          shr     eax, 0x8
0143C4B0  |.  8841 05          mov     byte ptr [ecx+0x5], al
0143C4B3  |.  8BC3             mov     eax, ebx
0143C4B5  |.  C1EA 10          shr     edx, 0x10
0143C4B8  |.  C1E8 10          shr     eax, 0x10
0143C4BB  |.  C1EB 18          shr     ebx, 0x18
0143C4BE  |.  8859 07          mov     byte ptr [ecx+0x7], bl
0143C4C1  |.  8851 02          mov     byte ptr [ecx+0x2], dl
0143C4C4  |.  8841 06          mov     byte ptr [ecx+0x6], al
0143C4C7  |.  5B               pop     ebx
0143C4C8  |.  5D               pop     ebp
0143C4C9  \.  C3               retn
;
;-------------------------------------------------------------------------------------------------------------------
;
0143C4F0  />  55               push    ebp                                   ;  MakePasswordNoSupports()
0143C4F1  |.  8BEC             mov     ebp, esp
0143C4F3  |.  53               push    ebx
0143C4F4  |.  56               push    esi
0143C4F5  |.  8B75 10          mov     esi, dword ptr [ebp+0x10]
0143C4F8  |.  56               push    esi
0143C4F9  |.  FF75 0C          push    dword ptr [ebp+0xC]
0143C4FC  |.  6A 01            push    0x1
0143C4FE  |.  FF75 08          push    dword ptr [ebp+0x8]
0143C501  |.  E8 E76CE2FE      call    002631ED                              ;  EncodeName(name)
0143C506  |.  8075 0C A7       xor     byte ptr [ebp+0xC], 0xA7
0143C50A  |.  8BD8             mov     ebx, eax
0143C50C  |.  806D 0C 3D       sub     byte ptr [ebp+0xC], 0x3D
0143C510  |.  83C4 10          add     esp, 0x10
0143C513  |.  6BCE 0B          imul    ecx, esi, 0xB
0143C516  |.  8B75 14          mov     esi, dword ptr [ebp+0x14]
0143C519  |.  C1E8 10          shr     eax, 0x10
0143C51C  |.  3045 0C          xor     byte ptr [ebp+0xC], al
0143C51F  |.  81F1 21340000    xor     ecx, 0x3421
0143C525  |.  8846 06          mov     byte ptr [esi+0x6], al
0143C528  |.  8B45 0C          mov     eax, dword ptr [ebp+0xC]
0143C52B  |.  81E9 304D0000    sub     ecx, 0x4D30
0143C531  |.  81F1 92780000    xor     ecx, 0x7892
0143C537  |.  885E 04          mov     byte ptr [esi+0x4], bl
0143C53A  |.  34 18            xor     al, 0x18
0143C53C  |.  0FB7D1           movzx   edx, cx
0143C53F  |.  8806             mov     byte ptr [esi], al
0143C541  |.  8BCB             mov     ecx, ebx
0143C543  |.  C1EB 18          shr     ebx, 0x18
0143C546  |.  8BC2             mov     eax, edx
0143C548  |.  C1E9 08          shr     ecx, 0x8
0143C54B  |.  C1E8 08          shr     eax, 0x8
0143C54E  |.  32C3             xor     al, bl
0143C550  |.  884E 05          mov     byte ptr [esi+0x5], cl
0143C553  |.  32CA             xor     cl, dl
0143C555  |.  885E 07          mov     byte ptr [esi+0x7], bl
0143C558  |.  C646 03 9C       mov     byte ptr [esi+0x3], 0x9C              ;  授權類型:0x9C
0143C55C  |.  8846 01          mov     byte ptr [esi+0x1], al
0143C55F  |.  884E 02          mov     byte ptr [esi+0x2], cl
0143C562  |.  5E               pop     esi
0143C563  |.  5B               pop     ebx
0143C564  |.  5D               pop     ebp
0143C565  \.  C3               retn
;
;-------------------------------------------------------------------------------------------------------------------
;
0143C590  />  55               push    ebp                                   ;  MakePasswordFull()
0143C591  |.  8BEC             mov     ebp, esp
0143C593  |.  51               push    ecx
0143C594  |.  53               push    ebx
0143C595  |.  56               push    esi
0143C596  |.  8B75 10          mov     esi, dword ptr [ebp+0x10]
0143C599  |.  57               push    edi
0143C59A  |.  8B7D 0C          mov     edi, dword ptr [ebp+0xC]
0143C59D  |.  57               push    edi
0143C59E  |.  56               push    esi
0143C59F  |.  6A 01            push    0x1
0143C5A1  |.  FF75 08          push    dword ptr [ebp+0x8]
0143C5A4  |.  E8 446CE2FE      call    002631ED                              ;  EncodeName(name)
0143C5A9  |.  8BC8             mov     ecx, eax
0143C5AB  |.  83C4 10          add     esp, 0x10
0143C5AE  |.  8BC6             mov     eax, esi
0143C5B0  |.  894D FC          mov     dword ptr [ebp-0x4], ecx
0143C5B3  |.  C1E0 04          shl     eax, 0x4
0143C5B6  |.  8BD1             mov     edx, ecx
0143C5B8  |.  03C6             add     eax, esi
0143C5BA  |.  C1EA 10          shr     edx, 0x10
0143C5BD  |.  8B75 14          mov     esi, dword ptr [ebp+0x14]
0143C5C0  |.  35 6731E5A8      xor     eax, 0xA8E53167
0143C5C5  |.  05 75C10200      add     eax, 0x2C175
0143C5CA  |.  35 5F4C79FF      xor     eax, 0xFF794C5F
0143C5CF  |.  8945 10          mov     dword ptr [ebp+0x10], eax
0143C5D2  |.  6BC7 0B          imul    eax, edi, 0xB
0143C5D5  |.  884E 04          mov     byte ptr [esi+0x4], cl
0143C5D8  |.  8856 06          mov     byte ptr [esi+0x6], dl
0143C5DB  |.  5F               pop     edi
0143C5DC  |.  C646 03 AC       mov     byte ptr [esi+0x3], 0xAC              ;  授權類型:0xAC
0143C5E0  |.  35 21340000      xor     eax, 0x3421
0143C5E5  |.  2D 304D0000      sub     eax, 0x4D30
0143C5EA  |.  35 92780000      xor     eax, 0x7892
0143C5EF  |.  0FB7D8           movzx   ebx, ax
0143C5F2  |.  8BC1             mov     eax, ecx
0143C5F4  |.  C1E8 08          shr     eax, 0x8
0143C5F7  |.  8945 0C          mov     dword ptr [ebp+0xC], eax
0143C5FA  |.  8846 05          mov     byte ptr [esi+0x5], al
0143C5FD  |.  8BC3             mov     eax, ebx
0143C5FF  |.  C1E8 08          shr     eax, 0x8
0143C602  |.  C1E9 18          shr     ecx, 0x18
0143C605  |.  32C1             xor     al, cl
0143C607  |.  884E 07          mov     byte ptr [esi+0x7], cl
0143C60A  |.  8B4D 0C          mov     ecx, dword ptr [ebp+0xC]
0143C60D  |.  8846 01          mov     byte ptr [esi+0x1], al
0143C610  |.  8AC1             mov     al, cl
0143C612  |.  32C3             xor     al, bl
0143C614  |.  8B5D 10          mov     ebx, dword ptr [ebp+0x10]
0143C617  |.  8846 02          mov     byte ptr [esi+0x2], al
0143C61A  |.  32D3             xor     dl, bl
0143C61C  |.  8BC3             mov     eax, ebx
0143C61E  |.  8816             mov     byte ptr [esi], dl
0143C620  |.  C1E8 08          shr     eax, 0x8
0143C623  |.  3245 FC          xor     al, byte ptr [ebp-0x4]
0143C626  |.  C1EB 10          shr     ebx, 0x10
0143C629  |.  32D9             xor     bl, cl
0143C62B  |.  8846 08          mov     byte ptr [esi+0x8], al
0143C62E  |.  885E 09          mov     byte ptr [esi+0x9], bl
0143C631  |.  5E               pop     esi
0143C632  |.  5B               pop     ebx
0143C633  |.  8BE5             mov     esp, ebp
0143C635  |.  5D               pop     ebp
0143C636  \.  C3               retn

免費評分

參與人數 1吾愛幣 +1 熱心值 +1 收起 理由
Hmily + 1 + 1 用心討論,共獲提升!

查看全部評分

推薦
getserver 發表于 2020-1-29 20:55
C# 版注冊機 測試OK!
010editorRegister.rar (24.23 KB, 下載次數: 153)
推薦
 樓主| solly 發表于 2020-2-1 16:49 <
Hmily 發表于 2020-1-30 20:09
還差一個跨平臺其他的bin是不是也通用。。。

翻出多年不用的 Mac Book Pro 13 測試了一下,系統較老 MacOS X 10.9.5,裝了 010 Editor 6.0.3 x64 試了可行:



表示注冊算法,應該是全版本,全平臺通用的了。

Linux 和 MacOS 的注冊信息都是保存在 “010 Editor.ini” 文件中,如下形式:

點評

我又有疑問了,他們網絡驗證標記咋寸,好像其他平臺沒有注冊表。。。  詳情 回復 發表于 2020-2-1 19:10

免費評分

參與人數 1吾愛幣 +1 熱心值 +1 收起 理由
Hmily + 1 + 1 用心討論,共獲提升!

查看全部評分

推薦
 樓主| solly 發表于 2020-1-31 00:13 <
本帖最后由 solly 于 2020-1-31 00:14 編輯
Hmily 發表于 2020-1-30 23:45
不知道網絡驗證那塊會有使用過程中驗證不?如果只是注冊那好處理多了。

查了一下,在啟動時,讀取了標志,但只是在第二個注冊碼檢查函數判斷了一次,為0就檢查注冊表中的注冊碼是否合法,為1就是直接報注冊碼異常并不檢查注冊碼了。

[Asm] 純文本查看 復制代碼
01FE0225   > \8BC8                mov     ecx, eax
01FE0227   .  C645 FC 02          mov     byte ptr [ebp-0x4], 0x2
01FE022B   .  A3 5C80BD03         mov     dword ptr [0x3BD805C], eax
01FE0230   .  E8 DE22C2FE         call    00C02513                                  ;  啟動時讀取注冊表中的注冊信息檢查
01FE0235   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]
01FE023B   .  E8 3E3AC2FE         call    00C03C7E
01FE0240   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]
01FE0246   .  E8 852EC2FE         call    00C030D0
01FE024B   .  8B0D 5C80BD03       mov     ecx, dword ptr [0x3BD805C]
01FE0251   .  68 3C470000         push    0x473C
01FE0256   .  6A 0B               push    0xB
01FE0258   .  E8 FB9BC2FE         call    00C09E58                                  ;  啟動時注冊碼檢查
01FE025D   .  8BF0                mov     esi, eax
01FE025F   .  E8 C651C2FE         call    00C0542A
01FE0264   .  85C0                test    eax, eax
01FE0266   .  0F95C1              setne   cl
01FE0269   .  880D 8A80BD03       mov     byte ptr [0x3BD808A], cl
01FE026F   .  84C9                test    cl, cl
01FE0271   .  0F85 CC000000       jnz     01FE0343
01FE0277   .  E8 5037C2FE         call    00C039CC                                  ;  檢查是否顯示 flash window
01FE027C   .  85C0                test    eax, eax                                  ;  eax==0 表示顯示
01FE027E   .  74 0C               je      short 01FE028C
01FE0280   .  81FE DB000000       cmp     esi, 0xDB                                 ;  如果注冊不成功,則強行顯示
01FE0286   .  0F84 B7000000       je      01FE0343
01FE028C   >  68 987C8F03         push    038F7C98                                  ;  ASCII ":/Icons/resources/Splash.png"


使用該標志的地方:
[Asm] 純文本查看 復制代碼
01DDD540  /> \55                  push    ebp
01DDD541  |.  8BEC                mov     ebp, esp
01DDD543  |.  56                  push    esi
01DDD544  |.  8BF1                mov     esi, ecx
01DDD546  |.  837E 2C 00          cmp     dword ptr [esi+0x2C], 0x0                 ;  網絡驗證標志(從注冊表中讀取)
01DDD54A  |.  74 0A               je      short 01DDD556                            ;  等于0則跳轉去檢查注冊碼是否正確
01DDD54C  |.  B8 13010000         mov     eax, 0x113
01DDD551  |.  5E                  pop     esi
01DDD552  |.  5D                  pop     ebp
01DDD553  |.  C2 0800             retn    0x8
01DDD556  |>  57                  push    edi
01DDD557  |.  FF75 0C             push    dword ptr [ebp+0xC]                       ;  0x473C, release days
01DDD55A  |.  8B7D 08             mov     edi, dword ptr [ebp+0x8]                  ;  0x0B, version_id
01DDD55D  |.  57                  push    edi
01DDD55E  |.  E8 89D5E2FE         call    00C0AAEC                                  ;  注冊碼檢查(第二次檢查)
01DDD563  |.  83F8 2D             cmp     eax, 0x2D                                 ;  ‘-’; Switch (cases 2D..E7)
01DDD566  |.  0F84 A3000000       je      01DDD60F                                  ;  正確

點評

那看起來可以直接做一個本地注冊機,除了注冊碼把網絡驗證的校驗結果也一并寫入注冊表就一勞永逸了。  詳情 回復 發表于 2020-1-31 01:15

免費評分

參與人數 4吾愛幣 +4 熱心值 +4 收起 理由
niufq + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
crystal_577 + 1 + 1 我很贊同!
XDOP + 1 + 1 用心討論,共獲提升!
Hmily + 1 + 1 用心討論,共獲提升!

查看全部評分

7#
Hmily 發表于 2020-1-29 17:12
把網絡驗證也順便搞一下吧,不然光keygen不行的。
8#
 樓主| solly 發表于 2020-1-29 17:20 <
Hmily 發表于 2020-1-29 17:12
把網絡驗證也順便搞一下吧,不然光keygen不行的。

繼續看。當前沒注意,不過這個軟件會定時周期檢查注冊碼。

點評

嗯,和Beyond Compare差不多。  詳情 回復 發表于 2020-1-29 17:23
9#
shsww 發表于 2020-1-29 17:21
果然是高手!!                           
10#
Hmily 發表于 2020-1-29 17:23
solly 發表于 2020-1-29 17:20
繼續看。當前沒注意,不過這個軟件會定時周期檢查注冊碼。

嗯,和Beyond Compare差不多。
11#
suifeng165 發表于 2020-1-29 17:47
好貼,值得學習!
12#
cxj98 發表于 2020-1-29 18:10
Hmily 發表于 2020-1-29 17:23
嗯,和Beyond Compare差不多。

大佬,網絡驗證的問題交給你來解決吧。
13#
cxj98 發表于 2020-1-29 18:12
一看就知道是玉帝級別的破解大神,好文章要強頂加精推薦。
14#
q510 發表于 2020-1-29 18:15
感謝分享
15#
SnowRen 發表于 2020-1-29 19:02
很詳細,學習了
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:本版塊禁止灌水或回復與主題無關內容,違者重罰!

快速回復 收藏帖子 返回列表 搜索

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( )

GMT+8, 2020-4-3 12:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回復 返回頂部 返回列表