C++: Injecting 32 bit targets from 64 bit process

2019-01-23 20:46发布

I have written a DLL-Injector in C++ recently, for which the requirements were the following

  • 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. 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

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). 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.

To make clear what I mean, the following happens:

  • Injector has 64 bit version of kernel32.dll loaded at 0x12340000
  • Injector retrieves handle for LoadLibraryA 0x00005678 from this kernel32.dll
  • Target has 32 bit version of kernel32.dll loaded at 0xABCD0000
  • The handle for LoadLibrary of this kernel32.dll is expected to be 0x0000EFAB
  • Injector tries to start remote thread in target with function 0x12345678, but 0xABCDEFAB is expected

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. 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)
  • Get filename of that kernel32.dll, parse the PE header and get the RVA of LoadLibraryA (should be 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.
  • 64 bit Injector starts remote thread in 32 bit target with ImageBase + Function RVA, in this case the magical 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.

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). Ben Voigt's comments down below are totally true, the call to EnumProcessModulesEx would fail. A big big BIG sorry for that confusion :(

3条回答
Animai°情兽
2楼-- · 2019-01-23 21:21

This answer addresses an earlier version of the question, it is mostly irrelevant to the case of a 64-bit injector.


Are you saying that approach works? Because according to the documentation, you can't get information about 64-bit processes from WOW64:

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.

(EnumProcessModules explains the restriction further)

If this function is called from a 32-bit application running on WOW64, it can only enumerate the modules of a 32-bit process. If the process is a 64-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).

But you really do need to find the base address where kernel32.dll loaded, because of ASLR.

查看更多
狗以群分
3楼-- · 2019-01-23 21:29

I think you could use the debug symbols API to save yourself parsing the PE header and export table. This route should yield the required information for the 32-bit injector; 64-bit target case as well, although I still don't see how you're going to pass a 64-bit address to 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).

查看更多
三岁会撩人
4楼-- · 2019-01-23 21:37

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:

#include <Windows.h>

int main(int argc, const char**)
{
    if(argc > 1)
        return (int) LoadLibraryA;
    else
        return (int) GetProcAddress;
}
查看更多
登录 后发表回答