hook钩子:关于钩子(Hook)



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

钩子实际上是个处理消息通过系统把它挂入系统每当特定消息发出在没有到达目窗口前钩子就先捕获该消息亦即钩子先得到控

制权这时钩子即可以加工处理(改变)该消息也可以不作处理而继续传递该消息还可以强制结束消息传递

运行机制

1、钩子链表和钩子子程:

个Hook都有个和的相关联指针列表称的为钩子链表由系统来维护这个列表指针指向指定应用定义被Hook子程回调也就是该钩子各个处理子程当和指定Hook类型关联消息发生时系统就把这个消息传递到Hook子程些Hook子程可以只监视消息或者修改消息或者停止消息前进避免这些消息传递到下个Hook子程或者目窗口最近安装钩子放在链开始而最早安装钩子放在最后也就是后加入先获得控制权

Windows 并不要求钩子子程卸载顺序定得和安装顺序相反每当有个钩子被卸载Windows 便释放其占用内存并更新整个Hook链表如果安装了钩子但是在尚未卸载钩子的前就结束了那么系统会自动为它做卸载钩子操作

钩子子程是个应用定义回调(CALLBACK Function),不能定义成某个类成员只能定义为普通C用以监视系统或某特定类型事件这些事件可以是和某特定线程关联也可以是系统中所有线程事件

钩子子程必须按照以下语法:

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

HookProc是应用定义名字

nCode参数是Hook代码Hook子程使用这个参数来确定任务这个参数值依赖于Hook类型种Hook都有自己Hook代码特征

wParam和lParam参数值依赖于Hook代码但是它们典型值是包含了有关发送或者接收消息信息

2、钩子安装和释放:

使用APISetWindowsHookEx个应用定义钩子子程安装到钩子链表中SetWindowsHookEx总是在Hook链开头安装Hook子程当指定类型Hook监视事件发生时系统就和这个Hook关联Hook链开头Hook子程个Hook链中Hook子程都决定是否把这个事件传递到下个Hook子程Hook子程传递事件到下个Hook子程需要CallNextHookEx

HHOOK SetWindowsHookEx(
idHook, // 钩子类型即它处理消息类型
HOOKPROC lpfn, // 钩子子程地址指针如果dwThreadId参数为0
// 或是个由别进程创建线程标识
// lpfn必须指向DLL中钩子子程
// 除此以外lpfn可以指向当前进程段钩子子程代码
// 钩子入口地址当钩子钩到任何消息后便这个
HINSTANCE hMod, // 应用例子句柄标识包含lpfn所指子程
DLL
// 如果dwThreadId 标识当前进程创建个线程
// 而且子程代码位于当前进程hMod必须为NULL
// 可以很简单设定其为本应用例子句柄
DWORD dwThreadId // 和安装钩子子程相关联线程标识符
// 如果为0钩子子程和所有线程关联即为全局钩子
);

成功则返回钩子子程句柄失败返回NULL

以上所说钩子子程和线程相关联是指在钩子链表中发给该线程消息同时发送给钩子子程且被钩子子程先处理

在钩子子程中得到控制权钩子在完成对消息处理后如果想要该消息继续传递那么它必须另外个SDK中APICallNextHookEx来传递它以执行钩子链表所指个钩子子程这个成功时返回钩子链中下个钩子过程返回值返回值类型依赖于钩子类型这个原型如下:

LRESULT CallNextHookEx
(
HHOOK hhk;
nCode;
WPARAM wParam;
LPARAM lParam;
);

hhk为当前钩子句柄由SetWindowsHookEx返回

NCode为传给钩子过程事件代码

wParam和lParam 分别是传给钩子子程wParam值其具体含义和钩子类型有关


钩子也可以通过直接返回TRUE来丢弃该消息并阻止该消息传递否则其他安装了钩子应用将不会接收到钩子通知而且还有可能产生不正确结果

钩子在使用完的后需要用UnHookWindowsHookEx卸载否则会造成麻烦释放钩子比较简单UnHookWindowsHookEx只有个参数原型如下:

UnHookWindowsHookEx
(
HHOOK hhk;
);

成功返回TRUE否则返回FALSE

3、些运行机制:

在Win16环境中DLL全局数据对每个载入它进程来说都是相同;而在Win32环境中情况却发生了变化DLL代码所创建任何对象(包括变量)都归线程或进程所有当进程在载入DLL时操作系统自动把DLL地址映射到该进程私有空间也就是进程虚拟地址空间而且也复制该DLL全局数据份拷贝到该进程空间也就是说每个进程所拥有相同DLL全局数据它们名称相同但其值却并不定是相同而且是互不干涉


因此在Win32环境下要想在多个进程中共享数据就必须进行必要设置在访问同个Dll各进程的间共享存储器是通过存储器映射文件技术实现也可以把这些需要共享数据分离出来放置在个独立数据段里并把该段属性设置为共享必须给这些变量赋初值否则编译器会把没有赋变量放在个叫未被数据段中

#pragma data_seg预处理指令用于设置共享数据段例如:

#pragma data_seg("SharedDataName")


HHOOK hHook=NULL;
#pragma data_seg

在#pragma data_seg("SharedDataName")和#pragma data_seg的间所有变量将被访问该Dll所有进程看到和共享再加上条指令#pragma comment(linker,"/section:.SharedDataName,rws"),那么这个数据节中数据可以在所有DLL例子的间共享所有对这些数据操作都针对同个例子而不是在每个进程地址空间中都有

当进程隐式或显式个动态库里系统都要把这个动态库映射到这个进程虚拟地址空间里(以下简称"地址空间")这使得DLL成为进程部分以这个进程身份执行使用这个进程堆栈

4、系统钩子和线程钩子:

SetWindowsHookEx最后个参数决定了此钩子是系统钩子还是线程钩子


线程勾子用于监视指定线程事件消息线程勾子般在当前线程或者当前线程派生线程内


系统勾子监视系统中所有线程事件消息系统勾子会影响系统中所有应用所以勾子必须放在独立动态链接库(DLL) 中系统自动将包含"钩子回调"DLL映射到受钩子影响所有进程地址空间中即将这个DLL注入了那些进程

几点介绍说明:

(1)如果对于同事件(如鼠标消息)既安装了线程勾子又安装了系统勾子那么系统会自动先线程勾子然后系统勾子

(2)对同事件消息可安装多个勾子处理过程这些勾子处理过程形成了勾子链当前勾子处理结束后应把勾子信息传递给下个勾子

(3)勾子特别是系统勾子会消耗消息处理时间降低系统性能只有在必要时候才安装勾子在使用完毕后要及时卸载


钩子类型

种类型Hook可以使应用能够监视区别类型系统消息处理机制下面描述所有可以利用Hook类型

1、WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks

WH_CALLWNDPROC和WH_CALLWNDPROCRET Hooks使你可以监视发送到窗口过程消息系统在消息发送到接收窗口过程的前WH_CALLWNDPROC Hook子程并且在窗口过程处理完消息的后WH_CALLWNDPROCRET Hook子程

WH_CALLWNDPROCRET Hook传递指针到CWPRETSTRUCT结构再传递到Hook子程

CWPRETSTRUCT结构包含了来自处理消息窗口过程返回值同样也包括了和这个消息关联消息参数

2、WH_CBT Hook

在以下事件的前系统都会WH_CBT Hook子程这些事件包括:

1. 激活建立销毁最小化最大化移动改变尺寸等窗口事件;

2. 完成系统指令;

3. 来自系统消息队列中移动鼠标键盘事件;

4. 设置输入焦点事件;

5. 同步系统消息队列事件


Hook子程返回值确定系统是否允许或者防止这些操作中

3、WH_DEBUG Hook

在系统系统中和其他Hook关联Hook子程的前系统会WH_DEBUG Hook子程你可以使用这个Hook来决定是否允许系统和其他Hook关联Hook子程

