image.PNG
1,HOOK 介绍 (钩子, 挂钩)
是一种实现 Windows 平台下类似于中断的机制. HOOK 机制允许应用程序拦截并处理 Windows 消息或指定事件, 当指定的消息发出后, HOOK 程序就可以在消息到达目标窗口之前将其捕获, 从而得到对消息的控制权, 进而可以对该消息进行处理或修改, 加入我们所需的功能.
9693047-4e3847865e1a0b6c.PNG
钩子按使用范围分, 可分为线程钩子和系统钩子, 其中, 系统钩子具有相当大的功能, 几乎可以实现对所有 Windows 消息的拦截, 处理和监控. 这项技术涉及到两个重要的 API:
一个是 SetWindowsHookEx, 安装钩子.
另一个是 UnHookWindowsHookEx, 卸载钩子.
本文介绍的 HOOK API 技术, 是指截获系统或进程对某个 API 函数的调用, 使得 API 的执行流程转向我们指定的代码段, 从而实现我们所需的功能.
Windows 下的每个进程均拥有自己的地址空间, 并且进程只能调用其地址空间内的函数, 因此 HOOK API 尤为关键的一步是, 设法将自己的代码段注入到目标进程中, 才能进一步实现对该进程调用的 API 进行拦截.
然而微软并没有提供 HOOK API 的调用接口, 这就需要开发者自己编程实现, 大家所熟知的防毒软件, 防火墙软件等均采用 HOOK API 实现.
2, 常用的 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 子程, 这些事件包括:
激活, 建立, 销毁, 最小化, 最大化, 移动, 改变尺寸等窗口事件;
完成系统指令;
来自系统消息队列中的移动鼠标, 键盘事件;
设置输入焦点事件;
同步系统消息队列事件.
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, 它們不會被注射到任何行程位址空間.(估计按键精灵是用这个 hook 做的)
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钟情況:
只要有个 top-level,unowned 窗口被产生, 起作用, 或是被摧毁;
当 Taskbar 需要重画某个按钮;
当系统需要显示关于 Taskbar 的一个程序的最小化形式;
当目前的键盘布局状态改变;
当使用者按 Ctrl+Esc 去执行 Task Manager(或相同级别的程序).
按照惯例, 外壳应用程序都不接收 WH_SHELL 消息. 所以, 在应用程序能够接收 WH_SHELL 消息之前, 应用程序必须调用 SystemParametersInfo function 注册它自己.
以上是 13 种常用的 hook 类型!
3, 钩子部分的实现
钩子安装函数
image.PNG
其中:
对消息 WH_MOUSE_LL 进行了钩取.
当捕捉到该消息时, 交由 LowLevelMouseProc 函数进行操作.
g_hInstance 是返回自身句柄的函数
钩子处理函数
image.PNG
钩子处理函数向 g_hWnd 句柄发送 WM_HOOKMSG 消息.
然后将上述函数打包成 DLL 文件.
4, 调用钩子的实现
导入 DLL 并安装消息钩子
image.PNG
5, 实现效果
在没有使用钩子情况下, 不会对鼠标消息进行捕捉.
当点击启动鼠标 HOOK 后, 会随着鼠标进行移动, 并捕获鼠标消息.
6, 小结
本次 HOOK 选择的目标是自己, 下一节将会介绍如何 HOOK 其他进程.
来源: http://www.jianshu.com/p/d86babc70f67