WINDOWS下HOOK函数的方法
前两天和dvff谈论的一些技术总结。程序代码:
///////////////////////////////////////////////////////////////////////////////////// // HOOKAPI DEMO PROGRAM //文件名:HOOKTEST.C // //描述: 演示WINNT下HOOK系统API过程及方法 // (扩充为HOOK任意函数的方法) // //作者:东海一鱼 // //时间: 2010.7.22 // //使用编译器: VC2003 // //使用第三方库: NULL // // //Bug、修复纪录: // 1、2010.8.4 增加HOOK私有函数代码(被hook函数名TestFn,hook函数名MyHookFn2) // // 2、2010.8.6 增加HOOK类虚拟函数代码(被hook函数名TestVirtualFn, // hook函数名TestVirtualFn2) // // HOOK类成员函数,主要难度在于成员函数地址的获得。 // 普通成员函数指针在VC6下无法进行强制类型转换, // 解决手段见GetClassFnAddress辅助函数。 // 类虚拟成员函数HOOK需要获得类实例对象虚表中的虚拟函数指针。 //////////////////////////////////////////////////////////////////////////////////// #include <stdlib.h> #include <stdio.h> #include <windows.h> //#pragma pointers_to_members(best_case) #ifdef _X86_ #define FLATJMPCODE_LENGTH 5 //x86 平坦内存模式下,绝对跳转指令长度 #define FLATJMPCMD_LENGTH 1 //机械码0xe9长度 #define FLATJMPCMD 0xe9 #else #error WINVER ERRORSLECT ONLY USES ON X86!!! #endif /////////////////////////////////////////////////////////////////////////// //测试类函数HOOK class TestHookFnClass { public: virtual void TestVirtualFn(char* szPlay); virtual void TestVirtualFn2(char* szPlay); void TestHookFn(char* szPlay); void TestHookFn2(char* szPlay); }; void TestHookFnClass::TestHookFn(char* szPlay) { printf("%s\n",szPlay); } void TestHookFnClass::TestHookFn2(char* szPlay) { printf("%s - %s\n ",szPlay,"类函数已被HOOK!"); } void TestHookFnClass::TestVirtualFn(char* szPlay) { printf("%s\n",szPlay); } void TestHookFnClass::TestVirtualFn2(char* szPlay) { printf("%s - %s\n",szPlay,"Virtual2 HOOKS"); } ///////////////////////////////////////////////////////////////////////// #ifdef _X86_ //利用C变参特性,进行类成员函数指针类型转换 LPVOID GetClassFnAddress(...) //Add 2010.8.6 { LPVOID FnAddress; __asm { lea eax,FnAddress mov edx,[ebp+8] mov [eax],edx } return FnAddress; } #endif //获得类虚拟成员函数指针 LPVOID GetClassVirtualFnAddress(LPVOID pthis,int Index) //Add 2010.8.6 { LPVOID FnAddress; *(int*)&FnAddress = *(int*)pthis; //lpvtable *(int*)&FnAddress = *(int*)((int*)FnAddress + Index); return FnAddress; } ///////////////////////////////////////////////////////////////////////// //我的新API函数 int __stdcall MyHookFn(HWND hwnd,char* sztext,char* szTitle,int stly) { return printf("%s - %s\n",sztext,"原API函数已被HOOK!"); // } //我的新私有桩函数 void MyHookFn2(char* szTxt) { char* pBuf = (char*)malloc(strlen(szTxt) + sizeof(char*) * 32); __try { sprintf(pBuf,"%s - %s",szTxt," 原函数已被HOOK!"); printf("%s\n",pBuf); } __finally { free(pBuf); } } //私有测试函数 void TestFn(char* szTitle) { printf("%s",szTitle); } ////////////////////////////////////////////////////////////////////// //HOOK函数 BOOL HookApi(LPVOID ApiFun,LPVOID HookFun) { BOOL IsSuccess = FALSE; DWORD TempProtectVar; //临时保护属性变量 MEMORY_BASIC_INFORMATION MemInfo; //内存分页属性信息 VirtualQuery(ApiFun,&MemInfo,sizeof(MEMORY_BASIC_INFORMATION)); if(VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize, PAGE_READWRITE,&MemInfo.Protect)) //修改页面为可写 { *(BYTE*)ApiFun = FLATJMPCMD; *(DWORD*)((BYTE*)ApiFun + FLATJMPCMD_LENGTH) = (DWORD)HookFun - (DWORD)ApiFun - FLATJMPCODE_LENGTH; VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize, MemInfo.Protect,&TempProtectVar); //改回原属性 IsSuccess = TRUE; } return IsSuccess; } int main(int argc,char** argv) { HMODULE hDll; LPVOID OldFun; TestHookFnClass* TestClass = new TestHookFnClass(); __try { hDll = GetModuleHandle("User32.dll"); OldFun = GetProcAddress(hDll,"MessageBoxA"); //要HOOK的API函数 if(OldFun) { if(HookApi(OldFun,MyHookFn)) //如果HOOK成功 MessageBoxA(0,"call Api MessageBox","Is Hookd?",MB_OK); //调用原API,测试HOOK if(HookApi(TestFn,MyHookFn2)) TestFn("Private Function Hook Test"); //调用私有函数,测试HOOK if(HookApi(GetClassFnAddress(TestHookFnClass::TestHookFn), GetClassFnAddress(TestHookFnClass::TestHookFn2))) TestClass->TestHookFn("Hook Class Member Function Test!");//调用类成员函数,测试HOOK if(HookApi(GetClassVirtualFnAddress(TestClass,0), GetClassFnAddress(TestHookFnClass::TestHookFn2))) TestClass->TestVirtualFn("Call Class Virtual Function Test!");//调用类虚拟函数,测试HOOK if(HookApi(GetClassVirtualFnAddress(TestClass,0), GetClassVirtualFnAddress(TestClass,1))) TestClass->TestVirtualFn("Call Class Virtual Function Test2!");//同上,桩函数为另一虚函数 } } __finally { if(hDll) FreeLibrary(hDll); if(TestClass) delete(TestClass); } return 0; }