4、WH_FOREGROUNDIDLE Hook

当应用前台线程处于空闲状态时可以使用WH_FOREGROUNDIDLE Hook执行低优先级任务当应用前台线程大概要变成空闲状态时系统就会WH_FOREGROUNDIDLE Hook子程

5、WH_GETMESSAGE Hook

应用使用WH_GETMESSAGE Hook来监视从GetMessage or PeekMessage返回消息你可以使用WH_GETMESSAGE Hook去监视鼠标和键盘输入以及其他发送到消息队列中消息

6、WH_JOURNALPLAYBACK Hook

WH_JOURNALPLAYBACK Hook使应用可以插入消息到系统消息队列可以使用这个Hook回放通过使用WH_JOURNALRECORD Hook记录下来连续鼠标和键盘事件只要WH_JOURNALPLAYBACK Hook已经安装正常鼠标和键盘事件就是无效

WH_JOURNALPLAYBACK Hook是全局Hook它不能象线程特定Hook样使用

WH_JOURNALPLAYBACK Hook返回超时值这个值告诉系统在处理来自回放Hook当前消息的前需要等待多长时间(毫秒)这就使Hook可以控制实时事件回放

WH_JOURNALPLAYBACK是system-wide local hooks它们不会被注射到任何行程位址空间

7、WH_JOURNALRECORD Hook

WH_JOURNALRECORD Hook用来监视和记录输入事件典型可以使用这个Hook记录连续鼠标和键盘事件然后通过使用WH_JOURNALPLAYBACK Hook来回放

WH_JOURNALRECORD Hook是全局Hook它不能象线程特定Hook样使用

WH_JOURNALRECORD是system-wide local hooks它们不会被注射到任何行程位址空间

8、WH_KEYBOARD Hook

在应用WH_KEYBOARD Hook用来监视WM_KEYDOWN and WM_KEYUP消息这些消息通过GetMessage or PeekMessage function返回可以使用这个Hook来监视输入到消息队列中键盘消息

9、WH_KEYBOARD_LL Hook

WH_KEYBOARD_LL Hook监视输入到线程消息队列中键盘消息

10、WH_MOUSE Hook

WH_MOUSE Hook监视从GetMessage 或者 PeekMessage 返回鼠标消息使用这个Hook监视输入到消息队列中鼠标消息

11、WH_MOUSE_LL Hook

WH_MOUSE_LL Hook监视输入到线程消息队列中鼠标消息

12、WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks

WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以监视菜单滚动条消息框对话框消息并且发现用户使用ALT+TAB or ALT+ESC 组合键切换窗口WH_MSGFILTER Hook只能监视传递到菜单滚动条消息框消息以及传递到通过安装了Hook子程应用建立对话框消息WH_SYSMSGFILTER Hook监视所有应用消息


WH_MSGFILTER 和 WH_SYSMSGFILTER Hooks使我们可以在模式循环期间过滤消息这等价于在主消息循环中过滤消息


通过CallMsgFilter function可以直接WH_MSGFILTER Hook通过使用这个应用能够在模式循环期间使用相同代码去过滤消息如同在主消息循环里



13、WH_SHELL Hook

外壳应用可以使用WH_SHELL Hook去接收重要通知当外壳应用是激活并且当顶层窗口建立或者销毁时系统WH_SHELL Hook子程

WH_SHELL 共有5钟情况:

1. 只要有个top-level、unowned 窗口被产生、起作用、或是被摧毁;

2. 当Taskbar需要重画某个按钮;

3. 当系统需要显示有关Taskbar最小化形式;

4. 当目前键盘布局状态改变;

5. 当使用者按Ctrl+Esc去执行Task Manager(或相同级别)

按照惯例外壳应用都不接收WH_SHELL消息所以在应用能够接收WH_SHELL消息的前应用必须ParametersInfo function注册它自己
Tags:  全局钩子 夺钩子 键盘钩子 hook钩子

延伸阅读

最新评论

发表评论