Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

  1. Reads the WoW executable
  2. Detects client type and version
  3. Replaces embedded URLs (portal, version, CDNs)
  4. Replaces cryptographic keys (RSA modulus, Ed25519 public key)
  5. 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

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

ArgumentDescriptionRequiredDefault
-l, --warcraft-exePath to WoW executableYes (auto-detected on macOS)-
-o, --output-fileOutput file pathNoArctium

Optional Flags

FlagDescription
-h, --helpShow help message
-v, --verbosePrint detailed output
-n, --dry-runPreview changes without writing
-s, --strip-binary-codesignRemove 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:

KeySizeRestrictions
RSA256 bytesNot all zeros, not all identical bytes
Ed2551932 bytesNot 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):

  1. ConnectTo pattern (8 bytes signature)
  2. Signature pattern (8 bytes signature)
  3. 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):

  1. v1: http://%s.patch.battle.net:1119/%s/versions (43 bytes)
  2. v2: https://%s.version.battle.net/v2/products/%s/versions (53 bytes)
  3. 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 FormatPatchable 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:

  1. Size: Should be identical to input (patcher does not add or remove bytes)
  2. Permissions: Unix executables have 0o755 permissions
  3. Code Signing: macOS binaries preserve signatures unless strip_codesign is enabled