Overview
SysWhispers4 is a Python-based code generator that produces C/ASM syscall stubs. Understanding the project structure helps you:- Extend functionality (add new syscalls, resolution methods, etc.)
- Debug generation issues
- Contribute to the project
- Customize for specific needs
Directory Layout
Core Modules
syswhispers.py - CLI Entry Point
Purpose: Command-line interface, argument parsing, orchestration
Key responsibilities:
- Parse command-line arguments (
--preset,--method,--resolve, etc.) - Validate function names against
prototypes.json - Load preset configurations from
presets.json - Instantiate
Generatorclass - Write output files (
.h,.c,.asm/.cstubs)
- Adding new CLI flags
- Changing default behaviors
- Adding new output file types
core/models.py - Type Definitions
Purpose: Enums and dataclasses representing configuration options
Key types:
- Adding new architectures (e.g., RISC-V)
- Adding new resolution methods
- Adding new invocation techniques
core/generator.py - Code Generation Engine
Purpose: Core logic for generating C/ASM code
Size: ~1900 lines (largest module)
Key classes:
| Method | Generates | Example |
|---|---|---|
gen_types_header() | NT type definitions | typedef struct _UNICODE_STRING {...} |
gen_header() | Function prototypes | NTSTATUS SW4_NtAllocateVirtualMemory(...) |
gen_c_file() | Runtime SSN resolution | BOOL SW4_Initialize(void) {...} |
gen_asm_file() | MASM syscall stubs | SW4_NtAllocateVirtualMemory PROC |
gen_stubs_file() | GAS inline stubs | __asm__ volatile ("mov r10, rcx...") |
gen_ssn_table() | Static SSN array | DWORD SW4_SsnTable[] = {0x18, 0x50, ...} |
gen_gadget_pool() | Indirect gadget array | PVOID SW4_GadgetPool[64] = {...} |
gen_unhook_function() | ntdll unhooking code | SW4_UnhookNtdll() |
gen_etw_bypass() | ETW patch function | SW4_PatchEtw() |
gen_amsi_bypass() | AMSI patch function | SW4_PatchAmsi() |
gen_sleep_encrypt() | Ekko sleep encryption | SW4_SleepEncrypt(DWORD ms) |
- Adding new NT functions (update
data/prototypes.jsonfirst) - Implementing new evasion techniques
- Supporting new architectures
- Changing stub format/structure
core/obfuscator.py - Obfuscation Module
Purpose: Code obfuscation, junk injection, egg hunt, SSN encryption
Key functions:
- Adding new junk instruction variants
- Implementing new obfuscation techniques (control flow flattening, string encryption, etc.)
- Changing egg marker generation algorithm
core/utils.py - Helper Functions
Purpose: Hash functions, file I/O, data loading utilities
Key functions:
- Adding new hash algorithms
- Changing file encoding/format
- Adding data validation logic
Data Files
data/prototypes.json - Function Signatures
Format:
- Memory (8 functions)
- Section/Mapping (4)
- Process (10)
- Thread (13)
- Handle/Sync (10)
- File (5)
- Token (6)
- Transaction (3)
- Misc (5)
- Adding new NT functions
- Fixing incorrect signatures (check MSDN or ntdll headers)
data/presets.json - Function Presets
Format:
common(25 functions)injection(20)evasion(15)token(6)stealth(32)file_ops(7)transaction(7)all(64)
- Creating custom presets for specific use cases
- Adjusting existing preset function lists
data/syscalls_nt_x64.json - x64 Syscall Table
Format:
- Windows 7 SP1 → Windows 11 24H2
- 20+ builds tracked
- Auto-generated from j00ru/windows-syscalls
- New Windows build released (use
scripts/update_syscall_table.py) - SSN changes detected
data/syscalls_nt_x86.json - x86 Syscall Table
Same format as x64, but for 32-bit Windows.
Key differences:
- Uses
sysenterinstead ofsyscall - SSN values differ from x64
- Covers legacy Windows (NT 4.0, 2000, XP, etc.)
Scripts
scripts/update_syscall_table.py - Table Updater
Purpose: Fetch latest syscall numbers from j00ru’s repository
Usage:
- Fetches CSV from
https://raw.githubusercontent.com/j00ru/windows-syscalls/master/x64/csv/nt.csv - Parses CSV columns (each column = Windows build)
- Maps human-readable build names to short keys (
"Windows 10 1909"→"18363") - Converts hex SSN values to decimal
- Filters to
Nt*functions only - Writes JSON to
data/syscalls_nt_x64.json
- After new Windows build release (e.g., 25H2)
- When j00ru updates his repository
- Before generating stubs for new OS version
Generated Output Files
MSVC (Default)
MinGW / Clang
.c files instead of separate .asm
Code Flow Example
User runs:
Execution flow:
-
syswhispers.py- Parse args:
preset="common",method="indirect",resolve="freshycalls" - Load
data/presets.json→ expand"common"to 25 function names - Load
data/prototypes.json→ get signatures for those 25 functions - Load
data/syscalls_nt_x64.json→ get SSN values (not used for FreshyCalls, but loaded for static fallback)
- Parse args:
-
core/generator.py- Instantiate
Generator(functions=25, arch=X64, method=INDIRECT, resolve=FRESHYCALLS, compiler=MSVC) - Call
gen.generate():gen_types_header()→ CreateSW4Syscalls_Types.hgen_header()→ CreateSW4Syscalls.hwith 25 function prototypesgen_c_file()→ CreateSW4Syscalls.c:- Generate
SW4_Initialize()with FreshyCalls logic (sort exports by VA) - Generate
SW4_FindSyscallGadgets()for indirect method (scan ntdll forsyscall;ret)
- Generate
gen_asm_file()→ CreateSW4Syscalls.asm:- For each function, generate indirect stub:
- For each function, generate indirect stub:
- Instantiate
-
syswhispers.py(file output)- Write 4 files to disk
- Print summary:
Extension Points
Adding a New Resolution Method
-
Add enum to
core/models.py: -
Implement logic in
core/generator.py: -
Update CLI in
syswhispers.py:
Adding a New Invocation Method
Similar process:- Add to
InvocationMethodenum - Implement stub generation in
_gen_x64_stub()(or other arch methods) - Update CLI
Adding a New Architecture
- Add to
Architectureenum - Implement
_gen_<arch>_stub()method - Update syscall instruction/register mappings
- Add syscall table JSON (if SSNs differ)
Testing Your Changes
Unit Tests (Future)
Currently no formal test suite. Recommended approach:Integration Tests
Contributing Guidelines
-
Follow existing code style:
- 4-space indentation
- Type hints for all functions
- Docstrings for public APIs
-
Update
prototypes.jsonwhen adding functions:- Verify signature against MSDN or ntdll headers
- Test on multiple Windows versions
-
Run
update_syscall_table.pybefore release:- Ensure SSN tables are current
-
Test on multiple configurations:
- MSVC, MinGW, Clang
- x64, x86, WoW64, ARM64 (if applicable)
- All resolution methods
- All invocation methods
- Document new features in README.md
Debugging Tips
Enable Verbose Output
Inspect Generated Code
Before compiling, review the generated.c and .asm files:
Use Debugger
Set breakpoints in your compiled binary:Performance Profiling
Measure Initialization Time
- Static: ~0.001 ms (just loads from table)
- FreshyCalls: ~0.2 ms (sorts ~500 exports)
- From disk: ~5 ms (maps section, parses PE)
Further Reading
- Syscall Table Updates - Keep tables current
- Recommended Configurations - Usage examples
- Contributing Guide
