见过网上有很多ApiHook的类,但是都不尽入人意,要么就是写的不够好不够完善,要么就是跑不起来.
用别人写的代码总是有种不安心,所以自己就花了一晚上写了CApiHook类.已经尽量确保自己写的类是非常完善的.
//20151208稍微改变了一下ApiHook的逻辑,重写GetApiHookStatus函数并重命名为GetProcHookStatus,
并且很认真负责的测试了WinXP x86/Win7 x86/Win7 x64/Win8.1 x64系统下的GetProcHookStatus有效性.
//20150728稍微改进了一下ApiHook的稳定性,和增加了一个检测系统Api Hook状态的函数GetApiHookStatus
//编写和测试环境: Microsoft Visual Studio 2015 Enterprise RC / Microsoft Windows 7 Ultimate x86
1 // CApiHook, Last Code By gwsbhqt@163.com At 20151208 2 3 #pragma once 4 5 #ifndef __CAPIHOOK_H__ 6 #define __CAPIHOOK_H__ 7 8 #include <cstdio> 9 #include <windows.h> 10 11 using namespace std; 12 13 class CApiHook 14 { 15 private: 16 BOOL bStatus; // 当前钩子状态 17 BOOL bSuspend; // 当前钩子暂停状态 18 HMODULE hModule; // 目标函数所在的动态链接库的句柄 19 LPVOID lpProc; // 目标函数地址 20 LPVOID lpBaseAddr; // 目标函数基地址 21 LPVOID lpNewProc; // 新函数地址 22 BYTE bRawData[5]; // 目标函数原数据 23 BYTE bJMPStmt[5]; // JMP指令语句 24 25 BOOL WriteData(LPCVOID lpBuffer); // 将缓冲区内容写入目标函数地址 26 27 public: 28 CApiHook(); 29 ~CApiHook(); 30 31 BOOL Install(LPCSTR szModuleName, LPCSTR szProcName, FARPROC pNewProc); // 初始化钩子 32 BOOL Suspend(); // 暂停钩子 33 BOOL Resume(); // 恢复钩子 34 BOOL Uninstall(); // 卸载钩子 35 36 BOOL GetHookStatus(); 37 }; 38 39 BOOL GetProcHookStatus(LPCSTR lpModuleName, LPCSTR lpProcName); // 获取目标函数的钩子状态 40 41 #endif // __CAPIHOOK_H__
1 // CApiHook, Last Code By gwsbhqt@163.com At 20151208 2 3 #include "CApiHook.h" 4 5 CApiHook::CApiHook() 6 { 7 memset(this, 0, sizeof(CApiHook)); 8 } 9 10 CApiHook::~CApiHook() 11 { 12 if (bStatus) 13 Uninstall(); 14 } 15 16 // 将缓冲区内容写入目标函数地址 17 BOOL CApiHook::WriteData(LPCVOID lpBuffer) 18 { 19 // 更改目标函数基地址的保护状态为可读写 20 DWORD dwOldProtect; 21 if (!VirtualProtectEx(GetCurrentProcess(), lpBaseAddr, 5, PAGE_READWRITE, &dwOldProtect)) 22 return FALSE; 23 24 // 将缓冲区内容写入目标函数地址 25 if (!WriteProcessMemory(GetCurrentProcess(), lpProc, lpBuffer, 5, NULL)) 26 return FALSE; 27 28 // 恢复目标函数基地址的保护状态 29 if (!VirtualProtectEx(GetCurrentProcess(), lpBaseAddr, 5, dwOldProtect, &dwOldProtect)) 30 return FALSE; 31 32 return TRUE; 33 } 34 35 // 初始化钩子 36 BOOL CApiHook::Install(LPCSTR szModuleName, LPCSTR szProcName, FARPROC fpNewProc) 37 { 38 if (bStatus) 39 return FALSE; 40 41 // 获取目标函数所在的动态链接库的句柄 42 hModule = GetModuleHandleA(szModuleName); 43 if (NULL == hModule) 44 hModule = LoadLibraryA(szModuleName); 45 if (NULL == hModule) 46 return FALSE; 47 48 lpNewProc = (LPVOID)fpNewProc; // 获取新函数地址 49 lpProc = (LPVOID)GetProcAddress(hModule, szProcName); // 获取目标函数地址 50 if (NULL == lpNewProc || NULL == lpProc) 51 return FALSE; 52 53 // 获取并保存目标函数地址的原数据 54 RtlMoveMemory(bRawData, lpProc, 5); 55 56 // 构造JMP指令语句 57 bJMPStmt[0] = 0xE9; // JMP指令 58 *((PDWORD)(&(bJMPStmt[1]))) = (DWORD)lpNewProc - (DWORD)lpProc - 5; 59 60 // 获取目标函数基地址 61 MEMORY_BASIC_INFORMATION mbi = {}; 62 if (sizeof(mbi) != VirtualQueryEx(GetCurrentProcess(), lpProc, &mbi, sizeof(mbi))) 63 return FALSE; 64 lpBaseAddr = mbi.BaseAddress; 65 66 // 将JMP指令语句写入目标函数地址 67 if (!WriteData(bJMPStmt)) 68 return FALSE; 69 70 bStatus = TRUE; 71 72 return TRUE; 73 } 74 75 // 暂停钩子 76 BOOL CApiHook::Suspend() 77 { 78 if (!bStatus || bSuspend) 79 return FALSE; 80 81 // 将目标函数原数据写入目标函数地址 82 BOOL ret = WriteData(bRawData); 83 if (!ret) 84 return FALSE; 85 86 bSuspend = TRUE; 87 88 return TRUE; 89 } 90 91 // 恢复钩子 92 BOOL CApiHook::Resume() 93 { 94 if (!bStatus || !bSuspend) 95 return FALSE; 96 97 // 将JMP指令语句写入目标函数地址 98 BOOL ret = WriteData(bJMPStmt); 99 if (!ret) 100 return FALSE; 101 102 bSuspend = FALSE; 103 104 return TRUE; 105 } 106 107 // 卸载钩子 108 BOOL CApiHook::Uninstall() 109 { 110 if (!bStatus) 111 return FALSE; 112 113 // 将目标函数原数据写入目标函数地址 114 if (!WriteData(bRawData)) 115 return FALSE; 116 117 if (hModule != NULL) 118 FreeLibrary(hModule); 119 memset(this, 0, sizeof(*this)); 120 121 return TRUE; 122 } 123 124 BOOL CApiHook::GetHookStatus() 125 { 126 return bStatus; 127 } 128 129 // 获取目标函数的钩子状态 130 // 该函数暂仅对在WinXPx86/Win7x86/Win7x64/Win8.1x64下的ntdll.dll/kernel32.dll/user32.dll负责 131 BOOL GetProcHookStatus(LPCSTR lpModuleName, LPCSTR lpProcName) 132 { 133 // 获取目标函数所在的动态链接库的句柄 134 HMODULE hModule = GetModuleHandleA(lpModuleName); 135 if (hModule == NULL) 136 hModule = LoadLibraryA(lpModuleName); 137 if (hModule == NULL) 138 return ERROR; 139 140 // 获取目标函数的地址 141 FARPROC fpProc = GetProcAddress(hModule, lpProcName); 142 if (fpProc == NULL) 143 return ERROR; 144 145 // 获取目标函数地址的前7字节 146 BYTE buf[7] = {}; 147 if (!ReadProcessMemory(GetCurrentProcess(), fpProc, &buf, 7, NULL)) 148 return ERROR; 149 150 /* 151 E9 152 B8 XX XX XX XX FF E0 153 154 例外 155 E9 XX XX XX 00 156 E9 XX XX XX FA 157 E9 XX XX XX FC 158 E9 XX XX XX FF 159 E9 XX XX XX XX 90 160 */ 161 162 // 判断前7字节是否存在JMP/MOV指令语句并排除例外 163 if ((buf[0] == 0xB8 && buf[5] == 0xFF && buf[6] == 0xE0) || 164 (buf[0] == 0xE9 && buf[4] != 0x00 && buf[4] != 0xFA && buf[4] != 0xFC && buf[4] != 0xFF && buf[5] != 0x90)) 165 return TRUE; 166 167 return FALSE; 168 }
1 #include <cstdio> 2 #include <windows.h> 3 4 #include "CApiHook.h" 5 6 CApiHook HookMessageBoxA; 7 8 int WINAPI NewMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) 9 { 10 printf("PAY ATTENTION!! FOUND CALLING : MessageBoxA(%d, \"%s\", \"%s\", %d)\n", hWnd, lpText, lpCaption, uType); 11 12 char cText[MAX_PATH]; 13 strcpy(cText, lpText); 14 strcat(cText, " [Hijack]"); 15 16 char cCaption[MAX_PATH]; 17 strcpy(cCaption, lpCaption); 18 strcat(cCaption, " [Hijack]"); 19 20 HookMessageBoxA.Suspend(); 21 22 int ret = MessageBoxA(NULL, cText, cCaption, MB_ICONERROR); 23 24 HookMessageBoxA.Resume(); 25 26 return ret; 27 } 28 29 int main() 30 { 31 MessageBoxA(NULL, "Text1", "Caption1", MB_ICONINFORMATION); 32 33 printf("MessageBoxA Hook Status: %s\n", GetApiHookStatus("User32.dll", "MessageBoxA") ? "YES" : "NO"); 34 HookMessageBoxA.Install("User32.dll", "MessageBoxA", (FARPROC)NewMessageBoxA); 35 printf("MessageBoxA Hook Status: %s\n", GetApiHookStatus("User32.dll", "MessageBoxA") ? "YES" : "NO"); 36 37 MessageBoxA(NULL, "Text2", "Caption2", MB_ICONINFORMATION); 38 39 printf("MessageBoxA Hook Status: %s\n", GetApiHookStatus("User32.dll", "MessageBoxA") ? "YES" : "NO"); 40 HookMessageBoxA.Uninstall(); 41 printf("MessageBoxA Hook Status: %s\n", GetApiHookStatus("User32.dll", "MessageBoxA") ? "YES" : "NO"); 42 43 MessageBoxA(NULL, "Text3", "Caption3", MB_ICONINFORMATION); 44 45 system("pause > nul"); 46 return 0; 47 }