• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            旅途

            如果想飛得高,就該把地平線忘掉

            跨進(jìn)程API Hook(初稿)


            跨進(jìn)程API Hook(初稿)

            什么是“跨進(jìn)程 API Hook”?
            眾所周知Windows應(yīng)用程序的各種系統(tǒng)功能是通過(guò)調(diào)用API函數(shù)來(lái)實(shí)現(xiàn)。API Hook就是給系統(tǒng)的API附加上一段小程序,它能監(jiān)視甚至控制應(yīng)用程序?qū)PI函數(shù)的調(diào)用。所謂跨進(jìn)程也就是讓自己的程序來(lái)控制別人程序的API調(diào)用了。

            API Hook 理論
            通 過(guò)對(duì)Win32 PE文件的分析(如果你還不熟悉PE文件格式,可以看看Iczelion的PE教程或者LUEVELSMEYER的<>)。 我們知道在PE文件中的IMPORT TABLE內(nèi)存儲(chǔ)著API函數(shù)的很多信息。其中包括API的函數(shù)名,調(diào)用地址等等。而操作系統(tǒng)在執(zhí)行PE文件時(shí)會(huì)先 將其映射到內(nèi)存中。在映射的同時(shí)還會(huì)把當(dāng)前版本操作系統(tǒng)中API函數(shù)的入口地址寫(xiě)入IMPORT TABLE中一組與API調(diào)用相關(guān)的結(jié)構(gòu)體內(nèi),用于該應(yīng) 用程序的API調(diào)用。 當(dāng)應(yīng)用程序調(diào)用API時(shí),他會(huì)在自己內(nèi)存映像里尋找API的入口地址,然后執(zhí)行CALL指令。如此一來(lái),我們通過(guò)修改應(yīng)用程序內(nèi)存 映像的IMPORT TABLE中API函數(shù)的入口地址,就可以達(dá)到重定向API的目的。將API地址改為我們自己函數(shù)的地址,這樣我們的函數(shù)就可以完成 對(duì)API的監(jiān)視和控制了。

            API Hook 的實(shí)現(xiàn)
            /* 1 */HANDLE hCurrent = GetModuleHandle(NULL);
            /* 2 */IMAGE_DOS_HEADER *pidh;
            /* 3 */IMAGE_NT_HEADERS *pinh;
            /* 4 */IMAGE_DATA_DIRECTORY *pSymbolTable;
            /* 5 */IMAGE_IMPORT_DESCRIPTOR *piid;
             
            /* 6 */pidh = (IMAGE_DOS_HEADER *)hCurrent; 
            /* 7 */pinh = (IMAGE_NT_HEADERS *)((DWORD)hCurrent + pidh->e_lfanew);
            /* 8 */pSymbolTable = &pinh->OptionalHeader.DataDirectory[1];
            /* 9 */piid =(IMAGE_IMPORT_DESCRIPTOR *)((DWORD)hCurrent +  pSymbolTable->VirtualAddress);
            /*10 */do {
            /*11 */    IMAGE_THUNK_DATA *pitd,*pitd2;
            /*12 */    pitd = (IMAGE_THUNK_DATA *)((DWORD)hCurrent + piid->OriginalFirstThunk);
            /*13 */    pitd2 = (IMAGE_THUNK_DATA *)((DWORD)hCurrent + piid->FirstThunk);
            /*14 */    do {
            /*15 */ IMAGE_IMPORT_BY_NAME *piibn;
            /*16 */ piibn = (IMAGE_IMPORT_BY_NAME *)((DWORD)hCurrent +  *((DWORD *)pitd));
            /*17 */ PROC *ppfn = (PROC *)(pitd2->u1.Function);
            /*18 */ if (!strcmp("MessageBoxW",(char *)piibn->Name)) {
            /*19 */     oldMsg = (MsgBoxType)(ppfn);
            /*20 */     DWORD addr = (DWORD)MyMessage;
            /*21 */     DWORD written = 0;
                  /* 改變內(nèi)存讀寫(xiě)狀態(tài) */
            /*22 */     DWORD oldAccess;
            /*23 */     VirtualProtect(&pitd2->u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&oldAccess);
            /*24 */     APIAddress = (DWORD)&pitd2->u1.Function;
                  /* 向內(nèi)存映像寫(xiě)入數(shù)據(jù) */
            /*25 */     WriteProcessMemory(GetCurrentProcess(),&pitd2->u1.Function, &addr,sizeof(DWORD), &written);
            /*26 */ }
            /*27 */ pitd++;pitd2++;
            /*28 */    } while (pitd->u1.Function);
             
            /*29 */    piid++;
            /*30 */} while (piid->FirstThunk + piid->Characteristics 
              + piid->ForwarderChain + piid->Name + piid->TimeDateStamp);
            分析:
            尋覓IMPORT TALBE
            在/*1*/ 中我們使用GetModuleHandle(NULL)來(lái)返回當(dāng)前進(jìn)程在內(nèi)存中映像的基地址。但這個(gè)值在文檔中僅僅被描述為 "a module handle for the specified module",雖然他確實(shí)是進(jìn)程內(nèi)存映像的基地址。如果你不太放心的話也可以 使用,GetModuleInformation函數(shù)來(lái)獲得基地址,只不過(guò)你要額外包含psapi.h和psapi.lib了(這個(gè)庫(kù)在VC6里沒(méi)有,所 以我就沒(méi)有用這個(gè)函數(shù)了)。在/* 6 */里我們先找到IMAGE_DOS_HEADER結(jié)構(gòu),他的起始地址就是映像的基地址。/*7*/通過(guò) IMAGE_DOS_HEADER給出的PE文件頭的偏移量,找到IMAGE_NT_HEADERS結(jié)構(gòu)。順藤摸瓜,IMAGE_NT_HEADERS里 的OptionalHeader中的DataDirectory數(shù)組里的第二個(gè)元素正是指向我們想要的IMPORT TABLE的地址。在/*9*/中我們將其轉(zhuǎn)化為一個(gè)IMAGE_IMPORT_DESCRIPTOR的結(jié)構(gòu)指針存入piid中。

            替換的API函數(shù)入口地址
            在/*12*/ 和/*13*/中我們分別取得OriginalFirstThunk和FirstThunk結(jié)構(gòu),用于以后得到API函數(shù)的名稱和入口地址。/*10*/ 的do循環(huán)讓我們遍歷每一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)也就是應(yīng)用程序引用的每個(gè)DLL。在/*14*/的循環(huán)中我們遍歷DLL 中的IMAGE_THUNK_DATA結(jié)構(gòu)來(lái)一一查詢API的信息。/*16*/中我們將OriginalFirstThunk轉(zhuǎn)換為 IMAGE_IMPORT_BY_NAME結(jié)構(gòu)用于獲得API函數(shù)的名稱進(jìn)行比對(duì)。在/*18*/我們找到MessageBoxW函數(shù)之后,在 /*19*/保存其原始入口地址便于以后恢復(fù)時(shí)使用。在/*23*/我們需要用VirtualProtect改變一下內(nèi)存區(qū)域的讀寫(xiě)性,因?yàn)橐话銘?yīng)用程序 的映像都是只讀的,直接寫(xiě)入會(huì)造成一個(gè)非法訪問(wèn)的異常出現(xiàn)。在/*25*/我們寫(xiě)入自己函數(shù)的地址。

            這樣就基本完成一個(gè)API函數(shù)的重定向。

            其他
            恢復(fù)函數(shù)的API入口地址相對(duì)比較簡(jiǎn)單。只要把保存的值再寫(xiě)回去就可以了。上面的程序中/*24*/我用APIAddress保存了存有MessageBoxW入口地址的地方的地址,便于以后調(diào)用WriteProcessMemory恢復(fù)時(shí)使用。

            跨進(jìn)程理論
            我 們要用自己的函數(shù)來(lái)替代別人程序里的API函數(shù),但我們的函數(shù)與別人的程序處于不同的進(jìn)程空間內(nèi)啊。不同的進(jìn)程空間是不能相互調(diào)用函數(shù)的。因此我們要想辦 法把自己的函數(shù)放入別人的進(jìn)程空間去。這時(shí)我們就需要使用DLL injection技術(shù)了。如果你對(duì)她還不是十分熟悉的話,建議看看 Jeffrey Richter大師的< >,也可以參考陳寬達(dá)先生的<>。

            簡(jiǎn) 而言之,DLL injection就是想辦法讓對(duì)方的進(jìn)程加載我們的一個(gè)DLL程序,把需要替換的函數(shù)放在我們這個(gè)DLL里。如此一來(lái),我們的函數(shù)就進(jìn) 入了別人的進(jìn)程空間了。DLL injection方法很多,Richter大師在書(shū)中對(duì)各方法利弊有詳細(xì)解釋,陳寬大先生的書(shū)中也有深入的分析。我在這 里使用SetWindowsHookEx函數(shù)來(lái)達(dá)到目的。主要有這幾個(gè)原因: 1, 不用重新啟動(dòng)系統(tǒng),調(diào)試方便。2, 可以利用消息循環(huán)機(jī)制進(jìn)行兩個(gè)進(jìn) 程之間的通信,可以較好的掌握Hook的狀態(tài)。便于安裝與卸載。

            SetWindowsHookEx之所以能完成 DLL injection是因?yàn)樗o一個(gè)應(yīng)用程序某個(gè)環(huán)節(jié)加上一個(gè)Hook,而Hook就要有Hook Procedure也就是Hook函數(shù)。如果 這個(gè)Hook函數(shù)在一個(gè)DLL中,那么系統(tǒng)就會(huì)把這個(gè)DLL加載到SetWindowsHookEx的目標(biāo)進(jìn)程上。從而也就達(dá)到了我們 DLL injection的目的了。當(dāng)然這里我們會(huì)用WH_GETMESSAGE的Hook進(jìn)行injection,因?yàn)檫@個(gè)Hook可以用來(lái)監(jiān)視目標(biāo) 進(jìn)程的消息循環(huán)方便我們的進(jìn)程與目標(biāo)進(jìn)程通信。 

            跨進(jìn)程的實(shí)現(xiàn)和幾點(diǎn)注意
            /* DllPart.Dll */
            #include 
            #include 
            #include 
            #include 
            typedef (WINAPI *MsgBoxType)(HWND,LPCWSTR,LPCWSTR,UINT); 
            MsgBoxType oldMsg;  /*API原入口地址*/
            DWORD APIAddress; /*存儲(chǔ)API入口地址的地方的地址*/
            int WINAPI  MyMessage(HWND hWnd ,LPCWSTR M1,LPCWSTR M2, UINT M3) {
             /* 這是用來(lái)替換的函數(shù) */
             return oldMsg(hWnd,buf,M2,MB_OK);
            }
            const char szApp[] = "DllPart.dll";
            HHOOK hHook; /*Hook的句柄*/
            HMODULE hInst; /*DLL 模塊句柄,用于SetWindowsHookEx函數(shù)*/
            HWND hTarget; /*目標(biāo)窗口句柄*/
            /*DLL 入口*/
            BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID lpvReserved)
            {
                hInst = inst;
                switch (reason) {
             case DLL_PROCESS_ATTACH:
                 /*調(diào)試信息,表示DLL已經(jīng)加載*/
                 MessageBox(NULL,"DLL_PROCESS_ATTACH",szApp,MB_OK);
                 break;
             case DLL_PROCESS_DETACH:
                 /*調(diào)試信息,表示DLL已經(jīng)卸載*/
                 MessageBox(NULL,"DLL_PROCESS_DETACH",szApp,MB_OK);
                 break;
                }
                return true;
            }
            /*顯示GetLastError的信息*/
            void showerr(const char *m) {
                char message[255];
                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError()
             ,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,255, 0);
                MessageBox(NULL,message,m,MB_OK);
            }
            //-----------------------
            void UnHookApi() {
             /*卸載API Hook用*/
            }
            void HookApi() {
             /*加載API Hook同上面介紹的函數(shù)一樣*/
            }
            //-----------------------
            /*用于WH_GETMESSAGE的Hook Procedure*/
            LRESULT CALLBACK GetMsgProc(int nCode,WPARAM wParam, LPARAM lParam) {
             if (nCode == HC_ACTION) {
                 MSG *msg = (MSG *)lParam;
            &n
              if (msg->message == WM_CHAR) {
                  if (msg->wParam == 'h') HookApi();
                  if (msg->wParam == 'u') UnHookApi();
                 }
             }
                return CallNextHookEx(hHook,nCode,wParam,lParam);
            }
            extern "C" __declspec(dllexport) SetAPIHook(HWND handle) {
                DWORD ThreadId = GetWindowThreadProcessId(handle, NULL);
                hTarget = handle;
                MessageBox(NULL, "Enabling CallWndProc Hook", szApp, MB_OK);
                hHook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInst,ThreadId); 
                if (hHook) {
             MessageBox(NULL,"Hook OK!", szApp, MB_OK);
                } else {
             showerr("SetWindowsHookEx");
                }
            }
            extern "C" __declspec(dllexport) UnHookAPIHook() {
                MessageBox(NULL, "Disenabling CallWndProc Hook", szApp, MB_OK);
                if (UnhookWindowsHookEx(hHook)) {
                    MessageBox(NULL,"UnHook OK!", szApp, MB_OK); 
                } else {
             showerr("UnHookWindowsHookEx");
                }
            }
            分析
            幾個(gè)需要注意的問(wèn)題
            SetAPIHook 和UnHookAPIHook是我們自己進(jìn)程調(diào)用的用來(lái)加載WH_GETMESSAGE Hook的函數(shù)。由于我們的程序要用LoadLibrary加載 這個(gè)Dll因此這兩個(gè)函數(shù)要用__declspec(dllexport)修飾,使其成為導(dǎo)出函數(shù),才能被GetAddressProc函數(shù)找到。加上  extern "C"是讓編譯器使用C語(yǔ)言編碼方式。因?yàn)镃++編譯器會(huì)進(jìn)行Dynamic Binding(C++函數(shù)重載的實(shí)現(xiàn)),將函數(shù)的參數(shù)類 型附加到名稱上。是函數(shù)的導(dǎo)出名看起來(lái)像SetAPIHook@XYTZX之類的,不利于GetAddressProc進(jìn)行引用。因此使用 extern "C"讓編譯器不使用Dynamic Binding,自然使用extern"C"的函數(shù)也就不能被重載了。

            不要忘記在GetMsgProc最后要調(diào)用CallNextHookEx函數(shù),保證Hook鏈的完整性。

            一 定要在Hook Procedure中調(diào)用HookApi和UnHookApi函數(shù),因?yàn)楸4鍭PI入口地址的地方在目標(biāo)進(jìn)程中,你必須在目標(biāo)進(jìn)程的進(jìn)程 空間內(nèi)完成卸載操作,不能在UnHookAPIHook或是SetAPIHook函數(shù)中調(diào)用,因?yàn)閁nHookAPIHook是我們的進(jìn)程調(diào)用的,因此在 我們的進(jìn)程空間中。在這里使用UnHookApi會(huì)造成一個(gè)非法訪問(wèn)的錯(cuò)誤。而使用HookApi會(huì)給自己的DLL加上API Hook。

            SetWindowsHookEx的最后參數(shù)是ThreadId不是Handle,因此要通過(guò)調(diào)用GetWindowThreadProcessId轉(zhuǎn)換一下。 

            在跨進(jìn)程API HOOK時(shí)可能用到的其他技術(shù)
            主進(jìn)程與目標(biāo)進(jìn)程的信息交互和共享
            由 于使用了WH_GETMESSAGE鉤子我們可以利用Windows消息機(jī)制實(shí)現(xiàn)進(jìn)程間通訊。需要注意的是應(yīng)該使用PostThreadMessage來(lái) 發(fā)送讓W(xué)H_GETMESSAGE得到的消息而不是SendMessage或者PostMessage,因?yàn)楹髢蓚€(gè)是用來(lái)給窗口發(fā)送消息的。而我們的 WH_GETMESSAGE是Hook在線程上面的,因此需使用PostThreadMessage.

            傳遞不太大的數(shù)據(jù)可以使用 WM_COPYDATA消息來(lái)進(jìn)行。同樣也應(yīng)該注意,如果使用MFC的窗口過(guò)程獲得消息就需要用SendMessage發(fā)送了。WM_COPYDATA的 使用相對(duì)簡(jiǎn)單可以參考MSDN的文檔。也可以參考附錄里的程序Hook.cpp的showerr函數(shù)部分。

            如果傳遞較大的數(shù)據(jù)或者希望數(shù)據(jù)共享比較方便可以開(kāi)辟共享內(nèi)存來(lái)進(jìn)行數(shù)據(jù)共享。這里簡(jiǎn)單分析一下使用共享內(nèi)存的代碼 

            HANDLE hMap;
            switch (reason) {
                case DLL_PROCESS_ATTACH:
                /*創(chuàng)建/打開(kāi)共享內(nèi)存區(qū)域*/
                hMap = CreateFileMapping((HFILE *)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(GLOBALDATA),ID_MAP);
                pg_data = (GLOBALDATA*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0 ,0 ,0);
                if (!pg_data) {
             MessageBox(NULL,"無(wú)法建立共享內(nèi)存,程序終止!",szApp,MB_OK);
             if (hMap) {
                 CloseHandle(hMap);
                 hMap = NULL;
                 return 0;
                   }
                }
                pg_data->hInst = hInst;
                showerr("共享內(nèi)存映像文件");
                showerr("DLL裝載中...",FALSE);
                break;
                case DLL_PROCESS_DETACH:
                if (pg_data) {
                    UnmapViewOfFile(pg_data);
             pg_data = NULL;
                }
                if (hMap) {
             CloseHandle(hMap);
             hMap = NULL;
                 }
                break;
            }

            上 面的代碼通過(guò)CreateFileMapping建立共享區(qū)域。將其第一個(gè)參數(shù)設(shè)置為0xFFFFFFFF使其能創(chuàng)建一個(gè)內(nèi)存共享區(qū)域而不是文件。并標(biāo)記 為可讀寫(xiě)的(PAGE_READWRITE).其大小為我們定義的結(jié)構(gòu)體GLOBALDATA的大小。最后的ID_MAP是一個(gè)用來(lái)標(biāo)示這個(gè)區(qū)域的字符 串。打開(kāi)或者創(chuàng)建完共享區(qū)域后,我們用MapViewOfFile來(lái)獲得這個(gè)區(qū)域的地址。之后就可以直接使用pg_data來(lái)操作共享區(qū)域了。不要忘記在 DLL退出的時(shí)候安全的刪除共享區(qū)域釋放內(nèi)存。 
            消息等待與安全卸載
            在我們卸載WH_GETMESSAGE鉤子之前必須先把目標(biāo)程序的 API調(diào)用恢復(fù)正常。我們不能再調(diào)用UnHookApi之后就立刻調(diào)用UnhookWindowsHookEx,因?yàn)楹苡锌赡躑nHookApi還沒(méi)來(lái)得 急完成API入口地址的恢復(fù)操作,WH_GETMESSAGE鉤子就已經(jīng)被卸載了。因此需要等待一段時(shí)間,等UnHookApi完成了恢復(fù)操作在調(diào)用 UnhookWindowsHookEx。以防錯(cuò)誤發(fā)生。

            extern "C" __declspec(dllexport) void UnHookAPIHook() {
                /*向目標(biāo)線程發(fā)送消息進(jìn)行API UNHOOK*/
                PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);
                showerr("WM_DISABLEAPIHOOK");
                /*等待目標(biāo)進(jìn)程返回WM_UNHOOKOK消息,確認(rèn)可以將WH_GETMESSAGE的HOOK去掉*/
                
                MSG Msg;
                do {
                    GetMessage(&Msg,NULL,0,0);
                }while(Msg.message !=  WM_UNHOOKOK);
                UnhookWindowsHookEx(pg_data->hHook);
                PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOKOK,(WPARAM)GetCurrentThreadId(),0);
                showerr("UnHookWindowsHookEx");
            }
            上面的代碼中我們使用一個(gè)含有GetMessage的循環(huán)來(lái)等待消息的到達(dá),一旦UnHookApi完成他就會(huì)發(fā)送WM_UNHOOKOK消息。等我們接收到消息確認(rèn)一切安全了在來(lái)卸載WH_GETMESSAGE鉤子。 
            弄清消息對(duì)象
            我 們一定要清楚代碼是在主程序進(jìn)程空間中執(zhí)行的還是在目標(biāo)程序進(jìn)程空間中執(zhí)行的。像上面的UnHookAPIHook函數(shù)就是通過(guò)主程序調(diào)用的,因此在主程 序進(jìn)程空間中執(zhí)行。這樣一來(lái)用來(lái)恢復(fù)目標(biāo)程序API信息的UnHookApi完成后就應(yīng)該向主程序發(fā)送消息,而不是目標(biāo)程序。

            目標(biāo)進(jìn)程加載了其他DLL
            如果目標(biāo)進(jìn)程動(dòng)態(tài)加載了其他的DLL文件,我們必須監(jiān)視LoadLibrary函數(shù)。保證DLL中的API入口地址也被正確修改。防止出現(xiàn)混亂的情況。我從LoadLibrary獲得DLL的路徑用于GetModuleHandle來(lái)取得他的ImageBase的地址。

            不知道文章寫(xiě)的如何,希望大家能多給些批評(píng)意見(jiàn)。發(fā)現(xiàn)問(wèn)題我馬上改正
            Email: detrox@yang.com.cn

            參考資料
            < >, Jeffrey Richter, Microsoft Press

            <>,陳寬達(dá),華中科大出版社

            <>, LUEVELSMEYER

            <>, Iczelion

            附:跨進(jìn)程APIHook的例子
            先打開(kāi)一個(gè)記事本程序并輸入幾個(gè)字符,運(yùn)行下面的程序,加載APIHook.之后在記事本的文件菜單中選擇新建就會(huì)看到API Hook將MessageBoxW 函數(shù)Hook的結(jié)果了.
            代碼在WinXP SP1 + VC6.0測(cè)試成功。

            下載源代碼

            (特別感謝老羅的代碼著色器,比我自己那個(gè)好多了)

            這是DLL的程序,Hook.dll
            #include 
            #include 
            #include 
            #include 
            #include "mydef.h"

            const char szApp[] = "Hook.dll"; /*應(yīng)用程序名稱*/
            HANDLE hMap;/*在共享內(nèi)存映像的句柄*/
            GLOBALDATA *pg_data; /*在共享內(nèi)存中的全局?jǐn)?shù)據(jù)*/
            LRESULT CALLBACK GetMsgProc(int,WPARAM, LPARAM);

            /*顯示GetLastError指出的錯(cuò)誤*/
            void showerr(const char *m, BOOL GetError = TRUE) {
                char message[127];
                char buf[255];
                COPYDATASTRUCT cds;
                if (GetError) 
                    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0
              ,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,127, 0);
                else 
                    *message = 0;
                if (Get
            CurrentThreadId() != pg_data->idMain)
                    sprintf(buf,"目標(biāo)程序空間DLL: %-30s [%-40s]",m, message);
                else
                    sprintf(buf,"主程序空間DLL  : %-30s [%-40s]",m, message);
                cds.lpData = buf;
                cds.cbData = sizeof(buf);
                cds.dwData = 0;
             
                SendMessage(pg_data->hWndMain,WM_COPYDATA,(WPARAM)pg_data->hWndTarget,(LPARAM)&cds);
              
                SetLastError(0);
            }
            int WINAPI MyMessageBoxW(HWND hWnd ,LPCWSTR M1,LPCWSTR M2, UINT M3) {
                wchar_t buf[255];
                swprintf(buf,L"!!這個(gè)窗口的API被Hook了!! HWND: 0x%08X Message: %s Caption: %s"
                    ,(DWORD *)hWnd
                    , M1
                    , M2);
                pg_data->oldAPIFunction(hWnd,buf,M2,MB_OK);
                return pg_data->oldAPIFunction(hWnd,M1,M2,M3);
            }

            /*DLL 入口函數(shù)*/
            BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason,LPVOID lpvReserved)
            {
                switch (reason) {
                case DLL_PROCESS_ATTACH:
                    /*創(chuàng)建/打開(kāi)共享內(nèi)存區(qū)域*/
                    hMap = CreateFileMapping((HFILE *)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(GLOBALDATA),ID_MAP);
                    pg_data = (GLOBALDATA*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0 ,0 ,0);
                    if (!pg_data) {
                       MessageBox(NULL,"無(wú)法建立共享內(nèi)存,程序終止!",szApp,MB_OK);
                       if (hMap) {
                           CloseHandle(hMap);
                           hMap = NULL;
                           return 0;
                        }
                    }
                    pg_data->hInst = hInst;
                    showerr("共享內(nèi)存映像文件");
                    showerr("DLL裝載中...",FALSE);
                    break;
                case DLL_PROCESS_DETACH:
                    showerr("DLL卸載中...",FALSE);
                    if (pg_data) {
                        UnmapViewOfFile(pg_data);
                        pg_data = NULL;
                    }
                    if (hMap) {
                        CloseHandle(hMap);
                        hMap = NULL;
                    }
                    break;
                }

             return true;
            }
            /*卸載API Hook*/
            void UnHookApi() {
                DWORD written = 0;
                DWORD oldaddrAPIFunction = (DWORD)pg_data->oldAPIFunction;
                WriteProcessMemory(GetCurrentProcess(),(DWORD *)pg_data->addrAPIEntryPoint
                    , &oldaddrAPIFunction,sizeof(DWORD), &written);
                showerr("WriteProcessMemory on UnHook");
                /*向主線程發(fā)送 API UNHOOK 處理完畢的消息*/
                PostThreadMessage(pg_data->idMain,WM_UNHOOKOK,0,0);
            }

            /*加載API Hook*/
            void HookApi(const char* szApiName, tAPIFunction newAddr, DWORD ImageBase) {
                /*這段代碼請(qǐng)參考文章中的分析*/
                IMAGE_DOS_HEADER *pidh;
                IMAGE_NT_HEADERS *pinh;
                IMAGE_DATA_DIRECTORY *pSymbolTable;
                IMAGE_IMPORT_DESCRIPTOR *piid;
              
                pidh = (IMAGE_DOS_HEADER *)ImageBase;    
                pinh = (IMAGE_NT_HEADERS *)((DWORD)ImageBase + pidh->e_lfanew);
                pSymbolTable = &pinh->OptionalHeader.DataDirectory[1];
                piid =(IMAGE_IMPORT_DESCRIPTOR *)((DWORD)ImageBase +  pSymbolTable->VirtualAddress);

                do {
                    IMAGE_THUNK_DATA *pitd_org,*pitd_1st;
                    pitd_org = (IMAGE_THUNK_DATA *)((DWORD)ImageBase + piid->OriginalFirstThunk);
                    pitd_1st = (IMAGE_THUNK_DATA *)((DWORD)ImageBase + piid->FirstThunk);
                    do {
                        IMAGE_IMPORT_BY_NAME *piibn;
                        piibn = (IMAGE_IMPORT_BY_NAME *)((DWORD)ImageBase +  *((DWORD *)pitd_org));
                        PROC *pAPIFunction = (PROC *)(pitd_1st->u1.Function);
                        if (!strcmp(szApiName,(char *)piibn->Name)) {
                            DWORD addrNewAPIFunction = (DWORD)MyMessageBoxW;
                            DWORD written = 0;
                            DWORD oldAccess;

                            pg_data->oldAPIFunction = (tAPIFunction)(pAPIFunction);
                            /*Change Memeory State*/
                            VirtualProtect(&pitd_1st->u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&oldAccess);
                            showerr("VirtualProtect");
                            pg_data->addrAPIEntryPoint = (DWORD)&pitd_1st->u1.Function;
                            /*Write Process Memory*/
                            WriteProcessMemory(GetCurrentProcess(),&pitd_1st->u1.Function
                                , &addrNewAPIFunction,sizeof(DWORD), &written);
                            showerr("WriteProcessMemory on Hook");
                        }
                        pitd_org++;
                        pitd_1st++;
                    } while (pitd_1st->u1.Function);
                   
                    piid++;
                } while (piid->FirstThunk + piid->Characteristics 
             + piid->ForwarderChain + piid->Name + piid->TimeDateStamp);
            }

            //-----------------------
            extern "C" __declspec(dllexport) BOOL SetAPIHook(HWND _target) {
                pg_data->hHook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,pg_data->hInst,pg_data->idTarget);    
                showerr("SetWindowsHookEx");
                /*向目標(biāo)線程發(fā)送消息進(jìn)行API HOOK*/
                if (pg_data->hHook) {
                    PostThreadMessage(pg_data->idTarget,WM_ENABLEAPIHOOK,0,0);
                } else {
                    return FALSE;
                }
                showerr("WM_ENABLEAPIHOOK");
                return TRUE;
            }

            extern "C" __declspec(dllexport) void UnHookAPIHook() {
                /*向目標(biāo)線程發(fā)送消息進(jìn)行API UNHOOK*/
                PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);
                showerr("WM_DISABLEAPIHOOK");
                /*等待目標(biāo)進(jìn)程返回WM_UNHOOKOK消息,確認(rèn)可以將WH_GETMESSAGE的HOOK去掉*/
                MSG Msg;
                do {
                    GetMessage(&Msg,NULL,0,0);
                }while(Msg.message !=  WM_UNHOOKOK);

                UnhookWindowsHookEx(pg_data->hHook);
                PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOKOK,(WPARAM)GetCurrentThreadId(),0);
                showerr("UnHookWindowsHookEx");
            }

            LRESULT CALLBACK GetMsgProc(int nCode,WPARAM wParam, LPARAM lParam) {
                if (nCode == HC_ACTION) {
                    MSG *msg = (MSG *)lParam;
                 
                    if (msg->message == WM_ENABLEAPIHOOK) {
                        HookApi("MessageBoxW",MyMessageBoxW,(DWORD)GetModuleHandle(NULL));
                    }
                    if (msg->message == WM_DISABLEAPIHOOK) {
                        UnHookApi();
              ;      }
                    if (msg->message == WM_DESTROY) {
                        showerr("目標(biāo)進(jìn)程退出!",FALSE);
                    }
                }
                return CallNextHookEx(pg_data->hHook,nCode,wParam,lParam);
            }
             
            這個(gè)是主程序的關(guān)鍵部分 HookGui.cpp
            用MFC建立一個(gè)窗口程序,包含兩個(gè)按鈕和一個(gè)ListBox

            typedef void (*PUnHookAPIHook)();
            typedef BOOL (*PSetAPIHook)(HWND);
            HMODULE hDll = NULL;
            HWND hNotePad = NULL;
            PSetAPIHook SetAPIHook;
            PUnHookAPIHook UnHookAPIHook;
            GLOBALDATA *pg_data; /*在共享內(nèi)存中的全局?jǐn)?shù)據(jù)*/
            HANDLE hMap; /*在共享內(nèi)存映像的句柄*/
            int CHookGUIDlg::showerr(const char* m) {
                char message[127];
                char buf[255];
                int errId = GetLastError();
                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0
             ,errId,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,127, 0);
                sprintf(buf,"主程序         : %-30s [%-40s] ",m, message);
                c_List1.InsertString(c_List1.GetCount(),buf);
                UpdateData(FALSE);
                return errId;
            }

            void CHookGUIDlg::OnSetapihook() 
            {
                // TODO: Add your control notification handler code here
                hDll = LoadLibrary("Hook.dll");
                showerr("LoadLibrary");
                hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,ID_MAP);
                showerr("OpenFileMapping");    
                pg_data = (GLOBALDATA *)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);
                showerr("MapViewOfFile");    
                if (!pg_data) {
                    MessageBox("不能打開(kāi)共享內(nèi)存程序終止!");
                    return;
                }
                SetAPIHook = (PSetAPIHook)GetProcAddress(hDll,"SetAPIHook");
                showerr("GetProcAddress-SetAPIHOOK");
               
                pg_data->hWndTarget = ::FindWindow("NotePad",NULL);
                pg_data->hWndMain = m_hWnd;
                pg_data->idMain = GetWindowThreadProcessId(m_hWnd,NULL);
                pg_data->idTarget = GetWindowThreadProcessId(pg_data->hWndTarget,NULL);
                if (!showerr("FindWindow")) {
                    if (SetAPIHook) { 
                        if (SetAPIHook(hNotePad))
                            PostThreadMessage(pg_data->idTarget
               , WM_SETCALLERID,(LPARAM)GetCurrentThreadId(),0);
                        else {
                            MessageBox("SetWindowHookEx時(shí)出錯(cuò),程序終止!");
                            return;
                        }
              &n } else {
                        MessageBox("無(wú)法取得SetAPIHook函數(shù)!程序終止!");                    
                    }
                } else {
                        MessageBox("內(nèi)存中沒(méi)有找到NOTEPAD.EXE");            
                }
                c_SetApiHook.EnableWindow(FALSE);
                c_UnsetApiHook.EnableWindow();
            }

            void CHookGUIDlg::OnUnsetapihook() 
            {
                // TODO: Add your control notification handler code here
                if (hDll) {
                    if ( !IsWindow(pg_data->hWndTarget)) {
                        MessageBox("目標(biāo)進(jìn)程不在內(nèi)存中");
                        return;
                    }
                    UnHookAPIHook = (PUnHookAPIHook)GetProcAddress(hDll,"UnHookAPIHook");
                    showerr("GetProcAddress-UnHookAPIHook");
                    if (UnHookAPIHook) 
                        UnHookAPIHook();
                    FreeLibrary(hDll);
                    showerr("FreeLibrary");
                    hDll = NULL;
                } else {
                    MessageBox("請(qǐng)先加載DLL");
                }
                c_SetApiHook.EnableWindow();
                c_UnsetApiHook.EnableWindow(FALSE);
            }

            void CHookGUIDlg::OnOK() 
            {
                // TODO: Add extra validation here
                if (hDll) {
                    OnUnsetapihook();
                }
                CDialog::OnOK();
            }

            BOOL CHookGUIDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) 
            {
                // TODO: Add your message handler code here and/or call default
                c_List1.InsertString(c_List1.GetCount(),(char *)pCopyDataStruct->lpData);
                return CDialog::OnCopyData(pWnd, pCopyDataStruct);
            }

            posted on 2007-07-29 11:08 旅途 閱讀(1311) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 深入windows

            中文字幕乱码人妻无码久久| 99久久婷婷国产综合精品草原| 久久久久久久亚洲精品| 蜜臀久久99精品久久久久久| 久久精品aⅴ无码中文字字幕不卡| 久久精品无码专区免费青青| 久久久久久久综合综合狠狠| 久久久久人妻一区精品色| 国产成人99久久亚洲综合精品| 久久免费视频1| 久久se精品一区精品二区国产 | 2021久久精品国产99国产精品| 亚洲国产精品久久久久久| 久久亚洲精品国产精品婷婷| 亚洲成人精品久久| 漂亮人妻被黑人久久精品| 亚洲国产成人精品女人久久久 | 色婷婷久久久SWAG精品| 97久久超碰国产精品2021| 色狠狠久久综合网| 午夜精品久久久久久久无码| 久久91这里精品国产2020| 国产精品99久久精品| 伊人久久无码中文字幕| 日本欧美国产精品第一页久久| 青青青青久久精品国产h| 精品国产VA久久久久久久冰| 国内精品人妻无码久久久影院导航| 久久久久97国产精华液好用吗| 久久国产精品久久精品国产| 国产91色综合久久免费| 久久99国产精品尤物| 久久er99热精品一区二区| 久久久亚洲欧洲日产国码aⅴ| 性做久久久久久久久浪潮| 性做久久久久久免费观看| 久久久精品久久久久久 | 亚洲欧美日韩中文久久| 久久亚洲国产精品成人AV秋霞| 欧美久久亚洲精品| 亚洲国产天堂久久久久久|