x64中HMODULE的结构是什么?

时间:2017-10-31 08:11:41

标签: winapi

我正在尝试将injection of my 64-bit DLL实现为64位进程。我的主机进程使用指向CreateRemoteThread的线程子例程调用LoadLibrary。 DLL稍后通过调用FreeLibraryAndExitThread从内部卸载自己。

我的目标是知道注入的LoadLibrary呼叫是否成功。遗憾的是,我无法在我的(主机)进程中使用GetExitCodeThread,因为返回的64位HMODULE句柄被远程线程截断为DWORD。而且我不想使用Tool Help APIs,因为它们会引入竞争条件。

因此我想知道64位进程中HMODULE返回的LoadLibrary的低32位 - 我能否可靠地假设它的低32位不是0的有效的句柄?

PS。我不需要HMODULE句柄本身,我需要知道LoadLibrary是否成功。

编辑。来自我的主机进程的调用是这样完成的(以非常简洁的伪代码 - 没有错误检查):

CreateRemoteThread(hProcess, 0, 0, 
  GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"),
  pVmAddressOfMyDllsPathWrittenWith_WriteProcessMemory, 0, 0);

2 个答案:

答案 0 :(得分:3)

  

我能否可靠地假设它的低32位对于有效的句柄不会是0?

不,你不能。 HMODULE在64位中与在32位中相同。它是加载模块的基址。因此,没有理由为有效的HMODULE必须具有非零的低阶位。

您可以非常简单地确认这一点。创建一个64位DLL,IMAGEBASE设置为0x0000000100000000。加载该DLL,并检查返回的HMODULE的值。

答案 1 :(得分:2)

CreateRemoteThread使用指向LoadLibraryW的线程子例程,我们可以向远程进程注入微小的shell代码,首先调用LoadLibraryW,如果失败,则GetLastError - 结果远程线程返回错误代码(如果没有错误则为0) - 并且您将确切地知道 - LoadLibrary是否正常,如果没有 - 有错误代码。 64位asm代码可以是:

CONST segment

SHELLDATA struct
    LoadLibrary DQ ?
    GetLastError DQ ?
SHELLDATA ends

public RemoteThreadProc_begin
public RemoteThreadProc_end

RemoteThreadProc_begin:
RemoteThreadProc proc
    nop
    nop
    nop
    call @@0
    ___ SHELLDATA <>
@@0:
    xchg [rsp],rbp
    sub rsp,20h
    call SHELLDATA.LoadLibrary[rbp]
    test rax,rax
    jz @@1
    xor eax,eax
@@2:
    add rsp,20h
    pop rbp
    ret
@@1:
    call SHELLDATA.GetLastError[rbp]
    jmp @@2
RemoteThreadProc endp
RemoteThreadProc_end:

CONST ends

和c ++代码:

extern "C"
{
    extern UCHAR RemoteThreadProc_begin[], RemoteThreadProc_end[];
}

enum INJECT_PHASE {
    fOpenProcess, fVirtualAlloc, fWriteProcessMemory, fCreateRemoteThread, fMax
};

ULONG injectDll(ULONG dwprocessId, PCWSTR dllFilePath, INJECT_PHASE& phase)
{
    ULONG err = 0;

    struct SHELLDATA 
    {
        __int64 code;
        PVOID LoadLibrary, GetLastError;
    };

    if (HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, dwprocessId))
    {
        SIZE_T cbStr = (wcslen(dllFilePath) + 1) * sizeof(WCHAR);
        SIZE_T cbCode = ((RemoteThreadProc_end - RemoteThreadProc_begin) + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);

        union {
            PVOID RemoteAddress;
            PBYTE pbRemote;
            PTHREAD_START_ROUTINE lpStartAddress;
        };

        if (RemoteAddress = VirtualAllocEx(hProcess, 0, cbStr + cbCode, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
        {
            union {
                PVOID pv;
                PBYTE pb;
                SHELLDATA* ps;
            };

            pv = alloca(cbStr + cbCode);

            memcpy(pv, RemoteThreadProc_begin, cbCode);
            memcpy(pb + cbCode, dllFilePath, cbStr);

            HMODULE hmod = GetModuleHandle(L"kernel32");
            ps->GetLastError = GetProcAddress(hmod, "GetLastError");
            ps->LoadLibrary = GetProcAddress(hmod, "LoadLibraryW");

            if (WriteProcessMemory(hProcess, RemoteAddress, pv, cbStr + cbCode, 0))
            {
                if (HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, lpStartAddress, pbRemote + cbCode, 0, 0))
                {
                    phase = fMax;
                    WaitForSingleObject(hThread, INFINITE);
                    GetExitCodeThread(hThread, &err);

                    CloseHandle(hThread);
                }
                else
                {
                    phase = fCreateRemoteThread;
                    err = GetLastError();
                }
            }
            else
            {
                phase = fWriteProcessMemory;
                err = GetLastError();
            }

            VirtualFreeEx(hProcess, RemoteAddress, 0, MEM_RELEASE);
        }
        else
        {
            phase = fVirtualAlloc;
            err = GetLastError();
        }

        CloseHandle(hProcess);
    }
    else
    {
        phase = fOpenProcess;
        err = GetLastError();
    }

    return err;
}