本地键盘挂钩终止目标进程 [英] Local keyboard hook terminates the target process
问题描述
我正尝试使用托管C#代码中的C ++ DLL在进程中安装 LOCAL 键盘钩,如下所示:
I'm trying to install a LOCAL keyboard hook into a process using a C++ DLL from managed C# code, as follows:
public class KeyboardHook
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("DLL.dll", CallingConvention = CallingConvention.Cdecl)]
protected static extern IntPtr Install(int idHook, IntPtr windowHandle, HookCallback callback);
private IntPtr instance;
private HookCallback handler;
public KeyboardHook()
{
instance = IntPtr.Zero;
handler = Callback;
}
public void Install(Process process)
{
instance = Install(WH_KEYBOARD, process.MainWindowHandle, handler);
}
public void Uninstall()
{
UnhookWindowsHookEx(instance);
}
private IntPtr Callback(int nCode, IntPtr wParam, IntPtr lParam)
{
// TODO Use hook data here
return CallNextHookEx(instance, nCode, wParam, lParam);
}
}
C ++ DLL代码应该足以将钩子数据分派到C#的 Callback
函数,如下所示:
The C++ DLL code should be just enough to dispatch the hook data to the C#'s Callback
function, like this:
// dll.h
#pragma data_seg(".foo")
HOOKPROC _hookCallback = NULL;
#pragma comment(linker, "/SECTION:.foo,RWS")
#pragma data_seg()
static HINSTANCE _moduleHandle = NULL;
extern "C" __declspec(dllexport)
HHOOK Install(int idHook, HWND window, HOOKPROC hookCallback);
extern "C" __declspec(dllexport)
LRESULT CALLBACK HookProc(int code, WPARAM wparam, LPARAM lparam);
// dll.cpp
HHOOK Install(int idHook, HWND window, HOOKPROC hookCallback)
{
auto processId = 0ul;
auto threadId = GetWindowThreadProcessId(window, &processId);
_hookCallback = hookCallback;
_hookCallback(-1, NULL, NULL); // Test callback (works)
return SetWindowsHookExA(idHook, HookProc, _moduleHandle, threadId);
}
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
// The following line terminates the target process
return _hookCallback(code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
_moduleHandle = hModule;
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
当DLL KeyboardProc函数被触发时,本地挂钩已成功安装,但是,从C ++ DLL调用C#委托将终止应用程序.为什么?
The local hook is successfuly installed as the DLL KeyboardProc function is triggered, however, calling the C# delegate from the C++ DLL terminates the application. Why?
注释:
- DLL和应用程序均为32位 触发
-
_hookCallback _
不为空(尽管我不确定它是否指向有效的内存地址) -
KeyboardProc :: handler
不应被垃圾回收,因为KeyboardProc实例的生存时间与C#应用程序的寿命一样 - 在DLL的
Install
函数中使用_hookCallback
函数指针可以正常工作,但是在HookProc
函数中使用时终止该过程. - 没有任何例外,该过程只是突然终止
HookProc
时,- Both the DLL and the application are 32 bits
_hookCallback_
is not null whenHookProc
is triggered (although I'm not sure whether it points to a valid memory address)KeyboardProc::handler
shouldn't be garbage collected, as the KeyboardProc instance lives for as long as the C# application does- Using
_hookCallback
function pointer within the DLL'sInstall
function works flawlessly, but terminates the process when used inside theHookProc
function. - There's no exception or whatsoever, the process just terminates abruptly
已经尝试过的内容:
给 HookCallback
一个 UnmanagedFunctionPointer
,以及使用 Marshal.GetFunctionPointerForDelegate
并告诉垃圾回收器不要收集 handler
属性,方法是使用 GCHandle.Alloc()
和 GC.KeepAlive()
:
Making HookCallback
a UnmanagedFunctionPointer
, as well as using Marshal.GetFunctionPointerForDelegate
and telling the garbage collector not to collect the handler
property by using GCHandle.Alloc()
and GC.KeepAlive()
:
public class KeyboardHook
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("DLL32.dll", CallingConvention = CallingConvention.Cdecl)]
protected static extern IntPtr Install(int idHook, IntPtr windowHandle, IntPtr delegatePointer);
// ...
protected readonly GCHandle garbageCollectorHandle;
public KeyboardHook()
{
instance = IntPtr.Zero;
handler = new HookCallback(Callback);
garbageCollectorHandle = GCHandle.Alloc(handler); // Or GC.KeepAlive(handler)
}
~KeyboardHook()
{
garbageCollectorHandle.Free();
}
public void Install(Process process)
{
IntPtr delegatePointer = Marshal.GetFunctionPointerForDelegate(handler);
instance = Install(WH_KEYBOARD, process.MainWindowHandle, delegatePointer);
}
// ...
}
直接使用 handler
到 SetWindowsHookExA
(C ++)中:
Using handler
directly into SetWindowsHookExA
(C++):
HHOOK Install(int idHook, HWND window, HOOKPROC hookCallback)
{
auto processId = 0ul;
auto threadId = GetWindowThreadProcessId(window, &processId);
_hookCallback = hookCallback;
return SetWindowsHookExA(idHook, hookCallback, _moduleHandle, threadId);
}
推荐答案
该过程由于访问无效的内存地址而终止.
The process terminates due to accessing an invalid memory address.
每个Windows进程都有不同的虚拟内存区域.换句话说,进程 A
中的 0x1234
内存地址不指向与进程 0x1234
中的 0x1234
内存地址相同的值/函数.code> B ,因为 0x1234
是绑定到其相应进程的虚拟内存地址.
Every Windows process have different virtual memory regions. In other words, the 0x1234
memory address within the process A
does not point to the same value/function as 0x1234
memory address within the process B
, since 0x1234
is a virtual memory address bound to it's corresponding process.
为了实现C ++ DLL和C#应用程序之间的通信(总体上任何不同的过程),请
In order to achieve that communication between a C++ DLL and a C# application (any different process overall), an inter-process communication (IPC) is required.
对于那些对此特定案例感兴趣的人,我最终创建了一个不可见的虚拟窗口用作通过DLL的 SendMessage
调用接收消息的中心点.
For those interested on this specific case, I ended up creating an invisible dummy window to serve as a central point for receiving messages through SendMessage
calls from the DLL.
这篇关于本地键盘挂钩终止目标进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!