Sunday, February 22, 2009

Injecting Code using CreateRemoteThread.

We all know that we try to do those things that we are barred from… J A normal human tendency! Or maybe a weird human tendency!

So let's first put down what we want to achieve:

  1. We want a way to inject some code in a process (of course I am not talking about our own process).
  2. How do we make it execute?

One line answers:

  1. We can load a DLL in the process to inject the code.
  2. We need to create a thread which will execute that piece of code.


 

Let's enumerate as to what we have that we can make use of:

  1. CreateRemoteThread API to create a thread in a process.
  2. LoadLibrary API to load a DLL.


 

CreateRemoteThread has a parameter which takes the address of the function to be executed when the thread starts. Can we somehow combine points 1 & 2 enumerated above? Yes, we can pass the address of LoadLibrary in CreateRemoteThread. But there is a catch! Don't just write LoadLibrary in the following manner:

CreateRemoteThread( …, LoadLibrary, …);

This is incorrect. You need to get the address of LoadLibrary in kernel32.dll using GetProcAddress and pass that address in CreateRemoteThread.

Next step is to tell LoadLibrary the name of the DLL which needs to be loaded. But remember one thing, you can't use a string allocated in your process in the process where the DLL needs to be loaded. So you need to allocate memory in the target process using VirtualAllocEx. And then copy the path of the DLL in the allocated space using WriteProcessMemory.

Upto this point we have discussed how to inject the code; by using CreateRemoteThread, LoadLibrary, GetProcAddress, VirtualAllocEx and WriteProcessMemory.

But where should we place the code in the DLL so that it gets executed? Afterall if you make some functions in DLL and export them, the target process will not call them anyways. Let's think of the first function that gets called in the DLL when it is loaded. It is DllMain with notification type DLL_PROCESS_ATTACH. You can place the code to be executed in DllMain under the case for DLL_PROCESS_ATTACH.

Simple! Isn't it? But this method faces a problem in Vista. This is because the CreateRemoteThread API does not work across sessions. So all process that run in a different session cannot be targeted using this method.

1 comment:

  1. You can't just "put the code you want to be executed" in DllMain. There are very strict rules about what is safe in DllMain and what isn't. You can only perform very basic tasks in DllMain.

    If you want your code to be safe, stable, and portable you should export a function to do all the 'real' work, then call that remotely once your module has been loaded into the remote process.

    Just take the pointer/handle returned from the call to LoadLibrary and use it to walk the EAT remotely, find the initialize function which you exported, and call it.

    Also, calling GetProcAddress on LoadLibrary and expecting it to be the same cross-process is unsafe. Vista's compatiability engine performs IAT/EAT hooking and so if your process has been hooked and the target process has not you will be creating a thread at a garbage memory location. You should manually walk the EAT of Kernel32 to get the 'true' address of LoadLibrary.

    ReplyDelete