Files
youssefnoob003-SindriKit/docs/scripts/generate_hashes.md
T
2026-06-22 12:38:04 +01:00

4.0 KiB
Raw Blame History

generate_hashes.py

Location: scripts/generate_hashes.py

This script is the core of SindriKit's compile-time API hashing pipeline. It is invoked automatically by the CMake build system before compilation begins. Its output is a generated C header (include/generated/sindri_hashes.h) containing #define macros for every API name and module name the framework needs to resolve at runtime.

Purpose

Offensive tooling that resolves Windows APIs by plaintext name (e.g., "NtAllocateVirtualMemory") leaves those strings embedded in the binary's .rdata section. Static analysis tools and YARA rules trivially flag these artifacts. SindriKit eliminates this surface by pre-computing hashes of all required strings at configure time. At runtime, the framework hashes encountered export names and compares the result against these compile-time constants. The plaintext string never appears in the binary.

Anti-Analysis: Randomized Seed

The script accepts a RANDOMIZE flag (ON/OFF) as its final argument.

  • When ON: The script generates a fresh, randomized 32-bit seed in the range [0x10000000, 0xFFFFFFFF]. This guarantees that hash values are unique per build, preventing signature-based detection and thwarting pre-computed rainbow tables targeting standard DJB2/FNV1A initialization constants.
  • When OFF: The script uses a deterministic initialization constant (e.g., 0x5381 for DJB2). This ensures that the generated header remains identical across executions, preserving file system timestamps and preventing unnecessary recompilations during local development.

The generated header emits the seed as SND_HASH_SEED, and the runtime hashing functions in hash.h consume it dynamically.

Supported Algorithms

Algorithm CMake Variable Description
DJB2 SND_HASH_ALGO=DJB2 Daniel J. Bernstein's hash. Shift-and-add (h = (h << 5) + h + c).
FNV-1a SND_HASH_ALGO=FNV1A FowlerNollVo variant 1a. XOR-then-multiply with prime 16777619.

Switching the algorithm across the entire codebase requires only changing the SND_HASH_ALGO CMake variable without any source code modifications.

Usage

python scripts/generate_hashes.py <hashes.ini> <sindri_hashes.h> <ALGO> <RANDOMIZE>
Argument Description
hashes.ini Path to the hash manifest (typically config/hashes.ini)
sindri_hashes.h Output path for the generated C header
ALGO Hashing algorithm to use (DJB2 or FNV1A)
RANDOMIZE Toggle randomized seeds (ON or OFF)

Build System Integration (Smart Caching)

Under normal operation, this script is never invoked manually. The CMake build system evaluates it at configure time via execute_process.

To support aggressive incremental builds without sacrificing opsec agility, the script employs "Smart Caching" logic:

  1. It pre-calculates the exact header string in memory.
  2. It attempts to read the existing sindri_hashes.h from disk.
  3. If the contents are a perfect 1:1 match, the script cleanly exits without touching the file, preserving the disk modification timestamp.

Because the timestamp remains unmodified, ninja and MSBuild correctly deduce that dependent C files do not need to recompile, vastly improving developer velocity when SND_RANDOMIZE_SEED=OFF.

Output Format

The generated header contains:

  1. A SND_HASH_SEED define with the randomized seed value.
  2. Grouped SND_HASH_<NAME> defines for each module and API.
// AUTO-GENERATED by scripts/generate_hashes.py (DO NOT EDIT)
// Algorithm: DJB2

#define SND_HASH_SEED 0xA3F7B1C2U

// --------------------------------------------------------------------------
// ntdll.dll
// --------------------------------------------------------------------------
#define SND_HASH_NTDLL_DLL                                      0x1B2C3D4EU  // module
#define SND_HASH_NTALLOCATEVIRTUALMEMORY                        0x5A6B7C8DU
#define SND_HASH_NTPROTECTVIRTUALMEMORY                         0x9E0F1A2BU
...