Integrating Sysplant
Integrating Sysplant into an existing project
This guide walks through the complete workflow: discovering which native functions your project uses, generating the stubs, and including the output in your build.
Workflow overview
1. sysplant list ./src → discover Nt* / Zw* functions in your code
2. sysplant generate … -f … → generate a single stub file
3. #include "syscalls.h" → add one include, remove old imports
4. Rebuild → no other changes required
Step 1 — Discover functions in use
Run sysplant list against your project's source directory. It scans .h, .hpp, .c, .cpp, .nim, and .rs files for Nt* and Zw* function names.
sysplant list ./src
Example output:
NtOpenProcess
NtWriteVirtualMemory
NtCreateThreadEx
NtAllocateVirtualMemory
NtProtectVirtualMemory
Copy this list to use with the -f flag in the next step.
Step 2 — Generate the stub file
Choose a gate (iterator) and produce the stub file for your language.
Recommended starting point: canterlot with default (random) method — the most EDR-resilient built-in combination.
C / C++
# C header — recommended gate
sysplant generate -c -o ./src/syscalls canterlot \
-f NtOpenProcess,NtWriteVirtualMemory,NtCreateThreadEx,NtAllocateVirtualMemory,NtProtectVirtualMemory
# C++ header
sysplant generate -cpp -o ./src/syscalls canterlot \
-f NtOpenProcess,NtWriteVirtualMemory,NtCreateThreadEx
This creates ./src/syscalls.h (C) or ./src/syscalls.hpp (C++).
NIM
sysplant generate -nim -o ./src/syscalls canterlot \
-f NtOpenProcess,NtWriteVirtualMemory,NtCreateThreadEx
Creates ./src/syscalls.nim.
Rust
sysplant generate -rust -o ./src/syscalls canterlot \
-f NtOpenProcess,NtWriteVirtualMemory,NtCreateThreadEx
Creates ./src/syscalls.rs.
Step 3 — Remove old Win32 declarations
C / C++ — before
#include <windows.h>
#include <winternl.h> // for Nt* declarations
/* … */
NTSTATUS status = NtWriteVirtualMemory(
hProcess, lpBase, lpBuffer, dwSize, NULL
);
C / C++ — after
Replace the winternl.h include with the generated header. The generated file declares all the Nt* prototypes and typedefs internally — no other includes are needed for the syscall functions themselves.
#include "syscalls.h" // replaces winternl.h for syscall declarations
/* … */
NTSTATUS status = NtWriteVirtualMemory(
hProcess, lpBase, lpBuffer, dwSize, NULL
);
The call site is unchanged — same function names, same signatures.
Step 4 — (egg_hunter only) Verify auto-init
If you generated stubs with the egg_hunter method, the sanitizer runs automatically before main() via .CRT$XCU when compiled with MinGW/GCC. Nothing extra is required.
If your toolchain does not process .CRT$XCU (MSVC, some cross-compilation setups), add a single call at the start of your entry point:
int main(void) {
SPT_SanitizeSyscalls(); // only needed when .CRT$XCU is not supported
/* … */
}
Automating stub generation in a build system
Makefile
SYSCALLS_H := src/syscalls.h
$(SYSCALLS_H):
sysplant generate -c -o src/syscalls canterlot \
-f NtOpenProcess,NtWriteVirtualMemory,NtCreateThreadEx
implant: $(SYSCALLS_H) src/implant.c
gcc -o implant src/implant.c
Python build script
from sysplant.sysplant import Sysplant
import pathlib
# Discover functions used in existing sources
engine = Sysplant(arch="x64", language="c")
functions = engine.list("./src")
# Generate stubs for exactly those functions
engine.generate(
iterator="canterlot",
method="random",
syscalls=list(functions),
)
# Optional: randomise internal SPT_* symbol names
engine.scramble(True)
# Write to file
engine.output("./src/syscalls")
print(f"Generated stubs for: {sorted(functions)}")
Scrambling internal symbols
If your binary will be statically analysed, add -x to randomise the 23 internal SPT_* symbol names. The public Nt* function names remain unchanged.
sysplant generate -c -x -o ./src/syscalls canterlot \
-f NtOpenProcess,NtWriteVirtualMemory
Each invocation with -x produces different internal names. Regenerating with -x requires a full rebuild.
Quick reference — iterator selection guide
| Situation | Recommended gate |
|---|---|
| Unknown EDR, modern Windows | canterlot |
Need egg-hunter (no syscall on disk) | custom -i canterlot -m egg_hunter |
| Legacy target (older Windows) | halo or tartarus |
| Need indirect syscall return address | syswhispers |
| Smallest code size | freshy |