在上一回 .Net 加密原理,方法體加密資訊對應關係的實現 中介紹了實現加密殼首要解決的基礎問題,
今回以第一種實現模式介紹如何?一個純EE層(mscorwks.dll)的加密殼核心。
首先確定 “方法體加密對應資訊” 直接通過中繼資料來儲存。
這裡我們使用最簡單的記錄方式--記錄一個四位元組的指標資訊。
另外再加上一個標識資料,這個我們採用一個 magic DWORD表示。
這樣記錄資訊一共是8位元組。所以方法體小於8位元組的Method將不能被加密處理。
接下來就是加密殼運行庫核心的實現了。這裡以早期DNGuard v1.0的運行庫實現為例。
在mscorwks.dll 中有一個函數 GetILHeader,架構所有需要取方法體的地方都是通過調用這個函數實現的。
這個函數的原型 COR_ILMETHOD* __fastcall GetILHeader(DWORD_PTR RuntimeMethodHandler);
可以看著這樣 DWORD* __fastcall GetILHeader(DWORD_PTR MethodPtr);
在我們的加密殼運行庫中實現這個函數,然後用運行庫實現的這個函數替換 mscorwks.dll 中的這個函數,
這個過程就是一個標準的 api hook 過程,這裡就不詳細介紹了。
這樣 .Net 架構在需要取方法體時就會進入到我們運行庫的這個函數中。
在運行庫的函數如: DWORD* __fastcall DNGuard_GetILHeader(DWORD_PTR MethodPtr) 中。
首先我們調用原始的 GetILHeader,得到傳回值,
首先判斷傳回值的前四個位元組是否 magic DWORD,
(因為我們把對應關聯性記錄在中繼資料中的,所以省去自己查詢虛擬表的過程,架構已經幫我們完成了。)
如果不是,則直接返回。
如果是,則根據後面的四個位元組執行的資料進行方法體的解密,然後把解密結果返回。
DWORD* __fastcall DNGuard_GetILHeader(DWORD_PTR MethodPtr)
{
DWORD* pIL = OrgGetILHeader(MethodPtr);
if(*pIL == gdwMagic)
{
pIL = DecryptMethod(pIL[1]);
}
return pIL;
}
這樣一個 EE 層加密殼核心運行庫就算完成了。
這種方式相容性非常好,不會破壞dotNet原有的任何功能,自然也就包含反射功能了。
在 .Net 2.0 中這種加密殼運行庫 就會出現反射漏洞了。
下回再介紹這種核心的改進--針對反射漏洞。