Hook 技术「建议收藏」

Hook 技术「建议收藏」一、原理钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。  钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息

大家好,又见面了,我是你们的朋友全栈君。

一、原理

钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

    钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。这和前面我博客的窗口子类化都异曲同工,但是Hook可强大多了,我是这两天才开始看的,所以略知皮毛。

/* 钩子的原理 */
    我听完孙鑫老师C++教程里的解释,觉得还是把Hook讲得比较形象,加上我自己的一些理解就觉得Hook原理不是很难。windows一直都是有自己处理各种消息的函数,Hook其实就能够做到程序员自己处理自己感兴趣的事情。这样说,假设Windows的消息就是马路上的车辆,一般情况下是Windows自己派人在检查,然后呢,Hook是拥有这个能力能在Windows自己安排的检查站之前也进行抽查,Hook根据程序员的需求可以变化,比如我就感兴趣100万以上的车(可能是走私的(*^__^*)),Hook就能在检查的时候专门找100万以上的车,至于其他不上档次的车Hook就放行,交还给Windows自己的检查站。同样Hook可以“为所欲为”,可以擅自设立一个检查站,也可以两个,三个···换成程序来说,钩子函数的工作原理是:当我们创建一个钩子时,WINDOWS会先在内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去。新的钩子将加到老的前面。当一个事件发生时,如果我们安装的是一个局部钩子(下面有解释,暂时理解为你程序本身中的),我们进程中的钩子函数将被调用。


/* 钩子链表和函数 */
    每一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。被Hook子程调用的回调函数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。一些Hook子程可以只监视消息,或者修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。钩子子程是一个应用程序定义的回调函数(CALLBACKFunction),不能定义成某个类的成员函数,只能定义为普通的C函数。用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事件。
钩子子程必须按照以下的语法:

LRESULT CALLBACK HookProc
(
int nCode, //指定是否需要处理该消息 
WPARAM wParam, 
LPARAM lParam //包含该消息的附加消息 ,
);

这个回调函数的名字可以随你取,但形式可一定要满足以上要求,其实钩子的回调函数和Windows的差不多一个德行。看看钩子函数的返回值,若是返回非0值,表示我们已经自己处理了该消息,则消息就不被传递到目标窗口过程。


二、相关函数

1、SetWindowsHookEx函数

函数原型:

<span style="font-family:Times New Roman;font-size:14px;">HHOOK SetWindowsHookEx(
  int idHook,        // hook type
  HOOKPROC lpfn,     // hook procedure
  HINSTANCE hMod,    // handle to application instance
  DWORD dwThreadId   // thread identifier
);</span>

函数功能:
该函数将一个应用程序定义的挂钩处理过程安装到挂钩链中去,您可以通过安装挂钩处理过程来对系统的某些类型事件进行监控,这些事件与某个特定的线程或系统中的所有事件相关.具体参数详见MSDN;

参数说明:

iHook:指定了钩子的种类,统计有13种,如下

   WH_CALLWNDPROC 系统将消息发送到指定窗口之前的”钩子” 


   WH_CALLWNDPROCRET 消息已经在窗口中处理的”钩子” 


   WH_CBT 基于计算机培训的”钩子” 


   WH_DEBUG 差错”钩子” 


   WH_FOREGROUNDIDLE 前台空闲窗口”钩子” 


   WH_GETMESSAGE 接收消息投递的”钩子” 


   WH_JOURNALPLAYBACK 回放以前通过WH_JOURNALRECORD”钩子”记录的输入消息 


   WH_JOURNALRECORD 输入消息记录”钩子” 


   WH_KEYBOARD 键盘消息”钩子” 


   WH_MOUSE 鼠标消息”钩子” 


   WH_MSGFILTER 对话框、消息框、菜单或滚动条输入消息”钩子” 


   WH_SHELL 外壳”钩子” 

   WH_SYSMSGFILTER 系统消息”钩子” 

lpfn: 指向钩子的处理函数指针,指向的函数一定要满足在上一节中“钩子链表和函数”中所讲述的格式,否则会出错

hMod: 标识了钩子处理函数所处模块的句柄

dwThreadID: 指定所需监视的线程Id

