【发布时间】:2015-10-30 16:45:56
【问题描述】:
我一直在开发一个应用程序,该应用程序需要监视另一个进程上的线程特定鼠标活动 (WH_MOUSE),并且遇到了一些非常奇怪的事情。
在发现 this is not possible via exclusively managed code 如果我不想使用 WH_MOUSE_LL 并且我需要一个本地 DLL 导出来将自己注入目标进程后,我开始根据什么在 C++ 中创建它我可以找到关于该主题的零散文档,然后尝试使用它连接到记事本。
虽然根据GetLastWin32Error 注入成功,但我没有收到鼠标事件的通知。在几乎放弃并选择低级全局挂钩选项后,我重新阅读了this article 的“备注”部分,这让我怀疑问题可能是因为我的代码与记事本的“位”:
32 位 DLL 不能注入 64 位进程,而 64 位 DLL 不能注入 32 位进程。如果一个应用程序 需要在其他进程中使用钩子,需要一个 32 位应用程序调用 SetWindowsHookEx 将 32 位 DLL 注入 32 位进程和 64 位应用程序调用 SetWindowsHookEx 将 64 位 DLL 注入 64 位进程。
但是,我的本地 DLL 和托管应用程序都编译为 x64,并且我试图挂接到 64 位版本的记事本,所以它应该可以正常工作,但我还是在黑暗中拍摄了进入SysWOW64 文件夹并从那里打开 32 位记事本,再次尝试挂接,这次挂接效果很好!
奇怪的是,我随后将我的原生 DLL 和托管应用程序都重新编译为 x86,并在 32 位记事本上对其进行了测试,但它不起作用,但它在我的普通 64 位记事本上运行!
我怎么可能将 32 位 DLL 注入 64 位进程,反之亦然!
虽然我最初的问题已经解决并且我可以继续我的应用程序的开发,但对于为什么我从SetWindowsHookEx 观察到这种奇怪的反向行为的好奇心让我发疯了,所以我真的希望有人能够对此有所了解。
我知道这话很多,没有代码,但即使是一个示例应用程序的代码也相当大,并且有托管和非托管两种风格,但是我会及时发布您认为可能相关的任何代码.
我还创建了一个示例应用,以便您自己测试此行为。这是一个简单的 WinForms 应用程序,它尝试挂接到记事本并显示其鼠标事件:
http://saebamini.com/HookTest.zip
它包含 x86 版本和 x64 版本。在我的机器上(我在 64 位 Windows 7 上),x86 版本仅适用于 64 位记事本,而 x64 版本仅适用于 32 位记事本(来自 SysWOW64)。
更新 - 相关代码:
对非托管库的 C# 调用:
public SetCallback(HookTypes type)
{
_type = type;
_processHandler = new HookProcessedHandler(InternalHookCallback);
SetCallBackResults result = SetUserHookCallback(_processHandler, _type);
if (result != SetCallBackResults.Success)
{
this.Dispose();
GenerateCallBackException(type, result);
}
}
public void InstallHook()
{
Process[] bsProcesses = Process.GetProcessesByName("notepad");
if(bsProcesses.Length == 0)
{
throw new ArgumentException("No open Notepad instance found.");
}
ProcessThread tmp = GetUIThread(bsProcesses[0]);
if (!InitializeHook(_type, tmp.Id))
{
throw new ManagedHooksException("Hook initialization failed.");
}
_isHooked = true;
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr procid);
// 64-bit version
[DllImport("SystemHookCore64.dll", EntryPoint = "InitializeHook", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern bool InitializeHook(HookTypes hookType, int threadID);
[DllImport("SystemHookCore64.dll", EntryPoint = "SetUserHookCallback", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern SetCallBackResults SetUserHookCallback(HookProcessedHandler hookCallback, HookTypes hookType);
C++:
HookProc UserMouseHookCallback = NULL;
HHOOK hookMouse = NULL;
HINSTANCE g_appInstance = NULL;
MessageFilter mouseFilter;
bool InitializeHook(UINT hookID, int threadID)
{
if (g_appInstance == NULL)
{
return false;
}
if (hookID == WH_MOUSE)
{
if (UserMouseHookCallback == NULL)
{
return false;
}
hookMouse = SetWindowsHookEx(hookID, (HOOKPROC)InternalMouseHookCallback, g_appInstance, threadID);
return hookMouse != NULL;
}
}
int SetUserHookCallback(HookProc userProc, UINT hookID)
{
if (userProc == NULL)
{
return HookCoreErrors::SetCallBack::ARGUMENT_ERROR;
}
if (hookID == WH_MOUSE)
{
if (UserMouseHookCallback != NULL)
{
return HookCoreErrors::SetCallBack::ALREADY_SET;
}
UserMouseHookCallback = userProc;
mouseFilter.Clear();
return HookCoreErrors::SetCallBack::SUCCESS;
}
return HookCoreErrors::SetCallBack::NOT_IMPLEMENTED;
}
int FilterMessage(UINT hookID, int message)
{
if (hookID == WH_MOUSE)
{
if(mouseFilter.AddMessage(message))
{
return HookCoreErrors::FilterMessage::SUCCESS;
}
else
{
return HookCoreErrors::FilterMessage::FAILED;
}
}
return HookCoreErrors::FilterMessage::NOT_IMPLEMENTED;
}
static LRESULT CALLBACK InternalMouseHookCallback(int code, WPARAM wparam, LPARAM lparam)
{
if (code < 0)
{
return CallNextHookEx(hookMouse, code, wparam, lparam);
}
if (UserMouseHookCallback != NULL && !mouseFilter.IsFiltered((int)wparam))
{
UserMouseHookCallback(code, wparam, lparam);
}
return CallNextHookEx(hookMouse, code, wparam, lparam);
}
【问题讨论】:
-
因为你的问题是关于钩子的,所以显示设置钩子的代码,以及钩子本身(你得到鼠标事件的地方)。
-
@ElderBug,感谢您的关注。我已经用相关的代码更新了这个问题。
标签: c# c++ windows hook code-injection