C++:从64位进程注入32位目标

Pue*_*tis 5 c++ dll winapi code-injection 32bit-64bit

我最近在C++中编写了一个DLL-Injector,其要求如下

  • 喷射过程(让我们把它叫做"注射器")以及该DLL被注入(注射)在64位和32位的变体存在.根据目标,尝试注入匹配的注射版本.
  • 即使Injector以64位运行,也必须能够注入32位(WOW64)的目标进程

很快我注意到,Injector 中GetProcAddress("LoadLibraryA")的调用返回一个"不可用"句柄,因为32位目标加载了另一个kernel32.dll,并且函数的地址不同,因此注入失败(无法使用返回的地址/句柄启动远程线程).此外,32位进程将kernel32.dll加载到不同的基址,这使得创建远程线程更加不可能.

为了说清楚我的意思,会发生以下情况:

  • Injector有64位版本的kernel32.dll加载在0x12340000
  • Injector 从此kernel32.dll 检索LoadLibraryA 0x00005678的句柄
  • Target 在0xABCD0000上加载了32位版本的kernel32.dll
  • 此kernel32.dll的LoadLibrary句柄应为0x0000EFAB
  • Injector尝试使用函数0x12345678在目标中启动远程线程,但是需要0xABCDEFAB

当从64位进程注入64位进程,从32位注入32位时,通常没有问题,因为kernel32.dll(很可能)在相同的基地址加载并且可以使用相同的函数地址 - 到目前为止,这是我的解释.在这种情况下,条件不同.

为了解决这个问题,我做了以下步骤:

  • 64位Injector使用EnumProcessModulesEx()检索由32位目标加载的kernel32.dll的地址(应为0xABCD000)
  • 获取该kernel32.dll的文件名,解析PE头并获取LoadLibraryA的RVA (应为0x000EFAB)
  • 此时,我们知道在32位目标中加载kernel32.dll的位置以及此DLL中函数的地址.
  • 64位Injector使用ImageBase + Function RVA在32位目标中启动远程线程,在这种情况下是神奇的0xABCDEFAB

这种方法实际上运行得很好,但我无法摆脱这是总开销的想法,并且必须有一个更简单的解决方案来从64位注入器注入32位目标.

我有两个问题,如果可以在这里回答,我将非常感激:

  1. 有没有更简单的方法来实现这种注射?
  2. 我一直在采取的方法可能存在问题,我没想过?

任何答案都非常感谢,谢谢!

编辑:哦,我的天啊...我刚刚意识到,我在最初的帖子中描述了错误的情况.INJECTOR是64位,TARGET是32位(最初是另一种方式,但我已经纠正了它).Ben Voigt在下面的评论完全正确,对EnumProcessModulesEx的调用将失败.一个大大的抱歉,这种混乱:(

zah*_*zah 5

我偶然发现这个线程正在寻找同样问题的解决方案.

到目前为止,我倾向于使用另一种更简单的解决方案.要获得32位内核proc地址,64位进程只需执行一个32位程序,它将为我们查找proc地址:

#include <Windows.h>

int main(int argc, const char**)
{
    if(argc > 1)
        return (int) LoadLibraryA;
    else
        return (int) GetProcAddress;
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*igt 0

我认为您可以使用调试符号 API 来节省自己解析 PE 标头和导出表的时间。该路由应该产生 32 位注入器所需的信息;64 位目标情况也是如此,尽管我仍然不知道如何将 64 位地址传递给CreateRemoteThread.

通常这些调试符号函数需要 .pdb 或 .sym 文件才能运行,但是我很确定它们也会从 DLL 导出表中获取信息(仅根据调试器对没有符号的文件显示的内容的经验)展示)。