160 个 CrackMe 之 159 - Torn@do.2 脱壳修复、注册分析及注册机

本帖最后由 solly 于 2019-7-15 02:45 编辑

160 个 CrackMe 之 159 - Torn@do.2 是一个加了壳的 CrackMe ,文件信息如下:



显示未知的壳,用 "scan /t" 重新扫描一下:



这次显示为 "EncryptPE" 了。而且其文件末尾为字符串“eEnCrypter! 🙂 2nd&mi”,没见过,只有手动脱壳了。
节信息如下:



看起来与我原来脱过的 043 Ding Boy 的壳很象,也是很多节,并依次对下一节解码,也就是节名为 ".Stone" 的节,都是解码用的。
在 Windows 10 下OD载入 CrackMe,如下图所示:



往下拖可以看到 0x0041F096 有一个 jmp eax,我们直接选择在这一条指令上按 F4 , 然后再 F8 就会跳转到下一节的解码代码,与这一节基本一样,也是到 jmp eax 处 F4, 再F8跳转到下一节的解码代码,这个操作有多次,一直来到下面代码处,如下图,才来到 OEP:



上图的 0x00403560 才是 OEP,到这里我们就可以脱壳了。
再往下拖一下,可以找到 WinMain() 函数的调用,如下图:



如上图,call 00401DE0 就是调用 WinMain() 函数。
我们先脱壳,脱壳后,我们运行一下,报一个错,运行不了,错误提示如下所示:



是一个 API 函数的问题,这个 API 函数是 DefWindowProcA(),我们需要手动修复这个问题,我们重新来到 OEP。用“管理员身份运行” ImportREC,如下图所示:



可以看到,最后一行的 Thunk 的 Valid 为 NO,点击旁边的 ”Show Invalid" 按钮,如下图显示:



其中那条 NtdllDefWindowProc_A 就是要手动修复的,鼠标左键双击这一行,弹出手动导入表编辑对话框,如下图所示:



我们先在 "Module" 下位列表中,将  “ntdll.dll” 改成 "User32.dll",如下图所示:



然后在 Function 列表中找到“DefWindowProcA”这一行并选择,如上图所示,选好后按 “OK” 即可,这时显示如下图:



所有的函数都有效了,这时就是可以 "Fix Dump" 了,如下图所示,选择要修复的 Dump 文件即可。



这样操作后,就可以正常在 Windows 10 运行了,如果还不行,还可以用 LordPE 来 dump,不用 OD 的 dump 功能,如下图所示:



再按前面的方法修复,就应该可以在 Windows 10 下运行了。


脱壳后,OD 重新载入 F9 直接运行,来到其界面:



随便输入几个信息,点“ValIDAte”,没有动静,按3次后,“Validate” 按钮不可用了,提示变成了:"TRY AGAIN!",如下图所示:



通过前面所述,我们知道  WinMain() 函数入口在 0x00401DE0,我们浏览一下这个 WinMain()函数,可以看到这是一个标准的 Windows 窗口API应用的代码,最后面是消息循环处理。
从最前的4行代码,我们找到了 WndProc 的入口为 0x00401FD0,如下所示:
[Asm] 纯文本查看 复制代码

00401DE0    83EC 4C                sub     esp, 4C
00401DE3    C74424 00 30000000     mov     dword ptr [esp], 30
00401DEB    C74424 04 03000000     mov     dword ptr [esp+4], 3
00401DF3    C74424 08 D01F4000     mov     dword ptr [esp+8], 00401FD0

我们跟随立即数,来到 0x00401FD0,如下所示,是 WndProc() 的主处理代码:
[Asm] 纯文本查看 复制代码

00401FD0    8B4C24 08              mov     ecx, dword ptr [esp+8]                         ; nMessage
00401FD4    56                     push    esi
00401FD5    83F9 01                cmp     ecx, 1                                         ; WM_CREATE
00401FD8    74 2F                  je      short 00402009
00401FDA    83F9 02                cmp     ecx, 2                                         ; WM_DESTROY
00401FDD    0F84 84000000          je      00402067
00401FE3    81F9 11010000          cmp     ecx, 111                                       ; WM_COMMAND
00401FE9    0F84 86000000          je      00402075
00401FEF    8B4424 14              mov     eax, dword ptr [esp+14]                        ; lParam
00401FF3    8B5424 10              mov     edx, dword ptr [esp+10]                        ; wParam
00401FF7    8B7424 08              mov     esi, dword ptr [esp+8]                         ; hWnd
00401FFB    50                     push    eax                                            ; 默认消息处理
00401FFC    52                     push    edx
00401FFD    51                     push    ecx
00401FFE    56                     push    esi
00401FFF    FF15 D4E24000          call    dword ptr [<&USER32.DefWindowProcA>]           ; ntdll.NtdllDefWindowProc_A
00402005    5E                     pop     esi
00402006    C2 1000                retn    10

最后那个 call User32.DefWindowProcA 就是我们前面修复的那个 API 调用。
我们再次跟随 WM_CREATE 消息处理的“je 00402009”,来到 0x00402009,如下所示:
[Asm] 纯文本查看 复制代码

00402009    8B4424 14              mov     eax, dword ptr [esp+14]
0040200D    68 F4010000            push    1F4
00402012    68 88C14000            push    0040C188                                       ; ASCII "F:\Downloads\crack\[url=mailto:159_Torn@do.2]159_Torn@do.2[/url]"
00402017    6A 00                  push    0
00402019    8B48 04                mov     ecx, dword ptr [eax+4]
0040201C    890D F8BE4000          mov     dword ptr [40BEF8], ecx
00402022    FF15 64E24000          call    dword ptr [<&KERNEL32.GetModuleHandleA>]       ; KERNEL32.GetModuleHandleA
00402028    50                     push    eax
00402029    FF15 68E24000          call    dword ptr [<&KERNEL32.GetModuleFileNameA>]     ; KERNEL32.GetModuleFileNameA
0040202F    85C0                   test    eax, eax
00402031    74 10                  je      short 00402043
00402033    B9 5C000000            mov     ecx, 5C
00402038    3888 88C14000          cmp     byte ptr [eax+40C188], cl
0040203E    74 03                  je      short 00402043
00402040    48                     dec     eax
00402041  ^ 75 F5                  jnz     short 00402038
00402043    8B7424 08              mov     esi, dword ptr [esp+8]
00402047    6A 00                  push    0
00402049    C680 88C14000 00       mov     byte ptr [eax+40C188], 0
00402050    68 77777777            push    77777777
00402055    68 11010000            push    111
0040205A    56                     push    esi
0040205B    FF15 E4E24000          call    dword ptr [<&USER32.PostMessageA>]             ; USER32.PostMessageA
00402061    33C0                   xor     eax, eax
00402063    5E                     pop     esi
00402064    C2 1000                retn    10

可以看到,在处理 WM_CREATE 消息时,在最后,给窗口 post 了一条自定义的 WM_COMMAND 消息。我们再次回到前面的 WndProc()框架函数,来到 WM_COMMAND 消息处理跳转 "je 00402075",跟随这个跳转,来到 WM_COMMAND 消息处理代码处:
[Asm] 纯文本查看 复制代码

00402075    817C24 10 77777777     cmp     dword ptr [esp+10], 77777777
0040207D    75 21                  jnz     short 004020A0
0040207F    8B7424 08              mov     esi, dword ptr [esp+8]
00402083    6A 00                  push    0
00402085    68 B0204000            push    004020B0
0040208A    A1 F8BE4000            mov     eax, dword ptr [40BEF8]
0040208F    56                     push    esi
00402090    6A 65                  push    65
00402092    50                     push    eax
00402093    FF15 E0E24000          call    dword ptr [<&USER32.DialogBoxParamA>]          ; USER32.DialogBoxParamA
00402099    56                     push    esi
0040209A    FF15 F0E24000          call    dword ptr [<&USER32.DestroyWindow>]            ; USER32.DestroyWindow
004020A0    33C0                   xor     eax, eax
004020A2    5E                     pop     esi
004020A3    C2 1000                retn    10

