X86 Paste code into an x86 process from an x64 process

I understand the name is a bit confusing, so let me explain what I'm trying to do:

I just finished writing a simple DLL injector to prove the concept I'm trying to write. The program takes a snapshot of the current processes, lists the process tree, and inserts the DLL into its direct parent process. Now, under ideal conditions, this works great: the 32-bit version of the injector can inject into 32-bit parent processes, and the 64-bit version of the injector can inject into 64-bit parent processes.

However, now I want to add the 32-bit DLL to the 32-bit parent process from the x64 injector. After this DLL was injected, I was hoping then to introduce a call to one of the functions exported by the embedded DLL. I am not sure though if this is really possible. (I already compiled some code to determine if the parent process is a 32-bit process or a 64-bit process, so this will not be a problem)

Now, I've already found code that seems to do the first part of injecting precompiled machine code into a process . (At least I think that what he does). Usually, after entering a call to LoadLibraryW, I get the address returned by this call, add the relative offset to the exported function that I want to call, and insert a call to this function. In this case, I cannot load the 32-bit library into my 64-bit injector, so I cannot find the relative offset of the function using GetProcAddress , as usual. I walked past this issue by doing the following:

Since I cannot find the function offset of the 32-bit DLL using conventional means, I am now reading the file into the buffer using this buffer to fill in IMAGE_NT_HEADERS32 and the IMAGE_EXPORT_DIRECTORY enumeration to find the names and relative offsets of all exported functions.

So at this moment I have the following:

  • 32-bit DLL loaded in a 32-bit process
  • The value equivalent to funcAddr when running the following code in a 32-bit process:

code:

HMODULE hInjectedDLL = LoadLibrary("mydll.dll"); DWORD funcAddr = (DWORD)GetProcAddress(hInjectedDLL, "ExportedFunc") - (DWORD)hInjectedDLL; 

Theoretically, all I need now is the value of hInjectedDLL, and I should be able to make a call to this function. Unfortunately, I donโ€™t know enough about assembly or machine codes to know how to do this.

Any ideas?

(In addition, I know that I could save a lot of trouble just by compiling two versions of the injector, and one starting the other when the parent processor architecture of the processor does not match. To avoid this route, though.)

Change Perhaps this will help explain what I'm actually trying to fulfill in this proof of concept.

I am experimenting with the idea that I should allow the execution of a child process in the current console, without the need for the original process to wait for the child to finish. Since there is no built-in API for the console application, you usually loop around the process tree, all waiting for the completion of their child process. To facilitate this functionality, I want to do the following:

Injection

The DLL injector will play the role of the "execution process". (a process that usually needs to wait for a child process to complete). When it starts, it determines the platform of its parent process and whether the parent process is even a console application. If this is not the case, the process simply uses the exec family of functions to start the desired subprocess immediately exiting. If the parent process is a console application, the injector determines which DLL to use, pauses the thread that originally created the injector process, and then inserts the DLL into the parent process.

Resolution of our function

Once the DLL is in place, the injector determines the address of the function exported by the DLL. (I usually did this by calling CreateRemoteThread to do the initial injection, and then use GetExitCodeThread in this thread to get the base address of the DLL in the parent process. Once I have this, try arithmetic to find the address of our exported function, which then I can use a second call to this function to enter.

Call our function

The exported function will look like this:

BOOL RewriteHProcess (HANDLE hProcess)

The injector will again use CreateRemoteThread to call this function from the context of the parent process, with hProcess being the handle to the injector process. On the side of the DLL, the function will do one of two things (I'm not quite sure if my first idea is possible, given the security limitations of memory access by threads, so I put together a second idea to return if it fails first.)

  • RewriteHProcess will open a previously paused stream for reading and writing and using ReadProcessMemory , it will look for the process memory for the HANDLE to our injection process. (We assume that the parent process is currently blocking further execution using the WaitForSingleObject function. I know that Command Prompt does, at the very least, and that my focus is currently on). The DLL then calls an internal function to create the desired child process, closes the old descriptor, and overwrites the memory with the descriptor of our new child process. At this stage, he cleans everything he can and returns. The injector then performed any remaining flushing to resume the paused thread, close the process and thread descriptors, and exit, leaving the parent process to continue locking while it waits for the new child process to complete.

  • If this route is not possible, my reserve was simply to suspend the blocking stream from the injector, create a new child process in the injected DLL, clean and exit the injector, and wait in the DLL until the child process is complete. At this point, the DLL will clear, resume the paused thread, and unload itself. (The disadvantage of this route is that the return code returned by the parent process from the injector may not be the same as the return code from our target child process)

+4
source share
2 answers

Use VirtualAllocEx() to allocate an executable memory block inside the target process, then use WriteProcessMemory() to write x86 or x64 machine instructions to this memory block as needed. Ask these instructions to call LoadLibrary() , GetProcAddress() , the exported DLL function as necessary. Then use CreateRemoteThread() to execute the memory block. Your injector cannot call the exported DLL function directly if it is running in a separate process. The exported function must be loaded and called in the context of the target process. And do not subtract the return value of LoadLibrary() from the return value of GetProcAddress() . GetProcAddress() returns a direct memory pointer to a function, so it can be called directly.

Update: the option is to put all the code you entered inside the entry point into the DLL (or have an entry point that spawns a thread to run the code) when it is called using the DLL_ATTACH_PROCESS reason. Thus, there is no need to export any functions from the DLL. You can then use VirtualAllocEx() and WriteProcessMemory() to store the DLL path in the target process, and then use CreateRemoteThread() to directly call LoadLibrary() . Kernel functions always have the same memory address in different processes, so your injection process can call GetProcAddress() in its own address space to get the address of LoadLibrary() , and then pass this pointer to the lpStartAddress CreateRemoteThread() parameter. This way you don't have to worry about writing any x86 / x64 assembly code.

This method is described in more detail in section 3 of this article:

Three ways to embed your code in another process

+2
source

If someone finds this question and is still confused after reading the comments, you can find (admittedly, ugly) proof of concept here , Assuming you already know a normal DLL injection strategy, explain what you need to do differently . (with corresponding code):


Search for our export ( injdll32_64.c )

Usually we could go along the LoadLibrary/GetProcAddress route, but since these two modules are for different processors, we need to do something different. As Remy Lebo suggested in his answer , we could do this completely on the assembly side. From my point of view, however, recording the assembly to find the base address of kernel32.dll , find the export table and find LoadLibrary and GetProcAddress , it seems like a pain in the ass. Instead, I processed it on the C side, reading in each DLL, searching for IMAGE_EXPORT_DIRECTORY for the required export, and IMAGE_EXPORT_DIRECTORY their RVA for later use.


Call our export on RVA ( injdll32.c , x86.final.asm )

For my purposes, I needed to execute a nested DLL in the main thread of the target application. To do this, I suspended the main thread of the target application, allocated memory for my pre-compiled machine code, filled the placeholders with the corresponding RVAs of the export, changed the EIP of the target application to GetThreadContext/SetThreadContext calls and resumed the hanging thread. (Not necessarily in that order) Unfortunately, I was never going to write the memory release mechanism that VirtualAlloc'ed we had in our target application, but one solution would be to implement the injector notification mechanism when the target process returns to the original EIP. At this point, it would be safe for the VirtualFree injector to allocate allocated memory. (In addition, you can always find a suitable code cave and get rid of worries about freeing memory)

+1
source

Source: https://habr.com/ru/post/1444928/


All Articles