Windows 钩子

Windows钩子

Windows应用程序的运行模式是基于消息驱动的,任何线程只要注册了窗口类都会有一个消息队列来接受用户的消息和系统消息。为了取得特定线程接受或发送的消息,就要用到windows提供的钩子。

1、钩子的概念

钩子(Hook),Windows消息处理机制中的一个监视点,应用程序可以在这里安装一个子程序(钩子函数)一监视制定窗口某种类型的消息,所监视的窗口可以是其他进程创建的。当消息到达后,在没有到达目标窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数既可以加工处理(改变)该消息,也可以不作处理而继续传递该消息。

总之,关于Windows钩子要知道以下几点:

(1)钩子是用来截获系统中的消息流的。利用钩子可以处理任何感兴趣的消息,包括其他进程的消息。

(2)截获消息后,用于处理消息的子程序叫做钩子函数,它是应用程序自定义的一个函数,在安装钩子时要把这个函数的地址告诉Windows

(3)系统中同一时间可能有多个进程安装了钩子函数,多个钩子函数在一起组成钩子链。所以在处理截获到的消息时,应该把消息事件传递下去,以便其他钩子也有机会处理这一消息。

钩子会是系统变慢,因为它增加了系统对每个消息的处理量。仅应该在必要的时候才安装钩子,而且在不需要的时候应尽快移除。

2、钩子的安装和卸载

1、安装钩子

SetWindowsHookEx 函数可以把用应用程序定义的钩子函数安装到系统中。函数用法如下:

HHOOK SetWindowsHookEx(         

int idHook, //制定钩子的类型

HOOKPROC lpfn, //钩子函数的地址。如果使用的是远程钩子,钩子函数必须放在一个DLL

HINSTANCE hMod, //钩子函数所在DLL的实例句柄。如果是一个局部的钩子,该参数的值为NULL

DWORD dwThreadId //制定要为哪个线程安装钩子。如果该值为0,那么该钩子将被解释成系统范围内的

);

参数解释:

(1)idHook参数制定了要安装的钩子类型,可以是下列取值之一:

WH_CALLWNDPROC:当目标线程调用SendMessage函数发送消息时,钩子函数被调用 

WH_CALLWNDPROCRET:SendMessage发送的消息返回时,钩子函数被调用

WH_GETMESSAGE:当目标线程调用GetMessagePeekMessage

WM_KEYBOARD:当从消息队列中查询WM_KEYUPWM_KEYDOWN消息时

WH_MOUSE:当调用从消息队列中查询鼠标事件时

WH_MSGFILTER:当对话框、菜单或滚动条要处理一个消息时,钩子函数被调用。该钩子时局部的,它是为那些有自己消息处理过程的控件设计的

WH_SYSMSGFILTER:WH_MSGFILTER一样,只不过是系统范围的

WH_JOURNALRECORD:Windows从硬件队列中获得消息时

WH_JOURNALPLAYBACK:当一个事件从系统的硬件输入队列中被请求时

WH_SHELL:当关于Windows外壳事件发生时,比如任务条需要重画它的按钮

WH_CBT:当基于计算机的训练(CBT)事件发生时

WH_FOREGROUNDIDLE:Windows自己使用,一般的应用程序很少使用

WH_DEBUG:用来给钩子函数除错

(2)lpfn参数是钩子函数的地址。钩子安装以后如果有相应的消息发生,Windows将调用此参数指定的函数。比如,idHook的值时WH_MOUSE,则当目标线程的消息队列中有鼠标消息取出时,lpfn函数就会被调用。

如果dwThreadId参数是0,或者指定一个由其他进程创建的线程IDlpfn参数指向的钩子函数必须位于一个DLL中。这是因为进程的地址空间相互隔离的,发生事件的进程不能调用其他进程地址空间的钩子函数。如果钩子函数的实现代码在DLL中,在相关事件发生时,系统会把这个DLL插入到发生事件的进程的地址空间,使它能够调用钩子函数。这种需要将钩子函数写入DLL以便挂钩其他进程事件的钩子称为远程钩子。

如果dwThreadID参数指定一个由自身进程创建的线程IDlpfn参数指向的钩子函数只要在当前进程中即可,不必写入DLL。这种仅挂钩属于自身进程事件的钩子称为局部钩子。

(3)hmod参数是钩子函数所在的DLL的实例句柄,如果钩子函数不在DLL中,应将hmod的值设为NULL

(4)dwThreadID参数指定要与钩子相关联的线程ID号。如果设为0,那么该钩子就是系统范围内的,即钩子函数将关联到系统内的所有线程。

2、钩子函数

钩子安装以后如果有相应的消息发生,Windows将调用SetWindowsHookEx函数指定的钩子函数lpfn。钩子函数的一般形式如下所示:

LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam)

{

//...处理该消息的代码

return ::CallNextHookEx(hHook,nCode,wParam,lParam);

}

HookProc是应用程序定义的名字。nCode参数是Hook代码,钩子函数使用这个参数来确定任务,它的值依赖于Hook的类型。wParamlParam参数的值依赖于Hook代码,但是它的典型的值时一些关于发送或者接受消息的信息。

因为系统中可能会有多个钩子存在,所以要调用CallNextHookEx函数把消息传到链中下一个钩子。hHook参数是安装钩子时得到的钩子句柄(SetWindowsHookEx的返回值)

3、卸载钩子

要卸载钩子,可以调用 UnHookWindowsHookEx函数。

BOOL UnhookWindowsHookEx(HHOOK hhk); // hhk为要卸载的钩子函数

示例可在我的资源中找到。

1、通过内存地址取得模块句柄

HMODULE WINAPI ModuleFromAddress(PVOID pv) 

{

MEMORY_BASIC_INFORMATION mbi;

if(::VirtualQuery(pv, &mbi, sizeof(mbi)) != 0)

{

return (HMODULE)mbi.AllocationBase;

}

else

{

return NULL;

}

}

MEMORY_BASIC_INFORMATION结构体:

typedef struct _MEMORY_BASIC_INFORMATION { 

  PVOID BaseAddress;  //保留区域的基地址

  PVOID AllocationBase;  //VirtualAlloc函数分配的基地址

  DWORD AllocationProtect;  //初次保留时设置的保护属性,可能是PAGE_EXECUTE,PAGE_READWRITE

  DWORD RegionSize;  //区域大小

  DWORD State;  //状态(提交、保留或空闲)

  DWORD Protect;  //当前访问保护属性

  DWORD Type;  //页面类型

  } MEMORY_BASIC_INFORMATION; 

typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION; 

虚拟管理内存函数VirtualQuery:

DWORD VirtualQuery(

  LPCVOID lpAddress, //内存地址

  PMEMORY_BASIC_INFORMATION lpBuffer, // MEMORY_BASIC_INFORMATION 指针

  DWORD dwLength //MEMORY_BASIC_INFORMATION对象的大小

); 

 

摘自:王艳平 张铮《windows程序设计<第二版>》其中示例也此书中提供的光盘。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值