这个消息处理非常简单,就是只要wParam为自定义的 0x77777777 就显示 CrackMe 的主对话框,因此这里就是显示主界面的地方,我们也找到了 DlgProc() 的入口为 0x004020B0。
再次“跟随立即数”,来到 0x004020B0,对话框消息处理框架代码如下:
[Asm] 纯文本查看 复制代码

004020B0    8B4424 08              mov     eax, dword ptr [esp+8]
004020B4    53                     push    ebx
004020B5    56                     push    esi
004020B6    83F8 02                cmp     eax, 2                                         ; WM_DESTROY
004020B9    57                     push    edi
004020BA    0F84 C6000000          je      00402186
004020C0    3D 10010000            cmp     eax, 110                                       ; WM_INITDIALOG
004020C5    74 13                  je      short 004020DA
004020C7    3D 11010000            cmp     eax, 111                                       ; WM_COMMAND
004020CC    0F84 9D000000          je      0040216F
004020D2    33C0                   xor     eax, eax
004020D4    5F                     pop     edi
004020D5    5E                     pop     esi
004020D6    5B                     pop     ebx
004020D7    C2 1000                retn    10

我们跟随 WM_INITDIALOG 消息处理跳转 "je 004020DA" 后,可以看到这样一优代码:
[Asm] 纯文本查看 复制代码

004020F6    6A 00                  push    0                                              ; 0 - Disabled, 1 - Enabled
004020F8    8B35 A0E24000          mov     esi, dword ptr [<&USER32.GetDlgItem>]          ; USER32.GetDlgItem
004020FE    68 EC030000            push    3EC                                            ; "Request" ID
00402103    53                     push    ebx                                            ; hDlg
00402104    FFD6                   call    esi                                            ; call GetDlgItem()
00402106    50                     push    eax                                            ; Control hwnd
00402107    FF15 98E24000          call    dword ptr [<&USER32.EnableWindow>]             ; USER32.EnableWindow

这段代码就是在 CrackMe 启动时将 "Request" 按钮的状态改为 "Disabled" 状态的。

我们再回到 DlgProc(),跟随处理 WM_COMMAND 跳转 "je 0040216F",来到其处理框架代码:
[Asm] 纯文本查看 复制代码

0040216F    8B4424 18              mov     eax, dword ptr [esp+18]
00402173    25 FFFF0000            and     eax, 0FFFF
00402178    3D EB030000            cmp     eax, 3EB                                       ; Validate 按钮
0040217D    7F 1B                  jg      short 0040219A
0040217F    74 54                  je      short 004021D5                                 ; 跳转去进行注册验证
00402181    83F8 02                cmp     eax, 2                                         ; WM_CLOSE
00402184    74 37                  je      short 004021BD
00402186    A1 08BE4000            mov     eax, dword ptr [40BE08]
0040218B    50                     push    eax
0040218C    FF15 F4E14000          call    dword ptr [<&GDI32.DeleteObject>]              ; GDI32.DeleteObject
00402192    33C0                   xor     eax, eax
00402194    5F                     pop     edi
00402195    5E                     pop     esi
00402196    5B                     pop     ebx
00402197    C2 1000                retn    10

可以看到,跟随 “ je 004021D5” 后就可以到达注册验证的代码了:
[Asm] 纯文本查看 复制代码

