Skip to content

Instantly share code, notes, and snippets.

@LukeZGD
Forked from mineek/main.c
Last active September 29, 2026 02:43
Show Gist options
  • Select an option

  • Save LukeZGD/244d7dc3f07ec98a4505e4084c5dbf6b to your computer and use it in GitHub Desktop.

Select an option

Save LukeZGD/244d7dc3f07ec98a4505e4084c5dbf6b to your computer and use it in GitHub Desktop.
patch restored external for iPhone X downgrades
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
// the following few functions are from patchfinder64
#define GET_OFFSET(len, x) (x - (uintptr_t) restored_external)
typedef unsigned long long addr_t;
static uint32_t arm64_branch_instruction(uintptr_t from, uintptr_t to) {
return from > to ? 0x18000000 - (from - to) / 4 : 0x14000000 + (to - from) / 4;
}
static addr_t
xref64(const uint8_t *buf, addr_t start, addr_t end, addr_t what)
{
addr_t i;
uint64_t value[32];
memset(value, 0, sizeof(value));
end &= ~3;
for (i = start & ~3; i < end; i += 4) {
uint32_t op = *(uint32_t *)(buf + i);
unsigned reg = op & 0x1F;
if ((op & 0x9F000000) == 0x90000000) {
signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
//printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF));
value[reg] = ((long long)adr << 1) + (i & ~0xFFF);
continue; // XXX should not XREF on its own?
/*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {
unsigned rd = op & 0x1F;
unsigned rm = (op >> 16) & 0x1F;
//printf("%llx: MOV X%d, X%d\n", i, rd, rm);
value[rd] = value[rm];*/
} else if ((op & 0xFF000000) == 0x91000000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned shift = (op >> 22) & 3;
unsigned imm = (op >> 10) & 0xFFF;
if (shift == 1) {
imm <<= 12;
} else {
//assert(shift == 0);
if (shift > 1) continue;
}
//printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm);
value[reg] = value[rn] + imm;
} else if ((op & 0xF9C00000) == 0xF9400000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned imm = ((op >> 10) & 0xFFF) << 3;
//printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
if (!imm) continue; // XXX not counted as true xref
value[reg] = value[rn] + imm; // XXX address, not actual value
/*} else if ((op & 0xF9C00000) == 0xF9000000) {
unsigned rn = (op >> 5) & 0x1F;
unsigned imm = ((op >> 10) & 0xFFF) << 3;
//printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm);
if (!imm) continue; // XXX not counted as true xref
value[rn] = value[rn] + imm; // XXX address, not actual value*/
} else if ((op & 0x9F000000) == 0x10000000) {
signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);
//printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i);
value[reg] = ((long long)adr >> 11) + i;
} else if ((op & 0xFF000000) == 0x58000000) {
unsigned adr = (op & 0xFFFFE0) >> 3;
//printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i);
value[reg] = adr + i; // XXX address, not actual value
}
if (value[reg] == what) {
return i;
}
}
return 0;
}
static addr_t
bof64(const uint8_t *buf, addr_t start, addr_t where)
{
for (; where >= start; where -= 4) {
uint32_t op = *(uint32_t *)(buf + where);
if ((op & 0xFFC003FF) == 0x910003FD) {
unsigned delta = (op >> 10) & 0xFFF;
//printf("%x: ADD X29, SP, #0x%x\n", where, delta);
if ((delta & 0xF) == 0) {
addr_t prev = where - ((delta >> 4) + 1) * 4;
uint32_t au = *(uint32_t *)(buf + prev);
if ((au & 0xFFC003E0) == 0xA98003E0) {
//printf("%x: STP x, y, [SP,#-imm]!\n", prev);
return prev;
}
// try something else
while (where > start) {
where -= 4;
au = *(uint32_t *)(buf + where);
// SUB SP, SP, #imm
if ((au & 0xFFC003FF) == 0xD10003FF && ((au >> 10) & 0xFFF) == delta + 0x10) {
return where;
}
// STP x, y, [SP,#imm]
if ((au & 0xFFC003E0) != 0xA90003E0) {
where += 4;
break;
}
}
}
}
}
return 0;
}
uint32_t* find_next_insn(uint32_t* from, uint32_t num, uint32_t insn, uint32_t mask)
{
while(num)
{
// printf("from: %p, num: %d, insn: %x, mask: %x\n", from, num, insn, mask);
if((*from & mask) == (insn & mask))
{
return from;
}
from++;
num--;
}
return NULL;
}
uint32_t* find_prev_insn(uint32_t* from, uint32_t num, uint32_t insn, uint32_t mask)
{
while(num)
{
if((*from & mask) == (insn & mask))
{
return from;
}
from--;
num--;
}
return NULL;
}
int get_faceid_patch(void *restored_external, size_t len) {
printf("getting %s()\n", __FUNCTION__);
void *str_ref = memmem(restored_external, len, "refFrame", strlen("refFrame"));
if (!str_ref) {
printf("[-] Failed to find string refFrame\n");
return -1;
}
addr_t xref = xref64(restored_external, 0, len, GET_OFFSET(len, (uintptr_t)str_ref));
if (!xref) {
printf("[-] Failed to find xref to refFrame\n");
return -1;
}
// printf("[+] Found xref to refFrame at 0x%llx\n", xref);
// go to the next ret
uint32_t *insn = find_next_insn((uint32_t *)(restored_external + xref), 0x300, 0xD65F03C0, 0xFFFFFFFF);
if (!insn) {
printf("[-] Failed to find next ret\n");
return -1;
}
// printf("[+] Found next ret at 0x%lx\n", (uintptr_t)insn - (uintptr_t)restored_external);
insn = find_prev_insn(insn, 0x100, 0xAA000000, 0xFF000000);
if (!insn) {
printf("[-] Failed to find prev mov\n");
return -1;
}
// printf("[+] Found prev mov at 0x%lx\n", (uintptr_t)insn - (uintptr_t)restored_external);
printf("[+] Patching decompressReferenceFrames patch point at 0x%lx\n", (uintptr_t)insn - (uintptr_t)restored_external);
*insn = 0xD2800000; // mov x0, #0
printf("[+] Patched decompressReferenceFrames\n");
return 0;
}
int main(int argc, char* argv[]) {
printf("restored patcher by @mineekdev\n");
if (argc < 3) {
printf("usage: %s <restored_external> <restored_external.patched>\n", argv[0]);
return -1;
}
char *in = argv[1];
char *out = argv[2];
void *restored_external;
size_t len;
FILE* fp = fopen(in, "rb");
if (!fp) {
printf("failed to open %s, does it exist?\n", in);
return -1;
}
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fseek(fp, 0, SEEK_SET);
restored_external = (void*)malloc(len);
if(!restored_external) {
printf("malloc failed\n");
fclose(fp);
return -1;
}
fread(restored_external, 1, len, fp);
fclose(fp);
get_faceid_patch(restored_external, len);
printf("Patched file to %s\n", out);
fp = fopen(out, "wb+");
fwrite(restored_external, 1, len, fp);
fflush(fp);
fclose(fp);
free(restored_external);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment