青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

S.l.e!ep.¢%

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

跨進程API Hook

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

【轉】跨進程API Hook

什么是“跨進程APIHook”?

眾所周知Windows應用程序的各種系統功能是通過調用API函數來實現。API Hook就是給系統的API附加上一段小程序,它能監視甚至控制應用程序對API函數的調用。所謂跨進程也就是讓自己的程序來控制別人程序的API調用了。
API Hook 理論

通過對Win32 PE文件的分析(如果你還不熟悉PE文件格式,可以看看Iczelion的PE教程或者LUEVELSMEYER的<<The PE File Format>>)。我們知道在PE文件中的IMPORT TABLE內存儲著API函數的很多信息。其中包括API的函數名,調用地址等等。而操作系統在執行PE文件時會先將其映射到內存中。在映射的同時還會把當前版本操作系統中API函數的入口地址寫入IMPORT TABLE中一組與API調用相關的結構體內,用于該應用程序的API調用。當應用程序調用API時,他會在自己內存映像里尋找API的入口地址,然后執行CALL指令。如此一來,我們通過修改應用程序內存映像的IMPORT TABLE中API函數的入口地址,就可以達到重定向API的目的。將API地址改為我們自己函數的地址,這樣我們的函數就可以完成對API的監視和控制了。
API Hook 的實現
  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. ? ? ? /* 改變內存讀寫狀態 */
  23. /*22 */? ???DWORD oldAccess;
  24. /*23 */? ???VirtualProtect(&pitd2->u1.Function,sizeof(DWORD),PAGE_WRITECOPY,&oldAccess);
  25. /*24 */? ???APIAddress = (DWORD)&pitd2->u1.Function;
  26. ? ? ? /* 向內存映像寫入數據 */
  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);
復制代碼
分析:
尋覓IMPORT TALBE

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

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

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

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

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

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

SetWindowsHookEx之所以能完成DLL injection是因為它要給一個應用程序某個環節加上一個Hook,而Hook就要有Hook Procedure也就是Hook函數。如果這個Hook函數在一個DLL中,那么系統就會把這個DLL加載到SetWindowsHookEx的目標進程上。從而也就達到了我們DLL injection的目的了。當然這里我們會用WH_GETMESSAGE的Hook進行injection,因為這個Hook可以用來監視目標進程的消息循環方便我們的進程與目標進程通信。
跨進程的實現和幾點注意
  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. /* 這是用來替換的函數 */
  11. return oldMsg(hWnd,buf,M2,MB_OK);
  12. }
  13. const char szApp[] = "DllPart.dll";
  14. HHOOK hHook; /*Hook的句柄*/
  15. HMODULE hInst; /*DLL 模塊句柄,用于SetWindowsHookEx函數*/
  16. HWND hTarget; /*目標窗口句柄*/
  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. ? ???/*調試信息,表示DLL已經加載*/
  24. ? ???MessageBox(NULL,"DLL_PROCESS_ATTACH",szApp,MB_OK);
  25. ? ???break;
  26. case DLL_PROCESS_DETACH:
  27. ? ???/*調試信息,表示DLL已經卸載*/
  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同上面介紹的函數一樣*/
  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. }
復制代碼
分析
幾個需要注意的問題

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

不要忘記在GetMsgProc最后要調用CallNextHookEx函數,保證Hook鏈的完整性。

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

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

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

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

如果傳遞較大的數據或者希望數據共享比較方便可以開辟共享內存來進行數據共享。這里簡單分析一下使用共享內存的代碼
  1. HANDLE hMap;
  2. switch (reason) {
  3. ? ? case DLL_PROCESS_ATTACH:
  4. ? ? /*創建/打開共享內存區域*/
  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,"無法建立共享內存,程序終止!",szApp,MB_OK);
  9. if (hMap) {
  10. ? ???CloseHandle(hMap);
  11. ? ???hMap = NULL;
  12. ? ???return 0;
  13. ? ? ???}
  14. ? ? }
  15. ? ? pg_data->hInst = hInst;
  16. ? ? showerr("共享內存映像文件");
  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. }
復制代碼
上面的代碼通過CreateFileMapping建立共享區域。將其第一個參數設置為0xFFFFFFFF使其能創建一個內存共享區域而不是文件。并標記為可讀寫的(PAGE_READWRITE).其大小為我們定義的結構體GLOBALDATA的大小。最后的ID_MAP是一個用來標示這個區域的字符串。打開或者創建完共享區域后,我們用MapViewOfFile來獲得這個區域的地址。之后就可以直接使用pg_data來操作共享區域了。不要忘記在DLL退出的時候安全的刪除共享區域釋放內存。
消息等待與安全卸載

在我們卸載WH_GETMESSAGE鉤子之前必須先把目標程序的API調用恢復正常。我們不能再調用UnHookApi之后就立刻調用UnhookWindowsHookEx,因為很有可能UnHookApi還沒來得急完成API入口地址的恢復操作,WH_GETMESSAGE鉤子就已經被卸載了。因此需要等待一段時間,等UnHookApi完成了恢復操作在調用UnhookWindowsHookEx。以防錯誤發生。
  1. extern "C" __declspec(dllexport) void UnHookAPIHook() {
  2. ? ? /*向目標線程發送消息進行API UNHOOK*/
  3. ? ? PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);
  4. ? ? showerr("WM_DISABLEAPIHOOK");
  5. ? ? /*等待目標進程返回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. }
復制代碼
上面的代碼中我們使用一個含有GetMessage的循環來等待消息的到達,一旦UnHookApi完成他就會發送WM_UNHOOKOK消息。等我們接收到消息確認一切安全了在來卸載WH_GETMESSAGE鉤子。
弄清消息對象

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

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

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 函數Hook的結果了.
代碼在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"; /*應用程序名稱*/
  7. HANDLE hMap;/*在共享內存映像的句柄*/
  8. GLOBALDATA *pg_data; /*在共享內存中的全局數據*/
  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,"目標程序空間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 入口函數*/
  40. BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason,LPVOID lpvReserved)
  41. {
  42. ? ? switch (reason) {
  43. ? ? case DLL_PROCESS_ATTACH:
  44. ? ? ? ? /*創建/打開共享內存區域*/
  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,"無法建立共享內存,程序終止!",szApp,MB_OK);
  49. ? ? ? ? ???if (hMap) {
  50. ? ? ? ? ? ? ???CloseHandle(hMap);
  51. ? ? ? ? ? ? ???hMap = NULL;
  52. ? ? ? ? ? ? ???return 0;
  53. ? ? ? ? ? ? }
  54. ? ? ? ? }
  55. ? ? ? ? pg_data->hInst = hInst;
  56. ? ? ? ? showerr("共享內存映像文件");
  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. ? ? /*向主線程發送 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. ? ? /*向目標線程發送消息進行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. ? ? /*向目標線程發送消息進行API UNHOOK*/
  138. ? ? PostThreadMessage(pg_data->idTarget,WM_DISABLEAPIHOOK,(WPARAM)GetCurrentThreadId(),0);
  139. ? ? showerr("WM_DISABLEAPIHOOK");
  140. ? ? /*等待目標進程返回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("目標進程退出!",FALSE);
  160. ? ? ? ? }
  161. ? ? }
  162. ? ? return CallNextHookEx(pg_data->hHook,nCode,wParam,lParam);
  163. }
  164.  
  165. 這個是主程序的關鍵部分 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; /*在共享內存中的全局數據*/
  174. HANDLE hMap; /*在共享內存映像的句柄*/
  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("不能打開共享內存程序終止!");
  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函數!程序終止!");
  216. ? ? ? ? ? ? ? ? ? ? ? ? ???}
  217. ? ? } else {
  218. ? ? ? ? ? ? MessageBox("內存中沒有找到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("目標進程不在內存中");
  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);
復制代碼
附件: 您需要登錄才可以下載或查看附件。沒有帳號?注冊
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            一区二区三区高清视频在线观看| 国产一区二区三区在线观看免费视频 | 在线中文字幕一区| 亚洲美女色禁图| 国产精品国产| 久久www成人_看片免费不卡| 亚洲欧美日韩在线高清直播| 国产日韩欧美综合一区| 久久在线观看视频| 久久综合伊人77777麻豆| 亚洲三级影片| 99精品国产在热久久| 国产欧美日韩另类一区 | 亚洲乱码视频| 亚洲图片欧美午夜| 伊人精品久久久久7777| 亚洲国产日韩一区二区| 国产精品久久久久9999高清| 欧美在线亚洲| 欧美大色视频| 欧美在线一区二区| 你懂的视频欧美| 午夜久久福利| 欧美三级在线| 亚洲美女在线一区| 欧美亚洲日本网站| 99热在这里有精品免费| 午夜精彩视频在线观看不卡| 亚洲黄色尤物视频| 亚洲永久精品大片| 亚洲区欧美区| 亚洲男同1069视频| 亚洲日本激情| 欧美一区激情| 亚洲欧美国产高清| 欧美aⅴ一区二区三区视频| 欧美亚洲专区| 欧美日韩dvd在线观看| 久久蜜桃香蕉精品一区二区三区| 欧美日韩免费一区二区三区视频| 久久青草久久| 国产欧美精品一区二区三区介绍| 亚洲国产裸拍裸体视频在线观看乱了| 国产欧美日韩综合一区在线播放 | 一道本一区二区| 麻豆精品网站| 久久精品国产久精国产一老狼| 欧美精品久久一区| 欧美高清在线视频| 韩国在线一区| 久久国产精品99久久久久久老狼| 亚洲图片欧美一区| 欧美欧美天天天天操| 欧美黑人在线播放| 在线观看三级视频欧美| 欧美一区亚洲| 久久九九精品99国产精品| 国产精品乱码妇女bbbb| 日韩手机在线导航| 一本色道久久综合亚洲91| 免费一级欧美片在线观看| 久久在线视频在线| 在线精品视频一区二区三四| 欧美在线在线| 美女久久网站| 亚洲黄色在线看| 欧美国产免费| 日韩午夜中文字幕| 亚洲永久在线| 国产精品久久福利| 亚洲专区一区二区三区| 亚洲欧美中文在线视频| 国产乱肥老妇国产一区二| 一区二区激情视频| 先锋影院在线亚洲| 国产视频在线一区二区| 欧美亚洲一级| 美女久久网站| 日韩天堂在线视频| 国产精品久久久久久久7电影| 亚洲最黄网站| 欧美在线免费观看亚洲| 影音先锋国产精品| 欧美精品二区| 亚洲一区二区三区视频播放| 欧美在线日韩精品| 亚洲国产欧美精品| 欧美日韩视频在线| 小黄鸭精品aⅴ导航网站入口| 欧美三区视频| 欧美成人精品在线| 99精品国产高清一区二区 | 久久精品在这里| 亚洲国产综合视频在线观看| 亚洲神马久久| 激情欧美丁香| 欧美午夜电影在线| 久久精品国产91精品亚洲| 欧美国产日韩a欧美在线观看| 国产精品99久久久久久久久久久久| 国产免费观看久久| 欧美成人黑人xx视频免费观看| 亚洲一区二区三区高清| 毛片av中文字幕一区二区| 一区二区三区四区五区精品| 国产亚洲精品激情久久| 欧美精品电影在线| 久久久久国内| 亚洲视频免费在线| 欧美激情亚洲视频| 久久天天综合| 午夜精品久久久久久久白皮肤| 1024日韩| 国产性色一区二区| 国产精品成人免费| 欧美成人官网二区| 久久精品亚洲| 亚洲一区二区三区四区在线观看 | 久久中文字幕一区| 亚洲自拍偷拍网址| 亚洲精品激情| 欧美成人午夜剧场免费观看| 欧美一区二区视频观看视频| 99国产精品视频免费观看| 永久久久久久| 国产免费观看久久| 国产精品久久久久久久久久妞妞| 欧美99久久| 免费欧美日韩国产三级电影| 欧美一区二区三区四区高清| 中文av字幕一区| 日韩亚洲一区二区| 亚洲精品孕妇| 亚洲日本va在线观看| 亚洲第一二三四五区| 美女精品在线观看| 免费看亚洲片| 美女精品在线| 欧美二区不卡| 欧美福利视频在线观看| 蜜臀久久99精品久久久画质超高清 | 欧美国产日韩精品| 欧美承认网站| 欧美精品一区二区三区蜜桃| 久久亚洲精品一区二区| 久久精品一区二区国产| 久久激情久久| 久久久欧美一区二区| 久久精品国产久精国产思思| 久久国产视频网站| 久久精品人人做人人爽| 久久免费少妇高潮久久精品99| 久久亚洲精品中文字幕冲田杏梨 | 亚洲欧美国产精品va在线观看 | 国产日韩欧美综合| 欧美激情第五页| 老**午夜毛片一区二区三区| 蜜桃久久av| 欧美日韩精品免费观看视一区二区 | 久久久999精品视频| 久久久久久免费| 欧美高清视频免费观看| 最新日韩在线| 亚洲午夜女主播在线直播| 亚洲综合电影| 久久资源在线| 欧美四级电影网站| 国产综合色在线| 亚洲精品极品| 午夜在线一区| 欧美激情精品| 一区二区三区导航| 欧美专区在线观看一区| 欧美成人一区在线| 国产精品久久久久久久电影| 极品尤物av久久免费看| 亚洲精品资源| 欧美永久精品| 亚洲国产三级| 欧美亚洲自偷自偷| 欧美日韩第一页| 加勒比av一区二区| 一区二区三区视频免费在线观看| 性娇小13――14欧美| 免费成人性网站| 亚洲网站在线看| 久久亚洲私人国产精品va媚药| 欧美日韩中文字幕| 在线观看日韩av电影| 99精品99久久久久久宅男| 久久av二区| 亚洲免费大片| 久久天堂精品| 国产一区二区三区在线免费观看 | 国产日韩综合| 亚洲欧美精品| 亚洲日本理论电影| 久久夜色精品国产欧美乱极品| 国产精品美女久久久久久久| 日韩视频免费大全中文字幕|