SetWindowsHookEx 返回空值的功能问题

4

我正在进行DLL注入,但是遇到了以下错误:

无法挂钩进程:87 参数不正确。

目标进程和dll都是64位的。

注入代码如下:

BOOL HookInjection(TCHAR target[], TCHAR *dll_name)
{
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
    // SetWindowsHookEx can be used to inject a DLL into another process. A 32 - bit DLL cannot be injected into a 64 - bit process, 
    // and a 64 - bit DLL cannot be injected into a 32 - bit process.If an application requires the use of hooks in other processes, 
    // it is required that a 32 - bit application call SetWindowsHookEx to inject a 32 - bit DLL into 32 - bit processes, 
    // and a 64 - bit application call SetWindowsHookEx to inject a 64 - bit DLL into 64 - bit processes.The 32 - bit and 64 - bit DLLs must have different names.

    DbgPrint((char*)"[ ] loading module in local process");
    auto hdll = LoadLibrary(dll_name);
    //Load module ->Loads the specified module into the address space of the calling process. The specified module may cause other modules to be loaded.

    DbgPrint((char*)"[+] loaded dll\n");

    typedef LRESULT(WINAPI * MyProc)(int code, WPARAM wp, LPARAM lp); // export from calc_dll.dll

    //GetProcAdress -> // GetPROCEDUREAdress Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).
    HOOKPROC addr = (HOOKPROC)(GetProcAddress(hdll, "print_successful_injection"));
    //auto mp = MyProc(GetProcAddress(hdll, "StartW"));
    //If you know who uses StartW, hush, its a secret ;)
    DbgPrint((char*)"[] It worked");
    auto pStartupInfo = new STARTUPINFO();
    auto pProcessInfo = new PROCESS_INFORMATION();


    DbgPrint((char*)"[ ] creating process to hook");
    CreateProcess(target,
        nullptr,
        nullptr,
        nullptr,
        FALSE,
        NORMAL_PRIORITY_CLASS,
        nullptr,
        nullptr,
        pStartupInfo,
        pProcessInfo);
    if (!pProcessInfo)
    {
        DbgPrint((char*)"[-] pprocessInfo fucked up");
    }

    if (!pProcessInfo->hProcess)
    {
        DbgPrint((char*)"[-] failed to create process");
        return FALSE;
    }
    DbgPrint((char*)"[+] Created hook process\n");

    DbgPrint((char*)"[ ] creating process hook");
    auto hProc = SetWindowsHookEx(WH_CBT,   // Installs a hook procedure that receives notifications useful to a CBT application
        addr,                                   // my proc symbol taken from the dll
        hdll,                               // dll containing my proc
        pProcessInfo->dwThreadId);          // dword to the thread (something something windows store) RTFM
    if (!hProc)
    {
        DbgPrint((char*)"[-] failed to hook process");
        //This is where the code fails ie hproc is NULL
        return FALSE;
    }
    DbgPrint((char*)"[+] hook injected");
    UnhookWindowsHookEx(hProc);

    return TRUE;
}

注入的dll如下所示:
#include "stdafx.h"
#include<Windows.h>

LRESULT __stdcall print_successful_injection(int code, WPARAM w, LPARAM l)
{
    MessageBox(0, L"Successfully Injected!", L"Hello", MB_ICONINFORMATION);
    return (CallNextHookEx(NULL, code, w, l));
}

def文件内容如下:

LIBRARY "dll_to_inject"
EXPORTS
print_successful_injection

DbgFunction的工作原理如下:
VOID DbgPrint(char *msg)
{

#ifdef DEBUG
DWORD eMsgLen, errNum = GetLastError();//dword is unsigned int
LPTSTR lpvSysMsg; // __Out__ LPTSTR lpBuffer , A pointer to a buffer that receives the null-terminated string that specifies the formatted message

if (msg)
    printf("%s: ", msg);

//FORMAT_MESSAGE_ALLOCATE_BUFFER -> The function allocates a buffer large enough to hold the formatted message, and places a pointer to the allocated buffer at the address specified by lpBuffer.The lpBuffer parameter is a pointer to an LPTSTR
//FORMAT_MESSAGE_FROM_SYSTEM -> The function should search the system message-table resource(s) for the requested message
eMsgLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM,
    NULL, errNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR)&lpvSysMsg, 0, NULL);

//If the function succeeds, the return value is the number of TCHARs stored in the output buffer, excluding the terminating null character.
//If the function fails, the return value is zero.

if (eMsgLen > 0)
    _ftprintf(stderr, _T("%d %s\n"), errNum, lpvSysMsg);
else
    _ftprintf(stderr, _T("Error %d\n"), errNum);
if (lpvSysMsg != NULL)
    LocalFree(lpvSysMsg);
#endif
}

我对stackoverflow还比较陌生,希望我的详细说明足够清晰。

你尝试调用GetLastError()来查看SetWindowsHookEx失败的原因了吗? - thurizas
DbgFunction会这样做。它返回“无法钩取进程:87 参数不正确。” - xizt
你确定 addr 和 hdll 被正确设置了吗?我没有看到你检查 LoadLibrary 或 GetProcAddress 的返回值。虽然我不认为它们会失败,但你应该检查这些返回值。 - thurizas
1个回答

3
如果不是GUI线程调用了SetWindowsHookEx,那么它会失败。更确切地说,如果KTHREADWin32Thread字段为0,则会失败。如果您在太早的时候调用SetWindowsHookEx,那么线程就还不是GUI线程(尚未初始化GUI子系统)。因此,在调用SetWindowsHookEx之前需要等待此过程。不确定是否可能精确捕捉到可以调用SetWindowsHookEx的时刻(在线程调用NtGdiInit后),但最简单的方法是使用新创建进程的句柄调用WaitForInputIdle(pi.hProcess, INFINITE),只有在它返回WAIT_OBJECT_0后才调用SetWindowsHookExW
另外,作为一个独立的注意点 - 您为什么要从堆中分配STARTUPINFOSTARTUPINFO?(并且不要晚些时候释放它)。只需在函数中声明它们为局部变量即可。此外,STARTUPINFO必须初始化,至少如下所示:STARTUPINFO si = { sizeof(si) };您也没有关闭进程和线程句柄。

问题仍然存在。 - xizt
@tejaskulkarni - 如果你只是去修正代码,那么很可能出现你在某个地方犯了错误。最好的方法就是在调试器下一步步运行你的代码(这样子可以给子进程足够的时间去开始运行)- 还会得到87个字符的结果吗? - RbMm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接