Guides

Integrating Sysplant

How to integrate Sysplant-generated syscall stubs into an existing C, C++, NIM, or Rust project.

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

SituationRecommended gate
Unknown EDR, modern Windowscanterlot
Need egg-hunter (no syscall on disk)custom -i canterlot -m egg_hunter
Legacy target (older Windows)halo or tartarus
Need indirect syscall return addresssyswhispers
Smallest code sizefreshy
Copyright © 2026