Skip to content
λmaldev wiki/
pagesDirect & Indirect Syscalls
T1106Windowsx64ASMC / C++

Direct & Indirect Syscalls

updated 2026-07-086 min readthehackersbrain
Authorized use only. This material is published for detection engineering, malware analysis and authorized red-team engagements. Running these techniques against systems you do not own or have written permission to test is illegal.

Overview

If a hook lives in the ntdll stub, the obvious answer is not to call the stub. A direct syscall loads the service number into EAX and executes syscall from the payload’s own code, skipping userland entirely.

That works against userland hooks and fails against everything else. The kernel still sees the call, ETW-TI still reports it, and the syscall instruction now sits in memory that no legitimate module owns — which is a better signal than the hook it evaded. Indirect syscalls exist to close that gap by jumping into a real syscall instruction inside ntdll, so a stack walk lands somewhere plausible.

Note.

Service numbers change between Windows builds. Hardcoded SSN tables break on patch Tuesday; that fragility is why the “gate” family of techniques derives them at runtime instead.

The call chain

  1. 1
    resolve the syscall number (SSN)
    Read it from a clean ntdll, or derive it by sorting stub addresses (Hell's Gate / Halo's Gate).
  2. 2
    load arguments per the x64 ABI
    RCX moves to R10; the rest follow the standard register and stack layout.
  3. 3
    syscall
    Direct variant executes the instruction from the payload's own memory.
  4. 4
    jmp into ntdll's syscall
    Indirect variant jumps to a real syscall instruction inside ntdll so the return address looks legitimate.

Reference implementation

syscall.asmASM
; direct: the syscall instruction lives in our own memory
NtAllocateVirtualMemory PROC
  mov r10, rcx
  mov eax, 18h            ; SSN, resolved at runtime in real tooling
  syscall
  ret
NtAllocateVirtualMemory ENDP

; indirect: same setup, but the instruction executed belongs to ntdll
NtAllocateVirtualMemoryIndirect PROC
  mov r10, rcx
  mov eax, 18h
  jmp qword ptr [ntdllSyscallGadget]
NtAllocateVirtualMemoryIndirect ENDP

Detection

ETW-TI
Kernel-side telemetry sees the call regardless of what userland did — hooks were never the only sensor.
MEMORY SCAN
A syscall instruction in private, non-image memory; the direct variant's defining artifact.
STACK WALK
Kernel callbacks that unwind the user stack find a return address outside any mapped module.
YARA
The mov r10, rcx / mov eax, imm / syscall triplet is a short but usable signature in staged loaders.

Do not build the detection story on userland hooks. ETW-TI plus a periodic scan for syscall instructions outside mapped images covers both variants; the stack-walk check is what separates indirect syscalls from ordinary API use.

Was this page useful?edit this page ↗