• <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>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運轉(zhuǎn),開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            跨進程API Hook

            Posted on 2009-11-06 12:05 S.l.e!ep.¢% 閱讀(870) 評論(0)  編輯 收藏 引用 所屬分類: RootKit

            【轉(zhuǎn)】跨進程API Hook

            什么是“跨進程APIHook”?

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

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

            6. /* 6 */pidh = (IMAGE_DOS_HEADER *)hCurrent;
            7. /* 7 */pinh = (IMAGE_NT_HEADERS *)((DWORD)hCurrent + pidh->e_lfanew);
            8. /* 8 */pSymbolTable = &pinh->OptionalHeader.DataDirectory[1];
            9. /* 9 */piid =(IMAGE_IMPORT_DESCRIPTOR *)((DWORD)hCurrent +? pSymbolTable->VirtualAddress);
            10. /*10 */do {
            11. /*11 */? ? IMAGE_THUNK_DATA *pitd,*pitd2;
            12. /*12 */? ? pitd = (IMAGE_THUNK_DATA *)((DWORD)hCurrent + piid->OriginalFirstThunk);
            13. /*13 */? ? pitd2 = (IMAGE_THUNK_DATA *)((DWORD)hCurrent + piid->FirstThunk);
            14. /*14 */? ? do {
            15. /*15 */ IMAGE_IMPORT_BY_NAME *piibn;
            16. /*16 */ piibn = (IMAGE_IMPORT_BY_NAME *)((DWORD)hCurrent +? *((DWORD *)pitd));
            17. /*17 */ PROC *ppfn = (PROC *)(pitd2->u1.Function);
            18. /*18 */ if (!strcmp("MessageBoxW",(char *)piibn->Name)) {
            19. /*19 */? ???oldMsg = (MsgBoxType)(ppfn);
            20. /*20 */? ???DWORD addr = (DWORD)MyMessage;
            21. /*21 */? ???DWORD written = 0;
            22. ? ? ? /* 改變內(nèi)存讀寫狀態(tài) */
            23. /*22 */? ???DWORD oldAccess;
            24. /*23 */? ???VirtualProtect(&pitd2->u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&oldAccess);
            25. /*24 */? ???APIAddress = (DWORD)&pitd2->u1.Function;
            26. ? ? ? /* 向內(nèi)存映像寫入數(shù)據(jù) */
            27. /*25 */? ???WriteProcessMemory(GetCurrentProcess(),&pitd2->u1.Function, &addr,sizeof(DWORD), &written);
            28. /*26 */ }
            29. /*27 */ pitd++;pitd2++;
            30. /*28 */? ? } while (pitd->u1.Function);

            31. /*29 */? ? piid++;
            32. /*30 */} while (piid->FirstThunk + piid->Characteristics
            33. ? + piid->ForwarderChain + piid->Name + piid->TimeDateStamp);
            復(fù)制代碼
            分析:
            尋覓IMPORT TALBE

            在/*1*/中我們使用GetModuleHandle(NULL)來返回當(dāng)前進程在內(nèi)存中映像的基地址。但這個值在文檔中僅僅被描述為"a module handle for the specified module",雖然他確實是進程內(nèi)存映像的基地址。如果你不太放心的話也可以使用,GetModuleInformation函數(shù)來獲得基地址,只不過你要額外包含psapi.h和psapi.lib了(這個庫在VC6里沒有,所以我就沒有用這個函數(shù)了)。在/* 6 */里我們先找到IMAGE_DOS_HEADER結(jié)構(gòu),他的起始地址就是映像的基地址。/*7*/通過IMAGE_DOS_HEADER給出的PE文件頭的偏移量,找到IMAGE_NT_HEADERS結(jié)構(gòu)。順藤摸瓜,IMAGE_NT_HEADERS里的OptionalHeader中的DataDirectory數(shù)組里的第二個元素正是指向我們想要的IMPORT TABLE的地址。在/*9*/中我們將其轉(zhuǎn)化為一個IMAGE_IMPORT_DESCRIPTOR的結(jié)構(gòu)指針存入piid中。
            替換的API函數(shù)入口地址

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

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

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

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

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

            SetWindowsHookEx之所以能完成DLL injection是因為它要給一個應(yīng)用程序某個環(huán)節(jié)加上一個Hook,而Hook就要有Hook Procedure也就是Hook函數(shù)。如果這個Hook函數(shù)在一個DLL中,那么系統(tǒng)就會把這個DLL加載到SetWindowsHookEx的目標(biāo)進程上。從而也就達到了我們DLL injection的目的了。當(dāng)然這里我們會用WH_GETMESSAGE的Hook進行injection,因為這個Hook可以用來監(jiān)視目標(biāo)進程的消息循環(huán)方便我們的進程與目標(biāo)進程通信。
            跨進程的實現(xiàn)和幾點注意
            1. /* DllPart.Dll */
            2. #include <windows.h>
            3. #include <stdio.h>
            4. #include <stdlib.h>
            5. #include <string.h>
            6. typedef (WINAPI *MsgBoxType)(HWND,LPCWSTR,LPCWSTR,UINT);
            7. MsgBoxType oldMsg;? /*API原入口地址*/
            8. DWORD APIAddress; /*存儲API入口地址的地方的地址*/
            9. int WINAPI? MyMessage(HWND hWnd ,LPCWSTR M1,LPCWSTR M2, UINT M3) {
            10. /* 這是用來替換的函數(shù) */
            11. return oldMsg(hWnd,buf,M2,MB_OK);
            12. }
            13. const char szApp[] = "DllPart.dll";
            14. HHOOK hHook; /*Hook的句柄*/
            15. HMODULE hInst; /*DLL 模塊句柄,用于SetWindowsHookEx函數(shù)*/
            16. HWND hTarget; /*目標(biāo)窗口句柄*/
            17. /*DLL 入口*/
            18. BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID lpvReserved)
            19. {
            20. ? ? hInst = inst;
            21. ? ? switch (reason) {
            22. case DLL_PROCESS_ATTACH:
            23. ? ???/*調(diào)試信息,表示DLL已經(jīng)加載*/
            24. ? ???MessageBox(NULL,"DLL_PROCESS_ATTACH",szApp,MB_OK);
            25. ? ???break;
            26. case DLL_PROCESS_DETACH:
            27. ? ???/*調(diào)試信息,表示DLL已經(jīng)卸載*/
            28. ? ???MessageBox(NULL,"DLL_PROCESS_DETACH",szApp,MB_OK);
            29. ? ???break;
            30. ? ? }
            31. ? ? return true;
            32. }
            33. /*顯示GetLastError的信息*/
            34. void showerr(const char *m) {
            35. ? ? char message[255];
            36. ? ? FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError()
            37. ,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,255, 0);
            38. ? ? MessageBox(NULL,message,m,MB_OK);
            39. }
            40. //-----------------------
            41. void UnHookApi() {
            42. /*卸載API Hook用*/
            43. }
            44. void HookApi() {
            45. /*加載API Hook同上面介紹的函數(shù)一樣*/
            46. }
            47. //-----------------------
            48. /*用于WH_GETMESSAGE的Hook Procedure*/
            49. LRESULT CALLBACK GetMsgProc(int nCode,WPARAM wParam, LPARAM lParam) {
            50. if (nCode == HC_ACTION) {
            51. ? ???MSG *msg = (MSG *)lParam;
            52. ? ???if (msg->message == WM_CHAR) {
            53. ? ? ? if (msg->wParam == 'h') HookApi();
            54. ? ? ? if (msg->wParam == 'u') UnHookApi();
            55. ? ???}
            56. }
            57. ? ? return CallNextHookEx(hHook,nCode,wParam,lParam);
            58. }
            59. extern "C" __declspec(dllexport) SetAPIHook(HWND handle) {
            60. ? ? DWORD ThreadId = GetWindowThreadProcessId(handle, NULL);
            61. ? ? hTarget = handle;
            62. ? ? MessageBox(NULL, "Enabling CallWndProc Hook", szApp, MB_OK);
            63. ? ? hHook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInst,ThreadId);
            64. ? ? if (hHook) {
            65. MessageBox(NULL,"Hook OK!", szApp, MB_OK);
            66. ? ? } else {
            67. showerr("SetWindowsHookEx");
            68. ? ? }
            69. }
            70. extern "C" __declspec(dllexport) UnHookAPIHook() {
            71. ? ? MessageBox(NULL, "Disenabling CallWndProc Hook", szApp, MB_OK);
            72. ? ? if (UnhookWindowsHookEx(hHook)) {
            73. ? ? ? ? MessageBox(NULL,"UnHook OK!", szApp, MB_OK);
            74. ? ? } else {
            75. showerr("UnHookWindowsHookEx");
            76. ? ? }
            77. }
            復(fù)制代碼
            分析
            幾個需要注意的問題

            SetAPIHook和UnHookAPIHook是我們自己進程調(diào)用的用來加載WH_GETMESSAGE Hook的函數(shù)。由于我們的程序要用LoadLibrary加載這個Dll因此這兩個函數(shù)要用__declspec(dllexport)修飾,使其成為導(dǎo)出函數(shù),才能被GetAddressProc函數(shù)找到。加上 extern "C"是讓編譯器使用C語言編碼方式。因為C++編譯器會進行Dynamic Binding(C++函數(shù)重載的實現(xiàn)),將函數(shù)的參數(shù)類型附加到名稱上。是函數(shù)的導(dǎo)出名看起來像SetAPIHook@XYTZX之類的,不利于GetAddressProc進行引用。因此使用extern "C"讓編譯器不使用Dynamic Binding,自然使用extern"C"的函數(shù)也就不能被重載了。

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

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

            SetWindowsHookEx的最后參數(shù)是ThreadId不是Handle,因此要通過調(diào)用GetWindowThreadProcessId轉(zhuǎn)換一下。
            在跨進程API HOOK時可能用到的其他技術(shù)
            主進程與目標(biāo)進程的信息交互和共享

            由于使用了WH_GETMESSAGE鉤子我們可以利用Windows消息機制實現(xiàn)進程間通訊。需要注意的是應(yīng)該使用PostThreadMessage來發(fā)送讓W(xué)H_GETMESSAGE得到的消息而不是SendMessage或者PostMessage,因為后兩個是用來給窗口發(fā)送消息的。而我們的WH_GETMESSAGE是Hook在線程上面的,因此需使用PostThreadMessage.

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

            如果傳遞較大的數(shù)據(jù)或者希望數(shù)據(jù)共享比較方便可以開辟共享內(nèi)存來進行數(shù)據(jù)共享。這里簡單分析一下使用共享內(nèi)存的代碼
            1. HANDLE hMap;
            2. switch (reason) {
            3. ? ? case DLL_PROCESS_ATTACH:
            4. ? ? /*創(chuàng)建/打開共享內(nèi)存區(qū)域*/
            5. ? ? hMap = CreateFileMapping((HFILE *)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(GLOBALDATA),ID_MAP);
            6. ? ? pg_data = (GLOBALDATA*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0 ,0 ,0);
            7. ? ? if (!pg_data) {
            8. MessageBox(NULL,"無法建立共享內(nèi)存,程序終止!",szApp,MB_OK);
            9. if (hMap) {
            10. ? ???CloseHandle(hMap);
            11. ? ???hMap = NULL;
            12. ? ???return 0;
            13. ? ? ???}
            14. ? ? }
            15. ? ? pg_data->hInst = hInst;
            16. ? ? showerr("共享內(nèi)存映像文件");
            17. ? ? showerr("DLL裝載中...",FALSE);
            18. ? ? break;
            19. ? ? case DLL_PROCESS_DETACH:
            20. ? ? if (pg_data) {
            21. ? ? ? ? UnmapViewOfFile(pg_data);
            22. pg_data = NULL;
            23. ? ? }
            24. ? ? if (hMap) {
            25. CloseHandle(hMap);
            26. hMap = NULL;
            27. ? ???}
            28. ? ? break;
            29. }
            復(fù)制代碼
            上面的代碼通過CreateFileMapping建立共享區(qū)域。將其第一個參數(shù)設(shè)置為0xFFFFFFFF使其能創(chuàng)建一個內(nèi)存共享區(qū)域而不是文件。并標(biāo)記為可讀寫的(PAGE_READWRITE).其大小為我們定義的結(jié)構(gòu)體GLOBALDATA的大小。最后的ID_MAP是一個用來標(biāo)示這個區(qū)域的字符串。打開或者創(chuàng)建完共享區(qū)域后,我們用MapViewOfFile來獲得這個區(qū)域的地址。之后就可以直接使用pg_data來操作共享區(qū)域了。不要忘記在DLL退出的時候安全的刪除共享區(qū)域釋放內(nèi)存。
            消息等待與安全卸載

            在我們卸載WH_GETMESSAGE鉤子之前必須先把目標(biāo)程序的API調(diào)用恢復(fù)正常。我們不能再調(diào)用UnHookApi之后就立刻調(diào)用UnhookWindowsHookEx,因為很有可能UnHookApi還沒來得急完成API入口地址的恢復(fù)操作,WH_GETMESSAGE鉤子就已經(jīng)被卸載了。因此需要等待一段時間,等UnHookApi完成了恢復(fù)操作在調(diào)用UnhookWindowsHookEx。以防錯誤發(fā)生。
            1. extern "C" __declspec(dllexport) void UnHookAPIHook() {
            2. ? ? /*向目標(biāo)線程發(fā)送消息進行API UNHOOK*/
            3. ? ? PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);
            4. ? ? showerr("WM_DISABLEAPIHOOK");
            5. ? ? /*等待目標(biāo)進程返回WM_UNHOOKOK消息,確認可以將WH_GETMESSAGE的HOOK去掉*/

            6. ? ? MSG Msg;
            7. ? ? do {
            8. ? ? ? ? GetMessage(&Msg,NULL,0,0);
            9. ? ? }while(Msg.message !=? WM_UNHOOKOK);
            10. ? ? UnhookWindowsHookEx(pg_data->hHook);
            11. ? ? PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOKOK,(WPARAM)GetCurrentThreadId(),0);
            12. ? ? showerr("UnHookWindowsHookEx");
            13. }
            復(fù)制代碼
            上面的代碼中我們使用一個含有GetMessage的循環(huán)來等待消息的到達,一旦UnHookApi完成他就會發(fā)送WM_UNHOOKOK消息。等我們接收到消息確認一切安全了在來卸載WH_GETMESSAGE鉤子。
            弄清消息對象

            我們一定要清楚代碼是在主程序進程空間中執(zhí)行的還是在目標(biāo)程序進程空間中執(zhí)行的。像上面的UnHookAPIHook函數(shù)就是通過主程序調(diào)用的,因此在主程序進程空間中執(zhí)行。這樣一來用來恢復(fù)目標(biāo)程序API信息的UnHookApi完成后就應(yīng)該向主程序發(fā)送消息,而不是目標(biāo)程序。
            目標(biāo)進程加載了其他DLL

            如果目標(biāo)進程動態(tài)加載了其他的DLL文件,我們必須監(jiān)視LoadLibrary函數(shù)。保證DLL中的API入口地址也被正確修改。防止出現(xiàn)混亂的情況。我從LoadLibrary獲得DLL的路徑用于GetModuleHandle來取得他的ImageBase的地址。
            不知道文章寫的如何,希望大家能多給些批評意見。發(fā)現(xiàn)問題我馬上改正

            Email: detrox@yang.com.cn
            參考資料

            <<;Programming Applications for Microsoft Windows>>, Jeffrey Richter, Microsoft Press

            <<C++ Builder 深度歷險>>,陳寬達,華中科大出版社

            <<The PE File Format>>, LUEVELSMEYER

            <<Iczelion's PE Tutorial>>, Iczelion
            附:跨進程APIHook的例子

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

            下載源代碼

            (特別感謝老羅的代碼著色器,比我自己那個好多了)
            這是DLL的程序,Hook.dll
            1. #include <windows.h>
            2. #include <stdio.h>
            3. #include <stdlib.h>
            4. #include <string.h>
            5. #include "mydef.h"

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

            10. /*顯示GetLastError指出的錯誤*/
            11. void showerr(const char *m, BOOL GetError = TRUE) {
            12. ? ? char message[127];
            13. ? ? char buf[255];
            14. ? ? COPYDATASTRUCT cds;
            15. ? ? if (GetError)
            16. ? ? ? ? FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0
            17. ? ,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,127, 0);
            18. ? ? else
            19. ? ? ? ? *message = 0;
            20. ? ? if (GetCurrentThreadId() != pg_data->idMain)
            21. ? ? ? ? sprintf(buf,"目標(biāo)程序空間DLL: %-30s [%-40s]",m, message);
            22. ? ? else
            23. ? ? ? ? sprintf(buf,"主程序空間DLL? : %-30s [%-40s]",m, message);
            24. ? ? cds.lpData = buf;
            25. ? ? cds.cbData = sizeof(buf);
            26. ? ? cds.dwData = 0;
            27. ? ???SendMessage(pg_data->hWndMain,WM_COPYDATA,(WPARAM)pg_data->hWndTarget,(LPARAM)&cds);
            28. ? ? ? SetLastError(0);
            29. }
            30. int WINAPI MyMessageBoxW(HWND hWnd ,LPCWSTR M1,LPCWSTR M2, UINT M3) {
            31. ? ? wchar_t buf[255];
            32. ? ? swprintf(buf,L"!!這個窗口的API被Hook了!!\nHWND: 0x%08X\nMessage: %s\nCaption: %s"
            33. ? ? ? ? ,(DWORD *)hWnd
            34. ? ? ? ? , M1
            35. ? ? ? ? , M2);
            36. ? ? pg_data->oldAPIFunction(hWnd,buf,M2,MB_OK);
            37. ? ? return pg_data->oldAPIFunction(hWnd,M1,M2,M3);
            38. }

            39. /*DLL 入口函數(shù)*/
            40. BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason,LPVOID lpvReserved)
            41. {
            42. ? ? switch (reason) {
            43. ? ? case DLL_PROCESS_ATTACH:
            44. ? ? ? ? /*創(chuàng)建/打開共享內(nèi)存區(qū)域*/
            45. ? ? ? ? hMap = CreateFileMapping((HFILE *)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(GLOBALDATA),ID_MAP);
            46. ? ? ? ? pg_data = (GLOBALDATA*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0 ,0 ,0);
            47. ? ? ? ? if (!pg_data) {
            48. ? ? ? ? ???MessageBox(NULL,"無法建立共享內(nèi)存,程序終止!",szApp,MB_OK);
            49. ? ? ? ? ???if (hMap) {
            50. ? ? ? ? ? ? ???CloseHandle(hMap);
            51. ? ? ? ? ? ? ???hMap = NULL;
            52. ? ? ? ? ? ? ???return 0;
            53. ? ? ? ? ? ? }
            54. ? ? ? ? }
            55. ? ? ? ? pg_data->hInst = hInst;
            56. ? ? ? ? showerr("共享內(nèi)存映像文件");
            57. ? ? ? ? showerr("DLL裝載中...",FALSE);
            58. ? ? ? ? break;
            59. ? ? case DLL_PROCESS_DETACH:
            60. ? ? ? ? showerr("DLL卸載中...",FALSE);
            61. ? ? ? ? if (pg_data) {
            62. ? ? ? ? ? ? UnmapViewOfFile(pg_data);
            63. ? ? ? ? ? ? pg_data = NULL;
            64. ? ? ? ? }
            65. ? ? ? ? if (hMap) {
            66. ? ? ? ? ? ? CloseHandle(hMap);
            67. ? ? ? ? ? ? hMap = NULL;
            68. ? ? ? ? }
            69. ? ? ? ? break;
            70. ? ? }
            71. ? ? return true;
            72. }
            73. /*卸載API Hook*/
            74. void UnHookApi() {
            75. ? ? DWORD written = 0;
            76. ? ? DWORD oldaddrAPIFunction = (DWORD)pg_data->oldAPIFunction;
            77. ? ? WriteProcessMemory(GetCurrentProcess(),(DWORD *)pg_data->addrAPIEntryPoint
            78. ? ? ? ? , &oldaddrAPIFunction,sizeof(DWORD), &written);
            79. ? ? showerr("WriteProcessMemory on UnHook");
            80. ? ? /*向主線程發(fā)送 API UNHOOK 處理完畢的消息*/
            81. ? ? PostThreadMessage(pg_data->idMain,WM_UNHOOKOK,0,0);
            82. }

            83. /*加載API Hook*/
            84. void HookApi(const char* szApiName, tAPIFunction newAddr, DWORD ImageBase) {
            85. ? ? /*這段代碼請參考文章中的分析*/
            86. ? ? IMAGE_DOS_HEADER *pidh;
            87. ? ? IMAGE_NT_HEADERS *pinh;
            88. ? ? IMAGE_DATA_DIRECTORY *pSymbolTable;
            89. ? ? IMAGE_IMPORT_DESCRIPTOR *piid;
            90. ? ? ? pidh = (IMAGE_DOS_HEADER *)ImageBase;
            91. ? ? ???pinh = (IMAGE_NT_HEADERS *)((DWORD)ImageBase + pidh->e_lfanew);
            92. ? ? pSymbolTable = &pinh->OptionalHeader.DataDirectory[1];
            93. ? ? piid =(IMAGE_IMPORT_DESCRIPTOR *)((DWORD)ImageBase +? pSymbolTable->VirtualAddress);

            94. ? ? do {
            95. ? ? ? ? IMAGE_THUNK_DATA *pitd_org,*pitd_1st;
            96. ? ? ? ? pitd_org = (IMAGE_THUNK_DATA *)((DWORD)ImageBase + piid->OriginalFirstThunk);
            97. ? ? ? ? pitd_1st = (IMAGE_THUNK_DATA *)((DWORD)ImageBase + piid->FirstThunk);
            98. ? ? ? ? do {
            99. ? ? ? ? ? ? IMAGE_IMPORT_BY_NAME *piibn;
            100. ? ? ? ? ? ? piibn = (IMAGE_IMPORT_BY_NAME *)((DWORD)ImageBase +? *((DWORD *)pitd_org));
            101. ? ? ? ? ? ? PROC *pAPIFunction = (PROC *)(pitd_1st->u1.Function);
            102. ? ? ? ? ? ? if (!strcmp(szApiName,(char *)piibn->Name)) {
            103. ? ? ? ? ? ? ? ? DWORD addrNewAPIFunction = (DWORD)MyMessageBoxW;
            104. ? ? ? ? ? ? ? ? DWORD written = 0;
            105. ? ? ? ? ? ? ? ? DWORD oldAccess;

            106. ? ? ? ? ? ? ? ? pg_data->oldAPIFunction = (tAPIFunction)(pAPIFunction);
            107. ? ? ? ? ? ? ? ? /*Change Memeory State*/
            108. ? ? ? ? ? ? ? ? VirtualProtect(&pitd_1st->u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&oldAccess);
            109. ? ? ? ? ? ? ? ? showerr("VirtualProtect");
            110. ? ? ? ? ? ? ? ? pg_data->addrAPIEntryPoint = (DWORD)&pitd_1st->u1.Function;
            111. ? ? ? ? ? ? ? ? /*Write Process Memory*/
            112. ? ? ? ? ? ? ? ? WriteProcessMemory(GetCurrentProcess(),&pitd_1st->u1.Function
            113. ? ? ? ? ? ? ? ? ? ? , &addrNewAPIFunction,sizeof(DWORD), &written);
            114. ? ? ? ? ? ? ? ? showerr("WriteProcessMemory on Hook");
            115. ? ? ? ? ? ? }
            116. ? ? ? ? ? ? pitd_org++;
            117. ? ? ? ? ? ? pitd_1st++;
            118. ? ? ? ? } while (pitd_1st->u1.Function);
            119. ? ? ? ? ? ? ???piid++;
            120. ? ? } while (piid->FirstThunk + piid->Characteristics
            121. + piid->ForwarderChain + piid->Name + piid->TimeDateStamp);
            122. }

            123. //-----------------------
            124. extern "C" __declspec(dllexport) BOOL SetAPIHook(HWND _target) {
            125. ? ? pg_data->hHook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,pg_data->hInst,pg_data->idTarget);
            126. ? ? ???showerr("SetWindowsHookEx");
            127. ? ? /*向目標(biāo)線程發(fā)送消息進行API HOOK*/
            128. ? ? if (pg_data->hHook) {
            129. ? ? ? ? PostThreadMessage(pg_data->idTarget,WM_ENABLEAPIHOOK,0,0);
            130. ? ? } else {
            131. ? ? ? ? return FALSE;
            132. ? ? }
            133. ? ? showerr("WM_ENABLEAPIHOOK");
            134. ? ? return TRUE;
            135. }

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

            145. ? ? UnhookWindowsHookEx(pg_data->hHook);
            146. ? ? PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOKOK,(WPARAM)GetCurrentThreadId(),0);
            147. ? ? showerr("UnHookWindowsHookEx");
            148. }

            149. LRESULT CALLBACK GetMsgProc(int nCode,WPARAM wParam, LPARAM lParam) {
            150. ? ? if (nCode == HC_ACTION) {
            151. ? ? ? ? MSG *msg = (MSG *)lParam;
            152. ? ? ? ? ? ???if (msg->message == WM_ENABLEAPIHOOK) {
            153. ? ? ? ? ? ? HookApi("MessageBoxW",MyMessageBoxW,(DWORD)GetModuleHandle(NULL));
            154. ? ? ? ? }
            155. ? ? ? ? if (msg->message == WM_DISABLEAPIHOOK) {
            156. ? ? ? ? ? ? UnHookApi();
            157. ? ? ? ? }
            158. ? ? ? ? if (msg->message == WM_DESTROY) {
            159. ? ? ? ? ? ? showerr("目標(biāo)進程退出!",FALSE);
            160. ? ? ? ? }
            161. ? ? }
            162. ? ? return CallNextHookEx(pg_data->hHook,nCode,wParam,lParam);
            163. }
            164.  
            165. 這個是主程序的關(guān)鍵部分 HookGui.cpp

            166. 用MFC建立一個窗口程序,包含兩個按鈕和一個ListBox
            167. typedef void (*PUnHookAPIHook)();
            168. typedef BOOL (*PSetAPIHook)(HWND);
            169. HMODULE hDll = NULL;
            170. HWND hNotePad = NULL;
            171. PSetAPIHook SetAPIHook;
            172. PUnHookAPIHook UnHookAPIHook;
            173. GLOBALDATA *pg_data; /*在共享內(nèi)存中的全局數(shù)據(jù)*/
            174. HANDLE hMap; /*在共享內(nèi)存映像的句柄*/
            175. int CHookGUIDlg::showerr(const char* m) {
            176. ? ? char message[127];
            177. ? ? char buf[255];
            178. ? ? int errId = GetLastError();
            179. ? ? FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0
            180. ,errId,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),message,127, 0);
            181. ? ? sprintf(buf,"主程序? ? ? ???: %-30s [%-40s]\n",m, message);
            182. ? ? c_List1.InsertString(c_List1.GetCount(),buf);
            183. ? ? UpdateData(FALSE);
            184. ? ? return errId;
            185. }

            186. void CHookGUIDlg::OnSetapihook()
            187. {
            188. ? ? // TODO: Add your control notification handler code here
            189. ? ? hDll = LoadLibrary("Hook.dll");
            190. ? ? showerr("LoadLibrary");
            191. ? ? hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,ID_MAP);
            192. ? ? showerr("OpenFileMapping");
            193. ? ? ???pg_data = (GLOBALDATA *)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);
            194. ? ? showerr("MapViewOfFile");
            195. ? ? ???if (!pg_data) {
            196. ? ? ? ? MessageBox("不能打開共享內(nèi)存程序終止!");
            197. ? ? ? ? return;
            198. ? ? }
            199. ? ? SetAPIHook = (PSetAPIHook)GetProcAddress(hDll,"SetAPIHook");
            200. ? ? showerr("GetProcAddress-SetAPIHOOK");
            201. ? ? ???pg_data->hWndTarget = ::FindWindow("NotePad",NULL);
            202. ? ? pg_data->hWndMain = m_hWnd;
            203. ? ? pg_data->idMain = GetWindowThreadProcessId(m_hWnd,NULL);
            204. ? ? pg_data->idTarget = GetWindowThreadProcessId(pg_data->hWndTarget,NULL);
            205. ? ? if (!showerr("FindWindow")) {
            206. ? ? ? ? if (SetAPIHook) {
            207. ? ? ? ? ? ? if (SetAPIHook(hNotePad))
            208. ? ? ? ? ? ? ? ? PostThreadMessage(pg_data->idTarget
            209. ???, WM_SETCALLERID,(LPARAM)GetCurrentThreadId(),0);
            210. ? ? ? ? ? ? else {
            211. ? ? ? ? ? ? ? ? MessageBox("SetWindowHookEx時出錯,程序終止!");
            212. ? ? ? ? ? ? ? ? return;
            213. ? ? ? ? ? ? }
            214. ? ? ? ? } else {
            215. ? ? ? ? ? ? MessageBox("無法取得SetAPIHook函數(shù)!程序終止!");
            216. ? ? ? ? ? ? ? ? ? ? ? ? ???}
            217. ? ? } else {
            218. ? ? ? ? ? ? MessageBox("內(nèi)存中沒有找到NOTEPAD.EXE");
            219. ? ? ? ? ? ? ???}
            220. ? ? c_SetApiHook.EnableWindow(FALSE);
            221. ? ? c_UnsetApiHook.EnableWindow();
            222. }

            223. void CHookGUIDlg::OnUnsetapihook()
            224. {
            225. ? ? // TODO: Add your control notification handler code here
            226. ? ? if (hDll) {
            227. ? ? ? ? if ( !IsWindow(pg_data->hWndTarget)) {
            228. ? ? ? ? ? ? MessageBox("目標(biāo)進程不在內(nèi)存中");
            229. ? ? ? ? ? ? return;
            230. ? ? ? ? }
            231. ? ? ? ? UnHookAPIHook = (PUnHookAPIHook)GetProcAddress(hDll,"UnHookAPIHook");
            232. ? ? ? ? showerr("GetProcAddress-UnHookAPIHook");
            233. ? ? ? ? if (UnHookAPIHook)
            234. ? ? ? ? ? ? UnHookAPIHook();
            235. ? ? ? ? FreeLibrary(hDll);
            236. ? ? ? ? showerr("FreeLibrary");
            237. ? ? ? ? hDll = NULL;
            238. ? ? } else {
            239. ? ? ? ? MessageBox("請先加載DLL");
            240. ? ? }
            241. ? ? c_SetApiHook.EnableWindow();
            242. ? ? c_UnsetApiHook.EnableWindow(FALSE);
            243. }

            244. void CHookGUIDlg::OnOK()
            245. {
            246. ? ? // TODO: Add extra validation here
            247. ? ? if (hDll) {
            248. ? ? ? ? OnUnsetapihook();
            249. ? ? }
            250. ? ? CDialog::OnOK();
            251. }

            252. BOOL CHookGUIDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
            253. {
            254. ? ? // TODO: Add your message handler code here and/or call default
            255. ? ? c_List1.InsertString(c_List1.GetCount(),(char *)pCopyDataStruct->lpData);
            256. ? ? return CDialog::OnCopyData(pWnd, pCopyDataStruct);
            復(fù)制代碼
            附件: 您需要登錄才可以下載或查看附件。沒有帳號?注冊
            久久精品国产清自在天天线| 久久国产视屏| 欧美性大战久久久久久| 精品午夜久久福利大片| 久久综合综合久久综合| 久久久久久久精品妇女99| 久久久久久亚洲精品不卡| 99热成人精品免费久久| 精品久久香蕉国产线看观看亚洲 | 久久精品视频一| 久久国产视频网| 久久久无码精品亚洲日韩软件| 大蕉久久伊人中文字幕| 热久久这里只有精品| 99国内精品久久久久久久| 999久久久免费国产精品播放| 曰曰摸天天摸人人看久久久| 青青草国产精品久久| 国产精品九九久久精品女同亚洲欧美日韩综合区 | 久久久久女教师免费一区| 久久精品国产国产精品四凭| 久久久久18| 久久久久久亚洲精品不卡| 一本综合久久国产二区| 久久久久青草线蕉综合超碰| 老色鬼久久亚洲AV综合| 亚洲国产二区三区久久| 久久精品18| 思思久久好好热精品国产| 日韩精品久久无码人妻中文字幕| 久久久久99精品成人片直播| 精品久久一区二区三区| 久久精品成人欧美大片| 精品久久亚洲中文无码| 99精品国产在热久久无毒不卡 | 99久久精品免费看国产| 色婷婷久久综合中文久久一本| 亚洲综合熟女久久久30p| 91精品国产乱码久久久久久 | 国产精品亚洲美女久久久| 香蕉久久夜色精品国产2020|