共兩篇,首篇與殼本身關係不大,聚焦 CLR 內核中介面虛方法定位機制;次篇詳細調試 CLISecure 保護原理。部落格原名「CLR 內核調試隨記」,屬隨手筆記,可能有疏漏錯誤,歡迎指正。急躁者請直接看第二篇。 
調試殼:CLISecure,下載 secureteam.net,最新 3.0,調試版本 2.5,可能有差異。
追蹤 CLR 中介面虛方法定位,純屬好玩。某殼 Hook JIT 代碼中涉及此機制,頗有意思(殼作者似深諳 CLR 內部結構,推測微軟部分開源給他們)。
.text:10002A4C mov eax, [ebp+ICorJitInfo]
.text:10002A4F mov ecx, [eax+4]
; ecx 指向 CEEJitInfo::'vbtable'{for `ICorJitInfo'}
; 第一雙字指向 .text:79E97B14 dd offset [thunk]:CEEInfo::getHelperName...
79E97C14 FC FF FF FF 34 00 00 00 3C 00 00 00 44 00 00 00
79E97C24 4C 00 00 00 54 00 00 00 5C 00 00 00 64 00 00 00
79E97C34 6C 00 00 00 74 00 00 00 80 00 00 00 FC FF FF FF
編譯期確定(CLR 部分 C++ 實作)。FC FF FF FF 可能為 vtable 起始標記(結尾再見一次)。兩標記間雙字數暗示 10 個方法(SSCLI 代碼稍多,暫不深究)。
.text:10002A52 mov edx, [ecx+4]
.text:10002A55 mov eax, [ebp+ICorJitInfo]
...
.text:10002A61 lea eax, [ecx+eax+4]
.text:10002A65 mov ecx, [ebp+ICorJitInfo]
.text:10002A68 mov edx, [ecx+edx+4]
執行 lea eax 後,eax 指向記憶體:
0013EA18 78 7B E9 79 00 00 00 00 4C 7B E9 79 00 00 00 00
0013EA28 A8 7A E9 79 00 00 00 00 84 7A E9 79 00 00 00 00
[eax] = 0x79E97B78 指向:
.text:79E97B78 const CEEJitInfo::'vftable'{for `ICorMethodInfo'} dd offset [thunk]:CEEInfo::getMethodName...
即 ICorJitInfo vtable 含 getMethodName。但 SSCLI 代碼中 ICorJitInfo 無此方法。考慮繼承鏈:
class ICorJitInfo : public virtual ICorDynamicInfo
class ICorDynamicInfo : public virtual ICorStaticInfo
class ICorStaticInfo : public virtual ICorMethodInfo, public virtual ICorModuleInfo, ...
ICorStaticInfo 首繼承 ICorMethodInfo,其中定義:
class ICorMethodInfo {
virtual const char* __stdcall getMethodName(CORINFO_METHOD_HANDLE ftn, const char** moduleName) = 0;
virtual unsigned __stdcall getMethodHash(CORINFO_METHOD_HANDLE ftn) = 0;
}
虛方法定位完成。實為 C++ 編譯器記憶體佈局與運行期動態填充機制,與 CLR 核心關係不大。
.text:79E977EC mov [esi+4], offset CEEJitInfo::'vbtable'{for `CEEInfo'}
.text:79E977F3 mov [esi+10h], offset CEEJitInfo::'vbtable'{for `ICorJitInfo'}
.text:79E977FA mov [esi+88h], offset CEEInfo::'vbtable'{for `ICorStaticInfo'}
.text:79E97804 mov [esi+94h], offset CEEJitInfo::'vbtable'{for `ICorDynamicInfo'}
.text:79E9780E mov [esi+44h], offset ICorStaticInfo::'vftable'{for `ICorMethodInfo'}
.text:79E97815 mov [esi+4Ch], offset ICorModuleInfo::'vftable'
.text:79E9781C mov [esi+54h], offset ICorCompileInfo::'vftable'{for `ICorClassInfo'}
.text:79E97823 mov [esi+5Ch], offset ICorJitInfo::'vftable'{for `ICorFieldInfo'}
.text:79E9782A mov [esi+64h], offset ICorDebugInfo::'vftable'
.text:79E97831 mov [esi+6Ch], offset ICorCompileInfo::'vftable'{for `ICorArgInfo'}
.text:79E97838 mov [esi+74h], offset CHashTableAndData::'vftable'
回到開頭 ICorJitInfo 表中第一值 0x34 定位至 getMethodName,第二值 0x3C 指向何方法?請自行追蹤。
下次將追蹤標記「for internal use」的 CLR 內部機制。環境:XP SP2 + .NET Framework 2.0 簡體中文版。