dll-injection - 在 LoadLibrary 上 CreateRemoteThread 并取回 HMODULE

标签 dll-injection

我最近在做DLL注入(inject)工作,所以我做了一些研究
在谷歌上。现在我知道使用 CreateRemoteThread 是一个好方法。

ASLR(地址空间布局随机化,从 Windows Vista 开始)使
kernel32.dll的地址是随机的,但这并不影响整体,因为
在 session 中,所有进程中 kernel32.dll 的基地址只是
相同 - 直到操作系统重置。

所以这段代码通常是安全的:

void launchAndInject(const char* app, const char* dll)
{
    STARTUPINFOA si = {0};
    si.cb = sizeof(si);
    PROCESS_INFORMATION pi = {0};

    if (CreateProcessA(app, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
    {
        LPVOID loadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
        if (loadLibrary == NULL) {
            return;
        }
        SIZE_T len = ::strlen(dll) + 1;
        LPVOID addr = VirtualAllocEx(pi.hProcess, NULL, len, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
        if (addr == NULL) {
            return;
        }
        if (!WriteProcessMemory(pi.hProcess, addr, dll, len, NULL)) {
            return;
        }
        HANDLE th = CreateRemoteThread(pi.hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibrary, addr, 0, NULL);
        WaitForSingleObject(th, INFINITE);
        DWORD ret = 0;
        GetExitCodeThread(th, &ret);
        CloseHandle(th);
        ResumeThread(pi.hThread);
    }
}

注入(inject)线程的退出代码就是返回值
LoadLibrary,所以 ret 只是加载的 DLL 的 HMODULE(在
当然),它就像魔法一样,到目前为止一切都很好。

我读过很多关于 DLL 注入(inject)的项目,他们使用 DLLMain 做了很多
作业——比如创建线程或钩子(Hook) API 等等。他们一定很
仔细去做这些事情,引用文档《Best Practices for
微软的“创建 DLL”,创建线程等行为可能会导致
死锁,“理想的 DllMain 将只是一个空 stub ”,所以我不认为
这是一个非常好的方法。

所以,获取加载的DLL的HMODULE很重要。有了这个 handle ,你可以
使用 CreateRemoteThread 调用注入(inject)的 DLL 的导出函数,做任何事情
您想要,无需担心加载程序锁定的事情。

不幸的是,上面的代码只适用于 32 位进程,这是因为
线程退出代码的类型是 DWORD - 一个 32 位无符号整数,但是
HMODULE 是一个指针,它可以是 64 位的。所以在 64 位进程中,你可能会得到一个
DWORD 值 0xeb390000 来自 GetExitCodeThread,但实际上是 HMODULE
LoadLibrary 返回的是 0x7feeb390000。 0xeb390000 只是截断的 64 位
指针。

我们如何解决这个问题?

最佳答案

您可以假设所示代码可能有效并且截断的 HMODULE大多数时候实际上可能没问题,因为模块通常在进程地址空间中加载得足够低,这无关紧要。为了确保代码始终有效,尽管您可以通过调用 EnumProcessModules() 来遵循“损坏”示例代码功能。如果返回 HMODULE出现在目标进程的进程模块列表中,然后你就可以开始了。如果不是,则需要迭代返回的HMODULE s 并调用 GetModuleBaseName()GetModuleFileNameEx()直到找到注入(inject)的 DLL。

或者,如果您已经作为自定义调试器运行(当我想注入(inject)时我发现它很有用),那么您可以将注入(inject)时加载的模块匹配到相应的 LOAD_DLL_DEBUG_EVENT将由 WaitForDebugEvent() 报告.这将为您提供 HMODULE (图像的基础)和图像文件名,事件将在您注入(inject) DLL 后立即发生。

我个人会采用后一种方法,但实际上我还没有看到截断的 HMODULE从损坏的代码返回的结果不是正确的,但我希望我很幸运,并且依靠加载程序将 DLL 加载到进程地址空间的低位。

关于dll-injection - 在 LoadLibrary 上 CreateRemoteThread 并取回 HMODULE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27332509/

相关文章:

dll-injection - Dll 注入(inject)在挂起的进程中不起作用

c++ - 如何捕获 C++/Windows 中的每个异常?

c++ - 卸载注入(inject)的 DLL 时,FreeLibraryAndExitThread 使程序崩溃

c++ - 使用 GCC/MinGW 创建代理 DLL

dll-injection - 通过 EasyHook 卸载注入(inject)的 DLL

c++ - 在调用导入之前将钩子(Hook) DLL 注入(inject)到进程中?

java - C++ 注入(inject) Java 应用程序

c# - 如何在 C# 中处理动态加载的托管库

c - SetWindowLongPtr 返回 ERROR_ACCESS_DENIED

c# - 为什么 Control.FromHandle(IntPtr) 在一个钩子(Hook)进程中返回 null 并返回 "Form"的有效对象?在另一个上钩的过程中?