HOOK技术-满足我们程序的偷窥欲(二)

   话接上回,这次给个例子讲讲Hook的实例。

   这个例子是设置一个全局钩子,捕捉其它程序的键盘消息。

   首先,构建DLL,以便给其它程序映射。这个DLL文件名为KeyHook.h / KeyHook.cpp

   在KeyHook.h里面,导出两个函数,分别是设置Hook和取消Hook的函数。
   

//----------------------------------KeyHook.h-----------------------------------//

   #ifndef EXPERT
#define EXPERT extern "C" __declspec(dllimport)
#endif

EXPERT BOOL SetHook(HWND hwnd);  
//设置HOOK
EXPERT BOOL CancelHook(HWND hwnd);  //取消HOOK

#define WM_KEY_HOOK WM_USER+102 //自定义消息,设置自定义消息的作用是,当这个DLL截取到其它程序的键盘消息时,给我们的应用程序发送这个消息。


//-------------------------KeyHook.cpp---------------------//

#define EXPERT extern "C" __declspec(dllexport)

//定义DLL共享数据段,为的是这个段中的数据可以被本应用程序所改写
#pragma data_seg("HOOKSHARE")
HWND hwndServer
=NULL;
#pragma data_seg()
#pragma comment(linker,
"/section:HOOKSHARE,rws")

HINSTANCE hInst; 
//Dll的实例句柄
HHOOK hook;   //Hook句柄

LRESULT WINAPI WndHookProc(
int nCode,WPARAM wParam,LPARAM lParam); //钩子一旦挂上,这个WndHookProc就会接收其它应用程序的消息了。

BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
  
switch(ul_reason_for_call)
  
{
  
case DLL_PROCESS_ATTACH:
     hInst 
= (HINSTANCE)hModule;
     
return TRUE;
  
//在以后设置钩子时需要用到Dll的实例句柄。所以这里把hModule赋给了全局变量hInst,
  case DLL_PROCESS_DETACH:
     CancelHook(hwndServer);
  
return TRUE;
  }

  
return TRUE;
}



EXPERT BOOL SetHook(HWND hwnd)
{
   
if(hwndServer==NULL) //have't hook
   {
      hook 
= ::SetWindowsHookEx(WH_GETMESSAGE,WndHookProc,hInst,0); 
     
//设置全局钩子,这个钩子捕获消息,捕获消息传递到WndHookProc中去处理。hInst是保存了Dll的实例句柄。最后一个参数是线程的ID,设置0表示为全局钩子

      
if(hook!=NULL)
      
{
          hwndServer 
= hwnd; 
      
//把我们应用程序的窗口句柄赋给hwndServer.这样,我们在DLL中发送消息就有个目的地(即截取消息后发送到哪个窗口去处理)。
          return TRUE;
      }

      
else
        
return FALSE;
    }

    
else
      
return FALSE;
}


EXPERT BOOL CancelHook(HWND hwnd)
{
   
if(hwndServer!=NULL) //is hook
   {
      
if(UnhookWindowsHookEx(hook))
      
{
         hwndServer 
= NULL;
         
return TRUE;
      }

      
else
         
return FALSE;
   }

   
else
      
return FALSE;
}


LRESULT WINAPI WndHookProc(
int nCode,WPARAM wParam,LPARAM lParam)
{
   
if(nCode<0)
   
{
      ::CallNextHookEx(hook,nCode,wParam,lParam);
      
return 0;
   }


   LPMSG lpMsg 
= (LPMSG)lParam;
   
if(lpMsg->message == WM_KEYDOWN)
   
{
     
//如果消息是WM_KEYDOWN消息,则发送我们自定义的消息给我们的应用程序窗口(hwndServer)
     ::PostMessage(hwndServer,WM_KEY_HOOK,lpMsg->wParam,lpMsg->lParam);
     
return ::CallNextHookEx(hook,nCode,wParam,lParam);
   }

   
return 0;
}



下面,就要写我们的应用程序来处理DLL截获过来的消息了。假定我们的应用程序由一个对话框来处理。
对话框的文件名分别是:SendMsg.h     SendMsg.cpp


//------------------SendMsg.h---------------------//

//添加两个Button,分别是Hook / Unhook ,他们的处理程序分别是OnHook和OnUnhook
afx_msg void OnHook();
afx_msg 
void OnUnhook();
//自定义消息,当窗口接收到WM_KEY_HOOK消息时,就是用onHookMsg函数来处理
afx_msg LRESULT OnHookMsg(WPARAM wParam,LPARAM lParam);


//--------------------SendMsg.cpp-------------------//
#include "SetHook.h" //把Dll的.h文件添加进项目

//自定义消息映射
ON_MESSAGE(WM_KEY_HOOK,OnHookMsg)

//当点击Hook按纽时,设置Hook
void CSendMsg::OnHook()
{
   
if(!m_IsHook)
   
{
      BOOL isHook 
= SetHook(m_hWnd); //设置挂钩,让DLL映射进其它进程的地址空间
      if(isHook)
      
{
         m_Hook.EnableWindow(FALSE);
         m_UnHook.EnableWindow(TRUE);
         m_IsHook 
= TRUE;
      }

   }

}



//点击UnHook按纽时,取消hook
void CSendMsg::OnUnhook()
{
// TODO: Add your control notification handler code here
   if(m_IsHook)
   
{
      BOOL isHook 
= CancelHook(m_hWnd);
      
if(isHook)
      
{
         m_Hook.EnableWindow(TRUE);
         m_UnHook.EnableWindow(FALSE);
         m_IsHook 
= FALSE;
      }

   }

}



LRESULT CSendMsg::OnHookMsg(WPARAM wParam,LPARAM lParam)
{
//这里是当在别的进程中收到KeyDown消息后,转到这里来处理。
//可以在这里获得键盘的值,或者把KeyDown更改后转发都可以。
//具体的就不写了,还是比较简单的。
return 0;
}


   另外,还有其它编译时注意的事项,如果我们要编译本应用程序,需要和DLL一起编译,并且,要告诉编译器,这个项目的依赖项是KeyHook.dll(菜单:项目->项目依赖项)
posted @ 2007-01-04 21:31  shipfi  阅读(3689)  评论(0编辑  收藏