004021D5   > \8B5C24 10                mov     ebx, dword ptr [esp+10]                       ;  Case 3EB of switch 00402178
004021D9   .  53                       push    ebx
004021DA   .  E8 31F1FFFF              call    00401310                                      ;  假的序列号验证,实际取用户名
004021DF   .  83C4 04                  add     esp, 4
004021E2   .  8BF8                     mov     edi, eax                                      ;  eax ===> "solly"
004021E4   .  B9 FFFFFFFF              mov     ecx, -1
004021E9   .  2BC0                     sub     eax, eax
004021EB   .  F2:AE                    repne   scas byte ptr es:[edi]
004021ED   .  F7D1                     not     ecx
004021EF   .  2BF9                     sub     edi, ecx
004021F1   .  8BC1                     mov     eax, ecx
004021F3   .  C1E9 02                  shr     ecx, 2
004021F6   .  8BF7                     mov     esi, edi
004021F8   .  BF 30BF4000              mov     edi, 0040BF30                                 ;  ASCII "solly"
004021FD   .  F3:A5                    rep     movs dword ptr es:[edi], dword ptr [esi]
004021FF   .  8BC8                     mov     ecx, eax
00402201   .  53                       push    ebx
00402202   .  83E1 03                  and     ecx, 3
00402205   .  F3:A4                    rep     movs byte ptr es:[edi], byte ptr [esi]
00402207   .  E8 74F1FFFF              call    00401380                                      ;  假的序列号验证,实际取公司名
0040220C   .  83C4 04                  add     esp, 4
0040220F   .  8BF8                     mov     edi, eax                                      ;  eax ===> "company"
00402211   .  B9 FFFFFFFF              mov     ecx, -1
00402216   .  2BC0                     sub     eax, eax
00402218   .  F2:AE                    repne   scas byte ptr es:[edi]
0040221A   .  F7D1                     not     ecx
0040221C   .  2BF9                     sub     edi, ecx
0040221E   .  8BD1                     mov     edx, ecx
00402220   .  C1E9 02                  shr     ecx, 2
00402223   .  8BF7                     mov     esi, edi
00402225   .  BF E0BD4000              mov     edi, 0040BDE0                                 ;  ASCII "company"
0040222A   .  F3:A5                    rep     movs dword ptr es:[edi], dword ptr [esi]
0040222C   .  8BCA                     mov     ecx, edx
0040222E   .  53                       push    ebx
0040222F   .  83E1 03                  and     ecx, 3
00402232   .  F3:A4                    rep     movs byte ptr es:[edi], byte ptr [esi]
00402234   .  E8 B7F1FFFF              call    004013F0                                      ;  假的序列号验证,实际取序列名
00402239   .  83C4 04                  add     esp, 4
0040223C   .  8BF8                     mov     edi, eax                                      ;  eax ===> "78787878"
0040223E   .  B9 FFFFFFFF              mov     ecx, -1
00402243   .  2BC0                     sub     eax, eax
00402245   .  F2:AE                    repne   scas byte ptr es:[edi]
00402247   .  F7D1                     not     ecx
00402249   .  2BF9                     sub     edi, ecx
0040224B   .  8BD1                     mov     edx, ecx
0040224D   .  C1E9 02                  shr     ecx, 2
00402250   .  8BF7                     mov     esi, edi
00402252   .  BF 28BE4000              mov     edi, 0040BE28                                 ;  ASCII "78787878"
00402257   .  F3:A5                    rep     movs dword ptr es:[edi], dword ptr [esi]
00402259   .  8BCA                     mov     ecx, edx
0040225B   .  83E1 03                  and     ecx, 3
0040225E   .  F3:A4                    rep     movs byte ptr es:[edi], byte ptr [esi]
00402260   .  53                       push    ebx                                           ;  EBX == 0x00B50DE8
00402261   .  68 28BE4000              push    0040BE28                                      ;  ASCII "78787878"
00402266   .  68 E0BD4000              push    0040BDE0                                      ;  ASCII "company"
0040226B   .  68 30BF4000              push    0040BF30                                      ;  ASCII "solly"
00402270   .  E8 7BFAFFFF              call    00401CF0                                      ;  真正的注册码验证位置
00402275   .  83C4 10                  add     esp, 10
00402278   .  66:833D 20BE4000 28      cmp     word ptr [40BE20], 28                         ; 是否成功!
00402280   .  75 1E                    jnz     short 004022A0                                ; [40BE20] == 0x28 表示成功!
00402282   .  6A 00                    push    0                                             ; /lParam = NULL
00402284   .  A1 F8BE4000              mov     eax, dword ptr [40BEF8]                       ; |
00402289   .  68 A0254000              push    004025A0                                      ; |DlgProc = [url=mailto:Torn@do_.004025A0]Torn@do_.004025A0[/url]
0040228E   .  53                       push    ebx                                           ; |hOwner
0040228F   .  6A 68                    push    68                                            ; |pTemplate = 68
00402291   .  50                       push    eax                                           ; |hInst => NULL
00402292   .  FF15 E0E24000            call    dword ptr [<&user32.DialogBoxParamA>          ; \DialogBoxParamA
00402298   .  33C0                     xor     eax, eax
0040229A   .  5F                       pop     edi
0040229B   .  5E                       pop     esi
0040229C   .  5B                       pop     ebx
0040229D   .  C2 1000                  retn    10
004022A0   >  66:A1 74A04000           mov     ax, word ptr [40A074]
004022A6   .  66:40                    inc     ax
004022A8   .  66:A3 74A04000           mov     word ptr [40A074], ax
004022AE   .  66:3D 0300               cmp     ax, 3                                         ; 尝试3次
004022B2   .  75 32                    jnz     short 004022E6
004022B4   .  6A 00                    push    0                                             ; /Enable = FALSE
004022B6   .  8B35 A0E24000            mov     esi, dword ptr [<&user32.GetDlgItem>          ; |USER32.GetDlgItem
004022BC   .  68 EB030000              push    3EB                                           ; |/ControlID = 3EB (1003.)
004022C1   .  53                       push    ebx                                           ; ||hWnd
004022C2   .  FFD6                     call    esi                                           ; |\GetDlgItem
004022C4   .  50                       push    eax                                           ; |hWnd
004022C5   .  8B3D 98E24000            mov     edi, dword ptr [<&user32.EnableWindow>        ; |USER32.EnableWindow
004022CB   .  FFD7                     call    edi                                           ; \EnableWindow
004022CD   .  68 68A04000              push    0040A068                                      ; /Text = "TRY AGAIN!"
004022D2   .  68 EE030000              push    3EE                                           ; |ControlID = 3EE (1006.)
004022D7   .  53                       push    ebx                                           ; |hWnd
004022D8   .  FF15 F8E24000            call    dword ptr [<&user32.SetDlgItemTextA>          ; \SetDlgItemTextA
004022DE   .  66:A1 74A04000           mov     ax, word ptr [40A074]
004022E4   .  EB 0C                    jmp     short 004022F2
004022E6   >  8B3D 98E24000            mov     edi, dword ptr [<&user32.EnableWindow>        ;  USER32.EnableWindow
004022EC   .  8B35 A0E24000            mov     esi, dword ptr [<&user32.GetDlgItem>          ;  USER32.GetDlgItem
004022F2   >  66:A3 74A04000           mov     word ptr [40A074], ax
004022F8   .  66:3D 0300               cmp     ax, 3                                         ; 尝试3次
004022FC   .  7E 21                    jle     short 0040231F
004022FE   .  6A 00                    push    0
00402300   .  68 EB030000              push    3EB
00402305   .  53                       push    ebx
00402306   .  FFD6                     call    esi
00402308   .  50                       push    eax
00402309   .  FFD7                     call    edi
0040230B   .  6A 40                    push    40                                            ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
0040230D   .  68 98A74000              push    0040A798                                      ; |Title = "Message from TORN@DO"
00402312   .  68 10A74000              push    0040A710                                      ; |Text = "You're using a window editing tool like THE CUSTOMISER!",LF,"You have had 3 chances for entering the right code!",LF,"Do you think that's fair?"
00402317   .  6A 00                    push    0                                             ; |hOwner = NULL
00402319   .  FF15 DCE24000            call    dword ptr [<&user32.MessageBoxA>]             ; \MessageBoxA
0040231F   >  33C0                     xor     eax, eax
00402321   .  5F                       pop     edi
00402322   .  5E                       pop     esi
00402323   .  5B                       pop     ebx
00402324   .  C2 1000                  retn    10

从上面的我的注释中,可以看到,前面三次都是没有用的验证,迷惑用的,实际用途只是取界面上输入的三个字符串。直正的验证是如下代码处:
[Asm] 纯文本查看 复制代码

00402260   .  53                       push    ebx                                           ;  EBX == 0x00B50DE8
00402261   .  68 28BE4000              push    0040BE28                                      ;  ASCII "78787878"
00402266   .  68 E0BD4000              push    0040BDE0                                      ;  ASCII "company"
0040226B   .  68 30BF4000              push    0040BF30                                      ;  ASCII "solly"
00402270   .  E8 7BFAFFFF              call    00401CF0                                      ;  真正的注册码验证位置
00402275   .  83C4 10                  add     esp, 10
00402278   .  66:833D 20BE4000 28      cmp     word ptr [40BE20], 28                         ; 是否成功!
00402280   .  75 1E                    jnz     short 004022A0                                ; [40BE20] == 0x28 表示成功!

上面的 call 00401CF0 才是真正的验证代码,其代码下:
[Asm] 纯文本查看 复制代码

00401CF0  /$  53                       push    ebx
00401CF1  |.  56                       push    esi
00401CF2  |.  8B5C24 14                mov     ebx, dword ptr [esp+14]                ;  序列号
00401CF6  |.  57                       push    edi
00401CF7  |.  55                       push    ebp
00401CF8  |.  53                       push    ebx
00401CF9  |.  E8 F2FCFFFF              call    004019F0                               ;  strcmp(),判断是否空串
00401CFE  |.  83C4 04                  add     esp, 4
00401D01  |.  53                       push    ebx                                    ;  ebx ===> SN
00401D02  |.  E8 19FAFFFF              call    00401720                               ;  sn[0]~sn[4],固定字符 "IDC40"
00401D07  |.  83C4 04                  add     esp, 4
00401D0A  |.  83F8 01                  cmp     eax, 1
00401D0D  |.  74 0E                    je      short 00401D1D
00401D0F  |.  66:C705 20BE4000 FFFF    mov     word ptr [40BE20], 0FFFF
00401D18  |.  5D                       pop     ebp
00401D19  |.  5F                       pop     edi
00401D1A  |.  5E                       pop     esi
00401D1B  |.  5B                       pop     ebx
00401D1C  |.  C3                       retn
00401D1D  |>  8B6C24 20                mov     ebp, dword ptr [esp+20]
00401D21  |.  8B7C24 18                mov     edi, dword ptr [esp+18]
00401D25  |.  8B7424 14                mov     esi, dword ptr [esp+14]
00401D29  |.  55                       push    ebp
00401D2A  |.  53                       push    ebx
00401D2B  |.  57                       push    edi
00401D2C  |.  56                       push    esi
00401D2D  |.  E8 EEFCFFFF              call    00401A20                               ;  无用校验
00401D32  |.  83C4 10                  add     esp, 10
00401D35  |.  53                       push    ebx
00401D36  |.  E8 55FAFFFF              call    00401790                               ;  sn[6]~sn[9],固定字符 "ETBL"
00401D3B  |.  83C4 04                  add     esp, 4
00401D3E  |.  83F8 01                  cmp     eax, 1
00401D41  |.  74 0E                    je      short 00401D51
00401D43  |.  66:C705 20BE4000 FFFF    mov     word ptr [40BE20], 0FFFF
00401D4C  |.  5D                       pop     ebp
00401D4D  |.  5F                       pop     edi
00401D4E  |.  5E                       pop     esi
00401D4F  |.  5B                       pop     ebx
00401D50  |.  C3                       retn
00401D51  |>  53                       push    ebx
00401D52  |.  E8 89FAFFFF              call    004017E0                               ;  序列号最后4字符,当前时间校验
00401D57  |.  83C4 04                  add     esp, 4
00401D5A  |.  83F8 01                  cmp     eax, 1
00401D5D  |.  74 0E                    je      short 00401D6D
00401D5F  |.  66:C705 20BE4000 FFFF    mov     word ptr [40BE20], 0FFFF
00401D68  |.  5D                       pop     ebp
00401D69  |.  5F                       pop     edi
00401D6A  |.  5E                       pop     esi
00401D6B  |.  5B                       pop     ebx
00401D6C  |.  C3                       retn
00401D6D  |>  55                       push    ebp
00401D6E  |.  53                       push    ebx
00401D6F  |.  57                       push    edi
00401D70  |.  56                       push    esi
00401D71  |.  E8 FAFDFFFF              call    00401B70                               ;  无用校验
00401D76  |.  83C4 10                  add     esp, 10
00401D79  |.  A1 80C34000              mov     eax, dword ptr [40C380]                ;  FirstInstallDateTime转换成字符串后的长度
00401D7E  |.  50                       push    eax
00401D7F  |.  53                       push    ebx
00401D80  |.  E8 EBFAFFFF              call    00401870                               ;  注册表FirstInstallDateTime验证,但由于的BUG,变成固定数字(1702505)的验证
00401D85  |.  83C4 08                  add     esp, 8
00401D88  |.  83F8 01                  cmp     eax, 1
00401D8B  |.  74 0E                    je      short 00401D9B
00401D8D  |.  66:C705 20BE4000 FFFF    mov     word ptr [40BE20], 0FFFF
00401D96  |.  5D                       pop     ebp
00401D97  |.  5F                       pop     edi
00401D98  |.  5E                       pop     esi
00401D99  |.  5B                       pop     ebx
00401D9A  |.  C3                       retn
00401D9B  |>  55                       push    ebp
00401D9C  |.  53                       push    ebx
00401D9D  |.  57                       push    edi
00401D9E  |.  56                       push    esi
00401D9F  |.  E8 8CFEFFFF              call    00401C30                               ;  无用校验
00401DA4  |.  83C4 10                  add     esp, 10
00401DA7  |.  53                       push    ebx                                    ;  ebx ===> sn
00401DA8  |.  E8 63FBFFFF              call    00401910                               ;  注册信息验证,包括注册表的 RegisteredOwner、输入的用户名和公司名验证
00401DAD  |.  83C4 04                  add     esp, 4
00401DB0  |.  83F8 01                  cmp     eax, 1
00401DB3  |.  74 0E                    je      short 00401DC3
00401DB5  |.  66:C705 20BE4000 FFFF    mov     word ptr [40BE20], 0FFFF
00401DBE  |.  5D                       pop     ebp
00401DBF  |.  5F                       pop     edi
00401DC0  |.  5E                       pop     esi
00401DC1  |.  5B                       pop     ebx
00401DC2  |.  C3                       retn
00401DC3  |>  55                       push    ebp
00401DC4  |.  E8 97F6FFFF              call    00401460                               ;  设置成功状态
00401DC9  |.  83C4 04                  add     esp, 4
00401DCC  |.  5D                       pop     ebp
00401DCD  |.  5F                       pop     edi
00401DCE  |.  5E                       pop     esi
00401DCF  |.  5B                       pop     ebx
00401DD0  \.  C3                       retn

这里説明一下,从上面代码中可以看到,有一个时间验证(call 004017E0),代码如下:
[Asm] 纯文本查看 复制代码

004017E0  /$  83EC 04                  sub     esp, 4
004017E3  |.  33C9                     xor     ecx, ecx
004017E5  |.  8D4424 01                lea     eax, dword ptr [esp+1]
004017E9  |.  56                       push    esi
004017EA  |.  8B5424 0C                mov     edx, dword ptr [esp+C]                            ;  edx ===> SN
004017EE  |.  57                       push    edi
004017EF  |.  8BFA                     mov     edi, edx                                          ;  edi ===> SN
004017F1  |.  884C24 08                mov     byte ptr [esp+8], cl
004017F5  |.  66:8908                  mov     word ptr [eax], cx
004017F8  |.  8848 02                  mov     byte ptr [eax+2], cl
004017FB  |.  B9 FFFFFFFF              mov     ecx, -1
00401800  |.  2BC0                     sub     eax, eax
00401802  |.  F2:AE                    repne   scas byte ptr es:[edi]
00401804  |.  F7D1                     not     ecx                                               ;  ecx = len(sn)+1
00401806  |.  8BFA                     mov     edi, edx
00401808  |.  2BC0                     sub     eax, eax
0040180A  |.  8A4C11 FB                mov     cl, byte ptr [ecx+edx-5]                          ;  sn[len-4]
0040180E  |.  884C24 08                mov     byte ptr [esp+8], cl
00401812  |.  B9 FFFFFFFF              mov     ecx, -1
00401817  |.  F2:AE                    repne   scas byte ptr es:[edi]
00401819  |.  F7D1                     not     ecx                                               ;  ecx = len(sn)+1
0040181B  |.  8BFA                     mov     edi, edx
0040181D  |.  8A4411 FC                mov     al, byte ptr [ecx+edx-4]                          ;  sn[len-3]
00401821  |.  B9 FFFFFFFF              mov     ecx, -1
00401826  |.  884424 09                mov     byte ptr [esp+9], al
0040182A  |.  2BC0                     sub     eax, eax
0040182C  |.  F2:AE                    repne   scas byte ptr es:[edi]
0040182E  |.  F7D1                     not     ecx                                               ;  ecx = len(sn)+1
00401830  |.  8BFA                     mov     edi, edx
00401832  |.  2BC0                     sub     eax, eax
00401834  |.  8A4C11 FD                mov     cl, byte ptr [ecx+edx-3]                          ;  sn[len-2]
00401838  |.  884C24 0A                mov     byte ptr [esp+A], cl
0040183C  |.  B9 FFFFFFFF              mov     ecx, -1
00401841  |.  F2:AE                    repne   scas byte ptr es:[edi]
00401843  |.  F7D1                     not     ecx                                               ;  ecx = len(sn)+1
00401845  |.  8D4424 08                lea     eax, dword ptr [esp+8]
00401849  |.  8A5411 FE                mov     dl, byte ptr [ecx+edx-2]                          ;  sn[len-1]
0040184D  |.  885424 0B                mov     byte ptr [esp+B], dl
00401851  |.  50                       push    eax
00401852  |.  E8 291C0000              call    00403480                                          ;  atoi(sn[len-4][len-3][len-2][len-1])
00401857  |.  83C4 04                  add     esp, 4
0040185A  |.  8BF0                     mov     esi, eax                                          ;  esi = 0
0040185C  |.  E8 3FFEFFFF              call    004016A0                                          ;  GetLocalTime
00401861  |.  2BC6                     sub     eax, esi                                          ;  eax = 0x0000081C = 2076
00401863  |.  5F                       pop     edi
00401864  |.  5E                       pop     esi
00401865  |.  83F8 01                  cmp     eax, 1
00401868  |.  1BC0                     sbb     eax, eax
0040186A  |.  83C4 04                  add     esp, 4
0040186D  |.  F7D8                     neg     eax
0040186F  \.  C3                       retn

其中又有一个调用(call 004016A0),就是根据当前时间生成一段注册验证,对注册码最后4个数字进行验证:
[Asm] 纯文本查看 复制代码

004016A0  /$  83EC 10                  sub     esp, 10
004016A3  |.  8D4424 00                lea     eax, dword ptr [esp]
004016A7  |.  56                       push    esi
004016A8  |.  50                       push    eax                                               ; /pLocaltime
004016A9  |.  FF15 6CE24000            call    dword ptr [<&kernel32.GetLocalTime>]              ; \GetLocalTime
004016AF  |.  33D2                     xor     edx, edx
004016B1  |.  33C0                     xor     eax, eax
004016B3  |.  66:8B5424 06             mov     dx, word ptr [esp+6]                              ;  月份 7
004016B8  |.  33C9                     xor     ecx, ecx
004016BA  |.  66:8B4424 0A             mov     ax, word ptr [esp+A]                              ;  日 6
004016BF  |.  0FAFD0                   imul    edx, eax                                          ;  EDX = 0x2A
004016C2  |.  66:8B4C24 0E             mov     cx, word ptr [esp+E]                              ;  分钟,cx = 0x09
004016C7  |.  8B4424 0C                mov     eax, dword ptr [esp+C]                            ;  eax = 0x00090003
004016CB  |.  25 FFFF0000              and     eax, 0FFFF                                        ;  小时 eax = 3
004016D0  |.  0FAFC1                   imul    eax, ecx                                          ;  eax == 0x1B
004016D3  |.  0FBE0D 60BF4000          movsx   ecx, byte ptr [40BF60]                            ;  RegisteredOwner[0]
004016DA  |.  03D0                     add     edx, eax                                          ;  edx = 0x2A + 0x1B
004016DC  |.  8B4424 04                mov     eax, dword ptr [esp+4]                            ;  ax = 2019
004016E0  |.  2BD1                     sub     edx, ecx                                          ;  ecx = 0
004016E2  |.  25 FFFF0000              and     eax, 0FFFF
004016E7  |.  8D3402                   lea     esi, dword ptr [edx+eax]                          ;  esi = edx + eax + 0x45 + 0x7E3 = 69 + 2019 = 2088
004016EA  |.  56                       push    esi
004016EB  |.  E8 A0FBFFFF              call    00401290                                          ;  检查 SoftICE (Win9x) 调试
004016F0  |.  83C4 04                  add     esp, 4
004016F3  |.  85C0                     test    eax, eax
004016F5  |.  74 06                    je      short 004016FD
004016F7  |.  81C6 43010000            add     esi, 143
004016FD  |>  56                       push    esi
004016FE  |.  E8 CDFBFFFF              call    004012D0                                          ;  检查 SoftICE (NT) 调试
00401703  |.  83C4 04                  add     esp, 4
00401706  |.  85C0                     test    eax, eax
00401708  |.  74 06                    je      short 00401710
0040170A  |.  81C6 71020000            add     esi, 271
00401710  |>  8BC6                     mov     eax, esi
00401712  |.  5E                       pop     esi
00401713  |.  83C4 10                  add     esp, 10
00401716  \.  C3                       retn

也就是説,其验证时间精准到了分钟,生成的序列号有效时间最多60秒,如果注册机生成序列号与你输入序列号不是在同一分钟数字时(不是指1分钟内)序列号就是无效的,也就是説当输入序列号时,只要秒钟跨过了第59秒,就得重新生成序列号。
注册码前面两段是固定的,由 call 00401720 和 call 00401790 实现的,比较简单,这里不对其进行分析。
call 00401870 是对注册表中的一个值进行验证,这样,序列号与具体机器有关,不是通用的了,必须要有注册机才能搞定注册。这个调用是处理注册表中  FirstInstallDateTime 这个值的,不过这个值只有在 Windows 9x 系统下才有,Win NT 系列,如 Windows 10 下就没有这个注册表项。另外 CrackMe 还要用到一个注册表项: RegisteredOwner,这个也只有在 Windows 9x 下才有。这个调用的主要代码如下(其前面有一段代码中没有用的,迷惑用的,不贴上来了):
[Asm] 纯文本查看 复制代码

00401870  /$  83EC 64                  sub     esp, 64
00401873  |.  53                       push    ebx
00401874  |.  56                       push    esi
00401875  |.  57                       push    edi
00401876  |.  33DB                     xor     ebx, ebx                                          ;  int i = 0;
00401878  |.  8D7C24 0D                lea     edi, dword ptr [esp+D]
0040187C  |.  55                       push    ebp
0040187D  |.  33C0                     xor     eax, eax
0040187F  |.  B9 18000000              mov     ecx, 18
00401884  |.  885C24 10                mov     byte ptr [esp+10], bl                             ;  sn_time[0] = '\0'
00401888  |.  F3:AB                    rep     stos dword ptr es:[edi]                           ;  len 0x63
0040188A  |.  66:AB                    stos    word ptr es:[edi]
0040188C  |.  AA                       stos    byte ptr es:[edi]
0040188D  |.  33F6                     xor     esi, esi                                          ;  int j = 0;
0040188F  |.  8B6C24 7C                mov     ebp, dword ptr [esp+7C]                           ;  FirstInstallDateTime 转换成字符串后的长度 len(FirstInstallDateTime) = 7
00401893  |.  3BE8                     cmp     ebp, eax
00401895  |.  74 24                    je      short 004018BB
00401897  |.  8B5424 78                mov     edx, dword ptr [esp+78]                           ;  edx ===> SN
0040189B  |>  8BFA                     /mov     edi, edx
0040189D  |.  B9 FFFFFFFF              |mov     ecx, -1
004018A2  |.  2BC0                     |sub     eax, eax
004018A4  |.  F2:AE                    |repne   scas byte ptr es:[edi]
004018A6  |.  F7D1                     |not     ecx
004018A8  |.  49                       |dec     ecx                                              ;  len(sn)
004018A9  |.  46                       |inc     esi                                              ;  j ++
004018AA  |.  2BCD                     |sub     ecx, ebp                                         ;  len(sn) - len(company)
004018AC  |.  03CB                     |add     ecx, ebx                                         ;  c = len(sn) - len(company) + i
004018AE  |.  43                       |inc     ebx                                              ;  i++
004018AF  |.  3BF5                     |cmp     esi, ebp                                         ;  j<len(company)
004018B1  |.  8A4411 FB                |mov     al, byte ptr [ecx+edx-5]                         ;  sn[c-5]
004018B5  |.  884434 0F                |mov     byte ptr [esp+esi+F], al
004018B9  |.^ 72 E0                    \jb      short 0040189B
004018BB  |>  8D4424 10                lea     eax, dword ptr [esp+10]                           ;  sn_time == sn[installtime]段
004018BF  |.  50                       push    eax
004018C0  |.  E8 BB1B0000              call    00403480                                          ;  atoi(FirstInstallTime) = 0x0019FA69 = 1702505
004018C5  |.  83C4 04                  add     esp, 4
004018C8  |.  8BF0                     mov     esi, eax
004018CA  |.  A1 FCBE4000              mov     eax, dword ptr [40BEFC]                           ;  [0x0040BEFC] == 0x0019FA74 == 1702516, FirstInstallTime
004018CF  |.  894424 10                mov     dword ptr [esp+10], eax                           ;  eax == 1702516
004018D3  |.  C74424 14 00000000       mov     dword ptr [esp+14], 0
004018DB  |.  DF6C24 10                fild    qword ptr [esp+10]
004018DF  |.  D9C0                     fld     st
004018E1  |.  E8 731C0000              call    00403559                                          ;  tanh(1702516) = 1.0000
004018E6  |.  DC0D 20904000            fmul    qword ptr [409020]                                ;  1.0 * 11.00
004018EC  |.  DEE9                     fsubp   st(1), st                                         ;  1702516-11=1702505
004018EE  |.  E8 590D0000              call    0040264C
004018F3  |.  2BC6                     sub     eax, esi                                          ;  eax = 0x0019FA69 = 1702505
004018F5  |.  5D                       pop     ebp
004018F6  |.  5F                       pop     edi
004018F7  |.  83F8 01                  cmp     eax, 1
004018FA  |.  1BC0                     sbb     eax, eax
004018FC  |.  5E                       pop     esi
004018FD  |.  F7D8                     neg     eax
004018FF  |.  5B                       pop     ebx
00401900  |.  83C4 64                  add     esp, 64
00401903  \.  C3                       retn

就是将 FirstInstallDateTime 进行简单计算后,与输入的序列号相关字段进行比较,相等即通过。
还有一个调用(call 00401910)就是对我们在界面上输入的用户名和公司名进行校验,当中还包括注册表项 RegisteredOwner 的验证,如下:
[Asm] 纯文本查看 复制代码

00401910  /$  83EC 64                  sub     esp, 64
00401913  |.  33C0                     xor     eax, eax
00401915  |.  B9 18000000              mov     ecx, 18                                           ;  ecx == 0x18 == 24
0040191A  |.  56                       push    esi
0040191B  |.  C64424 04 00             mov     byte ptr [esp+4], 0
00401920  |.  57                       push    edi
00401921  |.  8D7C24 09                lea     edi, dword ptr [esp+9]
00401925  |.  F3:AB                    rep     stos dword ptr es:[edi]
00401927  |.  66:AB                    stos    word ptr es:[edi]
00401929  |.  BE 0C000000              mov     esi, 0C                                           ;  int i = 12
0040192E  |.  B9 FFFFFFFF              mov     ecx, -1
00401933  |.  AA                       stos    byte ptr es:[edi]
00401934  |.  8B5424 70                mov     edx, dword ptr [esp+70]                           ;  edx ===> SN
00401938  |.  2BC0                     sub     eax, eax
0040193A  |.  8BFA                     mov     edi, edx                                          ;  edi ===> SN
0040193C  |.  F2:AE                    repne   scas byte ptr es:[edi]
0040193E  |.  F7D1                     not     ecx
00401940  |.  49                       dec     ecx                                               ;  ecx = len(sn) = 0x21 = 33
00401941  |.  2B0D 80C34000            sub     ecx, dword ptr [40C380]                           ;  FirstInstallDateTime 转换成字符串后的长度
00401947  |.  83E9 05                  sub     ecx, 5                                            ;  5 (当前时间的长度 "-nnnn")
0040194A  |.  3BCE                     cmp     ecx, esi                                          ;  len(sn) - 12 <= 12
0040194C  |.  76 24                    jbe     short 00401972
0040194E  |>  8A4432 FF                /mov     al, byte ptr [edx+esi-1]                         ;  sn[i-1]
00401952  |.  46                       |inc     esi                                              ;  i++
00401953  |.  8BFA                     |mov     edi, edx                                         ;  edi ====> sn
00401955  |.  B9 FFFFFFFF              |mov     ecx, -1
0040195A  |.  884434 FB                |mov     byte ptr [esp+esi-5], al                         ;  tmp[i-12] = sn[i-1]
0040195E  |.  2BC0                     |sub     eax, eax
00401960  |.  F2:AE                    |repne   scas byte ptr es:[edi]
00401962  |.  F7D1                     |not     ecx
00401964  |.  49                       |dec     ecx
00401965  |.  2B0D 80C34000            |sub     ecx, dword ptr [40C380]                          ;  FirstInstallDateTime 转换成字符串后的长度
0040196B  |.  83E9 05                  |sub     ecx, 5                                           ;  5 (当前时间的长度 "-nnnn")
0040196E  |.  3BCE                     |cmp     ecx, esi
00401970  |.^ 77 DC                    \ja      short 0040194E
00401972  |>  8D4424 08                lea     eax, dword ptr [esp+8]                            ;  eax ===> "398378258"
00401976  |.  50                       push    eax
00401977  |.  E8 041B0000              call    00403480                                          ;  atoi()
0040197C  |.  83C4 04                  add     esp, 4
0040197F  |.  8BF8                     mov     edi, eax                                          ;  eax == 0x17BEC512 == 398378258
00401981  |.  E8 0AFCFFFF              call    00401590                                          ;  RegisteredOwner索引check
00401986  |.  8BF0                     mov     esi, eax                                          ;  eax == 0x14 == 20
00401988  |.  E8 B3FBFFFF              call    00401540                                          ;  RegisteredOwner内容check
0040198D  |.  33F0                     xor     esi, eax                                          ;  eax == 0x01BA == 442, esi = 0x01AE == 430
0040198F  |.  68 E0BD4000              push    0040BDE0                                          ;  ASCII "ite company"
00401994  |.  68 30BF4000              push    0040BF30                                          ;  ASCII "solly88"
00401999  |.  E8 42FCFFFF              call    004015E0                                          ;  注册名和公司名  checkcode
0040199E  |.  83C4 08                  add     esp, 8
004019A1  |.  03C6                     add     eax, esi                                          ;  long a = checkcode + regOwner_check
004019A3  |.  8D0CC0                   lea     ecx, dword ptr [eax+eax*8]                        ;  ecx == a * 9
004019A6  |.  8D14C8                   lea     edx, dword ptr [eax+ecx*8]                        ;  edx == a * 73
004019A9  |.  8D0C52                   lea     ecx, dword ptr [edx+edx*2]                        ;  ecx == a * 219 = 778983
004019AC  |.  C1E1 02                  shl     ecx, 2                                            ;  ecx == a * 876
004019AF  |.  2BC8                     sub     ecx, eax                                          ;  ecx == a * 875
004019B1  |.  C1E1 06                  shl     ecx, 6                                            ;  ecx == a * 875*64 = a * 56000
004019B4  |.  2BC8                     sub     ecx, eax                                          ;  ecx == a * 55999
004019B6  |.  03C9                     add     ecx, ecx                                          ;  ecx == a * 111998
004019B8  |.  894C24 08                mov     dword ptr [esp+8], ecx                            ;  ecx == 0x17BEBFB6 = 398376886
004019BC  |.  C74424 0C 00000000       mov     dword ptr [esp+C], 0
004019C4  |.  DF6C24 08                fild    qword ptr [esp+8]
004019C8  |.  D9C0                     fld     st
004019CA  |.  D9FE                     fsin                                                      ;  sin(398376886) = -0.6866350580165284495
004019CC  |.  DC0D 28904000            fmul    qword ptr [409028]                                ;  [0x00409029] = 1999.0000, sin()*1999 = -1372.5834809750404020
004019D2  |.  DEE9                     fsubp   st(1), st                                         ;  st == 398378258.58348095420 = 398376886 - (-1372.5834809750404020)
004019D4  |.  E8 730C0000              call    0040264C                                          ;  eax == 0x17BEC512 == 398378258
004019D9  |.  2BC7                     sub     eax, edi                                          ;  edi = atoi()
004019DB  |.  5F                       pop     edi
004019DC  |.  5E                       pop     esi
004019DD  |.  83F8 01                  cmp     eax, 1
004019E0  |.  1BC0                     sbb     eax, eax
004019E2  |.  83C4 64                  add     esp, 64
004019E5  |.  F7D8                     neg     eax
004019E7  \.  C3                       retn

其中,对用户名和公司名处理的调用(call 004015E3)如下所示:
[Asm] 纯文本查看 复制代码

004015E0  /$  83EC 08                  sub     esp, 8
004015E3  |.  33D2                     xor     edx, edx                                          ;  long sum = 0;
004015E5  |.  B9 FFFFFFFF              mov     ecx, -1
004015EA  |.  53                       push    ebx
004015EB  |.  66:BB 0100               mov     bx, 1                                             ;  int i = 1
004015EF  |.  56                       push    esi
004015F0  |.  8B7424 14                mov     esi, dword ptr [esp+14]                           ;  esi ===> "solly"
004015F4  |.  57                       push    edi
004015F5  |.  8BFE                     mov     edi, esi                                          ;  edi ===> "solly"
004015F7  |.  2BC0                     sub     eax, eax
004015F9  |.  F2:AE                    repne   scas byte ptr es:[edi]
004015FB  |.  F7D1                     not     ecx
004015FD  |.  49                       dec     ecx                                               ;  ecx == 用户名长度
004015FE  |.  83F9 01                  cmp     ecx, 1
00401601  |.  76 2F                    jbe     short 00401632
00401603  |>  0FBFC3                   /movsx   eax, bx                                          ;  i
00401606  |.  0FBE4430 FF              |movsx   eax, byte ptr [eax+esi-1]                        ;  eax == name[i-1]
0040160B  |.  8BC8                     |mov     ecx, eax                                         ;  ecx == name[i-1]
0040160D  |.  C1E0 02                  |shl     eax, 2                                           ;  eax == name[i-1] * 4
00401610  |.  66:43                    |inc     bx                                               ;  i++
00401612  |.  8BFE                     |mov     edi, esi                                         ;  edi ===> "solly"
00401614  |.  8D04C0                   |lea     eax, dword ptr [eax+eax*8]                       ;  eax == name[i-1] * 36,   (4*8+4)
00401617  |.  8D0CC1                   |lea     ecx, dword ptr [ecx+eax*8]                       ;  ecx == name[i-1] * 289,  (36*8+1)
0040161A  |.  8D04C9                   |lea     eax, dword ptr [ecx+ecx*8]                       ;  eax == name[i-1] * 2601, (289*9)
0040161D  |.  B9 FFFFFFFF              |mov     ecx, -1
00401622  |.  03D0                     |add     edx, eax                                         ;  sum += eax;
00401624  |.  2BC0                     |sub     eax, eax
00401626  |.  F2:AE                    |repne   scas byte ptr es:[edi]
00401628  |.  0FBFC3                   |movsx   eax, bx                                          ;  i
0040162B  |.  F7D1                     |not     ecx
0040162D  |.  49                       |dec     ecx                                              ;  len(solly)
0040162E  |.  3BC8                     |cmp     ecx, eax                                         ;  i<len(name)
00401630  |.^ 77 D1                    \ja      short 00401603                                   ;  sum = 0x00118ACA
00401632  |>  66:BB 0100               mov     bx, 1                                             ;  int i = 1
00401636  |.  8B7424 1C                mov     esi, dword ptr [esp+1C]                           ;  esi ===> "company"
0040163A  |.  8BFE                     mov     edi, esi                                          ;  edi ===> "company"
0040163C  |.  B9 FFFFFFFF              mov     ecx, -1
00401641  |.  2BC0                     sub     eax, eax
00401643  |.  F2:AE                    repne   scas byte ptr es:[edi]
00401645  |.  F7D1                     not     ecx
00401647  |.  49                       dec     ecx                                               ;  len(company)
00401648  |.  83F9 01                  cmp     ecx, 1
0040164B  |.  76 21                    jbe     short 0040166E
0040164D  |>  0FBFC3                   /movsx   eax, bx                                          ;  i
00401650  |.  66:43                    |inc     bx                                               ;  i++
00401652  |.  8BFE                     |mov     edi, esi                                         ;  edi ===> "company"
00401654  |.  0FBE4C30 FF              |movsx   ecx, byte ptr [eax+esi-1]                        ;  company[i-1]
00401659  |.  03D1                     |add     edx, ecx                                         ;  sum += company[i-1]
0040165B  |.  B9 FFFFFFFF              |mov     ecx, -1
00401660  |.  2BC0                     |sub     eax, eax
00401662  |.  F2:AE                    |repne   scas byte ptr es:[edi]
00401664  |.  0FBFC3                   |movsx   eax, bx                                          ;  i
00401667  |.  F7D1                     |not     ecx
00401669  |.  49                       |dec     ecx                                              ;  len(company)
0040166A  |.  3BC8                     |cmp     ecx, eax                                         ;  i<len(company)
0040166C  |.^ 77 DF                    \ja      short 0040164D                                   ;  sum == 0x00118D48
0040166E  |>  8D0492                   lea     eax, dword ptr [edx+edx*4]                        ;  eax = sum * 5
00401671  |.  8D0C42                   lea     ecx, dword ptr [edx+eax*2]                        ;  ecx = sum * 11
00401674  |.  894C24 0C                mov     dword ptr [esp+C], ecx                            ;  ecx == 0x00C11218 == 12653080
00401678  |.  C74424 10 00000000       mov     dword ptr [esp+10], 0
00401680  |.  DF6C24 0C                fild    qword ptr [esp+C]
00401684  |.  D9FA                     fsqrt                                                     ;  sqrt(12653080) == 3557.1168100021682220
00401686  |.  E8 C10F0000              call    0040264C                                          ;  eax == 0x0DE5 == 3557
0040168B  |.  5F                       pop     edi
0040168C  |.  5E                       pop     esi
0040168D  |.  5B                       pop     ebx
0040168E  |.  83C4 08                  add     esp, 8
00401691  \.  C3                       retn

另外对 RegisteredOwner 的验证有两次,比较简单,见注册机,不在此分析。

因为其有对注册表项进行验证,所以其需要读取注册表中的数据,不过,其在读取 FirstInstallDateTime 有问题,并没有取得这个值,而是取得保存这个值的地址,将这个地址参与了序列号的计算,这段取注册表信息的代码如下:
[Asm] 纯文本查看 复制代码

00401E59  |.  68 F8A64000              push    0040A6F8                                          ;  ASCII "FirstInstallDateTime"
00401E5E  |.  68 CCA64000              push    0040A6CC                                          ;  ASCII "SOFTWARE\Microsoft\Windows\CurrentVersion"
00401E63  |.  68 02000080              push    80000002
00401E68  |.  E8 43F6FFFF              call    004014B0                                          ;  读注册表
00401E6D  |.  83C4 0C                  add     esp, 0C
00401E70  |.  8B2D B4E24000            mov     ebp, dword ptr [<&user32.wsprintfA>]              ;  USER32.wsprintfA
00401E76  |.  50                       push    eax                                               ; /<%lu>,这里有Bug,传入的不是读取的时间,而是指向时间的地址指针,固定为 0x0019FA74
00401E77  |.  68 C8A64000              push    0040A6C8                                          ; |Format = "%lu"
00401E7C  |.  68 90BF4000              push    0040BF90                                          ; |s = [url=mailto:Torn@do_.0040BF90]Torn@do_.0040BF90[/url]
00401E81  |.  FFD5                     call    ebp                                               ; \wsprintfA
00401E83  |.  83C4 0C                  add     esp, 0C
00401E86  |.  BF 90BF4000              mov     edi, 0040BF90                                     ;  ASCII "1702516"
00401E8B  |.  68 90BF4000              push    0040BF90                                          ;  ASCII "1702516"
00401E90  |.  E8 EB150000              call    00403480                                          ;  atoi(pointer)
00401E95  |.  83C4 04                  add     esp, 4
00401E98  |.  B9 FFFFFFFF              mov     ecx, -1
00401E9D  |.  A3 FCBE4000              mov     dword ptr [40BEFC], eax                           ;  保存 0x0019FA74,实际是一个地址指针,不是注册表的 FirstInstallDateTime
00401EA2  |.  2BC0                     sub     eax, eax
00401EA4  |.  F2:AE                    repne   scas byte ptr es:[edi]
00401EA6  |.  F7D1                     not     ecx
00401EA8  |.  49                       dec     ecx                                               ;  前面timestamp字符串的长度
00401EA9  |.  68 B8A64000              push    0040A6B8                                          ;  ASCII "RegisteredOwner"
00401EAE  |.  68 CCA64000              push    0040A6CC                                          ;  ASCII "SOFTWARE\Microsoft\Windows\CurrentVersion"
00401EB3  |.  890D 80C34000            mov     dword ptr [40C380], ecx                           ;  保存时间字符串的长度
00401EB9  |.  68 02000080              push    80000002
00401EBE  |.  E8 EDF5FFFF              call    004014B0                                          ;  读注册表

问题出在调用 sprintf() 这个函数的参数,因为 Call 004014B0 这个函数读取注册表信息后,返回的是一个地址,而 sprintf()中,引用的是这个地址,所以转换成字符串也是一个地址值,不是真正的 FirstInstallDateTime的值,如果要修改这个 Bug,可以进行以下修改,如下图所示:



将 0x00401E6D处的 add esp, 0C 改成 mov eax, [eax],然后在下面 0x00401E83 处的 add esp, 0C 改成 add esp, 18,这样堆栈也平衡了,Bug也消除了。

基本的注册验证过程分析到这里,用注册机生成注册码,并抓紧时间输入(粘贴),校验正确时,显示如下:



一定要注意时间,最好在当分钟的前 0~30秒内生成序列号,后30秒来输入注册码并验证,不然可能序列号就过期了。

另外,在 Windows 10 之类的新版 Windows 下,缺少注册表项,需要导入以下信息,不然也通不过注册验证,64位系统如下:
[HTML] 纯文本查看 复制代码

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion]
"FirstInstallDateTime"=hex:c1,b1,98,4c
"RegisteredOrganization"="ite"
"RegisteredOwner"="solly"
"ProductId"="51163-030-0389753-07447"

32位系统如下:
[HTML] 纯文本查看 复制代码

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion]
"FirstInstallDateTime"=hex:c1,b1,98,4c
"RegisteredOrganization"="ite"
"RegisteredOwner"="solly"
"ProductId"="51163-030-0389753-07447"

当然,键值可以改成自己的,键名不能改动。

分析完毕,下面是注册机源码,使用 Dev-C++调试通过:
[Asm] 纯文本查看 复制代码

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <windows.h>

union CBData{
        DWORD n;
        byte buffer[256];
};

CBData readKey(HKEY hKey, char * path, char * key);
void getRegInfo();
void getPart1();
void getPart2();
long getRegTimeStamp(int index);
long getCheckRegOwner();
long getCheck(char * name, char * company, int index); 
void getCurrDateTime(int index);

bool testSoftICE95();
bool testSoftICENT();

char sn[48];
CBData data;
long nFirstInstallDateTime = 0;
long nLenOfFirstInstallDateTime = 0;
char sFirstInstallDateTime[128];
char RegisteredOwner[128];
char RegisteredOrganization[128];
char ProductId[128];

int main(int argc, char** argv) {
        memset(sn, 0, 48);
        memset(sFirstInstallDateTime, 0, 128);
        memset(RegisteredOwner, 0, 128);
        memset(RegisteredOrganization, 0, 128);
        memset(ProductId, 0, 128);
        
        getRegInfo();
        
        getPart1();
        sn[5] = '-';

        getPart2();
        sn[10] = '-';
        
        char name[]    = "solly88";
        char company[] = "ite company";
        int n = getCheck(name, company, 11);

    sn[10+n+1] = '-';

        int m = getRegTimeStamp(10+n+2); 
        
        sn[10+n+2+m] = '-';
        
        /// 最后4字节为当前时间检查 
        getCurrDateTime(10+n+3+m);
        
        printf("\n SN = %s\n", sn);
        
        return 0;
}

void getPart1() {
    sn[1] = 0x0D ^ 0x49;
    sn[2] = 0x07 ^ 0x44;
    sn[3] = 0x0D ^ 0x39;
    sn[0] = 0x1D ^ 0x54;
    sn[4] = 0x09 ^ 0x39;
} 

void getPart2() {
        sn[7] = 0x06 ^ 0x52;
        sn[8] = 0x07 ^ 0x45;
        sn[9] = 0x1F ^ 0x53;
        sn[6] = 0x11 ^ 0x54;
}

/**

***/
/// FirstInstallTime 
long getRegTimeStamp(int index) {
        /// 0040BF90:  1702516
    //long a = 1702505;
    ////
    //long FirstInstallDateTime = 1702516; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win10
    //long FirstInstallDateTime = 6617404; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win98
    //long FirstInstallDateTime = 6682940; /// 实际上是一个指向保存FirstInstallDateTime的内存地址 Win98_unpacked
    long FirstInstallDateTime = nFirstInstallDateTime; /// 正常时是一个 Timestamp 
    
    long a = FirstInstallDateTime - tanh(FirstInstallDateTime) * 11.0; /// 固定值 1702505 
             
    //char str_a[8];
    sprintf(sFirstInstallDateTime, "%d", a);
    long n = strlen(sFirstInstallDateTime);
    for(int i=0; i<n; i++ ) {
            sn[index + i] = sFirstInstallDateTime[i];
        }
        
        return n;
}

long getCheckRegOwner() {  // Proc_00401590 和 Proc_00401540 
        long sum1 = 0;
        long sum2 = 0;
        long n = strlen(RegisteredOwner);
        for(int i=1; i<n; i++) {
                sum1 += i*2;
                sum2 += RegisteredOwner[i-1];
        }
        //printf("check reg owner: %d - %d\n", sum1, sum2);
        
        return sum1 ^ sum2;
}

long getCheck(char * name, char * company, int index) {  /// Proc_004015E0

        long checkbase = getCheckRegOwner();
        
        long sum = 0;
        int n = strlen(name);
        for(int i=0; i<n-1; i++) {
                sum += name[i] * 2601;
        }
        int m = strlen(company);
        for(int i=0; i<m-1; i++) {
                sum += company[i];
        }
        
        double x = sum * 11;
        int code1 = (long)sqrt(x);
        ////
        //printf("check code1: %d, %d\n", sum, code1);
        long a = code1 + checkbase;
        long c = a * 111998;
        double y = c - sin(c) * 1999.0;
        long code2 = (long)y;
        
        //printf("check code2: %d\n", code2);
        char code_str[12];
        sprintf(code_str, "%d", code2);
        int len = strlen(code_str);
        for(int i=0; i<len; i++) {
                sn[index+i] = code_str[i];
        }
        
        return len;
}

bool testSoftICE95() {
        HANDLE h = CreateFile("\\\\.\\SICE", 
                              GENERIC_READ|GENERIC_WRITE, 
                                                  FILE_SHARE_READ|FILE_SHARE_WRITE, 
                                                  NULL, OPEN_EXISTING, 
                                                  FILE_ATTRIBUTE_NORMAL, NULL);
        if(h != INVALID_HANDLE_VALUE) {
                CloseHandle(h);
                return true;
        }
        
        return false;
} 

bool testSoftICENT() {
        HANDLE h = CreateFile("\\\\.\\NTICE", 
                              GENERIC_READ|GENERIC_WRITE, 
                                                  FILE_SHARE_READ|FILE_SHARE_WRITE, 
                                                  NULL, OPEN_EXISTING, 
                                                  FILE_ATTRIBUTE_NORMAL, NULL);
        if(h != INVALID_HANDLE_VALUE) {
                CloseHandle(h);
                return true;
        }
        
        return false;
} 

/// Current date and time
void getCurrDateTime(int index) {
        long a = RegisteredOwner[0];
        time_t timer;
        struct tm * st;
        time(&timer);
        st = localtime(&timer);
        long t = (st->tm_year + 1900) + ((st->tm_mon + 1) * st->tm_mday - a) + st->tm_hour * st->tm_min; 
        
        ///// SoftICE 检查,修正时间检查值(基本无用) 
        bool isExistsSICE95 = testSoftICE95();
        bool isExistsSICENT = testSoftICENT();
        
        if (isExistsSICE95) {
                t += 0x143;
        }
        if (isExistsSICENT) {
                t += 0x271;
        }

        char str_t[12];
        itoa(t, str_t, 10);
        sn[index] = str_t[0];
        sn[index+1] = str_t[1]; 
        sn[index+2] = str_t[2]; 
        sn[index+3] = str_t[3]; 
        ///
        //printf("time: %d-%d-%d %d:%d\n", st->tm_year+1900, st->tm_mon+1, st->tm_mday, st->tm_hour, st->tm_min)        ;
}

CBData readKey(HKEY hKey, char * path, char * key) {
        HKEY h = (HKEY)-1; 
    DWORD cbData;
        DWORD regType = -1;

        data.n = 1;
        
        long s = RegOpenKeyEx(hKey, path, 0, KEY_READ, &h);
        if( s != ERROR_SUCCESS) {
                data.n = -1;
                return data;
        }
        
        s = RegQueryValueEx(h, key, NULL, NULL, NULL, &cbData);
        if(s == ERROR_SUCCESS) {
                RegQueryValueEx(h, key, NULL, &reg;Type, data.buffer, &cbData);
        }
        
        RegCloseKey(h);
        
        return data; 
}

void getRegInfo() {
        char subKey[] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion";
        char key1[] = "FirstInstallDateTime";
        char key2[] = "RegisteredOwner";
        char key3[] = "RegisteredOrganization";
        char key4[] = "ProductId";
        CBData cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key1);
        nFirstInstallDateTime = cb.n;
        struct tm * tm_reg = localtime((time_t *)&nFirstInstallDateTime);
        sprintf(sFirstInstallDateTime, "%lu", nFirstInstallDateTime);
        nLenOfFirstInstallDateTime = strlen(sFirstInstallDateTime);
        printf(" DateTime: %d-%d-%d %d:%d:%d\n", tm_reg->tm_year + 1900, tm_reg->tm_mon + 1, 
                                tm_reg->tm_mday, tm_reg->tm_hour, tm_reg->tm_min, tm_reg->tm_sec);
        printf("Timestamp: %d,  len=%d\n", nFirstInstallDateTime, nLenOfFirstInstallDateTime);
        ////
        cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key2);
        strcpy(RegisteredOwner, (char *)cb.buffer);
        ////
        cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key3);
        strcpy(RegisteredOrganization, (char *)cb.buffer);
        ////
        cb = (CBData)readKey(HKEY_LOCAL_MACHINE, subKey, key4);
        strcpy(ProductId, (char *)cb.buffer);
        
        printf("             ProductId: %s\n", ProductId);
        printf("       RegisteredOwner: %s\n", RegisteredOwner);
        printf("RegisteredOrganization: %s\n", RegisteredOrganization);
}

THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发
  • 管埋员的头像-小北的自留地

    昵称

  • 取消
    昵称