
Universal signature generation for any system function from all Windows Builds using Winbindex
Cross-version binary signatures and RVA offsets for Windows PE functions
pe-signgen is a tool for reverse engineers and security researchers that automatically generates:
The core idea is to provide a systematic, robust way to access unexported functions across Windows 10/11 builds. It leverages:
⚠️ Windows version support
pe-signgensupports Windows 10 and Windows 11 only. This is a deliberate design choice: Winbindex does not provide complete data for older versions.
Unexported Windows internals
Generate signatures for functions like LdrpInitializeTls, RtlpInsertInvertedFunctionTableEntry, etc.
Game hacking / anti-cheat research Generate stable signatures that survive game updates
Security research Locate security-critical routines across Windows builds
Automation Scriptable signature and offset generation for entire sets of internal APIs
pe-signgen provides three distinct output formats for different use cases:
Structured data for automation, scripting, and integration with other tools.
pe-signgen --signature ntdll!NtCreateFile -o ntcreatefile.json --output-format json
Output structure:
{
"dll_name": "ntdll",
"function_name": "NtCreateFile",
"architecture": "x64",
"generated": "2024-12-11T15:30:00.123456",
"total_builds": 1247,
"unique_signatures": 3,
"signature_groups": [
{
"matched_symbol": "NtCreateFile",
"signature": "4C 8B DC 49 89 5B 08 49 89 6B 10 49 89 73 18 ...",
"length": 48,
"build_count": 845,
"versions": [
{ "major": 10240, "minor": 16384, "build": "10240.16384" },
{ "major": 10586, "minor": 0, "build": "10586.0" }
]
}
]
}
Notes:
major and minor are derived from the build string by splitting at the first ..
Example: "10240.16384" → major = 10240, minor = 16384.build is the original build string key used internally.Compact, runtime-ready binary formats optimized for embedded systems and low-overhead scanning.
These match the on-disk layout implemented in write_wsig() and write_woff().
Magic: WSO\0 (0x57 0x53 0x4F 0x00)
Current Version: 1
Purpose: Store binary signatures with wildcard masks and associated Windows build versions
┌─────────────────────────────────────┐
│ Header (36 bytes) │
├─────────────────────────────────────┤
│ DLL Name (variable) │
├─────────────────────────────────────┤
│ Function Name (variable) │
├─────────────────────────────────────┤
│ Signature / Mask / Build blobs │ ← Arbitrary order, see notes
├─────────────────────────────────────┤ ← Aligned to 4 bytes
│ Groups Table (24 × N bytes) │
└─────────────────────────────────────┘
Important layout notes (matches write_wsig)
// Packed as: "<4sIIIIIIII" (little-endian)
typedef struct {
char magic[4]; // "WSO\0" (WSIG_MAGIC)
uint32_t version; // FORMAT_VERSION (currently 1)
uint32_t arch; // Architecture code (1=x64, 2=ARM64, 3=WoW64)
uint32_t dll_off; // Offset to DLL name string
uint32_t dll_len; // Length of DLL name in bytes
uint32_t func_off; // Offset to function name string
uint32_t func_len; // Length of function name in bytes
uint32_t group_count;// Number of signature groups
uint32_t groups_off; // Offset to groups table
} wsig_header_t; // 36 bytes
Each signature group represents a unique pattern that applies to one or more Windows builds.
// Packed as: "<IIIIII" (little-endian)
typedef struct {
uint32_t sig_off; // Offset to signature pattern bytes
uint32_t sig_len; // Length of signature pattern (in bytes)
uint32_t mask_off; // Offset to wildcard mask bytes
uint32_t mask_len; // Length of wildcard mask (≈ ceil(sig_len/8))
uint32_t builds_off; // Offset to build version array
uint32_t build_cnt; // Number of builds using this signature
} wsig_group_t; // 24 bytes
Each build entry identifies a specific Windows version that uses this signature.
typedef struct {
uint32_t major; // e.g. 19041
uint32_t minor; // e.g. 1234
} wsig_build_t; // 8 bytes
major and minor come from splitting the build string ("A.B" → A, B). The original build string is not stored in the binary format; if you need it, keep it externally (it is present in the JSON output).
The mask is a bitmask where each bit corresponds to a byte in the signature pattern:
Example:
Signature: 4C 8B DC 49 89 ?? 08 49
Mask bits: 1 1 1 1 1 0 1 1 (MSB first within each byte)
Mask byte: 0xBF (binary: 10111111)
Mask bytes are stored and interpreted in little-endian bit order within each byte (exactly as used in the C helpers and parse_signature):
uint8_t bit = (mask_bytes[byte_index >> 3] >> (byte_index & 7)) & 1u;
*_len to determine the length; do not read past that.Magic: WOF\0 (0x57 0x4F 0x46 0x00)
Current Version: 1
Purpose: Store direct RVA and file offsets for functions across Windows builds
┌─────────────────────────────────────┐
│ Header (36 bytes) │
├─────────────────────────────────────┤
│ DLL Name (variable) │
├─────────────────────────────────────┤
│ Function Name (variable) │
├─────────────────────────────────────┤
│ Matched Symbol Names (variable) │ ← One UTF‑8 string per entry
├─────────────────────────────────────┤ ← Aligned to 4 bytes
│ Entries Table (32 × N bytes) │
└─────────────────────────────────────┘
Layout details (matches write_woff):
matched_off, matched_len) pointing into this string pool.