Skip to content

Kernel patches for iPadOS 18.4.1 #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: iOS15
Choose a base branch
from
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
7 changes: 5 additions & 2 deletions checkra1n/kpf/bindfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,15 @@ static void kpf_fsctl_dev_by_role_patch(xnu_pf_patchset_t *xnu_text_exec_patchse
// /x 002088520000b072:e0ffffffe0ffffff
uint64_t matches[] =
{
0x52882000, // mov wN, 0x4100
0x52882000, // mov wN, 0x4100 (or 0x4101 on 18.4.1)
0x72b00000, // movk wN, 0x8000, lsl 16
0xeb08005f, // cmp x2, x8 // might be too specific, but works for 18.3.1 and 18.4.1
};
uint64_t masks[] =
{
0xffffffc0,
0xffffffe0,
0xffffffe0,
0xffffffff,
};
xnu_pf_maskmatch(xnu_text_exec_patchset, "fsctl_dev_by_role", matches, masks, sizeof(masks)/sizeof(uint64_t), true, (void*)kpf_fsctl_dev_by_role_callback);

Expand Down Expand Up @@ -247,6 +249,7 @@ static void kpf_shared_region_root_dir_patch(xnu_pf_patchset_t *xnu_text_exec_pa

static void kpf_bindfs_patches(xnu_pf_patchset_t *xnu_text_exec_patchset)
{
puts("kpf_bindfs_patches");
// iOS 15.0: Union mounts no longer work
if(do_bind_mounts)
{
Expand Down
4 changes: 2 additions & 2 deletions checkra1n/kpf/launch_constraints.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,14 @@ static void kpf_launch_constraints_patch(xnu_pf_patchset_t *patchset)
{
0x90000000, // adrp x0, ...
0x91000000, // add x0, x0, ...
0xf90003f0, // str x{16-31}, [sp]
0xa90003f0, // str x{16-31}, [sp] -- in 18.4.1 it's stp x22, x23, [sp] {var_390_1} {var_388_1}
0x94000000, // bl IOLog
};
uint64_t masks[] =
{
0x9f00001f,
0xffc003ff,
0xfffffff0,
0xafff03f0,
0xfc000000,
};
xnu_pf_maskmatch(patchset, "launch_constraints", matches, masks, sizeof(matches)/sizeof(uint64_t), true, (void*)kpf_launch_constraints_callback);
Expand Down
42 changes: 42 additions & 0 deletions checkra1n/kpf/mach_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,48 @@ static void kpf_convert_port_to_map_patch(xnu_pf_patchset_t *xnu_text_exec_patch
0xff00001e,
};
xnu_pf_maskmatch(xnu_text_exec_patchset, "convert_port_to_map", matches_variant, masks_variant, sizeof(matches_variant)/sizeof(uint64_t), false, (void*)kpf_convert_port_to_map_callback);

// changes in iOS 18.4.1
// fffffff0072275ec 08504039 ldrb w8, [x0, #0x14]
// fffffff0072275f0 1f050071 cmp w8, #0x1
// fffffff0072275f4 01feff54 b.ne 0xfffffff0072275b4
// fffffff0072275f8 081440f9 ldr x8, [x0, #0x28]
// fffffff0072275fc f40308aa mov x20, x8
// fffffff007227600 082140f9 ldr x8, [x8, #0x40]
// fffffff007227604 493c00b0 adrp x9, 0xfffffff0079b0000
// fffffff007227608 29e13b91 add x9, x9, #0xef8 {data_fffffff0079b0ef8}
// fffffff00722760c 1f0109eb cmp x8, x9
// fffffff007227610 c0000054 b.eq 0xfffffff007227628

uint64_t matches_variant2[] =
{
0x39400000, // ldrb wN, [xM, ...]
0x71000000, // cmp
0x54000000, // bne
0xf9400000, // ldr xN, [xM, {0x0-0x78}]
0xaa000000, // mov
0xf9402000, // ldr xN, [xM, {0x40|0x48}]
0x90000000, // adrp
0x91000000, // add
0xeb00001f, // cmp
0x54000000, // b.ne / b.eq
};
uint64_t masks_variant2[] =
{
0xffc00000,
0xff000000,
0xff000000,
0xffffc000,
0xff000000,
0xfffff800,
0x9f000000,
0xffc00000,
0xffe0fc1f,
0xff00001e,
};
xnu_pf_maskmatch(xnu_text_exec_patchset, "convert_port_to_map", matches_variant2, masks_variant2, sizeof(matches_variant2)/sizeof(uint64_t), false, (void*)kpf_convert_port_to_map_callback);


}

static bool found_task_conversion_eval_ldr = false;
Expand Down
163 changes: 117 additions & 46 deletions checkra1n/kpf/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ uint32_t* _mac_mount = NULL;
bool kpf_has_done_mac_mount = false;
bool kpf_mac_mount_callback(struct xnu_pf_patch* patch, uint32_t* opcode_stream) {
puts("KPF: Found mac_mount");

uint32_t* mac_mount = &opcode_stream[0];
// search for tbnz w*, 5, *
// and nop it (enable MNT_UNION mounts)
Expand All @@ -187,12 +188,24 @@ bool kpf_mac_mount_callback(struct xnu_pf_patch* patch, uint32_t* opcode_stream)
DEVLOG("kpf_mac_mount_callback: failed to find NOP point");
return false;
}

mac_mount_1[0] = NOP;
// search for ldrb w8, [x8, 0x71]
mac_mount_1 = find_prev_insn(mac_mount, 0x40, 0x3941c508, 0xFFFFFFFF);
if (!mac_mount_1) {
mac_mount_1 = find_next_insn(mac_mount, 0x40, 0x3941c508, 0xFFFFFFFF);
}

// on iOS 18.4.1, it is
// add x8, x8, #0x70
// ldrb w8, [x8, #0x1]
if (!mac_mount_1) {
mac_mount_1 = find_next_insn(mac_mount, 0x40, 0x39400508, 0xFFFFFFFF);
if (!mac_mount_1) {
mac_mount_1 = find_prev_insn(mac_mount, 0x40, 0x39400508, 0xFFFFFFFF);
}
}

if (!mac_mount_1) {
kpf_has_done_mac_mount = false;
DEVLOG("kpf_mac_mount_callback: failed to find xzr point");
Expand All @@ -209,6 +222,7 @@ bool kpf_mac_mount_callback(struct xnu_pf_patch* patch, uint32_t* opcode_stream)
DEVLOG("kpf_mac_mount_callback: failed to find stack frame");
return false;
}

// Now find the insn that decrements sp. This can be either
// "stp ..., ..., [sp, -0x...]!" or "sub sp, sp, 0x...".
// Match top bit of imm on purpose, since we only want negative offsets.
Expand Down Expand Up @@ -244,9 +258,11 @@ void kpf_mac_mount_patch(xnu_pf_patchset_t* xnu_text_exec_patchset) {

// ios 16.4 changed the codegen, so we match both
// r2: /x c9ff8312:ffffff3f
// ios 18.4: c9ff8392 mov x9, #0xffffffffffffe001
matches[0] = 0x1283ffc9; // movz w/x9, 0x1ffe/-0x1fff
masks[0] = 0x3fffffff;
xnu_pf_maskmatch(xnu_text_exec_patchset, "mac_mount_patch2", matches, masks, sizeof(matches)/sizeof(uint64_t), false, (void*)kpf_mac_mount_callback);

}

bool dounmount_found;
Expand Down Expand Up @@ -783,18 +799,21 @@ bool vnode_lookup_callback(struct xnu_pf_patch* patch, uint32_t* opcode_stream)
DEVLOG("vnode_lookup_callback: already ran, skipping...");
return false;
}
uint32_t *try = &opcode_stream[8]+((opcode_stream[8]>>5)&0xFFF);
if ((try[0]&0xFFE0FFFF) != 0xAA0003E0 || // MOV x0, Xn
(try[1]&0xFC000000) != 0x94000000 || // BL _sfree
(try[3]&0xFF000000) != 0xB4000000 || // CBZ
(try[4]&0xFC000000) != 0x94000000 ) { // BL _vnode_put
// ldur x0, [x29, -0x...]
// cbz x0, {forward}
// bl vnode_put
uint32_t *start = find_next_insn(opcode_stream - 1, 30, 0xf85003a0, 0xfff00fff); // ldur instruction
start = find_next_insn(start, 4, 0x94000000, 0xfc000000); //vnode_put

if (!start) {
DEVLOG("Failed match of vnode_lookup code at 0x%" PRIx64 "", kext_rebase_va(xnu_ptr_to_va(opcode_stream)));
return false;
}
puts("KPF: Found vnode_lookup");
vfs_context_current = follow_call(&opcode_stream[1]);
vnode_lookup = follow_call(&opcode_stream[6]);
vnode_put = follow_call(&try[4]);

vfs_context_current = follow_call(opcode_stream + 1);
vnode_lookup = follow_call(opcode_stream + 6);
vnode_put = follow_call(start);
xnu_pf_disable_patch(patch);
return true;
}
Expand Down Expand Up @@ -1503,7 +1522,7 @@ bool kpf_amfi_mac_syscall(struct xnu_pf_patch *patch, uint32_t *opcode_stream) {

bool foundit = false;
uint32_t *rep = opcode_stream;
for(size_t i = 0; i < 25; ++i)
for(size_t i = 0; i < 35; ++i)
{
uint32_t op = *rep;
if(op == 0x321c03e2 /* orr w2, wzr, 0x10 */ || op == 0x52800202 /* movz w2, 0x10 */)
Expand Down Expand Up @@ -1750,6 +1769,26 @@ void kpf_amfi_kext_patches(xnu_pf_patchset_t* patchset) {
};
xnu_pf_maskmatch(patchset, "amfi_mac_syscall_alt", iii_matches, iii_masks, sizeof(iii_matches)/sizeof(uint64_t), false, (void*)kpf_amfi_mac_syscall);

// changes in iOS 18.4.1
// fffffff005a874a8 68b9ffd0 adrp x8, 0xfffffff0051b5000
// fffffff005a874ac 08592191 add x8, x8, #0x856
// fffffff005a874b0 62000014 b 0xfffffff005a87638
// fffffff005a874b4 ff1300f9 str xzr, [sp, #0x20 {var_110}] {0x0}
uint64_t v_matches[] = {
0xd0ffb900, // adrp // might be too specific
0x91215908, // add x8, x8, #0x856
0x14000000, // b
0xf9000000, // str
};
uint64_t v_masks[] = {
0xffffff00,
0xffffffff,
0xff000000,
0xff000000,
};
xnu_pf_maskmatch(patchset, "amfi_mac_syscall_alt", v_matches, v_masks, sizeof(v_matches)/sizeof(uint64_t), false, (void*)kpf_amfi_mac_syscall);


// tvOS/audioOS 16 and bridgeOS 7 apparently got some cases removed, so their codegen looks different again.
//
// 0xfffffff008b0ad50 3f680171 cmp w1, 0x5a
Expand All @@ -1775,27 +1814,30 @@ void kpf_amfi_kext_patches(xnu_pf_patchset_t* patchset) {
}

void kpf_sandbox_kext_patches(xnu_pf_patchset_t* patchset, bool protobox_used) {
uint64_t matches[] = {
0x35000000, // CBNZ
0x94000000, // BL _vfs_context_current
0xAA0003E0, // MOV Xn, X0
0xD1006002, // SUB
0x00000000, // MOV X0, Xn || MOV W1, #0
0x00000000, // MOV X0, Xn || MOV W1, #0
0x94000000, // BL _vnode_lookup
0xAA0003E0, // MOV Xn, X0
0x35000000 // CBNZ
// FIXME: duplicate match pattern with kpf_vfs_patches
uint64_t matches[] =
{
0x35000000, // cbnz w*, {forward}
0x94000000, // bl vfs_context_current
0xaa0003e3, // mov x3, x0
0xd10063a2, // sub x2, x29, 0x... // be more specific here
0xaa1303e0, // {mov x0, x{16-31} | mov w1, 0} // be more specific here
0x52800001, // {mov x0, x{16-31} | mov w1, 0} // be more specific here
0x94000000, // bl vnode_lookup
//0xaa0003f0, // mov x{16-31}, x0 //this move instruction is no longer there!
//0x35000000, // cbnz w*, {forward}
};
uint64_t masks[] = {
0xFF000000,
0xFC000000,
0xFFFFFFE0,
0xFFFFE01F,
0x00000000,
0x00000000,
0xFC000000,
0xFFFFFFE0,
0xFF000000
uint64_t masks[] =
{
0xff800000,
0xfc000000,
0xffffffff,
0xffffffff,
0xffffffff,
0xffffffff,
0xfc000000,
//0xfffffff0,
//0xff800000,
};
xnu_pf_maskmatch(patchset, "vnode_lookup", matches, masks, sizeof(masks)/sizeof(uint64_t), true, (void*)vnode_lookup_callback);

Expand Down Expand Up @@ -2044,6 +2086,7 @@ bool load_init_program_at_path_callback(struct xnu_pf_patch *patch, uint32_t *op
if(bl) break;
}
}

if (!bl) {
for(int i = 0; i < 0x30; i++)
{
Expand All @@ -2061,6 +2104,33 @@ bool load_init_program_at_path_callback(struct xnu_pf_patch *patch, uint32_t *op
}
}
}

// iOS 18.4.1
// fffffff007686018 29008052 mov w9, #0x1
// fffffff00768601c 2221c81a lsl w2, w9, w8
// fffffff007686020 e1c30091 add x1, sp, #0x30 {var_80}
// fffffff007686024 030080d2 mov x3, #0
// fffffff007686028 040080d2 mov x4, #0 // new instruction here!
// fffffff00768602c 9628f197 bl mach_vm_allocate_kernel

if (!bl) {
for(int i = 0; i < 0x30; i++)
{
if (
(start[i ] & 0xffffffe0) == 0x52800020 && // mov wN, #0x1
(start[i + 1] & 0xffe0fc1f) == 0x1ac02002 && // mov w2, wN, wM
(start[i + 2] & 0xffc003ff) == 0x910003e1 && // add x1, sp, ...
(start[i + 3] & 0xffffffff) == 0xd2800003 && // mov x3, #0x0
(start[i + 4] & 0xffffffff) == 0xd2800004 && // mov x4, #0x0
(start[i + 5] & 0xfc000000) == 0x94000000 // bl
)
{
bl = &start[i + 5];
mach_vm_allocate_kernel_new = true;
break;
}
}
}

if (!bl) return false;

Expand All @@ -2071,15 +2141,13 @@ bool load_init_program_at_path_callback(struct xnu_pf_patch *patch, uint32_t *op
}

bool copyout_callsites_callback(struct xnu_pf_patch *patch, uint32_t *opcode_stream) {
// Don't match inlined copyout
if (find_prev_insn(opcode_stream-1, 20, 0x52801102, 0xffffffff)) return false; /* mov w2, #0x88 */

uint32_t* candidate = follow_call(&opcode_stream[1]);
uint32_t* candidate = follow_call(&opcode_stream[2]);
if (!copyout) {
copyout = candidate;
puts("KPF: Found copyout");
return true;
}

if (candidate != copyout) {
panic("KPF: Found multiple copyout candidates");
}
Expand Down Expand Up @@ -2179,23 +2247,26 @@ void kpf_md0oncores_patch(xnu_pf_patchset_t* patchset)
xnu_pf_maskmatch(patchset, "load_init_program_at_path", iii_matches, iii_masks, sizeof(iii_matches)/sizeof(uint64_t), false, (void*)load_init_program_at_path_callback);

// Find callsite(s) of copyout function
// Might match more than once but as long as they point the same address it's fine
// Note: In older iOS versions the cbnz instruction could be cbz, but we don't need it here
// /x 0211805200000094f00300aa00000035:ffffffff000000fcf003ffff000000ff
// Original copyout matches are no longer present in 18.4.1... this one works on 18.3.1 and 18.4.1:
// fffffff0072a4630 e0430091 add x0, sp, #0x10 {var_60}
// fffffff0072a4634 02058052 mov w2, #0x28
// fffffff0072a4638 87c00294 bl _copyout
// fffffff0072a463c 60000034 cbz w0, 0xfffffff0072a4648

uint64_t copyout_matches[] =
{
0x52801102, // mov w2, #0x88
0x94000000, // bl copyout
0xaa0003f0, // mov x{16-31}, x0
0x34000000 // cb(n)z wN, ...
0x910043e0, // add x0, sp, #0x10 {var_60}
0x52800502, // w2, #0x28
0x94000000, // bl _copyout
0x34000060 // cbz w0, 0xfffffff0072a4648
};

uint64_t copyout_masks[] =
{
0xffffffff,
0xfc000000,
0xffff03f0,
0xfe000000
0xffffffff,
0xff000000,
0xffffffff
};
xnu_pf_maskmatch(patchset, "copyout_callsites", copyout_matches, copyout_masks, sizeof(copyout_matches)/sizeof(uint64_t), true, (void*)copyout_callsites_callback);
}
Expand Down Expand Up @@ -2277,7 +2348,7 @@ kpf_component_t* const kpf_components[] = {
&kpf_proc_selfname,
&kpf_shellcode,
&kpf_spawn_validate_persona,
&kpf_overlay,
&kpf_overlay, // does IOMemoryDescriptor
&kpf_ramdisk,
&kpf_trustcache,
&kpf_vfs,
Expand Down Expand Up @@ -2714,8 +2785,8 @@ static void kpf_cmd(const char *cmd, char *args)
if (!mdevremoveall) panic("no mdevremoveall");
if (!mac_execve) panic("no mac_execve");
if (!mac_execve_hook) panic("no mac_execve_hook");
if (!copyout) panic("no copyout");
if (!mach_vm_allocate_kernel) panic("no mach_vm_allocate_kernel");
if (!copyout) puts("!!!!!!!!!! no copyout");
if (!mach_vm_allocate_kernel) puts("!!!!!!!!!!!! no mach_vm_allocate_kernel");
if (current_map_off == -1 || vm_map_page_size_off == -1) panic("no offsets");

uint64_t* repatch_launchd_execve_hook_ptrs = (uint64_t*)(launchd_execve_hook_ptr - shellcode_from + shellcode_to);
Expand Down
Loading