Windows HooK钩子技术是指基于Windows中窗口的程序的消息处理机制,对系统或者进程中的消息进行截获和处理,并将截获和处理的消息在重新处理和发送,使其可以实现不同的功能。
钩子技术分为系统钩子技术和线程钩子技术
系统钩子:是用于监视系统中的消息的钩子技术,因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL) 中。做好之后使用其他程序将钩子挂载到系统的进程中。
线程钩子:指的是对指定线程进行监视。
钩子原理
在使用钩子技术的时候,WINDOWS会先在内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去。新的钩子将加到老的前面。当系统触发产生一个消息时,如果安装的是一个线程钩子,您进程中的钩子函数将被调用。如果是一个系统钩子,系统就必须把钩子函数插入到其它进程的地址空间,要做到这一点要求钩子函数必须在一个动态链接库中,所以如果您想要使用系统钩子,就必须把该钩子函数放到动态链接库中去。
当然有两个例外:工作日志钩子和工作日志回放钩子。这两个钩子的钩子函数必须在安装钩子的线程中。原因是:这两个钩子是用来监控比较底层的硬件事件的,既然是记录和回放,所有的事件就当然都是有先后次序的。所以如果把回调函数放在DLL中,输入的事件被放在几个线程中记录,所以我们无法保证得到正确的次序。故解决的办法是:把钩子函数放到单个的线程中,譬如安装钩子的线程。
几点需要说明的地方:
(1) 如果对于同一消息同时安装了线程钩子和系统钩子,那么系统会自动先调用线程钩子,然后调用系统钩子。
(2) 对同一消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。当前钩子处理结束后应把钩子信息传递给下一个钩子函数。而且最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。
(3) 钩子特别是系统钩子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装钩子,在使用完毕后要及时卸载。
钩子类型:
WH_CALLWNDPROC | 监视到达窗口前的消息 |
---|---|
WH_CALLWNDPROCRET | 监视窗口处理后的消息 |
WH_DEBUG | 监视系统调用其他HOOK关联的HOOK子程 |
WH_GETMESSAGE | 监视发送到窗体消息队列里的消息 |
WH_JOURNALPLAYBACK | 全局HOOK,可以插入消息到消息队列 |
WH_JOURNALRECORD | 全局HOOK,监视输入事件(键盘、鼠标等) |
WH_KEYBOARD | 键盘钩子 |
WH_MOUSE | 鼠标钩子 |
WH_MSGFILTER | 监视菜单、滚动条、消息框、对话框消息和切换窗口的组合键 (Alt+Tab等) |
WH_SHELL | 接收系统中重要的通知(如窗口被产生、摧毁等) |
使用的函数:
1、SetWindowsHookEx()安装钩子
SetWindowsHookEx函数是微软提供给程序开发人员进行消息拦截的一个API。不过,他的功能不仅可以用作消息拦截,还可以进行DLL注入。
SetWindowsHookEx原型声明如下:
HHOOK SetWindowsHookEx(
int idHook,
HOOKPROC lpfn,
HINSTANCE hmod,
DWORD dwThreadId
);
2、UnhookWindowsHookEx(卸载钩子函数)
BOOL WINAPI UnhookWindowsHookEx( HHOOK hhk);
3、CallNextHookEx()
将钩子信息传递到当前钩子链中的下一个子程,一个钩子程序可以调用这个函数之前或之后处理钩子信息
LRESULT WINAPI CallNextHookEx(
HHOOK hhk,
int nCode,
WPARAM wParam,
LPARAM lParam);
线程钩子
HHOOK g_hGetMsgHooK;//定义一个钩子句柄,在使用安装钩子函数之后,
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MSG* pMsg = (MSG*)lParam;
if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP)
{
if (pMsg->wParam == 0x41)
{
pMsg->wParam = 0x42;
}
}
return CallNextHookEx(g_hGetMsgHooK,nCode,wParam,lParam);
}
void C钩子技术_局部Dlg::OnBnClickedInstall()
{
//安装钩子
g_hGetMsgHooK = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, NULL, GetCurrentThreadId());
}
void C钩子技术_局部Dlg::OnBnClickedRemove()
{
// 取消钩子
UnhookWindowsHookEx(g_hGetMsgHooK);
}
系统钩子
#include
#include "kbh.h"
#include
static HINSTANCE hInst;//定义一个全局的变量
static FILE *f1;
static HHOOK hhook;
//这是一个dll动态链接库的入口
int WINAPI DllMain(HINSTANCE hInstance ,DWORD fdwReason,PVOID pvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
hInst = hInstance;
break;
}
return TRUE;
}
//钩子函数
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
char ch;
WORD w;
UINT scan = 0;
if (((DWORD)lParam & 0x40000000) && (HC_ACTION == nCode))
{
if ((wParam == VK_SPACE) || (wParam == VK_RETURN) || (wParam >= 0x2f) && (wParam <= 0x100))
{
f1 = fopen("D:\\export.txt","a+");
if (wParam == VK_RETURN)
{
ch = '\n';
fwrite(&ch,1,1,f1);
}
else
{
BYTE ks[256];
GetKeyboardState(ks);
ToAscii(wParam,scan,ks,&w,0);
ch = (char)w;
fwrite(&ch,1,1,f1);
}
fclose(f1);
}
}
return CallNextHookEx(hhook, nCode, wParam, lParam);
}
EXPORT void SetKbHookyxd(void)
{
hhook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hInst,(DWORD)NULL);
}
// Start_HOOK.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "Start_HOOK.h"
#include "kbh.h"
#pragma comment(lib,"KBH.lib")
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
// TODO: 在此放置代码。
MSG msg;
SetKbHookyxd();
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}