第三个参数hMod和第四个参数dwThreadID还有另外一层关系,当第三个参数为NULL是,添加时局部钩子,钩子的回调函数位于当前进程,那么第四个参数就是当前线程的ID–GetCurrentThreadID();当第四个参数为NULL的时候,则说明添加的是全局钩子,钩子的回调函数与所有的线程关联,此时第三个参数是程序实例句柄;

举例:

HHOOK g_hMouse;//全局变量,保存钩子的句柄
LRESULT CALLBACK MouseProc(
  int nCode,      // hook code
  WPARAM wParam,  // message identifier
  LPARAM lParam   // mouse coordinates
)
{
  //……
}
g_hMouse=SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());

2、CallNextHookEx函数

函数原型:

<span style="font-family:Times New Roman;font-size:14px;">LRESULT CallNextHookEx(
  HHOOK hhk,      // handle to current hook
  int nCode,      // hook code passed to hook procedure
  WPARAM wParam,  // value passed to hook procedure
  LPARAM lParam   // value passed to hook procedure
);</span>

函数功能:

调用下一个钩子

参数说明:

hhk:当前钩子的句柄

nCode: 钩子代码

wParam: 要传递的参数

lParam   : 要传递的参数

举例:

LRESULT CALLBACK MouseProc<span style="font-family: Calibri; font-size: 16px; line-height: 24px; orphans: 2; widows: 2;"></span>(int nCode,WPARAM wParam,LPARAM lParam)
{
   if(nCode<0)
   {
      ::CallNextHookEx(g_hMouse,nCode,wParam,lParam);
      return 0;
   }
  /*
<span style="white-space:pre">	</span>your code
  */
<span style="font-family: Arial, Helvetica, sans-serif;">   return 0;
</span><span style="font-family: Arial, Helvetica, sans-serif;">}</span>

3、UnhookWindowsHookEx函数

函数原型:

<span style="font-family: 'Times New Roman';"><span style="font-size:10px;">BOOL UnhookWindowsHookEx( HHOOK hhk);  </span></span><span style="font-size: 10px; font-family: 'Times New Roman';">   // handle to hook procedure</span>

函数功能:删除钩子,这个一般和SetWindowsHookEx()对应使用;

参数说明:

hhk: SetWindowsHookEx() 得到的钩子句柄

三、小实例

我们创建一个局部钩子的小实例来讲解下,也许大家能更好的理解

实例的功能是截获对话框的所有鼠标和键盘消息

1、创建一个基于对话框的工程

2、在对话框cpp文件中创建鼠标消息和键盘消息的处理函数(也有人叫做子程)

LRESULT WINAPI MousePro(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(m_bFlag)
	{
		::CallNextHookEx(g_hMouse, nCode, wParam, lParam);
		return 0;
	}

	TRACE0("\r\nrecv Mouse message!!!");
	return 1;
}

LRESULT WINAPI BoardPro(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(wParam == 'C')	m_bFlag = true;
	if(wParam == 'O')	m_bFlag = false;

	if(m_bFlag)
	{
		::CallNextHookEx(g_hBoard, nCode, wParam, lParam);
		return 0;
	}
	
	CString strNotice;
	strNotice.Format("\r\n recv KeyBoard value is %d", wParam);

	TRACE0(strNotice);
	return 1;
}

注意:只有处理函数返回1时,才能彻底截断当前对话框的鼠标或者键盘消息;

3、在OnInitDialog()中添加钩子

