【问题标题】:Access to hook in hook procedure在钩子程序中访问钩子
【发布时间】:2012-03-03 21:49:43
【问题描述】:

如何从他的程序中访问钩子的句柄?

例子:

HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)hookProc, GetModuleHandle(NULL), 0);

LRESULT CALLBACK hookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    //I want my HHOOK here :O
}

【问题讨论】:

标签: c++ c winapi hook


【解决方案1】:

您需要将HHOOK 变量存储在全局内存中。不要将其声明为调用 SetWindowsHookEx() 的任何函数的局部变量。

编辑:这是一个基于类的 32 位 CPU 示例:

class THookKeyboardLL
{
private:
    HHOOK hHook;

    void *pProxy;
    static LRESULT CALLBACK ProxyStub(THookKeyboardLL *This, int nCode, WPARAM wParam, LPARAM lParam);

    LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);

public:
    THookKeyboardLL();
    ~THookKeyboardLL();
};

.

#include <pshpack1.h>
struct sProxy
{
    unsigned char PopEax;
    unsigned char Push;
    void *ThisPtr;
    unsigned char PushEax;
    unsigned char Jmp;
    int JmpOffset;
};
#include <poppack.h>

long CalcJmpOffset(void *Src, void *Dest)
{
    return reinterpret_cast<long>(Dest) - (reinterpret_cast<long>(Src) + 5);
}

LRESULT CALLBACK THookKeyboardLL::ProxyStub(THookKeyboardLL *This, int nCode, WPARAM wParam, LPARAM lParam)
{
    return This->HookProc(nCode, wParam, lParam);
}

THookKeyboardLL::THookKeyboardLL()
    : hHook(NULL), pProxy(NULL)
{
    sProxy *Proxy = (sProxy*) VirtualAlloc(NULL, sizeof(sProxy), MEM_COMMIT, PAGE_READWRITE);

    Proxy->PopEax = 0x58;
    Proxy->Push = 0x68;
    Proxy->ThisPtr = this;
    Proxy->PushEax = 0x50;
    Proxy->Jmp = 0xE9;
    Proxy->JmpOffset = CalcJmpOffset(&(Proxy->Jmp), &ProxyStub);

    // Note: it is possible, but not in a portable manner, to
    // get the memory address of THookKeyboardLL::HookProc()
    // directly in some compilers.  If you can get that address,
    // then you can pass it to CalcJmpOffset() above and eliminate
    // THookKeyboardLL::ProxyStub() completely. The important
    // piece is that the Proxy code above injects this class
    // instance's "this" pointer into the call stack before
    // calling THookKeyboardLL::HookProc()...

    DWORD dwOldProtect;
    VirtualProtect(Proxy, sizeof(sProxy), PAGE_EXECUTE, &dwOldProtect);
    FlushInstructionCache(GetCurrentProcess(), Proxy, sizeof(sProxy));

    pProxy = Proxy;
    hHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)pProxy, GetModuleHandle(NULL), 0);
}

THookKeyboardLL::~THookKeyboardLL()
{
    if (hHook != NULL)
        UnhookWindowsHookEx(hHook);

    if (pProxy)
        VirtualFree(pProxy, 0, MEM_RELEASE);
}

LRESULT CALLBACK THookKeyboardLL::HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    // ...

    return CallNextHookEx(hHook, nCode, wParam, lParam);
    // when this method exits, it will automatically jump
    // back to the code that originally called the Proxy.
    // The Proxy massaged the call stack to ensure that...
}

【讨论】:

  • 但是我想创建一个创建钩子的类,所以我不能使用全局变量,因为我必须能够创建多个对象。
  • SetWindowsHookEx() 不支持使用类。如果你想使用一个类方法作为钩子过程,并使用多个类实例设置多个钩子,那么你必须为每个类实例创建一个单独的代理thunk,将代理传递给SetWindowsHookEx(),代理调用根据需要进入其关联的类实例。您不能单独在直接的 C/C++ 中执行此操作,您必须在程序集中编写代理(至少是 SetWindowsHookEx() 调用的部分)。
  • 难度不大(至少在32bit,64bit我不知道),稍后我会用例子更新我的答案。
【解决方案2】:

如果您查看CallNextHookExdocumentation,您会发现HHOOK 参数在Windows NT 上是可选的,如果您需要支持Windows 9x,那么您需要将HHOOK 存储在一个全局变量中。

您的示例代码显示您正在创建一个全局挂钩,全局挂钩很昂贵,因此如果您想注册多个回调函数,您应该将其抽象化,以便您的应用程序只设置一个挂钩并且您在那里注册的回调函数调用您的真实功能(在链表等中)。

【讨论】:

    猜你喜欢
    • 2020-04-29
    • 1970-01-01
    • 2020-08-28
    • 2014-03-13
    • 2020-05-23
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    相关资源
    最近更新 更多