|
在我的上一篇文章中【Hook技術】實現(xiàn)從"任務管理器"中保護進程不被關閉 + 附帶源碼 + 進程保護知識擴展 介紹了X86下基于IAT Hook技術,通過Hook OpenProcess來實現(xiàn)從任務管理器中保護進程,看到一些評論,有朋友問該代碼是否適用于64位系統(tǒng)? 答案是肯定的,需要修改兩個地方: a. 編譯時候,設置平臺為X64 b.修改SetWindowsHookEx第三個參數(shù)為0,關于這點,是因為64為下和32為下調(diào)用SetWindowsHookEx略有不同,官方關于該函數(shù)的有一段解析為: SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names. 如果你希望在X64下通過HOOK技術實現(xiàn)進程的保護,不推薦Hook OpenProcess,可以考慮通過Hook Ntdll的函數(shù)(NtOpenProcess)實現(xiàn),這也是樓主寫此文的目的的,介紹通過MHook實現(xiàn)對NtOpenProcess的hook實現(xiàn)進程的保護. 1. Hook技術基礎知識(Inline Hook) 在開始本文的實例前想先通過對Hook技術做些簡單的介紹,幫助大家更好的理解所謂的Hook技術,所謂的hook技術其實就是修改函數(shù)行為的一種技術,通過對函數(shù)行為的修改可以實現(xiàn)例如:文件的監(jiān)控/保護 , 進程的監(jiān)控/隱藏等,例如大多數(shù)的安全軟件都是基于這種技術實現(xiàn)的,還有些病毒木馬技術也會涉及到hook技術。一般的hook函數(shù)的流程: { 目標API } ----- 【 Hook API 】 ------- 修改函數(shù)入口前幾個字節(jié),添加跳轉指令 類似JMP DWORD Ptr Address \ { jump 我們的代碼處 } |- a. 執(zhí)行我們代碼 |- b. 修復Hook |- c. 調(diào)用目標API 通過修改目標函數(shù)的前幾個字節(jié),然后跳轉到我們的代碼執(zhí)行,等執(zhí)行完我們定制的代碼后,在調(diào)用真實的目標API返回結果給調(diào)用程序. 大多數(shù)的系統(tǒng)API,前幾個字節(jié)都是對堆棧的操作,而hook技術就是利用了這幾個字節(jié)實現(xiàn)jmp的,偽代碼描述: 目標函數(shù): mov edi, edi // HOOK Jmp DWORD PTR MyFunctionAddress jump后 MyFunctionAddress內(nèi)部邏輯處理push ebp // 堆棧操作 < ==========> xor ecx ,exc <=========> 修復原函數(shù)堆棧操作 { mov edi,edi push ebp,...}mov ebp, esp // 跳到原函數(shù)執(zhí)行JMP 【ADDRESS】xor ecx, ecx ==> 標記地址為【ADDRESS】這是一種比較常用的HOOK思路,還有修改函數(shù)中部或者尾部的,思路相同,patch的位置不同 還有中Hook的思路是通過“跳板”函數(shù)實現(xiàn),定制函數(shù)和目標函數(shù)之間的關系 { Hook Api } \ { Jump 定制函數(shù) } \ { jump Trampoline(跳板函數(shù)) } \ ______ { Call 目標函數(shù) } ------ { 結果返回給調(diào)用程序 } 成功Hook函數(shù)后,跳轉我們定制的函數(shù)中執(zhí)行,當我們定制的代碼執(zhí)行完后,并不是在函數(shù)內(nèi)部調(diào)用原目標函數(shù),而是調(diào)用一個叫Trampoline的函數(shù),Trampoline的任務就是平衡堆棧,然后執(zhí)行原目標函數(shù), 最后將結果返回給調(diào)用程序 例如: edi, edi addr1 customFunction ; //執(zhí)行完地址的邏輯后,跳到調(diào)用Trampoline函數(shù) ebp < ==== JUMP ====> addr2 ecx,ecx ebp, esp
addr2 ecx, ecx
Trampoline函數(shù):
edi, edi ebp { 平衡堆棧 } ebp, esp addr2 ===> 然后跳到原函數(shù)某地址執(zhí)行這種方法相對于第一種方式來說,安全了很多至少在多線程的環(huán)境下 ,一般trampoline跳轉函數(shù)都是被標記為naked的,很多情況都是通過匯編實現(xiàn),由自己編碼控制堆棧。 2. 實戰(zhàn),X64下Hook NtOpenProcess 本demo中使用的hook引擎是MHook,Mhook是開源的,采用的是第二種hook方式,相比于MinHook/easyHook來說,使用簡單,只導出兩個函數(shù): //安裝Hook//ppSystemFunction,原函數(shù)地址//pHookFunction ,定制的函數(shù)地址BOOL Mhook_SetHook(PVOID *ppSystemFunction, PVOID pHookFunction);//卸載HOOK//ppHookedFuntion.原函數(shù)地址BOOL Mhook_Unhook(PVOID *ppHookedFunction); a. 下載Mhook,新建一個win32 DLL工程,名稱:HookNtOpenProcessLib b. 聲明NtOpenProcess函數(shù)和我們定制的Hook_NtOpenProcess View Code定制的Hook_NtOpenProcess,設置進程句柄為NULL,保護所有進程,針對某個進程保護,請通過ProcesssHandler獲取PID然后做比較 //===========================================================//定制我們自己的NtOpenProcessULONG WINAPI Hook_pfnNtOpenProcess(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK AccessMask ,
__in PVOID ObjectAttributes,
__in PCLIENT_ID ClientId){ //ULONG result = _NtOpenProcess( ProcessHandle,AccessMask,ObjectAttributes,ClientId); //DWORD pid = GetProcessIdByHandle( ProcessHandle); //通過進程句柄獲取PID,然后驗證 //if(gProtectProcessID == pid ){ // return STATUS_ACCESS_DENIED; //}
//return result; //=================================== //簡單處理,直接設置ProcessHandle,保護所有
ProcessHandle = NULL; return _NtOpenProcess( ProcessHandle, AccessMask,ObjectAttributes,ClientId);
}c. 安裝消息鉤子,跟一篇博文一樣,通過SetWindowsHookEx,只是在調(diào)用該函數(shù)時候需要注意區(qū)別下32位系統(tǒng)和64位系統(tǒng)情況,例如: extern "C" __declspec(dllexport) BOOL InstallHook(DWORD pid)
{
BOOL bResult=FALSE; //這里需要注意X86和X64下處理是不一樣的
#ifdef _M_IX86
glhHook = SetWindowsHookEx(WH_SHELL,ShellHookProc,glhInstance, 0); #elif defined _M_X64
glhHook = SetWindowsHookEx(WH_SHELL,ShellHookProc,0, 0); //第三參數(shù)為0,而不是當前模塊的實例句柄
#endif
if(glhHook!=NULL)
{
gProtectProcessID = pid;
bResult=TRUE;
}
return bResult;
}d.C#調(diào)用HOOKNtOpenProcessLib.dll View Codee.程序運行效果讀,第一張通過ARK工具查看inline hook了NtOpenProcess,NtOpenProcess進入內(nèi)核后是通過調(diào)用ZwOpenProcess的,所以我們看到ZwOpenProcess也被Inline hook了,第2張通過任務管理器結束進程
關于程序中一些注意問題: 1. 編譯HookNtOpenProcessLib.dll時候,如果要運行在64位系統(tǒng)下,通過“配置管理器”設置下平臺X64(也就是你要編譯兩份DLL,一份是平臺為win32的,一個是X64下的) 2. 附件中C#程序,如果希望運行在32位和64位系統(tǒng)上,請通過“配置管理器”設置平臺為“AnyCPU” 3. 將編譯好的dll(32位和64位)的放在測試demo下,測試demo在調(diào)用InstallHook時候,內(nèi)部SetWindowsHookEx會根據(jù)當前平臺調(diào)用對應的HookNtOpenProcessLib.dll |
|
|