Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions Kernel64Patcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
* gcc Kernel64Patcher.c -o Kernel64Patcher
*/

#ifdef __gnu_linux__
#define _GNU_SOURCE
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -11,6 +15,10 @@

#define GET_OFFSET(kernel_len, x) (x - (uintptr_t) kernel_buf)

static uint32_t arm64_branch_instruction(uintptr_t from, uintptr_t to) {
return from > to ? 0x18000000 - (from - to) / 4 : 0x14000000 + (to - from) / 4;
}

// iOS 15 "%s: firmware validation failed %d\" @%s:%d SPU Firmware Validation Patch
int get_SPUFirmwareValidation_patch(void *kernel_buf, size_t kernel_len) {
printf("%s: Entering ...\n",__FUNCTION__);
Expand Down Expand Up @@ -161,6 +169,127 @@ int get_AMFIInitializeLocalSigningPublicKey_patch(void* kernel_buf,size_t kernel
return 0;
}

//iOS 14 AppleFirmwareUpdate img4 signature check
int get_AppleFirmwareUpdate_img4_signature_check(void* kernel_buf,size_t kernel_len) {

printf("%s: Entering ...\n",__FUNCTION__);

char img4_sig_check_string[56] = "%s::%s() Performing img4 validation outside of workloop";
void* ent_loc = memmem(kernel_buf,kernel_len,img4_sig_check_string,55);
if(!ent_loc) {
printf("%s: Could not find \"%%s::%%s() Performing img4 validation outside of workloop\" string\n",__FUNCTION__);
return -1;
}
printf("%s: Found \"%%s::%%s() Performing img4 validation outside of workloop\" str loc at %p\n",__FUNCTION__,GET_OFFSET(kernel_len,ent_loc));
addr_t ent_ref = xref64(kernel_buf,0,kernel_len,(addr_t)GET_OFFSET(kernel_len, ent_loc));

if(!ent_ref) {
printf("%s: Could not find \"%%s::%%s() Performing img4 validation outside of workloop\" xref\n",__FUNCTION__);
return -1;
}
printf("%s: Found \"%%s::%%s() Performing img4 validation outside of workloop\" xref at %p\n",__FUNCTION__,(void*)ent_ref);

printf("%s: Patching \"%%s::%%s() Performing img4 validation outside of workloop\" at %p\n\n", __FUNCTION__,(void*)(ent_ref + 0xc));
*(uint32_t *) (kernel_buf + ent_ref + 0xc) = 0xD2800000;

return 0;
}

static addr_t
cbz_ref64_back(const uint8_t *buf, addr_t start, size_t length) {

//find cbz/cbnz
uint32_t cbz_mask = 0x7E000000;
uint32_t instr = 0;
uint32_t imm = 0;
addr_t cbz = start;
while (cbz) {
instr = *(uint32_t *) (buf + cbz);
if ((instr & cbz_mask) == 0x34000000) {
imm = ((instr & 0x00FFFFFF) >> 5) << 2;
if (cbz + imm == start)
return cbz;
}
cbz -= 4;
}
return 0;
}

//iOS 15 "could not authenticate personalized root hash!" patch
int get_could_not_authenticate_personalized_root_hash_patch(void* kernel_buf,size_t kernel_len) {

printf("%s: Entering ...\n", __FUNCTION__);

//get target offset for new branch
char roothash_authenticated_string[sizeof("successfully validated on-disk root hash")] = "successfully validated on-disk root hash";

unsigned char *roothash_authenticated_loc = memmem(kernel_buf, kernel_len, roothash_authenticated_string, sizeof("successfully validated on-disk root hash") - 1);
if(!roothash_authenticated_loc) {
printf("%s: Could not find \"%s\" string\n", __FUNCTION__, roothash_authenticated_string);
return -1;
}

for (; *roothash_authenticated_loc != 0; roothash_authenticated_loc--);
roothash_authenticated_loc++;
printf("%s: Found \"%s\" str loc at %p\n", __FUNCTION__, roothash_authenticated_string, GET_OFFSET(kernel_len, roothash_authenticated_loc));

addr_t roothash_authenticated_ref = xref64(kernel_buf,0,kernel_len,(addr_t)GET_OFFSET(kernel_len, roothash_authenticated_loc));
if(!roothash_authenticated_ref) {
printf("%s: Could not find \"%s\" xref\n",__FUNCTION__, roothash_authenticated_string);
return -1;
}
printf("%s: Found \"%s\" xref at %p\n",__FUNCTION__, roothash_authenticated_string, (void*) roothash_authenticated_ref);

//get previous cbz
addr_t branch_target = step64_back(kernel_buf, roothash_authenticated_ref, 20 * 4, 0x34000000, 0x7E000000);
if(!branch_target) {
printf("%s: Could not find previous cbz\n",__FUNCTION__);
return -1;
}
printf("%s: Found previous cbz at %p\n",__FUNCTION__, (void*) branch_target);
branch_target++;

//get patching offset for new branch
char roothash_failed_string[sizeof("could not authenticate personalized root hash!")] = "could not authenticate personalized root hash!";

unsigned char *roothash_failed_loc = memmem(kernel_buf, kernel_len, roothash_failed_string, sizeof("could not authenticate personalized root hash!") - 1);
if(!roothash_failed_loc) {
printf("%s: Could not find \"%s\" string\n", __FUNCTION__, roothash_failed_string);
return -1;
}

for (; *roothash_failed_loc != 0; roothash_failed_loc--);
roothash_failed_loc++;
printf("%s: Found \"%s\" str loc at %p\n", __FUNCTION__, roothash_failed_string, GET_OFFSET(kernel_len, roothash_failed_loc));

addr_t roothash_failed_ref = xref64(kernel_buf,0,kernel_len,(addr_t)GET_OFFSET(kernel_len, roothash_failed_loc));
if(!roothash_failed_ref) {
printf("%s: Could not find \"%s\" xref\n",__FUNCTION__, roothash_failed_string);
return -1;
}
printf("%s: Found \"%s\" xref at %p\n",__FUNCTION__, roothash_failed_string, (void*) roothash_failed_ref);

addr_t patch_loc = 0;

for (int i = 0; i < 16; i++, roothash_failed_ref -= 4) {
if (cbz_ref64_back(kernel_buf, roothash_failed_ref, roothash_failed_ref)) {
printf("%s: Found cbz target at %p\n", __FUNCTION__, (void*) roothash_failed_ref);
patch_loc = roothash_failed_ref;
break;
}
}

if (!patch_loc) {
printf("%s: Could not find cbz target\n",__FUNCTION__);
return -1;
}

printf("%s: Patching root hash check at %p\n",__FUNCTION__, (void*) patch_loc);
*((uint32_t *) (kernel_buf + patch_loc)) = arm64_branch_instruction((uintptr_t) patch_loc, (uintptr_t) branch_target);

return 0;
}

int get_amfi_out_of_my_way_patch(void* kernel_buf,size_t kernel_len) {

printf("%s: Entering ...\n",__FUNCTION__);
Expand Down Expand Up @@ -223,8 +352,10 @@ int main(int argc, char **argv) {
if(argc < 4){
printf("Usage: %s <kernel_in> <kernel_out> <args>\n",argv[0]);
printf("\t-a\t\tPatch AMFI\n");
printf("\t-f\t\tPatch AppleFirmwareUpdate img4 signature check\n");
printf("\t-s\t\tPatch SPUFirmwareValidation (iOS 15 Only)\n");
printf("\t-r\t\tPatch RootVPNotAuthenticatedAfterMounting (iOS 15 Only)\n");
printf("\t-o\t\tPatch could_not_authenticate_personalized_root_hash (iOS 15 Only)\n");
printf("\t-p\t\tPatch AMFIInitializeLocalSigningPublicKey (iOS 15 Only)\n");
return 0;
}
Expand Down Expand Up @@ -267,6 +398,10 @@ int main(int argc, char **argv) {
printf("Kernel: Adding AMFI_get_out_of_my_way patch...\n");
get_amfi_out_of_my_way_patch(kernel_buf,kernel_len);
}
if(strcmp(argv[i], "-f") == 0) {
printf("Kernel: Adding AppleFirmwareUpdate img4 signature check patch...\n");
get_AppleFirmwareUpdate_img4_signature_check(kernel_buf,kernel_len);
}
if(strcmp(argv[i], "-s") == 0) {
printf("Kernel: Adding SPUFirmwareValidation patch...\n");
get_SPUFirmwareValidation_patch(kernel_buf,kernel_len);
Expand All @@ -279,6 +414,10 @@ int main(int argc, char **argv) {
printf("Kernel: Adding RootVPNotAuthenticatedAfterMounting patch...\n");
get_RootVPNotAuthenticatedAfterMounting_patch(kernel_buf,kernel_len);
}
if(strcmp(argv[i], "-o") == 0) {
printf("Kernel: Adding could_not_authenticate_personalized_root_hash patch...\n");
get_could_not_authenticate_personalized_root_hash_patch(kernel_buf,kernel_len);
}
}

/* Write patched kernel */
Expand Down
174 changes: 0 additions & 174 deletions patchfinder64.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,8 +450,6 @@ xref64code(const uint8_t *buf, addr_t start, addr_t end, addr_t what)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <mach-o/loader.h>
//#include "vfs.h" // img4lib

#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
#include <mach/mach.h>
Expand Down Expand Up @@ -524,178 +522,6 @@ static addr_t kernel_entry = 0;
static void *kernel_mh = 0;
static addr_t kernel_delta = 0;

int
init_kernel(addr_t base, const char *filename)
{
size_t rv;
uint8_t buf[0x4000];
uint8_t *vstr;
unsigned i, j;
const struct mach_header *hdr = (struct mach_header *)buf;
FHANDLE fd = INVALID_HANDLE;
const uint8_t *q;
addr_t min = -1;
addr_t max = 0;
int is64 = 0;

if (filename == NULL) {
#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
rv = kread(base, buf, sizeof(buf));
if (rv != sizeof(buf) || !MACHO(buf)) {
return -1;
}
#else
(void)base;
return -1;
#endif
} else {
fd = OPEN(filename, O_RDONLY);
if (fd == INVALID_HANDLE) {
return -1;
}
rv = READ(fd, buf, sizeof(buf));
if (rv != sizeof(buf) || !MACHO(buf)) {
CLOSE(fd);
return -1;
}
}

if (IS64(buf)) {
is64 = 4;
}

q = buf + sizeof(struct mach_header) + is64;
for (i = 0; i < hdr->ncmds; i++) {
const struct load_command *cmd = (struct load_command *)q;
if (cmd->cmd == LC_SEGMENT_64 && ((struct segment_command_64 *)q)->vmsize) {
const struct segment_command_64 *seg = (struct segment_command_64 *)q;
if (min > seg->vmaddr) {
min = seg->vmaddr;
}
if (max < seg->vmaddr + seg->vmsize) {
max = seg->vmaddr + seg->vmsize;
}
if (!strcmp(seg->segname, "__TEXT_EXEC")) {
xnucore_base = seg->vmaddr;
xnucore_size = seg->filesize;
}
if (!strcmp(seg->segname, "__PLK_TEXT_EXEC")) {
prelink_base = seg->vmaddr;
prelink_size = seg->filesize;
}
if (!strcmp(seg->segname, "__PPLTEXT")) {
pplcode_base = seg->vmaddr;
pplcode_size = seg->filesize;
}
if (!strcmp(seg->segname, "__TEXT")) {
const struct section_64 *sec = (struct section_64 *)(seg + 1);
for (j = 0; j < seg->nsects; j++) {
if (!strcmp(sec[j].sectname, "__cstring")) {
cstring_base = sec[j].addr;
cstring_size = sec[j].size;
}
}
}
if (!strcmp(seg->segname, "__PRELINK_TEXT")) {
const struct section_64 *sec = (struct section_64 *)(seg + 1);
for (j = 0; j < seg->nsects; j++) {
if (!strcmp(sec[j].sectname, "__text")) {
pstring_base = sec[j].addr;
pstring_size = sec[j].size;
}
}
}
}
if (cmd->cmd == LC_UNIXTHREAD) {
uint32_t *ptr = (uint32_t *)(cmd + 1);
uint32_t flavor = ptr[0];
struct {
uint64_t x[29]; /* General purpose registers x0-x28 */
uint64_t fp; /* Frame pointer x29 */
uint64_t lr; /* Link register x30 */
uint64_t sp; /* Stack pointer x31 */
uint64_t pc; /* Program counter */
uint32_t cpsr; /* Current program status register */
} *thread = (void *)(ptr + 2);
if (flavor == 6) {
kernel_entry = thread->pc;
}
}
q = q + cmd->cmdsize;
}

if (pstring_base == 0 && pstring_size == 0) {
pstring_base = cstring_base;
pstring_size = cstring_size;
}
if (prelink_base == 0 && prelink_size == 0) {
prelink_base = xnucore_base;
prelink_size = xnucore_size;
}

kerndumpbase = min;
xnucore_base -= kerndumpbase;
prelink_base -= kerndumpbase;
pplcode_base -= kerndumpbase;
cstring_base -= kerndumpbase;
pstring_base -= kerndumpbase;
kernel_size = max - min;

if (filename == NULL) {
#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
kernel = malloc(kernel_size);
if (!kernel) {
return -1;
}
rv = kread(kerndumpbase, kernel, kernel_size);
if (rv != kernel_size) {
free(kernel);
kernel = NULL;
return -1;
}

kernel_mh = kernel + base - min;
#endif
} else {
kernel = calloc(1, kernel_size);
if (!kernel) {
CLOSE(fd);
return -1;
}

q = buf + sizeof(struct mach_header) + is64;
for (i = 0; i < hdr->ncmds; i++) {
const struct load_command *cmd = (struct load_command *)q;
if (cmd->cmd == LC_SEGMENT_64) {
const struct segment_command_64 *seg = (struct segment_command_64 *)q;
size_t sz = PREAD(fd, kernel + seg->vmaddr - min, seg->filesize, seg->fileoff);
if (sz != seg->filesize) {
CLOSE(fd);
free(kernel);
kernel = NULL;
return -1;
}
if (!kernel_mh) {
kernel_mh = kernel + seg->vmaddr - min;
}
if (!strcmp(seg->segname, "__LINKEDIT")) {
kernel_delta = seg->vmaddr - min - seg->fileoff;
}
}
q = q + cmd->cmdsize;
}

CLOSE(fd);
}

vstr = boyermoore_horspool_memmem(kernel, kernel_size, (uint8_t *)"Darwin Kernel Version", sizeof("Darwin Kernel Version") - 1);
if (vstr) {
kernel_version = atoi((const char *)vstr + sizeof("Darwin Kernel Version"));
}

return 0;
}

void
term_kernel(void)
{
Expand Down