Windows 下的窗口应用程序是基于事件驱动方式工作的,操作系统中点击鼠标和按下键盘都是一种事件,当事件发生时操作系统会将消息发送给相应的应用程序,应用程序收到消息之后会做出响应。
钩子(Hook),是Windows提供的一种截获和监视系统中消息的方法,应用程序可以通过 SetWindowsHook 函数设置钩子以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。
0x01 钩子原理
操作系统维护着一个链表进行钩子的管理,每设置一个钩子就在钩链中增加一个节点,最新设定的钩子将会最早获得消息的控制权。此外,每个钩子需要设定一个回调函数(钩子函数),在产生指定消息后作出处理。当指定消息发生时,系统会调用这些回调函数。在回调函数中可以监视消息、修改消息,或者屏蔽消息,使消息无法传递到目的窗口。
根据钩子的范围可分为全局钩子和局部钩子,全局钩子可以钩取所有基于消息机制的应用程序,局部钩子只是钩取指定线程的消息。全局钩子将钩子函数放在一个 DLL 中,当某个进程产生指定消息之后,操作系统会自动将该 DLL 注入到该进程中。
常用钩子类型有以下几种:
(1)键盘钩子和低级键盘钩子可以监视各种键盘消息。
(2)鼠标钩子和低级鼠标钩子可以监视各种鼠标消息。
(3)外壳钩子可以监视各种Shell事件消息。比如启动和关闭应用程序。
(4)日志钩子可以记录从系统消息队列中取出的各种事件消息。
(5)窗口过程钩子监视所有从系统消息队列发往目标窗口的消息。
Windows 提供消息钩子相关的 API 主要有 SetWindowsHookEx()、CallNextHookEx() 和 UnhookWindowsHookEx()。
0x02 键盘钩子
键盘记录器是恶意代码中常见的一种类型,木马编写者通常以隐蔽的方式将键盘记录器安装在目标主机以窃取登录凭证等敏感信息。通过消息钩子可以实现一个键盘记录器,但是这种方法极容易被杀毒软件发现。下面通过一个简单的例子演示全局键盘钩子。
1. 安装与卸载钩子
由于是全局消息钩子,所以需要将消息钩子的安装与卸载放在 DLL 中。
SetWindowsHookEx 用于安装消息钩子,该函数第二个参数为钩取消息后系统调用的回调函数,函数的返回值为钩子句柄。函数原型如下:
UnhookWindowsHookEx 用于卸载消息钩子,它只有一个参数,即需要卸载消息钩子的句柄。
在 DLL 中要将该函数导出供主程序使用,_declspec(dllexport)
声明 InstallHook() 和 UninstallHook() 为导出函数。
2. 钩子函数
全局键盘消息钩子会截获所有应用程序的键盘消息,包括系统的控制台程序,为了方便操作,若目标程序为控制台程序(conhost.exe)则直接将消息传递给它;否则当有键盘按下都会弹出消息窗口,并显示按下的按键。具体实现如下:
GetKeyNameTextA 用于获取按键名字符串。
CallNextHookEx 将消息继续传递给钩子链中下一个钩子函数,直到目标窗口。
3. 测试
以上即为消息钩子相关的函数,下面调用这些函数测试键盘钩子的效果。
在记事本中按下按键,弹出按键值。
查看记事本进程模块,可以看到 DLL 已成功注入该进程。
0x03 调试
使用 OllyDbg 可以调试注入到目标进程中的 DLL 文件,具体步骤如下:
1.运行 notepad.exe,使用 OD attach 运行中的 notepad;
2.选项/ 调试选项/ 事件/ 中断于新模块(dll);
3.运行 Hook.exe,安装全局消息钩子;
4.在 notepad 中使用键盘输入,keyhook.dll 被注入到 notepad 中;
5.OD 暂停调试,并弹出 Executable modules 窗口;
6.取消之前设置的 “ 中断于新模块(dll)” ,双击 keyhook.dll 即可到达其 EP 地址处。
References:
[1] 逆向工程核心原理
[2] Windows API 教程(七)hook 钩子监听
[3] DLL注入浅析(上)