一种注册表沙箱的思路、实现——Hook Nt函数
??????? Nt函數是在Ring3層最底層的函數了,選擇此類函數進行Hook,是為了提高繞過門檻。我的Hook方案使用的是微軟的Detours。(轉載請指明出處)
??????? Detours的Hook和反Hook的寫入如下:
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(lpOriFuncAddr, lpNewFuncAddr);
DetourTransactionCommit();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(lpOriFuncAddr, lpNewFuncAddr);
DetourTransactionCommit();
??????? 從以上可以見得,我們需要保存lpOriFuncAddr(原始函數入口地址)和lpNewFuncAddr(修改后函數入口地址),我們使用一個結構體來保存這兩個信息。
// 記錄(函數原始函數地址,修改后函數地址)的結構
typedef struct _FuncPointer_{VOID* lpOri;VOID* lpNew;
}FuncPointer, *pFuncPointer;
??????? 因為我們要Hook很多函數,我們定義一個Map來保存信息,以方便尋找到相關的函數入口,我們的Map是以函數名為Key,以保存原始函數入口和修改后函數入口結構體為值。
// 以函數名為Key,其(函數原始函數地址,修改后函數地址)為值的map
typedef std::map<std::string,FuncPointer> MapFuncPointer;
typedef MapFuncPointer::iterator MapFuncPointerIter;
typedef MapFuncPointer::const_iterator MapFuncPointerCIter;
??????? 尋找原始函數的入口地址可以通過Detours提供的DetourFindFunction,而修改后的函數入口地址則需要我們自己定義。在我工程的NewNtRegFunc.h和NewNtRegFunc.cpp文件中,我分別定義了所有修改后函數聲明和實現。新函數名的規則是“New_原函數名”,如
NTSTATUS __stdcall New_NtOpenKey(__out PHANDLE KeyHandle,__in ACCESS_MASK DesiredAccess,__in POBJECT_ATTRIBUTES ObjectAttributes );
??????? 我們第一步就是要生成這樣Map
extern MapFuncPointer g_MapRegFuncPointer;VOID GetHookNtRegFuncInfo()
{HOOKNTDLLFUNC( CreateKey );HOOKNTDLLFUNC( OpenKey );HOOKNTDLLFUNC( DeleteKey );HOOKNTDLLFUNC( DeleteValueKey );HOOKNTDLLFUNC( QueryKey );HOOKNTDLLFUNC( SetValueKey );HOOKNTDLLFUNC( QueryValueKey );HOOKNTDLLFUNC( EnumerateKey );HOOKNTDLLFUNC( EnumerateValueKey );HOOKNTDLLFUNC( FlushKey );HOOKNTDLLFUNC( NotifyChangeKey );HOOKNTDLLFUNC( Close );HOOKNTDLLFUNC( SetSecurityObject );HOOKNTDLLFUNC( QuerySecurityObject );// vista及以上系統HOOKNTDLLFUNC( OpenKeyEx );HOOKNTDLLFUNC( CreateKeyTransacted );HOOKNTDLLFUNC( OpenKeyTransacted );HOOKNTDLLFUNC( OpenKeyTransactedEx );
}
??????? 其中HOOKTNDLLFUNC是一個宏,其定義如下
#define HOOKNTDLLFUNC(x)\HOOKNTITEM("NtDll.dll", x )
????? HOOKNTITEM也是個宏
// Hook函數,同時將{函數名,(函數原始函數地址,修改后函數地址)}保存到map中
#define HOOKNTITEM(x,y)\FuncPointer FP_##y; FP_##y.lpOri = DetourFindFunction( x , "Nt"#y );FP_##y.lpNew = static_cast<VOID*>(New_Nt##y); g_MapRegFuncPointer["Nt"#y]= FP_##y;
??????? 現在來說說這個宏,這個也是這篇文章中的一個重點。宏其實可以認為是一個模板,對于使用宏的地方,編譯器會將其原封不動的替換到使用該宏處,這個特點和內聯函數(inline)很像(但是VC的內聯卻不是人能控制的,編譯器會根據它的判斷來決定是否將你定義為inline的函數內容替換到調用處)。首先,我們要定義一個FuncPointer結構體對象,如果你在宏定義這個對象如下:FuncPointer FP;則在編譯時報很多錯,錯誤的原因就是一個變量名被定義多次,想想為什么?就是因為我們多次調用HOOKNTITEM,編譯器也多次將FuncPointer FP插入到調用處。結果展開后如下
{FuncPointer FP;……FuncPointer FP;……FuncPointer FP;……
}
??????? 為了讓每次定義的變量名不一樣,我們使用了結合傳入參數的方法,故定義為:
FuncPointer FP_##y
??????? 該宏之后的內容很淺顯易懂了。
??????? 現在開始我們的HOOK操作
BOOL HookRegApi()
{BOOL bSuc = FALSE;do {GetHookNtRegFuncInfo();DetourTransactionBegin();DetourUpdateThread(GetCurrentThread());for ( MapFuncPointerIter it = g_MapRegFuncPointer.begin(); it != g_MapRegFuncPointer.end(); it++ ) {// 必須要加以判斷,否則之后不應該是失敗的也失敗了if ( NULL != it->second.lpOri && NULL != it->second.lpNew ) {LONG lRes = DetourAttach(&(it->second.lpOri), it->second.lpNew );}}DetourTransactionCommit();bSuc = TRUE;} while (0);return bSuc;
}
??????? 該函數也很簡單,但是其中有個細節一定要注意,那就是要判斷原函數地址和修改后函數地址是否為空。使用Detours進行Hook特別要注意這點,否則會出現你也想不到的問題。當時我寫這塊時,偽代碼可以如下表示
HOOK(CreateKey)
HOOK(OpenKeyEx)
HOOK(OpenKey)
??????? 結果我發現NtCreateKey函數被Hook了,而OpenKey卻沒有被Hook,出錯的原因是:NtOpenKeyEx這個函數在vista及其以上系統才有,而我的開發環境是Xp,于是DetourFindFunction尋找到NtOpenKeyEx函數的入口地址為NULL,調用DetourAttach(NULL,lpNewFuncAddr)失敗后,所有理論上應該成功的Hook(如Hook(OpenKey),NtOpenKey在xp上是存在的)也都會失敗。當然最好還可以判斷之前一步DetourAttach的返回值是否成功來決定是否繼續Hook。
??????? 反Hook的代碼如下
BOOL UnHookRegApi()
{BOOL bSuc = FALSE;do {DetourTransactionBegin();DetourUpdateThread(GetCurrentThread());for ( MapFuncPointerIter it = g_MapRegFuncPointer.begin(); it != g_MapRegFuncPointer.end(); it++ ) {// 必須要加以判斷,否則之后不應該是失敗的也失敗了if ( NULL != it->second.lpOri && NULL != it->second.lpNew ) {LONG lRes = DetourDetach(&(PVOID&)it->second.lpOri, it->second.lpNew );}}DetourTransactionCommit();bSuc = TRUE;} while (0);return bSuc;
}
??????? 為了之后方便調用真實函數,我定義了一個宏
// 獲取原始函數入口
#define GETORIFUNC(x)\( (pfn_Nt##x)g_MapRegFuncPointer["Nt"#x].lpOri )
總結
以上是生活随笔為你收集整理的一种注册表沙箱的思路、实现——Hook Nt函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一种注册表沙箱的思路、实现——注册表的一
- 下一篇: 一种注册表沙箱的思路、实现——研究Rea