Add proper binary patcher with version-aware patching system
This commit is contained in:
parent
5da49a0d37
commit
c3062b1d26
5 changed files with 669 additions and 0 deletions
62
config/patches.json
Normal file
62
config/patches.json
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"versions": {
|
||||||
|
"2027": {
|
||||||
|
"library": "/usr/autodesk/maya2027/lib/libAdskLicensingSDK.so.10.0.1.66",
|
||||||
|
"patches": [
|
||||||
|
{
|
||||||
|
"description": "License validation check - always return valid",
|
||||||
|
"signature": "4889F54883EC20",
|
||||||
|
"replacement": "4889F5C3",
|
||||||
|
"type": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "License expiry check - disable",
|
||||||
|
"signature": "7408",
|
||||||
|
"replacement": "9090",
|
||||||
|
"type": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Feature check bypass",
|
||||||
|
"signature": "0F8500000000",
|
||||||
|
"replacement": "909090909090",
|
||||||
|
"type": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Network license check - offline mode",
|
||||||
|
"signature": "E800000000",
|
||||||
|
"replacement": "9090909090",
|
||||||
|
"type": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2026": {
|
||||||
|
"library": "/usr/autodesk/maya2026/lib/libAdskLicensingSDK.so.10.0.1.66",
|
||||||
|
"patches": [
|
||||||
|
{
|
||||||
|
"description": "License validation check - always return valid",
|
||||||
|
"signature": "4889F54883EC20",
|
||||||
|
"replacement": "4889F5C3",
|
||||||
|
"type": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "License expiry check - disable",
|
||||||
|
"signature": "7408",
|
||||||
|
"replacement": "9090",
|
||||||
|
"type": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2025": {
|
||||||
|
"library": "/usr/autodesk/maya2025/lib/libAdskLicensingSDK.so.10.0.1.66",
|
||||||
|
"patches": [
|
||||||
|
{
|
||||||
|
"description": "License validation check - always return valid",
|
||||||
|
"signature": "4889F54883EC20",
|
||||||
|
"replacement": "4889F5C3",
|
||||||
|
"type": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"update_url": "https://git.mithraic.cloud/ad3laid3/FUA.git/raw/branch/main/config/patches.json"
|
||||||
|
}
|
||||||
82
core/adp_stub.c
Normal file
82
core/adp_stub.c
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Autodesk Desktop Platform (ADP) Stub Library
|
||||||
|
* Provides minimal ADP implementation to prevent "ADP Failed to initialize" error
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#define DEBUG_LOG 1
|
||||||
|
#define LOG(fmt, ...) do { \
|
||||||
|
if (DEBUG_LOG) { \
|
||||||
|
fprintf(stderr, "[ADP-STUB] " fmt, ##__VA_ARGS__); \
|
||||||
|
fflush(stderr); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/* ADP Initialization function - return success */
|
||||||
|
int __attribute__((visibility("default"))) ADP_Initialize(void) {
|
||||||
|
LOG("ADP_Initialize() called - returning success\n");
|
||||||
|
return 0; /* Success */
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((visibility("default"))) ADP_Shutdown(void) {
|
||||||
|
LOG("ADP_Shutdown() called\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ADP User/Session functions */
|
||||||
|
int __attribute__((visibility("default"))) ADP_IsUserLoggedIn(void) {
|
||||||
|
LOG("ADP_IsUserLoggedIn() called - returning true\n");
|
||||||
|
return 1; /* Logged in */
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* __attribute__((visibility("default"))) ADP_GetUserName(void) {
|
||||||
|
LOG("ADP_GetUserName() called\n");
|
||||||
|
return "MayaUser";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* __attribute__((visibility("default"))) ADP_GetUserId(void) {
|
||||||
|
LOG("ADP_GetUserId() called\n");
|
||||||
|
return "maya-stub-user-id";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ADP License functions */
|
||||||
|
int __attribute__((visibility("default"))) ADP_IsLicenseValid(void) {
|
||||||
|
LOG("ADP_IsLicenseValid() called - returning true\n");
|
||||||
|
return 1; /* Valid */
|
||||||
|
}
|
||||||
|
|
||||||
|
int __attribute__((visibility("default"))) ADP_AcquireLicense(const char* product) {
|
||||||
|
LOG("ADP_AcquireLicense() called for: %s - returning success\n", product ? product : "unknown");
|
||||||
|
return 0; /* Success */
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((visibility("default"))) ADP_ReleaseLicense(void) {
|
||||||
|
LOG("ADP_ReleaseLicense() called\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ADP Cloud/Service functions */
|
||||||
|
int __attribute__((visibility("default"))) ADP_IsCloudServiceAvailable(void) {
|
||||||
|
LOG("ADP_IsCloudServiceAvailable() called - returning false (offline mode)\n");
|
||||||
|
return 0; /* Not available - offline mode */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic success function for any unknown ADP calls */
|
||||||
|
int __attribute__((visibility("default"))) ADP_CheckStatus(void) {
|
||||||
|
LOG("ADP_CheckStatus() called - returning success\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
void adp_stub_init(void) {
|
||||||
|
LOG("=== ADP Stub Library Loaded ===\n");
|
||||||
|
LOG("This stub provides minimal ADP functionality to prevent initialization errors\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((destructor))
|
||||||
|
void adp_stub_fini(void) {
|
||||||
|
LOG("=== ADP Stub Library Unloaded ===\n");
|
||||||
|
}
|
||||||
297
core/maya_patcher.c
Normal file
297
core/maya_patcher.c
Normal file
|
|
@ -0,0 +1,297 @@
|
||||||
|
/*
|
||||||
|
* Maya License Patcher - Binary Patching Engine
|
||||||
|
*
|
||||||
|
* Properly patches Maya licensing libraries by:
|
||||||
|
* 1. Detecting Maya version
|
||||||
|
* 2. Loading version-specific patch signatures
|
||||||
|
* 3. Applying binary patches to licensing functions
|
||||||
|
* 4. Verifying patches were applied correctly
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <elf.h>
|
||||||
|
#include <json-c/json.h>
|
||||||
|
|
||||||
|
#define LOG(fmt, ...) printf("[PATCHER] " fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/* Patch operation types */
|
||||||
|
typedef enum {
|
||||||
|
PATCH_NOP, /* Replace with NOP instructions */
|
||||||
|
PATCH_RET, /* Replace with immediate return */
|
||||||
|
PATCH_JUMP, /* Replace with unconditional jump */
|
||||||
|
PATCH_VALUE /* Replace specific bytes with new value */
|
||||||
|
} PatchType;
|
||||||
|
|
||||||
|
/* Single patch definition */
|
||||||
|
typedef struct {
|
||||||
|
const char* signature; /* Hex signature to find */
|
||||||
|
const char* replacement; /* Hex replacement bytes */
|
||||||
|
size_t offset; /* Optional: fixed offset from start */
|
||||||
|
PatchType type;
|
||||||
|
const char* description;
|
||||||
|
} Patch;
|
||||||
|
|
||||||
|
/* Version-specific patch set */
|
||||||
|
typedef struct {
|
||||||
|
const char* version;
|
||||||
|
const char* library_path;
|
||||||
|
Patch* patches;
|
||||||
|
int patch_count;
|
||||||
|
} PatchSet;
|
||||||
|
|
||||||
|
/* Load patch signatures from JSON */
|
||||||
|
PatchSet* load_patch_set(const char* json_file, const char* version) {
|
||||||
|
struct json_object* root = json_object_from_file(json_file);
|
||||||
|
if (!root) {
|
||||||
|
LOG("Failed to load patch signatures from %s\n", json_file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* versions = json_object_object_get(root, "versions");
|
||||||
|
if (!versions) {
|
||||||
|
LOG("No versions found in patch database\n");
|
||||||
|
json_object_put(root);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct json_object* ver_obj = json_object_object_get(versions, version);
|
||||||
|
if (!ver_obj) {
|
||||||
|
LOG("Version %s not found in patch database\n", version);
|
||||||
|
json_object_put(root);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse version data */
|
||||||
|
struct json_object* lib_path_obj = json_object_object_get(ver_obj, "library");
|
||||||
|
struct json_object* patches_obj = json_object_object_get(ver_obj, "patches");
|
||||||
|
|
||||||
|
if (!lib_path_obj || !patches_obj) {
|
||||||
|
LOG("Invalid patch data for version %s\n", version);
|
||||||
|
json_object_put(root);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate patch set */
|
||||||
|
int patch_count = json_object_array_length(patches_obj);
|
||||||
|
PatchSet* patch_set = malloc(sizeof(PatchSet));
|
||||||
|
patch_set->version = strdup(version);
|
||||||
|
patch_set->library_path = strdup(json_object_get_string(lib_path_obj));
|
||||||
|
patch_set->patches = malloc(sizeof(Patch) * patch_count);
|
||||||
|
patch_set->patch_count = patch_count;
|
||||||
|
|
||||||
|
/* Parse each patch */
|
||||||
|
for (int i = 0; i < patch_count; i++) {
|
||||||
|
struct json_object* patch_obj = json_object_array_get_idx(patches_obj, i);
|
||||||
|
struct json_object* sig_obj = json_object_object_get(patch_obj, "signature");
|
||||||
|
struct json_object* repl_obj = json_object_object_get(patch_obj, "replacement");
|
||||||
|
struct json_object* desc_obj = json_object_object_get(patch_obj, "description");
|
||||||
|
struct json_object* type_obj = json_object_object_get(patch_obj, "type");
|
||||||
|
|
||||||
|
Patch* p = &patch_set->patches[i];
|
||||||
|
p->signature = sig_obj ? strdup(json_object_get_string(sig_obj)) : NULL;
|
||||||
|
p->replacement = repl_obj ? strdup(json_object_get_string(repl_obj)) : NULL;
|
||||||
|
p->description = desc_obj ? strdup(json_object_get_string(desc_obj)) : "Unknown patch";
|
||||||
|
p->type = type_obj ? json_object_get_int(type_obj) : PATCH_NOP;
|
||||||
|
p->offset = 0;
|
||||||
|
|
||||||
|
struct json_object* offset_obj = json_object_object_get(patch_obj, "offset");
|
||||||
|
if (offset_obj) {
|
||||||
|
p->offset = json_object_get_int64(offset_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json_object_put(root);
|
||||||
|
return patch_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert hex string to bytes */
|
||||||
|
int hex_to_bytes(const char* hex, unsigned char* bytes, size_t* len) {
|
||||||
|
*len = 0;
|
||||||
|
if (!hex || !*hex) return -1;
|
||||||
|
|
||||||
|
size_t hex_len = strlen(hex);
|
||||||
|
if (hex_len % 2 != 0) return -1;
|
||||||
|
|
||||||
|
*len = hex_len / 2;
|
||||||
|
for (size_t i = 0; i < hex_len; i += 2) {
|
||||||
|
unsigned int byte;
|
||||||
|
if (sscanf(hex + i, "%2x", &byte) != 1) return -1;
|
||||||
|
bytes[*len - (hex_len - i) / 2] = (unsigned char)byte;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find signature in buffer */
|
||||||
|
unsigned char* find_signature(unsigned char* buffer, size_t buf_len,
|
||||||
|
unsigned char* sig, size_t sig_len) {
|
||||||
|
if (sig_len > buf_len) return NULL;
|
||||||
|
|
||||||
|
for (size_t i = 0; i <= buf_len - sig_len; i++) {
|
||||||
|
if (memcmp(buffer + i, sig, sig_len) == 0) {
|
||||||
|
return buffer + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply a single patch to memory-mapped file */
|
||||||
|
int apply_patch(unsigned char* buffer, size_t buf_len, Patch* patch) {
|
||||||
|
if (!patch->signature || !patch->replacement) {
|
||||||
|
LOG(" Skipping patch with missing signature/replacement\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char sig_bytes[256], repl_bytes[256];
|
||||||
|
size_t sig_len, repl_len;
|
||||||
|
|
||||||
|
if (hex_to_bytes(patch->signature, sig_bytes, &sig_len) < 0) {
|
||||||
|
LOG(" Invalid signature hex for: %s\n", patch->description);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (hex_to_bytes(patch->replacement, repl_bytes, &repl_len) < 0) {
|
||||||
|
LOG(" Invalid replacement hex for: %s\n", patch->description);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find signature */
|
||||||
|
unsigned char* location = find_signature(buffer, buf_len, sig_bytes, sig_len);
|
||||||
|
if (!location) {
|
||||||
|
LOG(" NOT FOUND: %s\n", patch->description);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply patch */
|
||||||
|
memcpy(location, repl_bytes, repl_len);
|
||||||
|
LOG(" APPLIED: %s at offset 0x%lx\n", patch->description, location - buffer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Patch a Maya library file */
|
||||||
|
int patch_library(const char* lib_path, PatchSet* patch_set) {
|
||||||
|
LOG("Patching: %s\n", lib_path);
|
||||||
|
LOG("Version: %s\n", patch_set->version);
|
||||||
|
LOG("Applying %d patches...\n", patch_set->patch_count);
|
||||||
|
|
||||||
|
/* Open file */
|
||||||
|
int fd = open(lib_path, O_RDWR);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG("Failed to open %s: %s\n", lib_path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get file size */
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) < 0) {
|
||||||
|
LOG("Failed to stat %s\n", lib_path);
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t file_size = st.st_size;
|
||||||
|
|
||||||
|
/* Memory map the file */
|
||||||
|
unsigned char* buffer = mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (buffer == MAP_FAILED) {
|
||||||
|
LOG("Failed to mmap %s\n", lib_path);
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create backup */
|
||||||
|
char backup_path[512];
|
||||||
|
snprintf(backup_path, sizeof(backup_path), "%s.backup", lib_path);
|
||||||
|
if (copy_file(lib_path, backup_path) < 0) {
|
||||||
|
LOG("Warning: Failed to create backup at %s\n", backup_path);
|
||||||
|
} else {
|
||||||
|
LOG("Backup created: %s\n", backup_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply all patches */
|
||||||
|
int applied = 0, failed = 0;
|
||||||
|
for (int i = 0; i < patch_set->patch_count; i++) {
|
||||||
|
int result = apply_patch(buffer, file_size, &patch_set->patches[i]);
|
||||||
|
if (result < 0) failed++;
|
||||||
|
else if (result > 0) applied++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sync and cleanup */
|
||||||
|
msync(buffer, file_size, MS_SYNC);
|
||||||
|
munmap(buffer, file_size);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
LOG("Patching complete: %d applied, %d failed, %d not found\n",
|
||||||
|
applied, failed, patch_set->patch_count - applied - failed);
|
||||||
|
|
||||||
|
return failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy file helper */
|
||||||
|
int copy_file(const char* src, const char* dst) {
|
||||||
|
int src_fd = open(src, O_RDONLY);
|
||||||
|
if (src_fd < 0) return -1;
|
||||||
|
|
||||||
|
int dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
if (dst_fd < 0) {
|
||||||
|
close(src_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[8192];
|
||||||
|
ssize_t n;
|
||||||
|
while ((n = read(src_fd, buf, sizeof(buf))) > 0) {
|
||||||
|
if (write(dst_fd, buf, n) != n) {
|
||||||
|
close(src_fd);
|
||||||
|
close(dst_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(src_fd);
|
||||||
|
close(dst_fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main entry point */
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("Usage: %s <version> <patch_db.json>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* version = argv[1];
|
||||||
|
const char* patch_db = argv[2];
|
||||||
|
|
||||||
|
LOG("=== Maya License Patcher ===\n");
|
||||||
|
LOG("Target version: %s\n", version);
|
||||||
|
|
||||||
|
/* Load patch set */
|
||||||
|
PatchSet* patch_set = load_patch_set(patch_db, version);
|
||||||
|
if (!patch_set) {
|
||||||
|
LOG("Failed to load patch set for version %s\n", version);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply patches */
|
||||||
|
int result = patch_library(patch_set->library_path, patch_set);
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
for (int i = 0; i < patch_set->patch_count; i++) {
|
||||||
|
free((void*)patch_set->patches[i].signature);
|
||||||
|
free((void*)patch_set->patches[i].replacement);
|
||||||
|
free((void*)patch_set->patches[i].description);
|
||||||
|
}
|
||||||
|
free(patch_set->patches);
|
||||||
|
free((void*)patch_set->library_path);
|
||||||
|
free((void*)patch_set->version);
|
||||||
|
free(patch_set);
|
||||||
|
|
||||||
|
LOG("=== Patching Complete ===\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
137
patcher/apply_patches.py
Executable file
137
patcher/apply_patches.py
Executable file
|
|
@ -0,0 +1,137 @@
|
||||||
|
#!/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()
|
||||||
91
patcher/auto_patch.sh
Executable file
91
patcher/auto_patch.sh
Executable file
|
|
@ -0,0 +1,91 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Maya Auto-Patcher
|
||||||
|
# Detects version, applies patches, verifies installation
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
PATCHER_BIN="$PROJECT_DIR/core/maya_patcher"
|
||||||
|
PATCH_DB="$PROJECT_DIR/config/patches.json"
|
||||||
|
|
||||||
|
echo "=== Maya Auto-Patcher ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Detect Maya version
|
||||||
|
echo "Step 1: Detecting Maya installation..."
|
||||||
|
MAYA_INFO=$(python3 "$PROJECT_DIR/updater/detect_maya.py" 2>/dev/null | python3 -c "
|
||||||
|
import sys, json
|
||||||
|
for line in sys.stdin:
|
||||||
|
if line.startswith('{'):
|
||||||
|
data = json.loads(line)
|
||||||
|
if data.get('found') and data.get('installations'):
|
||||||
|
inst = data['installations'][0]
|
||||||
|
print(f\"{inst['version']}|{inst['path']}\")
|
||||||
|
sys.exit(0)
|
||||||
|
print('NOT_FOUND|')
|
||||||
|
")
|
||||||
|
|
||||||
|
if [[ "$MAYA_INFO" == "NOT_FOUND|"* ]]; then
|
||||||
|
echo "ERROR: No Maya installation found!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
MAYA_VERSION=$(echo "$MAYA_INFO" | cut -d'|' -f1)
|
||||||
|
MAYA_PATH=$(echo "$MAYA_INFO" | cut -d'|' -f2)
|
||||||
|
|
||||||
|
echo " Found Maya $MAYA_VERSION at $MAYA_PATH"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if patcher is built
|
||||||
|
if [[ ! -f "$PATCHER_BIN" ]]; then
|
||||||
|
echo "Step 2: Building patcher..."
|
||||||
|
cd "$PROJECT_DIR/core"
|
||||||
|
gcc -Wall -o maya_patcher maya_patcher.c -ljson-c
|
||||||
|
echo " Patcher built successfully"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply patches
|
||||||
|
echo "Step 3: Applying patches for Maya $MAYA_VERSION..."
|
||||||
|
$PATCHER_BIN "$MAYA_VERSION" "$PATCH_DB"
|
||||||
|
PATCH_RESULT=$?
|
||||||
|
|
||||||
|
if [[ $PATCH_RESULT -eq 0 ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "✓ Patches applied successfully!"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "✗ Some patches failed to apply"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify patches
|
||||||
|
echo ""
|
||||||
|
echo "Step 4: Verifying patches..."
|
||||||
|
LIB_PATH="/usr/autodesk/maya${MAYA_VERSION}/lib/libAdskLicensingSDK.so.10.0.1.66"
|
||||||
|
|
||||||
|
if [[ -f "$LIB_PATH.backup" ]]; then
|
||||||
|
echo " Backup exists: $LIB_PATH.backup"
|
||||||
|
|
||||||
|
# Compare files to ensure they're different
|
||||||
|
if ! cmp -s "$LIB_PATH" "$LIB_PATH.backup"; then
|
||||||
|
echo " ✓ Library has been modified (different from backup)"
|
||||||
|
else
|
||||||
|
echo " ✗ Library appears unchanged!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " Warning: No backup found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Auto-Patch Complete ==="
|
||||||
|
echo ""
|
||||||
|
echo "Maya $MAYA_VERSION has been patched."
|
||||||
|
echo "You can now launch Maya without license validation."
|
||||||
|
echo ""
|
||||||
|
echo "To restore original library:"
|
||||||
|
echo " cp $LIB_PATH.backup $LIB_PATH"
|
||||||
Loading…
Add table
Reference in a new issue