使用 winapi 的 Dll 注入和 GetProcAddress

逆向工程 视窗 dll C++ dll注入
2021-06-17 05:00:27

所以我只是读了一点关于如何将 dll 注入维基百科上正在运行的程序(这个CreateRemoteThread想法)。我按照所描述的步骤进行操作,并最终使其正常工作。我发现有趣但花了一些时间才弄清楚的事情如下:当创建我的远程线程并发送函数时,我想作为第一个/开始的线程运行我遇到了一个障碍,当它运行时它失败了为了调用正确的函数,当我在 OllyDBG 中查看它们时,它们似乎变成了垃圾,这反过来导致程序在我身上崩溃。我当时使用的代码是这样的:

static DWORD __stdcall inject(LPVOID threadParam)
{
    MessageBoxA(NULL, "test", "test", NULL);
    LoadLibrary("my.dll");
    return 0;
}

还有其他地方:

CreateRemoteThreadEx(hProcess, NULL, 0, LPTHREAD_START_ROUTINE(fnPageBase), dbPageBase, 0, NULL, &threadId);

fnPageBase我在要注入的过程中为我的函数分配的内存在哪里,而 dbPageBase 是我为作为LPVOID threadParam.

类似的东西,问题是这两个MessageBoxALoadLibrary没有得到它似乎是,当我在OllyDbg中检查了他们,他们总是指着一些不存在的正确的地址。我在谷歌上搜索了一下,发现我应该使用它GetProcAddr来获取 ie: 的地址:LoadLibrary我以后可以通过LPVOID threadParam在我的inject()通话中发送一些数据来使用所以我的问题是:为什么当我使用它GetProcAddr而不是当我只是尝试“正常”使用它时它会起作用使用它时,我是否会得到一些特定地址,这些地址总是映射到内存中同一区域的每个人?

另外,inject()函数中的字符串会发生什么变化它们是否在编译期间移动到其他地方,这使得它们对我正在注入的程序不可用,因为它位于内存的完全不同的位置(即,它没有映射到那里?)?我通过将它与结构一起发送到一个结构中来解决这个问题LPVOID threadParam,我已经复制到.exe我正在注入的内存中

如果您需要有关我如何完成其​​他部分的更多信息,请告诉我,我会更新。

1个回答

您需要记住的一件事是您的进程中的代码和目标进程中的代码驻留在不同的地址空间中因此,您程序中的任何地址在目标进程中都不一定有效,反之亦然。

这意味着您注入的代码不能对函数或变量的地址做出任何假设。甚至你的inject函数地址也只在你的进程中有效要使其在目标进程中可用,您必须:1)将代码复制到那里;2) 确保它引用的任何函数或内存地址在新地址空间中都是有效的。

这就是为什么使用 with 的正常方法CreateRemoteThreadEx是将 DLL 名称复制到目标进程并使用LoadLibrary函数的地址创建线程

// 1. Allocate memory in the remote process for szLibPath
pLibRemote = ::VirtualAllocEx( hProcess, NULL, sizeof(szLibPath),
                               MEM_COMMIT, PAGE_READWRITE );

// 2. Write szLibPath to the allocated memory
::WriteProcessMemory( hProcess, pLibRemote, (void*)szLibPath,
                      sizeof(szLibPath), NULL );    

// Load "LibSpy.dll" into the remote process
// (via CreateRemoteThread & LoadLibrary)
hThread = ::CreateRemoteThread( hProcess, NULL, 0,
            (LPTHREAD_START_ROUTINE) ::GetProcAddress( hKernel32,
                                       "LoadLibraryA" ),
             pLibRemote, 0, NULL );

代码项目的片段

可以看到pLibRemote(带有目标进程中DLL名称的地址)作为参数传递给线程例程。所以这个结果等价于:

LoadLibraryA(pLibRemote);

在目标进程中执行。

严格来说,这不能保证有效,因为LoadLibraryA您进程中的地址不一定与LoadLibraryA其他进程中的地址相同但是,实际上它确实有效,因为像 kernel32(LoadLibraryA驻留位置)这样的系统 DLL在所有进程中都映射到相同的地址,因此LoadLibraryA在两个进程中也具有相同的地址。