Syscall Methods & SSN Resolvers

← maldev README · docs/index

The win/syscall package composes three orthogonal concerns behind a single *Caller. Operators tune each axis independently; downstream packages (inject/*, evasion/*, c2/shell) accept a *Caller and inherit the chosen posture without recompiling.

Three concerns (read this first)

flowchart LR
    subgraph callsite [Call site<br>e.g. inject.RemoteThread]
        C["*wsyscall.Caller"]
    end
    subgraph axis1 [1. Calling method<br>HOW the syscall fires]
        A1["MethodWinAPI / NativeAPI / Direct /<br>Indirect / IndirectAsm"]
    end
    subgraph axis2 [2. SSN resolver<br>WHERE the syscall number comes from]
        A2["HellsGate / HalosGate / Tartarus /<br>HashGate / Chain"]
    end
    subgraph axis3 [3. API hashing<br>HOW the symbol is found without a string]
        A3["ROR13 / FNV / Jenkins / custom HashFunc"]
    end
    C --> A1
    C --> A2
    A2 --> A3

The three axes answer different questions:

AxisQuestion it answersPages
1 — Calling methodHow does the implant issue the syscall once the SSN is known? Which userland boundary do we cross / skip?direct-indirect.md
2 — SSN resolverWhere does the SSN come from? What happens when the canonical source (the unhooked ntdll prologue) is unavailable?ssn-resolvers.md
3 — API hashingHow do we identify the right Nt* export without a plaintext name in the binary?api-hashing.md

Tuning one axis does NOT imply tuning the others. You can:

  • pick MethodIndirect (axis 1) with HellsGate (axis 2) — no api-hashing.
  • pick MethodWinAPI (axis 1) with HashGate (axis 2 — uses axis 3 internally).
  • swap the hash function on HashGate (axis 3) without touching axis 1 / 2.

Architecture Overview

graph TD
    subgraph "Consumer Packages"
        INJ[inject/]
        EVA[evasion/]
        C2[c2/shell]
    end

    subgraph "win/syscall"
        CALLER["*Caller"]
        CALLER -->|method| WINAPI[MethodWinAPI]
        CALLER -->|method| NATIVE[MethodNativeAPI]
        CALLER -->|method| DIRECT[MethodDirect]
        CALLER -->|method| INDIRECT[MethodIndirect]

        CALLER -->|resolver| HG[HellsGate]
        CALLER -->|resolver| HAG[HalosGate]
        CALLER -->|resolver| TG[TartarusGate]
        CALLER -->|resolver| HGR[HashGate]
        CALLER -->|resolver| CH[Chain]
    end

    subgraph "win/api"
        PEB["PEB Walk"]
        HASH["API Hashing"]
        RESOLVE["ResolveByHash"]
    end

    INJ -->|"*Caller (nil = WinAPI)"| CALLER
    EVA -->|"*Caller (nil = WinAPI)"| CALLER
    C2 -->|"*Caller (nil = WinAPI)"| CALLER
    HGR --> PEB
    HGR --> HASH
    RESOLVE --> PEB
    RESOLVE --> HASH

Quick Reference

MethodHook BypassStack CleanMemory CleanStealth
WinAPINoneN/AN/ALowest
NativeAPIkernel32N/AN/ALow
DirectAll userlandNoNoMedium
IndirectAll userlandYesYesHigh (heap stub, RW↔RX cycle)
IndirectAsmAll userlandYesYesHighest (Go-asm stub, no writable code)
ResolverUnhooked ntdllJMP-hooked ntdllFully hooked ntdllString-free
HellsGateYesNoNoNo
HalosGateYesYes (neighbor)NoNo
TartarusGateYesYes (trampoline)Yes (neighbor fallback)No
HashGateYesNoNoYes
ChainDepends on compositionDepends on compositionDepends on compositionDepends

Quick decision tree

You want to…Use
…call a Windows API with no plaintext name in the binaryapi-hashing.md (HashGate)
…skip kernel32-level hooks but stay in ntdlldirect-indirect.mdMethodNativeAPI
…skip every userland hook (kernel32 + ntdll)direct-indirect.mdMethodIndirect / MethodIndirectAsm
…make the syscall return inside ntdll's .text (call-stack stealth)direct-indirect.mdMethodIndirect family
…avoid any writable code page in the implantdirect-indirect.mdMethodIndirectAsm
…randomise the syscall return address per calldirect-indirect.md — gadget pool
…auto-fall-back when the target stub is hookedssn-resolvers.md — Halo's / Tartarus / Chain
…read the SSN even when the entire ntdll text section is hookedssn-resolvers.md — TartarusGate
…swap in your own hash function (defeat ROR13 fingerprints)NewHashGateWith(fn) + Caller.WithHashFunc(fn)

Documentation

DocumentDescription
Direct & Indirect SyscallsThe five invocation methods (incl. Go-asm IndirectAsm) and when to use each
API HashingPEB walk + ROR13 hashing to eliminate plaintext strings
SSN ResolversHell's Gate, Halo's Gate, Tartarus Gate, HashGate

MITRE ATT&CK

TechniqueIDDescription
Native APIT1106Directly interact with the native OS API

D3FEND Countermeasures

CountermeasureIDDescription
System Call AnalysisD3-SCAMonitor syscall origins and patterns
Function Call RestrictionD3-FCRRestrict dynamic function resolution

See also