wow-patcher
World of Warcraft client patcher for TrinityCore-based private servers.
What It Does
wow-patcher modifies WoW client binaries on disk to enable connections to private servers. It replaces embedded URLs and cryptographic keys with your server’s configuration.
Key difference: This tool modifies files on disk. It does not modify running processes (unlike runtime patchers).
Supported Clients
- Retail
- Classic
- Classic Era
Supported Platforms
- Windows (PE binaries)
- macOS (Mach-O binaries)
- Linux (ELF binaries)
How It Works
- Reads the WoW executable
- Detects client type and version
- Replaces embedded URLs (portal, version, CDNs)
- Replaces cryptographic keys (RSA modulus, Ed25519 public key)
- Writes patched executable to new file
Quick Start
CLI
cargo build --release
./target/release/wow-patcher -l /path/to/Wow.exe -o Wow-patched.exe
Library
#![allow(unused)]
fn main() {
use wow_patcher::Patcher;
Patcher::new("Wow.exe")
.output("Wow-patched.exe")
.trinity_core_keys()
.patch()?;
}
Next Steps
- Usage - Command-line interface
- Library API - Rust crate integration
- Configuration - Keys and CDNs
- Patches - What gets modified
Usage
Installation
Build from source:
cargo build --release
The binary will be at target/release/wow-patcher.
Basic Command
wow-patcher -l /path/to/Wow.exe -o Wow-patched.exe
Arguments
| Argument | Description | Required | Default |
|---|---|---|---|
-l, --warcraft-exe | Path to WoW executable | Yes (auto-detected on macOS) | - |
-o, --output-file | Output file path | No | Arctium |
Optional Flags
| Flag | Description |
|---|---|
-h, --help | Show help message |
-v, --verbose | Print detailed output |
-n, --dry-run | Preview changes without writing |
-s, --strip-binary-codesign | Remove macOS code signing (default: true) |
Custom Keys
Use TrinityCore defaults:
wow-patcher -l Wow.exe -o Wow-patched.exe
Load keys from files:
wow-patcher -l Wow.exe -o Wow-patched.exe \
--rsa-file /path/to/rsa.bin \
--ed25519-file /path/to/ed25519.bin
Load keys from hex strings:
wow-patcher -l Wow.exe -o Wow-patched.exe \
--rsa-hex "91D59BB7D4E183A5..." \
--ed25519-hex "15D618BD7DB577BD..."
Custom CDN
Replace version and CDN URLs:
wow-patcher -l Wow.exe -o Wow-patched.exe \
--version-url "https://my-cdn.example.com/versions" \
--cdns-url "https://my-cdn.example.com/cdns"
macOS Code Signing
The CLI strips macOS code signatures by default (--strip-binary-codesign defaults to true). This is required for patched binaries to run on macOS.
To keep the code signature (not recommended):
wow-patcher -l Wow.exe -s=false
Dry Run
Preview what will change:
wow-patcher --dry-run -l Wow.exe -o Wow-patched.exe
Verbose Output
See details about each patch operation:
wow-patcher -v -l Wow.exe -o Wow-patched.exe
Library API
Cargo.toml
Add to your Cargo.toml:
[dependencies]
wow-patcher = "0.1"
Enable CLI feature if needed:
wow-patcher = { version = "0.1", features = ["cli"] }
Basic Usage
use wow_patcher::Patcher;
fn main() -> Result<(), Box<dyn std::error::Error>> {
Patcher::new("Wow.exe")
.patch()?;
Ok(())
}
Builder API
Input and Output
#![allow(unused)]
fn main() {
Patcher::new("Wow.exe")
.output("Wow-patched.exe") // Optional, auto-generated if not set
.patch()?;
}
Keys
TrinityCore Defaults
#![allow(unused)]
fn main() {
Patcher::new("Wow.exe")
.trinity_core_keys()
.patch()?;
}
Custom Keys from Bytes
#![allow(unused)]
fn main() {
let rsa_key: Vec<u8> = /* 256 bytes */;
let ed25519_key: Vec<u8> = /* 32 bytes */;
Patcher::new("Wow.exe")
.custom_keys(&rsa_key, &ed25519_key)?
.patch()?;
}
Custom Keys from Hex
#![allow(unused)]
fn main() {
Patcher::new("Wow.exe")
.custom_keys_from_hex(
"AA00BB11...", // RSA (512 hex chars = 256 bytes)
"CC22DD33...", // Ed25519 (64 hex chars = 32 bytes)
)?
.patch()?;
}
Custom Keys from Files
#![allow(unused)]
fn main() {
Patcher::new("Wow.exe")
.custom_keys_from_files(
"/path/to/rsa.bin",
"/path/to/ed25519.bin",
)?
.patch()?;
}
CDN URLs
#![allow(unused)]
fn main() {
Patcher::new("Wow.exe")
.version_url("https://my-cdn.example.com/versions")
.cdns_url("https://my-cdn.example.com/cdns")
.patch()?;
}
Options
#![allow(unused)]
fn main() {
Patcher::new("Wow.exe")
.dry_run(true) // Preview changes
.strip_codesign(true) // Remove macOS code signature
.verbose(true) // Print details
.patch()?;
}
Error Handling
#![allow(unused)]
fn main() {
use wow_patcher::{Patcher, WowPatcherError};
fn patch() -> Result<(), WowPatcherError> {
match Patcher::new("Wow.exe").patch() {
Ok(_) => println!("Success"),
Err(e) => eprintln!("Error: {}", e),
}
Ok(())
}
}
Key Validation
Keys must meet these requirements:
| Key | Size | Restrictions |
|---|---|---|
| RSA | 256 bytes | Not all zeros, not all identical bytes |
| Ed25519 | 32 bytes | Not all zeros, not all identical bytes |
Validation occurs when KeyConfig is created or loaded.
Configuration
Keys
What Keys Do
wow-patcher replaces cryptographic keys embedded in the WoW executable. These keys are used to verify server certificates and establish encrypted connections.
Key Types
RSA Modulus
- Size: 256 bytes
- Purpose: Verifies server certificate during TLS handshake
- Required: Yes
Ed25519 Public Key
- Size: 32 bytes
- Purpose: Alternative signature verification for some protocols
- Required: For Retail and Classic (optional for Classic Era)
Key Sources
TrinityCore Defaults
The patcher includes default keys for TrinityCore servers. Use these if your server uses standard TrinityCore configuration:
#![allow(unused)]
fn main() {
Patcher::new("Wow.exe")
.trinity_core_keys()
.patch()?;
}
Custom Keys
Generate keys for your server:
# RSA private key (TrinityCore uses this)
openssl genrsa -out server.key 2048
# Extract public modulus (256 bytes)
openssl rsa -in server.key -modulus -noout | sed 's/Modulus=//' | xxd -r -p
For Ed25519:
# Generate Ed25519 key pair
openssl genpkey -algorithm ed25519 -out ed25519.key
# Extract public key (32 bytes)
openssl pkey -in ed25519.key -pubout -outform DER | tail -c 32
Key Validation
All keys must pass these checks:
- Correct size (256 bytes for RSA, 32 bytes for Ed25519)
- Not all zeros
- Not all identical bytes (entropy check)
Invalid keys cause a validation error before patching begins.
Key Storage
CLI accepts keys from files:
wow-patcher -l Wow.exe \
--rsa-file /path/to/rsa.key \
--ed25519-file /path/to/ed25519.key
Library accepts keys via Patcher builder methods:
- Bytes:
.custom_keys(&rsa, &ed25519)? - Hex strings:
.custom_keys_from_hex(rsa_hex, ed25519_hex)? - Files:
.custom_keys_from_files(rsa_path, ed25519_path)?
KeyConfig is also available for direct key management via KeyConfig::new(), KeyConfig::from_hex(), and KeyConfig::from_files().
CDN URLs
What CDNs Do
CDN URLs tell the client where to download game updates and configuration files.
URL Types
Portal URL
- Default:
https://us.actual.battle.net - Replaced with: Null bytes (disabled)
- Required: Yes
The patcher disables the portal URL to prevent the client from connecting to Blizzard’s servers.
Version URL
- Default:
https://us.version.battle.net/v2/products/wow/versions - Purpose: Fetches version information
- Required: No (optional)
CDNs URL
- Default:
https://us.cdn.battle.net/1119/wow/cdns - Purpose: Fetches CDN configuration
- Required: No (optional)
Default URLs
When no custom URLs are provided, the patcher uses Arctium CDN defaults:
#![allow(unused)]
fn main() {
let version_url = "http://cdn.arctium.io/versions";
let cdns_url = "http://cdn.arctium.io/cdns";
}
Custom URLs
Set your own CDN:
wow-patcher -l Wow.exe \
--version-url "https://my-cdn.example.com/versions" \
--cdns-url "https://my-cdn.example.com/cdns"
Or via library:
#![allow(unused)]
fn main() {
Patcher::new("Wow.exe")
.version_url("https://my-cdn.example.com/versions")
.cdns_url("https://my-cdn.example.com/cdns")
.patch()?;
}
Unified API (v3)
Newer WoW clients use a unified version API. If detected, the patcher uses the v3 pattern and ignores the separate CDNs URL.
Patches
What Gets Modified
The patcher replaces specific byte patterns in the WoW executable. These patterns represent embedded configuration.
Mandatory Patches
Portal URL
Pattern: .actual.battle.net (18 bytes)
Replacement: Null bytes (0x00 repeated)
Purpose: Disables connection to Blizzard’s portal server
Status: Must be found for patching to succeed
RSA Modulus
Patterns (tried in order):
- ConnectTo pattern (8 bytes signature)
- Signature pattern (8 bytes signature)
- Crypto pattern (8 bytes signature)
Replacement: Your 256-byte RSA modulus
Purpose: Changes which server certificates are trusted
Status: Must be found for patching to succeed
Note: The patcher searches for 8-byte signatures to locate the full 256-byte RSA modulus in the binary.
Optional Patches
Ed25519 Public Key
Pattern: Crypto Ed25519 signature (8 bytes)
Replacement: Your 32-byte Ed25519 public key
Purpose: Alternative signature verification
Status: Optional, warning if not found
Version URL
Patterns (tried in order):
- v1:
http://%s.patch.battle.net:1119/%s/versions(43 bytes) - v2:
https://%s.version.battle.net/v2/products/%s/versions(53 bytes) - v3:
https://%s.version.battle.net/v2/products/%s/%s(48 bytes)
Replacement: Your custom version URL (or Arctium default)
Purpose: Changes where the client fetches version information
Status: Optional, warning if not found
CDNs URL
Pattern: http://%s.patch.battle.net:1119/%s/cdns (40 bytes)
Replacement: Your custom CDN URL (or Arctium default)
Purpose: Changes where the client fetches CDN configuration
Status: Optional, warning if not found
Note: Skipped if v3 unified API is detected (the v3 pattern handles both).
Patch Locations
The patcher verifies that all patterns are found in patchable sections of the binary:
| Binary Format | Patchable Sections |
|---|---|
| PE (Windows) | .rdata, .data |
| Mach-O (macOS) | __DATA, __DATA_CONST, __TEXT.__const |
| ELF (Linux) | .data |
Patterns found in code sections (.text, __TEXT) are rejected. This prevents accidental code modification.
Dry Run
Preview what will change before patching:
wow-patcher --dry-run -l Wow.exe -o Wow-patched.exe
Dry run shows:
- Client type and detected version
- All patterns found and their locations
- Replacement values that will be written
What Is Not Patched
These patterns are defined in the code but not used:
- Certificate Bundle: The patcher does not replace Blizzard’s certificate bundle with custom certificates. This feature from the reference implementation (Arctium) requires runtime patching.
Verification
After patching, verify the output file:
- Size: Should be identical to input (patcher does not add or remove bytes)
- Permissions: Unix executables have
0o755permissions - Code Signing: macOS binaries preserve signatures unless
strip_codesignis enabled