CreateRemoteThread DLL Injection
The classic remote DLL injection technique: allocate a DLL path in a target process, write it, then spawn a remote thread starting at LoadLibrary to map the DLL into the victim.
CreateRemoteThread DLL injection is the textbook process-injection primitive on
Windows. The injector writes the full path of an attacker-controlled DLL into the
target's address space, then creates a thread in that process whose start routine
is LoadLibraryA/LoadLibraryW and whose single argument is the DLL path. The OS
loader then maps and runs the DLL inside the victim — no exploit required, just a
handle with the right access rights.
How it works
Because LoadLibraryA has the same prototype as a thread start routine
(LPTHREAD_START_ROUTINE — one pointer argument), its address can be passed
directly to CreateRemoteThread, and the remote thread argument becomes the DLL
path. kernel32.dll is loaded at the same base in every process on a given boot,
so the injector can resolve LoadLibraryA locally and reuse the address remotely.
hProc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE, FALSE, targetPid);
remoteBuf = VirtualAllocEx(hProc, NULL, sizeof(dllPath),
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
WriteProcessMemory(hProc, remoteBuf, dllPath, sizeof(dllPath), NULL);
loadLib = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
CreateRemoteThread(hProc, NULL, 0,
(LPTHREAD_START_ROUTINE)loadLib, remoteBuf, 0, NULL);Detection & bypass
- Static — The injector imports the tell-tale quartet
OpenProcess,VirtualAllocEx,WriteProcessMemory, andCreateRemoteThread, usually next toGetProcAddress("LoadLibraryA"). A plaintext or lightly obfuscated DLL path string (.dll, a temp/AppData directory) is a strong indicator. Unlike most injection variants, the payload here is a real DLL on disk, so the dropped file is itself a static artifact. - Dynamic — In API Monitor or an ETW trace, watch for a
VirtualAllocEx+WriteProcessMemory+CreateRemoteThreadsequence where the source and target PIDs differ and the thread start address resolves toLoadLibraryA/Winsidekernel32. Sysmon Event ID 8 (CreateRemoteThread) records source process, target process, and start address; EID 7 (ImageLoad) then shows the unexpected new module in the victim. - Memory forensics — The injected module is a legitimately mapped,
image-backed DLL, so it does not show as private RWX. Instead it appears as
an unexpected module loaded into a process that should never host it (e.g. a
user DLL inside
lsass.exeorexplorer.exe). pe-sieve enumerates loaded modules and flags the foreign/unsigned DLL; Volatilitydlllist/ldrmodulesreveals a module present in the VAD but missing from one of the PEB loader lists if the entry was tampered with. - Tools — Sysmon (EID 8/7) + ETW, API Monitor, Process Hacker (module and
thread inspection), pe-sieve, Moneta, and Volatility (
dlllist,ldrmodules,malfind).