Process injection (T1055) is the act of running arbitrary code within the virtual address space of a separate, live process. Attackers use it to: masquerade as a trusted process (lsass.exe, explorer.exe, svchost.exe), evade application allowlisting by running under a signed binary, avoid EDR termination of a freshly-spawned malicious process, and inherit target process privileges or access tokens.
It is present in virtually every major post-exploitation framework — Cobalt Strike, Sliver, Brute Ratel, Metasploit — and in bespoke malware from ransomware pre-deployment tooling to nation-state implants.
The challenge for defenders is that the underlying Windows APIs (WriteProcessMemory, CreateRemoteThread, VirtualAllocEx) are legitimate. Security software, AV, and game anti-cheat tools all call the same APIs. High-fidelity detection requires combining API telemetry with process relationship context, memory characteristics, and timing signals.
Detection Surface Overview
Windows provides several telemetry sources relevant to process injection:
- ETW (Event Tracing for Windows): Kernel-level telemetry for memory allocation (
VirtualAlloc), remote thread creation, and cross-process memory writes. This is the most reliable source and the one EDRs primarily use. - Sysmon Event IDs: Event ID 8 (CreateRemoteThread), Event ID 10 (ProcessAccess), Event ID 25 (ProcessTampering).
- Windows Security Events: Event 4656/4663 (object access), though these generate high volume and require filtering.
- EDR memory scanning: Runtime detection of injected shellcode by scanning memory regions marked
MEM_PRIVATEwithPAGE_EXECUTE_READWRITEpermissions.
Technique 1: CreateRemoteThread Injection
The classic injection pattern:
OpenProcess→ obtain handle to target processVirtualAllocEx→ allocate RWX memory in target’s address spaceWriteProcessMemory→ write shellcode/DLL path to allocated memoryCreateRemoteThread→ create thread in target process pointing to allocated memory
Sysmon Event ID 8 fires when a remote thread is created. The following Sigma rule detects process injection attempts where the source process creates a thread in a high-value target:
title: Suspicious Remote Thread Creation in High-Value Process
id: a5e6d8f2-1234-4b56-9abc-def012345678
status: test
description: Detects CreateRemoteThread calls targeting processes commonly used as injection hosts
author: SOC Analyst Hub
date: 2026-06-24
references:
- https://attack.mitre.org/techniques/T1055/003/
logsource:
product: windows
category: create_remote_thread
detection:
selection:
TargetImage|endswith:
- '\lsass.exe'
- '\explorer.exe'
- '\svchost.exe'
- '\winlogon.exe'
- '\services.exe'
- '\spoolsv.exe'
- '\taskhost.exe'
- '\dwm.exe'
filter_legit:
SourceImage|endswith:
- '\System32\csrss.exe'
- '\System32\wininit.exe'
condition: selection and not filter_legit
falsepositives:
- Security products and legitimate debuggers
- Accessibility tools (magnifier, screen reader)
level: high
tags:
- attack.defense_evasion
- attack.t1055.003
KQL (Microsoft Sentinel / Defender for Endpoint):
DeviceEvents
| where ActionType == "CreateRemoteThreadApiCall"
| where TargetProcessName in~ (
"lsass.exe", "explorer.exe", "svchost.exe",
"winlogon.exe", "services.exe", "spoolsv.exe")
| where not (InitiatingProcessFolderPath has_any (
"\\Windows\\System32\\", "\\Windows\\SysWOW64\\"))
| where not InitiatingProcessFileName in~ (
"csrss.exe", "wininit.exe", "MsMpEng.exe", "SentinelAgent.exe")
| project Timestamp, DeviceName, InitiatingProcessFolderPath,
InitiatingProcessFileName, TargetProcessName,
InitiatingProcessCommandLine
| sort by Timestamp desc
Technique 2: VirtualAllocEx + WriteProcessMemory Pattern
Even without catching the CreateRemoteThread event, the sequence of OpenProcess with PROCESS_VM_WRITE + PROCESS_VM_OPERATION + PROCESS_CREATE_THREAD rights, followed by memory allocation and write, is itself suspicious when the source is an unexpected process.
Sysmon Event ID 10 (ProcessAccess) fires on cross-process handle acquisition. The access rights bitmask 0x1fffff (PROCESS_ALL_ACCESS) and 0x143a (common injection-specific combination) are documented indicators.
title: Cross-Process Memory Write Access with Injection Rights
id: b7f3e9a1-5678-4c78-bdef-901234567890
status: experimental
description: Detects process handle acquisition with memory write and thread creation rights, common in classic DLL/shellcode injection
author: SOC Analyst Hub
date: 2026-06-24
logsource:
product: windows
category: process_access
detection:
selection:
EventID: 10
GrantedAccess|contains:
- '0x1fffff'
- '0x143a'
- '0x40'
injection_targets:
TargetImage|endswith:
- '\svchost.exe'
- '\explorer.exe'
- '\lsass.exe'
- '\notepad.exe'
- '\mspaint.exe'
- '\calc.exe'
filter_av:
SourceImage|endswith:
- '\MsMpEng.exe'
- '\SentinelAgent.exe'
- '\CrowdStrike\CSFalconService.exe'
condition: selection and injection_targets and not filter_av
falsepositives:
- Security tooling and debuggers
- Process monitor / Sysinternals utilities
level: medium
tags:
- attack.t1055
Technique 3: QueueUserAPC Injection
QueueUserAPC (T1055.004) queues an asynchronous procedure call to a thread in the target process. Unlike CreateRemoteThread, it reuses existing threads and can be harder to detect through thread creation events alone.
The attacker’s flow: allocate + write to target via standard VirtualAllocEx/WriteProcessMemory, then enumerate threads of the target process and call QueueUserAPC to schedule execution when the thread enters an alertable wait state.
Detection focuses on the process access pattern followed by VirtualAllocEx activity without a corresponding CreateRemoteThread event:
// Defender for Endpoint: QueueUserAPC pattern
// Look for injection-capable handle followed by thread enumeration
let suspicious_access = DeviceEvents
| where ActionType == "OpenProcessApiCall"
| where AdditionalFields has_any ("0x1fffff", "PROCESS_ALL_ACCESS")
| where not (InitiatingProcessFolderPath has "\\Windows\\System32")
| project InitiatingProcessId, InitiatingProcessFileName,
TargetProcessId, Timestamp, DeviceId;
let subsequent_alloc = DeviceEvents
| where ActionType in ("VirtualAllocRemoteApiCall", "WriteToLsassProcess")
| project InitiatingProcessId, TargetProcessId, Timestamp as AllocTime, DeviceId;
suspicious_access
| join kind=inner subsequent_alloc on $left.InitiatingProcessId == $right.InitiatingProcessId
| where AllocTime between (Timestamp .. (Timestamp + 10s))
| project DeviceId, InitiatingProcessFileName, TargetProcessId, Timestamp
Technique 4: Reflective DLL Injection
Reflective DLL injection (T1055.001) loads a DLL into a process directly from memory, bypassing the Windows loader and leaving no record in the process module list. It is Cobalt Strike Beacon’s default injection method and is used extensively in offensive tooling.
Memory-based detection focuses on:
- Executable memory regions (
PAGE_EXECUTE_READWRITE/MEM_PRIVATE) in processes that should not have them - MZ/PE headers in memory regions not backed by a file on disk
- Threads with start addresses in anonymous memory regions (no associated module)
title: Thread Starting in Non-Backed Executable Memory Region
id: c8e4f1b2-9012-4d89-0123-456789abcdef
status: experimental
description: Detects threads whose start address falls in a memory region with no backing file on disk — consistent with reflective DLL injection or shellcode execution
author: SOC Analyst Hub
date: 2026-06-24
logsource:
product: windows
category: create_remote_thread
detection:
selection:
EventID: 8
filter_module_backed:
# If the StartModule field is empty or null, the thread starts in unbacked memory
StartModule: null
filter_legit_procs:
SourceImage|endswith:
- '\conhost.exe'
- '\csrss.exe'
condition: selection and filter_module_backed and not filter_legit_procs
falsepositives:
- JIT compilers (.NET CLR, V8) creating threads in dynamically-compiled code regions
- Some legitimate AV hooks
level: high
tags:
- attack.t1055.001
- attack.defense_evasion
Technique 5: Shellcode Injection via Syscalls (Indirect / Direct)
Modern offensive tooling increasingly bypasses user-mode API hooks by using direct or indirect syscalls, calling into ntdll.dll stubs that transition directly to kernel mode, or by locating syscall numbers dynamically and using inline assembly. This bypasses userland EDR hooks on NtAllocateVirtualMemory, NtWriteVirtualMemory, and NtCreateThreadEx.
Detection shifts from API call telemetry to:
- ETW kernel-mode events that fire regardless of how the syscall was invoked
- Process memory scanning for shellcode patterns (e.g. detection of PE headers in
MEM_PRIVATEexecutable regions) - Behavioral: process spawning patterns, unusual child processes, C2 network beaconing after injection
// Defender: detect processes with executable private memory and no module backing
// This surfaces reflective injection and shellcode regardless of injection API used
DeviceProcessEvents
| where ProcessCreationTime > ago(1d)
| where FileName in~ ("svchost.exe", "explorer.exe", "rundll32.exe", "msiexec.exe")
// Join with network events shortly after process creation — C2 beaconing pattern
| join kind=inner (
DeviceNetworkEvents
| where RemotePort in (80, 443, 8080, 8443)
| where not (RemoteUrl has_any ("windows.com", "microsoft.com", "windowsupdate.com"))
) on $left.DeviceId == $right.DeviceId, $left.ProcessId == $right.InitiatingProcessId
| summarize count() by DeviceName, InitiatingProcessFileName, RemoteIP, RemoteUrl
| where count_ > 5
| sort by count_ desc
Detection Engineering Notes
False positive management: The APIs used for process injection are called by legitimate software constantly. Effective detection requires:
- Process allowlisting for known-good callers (AV, EDR, debuggers)
- Context enrichment (is the source process a freshly-created, unsigned binary? Did it come from a temp directory or browser download folder?)
- Chaining events (handle acquisition → memory allocation → thread creation or network connection) rather than alerting on single events
Tuning approach: Start with the specific target processes most valuable as injection hosts (lsass.exe for credential access, svchost.exe for persistence) and expand to broader sets as you measure false positive rates.
EDR dependency: High-fidelity detection of modern injection techniques (direct syscalls, HWBP-based evasion) is only achievable with kernel-level telemetry from an EDR. Sysmon alone will miss direct syscall variants. If your environment relies solely on Windows Event Logs + Sysmon, prioritise detection of injection outcomes (anomalous C2 from host processes, credential access from unexpected processes) over the injection event itself.