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;
}
// 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;
}