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.

Loading library

In order to load library during runtime we can call LoadLibrary or 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.

Code

The code should be pretty obvious:

BOOL ok = FALSE; // Assume that the function fails
HANDLE process = NULL, thread = NULL;
PWSTR memory = NULL;

__try {
  // 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
	 FALSE, targetProcessId);
  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
  WaitForSingleObject(thread, INFINITE);

  // We are done
  ok = true; 
}
__finally { 
  // Cleanup
  if (memory) VirtualFreeEx(process, memory, 0, MEM_RELEASE);
  if (thread) CloseHandle(thread);
  if (process) CloseHandle(process);
}

return ok;

Summary

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.