Releases: 876N/KeyGen
Download
Source Code Documentation
Technical reference for the KeyGen codebase.
Architecture Overview
The project is a Rust workspace with three crates:
crates/
├── shared/ Library — crypto, license format, config structures
├── keygen/ Binary — CLI tool for protection and key generation
└── stub/ Binary — the protected loader that runs on end-user machines
Crate: kg_shared
Shared library used by both keygen and stub. Zero external dependencies for crypto.
Modules
| Module | Purpose |
|---|---|
aes.rs |
AES-256-CBC encrypt/decrypt with PKCS7 padding and random IV |
hash.rs |
SHA-1, MD5, HMAC-SHA1 implementations |
kdf.rs |
PBKDF2-HMAC-SHA1 key derivation (1000 rounds) |
license.rs |
License encoding/decoding, validation, expiration checks |
random.rs |
Secure random via BCryptGenRandom (Windows) or /dev/urandom (Unix) |
config.rs |
ConfigData struct layout — binary config embedded in the stub |
Key Functions
aes256_cbc_encrypt(plaintext, key)— Encrypts with random 16-byte IV prependedaes256_cbc_decrypt(ciphertext, key)— Reads IV from first 16 bytes, decryptsgenerate_license(hwid, enc_map, info)— Creates an HWID-bound license key stringvalidate_license(key, hwid, enc_map)— Validates and decodes a license keycrc32(data)— Standard CRC32 for integrity checkingwipe(buf)— Volatile zero-fill to prevent optimizer from removing the wipe
Crate: keygen
The CLI tool that developers use to protect executables and generate license keys.
Modules
| Module | Purpose |
|---|---|
main.rs |
Menu loop, build logic, license generation |
console.rs |
Color output, input handling, progress bar |
charmap.rs |
Character map editor for license key alphabet |
pe.rs |
PE header parsing, .NET detection, architecture detection |
icon.rs |
Icon resource extraction from PE files |
ui.rs |
UI component helpers |
Build Flow
- User selects target executable
pe.rsdetects architecture (32/64-bit) and type (.NET / Native)- Correct stub DLL is selected (S32/S64/N32/N64 + UAC variants)
- Encryption key → PBKDF2 → 32-byte AES key
- Target PE is encrypted with AES-256-CBC
ConfigDatais populated (tool name, encryption key, flags)- Stub DLL is copied as
.exe, config bytes are patched in - Original icon is extracted and applied to the output
- Encrypted payload is appended as an overlay
Crate: stub
The protected loader that ships with the protected executable. Runs on end-user machines.
Modules
| Module | Purpose |
|---|---|
main.rs |
Entry point — license UI or direct run |
cfg.rs |
Reads ConfigData from the binary's embedded config region |
console.rs |
Console I/O for the license prompt |
hwid.rs |
Hardware ID generation (CPUID + volume serial) |
payload.rs |
Extracts encrypted overlay from the running executable |
runner.rs |
Dispatches to native or .NET loader based on PE type |
dotnet_loader.rs |
.NET in-memory loader via bootstrap process + pipe |
antidebug.rs |
Encryption key transforms when debugger is detected |
Execution Flow
main()
├── No License mode → run_program() silently
└── License mode → show UI → validate → run_program()
run_program()
├── load_payload() → extract encrypted PE from overlay
├── get_payload_key() → read AES key from config
├── antidebug transform → corrupt key if debugger present
├── verify_self_integrity → corrupt key if binary was tampered
├── aes256_cbc_decrypt() → decrypt the PE
├── verify MZ header → confirm valid PE
├── crc32 integrity check → confirm no corruption
├── is_dotnet_assembly() → detect PE type
└── run_payload()
├── .NET → dotnet_loader::run_dotnet_inmemory()
└── Native → native_impl::run_native_inproc()
.NET In-Memory Loading
The .NET loader avoids writing the decrypted assembly to disk:
- A platform-matched bootstrap EXE (
bootstrap_x86.exe/bootstrap_x64.exe) is embedded viainclude_bytes! - Bootstrap is written to app directory with Hidden+System attributes
- A pipe is created; the read end is inheritable
- Bootstrap is spawned via
CreateProcessWwithCREATE_NO_WINDOW - Decrypted assembly bytes are sent through the pipe
- Bootstrap reads from pipe, patches AMSI, calls
Assembly.Load(byte[]) - Bootstrap invokes the assembly's entry point
- Parent waits for child to exit, then deletes the bootstrap file
Native PE Loading
Native executables are handled with a simpler disk-drop approach:
- Decrypted PE is written to app directory with Hidden+System attributes
- Executed via
CreateProcessW - Parent waits for child to exit, then deletes the dropped file
Features (Cargo)
| Feature | Effect |
|---|---|
dotnet |
Includes .NET bootstrap binaries via include_bytes! |
uac |
Embeds UAC manifest requesting admin elevation |
Config Structure
ConfigData is a fixed-size binary struct embedded in the stub executable. The keygen patches this region after copying the stub.
| Field | Size | Purpose |
|---|---|---|
marker |
19 bytes | Magic bytes for locating config in binary |
flags |
1 byte | Bit flags (no_license, etc.) |
tool_name |
32 bytes | Application name (null-terminated) |
orig_ext |
16 bytes | Original file extension |
payload_key |
32 bytes | AES-256 encryption key |
enc_map |
32 bytes | License encoding character map |
integrity |
4 bytes | CRC32 of the decrypted payload |
self_hash |
20 bytes | SHA-1 of the stub for tamper detection |
License Format
Licenses are encoded as Base32-like strings using a customizable character map.
Encoding process:
- HWID is hashed to produce a binding value
- License metadata (type, expiry, value) is packed into bytes
- Binding + metadata are XOR'd with the encryption map
- Result is Base32-encoded with the character map
- Checksum is appended
Validation reverses this process and verifies the HWID binding matches.
Build Targets
| Target | Arch | Output |
|---|---|---|
x86_64-pc-windows-msvc |
64-bit | S64, N64, KeyGen |
i686-pc-windows-msvc |
32-bit | S32, N32 |
Each target can be built with --features uac and/or --features dotnet.
Tests
Run tests with:
cargo test -p kg_sharedTests cover: AES roundtrip, SHA-1/MD5 known vectors, CRC32, PBKDF2 determinism, license roundtrip for all types, HWID mismatch rejection, wrong-key rejection, expiration logic.
Made By ABOLHB