BOOL CtestHookDlg::OnInitDialog(){	CDialog::OnInitDialog();	// 将“关于...”菜单项添加到系统菜单中。        //其他的代码<span style="white-space:pre">	</span>//<span style="white-space:pre">	</span>SetIcon(m_hIcon, TRUE);<span style="white-space:pre">			</span>// 设置大图标<span style="white-space:pre">	</span>SetIcon(m_hIcon, FALSE);<span style="white-space:pre">		</span>// 设置小图标<span style="white-space:pre">	</span>g_hBoard = ::SetWindowsHookEx(WH_KEYBOARD, BoardPro, NULL, GetCurrentThreadId());<span style="white-space:pre">	</span>g_hMouse = ::SetWindowsHookEx(WH_MOUSE, MousePro, NULL, GetCurrentThreadId());<span style="white-space:pre">	</span>return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE}

4、在程序的结束处删除钩子

void CtestHookDlg::OnDestroy(){	CDialog::OnDestroy();	::UnhookWindowsHookEx(g_hMouse);	::UnhookWindowsHookEx(g_hBoard);}

5、前面忘了告诉大家,还要在cpp文件的最开头添加变量定义和函数声明

HHOOK g_hMouse;HHOOK g_hBoard;bool m_bFlag = false;LRESULT WINAPI MousePro(int nCode, WPARAM wParam, LPARAM lParam);LRESULT WINAPI BoardPro(int nCode, WPARAM wParam, LPARAM lParam);

参考文章:
http://www.cnblogs.com/cryinstall/archive/2011/08/30/2280826.html

http://www.cnblogs.com/shipfi/archive/2006/12/26/604359.html

http://www.cnblogs.com/lidabo/p/3494603.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/141136.html原文链接:https://javaforall.net

(0)
上一篇 2022年5月26日 下午3:20
下一篇 2022年5月26日 下午3:40


相关推荐

  • Clipper库中文文档详解

    Clipper库中文文档详解Clipper 库中文文档详解简介 ClipperLibra 以下简称为 Clipper 库或 ClipperLib 或 Clipper 提供了对线段和多边形的裁剪 Clipping 以及偏置 offseting 的功能和其他的裁剪库相比 Clipper 具有以下特征 1 它能够接受各类多边形输入 包含自交的多边形 2 它支持多种填充规则 奇偶填充 非零填充 正填充 负填充 3 它相较于其他库效率极高 4 它数值稳定 鲁棒性强 鲁棒性 鲁棒性百科简介 5 它支持多边形和线段的偏置 6 它对于商

    2026年3月18日
    3
  • 部分链接

    部分链接url http api baiyug cn vip index php url name 超清 url http www vipjiexi com yun php url name 接口 1url http api 1008net com v php url name 接口 2url http api nepian com

    2026年3月18日
    2
  • 挖矿病毒攻击的排查处置手册

    挖矿病毒攻击的排查处置手册一、背景在用户不知情或未经允许的情况下,占用系统资源和网络资源进行挖矿,影响用户的网络和资源,从而获取虚拟币牟利。为了帮助应对恶意挖矿程序攻击,发现和清除恶意挖矿程序,防护和避免感染恶意挖矿程序,整理了如下针对挖矿活动相关的现状分析和检测处置建议。二、为什么会感染恶意挖矿程序通常遇到企业内网主机感染恶意挖矿程序,或者网站、服务器以及使用的云服务被植入恶意挖矿程序的时候,都不免提出“为什么会感染恶意挖矿程序,以及是如何感染的”诸如此类的问题,目前感染恶意挖矿程序的主要方式:2.1.利用类似其他病毒木

    2022年5月29日
    62
  • 音频可视化图形引擎—Specinker「建议收藏」

    音频可视化图形引擎—Specinker「建议收藏」bo主有话说:喜欢音乐的小伙伴相信都或多或少看到过一些频谱,简单的比如QQ音乐,酷狗等一些音乐软件上面都有一些,可惜的是这些频谱嵌入到软件界面上,好看的就那么一两个,并不能满足一些人对音乐的渴望,至少对我来说,是这样的。当然,还可以使用雨滴,AE来制作非常炫酷的频谱,但是这两个软件却也有一些弊端。通过雨滴,我们可以制作一些悬挂在桌面的频谱,但是制作这样的频谱,需要使用雨滴的编程语法进行开发,这…

    2022年10月12日
    3
  • windows本地用户及组的区别「建议收藏」

    windows本地用户及组的区别「建议收藏」Administrators(超级管理员组)用来管理注册用户或者具有一定权限的其他管理员,维护网站的运行。Administrators中的用户对计算机/域有不受限制的完全访问权,分配给该组的默认权

    2022年8月3日
    11
  • ubuntu 20.04 安装中文输入法_ubuntu20.04安装中文输入法

    ubuntu 20.04 安装中文输入法_ubuntu20.04安装中文输入法在安装ubuntu时,如果选择英文安装,默认会不启用中文输入法的。可以通过下述方法开启:在settings的Region&amp;amp;amp;amp;amp;amp;Language的InputSources设置栏中点击+添加Chinese(IntelligentPinyin)最后,重启后使之生效。…

    2026年4月13日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号