tags:

views:

671

answers:

3

Alright, I'm injecting some code into another process using the CreateRemoteThread/LoadLibrary "trick".

I end up with a thread id, and a process with a DLL of my choice spinning up. At least in theory, the DLL does nothing at the moment so verifying this is a little tricky. For the time being I'm willing to accept it on faith alone. Besides, this question needs to be answered before I push to hard in this direction.

Basically, you can't block in DllMain. However, all I've got to communicate with the remote thread is its id. This practically begs for PostThreadMessage/GetMessage shenanigans which block. I could spin up another thread in DllMain, but I have no way of communicating its id back to the creating thread and no way of passing the another thread's id to the remote one.

In a nutshell, if I'm creating a remote thread in a process how should I be communicating with the original process?

+1  A: 

You don't have the thread id of a thread in the remote process, because the one you used to load the dll exited when your module was successfully loaded into the address space of your process.

You can easily use the normal interprocess communication methods like named sections/pipes/creating a named window/etc. to communicate with your 'injecting' process.

Christopher
+2  A: 

Step zero; the injected DLL should have an entry point, lets call it Init() that takes a LPCWSTR as its single parameter and returns an int; i.e. the same signature as LoadLibrary() and therefore equally valid as a thread start function address...

Step one; inject using load library and a remote thread. Do nothing clever in the injected DLLs DLLMain(). Store the HMODULE that is returned as the exit code of the injecting thread, this is the HMODULE of the injected DLL and the return value of LoadLibrary().

Step two; load the injected DLL using LoadLibrary into the process that is doing the injecting. Then find the offset of your Init() entrypoint in your address space and subtract from it the HMODULE of your injected DLL in your address space. You now have the relative offset of the Init() function. Take the HMODULE of the injected DLL in the target process (i.e. the value you saved in step one) and add the relative address of Init() to it. You now have the address of Init() in your target process.

Step three; call Init() in the target process using the same 'remote thread' approach that you used to call LoadLibrary(). You can pass a string to the Init() call, this can be anything you fancy.

What I tend to do is pass a unique string key that I use as part of a named pipe name. The Injected DLL and the injecting process now both know the name of a named pipe and you can communicate between them. The Init() function isn't DLLMain() and doesn't suffer from the restrictions that affect DLLMain() (as it's not called from within LoadLibrary, etc) and so you can do normal stuff in it. Once the injected DLL and the injecting process are connected via a named pipe you can pass commands and data results back and forth as you like. Since you pass the Init() function a string you can make sure that the named pipe is unique for this particular instance of your injecting process and this particular injected dll which means you can run multiple instances of the injecting process at the same time and each process can inject into multiple target processes and all of these communication channels are unique and controllable.

Len Holgate
I don't see how passing a string to CreateRemoteThread(...,dllExportAddrInRemoteProcess,stringBuffer,...) could work (Without WriteProcessMemory). But, both processes know the process id and thread id of the injected thread so you could use those as part of a name used with IPC
Anders
Yes, you use WriteProcessMemory() in exactly the same way that you did to call LoadLibrary(). I agree you could fudge up a unique id by other means but you need to call something other than DLLMain() to allow you to do initialisation that you can't do in DLLMain() due to the restrictions.
Len Holgate
A: 

In Step 1, how do you set the thread's exit code?

LoadLibrary() returns the HMODULE of the module that you load. When you use a remote thread to run LoadLibrary() (the signature for LoadLibrary() matches that required to start a thread) the return value from LoadLibrary() ends up being the value returned from your thread function (which was LoadLibrary()) and the value returned from your thread function is the exit code of your thread. So, in summary, it just works.
Len Holgate