吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|www.mlqcje.live

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 6562|回復: 25
上一主題 下一主題

[原創] 160 個 CrackMe 之 126 - NZC.1 手動脫殼和注冊算法追蹤及注冊機實現

  [復制鏈接]
跳轉到指定樓層
樓主
solly 發表于 2019-5-29 15:13 回帖獎勵
本帖最后由 solly 于 2019-5-29 23:47 編輯

160 個 CrackMe 之 126 - NZC.1 手動脫殼和注冊算法追蹤及注冊機實現
CrackMe集合中的第126個 NZC.1 在 Windows 10 下是無法直接運行的,但在OD中可以載入,表示其可以在Windows10下運行,只是運行時執行了非法的指令(或訪問了無效的內存),一般這些指令都是由那些老掉牙的AntiDebug檢查用的,主要是針對SoftICE檢查,直接執行了 int 68,int 3 等指令。
首先,我們檢查一下軟件殼。

顯示有未知的殼。節的情況如下:

最后有一個 .defiler 的節,Defiler有掩蔽, 遮蔽之意,看來這個節就是殼了。


因為殼是未知的,只有手動脫殼,下面進行手動脫過程的講解,內容有點長,有點長,有點長,截圖就有50多個。


首先用OD載入 NZC.1.exe,入口第1條指令就是一個跳轉指令,如下圖,而且代碼看起來也很亂,還有無效指令,如下圖:


先不要運行,按回車跟隨,來到下一條指令,如下圖:

看到第2條執行的指令碼為”EB 02“,也就是一條 JMP 指令,但跳轉位置是在另一指令中間,并且上圖中有好幾個 "EB 02" 指令碼及顯示無效的指令,這些都符合”花指令“特征,因此,我們先處理這些花指令,便于我們后面的分析。
按”-“號,回退到程序入口,如下圖:

點擊“右鍵”,選擇菜單項“去除花指令”=>“ObSiDiUm”,也就是子菜單的第1項,執行完后,彈出對話框,告訴我們去除了多少花指令:

去除花指令后,代碼界面一下子多出了好多的 “NOP” 指令,有效指令一下子少了很多,如下圖:


因為默認情況,直接執行去除花指令的操作只處理 0x400個字節內的花指令,并沒有掃描全部代碼,我們手動拖動滾動條來到0x0040D400處,果然沒有處理完畢,還有一些花指令:

