├── Makefile ├── README.md ├── patchfinder32 ├── patchfinder32.h └── patchfinder32.c ├── machoman ├── machoman.h └── machoman.c └── of32.c /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc machoman/*.c patchfinder32/*.c *.c -o OF32 3 | clean: 4 | rm -rf OF32 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OF32 2 | A simple tool to find offsets needed in 32bit jailbreaks. Feel free to contribute. 3 | 4 | ### How to use 5 | To build the tool simply use `make`. Then to use: 6 | ``` 7 | ./OF32 [unencrypted_kernelcache_path] 8 | ``` 9 | 10 | ### Notes 11 | Only works on 32bit kernelcaches (obviously). Didn't do a lot of testing, so stuff may happen. Also not sure all offsets needed are included. 12 | Pull requests are appreciated! 13 | 14 | *Important:* will not work on dumps/runtime kernel as it is, since it relies on symbols that get stripped at runtime. 15 | -------------------------------------------------------------------------------- /patchfinder32/patchfinder32.h: -------------------------------------------------------------------------------- 1 | // 2 | // patchfinder32.h 3 | // HomeDepotOF 4 | // 5 | // Created by Nicolò Blasi on 24/08/2017. 6 | // Copyright © 2017 Nicolò Blasi. All rights reserved. 7 | // 8 | 9 | /* patchfinder32 - credits to planetbeing (https://github.com/planetbeing/ios-jailbreak-patchfinder) */ 10 | 11 | #ifndef patchfinder32_h 12 | #define patchfinder32_h 13 | 14 | #include 15 | 16 | int insn_is_32bit(uint16_t* i); 17 | 18 | int insn_is_add_reg(uint16_t* i); 19 | int insn_add_reg_rd(uint16_t* i); 20 | int insn_add_reg_rm(uint16_t* i); 21 | 22 | int insn_is_mov_imm(uint16_t* i); 23 | int insn_mov_imm_rd(uint16_t* i); 24 | int insn_mov_imm_imm(uint16_t* i); 25 | 26 | int insn_is_movt(uint16_t* i); 27 | int insn_movt_rd(uint16_t* i); 28 | int insn_movt_imm(uint16_t* i); 29 | 30 | int insn_is_ldr_imm(uint16_t* i); 31 | int insn_ldr_imm_rt(uint16_t* i); 32 | int insn_ldr_imm_imm(uint16_t* i); 33 | 34 | int insn_is_bl(uint16_t* i); 35 | uint32_t insn_bl_imm32(uint16_t* i); 36 | 37 | #endif /* patchfinder32_h */ 38 | -------------------------------------------------------------------------------- /machoman/machoman.h: -------------------------------------------------------------------------------- 1 | /* 2 | * == libmachoman v0.1.0 == 3 | * 4 | * A simple library providing all you need 5 | * for generic Mach-O parsing. 6 | * I found myself rewriting this fucking code 7 | * in every project, so I finally decided to 8 | * do it right, once and for all! 9 | * 10 | */ 11 | 12 | // 13 | // machoman.h 14 | // machoman 15 | // 16 | // Created by jndok on 26/05/16. 17 | // Copyright © 2016 jndok. All rights reserved. 18 | // 19 | 20 | #ifndef machoman_h 21 | #define machoman_h 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #define MACHO_MAP_MAGIC 0xDEADC0DE 37 | 38 | #define MACHO_MAP_SLIDE_OFFSET(map, off) ((uint64_t)(map->map_data) + (uint64_t)off) 39 | #define MACHO_MAP_UNSLIDE_OFFSET(map, off) ((uint64_t)off > (uint64_t)(map->map_data)) ? ((uint64_t)off - (uint64_t)(map->map_data)) : ((uint64_t)off) 40 | 41 | enum { 42 | MMRC_ErrGen = 1 43 | }; 44 | 45 | typedef struct macho_map { 46 | uint32_t map_magic; 47 | void *map_data; 48 | mach_vm_size_t map_size; 49 | uint32_t unique_id; 50 | } macho_map_t; 51 | 52 | macho_map_t *map_macho_with_path(const char *path, int mode); 53 | void free_macho_map(macho_map_t *map); 54 | 55 | __attribute__((always_inline)) boolean_t is_valid_macho_file(const char *path); /* before you map */ 56 | __attribute__((always_inline)) boolean_t is_valid_macho_map(macho_map_t *map); 57 | 58 | __attribute__((always_inline)) struct mach_header *get_mach_header32(macho_map_t *map); 59 | 60 | __attribute__((always_inline)) struct load_command *find_load_command32(struct mach_header *mh, uint32_t lc); 61 | __attribute__((always_inline)) struct segment_command *find_segment_command32(struct mach_header *mh, const char *segname); 62 | __attribute__((always_inline)) struct section *find_section32(struct segment_command *seg, const char *sectname); 63 | 64 | __attribute__((always_inline)) struct symtab_command *find_symtab_command(struct mach_header *mh); 65 | __attribute__((always_inline)) struct dysymtab_command *find_dysymtab_command(struct mach_header *mh); 66 | 67 | #endif /* machoman_h */ 68 | -------------------------------------------------------------------------------- /machoman/machoman.c: -------------------------------------------------------------------------------- 1 | // 2 | // machoman.c 3 | // machoman 4 | // 5 | // Created by jndok on 14/05/16. 6 | // Copyright © 2016 jndok. All rights reserved. 7 | // 8 | 9 | #include "machoman.h" 10 | 11 | macho_map_t *map_macho_with_path(const char *path, int mode) 12 | { 13 | if (!path) return NULL; 14 | if (access(path, R_OK) == -1) return NULL; 15 | 16 | int32_t fd = open(path, mode); 17 | if (fd < 0) { 18 | return NULL; 19 | } 20 | 21 | struct stat st; 22 | if(fstat(fd, &st) != 0) 23 | goto fail; 24 | 25 | macho_map_t *map = (macho_map_t *)malloc(sizeof(macho_map_t)); 26 | if((map->map_data = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, (mode == O_RDONLY) ? MAP_PRIVATE : MAP_SHARED, fd, 0)) == MAP_FAILED) 27 | goto fail; 28 | map->map_magic = MACHO_MAP_MAGIC; 29 | map->map_size = (mach_vm_size_t)st.st_size; 30 | map->unique_id = (uint32_t)(((uint64_t)map << 32) >> 32); 31 | 32 | return map; 33 | 34 | fail: 35 | close(fd); 36 | 37 | return NULL; 38 | } 39 | 40 | void free_macho_map(macho_map_t *map) 41 | { 42 | if (!is_valid_macho_map(map)) { 43 | return; 44 | } 45 | 46 | munmap(map->map_data, map->map_size); 47 | free(map); 48 | } 49 | 50 | __attribute__((always_inline)) 51 | boolean_t is_valid_macho_file(const char *path) 52 | { 53 | if (!path) return FALSE; 54 | if (access(path, R_OK) == -1) return FALSE; 55 | 56 | int32_t fd = open(path, O_RDONLY); 57 | if (fd < 0) 58 | return FALSE; 59 | 60 | uint32_t magic = 0; 61 | if (read(fd, (void*)&magic, sizeof(uint32_t)) == -1) 62 | return FALSE; 63 | 64 | if ((magic == MH_MAGIC) || (magic == MH_MAGIC_64)) 65 | return TRUE; 66 | else 67 | return FALSE; 68 | } 69 | 70 | __attribute__((always_inline)) 71 | boolean_t is_valid_macho_map(macho_map_t *map) 72 | { 73 | if (!map) return FALSE; 74 | if (!map->map_data) FALSE; 75 | if (map->map_magic != MACHO_MAP_MAGIC) return FALSE; 76 | 77 | return TRUE; 78 | } 79 | 80 | __attribute__((always_inline)) 81 | struct mach_header *get_mach_header32(macho_map_t *map) 82 | { 83 | if (!is_valid_macho_map(map)) return NULL; 84 | 85 | return (struct mach_header*)(map->map_data); 86 | } 87 | 88 | __attribute__((always_inline)) 89 | struct load_command *find_load_command32(struct mach_header *mh, uint32_t lc) 90 | { 91 | struct load_command *lcmd = (struct load_command *)(mh + 1); 92 | for (uint32_t i=0; incmds; i++, lcmd = (void *)lcmd + lcmd->cmdsize) { 93 | if (lcmd->cmd == lc) 94 | return lcmd; 95 | } 96 | 97 | return NULL; 98 | } 99 | 100 | __attribute__((always_inline)) 101 | struct segment_command *find_segment_command32(struct mach_header *mh, const char *segname) 102 | { 103 | struct load_command *lcmd = (struct load_command *)(mh + 1); 104 | for (uint32_t i=0; incmds; i++, lcmd = (void *)lcmd + lcmd->cmdsize) { 105 | if (lcmd->cmd == LC_SEGMENT) { 106 | struct segment_command *seg = (struct segment_command*)(lcmd); 107 | if (strcmp(seg->segname, segname) == 0) 108 | return seg; 109 | } 110 | } 111 | 112 | return NULL; 113 | } 114 | 115 | __attribute__((always_inline)) 116 | struct section *find_section32(struct segment_command *seg, const char *sectname) 117 | { 118 | struct section *sect = (struct section *)(seg + 1); 119 | for (uint32_t i=0; insects; i++, sect++) { 120 | if (strcmp(sect->sectname, sectname) == 0) 121 | return sect; 122 | } 123 | 124 | return NULL; 125 | } 126 | 127 | __attribute__((always_inline)) 128 | struct symtab_command *find_symtab_command(struct mach_header *mh) 129 | { 130 | return (struct symtab_command *)find_load_command32(mh, LC_SYMTAB); 131 | } 132 | 133 | __attribute__((always_inline)) 134 | struct dysymtab_command *find_dysymtab_command(struct mach_header *mh) 135 | { 136 | return (struct dysymtab_command *)find_load_command32(mh, LC_DYSYMTAB); 137 | } 138 | -------------------------------------------------------------------------------- /patchfinder32/patchfinder32.c: -------------------------------------------------------------------------------- 1 | // 2 | // patchfinder32.c 3 | // HomeDepotOF 4 | // 5 | // Created by Nicolò Blasi on 24/08/2017. 6 | // Copyright © 2017 Nicolò Blasi. All rights reserved. 7 | // 8 | 9 | #include "patchfinder32.h" 10 | 11 | static uint32_t bit_range(uint32_t x, int start, int end) 12 | { 13 | x = (x << (31 - start)) >> (31 - start); 14 | x = (x >> end); 15 | return x; 16 | } 17 | 18 | static uint32_t ror(uint32_t x, int places) 19 | { 20 | return (x >> places) | (x << (32 - places)); 21 | } 22 | 23 | static int thumb_expand_imm_c(uint16_t imm12) 24 | { 25 | if(bit_range(imm12, 11, 10) == 0) 26 | { 27 | switch(bit_range(imm12, 9, 8)) 28 | { 29 | case 0: 30 | return bit_range(imm12, 7, 0); 31 | case 1: 32 | return (bit_range(imm12, 7, 0) << 16) | bit_range(imm12, 7, 0); 33 | case 2: 34 | return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 8); 35 | case 3: 36 | return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 16) | (bit_range(imm12, 7, 0) << 8) | bit_range(imm12, 7, 0); 37 | default: 38 | return 0; 39 | } 40 | } else 41 | { 42 | uint32_t unrotated_value = 0x80 | bit_range(imm12, 6, 0); 43 | return ror(unrotated_value, bit_range(imm12, 11, 7)); 44 | } 45 | } 46 | 47 | int insn_is_32bit(uint16_t* i) 48 | { 49 | return (*i & 0xe000) == 0xe000 && (*i & 0x1800) != 0x0; 50 | } 51 | 52 | 53 | int insn_is_add_reg(uint16_t* i) 54 | { 55 | if((*i & 0xFE00) == 0x1800) 56 | return 1; 57 | else if((*i & 0xFF00) == 0x4400) 58 | return 1; 59 | else if((*i & 0xFFE0) == 0xEB00) 60 | return 1; 61 | else 62 | return 0; 63 | } 64 | 65 | int insn_add_reg_rd(uint16_t* i) 66 | { 67 | if((*i & 0xFE00) == 0x1800) 68 | return (*i & 7); 69 | else if((*i & 0xFF00) == 0x4400) 70 | return (*i & 7) | ((*i & 0x80) >> 4) ; 71 | else if((*i & 0xFFE0) == 0xEB00) 72 | return (*(i + 1) >> 8) & 0xF; 73 | else 74 | return 0; 75 | } 76 | 77 | int insn_add_reg_rm(uint16_t* i) 78 | { 79 | if((*i & 0xFE00) == 0x1800) 80 | return (*i >> 6) & 7; 81 | else if((*i & 0xFF00) == 0x4400) 82 | return (*i >> 3) & 0xF; 83 | else if((*i & 0xFFE0) == 0xEB00) 84 | return *(i + 1) & 0xF; 85 | else 86 | return 0; 87 | } 88 | 89 | int insn_is_mov_imm(uint16_t* i) 90 | { 91 | if((*i & 0xF800) == 0x2000) 92 | return 1; 93 | else if((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 94 | return 1; 95 | else if((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 96 | return 1; 97 | else 98 | return 0; 99 | } 100 | 101 | int insn_mov_imm_rd(uint16_t* i) 102 | { 103 | if((*i & 0xF800) == 0x2000) 104 | return (*i >> 8) & 7; 105 | else if((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 106 | return (*(i + 1) >> 8) & 0xF; 107 | else if((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 108 | return (*(i + 1) >> 8) & 0xF; 109 | else 110 | return 0; 111 | } 112 | 113 | int insn_mov_imm_imm(uint16_t* i) 114 | { 115 | if((*i & 0xF800) == 0x2000) 116 | return *i & 0xF; 117 | else if((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 118 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 119 | else if((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 120 | return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF); 121 | else 122 | return 0; 123 | } 124 | 125 | int insn_is_movt(uint16_t* i) 126 | { 127 | return (*i & 0xFBF0) == 0xF2C0 && (*(i + 1) & 0x8000) == 0; 128 | } 129 | 130 | int insn_movt_rd(uint16_t* i) 131 | { 132 | return (*(i + 1) >> 8) & 0xF; 133 | } 134 | 135 | int insn_movt_imm(uint16_t* i) 136 | { 137 | return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF); 138 | } 139 | 140 | int insn_is_ldr_imm(uint16_t* i) 141 | { 142 | uint8_t opA = bit_range(*i, 15, 12); 143 | uint8_t opB = bit_range(*i, 11, 9); 144 | 145 | return opA == 6 && (opB & 4) == 4; 146 | } 147 | 148 | int insn_ldr_imm_rt(uint16_t* i) 149 | { 150 | return (*i & 7); 151 | } 152 | 153 | int insn_ldr_imm_imm(uint16_t* i) 154 | { 155 | return (((*i >> 6) & 0x1F) << 2); 156 | } 157 | 158 | int insn_is_bl(uint16_t* i) 159 | { 160 | if((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd000) == 0xd000) 161 | return 1; 162 | else if((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd001) == 0xc000) 163 | return 1; 164 | else 165 | return 0; 166 | } 167 | 168 | uint32_t insn_bl_imm32(uint16_t* i) 169 | { 170 | uint16_t insn0 = *i; 171 | uint16_t insn1 = *(i + 1); 172 | uint32_t s = (insn0 >> 10) & 1; 173 | uint32_t j1 = (insn1 >> 13) & 1; 174 | uint32_t j2 = (insn1 >> 11) & 1; 175 | uint32_t i1 = ~(j1 ^ s) & 1; 176 | uint32_t i2 = ~(j2 ^ s) & 1; 177 | uint32_t imm10 = insn0 & 0x3ff; 178 | uint32_t imm11 = insn1 & 0x7ff; 179 | uint32_t imm32 = (imm11 << 1) | (imm10 << 12) | (i2 << 22) | (i1 << 23) | (s ? 0xff000000 : 0); 180 | return imm32; 181 | } 182 | 183 | /* patchfinder32 - END */ 184 | -------------------------------------------------------------------------------- /of32.c: -------------------------------------------------------------------------------- 1 | // 2 | // of32.c 3 | // OF32 4 | // 5 | // Created by jndok on 23/08/2017. 6 | // Copyright © 2017 jndok. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "machoman/machoman.h" 13 | #include "patchfinder32/patchfinder32.h" 14 | 15 | enum { 16 | INSN_SEARCH_MODE_THUMB = 0, 17 | INSN_SEARCH_MODE_ARM32 18 | }; 19 | 20 | enum { 21 | INSN_SEARCH_DIRECTION_FWD = 0, 22 | INSN_SEARCH_DIRECTION_BWD 23 | }; 24 | 25 | #define OSSERIALIZER_SERIALIZE_SYMBOL_NAME "__ZNK12OSSerializer9serializeEP11OSSerialize" 26 | #define OSSYMBOL_GETMETACLASS_SYMBOL_NAME "__ZNK8OSSymbol12getMetaClassEv" 27 | #define BUFATTR_CPX_SYMBOL_NAME "_bufattr_cpx" 28 | #define COPYIN_SYMBOL_NAME "_copyin" 29 | #define KERNEL_PMAP_SYMBOL_NAME "_kernel_pmap" 30 | 31 | #define SLIDE(type, addr, slide) (type)((type)addr + (type)slide) 32 | #define UNSLIDE(type, addr, slide) (type)((type)addr - (type)slide) 33 | 34 | #define ADDR_MAP_TO_KCACHE(addr) ({ uint32_t _tmp_addr = ((addr) ? SLIDE(uint32_t, UNSLIDE(void*, addr, base), kbase) : 0); _tmp_addr; }) 35 | #define ADDR_KCACHE_TO_MAP(addr) ({ void *_tmp_addr = (void *)((addr) ? SLIDE(uint64_t, UNSLIDE(uint32_t, addr, kbase), base) : 0); _tmp_addr; }) 36 | 37 | void *base = NULL; 38 | uint32_t kbase = 0; 39 | 40 | struct mach_header *mh = NULL; 41 | struct symtab_command *symtab = NULL; 42 | 43 | struct nlist *find_sym(const char *sym) 44 | { 45 | if (!sym || !base || !symtab) 46 | return NULL; 47 | 48 | void *psymtab = base + symtab->symoff; 49 | void *pstrtab = base + symtab->stroff; 50 | 51 | struct nlist *entry = (struct nlist *)psymtab; 52 | for (uint32_t i = 0; i < symtab->nsyms; i++, entry++) 53 | if (!strcmp(sym, (char *)(pstrtab + entry->n_un.n_strx))) 54 | return entry; 55 | 56 | return NULL; 57 | } 58 | 59 | uint32_t find_sig(uint8_t *sig, size_t size) 60 | { 61 | if (!mh || !sig) 62 | return -1; 63 | 64 | struct segment_command *text = find_segment_command32(mh, SEG_TEXT); 65 | if (!text) 66 | return -2; 67 | 68 | void *search_base = (base + text->fileoff); 69 | void *p = memmem(search_base, text->filesize, sig, size); 70 | if (!p) 71 | return -3; 72 | 73 | return (uint32_t)(p - base); 74 | } 75 | 76 | void *find_insn(void *start, size_t num, uint32_t insn, uint8_t direction, uint8_t mode) 77 | { 78 | if (!start || !num || !insn) 79 | return NULL; 80 | 81 | switch (mode) { 82 | case INSN_SEARCH_MODE_THUMB: { 83 | for (uint16_t *p = (uint16_t *)start; 84 | ((!direction) ? p < ((uint16_t *)start + num) : p > ((uint16_t *)start - num)); 85 | ((!direction) ? p++ : p--)) 86 | { 87 | if (*p == insn) 88 | return p; 89 | } 90 | break; 91 | } 92 | 93 | case INSN_SEARCH_MODE_ARM32: { 94 | for (uint32_t *p = (uint32_t *)start; 95 | ((!direction) ? p < ((uint32_t *)start + num) : p > ((uint32_t *)start - num)); 96 | ((!direction) ? p++ : p--)) 97 | { 98 | if (*p == insn) 99 | return p; 100 | } 101 | break; 102 | } 103 | 104 | default: 105 | break; 106 | } 107 | 108 | return NULL; 109 | } 110 | 111 | /* offset finders */ 112 | 113 | uint32_t find_OSSerializer_serialize(void) 114 | { 115 | struct nlist *n = find_sym(OSSERIALIZER_SERIALIZE_SYMBOL_NAME); 116 | assert(n); 117 | 118 | return UNSLIDE(uint32_t, n->n_value, kbase); 119 | } 120 | 121 | uint32_t find_OSSymbol_getMetaClass(void) 122 | { 123 | struct nlist *n = find_sym(OSSYMBOL_GETMETACLASS_SYMBOL_NAME); 124 | assert(n); 125 | 126 | return UNSLIDE(uint32_t, n->n_value, kbase); 127 | } 128 | 129 | uint32_t find_calend_gettime(void) 130 | { 131 | struct nlist *n = find_sym("_clock_get_calendar_nanotime"); 132 | assert(n); 133 | 134 | struct segment_command *text = find_segment_command32(mh, SEG_TEXT); 135 | 136 | uint32_t xref = n->n_value; 137 | 138 | for (uint16_t *p = (uint16_t *)(base + text->fileoff); p < (uint16_t *)(base + text->filesize); p++) 139 | if (insn_is_32bit(p) && insn_is_bl(p)) { 140 | uint32_t ip = ADDR_MAP_TO_KCACHE(p); 141 | if ((ip + (int32_t)insn_bl_imm32(p) + 4) == xref) // XXX: assuming first xref is correct one, may not be (?) 142 | return UNSLIDE(uint32_t, 143 | ADDR_MAP_TO_KCACHE(find_insn(p, 10, 0xB590, INSN_SEARCH_DIRECTION_BWD, INSN_SEARCH_MODE_THUMB)), 144 | kbase); 145 | } 146 | 147 | return 0; 148 | } 149 | 150 | uint32_t find_bufattr_cpx(void) 151 | { 152 | struct nlist *n = find_sym(BUFATTR_CPX_SYMBOL_NAME); 153 | assert(n); 154 | 155 | return UNSLIDE(uint32_t, n->n_value, kbase); 156 | } 157 | 158 | uint32_t find_clock_ops(void) 159 | { 160 | struct nlist *n = find_sym("_clock_get_system_value"); 161 | assert(n); 162 | 163 | uint32_t val = 0; 164 | 165 | for (uint16_t *p = (uint16_t *)(ADDR_KCACHE_TO_MAP(n->n_value)); *p != 0xBF00; p++) { 166 | if (insn_is_mov_imm(p) && (!insn_mov_imm_rd(p))) { 167 | val = insn_mov_imm_imm(p); 168 | } else if (insn_is_movt(p) && (!insn_movt_rd(p))) { 169 | val |= (insn_movt_imm(p) << 16); 170 | } else if (insn_is_add_reg(p) && (!insn_add_reg_rd(p)) && (insn_add_reg_rm(p) == 0xF)) { 171 | uint32_t ip = ADDR_MAP_TO_KCACHE(p); 172 | uint32_t *addr = (uint32_t *)ADDR_KCACHE_TO_MAP(ip+val+4); 173 | assert(*addr); 174 | 175 | return UNSLIDE(uint32_t, ((*addr) + 0xC), kbase); 176 | } 177 | } 178 | 179 | return 0; 180 | } 181 | 182 | uint32_t find_copyin(void) 183 | { 184 | struct nlist *n = find_sym(COPYIN_SYMBOL_NAME); 185 | assert(n); 186 | 187 | return UNSLIDE(uint32_t, n->n_value, kbase); 188 | } 189 | 190 | uint32_t find_bx_lr(void) 191 | { 192 | return find_bufattr_cpx() + 0x2; 193 | } 194 | 195 | uint32_t find_write_gadget(void) 196 | { 197 | struct nlist *n = find_sym("_enable_kernel_vfp_context"); 198 | assert(n); 199 | 200 | uint16_t *p = find_insn(ADDR_KCACHE_TO_MAP(n->n_value), 50, 0x100C, INSN_SEARCH_DIRECTION_BWD, INSN_SEARCH_MODE_THUMB); 201 | assert(p); 202 | 203 | return UNSLIDE(uint32_t, ADDR_MAP_TO_KCACHE(p), kbase); 204 | } 205 | 206 | uint32_t find_vm_kernel_addrperm(void) 207 | { 208 | struct nlist *n = find_sym("_buf_kernel_addrperm_addr"); 209 | assert(n); 210 | 211 | uint32_t val = 0; 212 | 213 | // 0x4700 is bx lr, this proc ends with it 214 | for (uint16_t *p = (uint16_t *)(base + (n->n_value - kbase)); *p != 0x4700; p++) { 215 | if (insn_is_mov_imm(p) && (insn_mov_imm_rd(p) == 1)) { 216 | // movw r1, #X 217 | val = insn_mov_imm_imm(p); 218 | } else if (insn_is_movt(p) && (insn_movt_rd(p) == 1)) { 219 | // movt r1, #X 220 | val |= (insn_movt_imm(p) << 16); 221 | } else if (insn_is_add_reg(p) && (insn_add_reg_rd(p) == 1) && (insn_add_reg_rm(p) == 0xF)) { 222 | // add r1, pc 223 | uint32_t ip = ADDR_MAP_TO_KCACHE(p); 224 | val += ip+4; 225 | } else if (insn_is_ldr_imm(p) && (insn_ldr_imm_rt(p) == 1)) { 226 | // ldr r1, [r0, #XX] 227 | val += insn_ldr_imm_imm(p); 228 | val -= 0x4; 229 | 230 | return UNSLIDE(uint32_t, val, kbase); 231 | } 232 | } 233 | 234 | return 0; 235 | } 236 | 237 | uint32_t find_kernel_pmap(void) 238 | { 239 | struct nlist *n = find_sym(KERNEL_PMAP_SYMBOL_NAME); 240 | assert(n); 241 | 242 | return UNSLIDE(uint32_t, n->n_value, kbase); 243 | } 244 | 245 | uint32_t find_flush_dcache(void) 246 | { 247 | uint8_t sig[] = { 248 | 0x00, 0x00, 0xA0, 0xE3, 249 | 0x5E, 0x0F, 0x07, 0xEE 250 | }; 251 | 252 | return find_sig((void *)&sig, sizeof(sig)); 253 | } 254 | 255 | uint32_t find_invalidate_tlb(void) 256 | { 257 | uint8_t sig[] = { 258 | 0x00, 0x00, 0xA0, 0xE3, 259 | 0x17, 0x0F, 0x08, 0xEE, 260 | 0x4B, 0xF0, 0x7F, 0xF5, 261 | 0x6F, 0xF0, 0x7F, 0xF5, 262 | 0x1E, 0xFF, 0x2F, 0xE1 263 | }; 264 | 265 | return find_sig((void *)&sig, sizeof(sig)); 266 | } 267 | 268 | uint32_t find_allproc(void) 269 | { 270 | struct nlist *n = find_sym("_groupmember"); 271 | struct nlist *n2 = find_sym("_kauth_cred_get"); 272 | struct nlist *n3 = find_sym("_lck_mtx_lock"); 273 | 274 | assert(n); 275 | assert(n2); 276 | assert(n3); 277 | 278 | boolean_t mark1 = FALSE; 279 | boolean_t mark2 = FALSE; 280 | 281 | uint32_t *p = NULL; 282 | for (p = (uint32_t *)(ADDR_KCACHE_TO_MAP(n->n_value));; p++) { 283 | if (insn_is_32bit((uint16_t *)p) && insn_is_bl((uint16_t *)p)) { 284 | uint32_t ip = ADDR_MAP_TO_KCACHE(p); 285 | uint32_t val = (ip + (int32_t)insn_bl_imm32((uint16_t *)p) + 4); 286 | 287 | if (!mark1 && (val == n2->n_value)) 288 | mark1++; 289 | else if (!mark2 && mark1 && (val == n3->n_value)) 290 | break; 291 | } 292 | } 293 | 294 | uint32_t val = 0; 295 | 296 | for (uint16_t *p2 = (uint16_t *)p; *p2 != 0xBF00; p2++) { 297 | if (insn_is_mov_imm(p2) && (!insn_mov_imm_rd(p2))) { 298 | val = insn_mov_imm_imm(p2); 299 | } else if (insn_is_movt(p2) && (!insn_movt_rd(p2))) { 300 | val |= (insn_movt_imm(p2) << 16); 301 | } else if (insn_is_add_reg(p2) && (!insn_add_reg_rd(p2)) && (insn_add_reg_rm(p2) == 0xF)) { 302 | uint32_t ip = (uint32_t)((void *)(p2+2) - base) + kbase; 303 | val += ip; 304 | } else if (insn_is_ldr_imm(p2) && (!insn_ldr_imm_rt(p2))) { 305 | val += insn_ldr_imm_imm(p2); 306 | val += 0x8; 307 | 308 | return UNSLIDE(uint32_t, val, kbase); 309 | } 310 | } 311 | 312 | return 0; 313 | } 314 | 315 | uint32_t find_proc_ucred(void) 316 | { 317 | struct nlist *n = find_sym("_proc_ucred"); 318 | assert(n); 319 | 320 | uint32_t *addr = (uint32_t *)(ADDR_KCACHE_TO_MAP(n->n_value)); 321 | assert(addr && *addr); 322 | 323 | return ((*addr) >> 16); 324 | } 325 | 326 | uint32_t find_setreuid(void) 327 | { 328 | uint8_t sig[] = { 329 | 0xf0, 0xb5, 0x03, 0xaf, 330 | 0x2d, 0xe9, 0x00, 0x0d, 331 | 0x87, 0xb0, 0x04, 0x46, 332 | 0x02, 0x91, 0x03, 0x94, 333 | 0xd1, 0xf8, 0x00, 0xb0, 334 | 0x4d, 0x68, 0xdf, 0xf7 335 | }; 336 | 337 | return find_sig((void *)&sig, sizeof(sig)); 338 | } 339 | 340 | uint32_t find_task_for_pid(void) 341 | { 342 | uint8_t sig[] = { 343 | 0xf0, 0xb5, 0x03, 0xaf, 344 | 0x2d, 0xe9, 0x00, 0x0d, 345 | 0x84, 0xb0, 0x01, 0x46, 346 | 0x91, 0xe8, 0x41, 0x08, 347 | 0x00, 0x21, 0x03, 0x91 348 | }; 349 | 350 | return find_sig((void *)&sig, sizeof(sig)); 351 | } 352 | 353 | #define FIND_OFFSET(name) uint32_t off_##name = find_##name(); 354 | #define PRINT_OFFSET(name) fprintf(stdout, "[%-25s]: %#x\n", #name, off_##name) 355 | 356 | #define FIND_AND_PRINT_OFFSET(name) { FIND_OFFSET(name); PRINT_OFFSET(name); } 357 | 358 | int main(int argc, const char * argv[]) { 359 | 360 | if (argc != 2) { 361 | printf("Usage: ./OF32 [kernelcache_path]\n"); 362 | return 1; 363 | } 364 | 365 | fprintf(stdout, "(+) Opening \'%s\', found in %s\n", (strrchr(argv[1], '/')) ? strrchr(argv[1], '/')+1 : argv[1], argv[1]); 366 | 367 | macho_map_t *map = map_macho_with_path(argv[1], O_RDONLY); 368 | assert(map); 369 | 370 | mh = get_mach_header32(map); 371 | 372 | if (mh->magic != MH_MAGIC) { 373 | printf("Error: Invalid kernelcache!\n"); 374 | return 2; 375 | } 376 | 377 | fprintf(stdout, "(+) Successfully mapped and validated kernelcache. Dumping offsets...\n\n"); 378 | 379 | base = map->map_data; 380 | kbase = find_segment_command32(mh, SEG_TEXT)->vmaddr; 381 | 382 | symtab = find_symtab_command(mh); 383 | assert(symtab); 384 | 385 | FIND_AND_PRINT_OFFSET(OSSerializer_serialize); 386 | FIND_AND_PRINT_OFFSET(OSSymbol_getMetaClass); 387 | FIND_AND_PRINT_OFFSET(calend_gettime); 388 | FIND_AND_PRINT_OFFSET(bufattr_cpx); 389 | FIND_AND_PRINT_OFFSET(clock_ops); 390 | FIND_AND_PRINT_OFFSET(copyin); 391 | FIND_AND_PRINT_OFFSET(bx_lr); 392 | FIND_AND_PRINT_OFFSET(write_gadget); 393 | FIND_AND_PRINT_OFFSET(vm_kernel_addrperm); 394 | FIND_AND_PRINT_OFFSET(kernel_pmap); 395 | FIND_AND_PRINT_OFFSET(flush_dcache); 396 | FIND_AND_PRINT_OFFSET(invalidate_tlb); 397 | FIND_AND_PRINT_OFFSET(setreuid); 398 | FIND_AND_PRINT_OFFSET(proc_ucred); 399 | FIND_AND_PRINT_OFFSET(task_for_pid); 400 | FIND_AND_PRINT_OFFSET(allproc); 401 | 402 | return 0; 403 | } 404 | --------------------------------------------------------------------------------