这次想写一篇,自己曾经做过的一个Hook程序,温故而知新。
作为一个C++程序员,肯定对钩子(Hook)技术有所了解:消息钩子,API钩子。
基本概念:
钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
对于标题所描述的拦截带有某些关键字窗体,基本思路是:我们需要创建一个全局钩子,然后捕获到窗体显示消息,捕获到后利用Windows消息机制,抛出去到外层获取窗口标题,当匹配关键字时,给对应窗口发送关闭消息。
对于创建全局钩子,我们需要采用DLL注入的方式,Hook的DLL工程主代码如下:
#include <Windows.h>
#pragma data_seg("HookWnd")
HHOOK g_HookWnd = NULL; //钩子句柄
HWND g_DestWnd = NULL; //目的窗口句柄,就是截获的消息要发往什么窗口
HINSTANCE g_hInst = NULL;
#pragma data_seg()
#pragma comment( linker, "/section:HookWnd,RWS" )
__declspec(dllexport) BOOL SetHook(HWND hWnd);
__declspec(dllexport) void DestroyHook();
#define WM_MYMESSAGE (WM_USER + 1)
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
{
g_hInst = hinstDll;//保存应用程序实例
return TRUE;
}
LRESULT CALLBACK MyWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CWPSTRUCT *pCwp = reinterpret_cast<CWPSTRUCT*>(lParam);
if (pCwp->message == WM_SHOWWINDOW)
{
::SendMessage(g_DestWnd, WM_MYMESSAGE, wParam, reinterpret_cast<LPARAM>(pCwp->hwnd));
return 0;
}
else
return CallNextHookEx(g_HookWnd, nCode, wParam, lParam);
}
BOOL SetHook(HWND hWnd)
{
if (NULL == hWnd)
return FALSE;
g_DestWnd = hWnd;
//第三个参数还可通过些方法获得:GetModuleHandle("HookTest.dll")
return (NULL != (g_HookWnd = ::SetWindowsHookEx(WH_CALLWNDPROC, MyWndProc, g_hInst, 0)));
}
void DestroyHook()
{
if (NULL != g_HookWnd)
{
UnhookWindowsHookEx(g_HookWnd);
g_DestWnd = NULL;
}
}
SetWindowsHookEx(WH_CALLWNDPROC, MyWndProc, g_hInst, 0));最后一个参数0,代表创建的是全局钩子。
WH_CALLWNDPROC装载的是:窗口钩子,当系统向目标窗口发送消息时将触发此钩子 进入到MyWndProc回调函数处理;
当回调函数里面捕获到:WM_SHOWWINDOW消息,发送消息到外层处理;
外层消息处理函数为:
LRESULT CHookTestDlg::OnMyMessage( WPARAM wParam, LPARAM lParam )
{
HWND hwnd = reinterpret_cast<HWND>(lParam);
UINT nTitleLen = ::GetWindowTextLength(hwnd);
TCHAR *pStr = new TCHAR[nTitleLen + 1]();
ZeroMemory(pStr, nTitleLen + 1);
::GetWindowText(hwnd, pStr, nTitleLen + 1);
CString str(pStr);
delete []pStr;
if (str.Find(m_str) != -1) //CString查找字符串未找到返回-1
{
::SendMessage(hwnd, WM_CLOSE, NULL, NULL);
return 1;
}
return 0;
}
获取对应窗口句柄的窗口标题,和设置的关键字匹配,当满足条件则发送关闭消息;
外层调用Hook的DLL函数实例:
HINSTANCE hIst = NULL;
// 创建全局钩子,监控所有进程
void CHookTestDlg::OnCreateDllHook()
{
m_edit.GetWindowText(m_str);
m_edit.EnableWindow(FALSE);
hIst = ::LoadLibrary("..\\HookTest\\HookDll.dll"); // 加载dll
if (NULL != hIst)
{
typedef BOOL (*pFunSetHook)(HWND);
pFunSetHook pSetHook = (pFunSetHook)GetProcAddress(hIst, "SetHook");
if (NULL != pSetHook)
{
if(pSetHook(m_hWnd))
AfxMessageBox("创建全局钩子成功...");
}
}
}
//卸载全局钩子
void CHookTestDlg::OnDestroyDllHook()
{
if (NULL != hIst)
{
typedef void (*pFunDestroyHook)();
pFunDestroyHook pDestryHook = (pFunDestroyHook)GetProcAddress(hIst, "DestroyHook");
if (NULL != pDestryHook)
{
pDestryHook();
::FreeLibrary(hIst);
hIst = NULL;
AfxMessageBox("销毁全局钩子成功!");
}
}
m_edit.EnableWindow(TRUE);
}
.........
至此,一个简单的拦截窗口程序,已经实现。