【问题标题】:SetWindowsHookEx() method fails with code: 1428 - dll injectionSetWindowsHookEx() 方法失败并出现代码:1428 - dll 注入
【发布时间】:2020-08-08 08:14:06
【问题描述】:

我有以下代码:

LRESULT __stdcall HookCallback(int code,
    WPARAM wParam,
    LPARAM lParam)
{
    ...

    return CallNextHookEx(_hook, code, wParam, lParam);
}

void SetHook()
{
    HMODULE hmod = GetModuleHandle(0);

    if (!(_hook = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallback, hmod, 0)))
    {
        OutputDebugString(TEXT("Failed to Install hook"));
    }

    OutputDebugString(TEXT("Exiting SETHOOK METHOD"));
}

void ReleaseHook()
{
    UnhookWindowsHookEx(_hook);
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    OutputDebugString(TEXT("Entered DLL"));

    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        SetHook();
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        ReleaseHook();
        break;
    }

    return TRUE;
}

我正在尝试设置一个挂钩来响应窗口操作。主要是开、关窗户。 我在 C++ 方面非常缺乏经验,所以我很难调试应用程序并理解我做错了什么。

在我的SetHook() 方法中,SetWindowHookEx 方法总是以代码 1428 失败。因此永远不会调用 Callback 方法(此处未显示)。

我做错了什么?

PS:我正在使用注册表将 .dll 注入进程: 路径:Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows 姓名:AppInit_DLLS

据我所知,这是有效的,因为我收到调试消息“无法安装挂钩”和“正在退出 SETHOOK 方法”。

