簡體   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