Syscall Generation
Syscall Generation
On Windows, calling APIs through the import table leaves a fingerprint that EDRs can flag. PayloadFactory replaces them with direct syscalls generated by the SysPlant library (a declared dependency in pyproject.toml), using one of several recovery strategies. This is Windows-only — Linux targets use native libc syscalls and skip this step entirely.
Control it with two flags:
python main.py thread_hijack -s sc.bin --syscall sysplant -r jumper_randomized
--syscall
Defines how syscalls are resolved at runtime:
| Value | Behaviour |
|---|---|
stubs | (default) Use the bundled GetSyscallStub helpers in libs/. |
sysplant | Generate syscall resolution code via SysPlant. |
plain | Call the syscalls directly (no indirection). |
-r/--recovery
SysPlant recovery strategy — how the stub recovers the syscall number and ntdll base at runtime. Mapped to SysPlant iterators in ExecutableFactory:
| Recovery flag | SysPlant iterator | Meaning |
|---|---|---|
embedded | hell | Number is embedded directly in the stub. |
jumper | tartarus | A single indirect "jumper" resolves it. |
jumper_randomized | canterlot | (default) Randomized jumper chain. |
egg_hunter | freshy | Egg-hunter scan to locate the stub. |
Randomizing syscall names
By default, syscall names in the stub (e.g. NtAllocateVirtualMemory) are randomized to reduce string-based detection. Disable this with -nr/--no-random:
python main.py thread_hijack -s sc.bin --syscall sysplant -nr
When randomization is on and --syscall sysplant is used, the random names are applied consistently to both the C++ stub and the generated libs/syscalls.h header.