我上网参照一些神人的代码想写个全局API HOOK, 大致是这样实现的,做了一个全局钩子(WH_GETMESSAGE)来确保含有修改API代码的DLL被加载到很多进程中。DLL有个类,在加载的时候初始化,修改API(MessageBoxW). 现在好像DLL都被那些进程正确加载了,而且都进行了API的修改,但是为什么只对我本进程有效,其它进程都无效, 和COPY ON WRITE有关吗?代码如下:
DLL部分:
---------------------------------------------
BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
glhInstance = hInstance;
pCHC=new CHookClass("user32.dll","MessageBoxW",MessageBoxWProxy);
pCHC->HookOn();
break ;
case DLL_PROCESS_DETACH:
delete pCHC;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
} // WH_GETMESSAGE钩子处理过程
LRESULT CALLBACK GetMsgHookProc(int nCode,WPARAM wparam,LPARAM lparam)
{// 什么也不做(只是为了进入其它进程)
return CallNextHookEx(glhMsgHook,nCode,wparam,lparam);
}DLLEXPORT BOOL InstallHOOK( void )
{
if (glhMsgHook == NULL ){
glhMsgHook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgHookProc,glhInstance,0 );
}
if (glhMsgHook == NULL) {
return FALSE;
}
return TRUE;
}
// 卸载钩子
DLLEXPORT BOOL UninstallHOOK(void)
{
BOOL bResult=FALSE;
if(glhMsgHook){
bResult= UnhookWindowsHookEx(glhMsgHook);
if(bResult){
glhMsgHook=NULL;
}
}
return bResult;
}
DLL头文件:
---------------------------------------------
class CHookClass{
CHookClass(const CHookClass&);
// 不准拷贝和赋值
CHookClass &operator=(const CHookClass&);
// 栈对齐为1字节
#pragma pack(push,1)
struct TJmpCode{
char Jmp;
DWORD Ptr;
};
#pragma pack(pop)public:
CHookClass(const char *LibName, // DLL名
const char *FuncName, // 目标函数名
void *NewFuncPtr); // 用于替换的函数指针
~CHookClass(); void HookOn(); // 开启 API Hook
void HookOff(); // 关闭 API Hook
void Lock(); // 进入临界区
void Unlock(); // 退出临界区 bool IsHooked(){
return _IsHooked; // 取Hook状态
}
private:
TJmpCode _OrgCode; // 原函数头5个字节
TJmpCode _NewCode; // 新函数头5个字节(jmp FuncPtr) void *_TagFuncPtr; // 目标函数指针
HANDLE _CurProcess; // 当前进程
bool _IsHooked; // 显示是否被Hook了 CRITICAL_SECTION _cs; // 临界区
};// 构造
CHookClass::CHookClass(const char *LibName, const char *FuncName, void *NewFuncPtr)
:_TagFuncPtr(NULL),_IsHooked(false),_CurProcess(0)
{
// 取目标API地址
HMODULE hModule=GetModuleHandle(LibName);
_TagFuncPtr=GetProcAddress(hModule, FuncName);
if(_TagFuncPtr==NULL) throw(-1); // 保存原函数前五字节
CopyMemory(&_OrgCode,_TagFuncPtr,5);
// 新的五字节为 jmp 偏移
_NewCode.Jmp=0xe9;
_NewCode.Ptr=DWORD(NewFuncPtr)-DWORD(_TagFuncPtr)-5;
// 以特权方式打开当前进程
_CurProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE, GetCurrentProcessId());
LogInfo("当前进程句柄%d",_CurProcess); InitializeCriticalSection(&_cs);
}
// 析构
CHookClass::~CHookClass()
{
if(_IsHooked) HookOff();
DeleteCriticalSection(&_cs);
}void CHookClass::HookOn()
{// !开启 API Hook
if(!_IsHooked){
DWORD dwOldProtect;
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
WriteProcessMemory(_CurProcess, _TagFuncPtr, &_NewCode, 5, NULL);
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, dwOldProtect, &dwOldProtect);
_IsHooked=true;
LogInfo("进程%d的API修改完成",GetCurrentProcessId());
}
}
void CHookClass::HookOff()
{// !关闭 API Hook
if(_IsHooked){
DWORD dwOldProtect;
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
WriteProcessMemory(_CurProcess, _TagFuncPtr, &_OrgCode, 5, NULL);
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, dwOldProtect, &dwOldProtect);
_IsHooked=false;
}
}有查看调度日志时发现,很多进程都载入了APIHOOK.dll, 而且在HookOn时都有改写MessageBoxW,为什么其它进程无效呀? APIHOOK.DLL已和这些进程在同一地址空间了呀,郁闷 望各位大侠不吝赐教!
DLL部分:
---------------------------------------------
BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
glhInstance = hInstance;
pCHC=new CHookClass("user32.dll","MessageBoxW",MessageBoxWProxy);
pCHC->HookOn();
break ;
case DLL_PROCESS_DETACH:
delete pCHC;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
} // WH_GETMESSAGE钩子处理过程
LRESULT CALLBACK GetMsgHookProc(int nCode,WPARAM wparam,LPARAM lparam)
{// 什么也不做(只是为了进入其它进程)
return CallNextHookEx(glhMsgHook,nCode,wparam,lparam);
}DLLEXPORT BOOL InstallHOOK( void )
{
if (glhMsgHook == NULL ){
glhMsgHook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)GetMsgHookProc,glhInstance,0 );
}
if (glhMsgHook == NULL) {
return FALSE;
}
return TRUE;
}
// 卸载钩子
DLLEXPORT BOOL UninstallHOOK(void)
{
BOOL bResult=FALSE;
if(glhMsgHook){
bResult= UnhookWindowsHookEx(glhMsgHook);
if(bResult){
glhMsgHook=NULL;
}
}
return bResult;
}
DLL头文件:
---------------------------------------------
class CHookClass{
CHookClass(const CHookClass&);
// 不准拷贝和赋值
CHookClass &operator=(const CHookClass&);
// 栈对齐为1字节
#pragma pack(push,1)
struct TJmpCode{
char Jmp;
DWORD Ptr;
};
#pragma pack(pop)public:
CHookClass(const char *LibName, // DLL名
const char *FuncName, // 目标函数名
void *NewFuncPtr); // 用于替换的函数指针
~CHookClass(); void HookOn(); // 开启 API Hook
void HookOff(); // 关闭 API Hook
void Lock(); // 进入临界区
void Unlock(); // 退出临界区 bool IsHooked(){
return _IsHooked; // 取Hook状态
}
private:
TJmpCode _OrgCode; // 原函数头5个字节
TJmpCode _NewCode; // 新函数头5个字节(jmp FuncPtr) void *_TagFuncPtr; // 目标函数指针
HANDLE _CurProcess; // 当前进程
bool _IsHooked; // 显示是否被Hook了 CRITICAL_SECTION _cs; // 临界区
};// 构造
CHookClass::CHookClass(const char *LibName, const char *FuncName, void *NewFuncPtr)
:_TagFuncPtr(NULL),_IsHooked(false),_CurProcess(0)
{
// 取目标API地址
HMODULE hModule=GetModuleHandle(LibName);
_TagFuncPtr=GetProcAddress(hModule, FuncName);
if(_TagFuncPtr==NULL) throw(-1); // 保存原函数前五字节
CopyMemory(&_OrgCode,_TagFuncPtr,5);
// 新的五字节为 jmp 偏移
_NewCode.Jmp=0xe9;
_NewCode.Ptr=DWORD(NewFuncPtr)-DWORD(_TagFuncPtr)-5;
// 以特权方式打开当前进程
_CurProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE, GetCurrentProcessId());
LogInfo("当前进程句柄%d",_CurProcess); InitializeCriticalSection(&_cs);
}
// 析构
CHookClass::~CHookClass()
{
if(_IsHooked) HookOff();
DeleteCriticalSection(&_cs);
}void CHookClass::HookOn()
{// !开启 API Hook
if(!_IsHooked){
DWORD dwOldProtect;
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
WriteProcessMemory(_CurProcess, _TagFuncPtr, &_NewCode, 5, NULL);
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, dwOldProtect, &dwOldProtect);
_IsHooked=true;
LogInfo("进程%d的API修改完成",GetCurrentProcessId());
}
}
void CHookClass::HookOff()
{// !关闭 API Hook
if(_IsHooked){
DWORD dwOldProtect;
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);
WriteProcessMemory(_CurProcess, _TagFuncPtr, &_OrgCode, 5, NULL);
VirtualProtectEx(_CurProcess, _TagFuncPtr, 5, dwOldProtect, &dwOldProtect);
_IsHooked=false;
}
}有查看调度日志时发现,很多进程都载入了APIHOOK.dll, 而且在HookOn时都有改写MessageBoxW,为什么其它进程无效呀? APIHOOK.DLL已和这些进程在同一地址空间了呀,郁闷 望各位大侠不吝赐教!
关于宿主进程句柄的获取没有问题的:我的日志记录如下:
当前进程句柄1480
进程2060的API修改完成
当前进程句柄0
进程1044的API修改完成
当前进程句柄0
进程3556的API修改完成
进程3272的API修改完成
当前进程句柄4040
进程836的API修改完成
当前进程句柄4756
进程3984的API修改完成
当前进程句柄0
进程1236的API修改完成
当前进程句柄4412
进程2180的API修改完成
当前进程句柄2696
进程252的API修改完成
当前进程句柄0
进程2184的API修改完成
当前进程句柄0
进程980的API修改完成
当前进程句柄0
进程552的API修改完成
进程836的API修改完成
在DLL_PROCESS_ATTACH时就调用了HOOK的过程(这点不知道会不会有影响),但看起来象是没影响的,如上面的日志所示。走过路过的大侠们,帮帮忙。
没有仔细看你的代码,但,估计你是遭遇到Windows的copy-on-write机制了,
建议看看这篇,或许对你有帮助。绕过Copy-On-Write机制安装全局Hook
http://dev.firnow.com/course/3_program/c++/cppsl/20081117/151293.html