Detection Engineering

Detecting Process Injection

How to detect process injection — CreateRemoteThread, RWX memory, and process hollowing signals in Sysmon, a Sigma rule, and the tuning that keeps it high-fidelity.

A cyan-glowing process block on a dark surface pierced by a red tendril, representing code injected into a process
Threat reference

Process injection is how malware hides in plain sight — it runs its code inside a legitimate process to inherit that process’s trust, evade process-based detection, and slip past application allowlists. Because the malicious code lives inside explorer.exe or a browser, you cannot detect it by looking for a bad process. You detect the act of injection: a remote thread created in another process, a handle opened with write-execute access, RWX memory allocated. This guide ships those signals and the Sigma rule that catches them.

Process injection maps to MITRE ATT&CK T1055 — Process Injection and its many sub-techniques (DLL injection, process hollowing, thread hijacking). It is a core defense-evasion step, and it depends on the same Sysmon telemetry as the rest of the Windows detection cluster.

What is process injection?

Process injection places attacker code into the memory of another, legitimate process and executes it there. The malware might allocate memory in a target process, write its payload, and start a thread to run it (classic DLL/shellcode injection); or carve out a legitimate process and replace its image (process hollowing); or hijack an existing thread. In every case the goal is the same: run as a trusted process to evade detection and inherit its privileges and network reputation.

That is why hunting for a malicious executable fails — there isn’t one running as itself. The reliable signals are the Windows API behaviors injection requires, which Sysmon surfaces as discrete events.

What does process injection look like in telemetry?

TechniqueThe injection stepTelemetry signal
Remote-thread injectionCreateRemoteThread into a targetSysmon Event ID 8
Handle-based injectionOpen target with VM_WRITE/VM_OPERATIONSysmon Event ID 10 (access mask)
Shellcode executionAllocate/mark RWX memoryRWX allocation (EDR / EID 8 start address)
Process hollowingUnmap and replace the process imageSysmon Event ID 25 (process tampering)

The unifying signal is one process reaching into another’s memory or threads. A source process that is not a debugger or security tool creating a remote thread in explorer.exe is injection — the discriminator is which source and which target.

How to detect process injection

The core rule flags a remote thread created in another process (Sysmon Event ID 8), allowlisting known-good source processes.

Sigma Remote Thread Created in Another Process (Sysmon Event ID 8)
title: Remote Thread Created in Another Process
id: 6f2c9a41-darkpwn-illustrative
status: experimental
logsource:
  product: windows
  category: create_remote_thread
detection:
  selection:
    TargetImage|endswith: ['\explorer.exe','\svchost.exe','\lsass.exe','\winlogon.exe']
  filter_known:
    SourceImage|endswith: ['\MsMpEng.exe','\CSFalconService.exe']
  condition: selection and not filter_known
falsepositives:
  - Debuggers, security tools, and some installers (allowlist by SourceImage/signer)
level: high

The chained detection in SPL and KQL

SPL Remote Thread Followed by Egress or LSASS Access
index=windows sourcetype=sysmon (EventCode=8 OR EventCode=3 OR EventCode=10)
| eval key = Computer . "|" . TargetProcessGuid
| bin _time span=5m
| stats values(EventCode) AS events, values(SourceImage) AS injectors,
        values(DestinationIp) AS dests, min(_time) AS first by key, Computer, TargetImage
| eval injected      = if(mvcount(mvfilter(match(events,"^8$")))  > 0, 1, 0)
| eval then_egress   = if(mvcount(mvfilter(match(events,"^3$")))  > 0, 1, 0)
| eval then_lsass    = if(mvcount(mvfilter(match(events,"^10$"))) > 0, 1, 0)
| where injected=1 AND (then_egress=1 OR then_lsass=1)
| eval severity = if(then_lsass=1, "critical", "high")
| table first, Computer, TargetImage, injectors, severity, dests
KQL Unbacked-Memory Execution — Injection Without a Remote Thread
DeviceEvents
| where ActionType in ("CreateRemoteThreadApiCall", "ProcessPrimaryTokenModified",
                       "WriteToProcessMemoryApiCall", "ReadProcessMemoryApiCall")
| extend Target = InitiatingProcessFileName, Injector = FileName
| summarize Actions = make_set(ActionType), Count = count()
          by DeviceName, Target, Injector, bin(Timestamp, 5m)
| where array_length(Actions) >= 2      // write + execute, not a single benign API call
| order by Count desc

The Splunk query encodes the point of the callout above: the remote thread is the setup and the follow-on is the confirmation. Correlating on TargetProcessGuid is what makes it reliable — PIDs get recycled, GUIDs do not.

Why Event ID 8 is not enough

Sysmon’s CreateRemoteThread event catches the classic injection pattern and misses several common modern ones, which is worth knowing before you rely on it.

Technique familyCreates a remote thread?What detects it instead
Classic remote threadYes — Event ID 8The rule above
Process hollowingUsually notSysmon Event ID 25 (process tampering); image/memory mismatch
Thread hijackingNo — reuses an existing threadUnbacked memory execution; EDR API telemetry
APC injectionNoQueued APC to an alertable thread; EDR telemetry
DLL injection via loadNo thread creationSysmon Event ID 7 — module loaded from an unusual path
Reflective / manual mappingSometimesUnbacked memory — no file behind the executing region

The unifying signal across the bottom half of that table is execution from memory that is not backed by a file on disk. Legitimate code executes from mapped images; injected code frequently does not. If your EDR exposes that property, it is a stronger primary detection than Event ID 8 because it is a property of the technique class rather than of one API.

This is the same discriminator as the CallTrace UNKNOWN frames used in LSASS credential dumping detection — the call originated from memory with no file behind it. One telemetry property, two detections.

Which T1055 sub-techniques should you actually prioritise?

MITRE tracks twelve sub-techniques under T1055, and treating them as a single detection problem is why coverage claims tend to be optimistic. Three are Linux-only, several are rare enough that a dedicated rule costs more to maintain than it returns, and the ones that carry real-world volume concentrate in a narrow band.

Sub-techniqueIDPlatformDetection anchorPriority
Dynamic-link Library InjectionT1055.001WindowsEID 8, plus EID 7 for a module from an unusual pathHigh
Portable Executable InjectionT1055.002WindowsUnbacked-memory executionHigh
Thread Execution HijackingT1055.003WindowsEID 10 with suspend/resume rights; no EID 8High
Asynchronous Procedure CallT1055.004WindowsEDR API telemetry onlyMedium
Thread Local StorageT1055.005WindowsUnbacked-memory executionLow
Ptrace System CallsT1055.008Linuxauditd rule on the ptrace syscallMedium (Linux)
Proc MemoryT1055.009LinuxWrites to /proc/<pid>/memMedium (Linux)
Extra Window Memory InjectionT1055.011WindowsEDR only; very rareLow
Process HollowingT1055.012WindowsEID 25 (process tampering)High
Process DoppelgängingT1055.013WindowsTransacted file operations; EDRLow
VDSO HijackingT1055.014Linuxptrace plus memory-map anomalyLow (Linux)
ListPlantingT1055.015WindowsEDR onlyLow

Four sub-techniques carry most of the volume you will actually meet: DLL injection, PE injection, thread hijacking, and hollowing. Two Sysmon events and one EDR property cover all four — Event ID 8, Event ID 25, and unbacked-memory execution. That is the whole high-priority programme.

Read the platform column before claiming T1055 coverage in a control review. If your estate runs Linux workloads and your only injection telemetry is Sysmon on Windows, three sub-techniques are structurally invisible and no amount of Sigma tuning changes it. The Linux equivalents are an auditd rule on the ptrace syscall and integrity monitoring on /proc/<pid>/mem — a different pipeline, usually a different owner, and almost always a different backlog.

What does the ProcessAccess mask actually tell you?

Sysmon Event ID 10 records the access rights one process requested when opening a handle to another, in the GrantedAccess field. That hexadecimal value is the most useful discriminator in the entire injection dataset, and most rules throw it away — they alert on the source-target pair and inherit every false positive that opening a handle for any benign reason produces.

Access rightValueWhat it enables
PROCESS_CREATE_THREAD0x0002Start a thread in the target
PROCESS_VM_OPERATION0x0008Allocate memory or change its protection
PROCESS_VM_READ0x0010Read the target’s memory
PROCESS_VM_WRITE0x0020Write the target’s memory
PROCESS_QUERY_INFORMATION0x0400Read process metadata
PROCESS_SUSPEND_RESUME0x0800Suspend and resume threads
PROCESS_QUERY_LIMITED_INFORMATION0x1000Read a metadata subset

Injection has to write. Credential theft only has to read. That one distinction splits Event ID 10 into two very different alerts:

  • Write-capable masks — anything containing 0x0002, 0x0008, or 0x0020. The classic injection triad is 0x002A: create-thread, VM-operation, VM-write combined. This is injection setup.
  • Read-only masks0x1010 and 0x1410 are the well-known LSASS-reading combinations. That is credential dumping, a different playbook with a different containment decision.
  • 0x1FFFFFPROCESS_ALL_ACCESS. Lazy tooling asks for everything, which makes it both a loud signal and a trivial one to catch.

Filtering Event ID 10 on write-capable masks removes a large share of benign volume before it ever reaches a rule, because most legitimate handle opens are queries. It also prevents the common misclassification where an LSASS read is triaged as injection and the responder spends the first hour of an incident hunting for a payload that was never written.

How do you hunt for injection when no rule fired?

Alerting covers the patterns you anticipated. Hunting covers the rest, and injection is a technique class where hunting is unusually productive, because the behaviour is structurally rare in normal operation. Three hypotheses are worth running on a schedule:

  1. Rarest source-target pairs. Aggregate Event ID 8 and write-capable Event ID 10 across the fleet by SourceImageTargetImage, then sort ascending by host count. Your EDR injecting appears on every host; a one-off binary injecting appears on one. Frequency analysis finds the second without knowing in advance what it is.
  2. Signer anomalies on injectors. Any process that injects and is unsigned, signed by a certificate seen on a handful of hosts, or running from a user-writable path is worth reviewing individually. The volume is low enough to review by hand, which is what makes this hypothesis practical rather than aspirational.
  3. Injectors that are themselves unbacked. A process injecting from memory with no file behind it is stage two of an intrusion. This is the highest-signal hunt of the three and returns almost nothing on a clean estate — which is the property you want. A hunt that always returns results is a tuning problem wearing a hunt’s clothing.

Run these against the same telemetry the alerts use. When a hunt repeatedly surfaces the same benign pattern, that is an allowlist input; when it surfaces something new, it becomes a rule. That feedback loop is the detection engineering workflow applied to a single technique.

Which false positives will you actually see?

False positiveWhy it happensResolution
EDR and AV agentsThey inject to hook and inspect processesAllowlist by signer, re-verify after every upgrade
Debuggers and profilersAttaching is their entire functionScope to developer workstations; alert elsewhere
APM and instrumentation agentsAttach to runtimes to traceAllowlist the specific agent path and signer
Accessibility softwareLegitimately injects into UI processesAllowlist by signer
Installers and updatersPatch running processes in placeCorrelate with a software-deployment record
Anti-cheat and DRMInject by designRare in enterprise; allowlist explicitly if present
Legacy IME / input toolsInject into every processInventory and plan removal; they are also a real risk

Re-verify agent allowlists after upgrades. Security vendors change binary paths and add helper processes between versions, and the failure mode is silent in both directions — either a flood of new alerts, or an allowlist entry that matches nothing and quietly stopped suppressing what it was written for.

How do you triage a process-injection alert?

  1. Identify the injector and the target. An unsigned or unusual process injecting into lsass.exe, explorer.exe, or a browser is high severity immediately.
  2. Check whether the injector is backed by a file on disk and whether that file is signed. An injector running from unbacked memory is itself already-injected code — you are seeing stage two, not stage one.
  3. Look at what the target did next. Outbound connections, LSASS access, or a spawned shell confirm the injection was operational rather than incidental.
  4. Trace the injector’s parent chain. This usually reveals the initial access vector — a document handler, a scripting engine, or a service process.
  5. Capture memory before killing anything. Injected code exists only in memory; terminating the process destroys the evidence and you lose attribution.
  6. Isolate the host, then look for persistence established from the injected context.
  7. Rotate credentials that were resident on that host, particularly if lsass.exe was the target.
  8. Hunt for the same injector hash and parent pattern fleet-wide. Injection tooling is reused, so one detection is usually not one host.

Step 5 is the one most often skipped under pressure, and it is the difference between knowing what the intrusion was and only knowing that there was one.

How to test your process-injection detection

In an isolated VM you own:

  1. Use a benign injection test (an Atomic Red Team T1055 test, or a lab tool that injects a harmless payload) and confirm Sysmon Event ID 8/10 fire.
  2. Confirm your allowlisted security tools do not trip the rule.
  3. Run a process-hollowing test and confirm Event ID 25 (process tampering) appears.
  4. Verify the rule survives a renamed injector — it keys on the behavior, not the name.

How to reduce the process-injection attack surface

  • Monitor EDR health — attackers inject after unhooking or disabling it via BYOVD.
  • Collect the right Sysmon events (EID 8, 10, 25) — see Sysmon configuration.
  • Baseline legitimate injectors so the allowlist is accurate.

Which surface-reduction control buys the most?

ControlWhat it removesEffortCaveat
ASR: block Office child processes / injectionThe most common initial-access pathLowAudit mode first; a few macros break
EDR tamper protectionThe unhook-then-inject sequenceLowVendor-dependent completeness
Credential GuardThe payoff of LSASS-targeted injectionMediumUEFI/Secure Boot prerequisites
WDAC / application allowlistingAn injected loader running arbitrary binariesHighReal programme; huge payoff
Microsoft vulnerable-driver blocklistThe BYOVD precursor to kernel-mode injectionVery lowKeep it updated
Removing legacy injecting softwarePersistent noise and real riskVariesOld IME and accessibility tools

Start with the ASR rules in audit mode. Blocking Office applications and script hosts from creating child processes or injecting removes the single most common route to a first injection, and audit mode tells you exactly what would break before anything does.

The last row is worth acting on rather than tuning around. Legacy software that injects into every process is simultaneously your loudest false-positive source and a genuine risk — anything with that capability is a target for hijacking. Removing it improves detection precision and security posture with one change.

Common process-injection detection mistakes

  • Hunting for a bad process. There isn’t one — the code runs inside a good process.
  • No CreateRemoteThread/ProcessAccess telemetry. Without EID 8/10, the act is invisible.
  • No source-target allowlist. The rule pages on debuggers and security tools.
  • Ignoring EDR tampering. Injection often follows the EDR being unhooked.
  • Relying on Event ID 8 alone. Hollowing, thread hijacking, and APC injection create no remote thread and are invisible to it.
  • Correlating on PID instead of ProcessGuid. PIDs are recycled; the chain breaks silently.
  • Killing the process before capturing memory. Injected code exists only in memory.
  • Never re-verifying agent allowlists. Vendor upgrades change paths, and the failure is silent in both directions.

Process injection detection checklist

  1. Collect Sysmon Event IDs 8 (remote thread), 10 (process access), and 25 (tampering).
  2. Alert on remote threads/handles into system and high-value processes.
  3. Allowlist legitimate injectors by SourceImage and code-signing certificate.
  4. Correlate injection with the target’s subsequent network/credential activity.
  5. Enable ASR rules blocking Office/script-host injection and child processes.
  6. Run Credential Guard and WDAC to limit the payoff and the payload.
  7. Monitor EDR health and driver loads (BYOVD precursor).
  8. Test with Atomic Red Team T1055 and a renamed injector.
  9. Collect Sysmon Event IDs 8, 10, and 25 — hollowing is invisible without 25.
  10. Correlate on ProcessGuid, never PID; PIDs are recycled and break the chain silently.
  11. Chain the injection event to what the target does next — egress, LSASS access, or a shell.
  12. Where your EDR exposes it, alert on unbacked-memory execution as a primary signal; it covers the technique families Event ID 8 cannot see.
  13. Allowlist injectors by signer and path, and re-verify after every agent upgrade.
  14. Capture memory before terminating anything — injected code exists nowhere else.
  15. Enable ASR rules blocking Office and script hosts from injecting, in audit mode first.
  16. Inventory and remove legacy software that injects into every process; it is both your noisiest false positive and a real hijacking target.

Items 10 and 12 are the two that most often separate a rule that looks correct from one that works. PID recycling silently breaks correlation on busy hosts, and unbacked-memory execution is the only signal that generalizes across the injection families a single API event misses.

The takeaway

Detecting process injection means watching the act — CreateRemoteThread, write/execute handles, RWX memory, process tampering — from unexpected source processes, allowlisted to your real injectors, and chained to the payoff. You cannot find a bad process; find the injection. Continue with LSASS credential dumping detection and BYOVD detection, or browse the full Detection Engineering pillar.

Training & tools referenced

Disclosure: Some links below are affiliate links. If you buy through them, darkpwn may earn a commission at no extra cost to you. We only recommend training and tools we actually use in our own lab, and affiliate links never influence editorial coverage.

  • TryHackMeAuthorized labs to practice detecting process injection on WindowsSecurity Training
    Start training

Frequently asked questions

How do you detect process injection?

Watch the Windows API behaviors injection needs: a remote thread created in another process (Sysmon Event ID 8, CreateRemoteThread), a process opening another with write/execute access (Event ID 10), allocation of read-write-execute (RWX) memory, and process image/memory tampering (Event ID 25). Alert on these from unexpected source processes, allowlisting legitimate injectors like security tools.

What is process injection?

Process injection is running malicious code inside the address space of a legitimate process to evade defenses and inherit that process's trust and privileges. Techniques include DLL injection, process hollowing, and thread execution hijacking. It maps to MITRE ATT&CK T1055 and its sub-techniques.

Why do attackers use process injection?

Injecting into a trusted process (like explorer.exe or a browser) lets malware hide from process-based detection, bypass application allowlists, and run under the identity and network reputation of the host process. It is a core defense- evasion technique used by most modern malware and C2 frameworks.

Does Sysmon Event ID 8 catch all process injection?

No. CreateRemoteThread catches the classic pattern but misses process hollowing, thread hijacking, APC injection, and DLL injection via a normal module load, none of which create a remote thread. The unifying signal across those techniques is execution from memory that is not backed by a file on disk, which is a stronger primary detection where your EDR exposes it because it is a property of the technique class rather than of one API.

Can EDR stop process injection?

Modern EDR detects many injection techniques via userland hooks and kernel telemetry, but attackers evade with direct/indirect syscalls, BYOVD to unhook the EDR, and novel injection variants. Behavioral detection on the underlying API sequence, plus EDR-health monitoring, remains necessary.