简体   繁体   English

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

[英]C++: Injecting 32 bit targets from 64 bit process

I have written a DLL-Injector in C++ recently, for which the requirements were the following 我最近用C ++编写了一个DLL-Injector,对此的要求如下

  • The INJECTING PROCESS (let's call it the 'Injector') as well as the DLL TO BE INJECTED (Injection) exist in 64 and 32 bit variants. 注入过程 (我们称其为“注入器”)以及要注入的DLL (注入)有64位和32位变体。 Depending on the target, the matching version of the injection is tried to be injected. 根据目标,尝试注入匹配版本的注入。
  • It must be possible to inject target processes that are 32 bit (WOW64) even with the Injector running in 64 bit 即使注入器以64位运行,也必须能够注入32位(WOW64)的目标进程

It came quickly to my notice, that the call of GetProcAddress("LoadLibraryA") in the Injector returns an "unusable" handle as the 32 bit target has another kernel32.dll loaded and the address of the function there is different, so injection fails (The remote thread can not be started using the returned address/handle). 我很快注意到,在Injector中对GetProcAddress(“ LoadLibraryA”)的调用返回了“无法使用”的句柄,因为32位目标已加载了另一个kernel32.dll,并且该函数的地址不同,因此注入失败(无法使用返回的地址/句柄启动远程线程)。 Furthermore, the 32 bit process has the kernel32.dll loaded at a different base address, which makes creation of the remote thread even more impossible. 此外,该32位进程在不同的基址上加载了kernel32.dll,这使得创建远程线程变得更加不可能。

To make clear what I mean, the following happens: 为了弄清楚我的意思,发生了以下情况:

  • Injector has 64 bit version of kernel32.dll loaded at 0x12340000 注入器具有0x12340000加载的64位版本的kernel32.dll
  • Injector retrieves handle for LoadLibraryA 0x00005678 from this kernel32.dll 注入器从该kernel32.dll中检索LoadLibraryA 0x00005678的句柄
  • Target has 32 bit version of kernel32.dll loaded at 0xABCD0000 目标具有0xABCD0000加载的32位版本的kernel32.dll
  • The handle for LoadLibrary of this kernel32.dll is expected to be 0x0000EFAB 此kernel32.dll的LoadLibrary的句柄应为0x0000EFAB
  • Injector tries to start remote thread in target with function 0x12345678, but 0xABCDEFAB is expected 注入器尝试使用功能0x12345678启动目标中的远程线程,但预期为0xABCDEFAB

When injecting a 64 bit process from a 64 bit process, and 32 bit from 32 bit, there is usually no problem, as the kernel32.dll is (most likely) loaded at the same base address and the same function address can be used - that's my unterstanding so far. 当从64位进程注入64位进程,从32位注入32位进程时,通常没有问题,因为kernel32.dll(最有可能)被加载到相同的基地址并且可以使用相同的功能地址-到目前为止,这是我的理解。 In this case however the conditions differ. 但是,在这种情况下,条件有所不同。

To overcome the problem I did the following steps: 为了解决该问题,我执行了以下步骤:

  • 64 bit Injector retrieves address of kernel32.dll loaded by 32 bit target using EnumProcessModulesEx() (should be 0xABCD000) 64位注入器使用EnumProcessModulesEx()检索由32位目标加载的kernel32.dll的地址(应为0xABCD000)
  • Get filename of that kernel32.dll , parse the PE header and get the RVA of LoadLibraryA (should be 0x000EFAB) 获取该kernel32.dll的文件名,解析PE标头并获取LoadLibraryA的RVA(应为0x000EFAB)
  • At this point, we know where kernel32.dll is loaded in the 32 bit target and the address of the function from this DLL. 至此,我们知道将kernel32.dll加载到32位目标中的位置以及该DLL中函数的地址。
  • 64 bit Injector starts remote thread in 32 bit target with ImageBase + Function RVA , in this case the magical 0xABCDEFAB 64位Injector使用ImageBase + Function RVA在32位目标中启动远程线程,在这种情况下是神奇的0xABCDEFAB

This approach actually works very well, but I can't get rid of the thought that this is total overhead and there must be a more simpler solution to inject 32 bit targets from 64 bit injectors. 这种方法实际上效果很好,但是我无法摆脱这是总开销的想法,必须有一个更简单的解决方案才能从64位注入器注入32位目标。

I have two questions, for which I am very grateful if they could be answered here: 我有两个问题,如果能在这里回答,我非常感谢:

  1. Is there a more simple way to achieve this kind of injection? 有没有更简单的方法来实现这种注射?
  2. Are there possible problems with the approach I've been taking that I haven't thought about? 我一直在考虑的方法是否存在未曾想到的问题?

Any answers are very much appreciated, thanks! 任何答案都非常感谢,谢谢!

EDIT: Oh my gosh... I just realized, that I described the situation wrong in my initial post. 编辑:哦,天哪...我刚刚意识到,我在最初的帖子中描述了错误的情况。 The INJECTOR is 64 bit, and the TARGET is 32 bit (Initially it was the other way around, but I already corrected it). INJECTOR是64位,而TARGET是32位(最初是相反的,但是我已经纠正了)。 Ben Voigt's comments down below are totally true, the call to EnumProcessModulesEx would fail. Ben Voigt在下面的评论完全正确,对EnumProcessModulesEx的调用将失败。 A big big BIG sorry for that confusion :( 非常感谢您的困惑:(

I stumbled upon this thread looking for a solution for the same problem. 我偶然发现了该线程,希望为同一问题找到解决方案。

So far I'm inclined to use another simpler solution. 到目前为止,我倾向于使用另一个更简单的解决方案。 To obtain a 32-bit kernel proc address, the 64-bit process can just execute a 32-bit program that will look up the proc addresses for us: 要获得32位内核proc地址,该64位进程只需执行一个32位程序即可为我们查找该proc地址:

#include <Windows.h>

int main(int argc, const char**)
{
    if(argc > 1)
        return (int) LoadLibraryA;
    else
        return (int) GetProcAddress;
}

This answer addresses an earlier version of the question, it is mostly irrelevant to the case of a 64-bit injector. 该答案解决了该问题的早期版本,与64位注入器的情况基本无关。


Are you saying that approach works? 您是说这种方法有效吗? Because according to the documentation , you can't get information about 64-bit processes from WOW64: 因为根据文档 ,您无法从WOW64获取有关64位进程的信息:

If the function is called by a 32-bit application running under WOW64, the dwFilterFlag option is ignored and the function provides the same results as the EnumProcessModules function. 如果该函数由在WOW64下运行的32位应用程序调用,则dwFilterFlag选项将被忽略,并且该函数提供的结果与EnumProcessModules函数相同。

( EnumProcessModules explains the restriction further) EnumProcessModules进一步解释了限制)

