Process Injection
Overview
Process injection executes code within the address space of another process, allowing the attacker to hide within a legitimate process, inherit its security context and network access, and evade process-based detection rules. Different injection techniques vary in stealth, complexity, and compatibility. Choosing the right technique depends on the target process, EDR coverage, and required privileges.
ATT&CK Mapping
- Tactic: TA0005 - Defense Evasion, TA0004 - Privilege Escalation
- Technique: T1055 - Process Injection
Techniques
Classic Remote Thread Injection (T1055)
The simplest and most detected injection technique:
1. OpenProcess(PROCESS_ALL_ACCESS, targetPID)
2. VirtualAllocEx(hProcess, RWX memory)
3. WriteProcessMemory(hProcess, shellcode)
4. CreateRemoteThread(hProcess, shellcode address)
Detection:
- EDR hooks all four API calls
- Cross-process memory allocation is highly suspicious
- CreateRemoteThread is a well-known indicator
Use case: Testing environments, CTFs, no EDR
DLL Injection (T1055.001)
Inject a DLL into a target process via LoadLibrary:
1. OpenProcess(targetPID)
2. VirtualAllocEx — allocate memory for DLL path string
3. WriteProcessMemory — write DLL path to target process
4. CreateRemoteThread with LoadLibraryA as the start address
and the DLL path as the argument
The target process calls LoadLibrary, which loads and executes
the DLL's DllMain function.
Advantages:
- Well-understood, simple to implement
- DLL can contain complex logic
Disadvantages:
- DLL must exist on disk (detectable by AV)
- CreateRemoteThread is monitored
- LoadLibrary triggers image load callbacks in the kernel
Reflective DLL Injection (T1055)
Load a DLL entirely from memory without touching disk:
1. Read DLL into a buffer (in the injecting process)
2. Allocate memory in target process
3. Write the entire DLL (PE file) to target process memory
4. Write a reflective loader stub that:
- Parses the PE headers
- Resolves imports manually
- Applies relocations
- Calls DllMain
5. CreateRemoteThread pointing to the reflective loader
Advantages:
- No DLL file on disk
- No LoadLibrary call (bypasses image load monitoring)
Disadvantages:
- Cross-process memory write still detectable
- Full PE in memory can be found by memory scanning
Process Hollowing (T1055.012)
Replace the code of a legitimate process with malicious code:
1. CreateProcess("svchost.exe", CREATE_SUSPENDED)
— process is created but not running yet
2. NtUnmapViewOfSection — unmap the legitimate code
3. VirtualAllocEx — allocate new memory at the image base
4. WriteProcessMemory — write malicious PE image
5. SetThreadContext — update entry point to malicious code
6. ResumeThread — process starts executing malicious code
From the OS perspective: svchost.exe is running normally
From memory perspective: the code is completely replaced
Detection:
- Memory image doesn't match the on-disk binary
- Section permissions don't match expected PE layout
- Thread start address outside mapped module ranges
APC Injection (T1055.004)
Asynchronous Procedure Calls — queue code execution in a target thread:
1. OpenProcess + OpenThread (find an alertable thread)
2. VirtualAllocEx — allocate memory for shellcode
3. WriteProcessMemory — write shellcode
4. QueueUserAPC(shellcode_address, hThread)
The shellcode executes when the target thread enters an alertable wait state
(SleepEx, WaitForSingleObjectEx, WaitForMultipleObjectsEx, etc.)
Advantages:
- No CreateRemoteThread (avoids that specific hook)
- Can target specific threads
Disadvantages:
- Requires an alertable thread (not guaranteed)
- Early Bird variant: inject into a newly created suspended process
(the first APC runs before the process entry point)
Early Bird APC Injection:
1. CreateProcess(SUSPENDED)
2. VirtualAllocEx + WriteProcessMemory (shellcode)
3. QueueUserAPC to the main thread
4. ResumeThread — APC fires before any application code
Thread Hijacking (T1055.003)
Hijack an existing thread's execution flow:
1. OpenProcess + OpenThread
2. SuspendThread(hThread)
3. GetThreadContext — save current register state
4. VirtualAllocEx + WriteProcessMemory (shellcode)
5. SetThreadContext — change RIP/EIP to shellcode address
6. ResumeThread — thread now executes shellcode
The shellcode can optionally restore the original context and jump back
to the original code after execution.
Advantages:
- No new thread created
- Uses existing thread context
Disadvantages:
- Suspending threads can cause stability issues
- GetThreadContext/SetThreadContext are monitored
NtMapViewOfSection (T1055)
Map a section object into a target process (no WriteProcessMemory):
1. NtCreateSection — create a shared memory section
2. NtMapViewOfSection — map section into current process (RW)
3. Copy shellcode into the mapped section
4. NtMapViewOfSection — map same section into target process (RX)
5. CreateRemoteThread or APC to execute
Advantages:
- No WriteProcessMemory call (bypasses that specific hook)
- Shared section appears in both processes
Disadvantages:
- Still need to trigger execution (thread/APC)
- NtMapViewOfSection in remote process is still suspicious
Module Stomping / DLL Hollowing
Overwrite a legitimate DLL's .text section in a target process:
1. Identify a loaded but infrequently used DLL in the target process
2. Write shellcode over the DLL's .text section
3. The shellcode now resides in a "legitimate" module's memory range
Advantages:
- Shellcode appears to be part of a signed, legitimate DLL
- Thread start address points to a known module (looks normal)
Disadvantages:
- DLL functionality is destroyed
- Memory content doesn't match on-disk DLL (detectable)
Injection Technique Comparison
Technique Stealth Complexity Disk Artifact New Thread
───────────────────────── ──────── ────────── ───────────── ──────────
Remote Thread Injection Low Low No Yes
DLL Injection Low Low Yes (DLL) Yes
Reflective DLL Injection Medium Medium No Yes
Process Hollowing Medium High No No (reused)
APC Injection Medium Medium No No
Early Bird APC High Medium No No
Thread Hijacking High High No No
NtMapViewOfSection Medium Medium No Yes
Module Stomping High High No No
Good Injection Targets
Process Why
─────────────────── ─────────────────────────────────────────────────
explorer.exe Always running, makes network connections
svchost.exe Many instances, expected to do everything
RuntimeBroker.exe Common, often idle
taskhostw.exe Runs scheduled tasks, varied behavior
dllhost.exe COM surrogate, varied behavior
sihost.exe Shell Infrastructure Host
Avoid:
- lsass.exe (heavily protected, triggers alerts)
- csrss.exe (protected process, injection fails)
- smss.exe (session manager, very restricted)
Detection Methods
Host-Based Detection
- Cross-process memory operations (VirtualAllocEx, WriteProcessMemory)
- Thread creation in remote processes (CreateRemoteThread, NtCreateThreadEx)
- Thread start addresses outside known module ranges
- Memory sections with executable permissions that don't correspond to loaded modules
- Kernel callbacks: PsSetCreateThreadNotifyRoutine, PsSetLoadImageNotifyRoutine
Behavioral Indicators
- svchost.exe making unexpected network connections
- Explorer.exe spawning cmd.exe or powershell.exe
- Processes with memory regions that don't match their on-disk image
Mitigation Strategies
- EDR with kernel callbacks — detect injection regardless of userland hooks
- Code Integrity Guard — prevent unsigned code from being injected into processes
- Attack Surface Reduction (ASR) — block common injection patterns
- Protected Process Light (PPL) — prevent injection into security-critical processes
- Credential Guard — prevent injection into lsass.exe