当前位置: 首页 > news >正文

深入探索Windows Hook技术:原理、内核级实现与高级应用

一、Windows消息机制与Hook的底层原理

1.1 Windows事件传递机制

  • 消息队列结构:每个GUI线程维护MSG队列,系统通过PostMessageSendMessage传递事件

  • 消息循环流程GetMessage -> TranslateMessage -> DispatchMessage

  • Hook插入点:Hook通过SetWindowsHookEx在消息处理链中插入自定义处理层

1.2 Hook链工作模型

原始消息流:
[系统] -> [应用消息队列] -> [窗口过程WndProc]

安装Hook后:
[系统] -> [Hook处理函数] -> [其他Hook] -> [应用消息队列] -> [窗口过程]

1.3 关键API

HHOOK SetWindowsHookEx(
  [in] int       idHook,
  [in] HOOKPROC  lpfn,
  [in] HINSTANCE hmod,
  [in] DWORD     dwThreadId
);
​
[in] idHook
类型:int
要安装的挂钩过程的类型。(文章最后有列出)

[in] lpfn
类型:HOOKPROC
指向挂钩过程的指针。 如果 dwThreadId 参数为零或指定由其他进程创建的线程的标识符,则 lpfn 参数必须指向 DLL 中的挂钩过程。 否则,lpfn 可以指向与当前进程关联的代码中的挂钩过程。

[in] hmod
类型:HINSTANCE
DLL 的句柄,其中包含由 lpfn 参数指向的挂钩过程。 如果 dwThreadId 参数指定由当前进程创建的线程,并且挂钩过程位于与当前进程关联的代码中,则必须将 hMod 参数设置为 NULL。

[in] dwThreadId
类型:DWORD
要与之关联的挂钩过程的线程的标识符。 对于桌面应用,如果此参数为零,则挂钩过程与调用线程在同一桌面上运行的所有现有线程相关联。 有关 Windows 应用商店应用,请参阅“备注”部分。

返回值
类型:HHOOK
如果函数成功,则返回值为挂钩过程的句柄。
如果函数失败,则返回值 NULL。 若要获取扩展的错误信息,请调用 GetLastError。

BOOL UnhookWindowsHookEx(
  [in] HHOOK hhk
);
参数
[in] hhk
类型: HHOOK
要移除的挂钩的句柄。 此参数是由先前调用 SetWindowsHookEx 获取的挂钩句柄。

返回值
类型: BOOL
如果该函数成功,则返回值为非零值。
如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。

​


二、全局Hook与DLL注入技术详解

2.1 跨进程Hook实现原理

  • DLL注入强制加载:通过SetWindowsHookEx的第三个参数指定DLL路径

  • 内存映射机制:Hook DLL会被加载到所有目标进程的地址空间

  • 共享数据段:使用#pragma data_seg创建共享内存区域

2.2 DLL代码示例(共享数据区)

// 共享内存声明
#pragma data_seg(".SHARED")
HHOOK g_hHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.SHARED,RWS")

// 导出函数
extern "C" __declspec(dllexport) LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code == HC_ACTION) {
        // 处理逻辑
    }
    return CallNextHookEx(g_hHook, code, wParam, lParam);
}

2.3 注入器核心代码

// 远程线程注入
HANDLE hThread = CreateRemoteThread(
    hProcess, 
    NULL, 
    0,
    (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32"), 
    "HookDLL.dll",
    0, 
    NULL);

2.4 键盘记录示例

// 全局Hook句柄存储
HHOOK g_hKeyboardHook = nullptr;

// 键盘事件处理函数
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code == HC_ACTION) {
        BYTE keyState[256];
        GetKeyboardState(keyState);
        
        WORD charCode;
        char buffer[16] = {0};
        if (ToAscii(wParam, (lParam >> 16) & 0xFF, 
                   keyState, &charCode, 0) == 1) {
            sprintf(buffer, "%c", charCode);
            OutputDebugStringA(buffer);  // 输出到调试器
        }
    }
    return CallNextHookEx(g_hKeyboardHook, code, wParam, lParam);
}

// 安装全局键盘Hook
void InstallKeyboardHook() {
    g_hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, 
                                      GetModuleHandle(NULL), 0);
}

// 卸载Hook
void UninstallHook() {
    if (g_hKeyboardHook) {
        UnhookWindowsHookEx(g_hKeyboardHook);
        g_hKeyboardHook = nullptr;
    }
}

2.5 鼠标记录实列

HHOOK g_hMouseHook = nullptr;

LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code >= 0) {
        MSLLHOOKSTRUCT* pMouse = (MSLLHOOKSTRUCT*)lParam;
        
        // 拦截右键点击
        if (wParam == WM_RBUTTONDOWN) {
            MessageBox(NULL, L"右键点击被拦截!", L"提示", MB_OK);
            return 1;  // 阻止事件传递
        }
        
        // 记录坐标
        if (wParam == WM_MOUSEMOVE) {
            POINT pt = pMouse->pt;
            TCHAR buf[50];
            wsprintf(buf, L"坐标: (%d, %d)", pt.x, pt.y);
            SetWindowText(GetConsoleWindow(), buf);
        }
    }
    return CallNextHookEx(g_hMouseHook, code, wParam, lParam);
}

// 安装低层级鼠标Hook
void InstallMouseHook() {
    g_hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, 
                                   GetModuleHandle(NULL), 0);
}

三、内核级Hook技术初探

3.1 驱动开发基础

  • WDM模型:Windows Driver Model基础架构

  • 过滤驱动:通过IoCreateDevice创建过滤设备对象

  • IRP拦截:拦截IRP_MJ_DEVICE_CONTROL控制码

3.2 键盘过滤驱动示例

NTSTATUS DriverEntry(PDRIVER_OBJECT drvObj, PUNICODE_STRING regPath) {
    // 创建设备对象
    IoCreateDevice(..., &deviceObject);

    // 设置IRP处理函数
    drvObj->MajorFunction[IRP_MJ_READ] = FilterRead;

    // 绑定键盘设备栈
    IoAttachDeviceToDeviceStack(...);
    return STATUS_SUCCESS;
}

NTSTATUS FilterRead(PDEVICE_OBJECT devObj, PIRP irp) {
    // 获取原始按键数据
    KEYBOARD_INPUT_DATA* pData = (KEYBOARD_INPUT_DATA*)irp->AssociatedIrp.SystemBuffer;
    
    // 修改按键值(示例:禁用F1键)
    if (pData->MakeCode == 0x3B) { // F1键扫描码
        pData->MakeCode = 0;      // 清零处理
    }
    
    return IoCallDriver(nextDevObj, irp);
}

四、高级Hook应用:API函数拦截

4.1 Inline Hook原理

  • 指令替换:修改目标函数头5字节为jmp跳转指令

  • 跳板代码:保存原始字节并重定向到自定义函数

  • 执行流程原函数 -> jmp到Hook函数 -> 执行代理逻辑 -> 跳回原函数

4.2 Detours库实战

#include <detours.h>

// 目标API函数指针
typedef BOOL (WINAPI* TrueMessageBox)(HWND, LPCWSTR, LPCWSTR, UINT);
TrueMessageBox OriginalMessageBox = MessageBox;

// Hook处理函数
BOOL WINAPI HookedMessageBox(HWND hWnd, LPCWSTR text, LPCWSTR caption, UINT type) {
    // 修改消息框文本
    return OriginalMessageBox(hWnd, L"被Hook修改的内容", caption, type);
}

// 安装Hook
void InstallHook() {
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)OriginalMessageBox, HookedMessageBox);
    DetourTransactionCommit();
}

五、Hook调试与反检测技术

5.1 调试技巧

  • 双机调试:使用WinDbg通过串口/USB调试内核Hook

  • 调试器标记检测

    if (IsDebuggerPresent()) {
        MessageBox(NULL, L"检测到调试器!", L"警告", MB_ICONWARNING);
    }

5.2 反Hook检测方法

// 检查函数头部指令
bool CheckHook(LPVOID funcAddr) {
    BYTE* pCode = (BYTE*)funcAddr;
    return (*pCode == 0xE9); // 检查是否包含jmp指令
}

// 定时校验关键函数
if (CheckHook(MessageBox)) {
    TerminateProcess(GetCurrentProcess(), 0);
}

六、性能优化与最佳实践

6.1 回调函数优化准则

  • 避免阻塞操作:严禁在Hook回调中进行文件I/O等耗时操作

  • 异步处理机制:使用线程池处理复杂逻辑

  • 内存管理:使用无锁队列传递数据

6.2 现代Hook技术演进

  • 用户模式APC注入QueueUserAPC实现精准线程控制

  • ETW(Event Tracing for Windows):监控系统事件的新方法

  • 内核回调PsSetLoadImageNotifyRoutine监控模块加载


附录:推荐工具集

  • Microsoft Detours:专业的Hook库

  • WinDbg Preview:内核级调试工具

  • Process Monitor:实时监控系统活动

  • x64dbg:开源逆向工程调试器

HOOK类型表

idHook意义

WH_CALLWNDPROC

4

安装一个挂钩过程,用于在系统将其发送到目标窗口过程之前监视消息。 有关详细信息,请参阅 CallWndProc 挂钩过程。

WH_CALLWNDPROCRET

