繁体   English   中英

SetWindowsHookEx将32位DLL注入64位进程,反之亦然

[英]SetWindowsHookEx is injecting 32-bit DLL into 64-bit process and vice versa

我一直在研究一个需要在另一个进程上监视线程特定鼠标活动( 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() InternalMouseHookCallback() 该框应该出现在64到64和32到32之间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM