如何从 SetWindowsHookEx 回调调用函数指针

Posted

技术标签:

【中文标题】如何从 SetWindowsHookEx 回调调用函数指针【英文标题】:How to call fuction-pointer from SetWindowsHookEx callback 【发布时间】:2019-06-25 13:57:50 【问题描述】:

我试图从一个 dll 中调用函数指针,该 dll 将 WM_LBUTONDOWN 或 WM_TOUCH 消息挂接到屏幕上显示的所有窗口上。

我有以下dll源代码:

typedef void (*PtrFonct)(int nCode, WPARAM wParam, LPARAM lParam);
PtrFonct pf;
HHOOK global;

extern "C" __declspec(dllexport) LRESULT WINAPI procedure(int nCode, WPARAM wParam,LPARAM lParam)

    if (nCode == HC_ACTION)
        MSG* pMSG = (MSG*)lParam;
        if (pMSG->message == WM_LBUTTONDOWN)
            pf(nCode, wParam, lParam);
        
    
    return CallNextHookEx(global, nCode, wParam, lParam);
 

extern "C" __declspec(dllexport) BOOL setCallback(void ((*callbackFunc)(int, WPARAM, LPARAM)))
    pf = callbackFunc;
    if (pf)
        return TRUE;
    return FALSE;


而我的监听源代码如下:

    MSG message;
    HMODULE lib = LoadLibrary(L"C:/HookTouch.dll");
    if (lib) 
        HOOKPROC procedure = (HOOKPROC)GetProcAddress(lib, "_procedure@12");
        dllFunct fonctionCallback = (dllFunct)GetProcAddress(lib, "setCallback");
        if (fonctionCallback)
            fonctionCallback(MyCallback);
        if (procedure)
            hook = SetWindowsHookEx(WH_GETMESSAGE, procedure, lib, 0);
    
    else
        printf("Can't find dll!\n");

    while (GetMessage(&message, NULL, 0, 0))
    
        TranslateMessage(&message);
        DispatchMessage(&message);
    
    FreeLibrary(lib);
    UnhookWindowsHookEx(hook);

我自己显示“Hello click”的回调是这个:

void MyCallback(int nCode, WPARAM wParam, LPARAM lParam)

    printf("Hello Click\n");

我知道我的钩子正在工作,因为我可以通过使用消息框而不是 pf(nCode, wParam, lParam) 在单击时显示消息,但是当我使用此函数指针时,不会触发 MyCallback。 我检查了我的函数是否受到 pf 函数指针的良好影响,一切似乎都正常。

你知道为什么pf(nCode, wParam, lParam)的调用不会触发监听器的MyCallback函数吗?

【问题讨论】:

您如何验证您的回调未被调用?要让printf 输出任何内容,目标进程必须附加一个控制台。处理鼠标和触摸输入的应用程序通常不是这种情况。另请注意,DLL 的不同实例不共享全局数据。 我的监听器是一个控制台应用程序,所以我可以看到我的 printf 日志。我还检查了 VS 中的断点是否调用了 Dll 的 setCallback,我看到 pf 填充正确。如果我在MyCallback 函数中设置断点,则不会发生任何事情。 您正在安装 global 挂钩。您的代码在目标进程内运行。您的启动器进程只是您的 DLL 被注入的众多 32 位目标进程之一。 好吧,我没有从这个角度看东西 :-)。这意味着我不能像那样提醒我的应用程序。你知道怎么做吗? 【参考方案1】:

您调用setCallback 仅为在您的进程中加载​​的dll。 SetWindowsHookEx 在所有其他进程中注入的 dll 不会设置回调。最重要的是,MyCallback 仅在您自己的进程中定义;在其他进程中注入的 Dll 没有简单的访问方式。

由于您无法知道 Windows 为您注入了哪些进程,因此您需要 Dll 通过进程间通信向您广播其“位置”,例如。命名管道。一旦你有了注入的每个 DLL 的进程 ID,你就可以使用 CreateRemoteThread 调用 Dll 中的一个函数,比如 setCallback.. 还有一些工作要做,以便 Dll 可以直接调用你回调:您需要为 Dll 提供回调与模块库的确切偏移量,然后 Dll 将需要使用CreateRemoteThread 本身来发出调用。 这一切很快就变得太乏味了,明智的做法是使用命名管道通信而不是直接调用函数。

提示:从其他进程记录内容的一种简单方法是使用OutputDebugString。或者,写入文件。

【讨论】:

只有在调试器附加到调用OutputDebugString 的进程时才能观察到来自OutputDebugString 的输出。不过,该调试器不必是 Visual Studio。 DebugView 很好。【参考方案2】:

这种方法行不通。

消息挂钩在每个被挂钩的线程的上下文中运行。每个挂钩的进程都会将自己的 DLL 副本注入其中。因此,只有最初安装挂钩的副本才会设置有效的函数指针。此外,无论如何您都不能跨进程边界调用回调函数。

您需要使用不同的 IPC 机制来让注入的钩子与您的主应用进程通信。

例如,您可以创建一个隐藏的HWND 并将其存储在一个全局共享内存块中,然后每个注入的钩子都可以向它发送窗口消息,例如WM_COPYDATA。或者,您的主应用程序可以打开一个命名管道,然后每个注入的钩子都可以连接到该管道并向其发送数据。

【讨论】:

以上是关于如何从 SetWindowsHookEx 回调调用函数指针的主要内容,如果未能解决你的问题,请参考以下文章

SetWindowsHookEx - 防病毒问题

在我的线程上下文中调用“SetWindowsHookEx”函数

在 VS2008 调试器中调用 SetWindowsHookEx 总是返回 NULL

调用 SetWindowsHookEx() 的应用程序能否捕获自动完成 URL 和密码?

SetWindowsHookEx 在快速输入或键盘按钮按住时冻结

SetWindowsHookEx DLL 卸载