Evasion detection
What this page is
A complete catalog of EDR evasion techniques that the sensor detects and the detection logic for each, including ETW-TI injection events, ETW/AMSI patching, direct syscall detection, kernel callback tampering, handle stripping, and PowerShell obfuscation. Every technique is mapped to MITRE ATT&CK.
Why it exists this way
EDR evasion is a mature adversarial discipline with documented
bypasses for every major commercial sensor. Defending against
evasion requires layered detection: the sensor must monitor the
monitoring infrastructure itself. The evasion detection module
(edr_windows::guard) treats any attempt to interfere with
telemetry collection as a detection event with higher severity
than the underlying behaviour the adversary is trying to hide.
How it works
The evasion detection runs as part of the guard module's integrity check cycle (every 30 seconds) and reactively on ETW-TI events.
ETW-TI injection events
The Microsoft-Windows-Threat-Intelligence provider exposes events that are invisible to user-mode API hooks. Three event types are critical for evasion detection:
-
Event ID 1 (CreateRemoteThread): A thread is created in a remote process. Detected injection techniques: classic DLL injection, reflective DLL injection, process hollowing (resume), and APC injection.
-
Event ID 2 (VirtualAllocEx_Remote): Memory is allocated in a remote process with executable permissions (PAGE_EXECUTE_READWRITE). This is the precursor to Process Hollowing (T1055.012) and Process Doppelganging (T1055.013).
-
Event ID 8 (QueueUserAPC): An APC is queued to a remote thread. This is the delivery mechanism for Early Bird APC injection and Atom Bombing.
The sensor correlates these events with process creation events from Kernel-Process to build an injection timeline: attacker process, target process, injection method, and payload.
ETW patching detection
The most common user-mode evasion technique is patching
EtwEventWrite in ntdll.dll to return 0 without writing the
event. The sensor detects this via:
// Simplified integrity check
fn check_etw_event_write_patched() -> bool {
let ntdll = get_module_base("ntdll.dll");
let etw_addr = resolve_export(ntdll, "EtwEventWrite");
let first_bytes = read_memory(etw_addr, 8);
// Clean ntdll: mov [rsp+8], rbx; push rdi; sub rsp, 0x30
// Patched: xor eax, eax; ret (three variants tracked)
matches!(first_bytes, PATCHED_SIGNATURE_1 | PATCHED_SIGNATURE_2 | PATCHED_SIGNATURE_3)
}
The sensor compares the in-memory bytes of EtwEventWrite and
EtwEventWriteFull against known clean signatures from the on-disk
ntdll.dll. If a patch signature is detected, the sensor:
- Logs a critical evasion alert with the patched function address and the first 16 bytes of the patch.
- Attempts to restore the clean bytes from the known-good on-disk
copy via
WriteProcessMemoryon the patching process. - If restoration fails (patch re-applied within 30 seconds), triggers fail-deadly WFP isolation.
AMSI patching detection
AMSI bypasses typically patch AmsiScanBuffer in amsi.dll to
always return AMSI_RESULT_CLEAN. The sensor's AMSI integrity
check reads the in-memory code section of amsi.dll and compares
its SHA-256 hash against the on-disk file. Mismatch triggers the
same escalation path as ETW patching.
Additionally, the sensor monitors for COM hijacking of the
IAntimalwareProvider interface via the registry key
HKCR\CLSID\{...}\InProcServer32. If the registered DLL path
does not point to the AuroraEDR AMSI provider, the sensor logs
the hijack attempt with the replacing DLL path and its digital
signature status.
Direct syscall detection
Adversaries bypass user-mode hooks (EtwEventWrite, NtCreateThread) by invoking the syscall instruction directly with manually-crafted arguments. The sensor detects direct syscalls via two mechanisms:
-
ETW-TI Event ID 12 (SyscallStub): The Threat-Intelligence provider fires when a syscall is executed from a non-standard module (not
ntdll.dllorwin32u.dll). This catches inline syscalls and syscall stubs from manually-mapped DLLs. -
Call stack analysis: When the minifilter driver's pre-operation callback fires for
IRP_MJ_CREATE, the driver walks the call stack viaRtlWalkFrameChain. If the call originates fromntdll.dll!NtCreateFilebut the return address in the caller's stack frame does not lie within a legitimate image, the driver reports a direct syscall detection.
Kernel callback tampering
The sensor queries callback health via IOCTL_QUERY_CALLBACK_HEALTH
every 30 seconds. If any of the four kernel callbacks return
NotRegistered, this indicates one of two attack vectors:
-
Callback removal: A kernel-mode driver unregistered the EDR callback. This requires a signed driver and is detectable by correlating with the driver load timeline from the Services ETW provider.
-
Callback hijack: A kernel-mode driver installed a new callback at a higher altitude that returns early before the EDR callback executes. The sensor detects this by comparing
PsGetProcessCreateNotifyRoutinecount before and after the sensor's callback registration.
Handle stripping detection
Adversaries strip the PROCESS_VM_READ right from EDR process
handles via NtSetInformationProcess(ProcessHandleInformation).
The sensor's ObRegisterCallbacks pre-operation callback
intercepts handle duplication and creation requests targeting the
EDR user-mode process. If a handle is opened with
OBJ_KERNEL_HANDLE or OBJ_FORCE_ACCESS_CHECK flags (indicating
kernel-mode origin or privileged access), the driver:
- Logs the requesting process ID and access mask.
- Strips
PROCESS_VM_READ,PROCESS_QUERY_INFORMATION, andPROCESS_DUP_HANDLEfrom the granted access. - Returns the modified handle with
STATUS_SUCCESSso the adversary's code does not detect the stripping.
PowerShell obfuscation
PowerShell attacks use obfuscation to evade signature-based detection. The sensor consumes PowerShell ETW events:
-
Event ID 4104 (ScriptBlock logging): Captures the de-obfuscated script block text after PowerShell's own parser has resolved escape sequences, string concatenation, and re-ordering tricks. The sensor ships this text to the Collector for analysis.
-
Event ID 4103 (Module logging): Captures the full pipeline execution details including command invocations, parameter values, and output types. This catches invocation-obfuscation techniques like
&("i"+"e"+"x")and re-assigned aliases.
The sensor also checks for System.Management.Automation.dll
being loaded from a non-standard path (common in reflection-load
bypasses) by monitoring ETW-TI Event ID 3 (LoadLibrary).
MITRE ATT&CK evasion coverage
| ATT&CK ID | Technique | Detection mechanism | Covered |
|---|---|---|---|
| T1055.001 | DLL injection | ETW-TI id=1 (CreateRemoteThread) | Yes |
| T1055.002 | Portable Executable injection | ETW-TI id=2 (VirtualAllocEx_Remote) + id=1 | Yes |
| T1055.012 | Process hollowing | ETW-TI id=2 + id=12 (syscall stub) | Yes |
| T1055.013 | Process doppelganging | Minifilter IRP_MJ_CREATE + TI id=2 | Yes |
| T1562.001 | Disable or modify tools | ETW/AMSI integrity checks | Yes |
| T1562.002 | Disable Windows Event Logging | EventLog ETW provider + guard poll | Yes |
| T1562.003 | Impair command history logging | PowerShell 4104 integrity check | Yes |
| T1562.006 | Indicator blocking | Callback health IOCTL poll | Yes |
| T1564.001 | Hidden files and directories | Minifilter IRP_MJ_CREATE (FILE_ATTRIBUTE_HIDDEN) | Yes |
| T1564.003 | Hidden window | Kernel-Process id=1 (STARTF_USESHOWWINDOW) | Yes |
| T1574.001 | DLL search order hijacking | ETW-TI id=3 (LoadLibrary) + path check | Yes |
| T1574.002 | DLL side-loading | ETW-TI id=3 + digital signature check | Yes |
| T1059.001 | PowerShell obfuscation | ScriptBlock 4104 + Module 4103 logging | Yes |
| T1027.005 | Multi-stage obfuscation | PowerShell 4103 pipeline trace | Yes |
| T1036.005 | Match legitimate name or location | Kernel-File id=30 + path comparison | Yes |
| T1106 | Native API (direct syscalls) | ETW-TI id=12 + call stack analysis | Yes |
| T1134.001 | Token impersonation/theft | ETW-TI id=6 (TokenAdjust) | Yes |
| T1134.002 | Process injection via APC | ETW-TI id=8 (QueueUserAPC) | Yes |
| T1055.004 | Thread execution hijacking | ETW-TI id=1 + call stack anomaly | Yes |
| T1556.002 | Password filter DLL | ETW-TI id=3 (LoadLibrary in LSASS) | Yes |
| T1562.004 | Disable system firewalls | WFP filter state poll (guard module) | Yes |
| T1547.001 | Registry run keys | CmRegisterCallback (kernel driver) | Yes |
| T1547.009 | Shortcut modification | Kernel-File id=30 (*.lnk in Startup) | Yes |
What goes wrong
- ETW-TI provider is not available (Windows 10 <1809 or Server
2016). Injection detection relies on Kernel-Process events only,
which do not capture remote thread creation with the same
granularity. The sensor logs a
PartialInjectionCoveragewarning. EtwEventWritepatch detection produces a false positive when a legitimate hooked version (e.g., from AppVerifier or Application Verifier) is present. The sensor checks the digital signature of the hooking module and whitelists Microsoft-signed hooks.- Call stack analysis fails for 32-bit processes on 64-bit systems
(WoW64). The minifilter driver only walks the 64-bit stack and
reports
PartialCallStackfor WoW64 processes. - PowerShell obfuscation detection relies on ScriptBlock logging
being enabled (default since PowerShell 5.0). If an adversary
downgrades to PowerShell 2.0 via
-Version 2, neither 4104 nor 4103 events fire. The sensor detects this by monitoring forpowershell.exe -Version 2in process command lines.