mirror of
https://github.com/CyberSecurityUP/SysWhispers4
synced 2026-06-08 10:47:52 +00:00
562c115e6c
- 5 SSN resolution methods: Static, FreshyCalls, Hell's Gate, Halo's Gate, Tartarus' Gate - 4 invocation methods: Embedded (direct), Indirect, Randomized (RDTSC entropy), Egg hunt - Architecture support: x64, x86, WoW64, ARM64 (SVC #0 / w8) - Compiler support: MSVC (MASM ml64.exe), MinGW (GAS inline asm), Clang - XOR SSN encryption at rest (randomized key per generation) - ETW user-mode bypass (ntdll!EtwEventWrite patch) - Call-stack spoofing trampoline (ntdll return address) - PEB-walk ntdll resolution (no Win32 API calls) - EAT parsing with DJB2 compile-time hashes (no string comparisons) - Fix: rdtsc clobbers rdx (arg2) in randomized stub — save rdx→r11 before rdtsc - 48 NT functions across 5 presets (common, injection, evasion, token, all) - j00ru syscall table update script (26 Windows builds Win7–Win11 24H2) - Comprehensive README with SW1/SW2/SW3/SW4 feature comparison matrix Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
213 lines
6.9 KiB
Python
213 lines
6.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
SysWhispers4 — Syscall Table Updater
|
|
Fetches the latest NT syscall numbers from j00ru/windows-syscalls and
|
|
updates data/syscalls_nt_x64.json and data/syscalls_nt_x86.json.
|
|
|
|
Usage:
|
|
python scripts/update_syscall_table.py
|
|
python scripts/update_syscall_table.py --arch x86
|
|
python scripts/update_syscall_table.py --arch x64,x86
|
|
python scripts/update_syscall_table.py --out custom_table.json
|
|
|
|
Requirements:
|
|
pip install requests (or: python -m pip install requests)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import csv
|
|
import io
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Dict, Optional
|
|
from urllib.request import urlopen, Request
|
|
from urllib.error import URLError
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# j00ru table URLs (raw CSV from GitHub)
|
|
# ---------------------------------------------------------------------------
|
|
JORU_BASE = "https://raw.githubusercontent.com/j00ru/windows-syscalls/master"
|
|
CSV_URLS = {
|
|
"x64": f"{JORU_BASE}/x64/csv/nt.csv",
|
|
"x86": f"{JORU_BASE}/x86/csv/nt.csv",
|
|
}
|
|
|
|
# Windows build number → human-readable label
|
|
BUILD_LABELS: Dict[str, str] = {
|
|
"5.1.2600.0": "Windows XP RTM",
|
|
"5.1.2600.2180": "Windows XP SP2",
|
|
"5.2.3790.0": "Windows Server 2003 RTM",
|
|
"5.2.3790.1830": "Windows Server 2003 SP1",
|
|
"5.2.3790.3959": "Windows Server 2003 SP2",
|
|
"6.0.6000.16386":"Windows Vista RTM",
|
|
"6.0.6001.18000":"Windows Vista SP1",
|
|
"6.0.6002.18005":"Windows Vista SP2",
|
|
"6.1.7600.16385":"Windows 7 RTM",
|
|
"6.1.7601.17514":"Windows 7 SP1",
|
|
"6.2.9200.16384":"Windows 8 RTM",
|
|
"6.3.9600.16384":"Windows 8.1 RTM",
|
|
"10.0.10240.16384":"Windows 10 1507",
|
|
"10.0.10586.0": "Windows 10 1511",
|
|
"10.0.14393.0": "Windows 10 1607",
|
|
"10.0.15063.0": "Windows 10 1703",
|
|
"10.0.16299.15": "Windows 10 1709",
|
|
"10.0.17134.1": "Windows 10 1803",
|
|
"10.0.17763.1": "Windows 10 1809",
|
|
"10.0.18362.1": "Windows 10 1903",
|
|
"10.0.18363.418":"Windows 10 1909",
|
|
"10.0.19041.1": "Windows 10 2004",
|
|
"10.0.19042.1": "Windows 10 20H2",
|
|
"10.0.19043.1": "Windows 10 21H1",
|
|
"10.0.19044.1": "Windows 10 21H2",
|
|
"10.0.19045.1": "Windows 10 22H2",
|
|
"10.0.20348.1": "Windows Server 2022",
|
|
"10.0.22000.1": "Windows 11 21H2",
|
|
"10.0.22621.1": "Windows 11 22H2",
|
|
"10.0.22631.1": "Windows 11 23H2",
|
|
"10.0.26100.1": "Windows 11 24H2 / Server 2025",
|
|
}
|
|
|
|
|
|
def _version_to_build(ver_str: str) -> Optional[str]:
|
|
"""
|
|
Convert 'major.minor.build.revision' to the short build number key
|
|
used in our JSON (e.g. '10.0.19041.1' → '19041').
|
|
Falls back to full string for older versions.
|
|
"""
|
|
parts = ver_str.split(".")
|
|
if len(parts) >= 3:
|
|
major = int(parts[0])
|
|
build = int(parts[2])
|
|
if major >= 10:
|
|
return str(build)
|
|
# For Vista/7/8: use minor.build
|
|
return f"{parts[1]}.{parts[2]}"
|
|
return ver_str
|
|
|
|
|
|
def fetch_csv(url: str) -> str:
|
|
print(f" [~] Fetching: {url}")
|
|
req = Request(url, headers={"User-Agent": "SysWhispers4/1.0"})
|
|
try:
|
|
with urlopen(req, timeout=30) as resp:
|
|
return resp.read().decode("utf-8")
|
|
except URLError as e:
|
|
print(f" [!] Failed to fetch {url}: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
def parse_joru_csv(csv_text: str) -> dict:
|
|
"""
|
|
Parse j00ru's CSV into our JSON format:
|
|
{ "FunctionName": { "build_number": ssn_int, ... }, ... }
|
|
"""
|
|
reader = csv.reader(io.StringIO(csv_text))
|
|
rows = list(reader)
|
|
if not rows:
|
|
return {}
|
|
|
|
# First row: "Function", "version1", "version2", ...
|
|
header = rows[0]
|
|
func_col = 0
|
|
version_cols = range(1, len(header))
|
|
|
|
result: dict = {
|
|
"_comment": "NT syscall numbers — generated by SysWhispers4/scripts/update_syscall_table.py",
|
|
"_source": "https://github.com/j00ru/windows-syscalls",
|
|
"_format": "FunctionName -> { build_number -> decimal_ssn }",
|
|
"_windows_builds": {},
|
|
}
|
|
|
|
# Build the build-label map
|
|
for col in version_cols:
|
|
ver = header[col].strip()
|
|
build_key = _version_to_build(ver)
|
|
if build_key:
|
|
label = BUILD_LABELS.get(ver, ver)
|
|
result["_windows_builds"][build_key] = label
|
|
|
|
for row in rows[1:]:
|
|
if not row or len(row) < 2:
|
|
continue
|
|
func_name = row[func_col].strip()
|
|
if not func_name:
|
|
continue
|
|
|
|
func_entry: dict = {}
|
|
for col in version_cols:
|
|
if col >= len(row):
|
|
break
|
|
cell = row[col].strip()
|
|
if not cell or cell.lower() in ("", "n/a", "-", "null"):
|
|
continue
|
|
try:
|
|
ssn = int(cell, 16) if cell.startswith("0x") else int(cell)
|
|
except ValueError:
|
|
continue
|
|
ver = header[col].strip()
|
|
build_key = _version_to_build(ver)
|
|
if build_key:
|
|
func_entry[build_key] = ssn
|
|
|
|
if func_entry:
|
|
result[func_name] = func_entry
|
|
|
|
return result
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(
|
|
description="Update SysWhispers4 syscall tables from j00ru/windows-syscalls",
|
|
)
|
|
parser.add_argument(
|
|
"--arch",
|
|
default="x64",
|
|
help="Comma-separated architectures to fetch: x64, x86 (default: x64)",
|
|
)
|
|
parser.add_argument(
|
|
"--out",
|
|
default=None,
|
|
help="Custom output path (overrides the default data/ location)",
|
|
)
|
|
parser.add_argument(
|
|
"--functions",
|
|
default=None,
|
|
help="Comma-separated list of functions to keep (default: all Nt* functions)",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
data_dir = Path(__file__).parent.parent / "data"
|
|
archs = [a.strip() for a in args.arch.split(",")]
|
|
filter_funcs = set(f.strip() for f in args.functions.split(",")) if args.functions else None
|
|
|
|
for arch in archs:
|
|
if arch not in CSV_URLS:
|
|
print(f" [!] Unknown arch '{arch}'. Available: {list(CSV_URLS)}")
|
|
continue
|
|
|
|
csv_text = fetch_csv(CSV_URLS[arch])
|
|
table = parse_joru_csv(csv_text)
|
|
|
|
# Filter to Nt* functions only (NT namespace) + keep metadata
|
|
filtered = {k: v for k, v in table.items()
|
|
if k.startswith("_") or k.startswith("Nt")}
|
|
|
|
# Further filter if user specified specific functions
|
|
if filter_funcs:
|
|
filtered = {k: v for k, v in filtered.items()
|
|
if k.startswith("_") or k in filter_funcs}
|
|
|
|
out_path = Path(args.out) if args.out else data_dir / f"syscalls_nt_{arch}.json"
|
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
out_path.write_text(json.dumps(filtered, indent=2, sort_keys=False), encoding="utf-8")
|
|
n_funcs = sum(1 for k in filtered if not k.startswith("_"))
|
|
print(f" [+] Written {n_funcs} functions ({arch}) → {out_path}")
|
|
|
|
print(" [+] Syscall table update complete.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|