【问题讨论】:

    标签: c++ windows winapi hook


    【解决方案1】:

    您将 0(又名 NULL)传递给 GetModuleHandle(),因此您正在检索您的 DLL 加载到其进程中的 EXE 文件的 HMODULE

    参数

    lpModuleName

    已加载模块的名称(.dll 或 .exe 文件)...

    如果此参数为 NULL,GetModuleHandle 返回用于创建调用进程的文件(.exe 文件)的句柄。

    您不能使用 HMODULE 来安装 DLL 中的 SetWindowsHookEx() 挂钩回调。您需要使用 DLL 自己的HMODULE 本身,即作为输入参数提供给您的DllMain() 的那个,例如:

    HHOOK _hook = NULL;
    
    LRESULT __stdcall HookCallback(int code,
        WPARAM wParam,
        LPARAM lParam)
    {
        ...
    
        return CallNextHookEx(_hook, code, wParam, lParam);
    }
    
    void SetHook(HMODULE hModule) // <-- ADD THIS PARAM
    {
        if (!_hook)
        {
            _hook = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallback, hModule, 0); // <-- USE IT HERE
            if (!_hook)
            {
                OutputDebugString(TEXT("Failed to Install hook"));
            }
        }
    
        OutputDebugString(TEXT("Exiting SETHOOK METHOD"));
    }
    
    void ReleaseHook()
    {
        if (_hook)
        {
            UnhookWindowsHookEx(_hook);
            _hook = NULL;
        }
    }
    
    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )
    {
        OutputDebugString(TEXT("Entered DLL"));
    
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls(hModule);
            SetHook(hModule); // <-- PASS IT HERE
            break;
        case DLL_PROCESS_DETACH:
            ReleaseHook();
            break;
        }
    
        return TRUE;
    }
    

    话虽如此,您正在尝试全局安装一个钩子(hMod != NULLdwThreadId == 0),所以您只需要调用一次SetWindowsHookEx(),在每个中调用它是没有意义的/em> 加载 DLL 的进程。您应该创建自己的 EXE,将您的 DLL 加载到内存中并为其调用 SetWindowsHookEx() 1 次,例如:

    HMODULE _hmod = NULL;
    HHOOK _hook = NULL;
    
    // be sure to export your hook functions from the DLL..
    
    LRESULT __stdcall HookCallback(int code,
        WPARAM wParam,
        LPARAM lParam)
    {
        ...
    
        return CallNextHookEx(_hook, code, wParam, lParam);
    }
    
    void SetHook()
    {
        if (!_hook)
        {
            _hook = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallback, _hmod, 0);
            if (!_hook)
            {
                OutputDebugString(TEXT("Failed to Install hook"));
            }
        }
    
        OutputDebugString(TEXT("Exiting SETHOOK METHOD"));
    }
    
    void ReleaseHook()
    {
        if (_hook)
        {
            UnhookWindowsHookEx(_hook);
            _hook = NULL;
        }
    }
    
    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )
    {
        _hmod = hModule;
    
        OutputDebugString(TEXT("Entered DLL"));
    
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls(hModule);
            break;
        }
    
        return TRUE;
    }
    
    typedef void (*LPFN_SH)();
    typedef void (*LPFN_RH)();
    
    HMODULE hMod = LoadLibrary("my.dll");
    LPFN_SH SetHook = (LPFN_SH) GetProcAddress(hMod, "SetHook");
    LPFN_RH ReleaseHook = (LPFN_RH) GetProcAddress(hMod, "ReleaseHook");
    ...
    SetHook();
    ...
    ReleaseHook();
    FreeLibrary(hMod);
    

    然后,您的 DLL 将在 EXE 进程的整个生命周期内自动注入到与您的 DLL 位数相匹配的每个正在运行的进程中(这意味着您需要单独的 DLL 来挂钩 32 位和 64 位进程)。根本不需要使用AppInit_DLLS 注册表项。


    否则,如果您真的想使用 AppInit_DLLS 将 DLL 注入每个位匹配进程,那么最好让 DLL 在每个线程的基础上调用 SetWindowsHookEx()hMod == NULL 和 @ 987654339@) 而不是在全球范围内,例如:

    __declspec(thread) HHOOK _hook = NULL;
    
    LRESULT __stdcall HookCallback(int code,
        WPARAM wParam,
        LPARAM lParam)
    {
        ...
    
        return CallNextHookEx(_hook, code, wParam, lParam);
    }
    
    void SetHook()
    {
        if (!_hook)
        {
            DWORD dwThreadId = GetCurrentThreadId();
    
            _hook = SetWindowsHookEx(WH_CALLWNDPROCRET, HookCallback, NULL, dwThreadId);
            if (!_hook)
            {
                OutputDebugString(TEXT("Failed to Install hook"));
            }
        }
    
        OutputDebugString(TEXT("Exiting SETHOOK METHOD"));
    }
    
    void ReleaseHook()
    {
        if (_hook)
        {
            UnhookWindowsHookEx(_hook);
            _hook = NULL;
        }
    }
    
    BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
    )
    {
        OutputDebugString(TEXT("Entered DLL"));
    
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
            SetHook();
            break;
        case DLL_PROCESS_DETACH:
        case DLL_THREAD_DETACH:
            ReleaseHook();
            break;
        }
    
        return TRUE;
    }
    

    那么就不需要使用单独的 EXE 加载器了。

    【讨论】:

    • 我想我误解了SetWindowsHookEx 的工作原理。我的印象是,必须将 dll 注入每个进程才能实现“真正的”全局挂钩。关于第二种方法(EXE加载器)的一些问题:调用DisableThreadLibraryCalls(hModule)是必要的还是优化的?是否会调用SetWindowsHookEx 一次也钩住某个进程的子进程?注入如何对现有流程起作用?您能否指出一些描述此注入过程的资源?非常感谢!
    • 另外,是否有兴趣使用第三种方法(我原来使用AppInit_DLLS 的解决方案)?具体来说,我能以某种方式提高性能吗?我假设,我可以通过获取模块句柄来操作调用可执行文件,但这在我的用例中并不重要。
    • @AsPas 您的所有问题都在您仔细阅读的 MSDN 文档中得到了解答。至于AppInit_DLLS,它是有限制的,所以没有以前那么好用了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    • 1970-01-01
    • 2020-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多