#!/usr/bin/env python3 """ Maya License Patcher - Python Implementation Properly patches Maya licensing libraries with version-aware binary patches """ import sys import os import json import struct import shutil from pathlib import Path def log(msg): print(f"[PATCHER] {msg}") def hex_to_bytes(hex_str): """Convert hex string to bytes""" return bytes.fromhex(hex_str.replace(':', '').replace(' ', '')) def find_signature(buffer, signature): """Find signature in buffer, return offset or -1""" sig = hex_to_bytes(signature) for i in range(len(buffer) - len(sig) + 1): if buffer[i:i+len(sig)] == sig: return i return -1 def apply_patch(buffer, patch): """Apply a single patch to buffer, return True if applied""" sig = patch.get('signature', '') repl = patch.get('replacement', '') desc = patch.get('description', 'Unknown') if not sig or not repl: log(f" Skipping patch with missing data: {desc}") return False sig_bytes = hex_to_bytes(sig) repl_bytes = hex_to_bytes(repl) offset = find_signature(buffer, sig) if offset == -1: log(f" NOT FOUND: {desc}") return False # Apply patch buffer[offset:offset+len(repl_bytes)] = repl_bytes log(f" APPLIED: {desc} at offset 0x{offset:x}") return True def patch_library(lib_path, patches): """Patch a library file with given patches""" log(f"Patching: {lib_path}") # Read library with open(lib_path, 'rb') as f: buffer = bytearray(f.read()) log(f" File size: {len(buffer):,} bytes") # Create backup backup_path = f"{lib_path}.backup" shutil.copy2(lib_path, backup_path) log(f" Backup created: {backup_path}") # Apply patches applied = 0 not_found = 0 for patch in patches: if apply_patch(buffer, patch): applied += 1 else: not_found += 1 # Write patched library with open(lib_path, 'wb') as f: f.write(buffer) log(f" Patches applied: {applied}, not found: {not_found}") return applied, not_found def load_patch_db(db_path): """Load patch database from JSON""" with open(db_path, 'r') as f: return json.load(f) def main(): if len(sys.argv) < 3: print("Usage: apply_patches.py ") sys.exit(1) version = sys.argv[1] patch_db_path = sys.argv[2] log("=== Maya License Patcher ===") log(f"Target version: {version}") # Load patch database db = load_patch_db(patch_db_path) if version not in db.get('versions', {}): log(f"ERROR: Version {version} not found in patch database") sys.exit(1) version_data = db['versions'][version] lib_path = version_data.get('library') patches = version_data.get('patches', []) if not lib_path: log("ERROR: No library path specified") sys.exit(1) if not os.path.exists(lib_path): log(f"ERROR: Library not found: {lib_path}") sys.exit(1) log(f"Library: {lib_path}") log(f"Patches to apply: {len(patches)}") log("") # Apply patches applied, not_found = patch_library(lib_path, patches) log("") log("=== Patching Complete ===") if applied > 0: log(f"Successfully applied {applied} patches") sys.exit(0) else: log("No patches were applied!") sys.exit(1) if __name__ == "__main__": main()