FUA/patcher/apply_patches.py

137 lines
3.5 KiB
Python
Executable file

#!/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 <version> <patch_db.json>")
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()