如何从 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”函数
在 VS2008 调试器中调用 SetWindowsHookEx 总是返回 NULL
调用 SetWindowsHookEx() 的应用程序能否捕获自动完成 URL 和密码?