「Win」HOOK钩子技术

本文详细介绍了Windows系统中的HOOK技术,包括全局钩子和局部钩子的区别,以及各种类型的钩子如键盘钩子、鼠标钩子和消息钩子的使用方法。通过示例代码展示了如何安装和卸载这些钩子,以及如何处理截获的事件。同时,文章提醒读者在使用消息钩子时要注意可能对应用程序产生的影响和潜在风险。
摘要由CSDN通过智能技术生成

在这里插入图片描述

✨博客主页:何曾参静谧的博客
📌文章专栏:「Win」Windows程序设计


相关术语

HOOK技术:是一种在Windows系统中常用的技术,它可以截获并修改操作系统或应用程序的行为。通过使用Hook技术,我们可以实现以下功能:

  • 监视和记录系统和应用程序的行为。
  • 修改系统和应用程序的行为,以满足特定需求。
  • 在系统和应用程序的行为发生时,执行自定义代码。

全局钩子(Global Hook):是指在整个系统中安装的钩子。全局钩子可以截获并修改所有应用程序的行为。全局钩子通常用于实现系统级别的功能,如监视和记录用户输入、拦截和修改系统消息等。
局部钩子(Local Hook):是指在特定应用程序中安装的钩子。局部钩子只能截获并修改特定应用程序的行为。局部钩子通常用于实现应用程序级别的功能,如拦截和修改应用程序消息、增强用户体验等。(在使用时需要指定应用程序的句柄)

钩子类型对应ID
消息钩子WH_GETMESSAGE(全局)
键盘钩子WH_KEYBOARD(局部)
WH_KEYBOARD_LL(全局)
鼠标钩子WH_MOUSE(局部)
WH_MOUSE_LL(全局)
线程钩子WH_CALLWNDPROC(全局)
进程钩子WH_CBT(全局)

一、全局钩子和局部钩子

#include <Windows.h>
#include <iostream>

using namespace std;

// 全局钩子回调函数
LRESULT CALLBACK GlobalKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;
        if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
        {
            // 按下键盘键
            cout << "Global Key down: " << pKeyboard->vkCode << endl;
        }
        else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
        {
            // 松开键盘键
            cout << "Global Key up: " << pKeyboard->vkCode << endl;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

// 局部钩子回调函数
LRESULT CALLBACK LocalKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;
        if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
        {
            // 按下键盘键
            cout << "Local Key down: " << pKeyboard->vkCode << endl;
        }
        else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
        {
            // 松开键盘键
            cout << "Local Key up: " << pKeyboard->vkCode << endl;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int main()
{
    // 安装全局钩子
    HHOOK hGlobalHook = SetWindowsHookEx(WH_KEYBOARD_LL, GlobalKeyboardProc, GetModuleHandle(NULL), 0);

    // 安装局部钩子
    HHOOK hLocalHook = SetWindowsHookEx(WH_KEYBOARD, LocalKeyboardProc, GetModuleHandle(NULL), GetCurrentThreadId());

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // 卸载全局钩子和局部钩子
    UnhookWindowsHookEx(hGlobalHook);
    UnhookWindowsHookEx(hLocalHook);

    return 0;
}

二、消息钩子

实现现一个消息钩子回调函数 MessageProc,用于拦截窗口消息。然后,在 main 函数中,我们使用 SetWindowsHookEx 函数安装了一个 WH_GETMESSAGE 消息钩子,并在消息循环中等待消息的到来。在消息钩子回调函数中,我们判断收到的消息是否为键盘消息,如果是则打印出消息类型。最后,在消息循环结束时,我们调用 UnhookWindowsHookEx 函数卸载消息钩子。

#include <Windows.h>
#include <iostream>

using namespace std;

// 消息钩子回调函数
LRESULT CALLBACK MessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        MSG* pMsg = (MSG*)lParam;
        if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP)
        {
            // 拦截键盘消息
            cout << "Message Hook: " << pMsg->message << endl;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int main()
{
    // 安装消息钩子
    HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE, MessageProc, GetModuleHandle(NULL), 0);

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // 卸载消息钩子
    UnhookWindowsHookEx(hHook);

    return 0;
}

三、键盘钩子

首先定义了一个全局的键盘钩子句柄 g_hHook,并在 main 函数中通过 SetWindowsHookEx 函数安装了一个全局键盘钩子。然后,在键盘钩子回调函数 KeyboardProc 中,我们捕获并处理了键盘事件,并在控制台上显示了按下或松开的键盘键。最后,在消息循环结束时,我们调用 UnhookWindowsHookEx 函数卸载全局键盘钩子。

#include <Windows.h>
#include <iostream>

using namespace std;

// 定义全局的键盘钩子句柄
HHOOK g_hHook = NULL;

// 键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;
        if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
        {
            // 按下键盘键
            cout << "Key down: " << pKeyboard->vkCode << endl;
        }
        else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
        {
            // 松开键盘键
            cout << "Key up: " << pKeyboard->vkCode << endl;
        }
    }
    return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

int main()
{
    // 安装全局键盘钩子
    g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), 0);

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // 卸载全局键盘钩子
    UnhookWindowsHookEx(g_hHook);
    return 0;
}

四、鼠标钩子

代码实现了一个鼠标钩子回调函数 MouseProc,用于拦截鼠标事件。然后,在 main 函数中,我们使用 SetWindowsHookEx 函数安装了一个 WH_MOUSE_LL 鼠标钩子,并在消息循环中等待消息的到来。在鼠标钩子回调函数中,我们判断收到的消息类型并打印出鼠标位置。最后,在消息循环结束时,我们调用 UnhookWindowsHookEx 函数卸载鼠标钩子。

#include <Windows.h>
#include <iostream>

using namespace std;

// 鼠标钩子回调函数
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        MOUSEHOOKSTRUCT* pMouseStruct = (MOUSEHOOKSTRUCT*)lParam;
        if (wParam == WM_MOUSEMOVE)
        {
            // 拦截鼠标移动事件
            cout << "Mouse Hook: WM_MOUSEMOVE, x=" << pMouseStruct->pt.x 
                << ", y=" << pMouseStruct->pt.y << endl;
        }
        else if (wParam == WM_LBUTTONDOWN)
        {
            // 拦截鼠标左键按下事件
            cout << "Mouse Hook: WM_LBUTTONDOWN, x=" << pMouseStruct->pt.x 
                << ", y=" << pMouseStruct->pt.y << endl;
        }
        else if (wParam == WM_RBUTTONDOWN)
        {
            // 拦截鼠标右键按下事件
            cout << "Mouse Hook: WM_RBUTTONDOWN, x=" << pMouseStruct->pt.x 
                << ", y=" << pMouseStruct->pt.y << endl;
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int main()
{
    // 安装鼠标钩子
    HHOOK hHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, GetModuleHandle(NULL), 0);

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // 卸载鼠标钩子
    UnhookWindowsHookEx(hHook);

    return 0;
}

注意事项

需要注意的是,使用消息钩子需要谨慎,因为它可以拦截窗口消息,可能会对应用程序的正常运行产生影响。因此,在使用消息钩子时,应该根据实际需求选择合适的钩子类型,并谨慎对待其中的风险和安全问题。


在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何曾参静谧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值