电竞比分网-中国电竞赛事及体育赛事平台

分享

【Hook技術】64位下Hook NtOpenProcess的實現(xiàn)進程保護 + 源碼 (升級篇)

 盛夏流年閃耀 2013-09-11

在我的上一篇文章中【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 Code

e.程序運行效果讀,第一張通過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

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多