12

安装一个挂钩过程,用于在目标窗口过程处理消息后监视消息。 有关详细信息,请参阅 [HOOKPROC 回调函数](nc-winuser-hookproc.md) 挂钩过程。

WH_CBT

5

安装一个挂钩过程,用于接收对 CBT 应用程序有用的通知。 有关详细信息,请参阅 [CBTProc](/windows/win32/winmsg/cbtproc) 挂钩过程。

WH_DEBUG

9

安装用于调试其他挂钩过程的挂钩过程。 有关详细信息,请参阅 DebugProc 挂钩过程。

WH_FOREGROUNDIDLE

11

安装将在应用程序前台线程即将处于空闲状态时调用的挂钩过程。 此挂钩可用于在空闲时间执行低优先级任务。 有关详细信息,请参阅 ForegroundIdleProc 挂钩过程。

WH_GETMESSAGE

3

安装一个挂钩过程,用于监视发布到消息队列的消息。 有关详细信息,请参阅 GetMsgProc 挂钩过程。

WH_JOURNALPLAYBACK

1

 警告

Windows 11 及更新:不支持日记挂钩 API。 建议改用 SendInput TextInput API。

安装一个挂钩过程,该挂钩过程发布以前由 WH_JOURNALRECORD 挂钩过程记录的消息。 有关详细信息,请参阅 JournalPlaybackProc 挂钩过程。

WH_JOURNALRECORD

0

 警告

Windows 11 及更新:不支持日记挂钩 API。 建议改用 SendInput TextInput API。

安装一个挂钩过程,用于记录发布到系统消息队列的输入消息。 此挂钩可用于录制宏。 有关详细信息,请参阅 JournalRecordProc 挂钩过程。

WH_KEYBOARD

2

安装监视击键消息的挂钩过程。 有关详细信息,请参阅 KeyboardProc 挂钩过程。

WH_KEYBOARD_LL

13

安装用于监视低级别键盘输入事件的挂钩过程。 有关详细信息,请参阅 LowLevelKeyboardProc 挂钩过程。

WH_MOUSE

7

安装监视鼠标消息的挂钩过程。 有关详细信息,请参阅 MouseProc 挂钩过程。

WH_MOUSE_LL

14

安装一个挂钩过程,用于监视低级别鼠标输入事件。 有关详细信息,请参阅 LowLevelMouseProc 挂钩过程。

WH_MSGFILTER

-1

安装一个挂钩过程,用于监视对话框、消息框、菜单或滚动条中输入事件生成的消息。 有关详细信息,请参阅 MessageProc 挂钩过程。

WH_SHELL

10

安装一个挂钩过程,用于接收对 shell 应用程序有用的通知。 有关详细信息,请参阅 [ShellProc](/windows/win32/winmsg/shellproc) 挂钩过程。

WH_SYSMSGFILTER

6

安装一个挂钩过程,用于监视对话框、消息框、菜单或滚动条中输入事件生成的消息。 挂钩过程监视与调用线程位于同一桌面中的所有应用程序的消息。 有关详细信息,请参阅 SysMsgProc 挂钩过程。

相关文章:

  • 压力测试未覆盖边界条件的后果有哪些
  • 常见的锁策略
  • angular获取roleFormGroup的control值
  • k8s scheduler几种扩展方式的关系及区别
  • RDMA的挑战与限制
  • 远程办公新体验:用触屏手机流畅操作电脑桌面
  • PhotoScissors快速抠图与背景填充
  • 快速入手-基于Django-rest-framework的ModelViewSet终极版(七)
  • redis常见面试题
  • Java全栈面试宝典:多线程与Spring核心机制深度解析
  • Unix/Linux 中 dup、dup2 和 dup3 系统调用解析
  • Windows10清理机器大全集
  • parallelStream线程问题及解决方案
  • 内网服务器无法通过公网地址访问映射到公网的内网服务
  • SQL问题分析与诊断(8)——关键信息(1)
  • E5071C数据保存教程:SNP文件/CSV导出+远程传输步骤一键收藏
  • 蓝桥与力扣刷题(蓝桥 最少刷题数)
  • 2025企业级项目设计三叉戟:权限控制+错误监控+工程化提效实战指南
  • 手动搭建并配置react项目(webpack5)
  • 运筹说 第134期 | 矩阵对策的解法
  • 网站对网友发帖隐私做处理/百度 营销推广多少钱
  • 网站开发常用的语言/抖音营销推广怎么做
  • 网站还没有做解析是什么意思/简短的软文范例
  • 做网站的公司名字/刚刚刚刚刚刚好痛
  • 长春网站建设推广/桂平seo关键词优化
  • 58企业网站如何做/北京seo多少钱