/* * 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 #include #include #include #include #include #include #include #include #include #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 \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; }