Concepts

Methods

The 4 caller methods that control how the syscall instruction is executed.

Methods

A method controls how the syscall instruction is actually invoked at runtime once the SSN has been resolved by the iterator. Different methods present different artefacts to EDR stack-inspection heuristics.

Comparison table

NameDescriptionReturn addressComplexity
directInline syscall instruction in the stubInside your moduleLowest
indirectJump to ntdll function start; ntdll handles syscallInside ntdllLow
randomJump to a random syscall;ret gadget in ntdllInside ntdll (random)Low
egg_hunter8-byte marker patched before main() runsInside your moduleHighest

Method details

direct

The generated stub contains a literal syscall instruction. The CPU executes the kernel transition directly from within your module's memory.

Pros: Simple; no runtime patching; compatible with all iterators.
Cons: Return address (and call stack) is inside your code — not inside ntdll. Advanced EDR products that inspect the kernel call stack can detect this.

call stub → [your module] syscall → kernel

indirect

Rather than executing syscall inline, the stub jumps to the syscall;ret sequence at the real ntdll stub (past any hook). The return address visible to the kernel therefore appears to be inside ntdll.

Pros: Call stack looks natural — consistent with a legitimate ntdll call.
Cons: The target syscall;ret location must be located; slight overhead.

call stub → jmp &ntdll_syscall_ret → [ntdll] syscall → kernel

random

Like indirect, but instead of jumping to the corresponding ntdll stub, the code jumps to a randomly chosen syscall;ret gadget in ntdll. This further breaks call-stack correlation because the return address will differ on every invocation.

Pros: Defeats EDR heuristics that look for consistent call-origin addresses.
Cons: Slightly slower due to random selection at runtime.

egg_hunter

The most sophisticated method. The generated stub contains an 8-byte egg (marker sequence) instead of a syscall. Before any Nt* call is made, the egg must be replaced with real syscall; nop; nop; ret; nop; int3; int3 bytes by scanning the binary's .text section.

Automatic initialisation: The sanitizer function SPT_SanitizeSyscalls() is registered in the .CRT$XCU CRT init table and runs automatically before main() is called when compiled with MinGW/GCC. No explicit call in application code is required. A manual call to SPT_SanitizeSyscalls() is also available for toolchains that do not honour .CRT$XCU.

Choosing a method

The generate command accepts any iterator/method combination via the custom gate:

sysplant generate -c -p common -o stubs custom -i canterlot -m egg_hunter

When using a named gate (hell, halo, syswhispers, etc.), the default method for that gate is applied automatically. See the Iterators page for the default method of each gate.

Copyright © 2026