If this function is called from a 32-bit application running on WOW64, it can only enumerate the modules of a 32-bit process. 如果从在WOW64上运行的32位应用程序调用此函数,则它只能枚举32位进程的模块。 If the process is a 64-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299). 如果该进程是64位进程,则此函数将失败,并且最后的错误代码是ERROR_PARTIAL_COPY(299)。

But you really do need to find the base address where kernel32.dll loaded, because of ASLR . 但是由于ASLR ,您确实需要找到kernel32.dll加载的基址。

I think you could use the debug symbols API to save yourself parsing the PE header and export table. 我认为您可以使用调试符号API来节省解析PE标头和导出表的时间。 This route should yield the required information for the 32-bit injector; 此路由应为32位注入器提供所需的信息。 64-bit target case as well, although I still don't see how you're going to pass a 64-bit address to CreateRemoteThread . 同样以64位目标为例,尽管我仍然看不到如何将64位地址传递给CreateRemoteThread

Normally these debug symbol functions require a .pdb or .sym file to operate, however I'm pretty sure they also get information from a DLL export table (just going from experience of what a debugger shows for files where I don't have symbols present). 通常,这些调试符号函数需要.pdb或.sym文件才能运行,但是我很确定它们也可以从DLL导出表中获取信息(只是从调试器针对没有符号的文件显示的经验中得出的信息)当下)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM