SetWindowsHookEx正在注入32
我一直在研究需要在另一个进程上监视线程特定鼠标活动( WH_MOUSE
)的应用程序,并且遇到了一些非常好奇的事情。
如果我不想使用WH_MOUSE_LL
,并且我需要一个本地DLL导出来将自己注入到目标进程中,我发现通过独占托管代码无法实现这一点,所以我根据什么在C ++中设置并创建它我可以找到关于这个主题的分散文档,然后尝试使用它来挂钩记事本。
虽然根据GetLastWin32Error
注入成功,但我没有得到有关鼠标事件的通知。 在几乎放弃并参与低级别的全局钩子选项之后,我重新阅读了本文的“备注”部分,这让我怀疑问题可能是由于我的代码与记事本的“微不足道”:
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);
}
我对你的问题的最好猜测:
Windows钩子系统可以挂钩32位和64位应用程序。 正如你所指出的那样,你不能将一个DLL注入到一个错误位数的应用程序中。 为了达到这个目的,Windows会正常注入DLL(如果可以的话),但如果不行的话,它会设置一个使用挂钩应用程序消息循环的回调函数。 由于消息循环由OS处理,因此它用于从不同的位进行调用。
在你的情况下,唯一的工作是消息循环的方式。 有一个很好的理由:你的64到64和32到32的调用没有机会成功,因为钩子在被注入的DLL中,也就是说,在与应用程序不同的进程中。
你的情况没有发生,因为你的UserMouseHookCallback
保持为NULL。 事实上,调用SetUserHookCallback()
是在应用程序DLL实例中完成的,但UserMouseHookCallback
在目标DLL实例中没有改变。 一旦注入,DLL就处于不同的进程中,应该被视为这样。 你必须找到另一种回调应用程序的方式(可能会发布一条消息,例如32到64情况,和/或使用共享部分)。
为了测试这个,在InternalMouseHookCallback()
放置MessageBox()
类的东西。 该框即使在64到64和32到32之间也应该出现。
上一篇: SetWindowsHookEx is injecting 32
下一篇: How to inject x86 DLL from the WOW64 process to the x64 process