0%
毅种循环

模块 62 - API Hooking - 使用 Windows API

恶意软件开发课程 - API Hooking - 使用 Windows API


模块 62 - API Hooking - 使用 Windows API#

API Hooking - 使用 Windows API#

简介#

使用 SetWindowsHookEx WinAPI 是实现 API Hooking 的另一种方法。它主要用于监视系统中的某些事件类型。这与之前模块中讨论的技术有所不同:SetWindowsHookExW/A 并不直接修改目标函数的指令(如写入 jmp),而是在特定事件触发时,由系统自动调用一个预先定义的“回调函数”。不过,这种方法监控的事件类型受限于 Windows 系统本身提供的范围。

SetWindowsHookEx 使用方法#

SetWindowsHookExW 的函数定义如下:

HHOOK SetWindowsHookExW(
  [in] int       idHook,      // 要安装的钩子过程类型
  [in] HOOKPROC  lpfn,        // 钩子回调函数的指针(事件触发时执行的函数)
  [in] HINSTANCE hmod,        // 包含回调函数的 DLL 句柄(通常设为 NULL)
  [in] DWORD     dwThreadId   // 与钩子管理的线程 ID(通常设为 NULL,表示全局钩子)
);
c
  • idHook:要监视的事件。例如,WH_KEYBOARD_LL 用于监控低级键盘消息(常用于编写键盘记录器)。在本模块中,我们将使用 WH_MOUSE_LL 标志来监控鼠标点击事件。
  • lpfn:回调函数指针,每当事件发生时系统都会调用它。

回调函数定义#

回调函数必须符合 HOOKPROC 类型定义:

typedef LRESULT (CALLBACK* HOOKPROC)(int nCode, WPARAM wParam, LPARAM lParam);
c

一个典型的回调函数如下所示:

LRESULT CALLBACK HookCallbackFunc(int nCode, WPARAM wParam, LPARAM lParam){
    // 处理逻辑...
    
    // 必须调用 CallNextHookEx 将消息传递给链条中的下一个钩子
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
c

💡 初学者提示:为什么必须调用 CallNextHookEx?

系统中的钩子是以链表形式存在的。如果你拦截了消息但不向下传递(即不调用 CallNextHookEx),那么其他依赖该消息的程序(甚至是系统本身)可能无法获取输入消息,导致它们行为异常或完全卡死。

处理消息循环#

仅仅安装钩子是不够的,你必须确保你的程序(以及安装钩子的线程)保持运行,并且能够“吞吐”系统发来的消息。在 Windows 开发中,这通常需要一个 消息循环 (Message Loop)

如果我们只用一个死循环 while(1){},鼠标会因为消息积压而变得非常卡顿,甚至无法移动。我们需要使用 GetMessageW 获取消息,并使用 DefWindowProcW(或简单的 DispatchMessageW)来处理那些我们不感兴趣的消息。

BOOL MouseClicksLogger() {
    MSG Msg = { 0 };

    // 1. 安装低级鼠标钩子 (WH_MOUSE_LL)
    HHOOK hMouseHook = SetWindowsHookExW(WH_MOUSE_LL, (HOOKPROC)HookCallback, NULL, NULL);
    
    // 2. 消息循环:这是维持钩子运行的关键
    // 如果没有这段代码,钩子将无法接收到系统通知
    while (GetMessageW(&Msg, NULL, NULL, NULL)) {
        // 将消息交给默认窗口过程处理,确保鼠标能正常移动
        DefWindowProcW(Msg.hwnd, Msg.message, Msg.wParam, Msg.lParam);
    }
    
    return TRUE;
}
cpp

移除挂钩#

使用 UnhookWindowsHookEx 函数并传入钩子句柄即可停止监控。

完整示例代码#

下面的代码演示了如何实时监控并打印用户的鼠标左键、右击和中键操作。

📚 知识扩展:用户层钩子的局限性

SetWindowsHookEx 虽然强大且“官方”,但它非常容易被安全软件监测。因为它依赖于系统的消息机制,AV/EDR 只需要简单检查系统的钩子链(Hook Chain)就能发现是否存在可疑的回调函数。此外,由于所有消息都要经过你的回调函数处理,如果你的函数逻辑过于复杂,会严重拖慢整个系统的响应速度。


🎯 总结#

在本模块中,我们学习了:

  1. 官方挂钩机制:掌握了使用系统 API 监控全局事件的方法。
  2. 回调函数模型:理解了事件驱动型 Hook 的基本逻辑。
  3. 消息循环的重要性:学会了如何通过 GetMessageDefWindowProc 确保系统在被 Hook 时依然保持流畅。

📚 下一步学习

下一个模块将开启全新的专题:Syscalls - Introduction。我们将深入用户态与内核态的交界处,学习如何绕过那些在导出函数上安装 Hook 的监控工具!