SetWindowsHookEx() 方法失败,代码为:1428 - dll 注入

SetWindowsHookEx() method fails with code: 1428 - dll injection

我有以下代码:

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;
}

我正在尝试设置一个钩子来对 window 操作做出反应。主要是windows的开闭。 我在 C++ 方面非常缺乏经验,所以我很难调试应用程序并理解我做错了什么。

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

我做错了什么?

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

据我所知这是可行的,因为我收到了调试消息 "Failed to Install hook" 和 "Exiting SETHOOK METHOD".

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

Parameters

lpModuleName

The name of the loaded module (either a .dll or .exe file) ...

If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).

您不能使用 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),因此您只需要调用 1 次 SetWindowsHookEx(),这没有意义在加载 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);

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


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

__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 加载器了。