延續上篇,今日重點追蹤 CLISecure 的解密流程。殼安裝後含 GUI 主程式與本地 DLL,調試核心在該 DLL。仍在 JIT Hook 處下斷點,執行未 JIT 方法(固定用「關於視窗」觸發)激活。
中斷於 Hook 入口:

堆疊頂 0x79E9776F 指向 mscorwks.dll 呼叫 JIT 處,次頂 0x790AF170 指向 JIT 內部呼叫 compileMethod,隨即跳入 Hook 代碼。

代碼呼叫 CEEInfo::getMethodModule 判斷是否為當前模組需 JIT:
012B2A4C mov eax, [ebp+C]
012B2A4F mov ecx, [eax+4]
012B2A52 mov edx, [ecx+4]
...
012B2A70 call eax ; 調用 getMethodModule
012B2A72 mov [ebp-10], eax
012B2A83 call CliSec_1.012B2910 ; 關鍵檢查函數
012B2AA5 je CliSec_1.012B2CE0 ; 正常(需解密)不跳轉
012B2AAB lea edx, [ebp-4C]
012B2AD6 call edx ; 調用 CEEInfo::getMethodName
呼叫後 EAX = "UxQ=" —— 顯示「關於視窗」的方法名,顯然經過混淆。
012B2B04 call edx ; 調用 CEEInfo::getMethodDefFromMethod
返回 EAX = 0x060000B0,即方法 Token。
012B2B0C and eax, 0xFFFFFF
012B2B14 je CliSec_1.012B2CE0 ; 無效則跳過
重新調試,在 0x0013E890、0x0013E894 設硬體寫入斷點,發現被忽略的函數 CliSec_1.012B2910 修改了堆疊值。此函數分析留待下篇。
012B2B4E call CliSec_1.012B1FE0 ; 取得主程式基址 0x11000000
012B2B6F push 1C
012B2B71 call CliSec_1.012B7C6F ; new 分配記憶體
012B2B8F call CliSec_1.012B1FC0 ; 關鍵:解密代碼填充
堆疊頂 0x110A477C 指向 .text 區段:

該處資料呈現典型 IL 方法體特徵:

012B2CF8 call dword ptr ds:[12D45E4] ; mscorjit.7906E7F4 (真正 JIT)
參數 Arg3 指向修改後 IL 體:0x110A4788,大小 0x0E。
用 UltraEdit 開啟原檔搜尋 IL 特徵字串 133001000E00000027000011731D0100060A066F0E01000A,找到兩處。對應 0x110A477C 的檔案偏移確認:

該殼並未加密原始 IL 代碼,而是在 JIT 時動態建立新方法體,將正確偏移傳給真正 JIT。 脫殼機制極簡:直接修正原檔案偏移即可(理論上,實際可能需更多工作)。
殼版本:調試為 2.5,最新 3.0 可能不同。下載:secureteam.net