我上网参照一些神人的代码想写个全局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已和这些进程在同一地址空间了呀,郁闷 望各位大侠不吝赐教!

解决方案 »

  1.   

    我没有仔细看你的逻辑,既然你说在其他进程已经加载并hook成功了,那么,你是否确定调用了MessageBoxWProxy这个函数呢?
      

  2.   

    Windows消息分为队列消息和非队列消息,WH_GETMESSAGE不能取到非队列消息,用SendMessage发送的消息不经过队列,用PostMessage发送的消息被放入队列
      

  3.   

    不懂C++语法,不过以前用汇编写过一个全局HOOK的DLL,流程与你的不同.一,你_CurProcess句柄的获取,我是在DLL_PROCESS_ATTACH时调用GetCurrentProcess得到,参考自老罗的<<WINDOWS环境下32位汇编语言程序设计>>.这个函数只有在这个时候调用才能得到正确的句柄(书中的意思).二,所有涉及修改的内存操作都使用ReadProcessMemory/WriteProcessMemory来完成.三,DLL中有一个标志,用于判断是否已经被HOOK了.四,HOOK的过程写在CALLBACK GetMsgHookProc中,通过判断上面的标志来决定是否HOOK,并与主进程建立通讯.因此在DLL被加载到目标进程后,当有一个消息到来时,才开始HOOK.而你的代码是在DLL_PROCESS_ATTACH时就调用了HOOK的过程,这个时机不知道是否正确.五,以上仅供参考......
      

  4.   

    我不需要所有进程都挂上DLL,有消息循环的挂上即可。比如现在是我确定记事本已挂上了APIHOOK.DLL,而且代码 :LogInfo("进程%d的API修改完成",GetCurrentProcessId());已确实执行了。为什么会拦截不到MessageBoxW呢:(, 我用远程注入修改IAT的方式可以拦截这个函数的,说明记事本程序的确是调用了MessageBoxW。
      

  5.   


    关于宿主进程句柄的获取没有问题的:我的日志记录如下:
    当前进程句柄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的过程(这点不知道会不会有影响),但看起来象是没影响的,如上面的日志所示。走过路过的大侠们,帮帮忙。
      

  6.   

    楼主用hook注入啊,我都是用CreateRemoteThread注入的,感觉比hook好用的。
      

  7.   

    CreateRemoteThread 我实现了,只是不明白用HOOK为什么实现不了,望大侠们不吝赐教!
      

  8.   

    昨晚试了用VC6 生成, 居然一切OK, 天哪,偶要崩溃了!为什么用VS2008 或VS2010生成的就只能HOOK 自己。而VC6 生成的都可以HOOK ,explore,notepad都行. 高手们,大侠们,指点指点,谢谢了!
      

  9.   

    嗯,想写个全局Hook API啊,这可不是闹着玩的。
    没有仔细看你的代码,但,估计你是遭遇到Windows的copy-on-write机制了,
    建议看看这篇,或许对你有帮助。绕过Copy-On-Write机制安装全局Hook
    http://dev.firnow.com/course/3_program/c++/cppsl/20081117/151293.html
      

  10.   

    我也遇到过类似经历,而且是Debug版,可以Release版通不过,也是一头雾水啊。不知道是不是跟VS2008的编译优化有关???