再次在這里("0x0040D400“)右鍵菜單執行一次前面的操作,這次又去除了  41 條花指令:

去除花指令的步驟先到此暫停,后面還有去除花指令的操作,不過現在無法執行,因為那些代碼還是加密的,如下圖所示,在沒解密前也去不了花指令了:




現在我們開始跟蹤CM的殼代碼。


再次回到原點,如下圖:

按幾次F8,慢點按,按快了就可能要重新來一次了。
來到下圖位置:

這里有一個常用的手法,就是 call 下一條代碼(指令碼為 E8 00000000),然后一個 pop 指令將返回地址取出來,這個就是用來取得指令區的當前執行指令的地址的,這里相當于取得  0x0040D246這個地址,并存放到 EBP 中了,所以執行這樣的 call 調用時,一定要按F7進入,因為這個call是不會返回來了的。
F7進入后,再按F8往下走,來到這里:


來到這個指令位置 0x0040D25B call 0x0040D100,不了解功能,只有按F7跟蹤進去,在進去前,先在這個call的下一條指令上按F2下一個中斷,防止不小心按了F9返回時沒停下來(后面有些進入call的情況也可以這樣處理),返回來后再禁用或取消這個斷點。

進入后又是一個調用,老辦法,再次按 F7 進入調用,仔細看,其實就是調用了后面10個字節后的指令。


這個調用功能很簡單,就是尋找系統庫 Kernel32.dll 文件在內存中位置,這個位置也就是該dll的 hInstance,后面的代碼需要用到這個 hInstance。
因為 Windows 加載程序或dll一般都是按 0x10000 大小對齊內存的,所以只要找到一個庫中的地址,這里是在棧中讀取的用于返回  KERNEL32.BaseThreadInitThunk 的地址,并去掉低16位,形成 0x75460000的對齊地址,以此為基礎,尋找 Kernel32.dll在內存中的存放位置,并取得 hInstance。同時,這兩次call調用是利用同一個 retn 指令返回去的。
這兩層 call 調用代碼很短,幾個F8后就找到hInstance并返回了,再次F8往下走,來到第1個解碼代碼處:


這里是對數據區的字符串資源進行解碼,定位到JNZ指令的下一條指令,按F4執行解碼循環,解碼結果如下:


解碼出來的是一些API函數名和庫名。后面要用到這些名字,取得API的的入口地址,下面是關鍵代碼和數據變化情況:
[Asm] 純文本查看 復制代碼
解碼數據1:
0040D29E    B9 66000000         mov     ecx, 66                                                        ; 開始數據解碼,API函數庫和函數名等字符串數據
0040D2A3    8D9D F8284000       lea     ebx, dword ptr [ebp+4028F8]                                    ; ebx == 0x0040D8CC, EBX ==>解碼開始位置
0040D2A9    300B                xor     byte ptr [ebx], cl                                             ; CL == 0x66
0040D2AB    8003 40             add     byte ptr [ebx], 40
0040D2AE    43                  inc     ebx
0040D2AF    49                  dec     ecx
0040D2B0    85C9                test    ecx, ecx                                                       ; ecx=0x66,長度為  0x66字節
0040D2B2  ^ 75 F5               jnz     short 0040D2A9

解碼前:
0040D8CC  61 40 50 73 50 4E 43 5E 7A 79 6E 7E 69 6A 98 48  [email protected]^zyn~ij楬
0040D8DC  7A 7A 64 76 7C 91 5C 60 6F 69 40 62 68 7B 69 75  zzdv|慲[email protected]{iu
0040D8EC  7F 44 84 4E 67 72 73 1E 19 18 3E 14 02 38 F8 32  D凬grs>8?
0040D8FC  0E 1C 00 23 00 1E 13 0A 1D 1E EC 38 0F 1D 3C 0E  .#..?<
0040D90C  0B 00 16 E3 30 04 01 3B 0E 2F 33 38 3F 2A 2B 1A  .?;/38?*+
0040D91C  33 38 3B 21 2B D1 05 3C 2B 3F FF F9 CA 02 2D 35  38;!+?<+??-5
0040D92C  28 20 28 F0 F0 C1                                ( (痧?.
解碼后:
0040D8CC  47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 5F  GetProcAddress._
0040D8DC  6C 6F 70 65 6E 00 4C 6F 61 64 4C 69 62 72 61 72  lopen.LoadLibrar
0040D8EC  79 41 00 4D 65 73 73 61 67 65 42 6F 78 41 00 45  yA.MessageBoxA.E
0040D8FC  78 69 74 50 72 6F 63 65 73 73 00 53 65 74 54 69  xitProcess.SetTi
0040D90C  6D 65 72 00 52 65 61 64 50 72 6F 63 65 73 73 4D  mer.ReadProcessM
0040D91C  65 6D 6F 72 79 00 55 73 65 72 33 32 00 4B 65 72  emory.User32.Ker
0040D92C  6E 65 6C 33 32 00                                nel32.

將API解碼出來后,下一步是尋找這些API的入口地址了,一路F8來到 0x0040D2E3 ,如下圖:

來到  0x0040D2E3后,又是一個 call 調用,我們按  F7 跟進去,并F8來到下面:


這一段代碼的主要功能就是在 Kernel32.dll 中的導出表中的函數名列表中尋找 LoadLibraryA()函數名,并計算得到其入口地址。這里會用前面尋到 kernel32 的 hInstance,并會對其進行PE文件格式判斷,然后遍歷導出表中的函數名列表,找到需要的函數并計算該函數的入口地址,代碼如下,我把花指令的NOP去掉了,所以指令地址不是連續的了:
[Asm] 純文本查看 復制代碼
0040D005    90                    nop                                                ; Get_API_Address Proc
0040D009    58                    pop     eax
0040D00E    5B                    pop     ebx
0040D013    5F                    pop     edi
0040D019    59                    pop     ecx
0040D01E    50                    push    eax
0040D024    8BD3                  mov     edx, ebx                                   ; ebx == hInstance
0040D02A    66:813B 4D5A          cmp     word ptr [ebx], 5A4D                       ; 'MZ'
0040D033    0F85 C4000000         jnz     0040D0FD
0040D03E    0FB743 3C             movzx   eax, word ptr [ebx+3C]
0040D046    03D8                  add     ebx, eax
0040D04D    66:813B 5045          cmp     word ptr [ebx], 4550                       ; 'PE'
0040D056    0F85 A1000000         jnz     0040D0FD
0040D060    8B5B 78               mov     ebx, dword ptr [ebx+78]
0040D067    03DA                  add     ebx, edx                                   ; edx=0x756D0000,Kernel32.dll的hInstance
0040D06D    0BFF                  or      edi, edi                                   ; EDI ===> "LoadLibraryA", "GetProcAddress"
0040D073    74 78                 je      short 0040D0ED
0040D079    8B73 20               mov     esi, dword ptr [ebx+20]
0040D080    03F2                  add     esi, edx
0040D086    8B4B 18               mov     ecx, dword ptr [ebx+18]                    ; ecx == 0x643
0040D08D    53                    push    ebx
0040D092    33DB                  xor     ebx, ebx
0040D094    90                    nop                                                ; 循環開始位置
0040D098    AD                    lods    dword ptr [esi]                            ; eax ===> 內存區緩沖區,全0
0040D09D    03C2                  add     eax, edx                                   ; eax == 7576B1F2, EAX ==>"AcquireSRWLockExclusive"
0040D0A3    56                    push    esi
0040D0A4    57                    push    edi
0040D0A9    87FE                  xchg    esi, edi                                   ; ESI ===> "LoadLibraryA", "GetProcAddress"
0040D0AF    97                    xchg    eax, edi                                   ; EDI ===> "AcquireSRWLockExclusive"
0040D0B4    AC                    lods    byte ptr [esi]                             ; al = 0x4C, "LoadLibraryA"的第1個字母的ASCII碼值
0040D0B9    0AC0                  or      al, al                                     ; 檢查導入表是否結束
0040D0C0    75 0B                 jnz     short 0040D0CD
0040D0C2    90                    nop
0040D0C6    803F 00               cmp     byte ptr [edi], 0
0040D0C9    74 0B                 je      short 0040D0D6
0040D0CB    EB 07                 jmp     short 0040D0D4
0040D0CD    3807                  cmp     byte ptr [edi], al                         ; 檢查 [edi] 是否等于 al == 'L', 查找 LoadLibraryA 的位置
0040D0CF    75 03                 jnz     short 0040D0D4
0040D0D1    47                    inc     edi
0040D0D2  ^ EB DC                 jmp     short 0040D0B0                             ; 循環比較字符串是否"LoadLibraryA"
0040D0D4    B0 01                 mov     al, 1
0040D0D6    5F                    pop     edi
0040D0D7    5E                    pop     esi
0040D0D8    0AC0                  or      al, al
0040D0DA    74 06                 je      short 0040D0E2                             ; al=0則中斷循環,表示找到了"LoadLibraryA"
0040D0DC    43                    inc     ebx
0040D0DD  ^ E2 B5                 loopd   short 0040D094                             ; 循環結束位置
0040D0DF    5B                    pop     ebx
0040D0E0    EB 1B                 jmp     short 0040D0FD
0040D0E2    93                    xchg    eax, ebx                                   ; 循環中斷跳出到這里,計算LoadLibraryA的入口地址
0040D0E3    5B                    pop     ebx
0040D0E4    8B73 24               mov     esi, dword ptr [ebx+24]
0040D0E7    03F2                  add     esi, edx
0040D0E9    0FB70C46              movzx   ecx, word ptr [esi+eax*2]
0040D0ED    2B4B 10               sub     ecx, dword ptr [ebx+10]
0040D0F0    8B73 1C               mov     esi, dword ptr [ebx+1C]
0040D0F3    03F2                  add     esi, edx
0040D0F5    91                    xchg    eax, ecx
0040D0F6    8B4486 04             mov     eax, dword ptr [esi+eax*4+4]
0040D0FA    03C2                  add     eax, edx                                   ; eax == LoadLibraryA的入口地址
0040D0FC    C3                    retn                                               ; Get_API_Address Proc 結束
0040D0FD    33C0                  xor     eax, eax
0040D0FF    C3                    retn                                               ; Get_API_Address Proc 結束


代碼執行完后,會將 LoadLibraryA()函數的入口地址置于 EAX 中并返回,如果沒有找到該函數,EAX=0。

從函數返回后,取得了 Kernel32.LoadLibraryA()的入口,然后通過調用 LoadLibraryA("User32"),取得 User32.dll的 hInstance,如下圖所示。

然后,再次調用該函數:LoadLibraryA("Kernel32"),取得 Kernel32 的 hInstance,不過這個好象有點多余了,前面已經取得了這個 hInstance 了。


上面取得的 hInstance 與前面 0x0040D25B call 0x0040D100 取得的 hInstance 是一樣的。
再次幾個  F8,來到0x0040D369,這里再次調用 call 0x0040D005,這次是從 User32 中取 GetProcAddress() 函數的地址了,如下圖:

取得 GetProcAddress()的入口地址后,通過與LoadLibraryA()得到的 hInstance 配合,就可以得到其它幾個函數(如 MessageBoxA(), ExitProcess(), SetTimer(), ReadProcessMemory(), _lopen() 等幾個函數)的入口地址了,這一段代碼比較長,多按 F8 向下走:


取得這些系統 API 調用的入口后,再F8向下走,來到 0x0040D472,就可以看到程序將調用 SetTimer()函數設置一個定時器(我們需要跳過這段代碼的執行,減少調試時的干擾)這時可以看到還有4個push 指令,這些指令也不要執行,如下圖:


通過在OD中改變EIP的值就可以跳過定時器的調用,如下:



那幾個給 SetTimer() 設置參數的 Push 指令也要跳過,我們在 0x0040D493 的位置點擊右鍵,選擇“此處為新 EIP”就可以跳過 SetTimer()函數的調用。
點擊后,OD會彈出一個提示對話框,選擇“是(Y)”即可,如下所示:

跳過定時器后,按 F8 來到 0x0040D4AE 處,如下圖,這是一段解碼程序,這里一共有三個解碼循環,第1個也是解碼字符串資源,第2、3個是解碼代碼:

第1段代碼如下,去掉了無用的  NOP 指令,因此指令地址不連續了:
[Asm] 純文本查看 復制代碼
0040D497    8D9D 78284000         lea     ebx, dword ptr [ebp+402878]                ; ebx = 0x0040D84C,開始第2次數據解碼,解碼反SoftICE調試字符串等
0040D4A2    8D8D CB284000         lea     ecx, dword ptr [ebp+4028CB]                ; ecx = 0x0040D89F
0040D4AC    2BCB                  sub     ecx, ebx                                   ; 長度 0x53 字節, 解碼數據
0040D4AE    90                    nop                                                ; 循環開始
0040D4B2    8033 64               xor     byte ptr [ebx], 64
0040D4B9    8003 65               add     byte ptr [ebx], 65
0040D4C0    C003 66               rol     byte ptr [ebx], 66
0040D4C8    43                    inc     ebx
0040D4CD  ^ E2 DF                 loopd   short 0040D4AE;
解碼前:
0040D84C  37 A1 33 23 23 23 33 23 23 27 23 23 23 27 23 FF  7?###3##'###'#?
0040D85C  01 45 40 DF DF 3A CC 3C 48 54 CC 00 E4 38 08 7F  [email protected]哌:?HT??
0040D86C  40 E4 7F 48 54 50 24 28 54 00 37 FF B0 3C 54 7B  @?HTP$(T.7??T{
0040D87C  7F B4 44 4C 58 7F 54 00 0C 34 44 7F 8C 3C 50 08  碊LXT..4D?P
0040D88C  A4 CC D4 7F 1C 54 4C 58 7B FF 68 68 37 68 8C A4  ぬ?TLX{?hh7h尋
0040D89C  CC D4 FF 
解碼后:
0040D84C  2E 8A 2F 2B 2B 2B 2F 2B 2B 2A 2B 2B 2B 2A 2B 00  .?+++/++*+++*+.
0040D85C  B2 A1 62 08 08 F0 43 6F 64 65 43 72 79 70 74 20  病b餋odeCrypt
0040D86C  62 79 20 64 65 66 69 6C 65 72 2E 00 4E 6F 65 21  by defiler..Noe!
0040D87C  20 4D 61 63 68 20 65 72 73 6D 61 20 53 6F 66 74   Mach ersma Soft
0040D88C  49 43 45 20 77 65 63 68 21 00 5C 5C 2E 5C 53 49  ICE wech!.\\.\SI
0040D89C  43 45 00                                         CE.


然后就是2段代碼解碼的循環,第1段如下所示,去掉了無用的“NOP”指令:
[Asm] 純文本查看 復制代碼
0040D4CF    B9 78284000           mov     ecx, 00402878                              ; ASCII "rr"
0040D4D8    B8 7C254000           mov     eax, 0040257C
0040D4E1    2BC8                  sub     ecx, eax                                   ; 長度 0x2FC和 可變密鑰2,兩層功能
0040D4E7    8D9D 7C254000         lea     ebx, dword ptr [ebp+40257C]                ; ebx = 0x0040D550,指向解碼代碼的一個Proc,不過這個Proc需要先解碼
0040D4F1    8A95 EB284000         mov     dl, byte ptr [ebp+4028EB]                  ; ss:[0040D8BF] == 0xB4,解碼密鑰1
0040D4FC    90                    nop                                                ; 代碼解碼循環1開始
0040D501    3013                  xor     byte ptr [ebx], dl                         ; 解碼1,固定密鑰, dl = 0xB4
0040D508    300B                  xor     byte ptr [ebx], cl                         ; 解碼2, 可變密鑰, ecx=0x2D9, 0x2D8
0040D50E    43                    inc     ebx
0040D513    49                    dec     ecx
0040D518    85C9                  test    ecx, ecx
0040D51E  ^ 75 DC                 jnz     short 0040D4FC                             ; 代碼解碼循環1結束

第2段,也去掉了無用的"NOP"指令了:
[Asm] 純文本查看 復制代碼
0040D524    B9 78284000           mov     ecx, 00402878                              ; ASCII "rr"
0040D52D    B8 7C254000           mov     eax, 0040257C
0040D536    2BC8                  sub     ecx, eax                                   ; ecx = 0x02FC, 解碼長度和可變密鑰
0040D53C    8D9D 8B254000         lea     ebx, dword ptr [ebp+40258B]                ; ebx = 0x0040D55F, 第2個代碼解碼的開始地址
0040D546    8A95 88284000         mov     dl, byte ptr [ebp+402888]                  ; dl = 0xB2, 固定密鑰
0040D550    C00B 04               ror     byte ptr [ebx], 4
0040D553    3013                  xor     byte ptr [ebx], dl
0040D555    43                    inc     ebx
0040D556    49                    dec     ecx
0040D557    85C9                  test    ecx, ecx
0040D559  ^ 75 F5                 jnz     short 0040D550                             ; 解碼完成后,再次去花指令(開始位置:0x0040D55B,長度:0x0300,93個)

運行到 0x0040D55B 后(我們可以在 0x0040D55B 處選中該行,按 F4 直接運行到這里),如下圖:

這個時候,我們又看到一堆“EB 02”指令了,這是代碼解碼后,花指令也解碼出來了,前面去花指令并不會把這些加密的花指令去掉,所以我們再進行一次去花指令的操作,這次不要在右鍵菜單上操作,因為那個默認長度是 0x400,可能會超出本節的內存范圍,導致  OD 都會被操作系統關閉。所以,我們要從主菜單的“插件”菜單中來調用去花指令的功能:

如上圖所示,選擇“去除花指令”,會彈出一個對話框:

我們在上面填好開始地址和長度,長度的計算:由前面節信息可知為0x932字節,減去開始地址:0x55B,為0x3D7,由于后面還會有一些變量的空間或無用空間,我們只取0x300試試。
點“確定”,完成花指令的去除:

又干掉了一批花指令,一下子代碼又變得清新了:

可以看到一個 INT 68 指令,就是這個指令,導致其不能在 Windows NT 系列的系統上運行,執行到這里就會被關閉,所以我們也要跳過這個指令,如下所示:

我們執行到 0x0040D56F,給 ah 賦值后就可以了,然后跳過 INT 68 指令,由于 ECX 不為 0,下面這幾個對 ecx 的檢測和跳轉指令也不用執行了:

直接來到 0x0040D59A 處,設置為新的 EIP,如下所示:

由于 ah 前面賦值為 0x43,也就不會等于 0xF386了,如下所示,跳轉會成功:


這段指令整理后如下,是一個循環執行 int 68 指令的代碼。

[Asm] 純文本查看 復制代碼
0040D564    B9 FFFF0100           mov     ecx, 1FFFF                                 ; 調用 int 68 次數
0040D569    90                    nop                                                ; 開始循環檢測
0040D56D    B4 43                 mov     ah, 43                                     ; 功能號
0040D572    90                    nop
0040D573    CD 68                 int     68                                         ; 中斷調用,檢測 SoftICE 是否加載,對 OD 沒有用,但會引起NT內核系統關閉CM。
0040D575    90                    nop
0040D579    49                    dec     ecx
0040D57F    85C9                  test    ecx, ecx
0040D585  ^ 75 E2                 jnz     short 0040D569                             ; 循環調用 int 68
0040D58C    85C9                  test    ecx, ecx
0040D592    0F85 96020000         jnz     0040D82E                                   ; 跳轉到錯誤地址去了
0040D59C    66:3D 86F3            cmp     ax, 0F386                                  ; 如果 SoftICE 在運行,int 68調用將把 ax 設值為 0xF386
0040D5A5    0F85 97000000         jnz     0040D642                                   ; 如果沒有檢測到SoftICE, 就開始跳轉去解碼原始代碼了。
0040D5AB    90                    nop

如果上面代碼最后沒有跳轉,就會去執行一段覆蓋CM殼代碼的操作代碼,以及顯示一個失敗對話框。代碼如下:
[Asm] 純文本查看 復制代碼
0040D5AF    C785 84284000 22000000   mov     dword ptr [ebp+402884], 22
0040D5BE    8DBD 6E264000            lea     edi, dword ptr [ebp+40266E]                ; edi == 0x0040D642
0040D5C8    B9 FF000000              mov     ecx, 0FF                                   ; exc 為循環次數
0040D5D1    F2:AA                    repne   stos byte ptr es:[edi]                     ; 覆蓋代碼區內容,清成 AL 中的值, 直到 ecx 變為 0
0040D5D7    B9 D7254000              mov     ecx, 004025D7
0040D5E0    BB 95254000              mov     ebx, 00402595
0040D5EA    2BCB                     sub     ecx, ebx                                   ; exc 為循環次數
0040D5F0    8DBD 95254000            lea     edi, dword ptr [ebp+402595]                ; edi ===> 0x0040D5F6
0040D5FA    F2:AA                    repne   stos byte ptr es:[edi]                     ; 覆蓋代碼區內容,清成 AL 中的值, 直到 ecx 變為 0
0040D5FF    90                       nop
0040D600    8D8D A4284000            lea     ecx, dword ptr [ebp+4028A4]                ; ecx ==> "Noe! Mach ersma SoftICE wech!"
0040D60A    8D9D 8E284000            lea     ebx, dword ptr [ebp+40288E]                ; ebx ==> "CodeCrypt by defiler."
0040D614    6A 30                    push    30                                         ; 顯示信息
0040D61B    53                       push    ebx
0040D620    51                       push    ecx
0040D626    6A 00                    push    0
0040D62C    FF95 D3284000            call    dword ptr [ebp+4028D3]                     ; call MessageBoxA
0040D636    FF95 D7284000            call    dword ptr [ebp+4028D7]                     ; ExitProcess
0040D640    33ED                     xor     ebp, ebp                                   ; 清0了本地變量基址指針

由于ah=0x43,AX != 0xF386,不會執行上面的代碼,我們成功跳轉到了新的解碼代碼,來到 0x0040D642,如下圖所示:

這里是對CM的原有代碼進行解密,多次解密后,就會跳轉到 OEP,準備執行 CM 原有的程序代碼,到這個時候也可以脫殼了。
下面具體説明,下圖是對原始代碼進行第1次解密,如下所示:

第1次解密后,還有一次對  SoftICE 的檢查,就是通過打開"\\\\.\\SICE"文件句柄來實現的,如下圖所示。


不過我們用的是OD,這個檢查無效,我們可以執行,并且能夠完成檢查也不會引起異常。

接下來是第2次對原有代碼進行重復解密運算,如下圖所示:


搞完2次解密后,原始代碼還沒有出來,這個時候,CM殼又對整個殼代碼進行了一次8位"校驗和"的運算處理,如下圖:


按常理來説,這個校驗是包括了花指令在內的校驗運算,不過,經過測試,去除花指令后的“校驗和”與沒有去除花指令的“校驗和”是一樣的,都是0x98。后來觀察,有些花指令中間無用數據并不一樣,有幾個是不同的,可能是作者調整了的。。。。降低點工作量(不過我在帶花指令的情況也試了下,確實是一樣的“校驗和”)。
“校驗和”計算完后,來到下面:

CM殼并不對”校驗和“進行檢查,直接保存到內存變量,為什么呢,因為,還要用這個”校驗和“對原始代碼繼續進行解碼操作,沒錯,用這個”校驗和“作為密鑰來解碼代碼,如下圖,dl中就是這個”校驗和“的值:

上面一波解碼操作完成后,才正式完成殼的全部解碼功能,可以看到原始未加密的代碼了:

以及原始代碼的入口,即OEP了,到這個時候,殼終于脫掉了:

上面這一波操作的殼代碼如下,去掉了無用的“NOP"指令:
[Asm] 純文本查看 復制代碼
0040D642    8B8D 84284000            mov     ecx, dword ptr [ebp+402884]                ; ecx == 0x00001000,開始解碼非殼代碼
0040D64D    8B85 7C284000            mov     eax, dword ptr [ebp+40287C]                ; eax == 0x00400000
0040D657    0385 80284000            add     eax, dword ptr [ebp+402880]                ; eax == 00401000, 指向非殼代碼區
0040D661    8BD8                     mov     ebx, eax                                   ; ebx == eax == 0x00401000
0040D668    66:51                    push    cx                                         ; 開始第1次循環解碼非殼代碼,字節數:ecx == 0x1000
0040D66A    8A8D 8D284000            mov     cl, byte ptr [ebp+40288D]                  ; cl == 0xF0, key
0040D670    000B                     add     byte ptr [ebx], cl                         ; 解碼1
0040D677    D20B                     ror     byte ptr [ebx], cl                         ; 解碼2
0040D679    66:59                    pop     cx
0040D67F    43                       inc     ebx
0040D680  ^ E2 E6                    loopd   short 0040D668
0040D686    9C                       pushfd
0040D68C    58                       pop     eax                                        ; eax = flag register == 0x0216
0040D691    F6C4 01                  test    ah, 1                                      ; ah == 0x02, 不等于 0x01
0040D698    0F85 90010000            jnz     0040D82E
0040D69E    8D8D C2284000            lea     ecx, dword ptr [ebp+4028C2]                ; ecx ===> "\\\\.\\SICE"
0040D6A8    6A 40                    push    40
0040D6AE    51                       push    ecx                                        ; ecx===>"\\\\.\\SICE"
0040D6B3    FF95 E3284000            call    dword ptr [ebp+4028E3]                     ; call _lopen("\\\\.\\SICE"),檢查 SoftICE 是否運行
0040D6BD    83F8 FF                  cmp     eax, -1                                    ; eax == 0xFFFFFFFF,表示 SoftICE 沒有運行
0040D6C4  ^ 0F85 E1FEFFFF            jnz     0040D5AB                                   ; 不等-1表示SICE在運行,跳去破壞代碼、顯示消息并退出
0040D6CF    8B8D 84284000            mov     ecx, dword ptr [ebp+402884]                ; ecx == 0x00010000, 解碼長度,開始第2次非殼代碼解碼
0040D6DA    8B85 7C284000            mov     eax, dword ptr [ebp+40287C]                ; eax == 0x00400000,基址
0040D6E4    0385 80284000            add     eax, dword ptr [ebp+402880]                ; eax == 0x00401000, 指向非殼代碼
0040D6EF    8BD8                     mov     ebx, eax                                   ; ebx = eax = 0x00401000, p
0040D6F5    8A95 88284000            mov     dl, byte ptr [ebp+402888]                  ; dl == 0xB2, key2
0040D6FF    33C0                     xor     eax, eax                                   ; key1=0
0040D705    FEC0                     inc     al                                         ; key1++
0040D70B    3003                     xor     byte ptr [ebx], al
0040D711    C00B 05                  ror     byte ptr [ebx], 5
0040D718    3013                     xor     byte ptr [ebx], dl
0040D71E    C003 07                  rol     byte ptr [ebx], 7
0040D725    43                       inc     ebx                                        ; p++
0040D72A    49                       dec     ecx                                        ; i--
0040D730    85C9                     test    ecx, ecx                                   ; i>0
0040D737  ^ 75 CC                    jnz     short 0040D705
0040D741    8B85 7C284000            mov     eax, dword ptr [ebp+40287C]                ; 基址(eax == 0x00400000),開始第3次非殼代碼解碼
0040D74B    0385 80284000            add     eax, dword ptr [ebp+402880]
0040D755    8BD8                     mov     ebx, eax                                   ; ebx == 0x00401000, p
0040D75B    8B03                     mov     eax, dword ptr [ebx]                       ; 讀取指令碼
0040D762    3985 89284000            cmp     dword ptr [ebp+402889], eax                ; [ebp+0x00402889] == 0x080862A1,檢查第2次解碼是否正確
0040D76C    0F85 BC000000            jnz     0040D82E                                   ; 相等則解碼正確
0040D777    33C0                     xor     eax, eax                                   ; checkSum = 0
0040D779    8D8D 78284000            lea     ecx, dword ptr [ebp+402878]                ; ecx == 0x0040D84C,OEP
0040D782    90                       nop                                                ; 下面是對殼代碼進行校驗和(checkSum)運算
0040D783    8D9D 2C204000            lea     ebx, dword ptr [ebp+<&MFC42.#3346_CWinThre>; ebx == 0x0040D000, 指向殼的入口地址,(ebp == 0x0000AFD4)
0040D789    2BCB                     sub     ecx, ebx                                   ; ecx == 0x0000084C, 循環次數
0040D78B    0203                     add     al, byte ptr [ebx]                         ; 循環對殼代碼字節進行求和,這個是對殼的修改校驗(因為去除花指令,求和后的值可能是錯的),也是下面解碼用的密鑰
0040D78D    43                       inc     ebx
0040D78E    49                       dec     ecx
0040D793    85C9                     test    ecx, ecx
0040D795  ^ 75 F4                    jnz     short 0040D78B
0040D79A    90                       nop
0040D79B    8885 EB284000            mov     byte ptr [ebp+4028EB], al                  ; al == 0x98,保存“校驗和”,因去除了花指令,該值不一定準確(后來驗證是正確的)
0040D7A1    8B8D 84284000            mov     ecx, dword ptr [ebp+402884]                ; ecx == 0x00010000,解碼長度
0040D7AC    8B85 7C284000            mov     eax, dword ptr [ebp+40287C]                ; eax == 0x00400000,基址
0040D7B6    0385 80284000            add     eax, dword ptr [ebp+402880]                ; eax == 0x00401000,解碼開始地址
0040D7C1    8BD8                     mov     ebx, eax                                   ; pointer p
0040D7C7    8A95 EB284000            mov     dl, byte ptr [ebp+4028EB]                  ; dl == 0x98, 解碼密鑰,也是前面求得的殼代碼的校驗和(checkSum)
0040D7D1    33C0                     xor     eax, eax                                   ; n = 0
0040D7D6    90                       nop
0040D7D7    FEC0                     inc     al                                         ; n++,開始循環解碼,第3次解碼
0040D7DD    D20B                     ror     byte ptr [ebx], cl                         ; cl, 可變密解(循環變量)
0040D7E4    3013                     xor     byte ptr [ebx], dl                         ; dl 為殼代碼的校驗和(checkSum)
0040D7EA    2813                     sub     byte ptr [ebx], dl                         ; dl 為殼代碼的校驗和(checkSum)
0040D7F0    43                       inc     ebx
0040D7F5    49                       dec     ecx
0040D7FB    85C9                     test    ecx, ecx
0040D802  ^ 75 D3                    jnz     short 0040D7D7
0040D804    90                       nop
0040D808    90                       nop                                                ; 全部解碼完成,準備轉去OEP
0040D809    8B85 78284000            mov     eax, dword ptr [ebp+402878]                ; eax = 0x00401A50, OEP
0040D817    5A                       pop     edx
0040D81C    59                       pop     ecx
0040D822    5B                       pop     ebx
0040D827    5D                       pop     ebp
0040D828    FFE0                     jmp     eax                                        ; goto OEP
0040D82A    90                       nop

下面,F8完 JMP EAX 后,我們正式進入 CM 的原始代碼區了,如下圖所示:


這個時候就可以開始脫殼了,如下圖所示,進行脫殼操作:

彈出脫殼對話框,全部默認設置,直接點擊”Dump“即可!


脫殼完成后,我們直接 F9 運行CM的代碼,由于跳過了int68指令,CM可以正常進入了,看到了親切的窗口界面:


還有一個就是對序列號的驗證了(上圖中水印太大,擋住了兩個按鈕,汗!!!)。

下面我們先找一下進行注冊碼驗證的代碼在哪里。
回到OD界面,看一下代碼,這個CM是VC+MFC框架編寫的,可以看到大量 MFC 對象的操作代碼。
最早做過MFC4~6版本下應用開發的應該知道,那個時候MFC是通過事件和成員變量的映射來處理消息的,映射好界面控件和成員變量之間的關系后,只要執行 MFC 框架的 CWnd::UpdateData()就可以將界面中輸入的值,自動賦給前面映射的成員變量,所以,我們先找找這個 UpdateData()函數,很快,我們就找到了,并且也只出現了一次:


可以肯定,這段代碼就是注冊碼處理驗證的地方了。

在這個函數的前面下一個斷點,就可以進行下一步的注冊碼驗證操作了。



回到 CM 界面。

輸入一個用戶名和注冊碼假碼"787878787878",如下圖:

點擊”OK!“(按鈕被水印擋住了)就會斷下來,進入OD調試,跟蹤注冊碼的算法,具體跟蹤、分析放一起了,如下所示:
[Asm] 純文本查看 復制代碼
00401410   .  6A FF                  push    -1                                                      ;  消息處理映射函數
00401412   .  68 181D4000            push    00401D18                                                ;  SE 處理程序安裝
00401417   .  64:A1 00000000         mov     eax, dword ptr fs:[0]
0040141D   .  50                     push    eax
0040141E   .  64:8925 00000000       mov     dword ptr fs:[0], esp
00401425   .  83EC 38                sub     esp, 38
00401428   .  53                     push    ebx                                                     ;  開始計算注冊碼
00401429   .  55                     push    ebp
0040142A   .  8BE9                   mov     ebp, ecx
0040142C   .  56                     push    esi
0040142D   .  57                     push    edi
0040142E   .  8D4C24 14              lea     ecx, dword ptr [esp+14]
00401432   .  E8 67050000            call    <jmp.&MFC42.#540_CString::CString>
00401437   .  33DB                   xor     ebx, ebx
00401439   .  8D4C24 10              lea     ecx, dword ptr [esp+10]
0040143D   .  895C24 50              mov     dword ptr [esp+50], ebx                                 ;  [esp+50] 字符串計數器
00401441   .  E8 58050000            call    <jmp.&MFC42.#540_CString::CString>
00401446   .  8D4C24 20              lea     ecx, dword ptr [esp+20]
0040144A   .  C64424 50 01           mov     byte ptr [esp+50], 1                                    ;  [esp+50] 字符串計數器
0040144F   .  E8 4A050000            call    <jmp.&MFC42.#540_CString::CString>
00401454   .  8D4C24 30              lea     ecx, dword ptr [esp+30]
00401458   .  C64424 50 02           mov     byte ptr [esp+50], 2
0040145D   .  E8 3C050000            call    <jmp.&MFC42.#540_CString::CString>
00401462   .  8D4C24 1C              lea     ecx, dword ptr [esp+1C]
00401466   .  C64424 50 03           mov     byte ptr [esp+50], 3
0040146B   .  E8 2E050000            call    <jmp.&MFC42.#540_CString::CString>
00401470   .  6A 01                  push    1
00401472   .  8BCD                   mov     ecx, ebp
00401474   .  C64424 54 04           mov     byte ptr [esp+54], 4                                    ;  字符串計數器
00401479   .  E8 80050000            call    <jmp.&MFC42.#6334_CWnd::UpdateData>                     ;  讀取數據給相應控件的映射變量(MFC映射成員變量)
0040147E   .  8D45 60                lea     eax, dword ptr [ebp+60]
00401481   .  8D4C24 14              lea     ecx, dword ptr [esp+14]
00401485   .  50                     push    eax
00401486   .  E8 6D050000            call    <jmp.&MFC42.#858_CString::operator=>                    ;  str1, eax==0x0019F4C8, [eax] ===> 用戶名,solly
0040148B   .  8D4D 64                lea     ecx, dword ptr [ebp+64]
0040148E   .  51                     push    ecx
0040148F   .  8D4C24 14              lea     ecx, dword ptr [esp+14]
00401493   .  E8 60050000            call    <jmp.&MFC42.#858_CString::operator=>                    ;  str2, eax==0x0019F4C4, [eax] ===> 注冊碼,"787878787878"
00401498   .  8B7C24 14              mov     edi, dword ptr [esp+14]                                 ;  edi ===> 用戶名,"solly"
0040149C   .  83C9 FF                or      ecx, FFFFFFFF
0040149F   .  33C0                   xor     eax, eax
004014A1   .  68 50304000            push    00403050                                                ;  ASCII "Ocbk~mxy`mxecb6Ucy+zi,o~mogih,ai-"
004014A6   .  F2:AE                  repne   scas byte ptr es:[edi]
004014A8   .  F7D1                   not     ecx
004014AA   .  49                     dec     ecx                                                     ;  int len = ecx == strlen(str1),用戶名長度
004014AB   .  8BF1                   mov     esi, ecx                                                ;  esi = ecx = length(username) == 5,用戶名長度
004014AD   .  8D4C24 24              lea     ecx, dword ptr [esp+24]
004014B1   .  E8 E2040000            call    <jmp.&MFC42.#860_CString::operator=>                    ;  str3, eax==0x0019F4D4, [eax] ===>"Ocbk~mxy`mxecb6Ucy+zi,o~mogih,ai-"
004014B6   .  68 4C304000            push    0040304C
004014BB   .  8D4C24 34              lea     ecx, dword ptr [esp+34]
004014BF   .  E8 D4040000            call    <jmp.&MFC42.#860_CString::operator=>                    ;  str4, eax==0x0019F4E4, [eax] ===> "4",用于檢查SN最后一位是否為"8"
004014C4   .  8D4C24 2C              lea     ecx, dword ptr [esp+2C]
004014C8   .  E8 D1040000            call    <jmp.&MFC42.#540_CString::CString>                      ;  eax == 0x0019F4E0
004014CD   .  8D4C24 18              lea     ecx, dword ptr [esp+18]
004014D1   .  C64424 50 05           mov     byte ptr [esp+50], 5
004014D6   .  E8 C3040000            call    <jmp.&MFC42.#540_CString::CString>                      ;  eax == 0x0019F4CC
004014DB   .  8D4C24 28              lea     ecx, dword ptr [esp+28]
004014DF   .  C64424 50 06           mov     byte ptr [esp+50], 6
004014E4   .  E8 B5040000            call    <jmp.&MFC42.#540_CString::CString>                      ;  eax==0x0019F4DC
004014E9   .  8D4C24 24              lea     ecx, dword ptr [esp+24]
004014ED   .  C64424 50 07           mov     byte ptr [esp+50], 7
004014F2   .  E8 A7040000            call    <jmp.&MFC42.#540_CString::CString>                      ;  eax==0x0019F4D8
004014F7   .  8D5424 10              lea     edx, dword ptr [esp+10]                                 ;  edx = sn ===> "787878787878"
004014FB   .  8D4C24 2C              lea     ecx, dword ptr [esp+2C]
004014FF   .  52                     push    edx
00401500   .  C64424 54 08           mov     byte ptr [esp+54], 8                                    ;  字符串計數器
00401505   .  E8 EE040000            call    <jmp.&MFC42.#858_CString::operator=>                    ;  str5, eax==0x0019F4E0, [eax] ===>"787878787878"
0040150A   .  68 48304000            push    00403048                                                ;  [00403048] ===> "-"
0040150F   .  8D4C24 14              lea     ecx, dword ptr [esp+14]                                 ;  [ecx] ===> 注冊碼假碼"787878787878"
00401513   .  895C24 38              mov     dword ptr [esp+38], ebx
00401517   .  E8 D6040000            call    <jmp.&MFC42.#2764_CString::Find>                        ;  在序列號中查找分隔符"-"
0040151C   .  8BF8                   mov     edi, eax                                                ;  沒找到分隔符,則eax == 0xFFFFFFFF,否則為"-"號的位置值
0040151E   .  83FF FF                cmp     edi, -1                                                 ;  位置值 保存于 EDI
00401521   .  75 0D                  jnz     short 00401530
00401523   .  8B45 00                mov     eax, dword ptr [ebp]                                    ;  eax == 0x00402350
00401526   .  8BCD                   mov     ecx, ebp
00401528   .  FF50 60                call    dword ptr [eax+60]                                      ;  call [0x004023B0], MFC42.#2446_CWnd::DestroyWindow
0040152B   .  E9 E8010000            jmp     00401718                                                ;  序列號格式不對,結束
00401530   >  8D4C24 10              lea     ecx, dword ptr [esp+10]                                 ;  [ecx] ===> 注冊碼假碼"7878-8787878",手動加了一個"-"
00401534   .  51                     push    ecx
00401535   .  8D4C24 2C              lea     ecx, dword ptr [esp+2C]
00401539   .  E8 BA040000            call    <jmp.&MFC42.#858_CString::operator=>                    ;  str6, eax==0x0019F4DC, [eax] ===> 注冊碼"7878-8787878"
0040153E   .  8D5424 38              lea     edx, dword ptr [esp+38]
00401542   .  57                     push    edi                                                     ;  長度(left)
00401543   .  52                     push    edx                                                     ;  buffer
00401544   .  8D4C24 30              lea     ecx, dword ptr [esp+30]                                 ;  引用 str6
00401548   .  E8 9F040000            call    <jmp.&MFC42.#4129_CString::Left>                        ;  str7, eax == 0x0019F4EC, [eax] ==>"7878"
0040154D   .  8B00                   mov     eax, dword ptr [eax]                                    ;  eax ===> "7878"
0040154F   .  8D4C24 3C              lea     ecx, dword ptr [esp+3C]                                 ;  ecx == 0x0019F4F0, 保存結果 str_sn1
00401553   .  6A 0A                  push    0A                                                      ; /radix = A (10.)
00401555   .  51                     push    ecx                                                     ; |endptr
00401556   .  50                     push    eax                                                     ; |str_sn1
00401557   .  FF15 CC214000          call    dword ptr [<&MSVCRT.strtol>]                            ; \MSVCRT.strtol(),轉成整數 sn1
0040155D   .  8BD8                   mov     ebx, eax                                                ;  eax==0x1EC6 = 7878
0040155F   .  83C4 0C                add     esp, 0C                                                 ;  恢復 esp 堆棧指針
00401562   .  8D4C24 38              lea     ecx, dword ptr [esp+38]                                 ;  ecx == 0x0019F4EC,[ecx] ===> "7878"
00401566   .  895C24 40              mov     dword ptr [esp+40], ebx                                 ;  保存 sn1
0040156A   .  E8 51030000            call    <jmp.&MFC42.#800_CString::~CString>                     ;  刪除字符串"7878"
0040156F   .  8D5424 2C              lea     edx, dword ptr [esp+2C]
00401573   .  8D4C24 18              lea     ecx, dword ptr [esp+18]
00401577   .  52                     push    edx
00401578   .  E8 7B040000            call    <jmp.&MFC42.#858_CString::operator=>                    ;  str8, eax == 0x0019F4CC, [eax] ===> 注冊碼假碼"7878-8787878"
0040157D   .  47                     inc     edi                                                     ;  edi=5, 指向"-"號的下一個字符位置
0040157E   .  8D4424 38              lea     eax, dword ptr [esp+38]                                 ;  str9
00401582   .  57                     push    edi                                                     ;  起始位置(mid)
00401583   .  50                     push    eax
00401584   .  8D4C24 20              lea     ecx, dword ptr [esp+20]
00401588   .  E8 59040000            call    <jmp.&MFC42.#4277_CString::Mid>                         ;  str9 = str8.Mid(n) ===> [eax]
0040158D   .  8B00                   mov     eax, dword ptr [eax]                                    ;  eax == 0x00BC0DE0 ===> "8787878",SN的后半截, 保存為 str_sn2
0040158F   .  8D4C24 3C              lea     ecx, dword ptr [esp+3C]                                 ;  ecx==0x0019F4F0
00401593   .  51                     push    ecx                                                     ; /endptr
00401594   .  50                     push    eax                                                     ; |str_sn2
00401595   .  FF15 D4214000          call    dword ptr [<&MSVCRT.strtod>]                            ; \strtod(), 轉成雙精度 sn2 保存在浮點寄存器ST0, ST0 == 8787878.000
0040159B   .  DA6424 48              fisub   dword ptr [esp+48]                                      ;  sn2 = sn2 - sn1, ST0 == 8780000.000
0040159F   .  83C4 08                add     esp, 8                                                  ;  恢復 esp 堆棧指針
004015A2   .  8D4C24 38              lea     ecx, dword ptr [esp+38]                                 ;  ecx == 0x0019F4EC, [ecx] ===> "8787878"
004015A6   .  DD5C24 40              fstp    qword ptr [esp+40]                                      ;  保存 ST0 在 [0x0019F4F0], 8字節
004015AA   .  E8 11030000            call    <jmp.&MFC42.#800_CString::~CString>                     ;  刪除"8787878"
004015AF   .  8D5424 14              lea     edx, dword ptr [esp+14]                                 ;  [edx] ===> "solly"
004015B3   .  8D4C24 24              lea     ecx, dword ptr [esp+24]                                 ;  ecx == 0x0019F4D8
004015B7   .  52                     push    edx
004015B8   .  E8 3B040000            call    <jmp.&MFC42.#858_CString::operator=>                    ;  eax == 0x0019F4D8, [eax] ===>"solly"
004015BD   .  DD4424 40              fld     qword ptr [esp+40]                                      ;  載入sn2到ST0, [0x0019F4F4] == 8780000.000
004015C1   .  DC1D 28244000          fcomp   qword ptr [402428]                                      ;  ST0浮點數與常量47391894.0比較,[0x00402428] == 47391894.000
004015C7   .  DFE0                   fstsw   ax
004015C9   .  F6C4 41                test    ah, 41                                                  ;  SN2需要大于47391894.000
004015CC   .  74 0D                  je      short 004015DB
004015CE   .  8B45 00                mov     eax, dword ptr [ebp]
004015D1   .  8BCD                   mov     ecx, ebp
004015D3   .  FF50 60                call    dword ptr [eax+60]                                      ;  MFC42.#2446_CWnd::DestroyWindow
004015D6   .  E9 3D010000            jmp     00401718                                                ;  退出
004015DB   >  8B7C24 24              mov     edi, dword ptr [esp+24]                                 ;  edi ==> "solly", SN2>47391894.000,來到這里
004015DF   .  83C9 FF                or      ecx, FFFFFFFF                                           ;  int len = -1
004015E2   .  33C0                   xor     eax, eax                                                ;  char a=0
004015E4   .  83F3 6F                xor     ebx, 6F                                                 ;  sn1 = ebx = sn1 xor 0x6F = 0x1EA9 = 7849
004015E7   .  8A5437 FF              mov     dl, byte ptr [edi+esi-1]                                ;  dl = name[len-1]
004015EB   .  895C24 40              mov     dword ptr [esp+40], ebx                                 ;  [0x0019F4F4] = sn1 == 0x00053297
004015EF   .  F2:AE                  repne   scas byte ptr es:[edi]                                  ;  計算 name 的長度
004015F1   .  DB4424 40              fild    dword ptr [esp+40]                                      ;  ST0 = sn1 = 7849
004015F5   .  F7D1                   not     ecx
004015F7   .  49                     dec     ecx                                                     ;  int len2 = name.Length() = 5,用戶名的長度
004015F8   .  83E2 7F                and     edx, 7F                                                 ;  edx = edx and 0x7F, int 變 char
004015FB   .  0FAFCA                 imul    ecx, edx                                                ;  int lc = len2 * (char)name[len-1] = 0x025D,用戶名長度x用戶名最后一個字符
004015FE   .  33D2                   xor     edx, edx                                                ;  int i=0
00401600   .  85F6                   test    esi, esi                                                ;  len>0, 檢查用名名長度>0, len == esi, 其在 0x004014AB處賦值
00401602   .  7E 1C                  jle     short 00401620                                          ;  for(int sum=0, int i=0; i<n; i++) {
00401604   .  8B7C24 14              mov     edi, dword ptr [esp+14]                                 ;  edi ===> "solly"
00401608   >  8A043A                 mov     al, byte ptr [edx+edi]                                  ;  a = name[i]
0040160B   .  8B5C24 34              mov     ebx, dword ptr [esp+34]                                 ;  [0x0019F4E8] == 0x00
0040160F   .  83E0 7F                and     eax, 7F                                                 ;  a = a and 0x7F
00401612   .  0FAFC1                 imul    eax, ecx                                                ;  a = a * lc
00401615   .  03D8                   add     ebx, eax                                                ;  sum = sum + a;
00401617   .  42                     inc     edx                                                     ;  i++;
00401618   .  3BD6                   cmp     edx, esi                                                ;  i<n;
0040161A   .  895C24 34              mov     dword ptr [esp+34], ebx                                 ;  循環結束時,sum = 0x00053287
0040161E   .^ 7C E8                  jl      short 00401608                                          ;  }
00401620   >  8B4424 34              mov     eax, dword ptr [esp+34]                                 ;  eax = sum = 0x00053287 = 340615
00401624   .  8B4C24 30              mov     ecx, dword ptr [esp+30]                                 ;  ecx = 0x00BC0D90, ecx ===> str4
00401628   .  83F0 10                xor     eax, 10                                                 ;  int sum2 = sum xor 0x10 = 0x00053297 = 340631
0040162B   .  894424 40              mov     dword ptr [esp+40], eax                                 ;  保存 sum2, 用于與輸入的SN1比較
0040162F   .  8A01                   mov     al, byte ptr [ecx]                                      ;  al = '4', str4,用于檢查SN最后一位是否為"8"
00401631   .  DB4424 40              fild    dword ptr [esp+40]                                      ;  ST0 = 340631, ST1=原ST0=sn1=7849
00401635   .  D9C9                   fxch    st(1)                                                   ;  交換ST0, ST1
00401637   .  D8D9                   fcomp   st(1)                                                   ;  比較大小
00401639   .  34 0C                  xor     al, 0C                                                  ;  int a4 = al = al xor 0x0C = 0x38, 異或后變成字符"8"
0040163B   .  884424 34              mov     byte ptr [esp+34], al                                   ;  保存 a4
0040163F   .  DFE0                   fstsw   ax                                                      ;  ax==0x3920
00401641   .  F6C4 40                test    ah, 40                                                  ;  sum2必須等于sn1
00401644   .  DDD8                   fstp    st                                                      ;  清空ST0
00401646   .  0F84 C4000000          je      00401710                                                ;  (sum2 != sn1)則退出
0040164C   .  8B5424 34              mov     edx, dword ptr [esp+34]                                 ;  edx == a4 == (char)0x00053238(0x38 == "4" xor 0x0C)
00401650   .  6A 01                  push    1                                                       ;  1個字節
00401652   .  52                     push    edx                                                     ;  a4
00401653   .  8D4C24 40              lea     ecx, dword ptr [esp+40]
00401657   .  E8 84030000            call    <jmp.&MFC42.#536_CString::CString>                      ;  str11, eax == 0x0019F4EC, (char)[eax] == 0x38 ===>"8",CString(TCHAR ch,int n = 1);
0040165C   .  8D4424 40              lea     eax, dword ptr [esp+40]                                 ;  eax = sum = 0x00053297
00401660   .  6A 01                  push    1
00401662   .  50                     push    eax                                                     ;  指向返回值緩沖區的指針 char **
00401663   .  8D4C24 20              lea     ecx, dword ptr [esp+20]                                 ;  buffer ;[ecx] = str2 ===> "7878-8787878"
00401667   .  C64424 58 09           mov     byte ptr [esp+58], 9                                    ;  字符串計數器
0040166C   .  E8 69030000            call    <jmp.&MFC42.#5710_CString::Right>                       ;  str12 = Right(sn, 1), eax = 0x0019F4F4, [eax]="8", 注冊碼的最后一位字符
00401671   .  8B4C24 38              mov     ecx, dword ptr [esp+38]                                 ;  ecx == 0x00BC0DE0 ===> "8"(0x34 xor 0x0C后的字符)
00401675   .  8B00                   mov     eax, dword ptr [eax]                                    ;  eax == 0x00B30E30 ===> "8" (注冊碼的最后一位字符)
00401677   .  51                     push    ecx                                                     ; /strParam2
00401678   .  50                     push    eax                                                     ; |strParam1
00401679   .  FF15 D8214000          call    dword ptr [<&MSVCRT._mbscmp>]                           ; \MSVCRT._mbcmp(), 比較SN最后一位是否為'8',相等返回 0
0040167F   .  83C4 08                add     esp, 8
00401682   .  8D4C24 40              lea     ecx, dword ptr [esp+40]                                 ;  str11, ecx = 0x0019F4F4, 準備刪除該字符串
00401686   .  85C0                   test    eax, eax                                                ;  檢查字符串比較結果
00401688   .  0F94C3                 sete    bl                                                      ;  相等時,bl = 1
0040168B   .  E8 30020000            call    <jmp.&MFC42.#800_CString::~CString>                     ;  清空 str11
00401690   .  8D4C24 38              lea     ecx, dword ptr [esp+38]
00401694   .  C64424 50 08           mov     byte ptr [esp+50], 8                                    ;  字符串計數
00401699   .  E8 22020000            call    <jmp.&MFC42.#800_CString::~CString>
0040169E   .  84DB                   test    bl, bl                                                  ;  檢查字符串比較結果,bl==1表示相等
004016A0   .  74 6E                  je      short 00401710                                          ;  bl等于0,則退出,bl等于1則顯示 Crack 成功!!!
004016A2   .  8B7C24 20              mov     edi, dword ptr [esp+20]                                 ;  一個加密靜態初始化的字符串 [0x00BC0D40] ===> "Ocbk~mxy`mxecb6Ucy+zi,o~mogih,ai-"
004016A6   .  83C9 FF                or      ecx, FFFFFFFF
004016A9   .  33C0                   xor     eax, eax                                                ;  '\0'
004016AB   .  33F6                   xor     esi, esi                                                ;  int i=0
004016AD   .  F2:AE                  repne   scas byte ptr es:[edi]
004016AF   .  F7D1                   not     ecx
004016B1   .  49                     dec     ecx                                                     ;  計算長度
004016B2   .  8BF9                   mov     edi, ecx                                                ;  edi 為長度
004016B4   .  85FF                   test    edi, edi
004016B6   .  7E 43                  jle     short 004016FB
004016B8   >  8B5424 20              mov     edx, dword ptr [esp+20]                                 ;  str3, edx == 0x00BC0D40 ===> "Ocbk~mxy`mxecb6Ucy+zi,o~mogih,ai-"
004016BC   .  8D4C24 1C              lea     ecx, dword ptr [esp+1C]                                 ;  ecx == 0x0019F4D0,臨時結果
004016C0   .  8A0416                 mov     al, byte ptr [esi+edx]                                  ;  al = str[i]
004016C3   .  8D5424 40              lea     edx, dword ptr [esp+40]                                 ;  str11, edx == 0x0019F4F4, 臨時存放解碼后CString字符
004016C7   .  34 0C                  xor     al, 0C                                                  ;  str[i] = str[i] xor 0x0C
004016C9   .  884424 34              mov     byte ptr [esp+34], al                                   ;  保存字符 str[i]
004016CD   .  8B4424 34              mov     eax, dword ptr [esp+34]                                 ;  eax ===> str[i]
004016D1   .  50                     push    eax
004016D2   .  51                     push    ecx
004016D3   .  52                     push    edx
004016D4   .  E8 FB020000            call    <jmp.&MFC42.#923_operator+>                             ;  連接字符串,eax == 0x0019F4F4, [eax] ===> 解碼后的字符串
004016D9   .  50                     push    eax
004016DA   .  8D4C24 20              lea     ecx, dword ptr [esp+20]
004016DE   .  C64424 54 0A           mov     byte ptr [esp+54], 0A                                   ;  字符串計數
004016E3   .  E8 10030000            call    <jmp.&MFC42.#858_CString::operator=>                    ;  字符串賦值,str13 = "C"
004016E8   .  8D4C24 40              lea     ecx, dword ptr [esp+40]
004016EC   .  C64424 50 08           mov     byte ptr [esp+50], 8                                    ;  字符串計數
004016F1   .  E8 CA010000            call    <jmp.&MFC42.#800_CString::~CString>                     ;  清除臨時字符串2個
004016F6   .  46                     inc     esi                                                     ;  i++
004016F7   .  3BF7                   cmp     esi, edi
004016F9   .^ 7C BD                  jl      short 004016B8                                          ;  循環解碼得到字符串 [0x00BC0DE0] ===> "Congratulation:You've cracked me!"
004016FB   >  8B4424 1C              mov     eax, dword ptr [esp+1C]
004016FF   .  6A 40                  push    40
00401701   .  68 38304000            push    00403038                                                ;  ASCII "[NZC] Crackme"
00401706   .  50                     push    eax
00401707   .  8BCD                   mov     ecx, ebp
00401709   .  E8 C0020000            call    <jmp.&MFC42.#4224_CWnd::MessageBoxA>                    ;  顯示 Crack 成功
0040170E   .  EB 08                  jmp     short 00401718
00401710   >  8B55 00                mov     edx, dword ptr [ebp]
00401713   .  8BCD                   mov     ecx, ebp
00401715   .  FF52 60                call    dword ptr [edx+60]                                      ;  MFC42.#2446_CWnd::DestroyWindow
00401718   >  8D4C24 24              lea     ecx, dword ptr [esp+24]
0040171C   .  C64424 50 07           mov     byte ptr [esp+50], 7                                    ;  字符串計數
00401721   .  E8 9A010000            call    <jmp.&MFC42.#800_CString::~CString>
00401726   .  8D4C24 28              lea     ecx, dword ptr [esp+28]
0040172A   .  C64424 50 06           mov     byte ptr [esp+50], 6
0040172F   .  E8 8C010000            call    <jmp.&MFC42.#800_CString::~CString>
00401734   .  8D4C24 18              lea     ecx, dword ptr [esp+18]
00401738   .  C64424 50 05           mov     byte ptr [esp+50], 5
0040173D   .  E8 7E010000            call    <jmp.&MFC42.#800_CString::~CString>
00401742   .  8D4C24 2C              lea     ecx, dword ptr [esp+2C]
00401746   .  C64424 50 04           mov     byte ptr [esp+50], 4
0040174B   .  E8 70010000            call    <jmp.&MFC42.#800_CString::~CString>
00401750   .  8D4C24 1C              lea     ecx, dword ptr [esp+1C]
00401754   .  C64424 50 03           mov     byte ptr [esp+50], 3
00401759   .  E8 62010000            call    <jmp.&MFC42.#800_CString::~CString>
0040175E   .  8D4C24 30              lea     ecx, dword ptr [esp+30]
00401762   .  C64424 50 02           mov     byte ptr [esp+50], 2
00401767   .  E8 54010000            call    <jmp.&MFC42.#800_CString::~CString>
0040176C   .  8D4C24 20              lea     ecx, dword ptr [esp+20]
00401770   .  C64424 50 01           mov     byte ptr [esp+50], 1
00401775   .  E8 46010000            call    <jmp.&MFC42.#800_CString::~CString>
0040177A   .  8D4C24 10              lea     ecx, dword ptr [esp+10]
0040177E   .  C64424 50 00           mov     byte ptr [esp+50], 0
00401783   .  E8 38010000            call    <jmp.&MFC42.#800_CString::~CString>
00401788   .  8D4C24 14              lea     ecx, dword ptr [esp+14]
0040178C   .  C74424 50 FFFFFFFF     mov     dword ptr [esp+50], -1
00401794   .  E8 27010000            call    <jmp.&MFC42.#800_CString::~CString>
00401799   .  8B4C24 48              mov     ecx, dword ptr [esp+48]
0040179D   .  5F                     pop     edi
0040179E   .  5E                     pop     esi
0040179F   .  5D                     pop     ebp
004017A0   .  5B                     pop     ebx
004017A1   .  64:890D 00000000       mov     dword ptr fs:[0], ecx
004017A8   .  83C4 44                add     esp, 44
004017AB   .  C3                     retn
004017AC      90                     nop

根據上面對算法的分析,寫出注冊機,經Dev-C++調試通過,代碼如下:
[C++] 純文本查看 復制代碼
#include "stdio.h"
#include "String.h"

void getCode(char * name);

int main() {

    char name[256];

    printf("Keygen for NZC.1\n");

    printf("Input your name: ");

    gets(name);

    getCode(name);

    return 0;
}

void getCode(char * name) {
    int len = strlen(name);
    int lc = len * (char)name[len-1];
    int sum = 0;
    for (int i=0; i<len; i++) {
        sum += lc * (char)(name[i] & 0x7F);
    }

    int sn1 = sum ^ 0x10 ^ 0x6F;
    int sn2 = sn1 + 47391894 + 2; // (sn2-sn1)>47391894, 加2是保證下面將尾數變成8后還是大于47391894
    sn2 = sn2 + (8 - (sn2 % 10)); //// 將個位數變為8
    
    printf("serial: %d-%d\n", sn1, sn2);
}

運算結果如下:
[HTML] 純文本查看 復制代碼
Keygen for NZC.1
Input your name: solly
serial: 340728-47732628
--------------------------------
Process exited after 1.482 seconds with return value 0
請按任意鍵繼續. . .

我們再次在 CM 中輸入上面得序列號,得到CM的提示如下:

分析完畢!
后面是脫殼后的文件信息。

03.jpg (44.14 KB, 下載次數: )

03.jpg

04.png (16.8 KB, 下載次數: )

04.png

53.png (11.02 KB, 下載次數: )

53.png

免費評分

參與人數 13吾愛幣 +19 熱心值 +12 收起 理由
hszt + 1 + 1 熱心回復!
alderaan + 1 [email protected]
it.liyong + 1 + 1 熱心回復!
alanyh + 1 + 1 用心討論,共獲提升!
000000 + 2 + 1 牛批
軟硬兼嗜 + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
tchivs + 3 + 1 [email protected]
yixi + 1 + 1 [email protected]
simplex + 1 [email protected]
黑的思想 + 2 + 1 用心討論,共獲提升!
pk8900 + 3 + 1 這個當時研究了一會,沒頭緒,直接跳過了,還得大神出手啊。
SomnusXZY + 1 + 1 熱心回復!
笙若 + 2 + 1 [email protected]

查看全部評分

本帖被以下淘專輯推薦:

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

推薦
 樓主| solly 發表于 2019-5-29 16:30 <
本帖最后由 solly 于 2019-5-29 16:56 編輯

補充一下關于那個定時器的説明,定時器也是用于反調試,檢查本 CM 所用的API是否被 BPX 中斷,如有中斷,則破壞CM代碼并引起異常,導致系統關閉CM。
生成定時器的代碼:
[Asm] 純文本查看 復制代碼
0040D467    8D8D 67214000            lea     ecx, dword ptr [ebp+402167]                             ; ecx 指向指令代碼區的地址,ecx==0x0040D13B, Timer回調函數
0040D472    51                       push    ecx                                                     ; lpTimerFunc, ecx==0x0040D13B,指令區地址 TimerProc
0040D478    68 F4010000              push    1F4                                                     ; uElapse == 500ms
0040D481    6A 00                    push    0                                                       ; nIDEvent
0040D487    6A 00                    push    0                                                       ; hWnd
0040D48D    FF95 DB284000            call    dword ptr [ebp+4028DB]                                  ; call User32.SetTimer(0,0,500, 0x0040D13B)
0040D493    90                       nop

定時器的回調代碼:
[Asm] 純文本查看 復制代碼
0040D13B    90                       nop                                                             ; 0x0040D467處的指令中的ecx 指向這里, 定時器回調函數 TimerProc
0040D14C    60                       pushad
0040D151    E8 05000000              call    0040D15B
0040D156    00000000                 dd      0x00000000                                              ; 0x0040D1CF處指令引用這里,保存數據用
0040D15A    00                       db      0x00                                                    ; 0x0040D207處指令引用這里,保存數據用
;---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0040D15B    5D                       pop     ebp                                                     ; 取得call后的返回地址
0040D160    81ED 82214000            sub     ebp, 00402182
0040D16A    33C9                     xor     ecx, ecx                                                ; i = 0
0040D170    8D940D CB284000          lea     edx, dword ptr [ebp+ecx+4028CB]                         ; edx=0040D89F, edx[i] ==> API 入口
0040D17B    8B12                     mov     edx, dword ptr [edx]                                    ; [edx] ==> LoadLibraryA, GetProcAddress, MessageBoxA, ExitProcess, SetTimer, ReadProcessMemory, _lopen
0040D181    85D2                     test    edx, edx
0040D188    74 39                    je      short 0040D1C3
0040D18E    E8 5F000000              call    0040D1F2                                                ; 讀取系統API(LoadLibraryA等)第1個字節,防 Int3 調試
0040D197    80BD 86214000 CC         cmp     byte ptr [ebp+402186], 0CC                              ; [0x0040D15A] != 0xCC, 反INT3調試
0040D1A3    74 28                    je      short 0040D1CD
0040D1A9    C685 86214000 00         mov     byte ptr [ebp+402186], 0                                ; 置 0x0040D15A 為 0, 隱藏  0xCC 反調試檢查
0040D1B5    83C1 04                  add     ecx, 4                                                  ; i++,指向下一個 API 入口
0040D1BD  ^ EB B1                    jmp     short 0040D170                                          ; 循環繼續
0040D1C3    90                       nop                                                             ; TimerProc 檢查 API 正常后,來到這里
0040D1C7    61                       popad
0040D1CC    C3                       retn                                                            ; TimerProc 結束
;----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0040D1CD    90                       nop                                                             ; TimerProc 內如果檢測到 API 被 BPX 中斷,則來到這里
0040D1D1    8DBD 87214000            lea     edi, dword ptr [ebp+402187]                             ; edi == 0x0040D15B, 指向上面的代碼
0040D1DB    B9 91000000              mov     ecx, 91
0040D1E4    33C0                     xor     eax, eax
0040D1EA    F2:AA                    repne   stos byte ptr es:[edi]                                  ; 覆蓋破壞上面的代碼,共破壞0x91字節
0040D1EC    90                       nop                                                             ; 會一直覆蓋到這里, 不留一點痕跡
0040D1F0    8B00                     mov     eax, dword ptr [eax]                                    ; 因為eax==0,這里是非法內存訪問,導至程序會被系統關閉
;----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0040D1F2    60                       pushad                                                          ; TimerProc 函數中 0x0040D18E 處的代碼調用這里
0040D1F3    B8 FFFFFF7F              mov     eax, 7FFFFFFF
0040D1FC    8D8D 82214000            lea     ecx, dword ptr [ebp+402182]                             ; ECX == 0x0040D156
0040D207    8D9D 86214000            lea     ebx, dword ptr [ebp+402186]                             ; EBX == 0x0040D15A
0040D211    51                       push    ecx                                                     ; lpNumberOfBytesRead , ReadProcMemory 返回讀了多少字節數據
0040D217    6A 01                    push    1                                                       ; nSize
0040D21D    53                       push    ebx                                                     ; lpBuffer,ReadProcMemory讀取的內容
0040D222    52                       push    edx                                                     ; lpBaseAddress, 指向 LoadLibraryA() 等函數第一個字節的指令
0040D227    50                       push    eax                                                     ; hProcess
0040D22C    FF95 DF284000            call    dword ptr [ebp+4028DF]                                  ; call ReadProcessMemory,用于防止本CM所調用API的第1個指令字節是 0xCC(int3 中斷)
0040D236    61                       popad
0040D237    C3                       retn


附件是前面所有截圖的打包。

images.rar

1.74 MB, 下載次數: 5, 下載積分: 吾愛幣 -1 CB

免費評分

參與人數 1吾愛幣 +1 熱心值 +1 收起 理由
wshze + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!

查看全部評分

3#
pk8900 發表于 2019-5-29 21:07
帖子加到我那個索引貼里了,寫這個帖子估計得半天時間吧~~
4#
 樓主| solly 發表于 2019-5-29 21:22 <
pk8900 發表于 2019-5-29 21:07
帖子加到我那個索引貼里了,寫這個帖子估計得半天時間吧~~

還不止半天,截圖處理費時。文字大部分在跟蹤時就寫在OD中了。
5#
kanxue2018 發表于 2019-5-29 23:36
非常好的練習資料,感謝樓主
6#
cpj1203 發表于 2019-5-30 01:01
受益良多
7#
學士天下 發表于 2019-5-30 08:25
謝謝,讓我好好學一下
8#
AAQZzx 發表于 2019-5-30 10:20
支持 樓主  辛苦了
9#
wapj152321 發表于 2019-6-13 07:44
謝謝分享
10#
liphily 發表于 2019-6-13 11:20

++

%D2%BB%BF%B4%BE%CD%B6%AE%A3%AC%D2%BB%D7%F6%BE%CD%B7%CF%A1%A3%0D%0A%D1%DB%A3%BA%CE%D2%BB%E1%C1%CB%0D%0A%C4%D4%A3%BA%C4%E3%B2%BB%BB%E1%7B%3A1_935%3A%7D
您需要登錄后才可以回帖 登錄 | 注冊[Register]

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

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

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( 京ICP備16042023號 | 京公網安備 11010502030087號 )

GMT+8, 2019-8-10 03:32

Powered by Discuz!

© 2001-2017 Comsenz Inc.

快速回復 返回頂部 返回列表
内蒙古11选5开奖查询百度