如何从 SetWindowsHookEx 回调中调用函数指针
How to call fuction-pointer from SetWindowsHookEx callback
我试图从挂钩 WM_LBUTONDOWN 或 WM_TOUCH 消息的 dll 调用函数指针,显示在屏幕上的所有 windows 上。
我有以下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函数吗?
这种方法行不通。
消息挂钩在每个被挂钩的线程的上下文中运行。每个挂钩的进程都会将自己的 DLL 副本注入其中。因此,只有最初安装挂钩的副本才会设置有效的函数指针。此外,您无论如何都不能跨进程边界调用回调函数。
您需要使用不同的 IPC 机制让注入的挂钩与主应用进程通信。
例如,您可以创建一个隐藏的 HWND
并将其存储在一块全局共享内存中,然后每个注入的挂钩都可以向它发送 window 消息,例如 WM_COPYDATA
.或者,您的主应用程序可以打开命名管道,然后每个注入的挂钩都可以连接到命名管道并向其发送数据。
您正在为进程中加载的 dll 调用 setCallback
。 SetWindowsHookEx
将在所有其他进程中注入的 dll 将不会设置回调。最重要的是, MyCallback
仅在您自己的进程中定义;在其他进程中注入的 Dll 没有简单的访问方式。
由于您不知道 Windows 为您注入了哪些进程,因此您需要 Dll 通过 Inter-Process 通信将其 'location' 广播给您,例如。命名管道。一旦获得了每个注入的 DLL 的进程 ID,就可以使用 CreateRemoteThread
调用 Dll 中的函数,例如 setCallback
.. 还有一些工作要做,以便 Dll可以直接调用你的回调:你需要给 Dll 你的回调从模块基址的确切偏移量,然后 Dll 需要使用 CreateRemoteThread
本身来发出调用。
这一切很快就会变得太乏味,明智的做法是只使用命名管道通信而不是发出直接函数调用。
提示:使用 OutputDebugString
从其他进程记录内容的一种简单方法。或者,写入文件。
我试图从挂钩 WM_LBUTONDOWN 或 WM_TOUCH 消息的 dll 调用函数指针,显示在屏幕上的所有 windows 上。
我有以下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函数吗?
这种方法行不通。
消息挂钩在每个被挂钩的线程的上下文中运行。每个挂钩的进程都会将自己的 DLL 副本注入其中。因此,只有最初安装挂钩的副本才会设置有效的函数指针。此外,您无论如何都不能跨进程边界调用回调函数。
您需要使用不同的 IPC 机制让注入的挂钩与主应用进程通信。
例如,您可以创建一个隐藏的 HWND
并将其存储在一块全局共享内存中,然后每个注入的挂钩都可以向它发送 window 消息,例如 WM_COPYDATA
.或者,您的主应用程序可以打开命名管道,然后每个注入的挂钩都可以连接到命名管道并向其发送数据。
您正在为进程中加载的 dll 调用 setCallback
。 SetWindowsHookEx
将在所有其他进程中注入的 dll 将不会设置回调。最重要的是, MyCallback
仅在您自己的进程中定义;在其他进程中注入的 Dll 没有简单的访问方式。
由于您不知道 Windows 为您注入了哪些进程,因此您需要 Dll 通过 Inter-Process 通信将其 'location' 广播给您,例如。命名管道。一旦获得了每个注入的 DLL 的进程 ID,就可以使用 CreateRemoteThread
调用 Dll 中的函数,例如 setCallback
.. 还有一些工作要做,以便 Dll可以直接调用你的回调:你需要给 Dll 你的回调从模块基址的确切偏移量,然后 Dll 需要使用 CreateRemoteThread
本身来发出调用。
这一切很快就会变得太乏味,明智的做法是只使用命名管道通信而不是发出直接函数调用。
提示:使用 OutputDebugString
从其他进程记录内容的一种简单方法。或者,写入文件。