Skip to content

Instantly share code, notes, and snippets.

@Randomblock1
Created March 8, 2026 05:00
Show Gist options
  • Select an option

  • Save Randomblock1/e6b9f46fbc170dac45df2920724eb976 to your computer and use it in GitHub Desktop.

Select an option

Save Randomblock1/e6b9f46fbc170dac45df2920724eb976 to your computer and use it in GitHub Desktop.
Metashape Pro patch
// gcc -shared -fPIC -o patcher.so patcher.c -ldl -O2
// Run with LD_PRELOAD=/path/to/patch.so metashape
#define _GNU_SOURCE
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
static const char* SIG_PRO =
"41 57 41 56 41 55 41 89 ?? 41 54 49 89 ?? 55 48 "
"89 ?? 53 48 89 ?? 48 89 ?? 48 83 EC 68";
typedef struct {
size_t length;
size_t capacity;
int32_t refcount;
int32_t padding;
char data[1];
} gnu_string_t;
struct license_result_pro {
int32_t status;
int32_t padding;
char* message_ptr;
};
static struct license_result_pro*
validator_proxy_pro(struct license_result_pro* res) {
res->status = 0;
gnu_string_t* s = calloc(1, sizeof(*s) + 7);
if (s) {
s->refcount = 0x7FFFFFFF;
s->data[0] = '\0';
res->message_ptr = s->data;
}
return res;
}
static uintptr_t find_pattern(const char* module, const char* pattern) {
uint8_t bytes[64];
bool mask[64];
size_t n = 0;
for (size_t i = 0, len = strlen(pattern); i < len; i++) {
if (pattern[i] == ' ')
continue;
if (pattern[i] == '?') {
mask[n] = false;
bytes[n] = 0;
if (pattern[i + 1] == '?')
i++;
} else {
mask[n] = true;
bytes[n] = (uint8_t)strtol(&pattern[i], NULL, 16);
i++;
}
n++;
}
uintptr_t result = 0;
FILE* maps = fopen("/proc/self/maps", "r");
if (!maps)
return 0;
char line[512];
while (fgets(line, sizeof(line), maps)) {
if (!strstr(line, "r-xp") || !strstr(line, module))
continue;
uintptr_t start, end;
sscanf(line, "%lx-%lx", &start, &end);
for (size_t i = 0; i < (end - start) - n; i++) {
bool found = true;
for (size_t j = 0; j < n; j++) {
if (mask[j] && ((uint8_t*)start)[i + j] != bytes[j]) {
found = false;
break;
}
}
if (found) {
result = start + i;
break;
}
}
if (result)
break;
}
fclose(maps);
return result;
}
__attribute__((constructor)) static void initialize_module(void) {
char path[512];
ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1);
if (len == -1)
return;
path[len] = '\0';
if (!strstr(path, "metashape") || strstr(path, "crashreporter"))
return;
printf("[*] Patcher: Context %s\n", path);
size_t pg = sysconf(_SC_PAGESIZE);
uintptr_t target_pro = find_pattern("metashape", SIG_PRO);
if (target_pro) {
printf("[+] Patcher: Detected Professional Edition at 0x%lx\n", target_pro);
uintptr_t proxy_func = (uintptr_t)validator_proxy_pro;
uint8_t jmp[12] = {0x48, 0xB8, [10] = 0xFF, [11] = 0xE0};
memcpy(&jmp[2], &proxy_func, 8);
void* base = (void*)(target_pro & ~(pg - 1));
mprotect(base, pg * 2, PROT_READ | PROT_WRITE | PROT_EXEC);
memcpy((void*)target_pro, jmp, sizeof(jmp));
mprotect(base, pg * 2, PROT_READ | PROT_EXEC);
printf("[+] Patcher: Successfully redirected license check.\n");
return;
}
fprintf(stderr,
"[!] Patcher: Failed to locate any known validator signature.\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment