For researchers (R&D)
You want to understand. This page walks the architecture, the design patterns that make every package compose, and the references behind each technique.
TL;DR
The library is built around one composable abstraction: every
syscall-issuing package accepts an optional
*wsyscall.Caller. The caller
encapsulates the calling method (WinAPI / NativeAPI / Direct / Indirect)
and the SSN-resolution strategy (chain of gates: HellsGate → HalosGate →
Tartarus → HashGate). This is the maldev "Caller pattern" — read it
first.
Architecture
flowchart TD
L0["Layer 0 (pure Go)<br>crypto · encode · hash · random · useragent"]
L1["Layer 1 (OS primitives)<br>win/api · win/syscall · win/ntapi · win/token · win/privilege<br>process/enum · process/session · kernel/driver"]
L2T["Layer 2 (techniques)<br>evasion/* · recon/* · inject · pe/* · runtime/*<br>cleanup/* · process/tamper/* · privesc/*"]
L2P["Layer 2 (post-ex)<br>persistence/* · collection/* · credentials/*"]
L3["Layer 3 (orchestration)<br>c2/transport · c2/shell · c2/meterpreter · c2/cert"]
L0 --> L1
L1 --> L2T
L1 --> L2P
L2T --> L3
L2P --> L3
Detailed dependency rules and the complete package matrix: architecture.md.
The Caller pattern
Every package that issues syscalls follows this signature:
func DoThing(args ..., caller *wsyscall.Caller) (..., error)
A nil caller falls back to WinAPI (the standard CRT path — easy
debugging, noisy in production). A non-nil caller routes the call through
the chosen method:
sequenceDiagram
participant Pkg as "package (e.g. amsi)"
participant Caller as "*wsyscall.Caller"
participant Resolver as "SSN Gate Chain"
participant NT as "ntdll syscall stub"
Pkg->>Caller: NtProtectVirtualMemory(...)
Caller->>Resolver: resolve("NtProtectVirtualMemory")
Resolver-->>Caller: SSN 0x50
Caller->>NT: indirect call (rcx, rdx, r8, r9, [rsp+0x28])
NT-->>Caller: NTSTATUS
Caller-->>Pkg: error or nil
Why this design?
- Uniform OPSEC tuning — change one variable, all dependent packages inherit the new stealth level. No per-call configuration sprawl.
- Resolver fall-back chain — if
HellsGatefails (ntdll hooked),HalosGatewalks down to find a clean stub. Each package gets the chain "for free". - Testability — the WinAPI fall-back lets unit tests run on any
Windows host without elevation, while integration tests in VMs run
with
MethodIndirectto validate the stealth path.
See: win/syscall/doc.go and the
direct-indirect /
ssn-resolvers pages.
Cross-version Windows behavior
Some techniques fail on newer Windows builds. Tracked deltas:
| Technique | Win10 22H2 | Win11 24H2 (build 26100) | Notes |
|---|---|---|---|
process/tamper/herpaderping.ModeRun | ✅ | ❌ | Win11 image-load notify hardening — use ModeGhosting |
cleanup/selfdelete.DeleteFile | ✅ | ⚠️ | MoveFileEx(MOVEFILE_DELAY_UNTIL_REBOOT) rename-on-reboot semantics changed |
process/tamper/fakecmd.SpoofPID | ✅ | ❌ | PROC_THREAD_ATTRIBUTE_PARENT_PROCESS tightened |
inject.CallerMatrix_RemoteInject (some methods + Direct/Indirect) | ✅ | ⚠️ | Cross-process write + thread-create primitives |
evasion/hook test EXE | (Defender flagged) | (Defender flagged) | Defender def-update — exclusions in bootstrap-windows-guest.ps1 |
Source of truth: the ## Win10 → Win11 cross-version deltas table in
testing.md.
Reading order — by complexity
- Pure Go: crypto,
encode, hash — read
*_test.gofirst; the algorithms speak for themselves. - OS-primitives: win/syscall — start here, the Caller pattern radiates out.
- Detection-evasion mechanics: evasion/amsi, evasion/etw, evasion/unhook. Concrete byte-pattern verification, easy to validate in x64dbg.
- Sleep masking:
sleepmask — the
EkkoROP chain is a small masterpiece; the Go bindings preserve the semantics. - Injection: inject. 15+
methods — read the
CallerMatrixtest in testing.md for the feature × stealth grid. - In-process runtime: runtime/bof,
runtime/clr. BOF/COFF parsing in
pure Go; CLR hosting via
ICorRuntimeHost(legacy v2 activation). - Kernel BYOVD:
kernel/driver/rtcore64. Layer-1
primitives (Reader / ReadWriter / Lifecycle); CVE-2019-16098 IOCTL
scaffold; consumed by
evasion/kcallback.Removeandcredentials/lsassdump.Unprotect.
VM testing
Reproducible test harness: coverage-workflow.md.
# One-time: bootstrap VMs from scratch
bash scripts/vm-provision.sh
# Each session: full coverage with all gates open, merged report
bash scripts/full-coverage.sh --snapshot=TOOLS
The harness orchestrates Windows + Linux + Kali VMs; gating env vars
(MALDEV_INTRUSIVE, MALDEV_MANUAL) unlock destructive tests safely.
How to extend
Adding a new injection method
- Add a
Method<Name>constant toinject/method.go. - Implement
case MethodXxx:inWindowsInjector.Inject. The*wsyscall.Calleris already wired — call through it for any syscall. - Add the method to the CallerMatrix test.
- Update docs/techniques/injection/ per the doc-conventions template.
- Tag the MITRE ID in the new package's
doc.go;cmd/docgenrolls it into mitre.md.
Adding a new evasion technique
Same shape: package under evasion/<name>, exposes a function returning
an evasion.Technique so it composes via evasion.ApplyAll.
References
- Caller pattern: Hells/Halos Gate paper · Tartarus Gate
- AMSI bypass: Rasta Mouse — AmsiScanBuffer patch
- ETW patch: modexp — Disabling ETW
- Sleep mask (Ekko): Cracked5pider/Ekko
- Herpaderping / Ghosting: jxy-s/herpaderping · hasherezade — process ghosting
- Donut PE-to-shellcode: TheWover/donut
- Phantom DLL hollowing: forrest-orr/phantom-dll-hollower-poc
- BOF spec: Cobalt Strike BOF documentation
Per-technique pages cite their own primary sources — these are the spine references for the architecture.
Where to next
- Operator path — if you want the practical chain, not the theory.
- Detection engineering path — read the same techniques from the artifacts left behind angle.
- Architecture — full layer-by-layer dependency map.
- Testing — evidence the techniques actually work cross-version.