This is the third part of the DLL Injection series. For your convenience you can find other parts in the table of contents in Part 1 – Registry
We already know how to inject a DLL into process using registry or hooks. With the former approach we cannot control the moment of injection (because it usually happens when the process is starting) whilst with the latter approach we cannot choose the target process (since our library is called to every process). Today we will see yet another method. This time we will be able to precisely choose the target process and the time of injection.
In order to load library during runtime we can call
LoadLibraryEx method and pass it a path to the library. What if we could do the same but in another process? Fortunately, Windows gives us an option to execute code in other process using CreateRemoteThread function. Basically, we are able to start a thread in other process.
Every thread requires a thread function: a piece of code which newly spawned thread will execute. This method can accept at most one parameter. How can we use this to inject DLL? Well, we can create remote thread and point its thread function to
LoadLibrary in target process. However, we need to be able to pass a path to the library as a parameter. We cannot simply allocate memory using
malloc because this method allocates memory in our process.
There is a method which is able to allocate memory in other process: VirtualAllocEx. We can use it to allocate some bytes in target address space and write there a DLL path using WriteProcessMemory function. This should work good.
So the plan looks as follows: we allocate memory in the target process and fill it with the path to the DLL. Next, we get the address of
LoadLibrary function and use it as a thread function for thread created in remote process. Let’s see some code.
The code should be pretty obvious:
BOOL ok = FALSE; // Assume that the function fails
HANDLE process = NULL, thread = NULL;
PWSTR memory = NULL;
// Get a handle for the target process
process = OpenProcess(
PROCESS_QUERY_INFORMATION | // Required by Alpha
PROCESS_CREATE_THREAD | // For CreateRemoteThread
PROCESS_VM_OPERATION | // For VirtualAllocEx
PROCESS_VM_WRITE, // For WriteProcessMemory
if (!process) __leave;
// Calculate the number of bytes required to store DLL path
int numberOfCharacters = 1 + lstrlenW("Path to DLL");
int numberOfBytes = numberOfCharacters * sizeof(wchar_t);
// Allocate memory
memory = (PWSTR) VirtualAllocEx(process, NULL, numberOfBytes, MEM_COMMIT, PAGE_READWRITE);
if (!memory) __leave;
// Write path to DLL
if (!WriteProcessMemory(process, memory, (PVOID) pszLibFile, numberOfBytes, NULL)) __leave;
// Get the address of LoadLibraryW in Kernell32.dll
PTHREAD_START_ROUTINE loadLibraryFunction = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
if (!loadLibraryFunction) __leave;
// Create a remote thread
thread = CreateRemoteThread(process, NULL, 0, loadLibraryFunction, memory, 0, NULL);
if (!thread) __leave;
// Wait for the remote thread to terminate
// We are done
ok = true;
if (memory) VirtualFreeEx(process, memory, 0, MEM_RELEASE);
if (thread) CloseHandle(thread);
if (process) CloseHandle(process);
We are now able to inject DLL into the process we choose and when we decide. Next time we will use this method to inject managed (.NET) DLL.