Skip to main content

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 Generator class
  • Write output files (.h, .c, .asm/.c stubs)
Main flow:
When to modify:
  • 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:
When to modify:
  • 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:
Key methods: Architecture-specific code paths:
When to modify:
  • Adding new NT functions (update data/prototypes.json first)
  • 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:
When to modify:
  • 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:
When to modify:
  • Adding new hash algorithms
  • Changing file encoding/format
  • Adding data validation logic

Data Files

data/prototypes.json - Function Signatures

Format:
Total functions: 64 Categories:
  • Memory (8 functions)
  • Section/Mapping (4)
  • Process (10)
  • Thread (13)
  • Handle/Sync (10)
  • File (5)
  • Token (6)
  • Transaction (3)
  • Misc (5)
When to modify:
  • Adding new NT functions
  • Fixing incorrect signatures (check MSDN or ntdll headers)

data/presets.json - Function Presets

Format:
Presets:
  • common (25 functions)
  • injection (20)
  • evasion (15)
  • token (6)
  • stealth (32)
  • file_ops (7)
  • transaction (7)
  • all (64)
When to modify:
  • Creating custom presets for specific use cases
  • Adjusting existing preset function lists

data/syscalls_nt_x64.json - x64 Syscall Table

Format:
Coverage: When to update:
  • 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 sysenter instead of syscall
  • 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:
How it works:
  1. Fetches CSV from https://raw.githubusercontent.com/j00ru/windows-syscalls/master/x64/csv/nt.csv
  2. Parses CSV columns (each column = Windows build)
  3. Maps human-readable build names to short keys ("Windows 10 1909""18363")
  4. Converts hex SSN values to decimal
  5. Filters to Nt* functions only
  6. Writes JSON to data/syscalls_nt_x64.json
When to run:
  • After new Windows build release (e.g., 25H2)
  • When j00ru updates his repository
  • Before generating stubs for new OS version
See the Syscall Table Updates page for detailed workflow.

Generated Output Files

MSVC (Default)

MinGW / Clang

Key difference: GAS uses inline assembly in .c files instead of separate .asm

Code Flow Example

User runs:

Execution flow:

  1. 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)
  2. core/generator.py
    • Instantiate Generator(functions=25, arch=X64, method=INDIRECT, resolve=FRESHYCALLS, compiler=MSVC)
    • Call gen.generate():
      • gen_types_header() → Create SW4Syscalls_Types.h
      • gen_header() → Create SW4Syscalls.h with 25 function prototypes
      • gen_c_file() → Create SW4Syscalls.c:
        • Generate SW4_Initialize() with FreshyCalls logic (sort exports by VA)
        • Generate SW4_FindSyscallGadgets() for indirect method (scan ntdll for syscall;ret)
      • gen_asm_file() → Create SW4Syscalls.asm:
        • For each function, generate indirect stub:
  3. syswhispers.py (file output)
    • Write 4 files to disk
    • Print summary:

Extension Points

Adding a New Resolution Method

  1. Add enum to core/models.py:
  2. Implement logic in core/generator.py:
  3. Update CLI in syswhispers.py:

Adding a New Invocation Method

Similar process:
  1. Add to InvocationMethod enum
  2. Implement stub generation in _gen_x64_stub() (or other arch methods)
  3. Update CLI

Adding a New Architecture

  1. Add to Architecture enum
  2. Implement _gen_<arch>_stub() method
  3. Update syscall instruction/register mappings
  4. Add syscall table JSON (if SSNs differ)

Testing Your Changes

Unit Tests (Future)

Currently no formal test suite. Recommended approach:

Integration Tests


Contributing Guidelines

  1. Follow existing code style:
    • 4-space indentation
    • Type hints for all functions
    • Docstrings for public APIs
  2. Update prototypes.json when adding functions:
    • Verify signature against MSDN or ntdll headers
    • Test on multiple Windows versions
  3. Run update_syscall_table.py before release:
    • Ensure SSN tables are current
  4. Test on multiple configurations:
    • MSVC, MinGW, Clang
    • x64, x86, WoW64, ARM64 (if applicable)
    • All resolution methods
    • All invocation methods
  5. Document new features in README.md

Debugging Tips

Enable Verbose Output

Shows detailed generation steps, loaded data, etc.

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

Typical results:
  • 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