【发布时间】:2012-02-05 06:43:57
【问题描述】:
我最近用 C++ 写了一个 DLL-Injector,要求如下
- 注入过程(我们称之为“注入器”)以及要注入的DLL(注入)存在于64 位和32 位变体中。根据目标,尝试注入匹配的注入版本。
- 必须能够注入 32 位 (WOW64) 的目标进程,即使 Injector 以 64 位运行
我很快注意到,在 Injector 中调用 GetProcAddress("LoadLibraryA") 返回一个“不可用”句柄,因为 32 位目标加载了另一个 kernel32.dll 并且地址功能不同,因此注入失败(无法使用返回的地址/句柄启动远程线程)。此外,32 位进程将 kernel32.dll 加载到不同的基地址,这使得创建远程线程更加不可能。
为了明确我的意思,发生以下情况:
- Injector 在 0x12340000 加载了 64 位版本的 kernel32.dll
- Injector 从此 kernel32.dll 检索 LoadLibraryA 0x00005678 的句柄
- 目标在 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)
- 此时,我们知道 kernel32.dll 在 32 位目标中加载的位置以及来自该 DLL 的函数的地址。
- 64 位 Injector 使用 ImageBase + Function RVA 在 32 位目标中启动远程线程,在本例中为神奇的 0xABCDEFAB
这种方法实际上效果很好,但我无法摆脱这样的想法,即这是总开销,必须有更简单的解决方案来从 64 位注入器注入 32 位目标。
我有两个问题,如果能在这里得到解答,我将非常感激:
- 有没有更简单的方法来实现这种注入?
- 我一直采取的方法是否存在我没有想到的问题?
非常感谢任何答案,谢谢!
编辑:天哪……我刚刚意识到,我在最初的帖子中描述的情况是错误的。 INJECTOR 是 64 位的,TARGET 是 32 位的(最初是相反的,但我已经更正了)。 Ben Voigt 下面的 cmets 完全正确,对 EnumProcessModulesEx 的调用将失败。对这种混乱感到非常抱歉:(
【问题讨论】:
-
啊,这更有意义。
标签: c++ winapi dll 32bit-64bit code-injection