Kelsidavis-WoWee/extract_warden_rsa.py
Kelsi ea69cac526 Add cross-platform x86 emulation via Unicorn Engine
Solves Linux execution limitation without Wine!

New Component: WardenEmulator
- Uses Unicorn Engine to emulate x86 CPU on any platform
- Can execute Windows Warden modules on Linux/macOS/ARM
- Provides sandboxed execution environment
- Intercepts Windows API calls with custom implementations

Features:
- CPU: x86 32-bit emulation via Unicorn
- Memory: Emulated address space (1MB stack, 16MB heap)
- API Hooks: VirtualAlloc, GetTickCount, ReadProcessMemory, etc.
- Safety: Module runs in isolated emulated environment
- Cross-platform: Works on Linux/macOS/Windows/ARM hosts

Architecture:
- Module code loaded into emulated memory at 0x400000
- Stack at 0x100000 (1MB)
- Heap at 0x200000 (16MB)
- API stubs at 0x70000000 (high memory)
- Intercept and provide Windows API implementations

Benefits vs Wine:
✓ Lightweight (no full Windows compatibility layer)
✓ Sandboxed (module can't harm host system)
✓ Cross-architecture (works on ARM, RISC-V, etc.)
✓ Full control over execution (can inspect/modify state)
✓ Easier debugging and analysis

Build:
- Added libunicorn-dev dependency
- Conditional compilation (HAVE_UNICORN)
- Falls back gracefully if Unicorn not available

Status: Infrastructure complete, ready for integration
Next: Connect WardenEmulator to WardenModule for real execution

Note: RSA modulus extraction script added but needs refinement
(current candidates are x86 code, not data section)
2026-02-12 03:01:36 -08:00

94 lines
3.2 KiB
Python
Executable file

#!/usr/bin/env python3
"""
Extract Warden RSA public key modulus from WoW 3.3.5a executable.
The RSA-2048 public key consists of:
- Exponent: 0x010001 (65537) - always the same
- Modulus: 256 bytes - hardcoded in WoW.exe
This script searches for the modulus by looking for known patterns.
"""
import sys
import struct
def find_warden_modulus(exe_path):
"""
Find Warden RSA modulus in WoW.exe
The modulus is typically stored as a 256-byte array in the .rdata or .data section.
It's near Warden-related code and often preceded by the exponent (0x010001).
"""
with open(exe_path, 'rb') as f:
data = f.read()
print(f"[*] Loaded {len(data)} bytes from {exe_path}")
# Search for RSA exponent (0x010001 = 65537)
# In little-endian: 01 00 01 00
exponent_pattern = b'\x01\x00\x01\x00'
print("[*] Searching for RSA exponent pattern (0x010001)...")
matches = []
offset = 0
while True:
offset = data.find(exponent_pattern, offset)
if offset == -1:
break
matches.append(offset)
offset += 1
print(f"[*] Found {len(matches)} potential exponent locations")
# For each match, check if there's a 256-byte modulus nearby
for exp_offset in matches:
# Modulus typically comes after exponent or within 256 bytes
for modulus_offset in range(max(0, exp_offset - 512), min(len(data), exp_offset + 512)):
# Check if we have space for 256 bytes
if modulus_offset + 256 > len(data):
continue
modulus_candidate = data[modulus_offset:modulus_offset + 256]
# Heuristic: RSA modulus should have high entropy (appears random)
# Check for non-zero bytes and variety
non_zero = sum(1 for b in modulus_candidate if b != 0)
unique_bytes = len(set(modulus_candidate))
if non_zero > 200 and unique_bytes > 100:
print(f"\n[+] Potential modulus at offset 0x{modulus_offset:08x} (near exponent at 0x{exp_offset:08x})")
print(f" Non-zero bytes: {non_zero}/256")
print(f" Unique bytes: {unique_bytes}")
print(f" First 32 bytes: {modulus_candidate[:32].hex()}")
print(f" Last 32 bytes: {modulus_candidate[-32:].hex()}")
# Check if it looks like a valid RSA modulus (high bit set)
if modulus_candidate[-1] & 0x80:
print(f" [✓] High bit set (typical for RSA modulus)")
else:
print(f" [!] High bit not set (unusual)")
# Write to C++ array format
print(f"\n[*] C++ array format:")
print_cpp_array(modulus_candidate)
return None
def print_cpp_array(data):
"""Print byte array in C++ format"""
print("const uint8_t modulus[256] = {")
for i in range(0, 256, 16):
chunk = data[i:i+16]
hex_bytes = ', '.join(f'0x{b:02X}' for b in chunk)
print(f" {hex_bytes},")
print("};")
if __name__ == '__main__':
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <path_to_Wow.exe>")
sys.exit(1)
exe_path = sys.argv[1]
find_warden_modulus(exe_path)