The code comes from the author of “Windows Core Programming”:
APIHOOK.h header file:
#pragma once #include <Windows.h> class CAPIHOOK { public: CAPIHOOK(LPTSTR lpszModName, LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod = TRUE); ~CAPIHOOK(void); private: static void ReplaceIATEntryInOneMod(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, HMODULE hModCaller); static void ReplaceIATEntryInAllMods(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, BOOL bExcludeAPIHookMod); //Prevent dynamic loading of modules while the program is running, called when a new DLL is loaded static void HookNewlyLoadedModule(HMODULE hModule, DWORD dwFlags); //Track the current process to load a new DLL static HMODULE WINAPI LoadLibraryA(LPCTSTR lpFileName); static HMODULE WINAPI LoadLibraryW(LPCTSTR lpFileName); static HMODULE WINAPI LoadLibraryExA(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags); static HMODULE WINAPI LoadLibraryExW(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags); //Prevent API functions from being called dynamically while the program is running. For requests to API functions that have been HOOKed, user-defined function addresses are returned. static FARPROC WINAPI GetProcess(HMODULE hModule, PCSTR pszProcName); private: //Defined as static, it will be automatically called to achieve automatic HOOK static CAPIHOOK sm_LoadLibraryA; static CAPIHOOK sm_LoadLibraryW; static CAPIHOOK sm_LoadLibraryExA; static CAPIHOOK sm_LoadLibraryExW; static CAPIHOOK sm_GetProcAddress; private: static CAPIHOOK* sm_pHeader; //hook list CAPIHOOK* m_pNext; //Function to hook PROC m_pfnOrig; PROC m_pfnHook; //The dll where the function to be hooked is located LPSTR m_pszModName; //Function name to be hooked LPSTR m_pszFuncName; };
APIHOOK.cpp implementation file:
#include "APIHOOK.h" #include <Tlhelp32.h> CAPIHOOK *CAPIHOOK::sm_pHeader = NULL; CAPIHOOK CAPIHOOK::sm_LoadLibraryA("kernel32.dll", "LoadLibraryA", (PROC)CAPIHOOK::LoadLibraryA, TRUE); CAPIHOOK CAPIHOOK::sm_LoadLibraryW("kernel32.dll", "LoadLibraryW", (PROC)CAPIHOOK::LoadLibraryW, TRUE); CAPIHOOK CAPIHOOK::sm_LoadLibraryExA("kernel32.dll", "LoadLibraryExA", (PROC)CAPIHOOK::LoadLibraryExA, TRUE); CAPIHOOK CAPIHOOK::sm_LoadLibraryExW("kernel32.dll", "LoadLibraryExW", (PROC)CAPIHOOK::LoadLibraryExW, TRUE); CAPIHOOK CAPIHOOK::sm_GetProcAddress("kernel32.dll", "GetProcAddress", (PROC)CAPIHOOK::GetProcess, TRUE); CAPIHOOK::CAPIHOOK(LPTSTR lpszModName, LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod) { //Initialize variables m_pszModName = lpszModName; m_pszFuncName = pszFuncName; m_pfnOrig = ::GetProcAddress(::GetModuleHandleA(lpszModName), pszFuncName); m_pfnHook = pfnHook; //Add this object to the linked list m_pNext = sm_pHeader; sm_pHeader = this; //HOOK this function in the currently loaded module ReplaceIATEntryInAllMods(lpszModName, m_pfnOrig, m_pfnHook, bExcludeAPIHookMod); } CAPIHOOK::~CAPIHOOK(void) { //Cancel the HOOK of the function ReplaceIATEntryInAllMods(m_pszModName, m_pfnHook, m_pfnOrig, TRUE); //Remove yourself from the linked list CAPIHOOK* p = sm_pHeader; if (p == this) { sm_pHeader = this->m_pNext; } else { while(p != NULL) { if (p->m_pNext == this) { p->m_pNext = this->m_pNext; break; } p = p->m_pNext; } } } //Prevent dynamic loading of modules while the program is running void CAPIHOOK::HookNewlyLoadedModule(HMODULE hModule, DWORD dwFlags) { if (hModule!=NULL & amp; & amp; (dwFlags & amp;LOAD_LIBRARY_AS_DATAFILE)==0) { CAPIHOOK* p = sm_pHeader; //Loop through the linked list and enter HOOK for each CAPIHOOK if (p != NULL) { ReplaceIATEntryInOneMod(p->m_pszModName, p->m_pfnOrig, p->m_pfnHook, hModule); p = p->m_pNext; } } } //Prevent dynamic calls to API functions while the program is running FARPROC WINAPI CAPIHOOK::GetProcess(HMODULE hModule, PCSTR pszProcName) { //Get the real address of the function FARPROC pfn = ::GetProcAddress(hModule, pszProcName); //Traverse the list to see if it is a function that requires HOOK CAPIHOOK* p = sm_pHeader; while(p != NULL) { if (p->m_pfnOrig == pfn) //It is the function to be HOOK { pfn = p->m_pfnHook; //HOOK off break; } p = p->m_pNext; } return pfn; } void CAPIHOOK::ReplaceIATEntryInOneMod(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, HMODULE hModCaller) { IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)hModCaller; IMAGE_OPTIONAL_HEADER* pOpNtHeader = (IMAGE_OPTIONAL_HEADER*)((BYTE*)hModCaller + pDosHeader->e_lfanew + 24); //Add 24 here IMAGE_IMPORT_DESCRIPTOR* pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)hModCaller + pOpNtHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); BOOL bFindDll = FALSE; while (pImportDesc->FirstThunk) { char* pszDllName = (char*)((BYTE*)hModCaller + pImportDesc->Name); if (stricmp(pszDllName, pszExportMod) == 0)//If the pszExportMod module is found, it is equivalent to "user32.dll" when hooking messageboxa { bFindDll = TRUE; break; } pImportDesc++; } if (bFindDll) { DWORD n = 0; //An IMAGE_THUNK_DATA is an import function IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)((BYTE*)hModCaller + pImportDesc->OriginalFirstThunk); while (pThunk->u1.Function) { // get function name char* pszFuncName = (char*)((BYTE*)hModCaller + pThunk->u1.AddressOfData + 2); //There are two in front of the function name.. //printf("function name:%-25s, ", pszFuncName); // Get function address PDWORD lpAddr = (DWORD*)((BYTE*)hModCaller + pImportDesc->FirstThunk) + n; //From the address of the first function, + 4 bytes each time thereafter //printf("addrss:%X\\ ", lpAddr); //Here is the comparison function address if (*lpAddr == (DWORD)pfnCurrent) //Find the function address in iat { DWORD* lpNewProc = (DWORD*)pfnNewFunc; MEMORY_BASIC_INFORMATION mbi; DWORD dwOldProtect; //Modify the protection attributes of the memory page ::VirtualQuery(lpAddr, & amp;mbi, sizeof(MEMORY_BASIC_INFORMATION)); ::VirtualProtect(lpAddr, sizeof(void*), PAGE_READWRITE, & amp;dwOldProtect); ::WriteProcessMemory(GetCurrentProcess(), lpAddr, & amp;lpNewProc, sizeof(void*), NULL); ::VirtualProtect(lpAddr, sizeof(void*), dwOldProtect, NULL); return; } n + + ; //Add one DWORD each time } } } void CAPIHOOK::ReplaceIATEntryInAllMods(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, BOOL bExcludeAPIHookMod) { //Get the current module handle HMODULE hModThis = NULL; if (bExcludeAPIHookMod) { MEMORY_BASIC_INFORMATION mbi; if (0 != ::VirtualQuery(ReplaceIATEntryInAllMods, & amp;mbi, sizeof(MEMORY_BASIC_INFORMATION))) //ReplaceIATEntryInAllMods must be a static function of the class { hModThis = (HMODULE)mbi.AllocationBase; } } //Get the module list of this process HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); if (INVALID_HANDLE_VALUE == hModuleSnap) { return; } me32.dwSize = sizeof( MODULEENTRY32 ); if( !Module32First( hModuleSnap, & amp;me32 ) ) { return; } do { //For each module if (me32.hModule != hModThis) { ReplaceIATEntryInOneMod(pszExportMod, pfnCurrent, pfnNewFunc, me32.hModule); } } while( Module32Next( hModuleSnap, & amp;me32 ) ); ::CloseHandle(hModuleSnap); //Paired writing } //prevent autoloading HMODULE WINAPI CAPIHOOK::LoadLibraryA(LPCTSTR lpFileName) { HMODULE hModule = LoadLibraryA(lpFileName); HookNewlyLoadedModule(hModule, 0); //This function detects hModule return hModule; } HMODULE WINAPI CAPIHOOK::LoadLibraryW(LPCTSTR lpFileName) { HMODULE hModule = LoadLibraryW(lpFileName); HookNewlyLoadedModule(hModule, 0); //This function detects hModule return hModule; } HMODULE WINAPI CAPIHOOK::LoadLibraryExA(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags) { HMODULE hModule = LoadLibraryExA(lpFileName, hFile, dwFlags); HookNewlyLoadedModule(hModule, dwFlags); //This function detects hModule return hModule; } HMODULE WINAPI CAPIHOOK::LoadLibraryExW(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags) { HMODULE hModule = LoadLibraryExW(lpFileName, hFile, dwFlags); HookNewlyLoadedModule(hModule, dwFlags); //This function detects hModule return hModule; }