
# Nur-Header Windows x64 indirekte Syscall-Bibliothek. Kein CRT, kein IAT, VEH Anti-BP, AMSI/ETW-Bypass, W^X-Speicher, dynamische Stubs pro Aufruf.
Header-only-Bibliothek für Windows x64, mit der du beliebige NT-Syscalls aufrufen kannst, ohne ntdll-Imports anzufassen, ohne Strings in deiner Binary zu hinterlassen und ohne die üblichen Warnsignale, die EDRs aus der Fassung bringen.
Kein CRT. Kein STL. Kein IAT. Das Ganze kompiliert auf ~19KB herunter – mit buchstäblich null DLL-Abhängigkeiten.
Entwickelt, um die typischen Fallstricke bestehender Syscall-Bibliotheken zu vermeiden – Klartext-Strings, bekannte Hash-Konstanten, direkte Syscalls aus Nicht-ntdll-Speicher, IAT-Imports, die schreien „Ich mache etwas Seltsames“, SEC_NO_CHANGE-IOC, CRT-Aufblähung. Nichts davon hier.
Syscall-Engine
syscall; ret-Gadget, sodass RIP beim Auslösen des Syscall-Befehls immer innerhalb von ntdll liegt\KnownDlls\ntdll.dll-Section-Mapping extrahiert (kein Dateisystemzugriff, unsichtbar für ProcMon)Anti-Breakpoint
Evasion
AmsiScanBuffer, um S_OK zurückzugebenEtwEventWrite, um SUCCESS zurückzugebenCode-Qualität
stealth/-Ordner in dein Projekt werfen und loslegen
initialize() öffnet ntdll über die \KnownDlls-Section, parst PE-Exports und sammelt jede Syscall-Nummer ein.text nach einem syscall; ret-Gadget – von hier aus wird der eigentliche Syscall-Befehl ausgeführtsc::invoke() aufrufst:
emit_stub() baut einen einzigartigen polymorphen Stub – zufällige Junk-Instruktionen davor/danach, XOR-verschleierte Syscall-Nummer mit einem Per-Call-Schlüssel, indirekter jmp zum ntdll-GadgetZu keinem Zeitpunkt existiert RWX-Speicher. Zu keinem Zeitpunkt wird ein syscall-Befehl außerhalb von ntdll ausgeführt. Zu keinem Zeitpunkt werden Syscall-Nummern im Klartext gespeichert.
Du rufst tramp::invoke() mit der Zielfunktion auf. Wenn kein Breakpoint vorhanden ist – läuft die Funktion einfach normal mit null Overhead. Wenn ein Debugger 0xCC platziert hat:
Die Breakpoint-Liste des Debuggers zeigt den Breakpoint weiterhin als aktiv an. Der Breakpoint wird bei unseren Aufrufen nur nie ausgelöst.
cmake -B build -A x64
cmake --build build --config Release
Benötigt MSVC (VS 2019+) und CMake 3.15+. Ausgabe ist ~19KB mit null Imports.
#include "stealth/syscall.hpp"
stealth::sc::initialize();
PVOID base = nullptr;
SIZE_T size = 0x1000;
NTSTATUS status = stealth::sc::invoke<NTSTATUS>(
HASH("NtAllocateVirtualMemory"),
NtCurrentProcess(), &base, (ULONG_PTR)0, &size,
(ULONG)(MEM_COMMIT | MEM_RESERVE), (ULONG)PAGE_READWRITE
);
#include "stealth/trampoline.hpp"
// funktioniert auch, wenn x64dbg einen BP auf MessageBoxA gesetzt hat
int ret = stealth::tramp::invoke<int>(
HASH_CI("user32.dll"), HASH("MessageBoxA"),
(HWND)nullptr, (LPCSTR)"hello", (LPCSTR)"title", (UINT)MB_OK
);
#include "stealth/bypass.hpp"
stealth::bypass::patch_etw();
stealth::bypass::patch_amsi();
stealth::tramp::shutdown();
stealth::sc::shutdown();
stealth/
common.hpp — Speicheroperationen, Spinlock, static_map, PRNG, Debug-Ausgabe
hash.hpp — Compile-Zeit eigener Hash
xorstr.hpp — Compile-Zeit XOR-Stringverschlüsselung
peb.hpp — PEB-Walk, PE-Export-Parser, Hook-Erkennung
syscall.hpp — Indirekte Syscall-Engine, Stub-Generator, W^X, Anti-Dump
trampoline.hpp — VEH-basierter Anti-Breakpoint
bypass.hpp — AMSI + ETW-Patching
MIT – mach damit, was du willst.