Methods

Indirect

How the indirect syscall method works in Sysplant — jumping to the ntdll stub, executing the syscall from inside ntdll.

Indirect Method


Principle

The indirect method does not contain a syscall instruction in your binary. Instead, it resolves the address of the original ntdll stub for the requested function and jumps directly to it. The syscall instruction that eventually executes resides inside ntdll's memory range.

The motivation is that EDR products watching the kernel's syscall handler can compare the return address of the syscall with the expected ntdll address. With indirect, the return address points inside ntdll — because that is where the syscall instruction is.


Generated stub (x64, from source)

SPT_Syscall:
    pop  rax              ; discard return address
    pop  r15              ; load function hash
    mov  [rsp+ 8], rcx    ; save arg1
    mov  [rsp+16], rdx    ; save arg2
    mov  [rsp+24], r8     ; save arg3
    mov  [rsp+32], r9     ; save arg4
    sub  rsp, 0x28        ; shadow space
    mov  rcx, r15         ; function hash → argument for SPT_GetSyscallAddress
    call SPT_GetSyscallAddress   ; returns Entries[i].Address (ntdll function start)
    mov  r15, rax         ; store ntdll address
    add  rsp, 0x28        ; restore stack
    mov  rcx, [rsp+ 8]    ; restore arg1
    mov  rdx, [rsp+16]    ; restore arg2
    mov  r8,  [rsp+24]    ; restore arg3
    mov  r9,  [rsp+32]    ; restore arg4
    jmp  r15              ; jump to ntdll function start (NO inline syscall)

What SPT_GetSyscallAddress returns

SPT_GetSyscallAddress (from resolvers/basic.c) returns Entries[i].Address, which is the start address of the ntdll function identified by the given hash.

This is not the syscall opcode's address — it is the beginning of the ntdll stub, which typically starts with MOV R10, RCX / MOV EAX, <SSN>. The kernel sets EAX from the ntdll stub's MOV EAX, <SSN> instruction.

When the jump lands there, the standard ntdll stub executes: it moves the SSN into EAX and then executes syscall. The syscall return address is inside ntdll.


Important: hook behaviour

If the ntdll function is hooked (patched with a JMP at its entry), the jump in the indirect stub lands on the hook, not on the real syscall stub. The iterator is responsible for having verified the address at list-population time, but the .Address field always holds the raw export address — which could be the hooked location.

This means indirect trades return-address detection resistance for potential vulnerability to in-process hooks landing at the entry point. Pair it with iterators that do not depend on the unhooked stub content (FreshyCalls, SysWhispers) rather than opcode-scanning iterators (Hell, Halo, Tartarus).


Characteristics

PropertyValue
Inline syscall in binaryNo
SSN resolved explicitly in stubNo — ntdll's own MOV EAX, <SSN> handles it
Return address during syscallInside ntdll
Call-stack originYour module
Sensitive to in-process entry-point hooksYes

Default iterator

indirect is the default method for the syswhispers iterator.

Copyright © 2026