├── .gitignore ├── Makefile ├── README ├── common.h ├── helper.h ├── iboot_patcher.c ├── ibootsup.c ├── ibootsup.h ├── img3maker.c ├── kdumper.c ├── kloader.c ├── multi_kloader.c ├── patch.c ├── patch.h ├── structs.h ├── tfp0.plist ├── util.c └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | BUILD 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | OBJROOT = BUILD/obj 2 | DSTROOT = BUILD/dst 3 | SYMROOT = BUILD/sym 4 | LDID = ldid 5 | SFLAGS = -Stfp0.plist 6 | SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/ 7 | CC = xcrun -sdk iphoneos clang -arch armv7 8 | CFLAGS = -no-integrated-as -DINLINE_IT_ALL 9 | LDFLAGS = -miphoneos-version-min=6.0 -framework IOKit -framework CoreFoundation 10 | 11 | all: multi_kloader kloader ibsspatch img3maker 12 | 13 | kloader: kloader.c 14 | SDKROOT=$(SDKROOT) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< 15 | $(LDID) $(SFLAGS) $@ 16 | 17 | multi_kloader: multi_kloader.c 18 | SDKROOT=$(SDKROOT) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< 19 | $(LDID) $(SFLAGS) $@ 20 | 21 | ibsspatch: patch.c util.c ibootsup.c iboot_patcher.c 22 | SDKROOT=$(SDKROOT) $(CC) $(CFLAGS) -o $@ patch.c util.c ibootsup.c iboot_patcher.c 23 | $(LDID) $@ 24 | 25 | img3maker: img3maker.c 26 | SDKROOT=$(SDKROOT) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< 27 | $(LDID) $@ 28 | 29 | clean: 30 | rm -f kloader ibsspatch img3maker multi_kloader 31 | rm -rf $(OBJROOT) $(DSTROOT) $(SYMROOT) 32 | 33 | install: all 34 | mkdir -p $(DSTROOT)/usr/local/bin 35 | install -c -m 755 multi_kloader $(DSTROOT)/usr/local/bin 36 | install -c -m 755 kloader $(DSTROOT)/usr/local/bin 37 | install -c -m 755 ibsspatch $(DSTROOT)/usr/local/bin 38 | install -c -m 755 img3maker $(DSTROOT)/usr/local/bin 39 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ios-kexec-utils 2 | =============== 3 | 4 | A miscellany of utilities designed to help you bootstrap 5 | another operating system on an iOS device. They're probably crap. 6 | 7 | You deal with them. No support/warranty implied/given. 8 | 9 | Warning: there are severe caveats with this method. 10 | 11 | Utilities included (and duplicated from opensn0w-X): 12 | 13 | * img3maker - Image3 file maker, needed for the decrypted boot chain. 14 | * ibsspatch - iBSS patcher for iOS 7, creates a generic patched iBSS for boot. 15 | * kloader - Image loader for the kernel, bootstraps custom image in RAM. 16 | * multi_kloader - Image loader for two images in memory. See source for boot 17 | protocol convention. 18 | 19 | Using these utilities in unison will let you do awesome things. 20 | 21 | (This is one of the last public projects I will push for now. 22 | Personal reasons, mainly stress related.) 23 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Misc helpers. 3 | */ 4 | 5 | #ifndef _HELPER_H_ 6 | #define _HELPER_H_ 7 | 8 | #define add_ptr2(x, y) ((uintptr_t)((uintptr_t)x + (uintptr_t)y)) 9 | #define add_ptr3(x, y, z) ((uintptr_t)((uintptr_t)x + (uintptr_t)y + (uintptr_t)z)) 10 | #define align_down(p, s) ((uintptr_t)(p)&~(s-1)) 11 | #define align_up(p, s) align_down((uintptr_t)(p)+s-1, s) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /iboot_patcher.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013, winocm 3 | * Copyright 2013, iH8sn0w. 4 | * All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * $Id$ 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include "ibootsup.h" 38 | #include "structs.h" 39 | #include "patch.h" 40 | #include "util.h" 41 | 42 | int 43 | main (int argc, char *argv[]) 44 | { 45 | if(argc != 3) { 46 | printf("usage: %s [in] [out] (input must be unencrypted image3)\n", argv[0]); 47 | return -1; 48 | } 49 | 50 | assert (ibootsup_map_file (argv[1]) == 0); 51 | assert (ibootsup_dynapatch () == 0); 52 | assert (ibootsup_write_file (argv[2]) == 0); 53 | return 0; 54 | } -------------------------------------------------------------------------------- /ibootsup.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013, winocm 3 | * Copyright 2013, iH8sn0w. 4 | * All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | * 20 | * $Id$ 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include "structs.h" 38 | #include "patch.h" 39 | #include "util.h" 40 | 41 | #define IBOOT_DEFAULT_BOOTARGS "rd=md0 nand-enable-reformat=1 -progress" 42 | #define IBOOT_DEFAULT_PWNARGS "-v amfi=0xff cs_enforcement_disable=1 " 43 | C_ASSERT (sizeof (IBOOT_DEFAULT_PWNARGS) == sizeof (IBOOT_DEFAULT_BOOTARGS)); 44 | 45 | #define IBOOT_IOS7_SIGPATTERN "\xAB\x29\x46\x32\x46" 46 | #define IBOOT_IOS7_SIGLEN 5 47 | #define IBOOT_IOS7_BA_COND "\x00\x2D\x7E\x4C\x18\xBF" 48 | #define IBOOT_IOS7_BA_LEN 6 49 | #define IBOOT_IOS7_IMG3PATCH_PATCH "\xC0\x46" 50 | #define IBOOT_IOS7_IMG3PATCH_PLEN 2 51 | #define IBOOT_IOS7_BA_COND_PATCH "\xC0\x46\xC0\x46\xC0\x46" 52 | #define IBOOT_IOS7_BA_COND_LEN 6 53 | #define IBOOT_IOS7_SIGPATCH "\x00\x20\x18\x60" 54 | #define IBOOT_IOS7_SIGPATCH_LEN 4 55 | #define IBOOT_IOS7_IMG3PATCH "\x46\xF2\x33\x72\x16\x20\xC4\xF6\x6D\x12" 56 | #define IBOOT_IOS7_IMG3PATCH_LEN 10 57 | 58 | #define IBOOT_IOS_LEGACY_PATCH "\x00\x20\x00\x20" 59 | #define IBOOT_IOS_LEGACY_PLEN 4 60 | #define IBOOT_IOS_RSA_PATTERN "\x8C\xEA\x02\x02" 61 | #define IBOOT_IOS_RSA_LEN 4 62 | #define IBOOT_IOS_BA_COND "\x00\x29\x14\xBF\x1C\x46\x14\x46\x10\x22" 63 | #define IBOOT_IOS_BA_LEN 10 64 | #define IBOOT_IOS_BA_PATCH "\x1C\x46\x1C\x46\x1C\x46\x1C\x46\x10\x22" 65 | #define IBOOT_IOS_BA_PLEN 10 66 | 67 | #define ARM_BRANCH_OPCODE "\x0e\x00\x00\xea" 68 | #define OPCODE_LENGTH 4 69 | #define IBOOT_IMAGE_VERSION 0x280 70 | 71 | static struct iboot_interval intervals[] = { 72 | {320, 590, 2}, 73 | {594, 817, 3}, 74 | {889, 1072, 4}, 75 | {1219, 1220, 5}, 76 | {1537, 1538, 6}, 77 | {1940, 1941, 7}, 78 | {0, 0, -1}, 79 | }; 80 | 81 | static uint32_t ibootsup_image3_tags[9] = { 'SDOM', 'PROD', 'CHIP', 'TYPE', 'SEPO', 'CEPO', 'BORD', 'ECID', 82 | 'OVRD' 83 | }; 84 | 85 | static struct mapped_image current_image; 86 | 87 | static void *pattern_search (void *addr, int len, int pattern, int mask, int step); 88 | static void *ldr_search_up (const void *start_addr, int len); 89 | static void *ldr32_search_up (const void *start_addr, int len); 90 | static void *bl_search_down (void *p, int l); 91 | static void *bl_search_up (void *p, int l); 92 | static void *resolve_bl32 (const void *bl); 93 | static void *locate_ldr (const void *startAddr); 94 | static boolean_t ibootsup_verify_arm_image (void); 95 | static int ibootsup_get_version (void); 96 | static int ibootsup_get_ios_version (void); 97 | static void ibootsup_patch_ios_old_iboot (void); 98 | static void ibootsup_patch_ios7_iboot (void); 99 | static void ibootsup_patch_iboot (void); 100 | 101 | static void * 102 | pattern_search (void *addr, int len, int pattern, int mask, int step) 103 | { 104 | char *caddr = (char *) (addr); 105 | int i; 106 | if (len <= 0) 107 | return NULL; 108 | 109 | if (step < 0) { 110 | len = -len; 111 | len &= ~-(step + 1); 112 | } 113 | else { 114 | len &= ~(step - 1); 115 | } 116 | 117 | for (i = 0; i != len; i += step) { 118 | int x = *(int *) (caddr + i); 119 | if ((x & mask) == pattern) { 120 | return (void *) (caddr + i); 121 | } 122 | } 123 | return NULL; 124 | } 125 | 126 | static void * 127 | ldr_search_up (const void *start_addr, int len) 128 | { 129 | // LDR pattern is xx xx 48 xx ( 00 00 f8 00 ) 130 | return pattern_search (start_addr, len, 0x00004800, 0x0000F800, -2); 131 | } 132 | 133 | static void * 134 | ldr32_search_up (const void *start_addr, int len) 135 | { 136 | // LDR32 pattern is DF F8 xx xx 137 | return pattern_search (start_addr, len, 0x0000F8DF, 0x0000FFFF, -2); 138 | } 139 | 140 | static void * 141 | bl_search_down (void *p, int l) 142 | { 143 | return pattern_search (p, l, 0xD000F000, 0xD000F800, 2); 144 | } 145 | 146 | static void * 147 | bl_search_up (void *p, int l) 148 | { 149 | return pattern_search (p, l, 0xD000F000, 0xD000F800, -2); 150 | } 151 | 152 | static void * 153 | resolve_bl32 (const void *bl) 154 | { 155 | typedef unsigned short uint16_t; 156 | typedef int int32_t; 157 | union 158 | { 159 | uint16_t value; 160 | 161 | struct 162 | { 163 | uint16_t immediate:10; 164 | uint16_t s:1; 165 | uint16_t:5; 166 | }; 167 | } bits = { 168 | *(uint16_t *) bl}; 169 | 170 | union 171 | { 172 | uint16_t value; 173 | 174 | struct 175 | { 176 | uint16_t immediate:11; 177 | uint16_t j2:1; 178 | uint16_t x:1; 179 | uint16_t j1:1; 180 | uint16_t:2; 181 | }; 182 | } exts = { 183 | ((uint16_t *) bl)[1]}; 184 | 185 | int32_t jump = 0; 186 | jump |= bits.s << 24; 187 | jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; 188 | jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; 189 | jump |= bits.immediate << 12; 190 | jump |= exts.immediate << 1; 191 | jump |= exts.x; 192 | jump <<= 7; 193 | jump >>= 7; 194 | return (void *) ((int) bl + 4 + jump); 195 | } 196 | 197 | static void * 198 | locate_ldr (const void *startAddr) 199 | { 200 | int xref_target = (int) startAddr; 201 | int i = xref_target; 202 | int min_addr = xref_target - 0x1000; 203 | while (1) { 204 | i = (int) ldr32_search_up ((void *) i, i - min_addr); 205 | if (i == 0) { 206 | break; 207 | } 208 | int dw = *(int *) i; 209 | int ldr_target = ((i + 4) & ~3) + ((dw >> 16) & 0xfff); 210 | if (ldr_target == xref_target) { 211 | return (void *) i; 212 | } 213 | i -= 4; 214 | } 215 | i = xref_target; 216 | min_addr = xref_target - 0x420; 217 | while (1) { 218 | i = (int) ldr_search_up ((void *) i, i - min_addr); 219 | if (i == 0) { 220 | break; 221 | } 222 | int dw = *(int *) i; 223 | int ldr_target = ((i + 4) & ~3) + ((dw & 0xff) << 2); 224 | if (ldr_target == xref_target) { 225 | return (void *) i; 226 | } 227 | i -= 2; 228 | } 229 | return 0; 230 | } 231 | 232 | static boolean_t 233 | ibootsup_verify_arm_image (void) 234 | { 235 | if (!memcmp (current_image.image, ARM_BRANCH_OPCODE, OPCODE_LENGTH)) 236 | return TRUE; 237 | return FALSE; 238 | } 239 | 240 | static int 241 | ibootsup_get_version (void) 242 | { 243 | int off = IBOOT_IMAGE_VERSION + sizeof ("iBoot-") - 1; /* Accomodate for '\0' */ 244 | return atoi ((char *) current_image.image + off); 245 | } 246 | 247 | static int 248 | ibootsup_get_ios_version (void) 249 | { 250 | int current_version = ibootsup_get_version (); 251 | struct iboot_interval *interval = &intervals[0]; 252 | while (interval->os_version != -1) { 253 | if (current_version >= interval->low_bound && current_version <= interval->high_bound) 254 | return interval->os_version; 255 | interval++; 256 | } 257 | err (-1, "failed to match iBoot version, probably too new/old?"); 258 | return 0; 259 | } 260 | 261 | int 262 | ibootsup_map_buffer (uint8_t * buf, int size) 263 | { 264 | current_image.image = buf; 265 | current_image.size = size; 266 | 267 | if (!ibootsup_verify_arm_image ()) { 268 | return -EBADF; 269 | } 270 | 271 | return 0; 272 | } 273 | 274 | int 275 | ibootsup_map_file (const char *filename) 276 | { 277 | struct stat buf; 278 | FILE *fp = fopen (filename, "rb"); 279 | 280 | if (!fp) 281 | return -ENOENT; 282 | if (stat (filename, &buf) > 0) 283 | return -ENOENT; 284 | 285 | current_image.image = (uint8_t *) _xmalloc (buf.st_size); 286 | current_image.size = buf.st_size; 287 | fread ((void *) current_image.image, buf.st_size, 1, fp); 288 | fclose (fp); 289 | 290 | if (!ibootsup_verify_arm_image ()) { 291 | free (current_image.image); 292 | return -EBADF; 293 | } 294 | 295 | return 0; 296 | } 297 | 298 | static inline uint8_t * 299 | ibootsup_off2pat_patch (int offset, uint8_t * patch, int bufsize, int patchsize) 300 | { 301 | uint8_t *buffer = (uint8_t *) _xmalloc (bufsize); 302 | memcpy (buffer, current_image.image + offset, bufsize); 303 | memcpy (buffer, patch, patchsize); 304 | return buffer; 305 | } 306 | 307 | static void 308 | ibootsup_patch_ios_old_iboot (void) 309 | { 310 | int i = 0, tag = 0, rsaoff = 0, bootargoff = 0, bacondoff = 0; 311 | 312 | /* 313 | * Initialize patch list. 314 | */ 315 | patch_list_initialize (); 316 | 317 | /* 318 | * Pass zero, scan file for image3 tags. 319 | */ 320 | for (i = 0; i < current_image.size; i++) { 321 | /* 322 | * Overwrite conditional 323 | */ 324 | if (!memcmp (current_image.image + i, IBOOT_IOS_BA_COND, IBOOT_IOS_BA_LEN)) 325 | bacondoff = i; 326 | 327 | /* 328 | * Overwrite with boot-arguments. 329 | */ 330 | if (!memcmp (current_image.image + i, IBOOT_DEFAULT_BOOTARGS, sizeof (IBOOT_DEFAULT_BOOTARGS))) 331 | bootargoff = i; 332 | 333 | for (tag = 0; tag < (sizeof (ibootsup_image3_tags) / sizeof (uint32_t)); tag++) { 334 | if (!memcmp (current_image.image + i, &ibootsup_image3_tags[tag], 4)) { 335 | void *ldr = locate_ldr (current_image.image + i); 336 | void *bl = bl_search_down (ldr, 0x200); 337 | uint32_t off = (uint32_t) bl - (uint32_t) current_image.image; 338 | printf ("%x tag check: %x\n", ibootsup_image3_tags[tag], off); 339 | patch_list_add_patch ("Image3 Tag Check", current_image.image + off, ibootsup_off2pat_patch (off, (uint8_t *) IBOOT_IOS_LEGACY_PATCH, 16, IBOOT_IOS_LEGACY_PLEN), 16); 340 | } 341 | } 342 | 343 | /* 344 | * RSA offset. 345 | */ 346 | if (!memcmp (current_image.image + i, IBOOT_IOS_RSA_PATTERN, IBOOT_IOS_RSA_LEN)) 347 | rsaoff = i + 0x10; 348 | } 349 | 350 | if (!rsaoff) { 351 | warn ("RSA check missing???"); 352 | return; 353 | } 354 | 355 | if (!bootargoff || !bacondoff) { 356 | warn ("boot-argument check missing, is this a proper iBoot?"); 357 | } 358 | 359 | /* 360 | * RSA check. 361 | */ 362 | printf ("RSA check at %x.\n", rsaoff); 363 | patch_list_add_patch ("RSA patch", current_image.image + rsaoff, ibootsup_off2pat_patch (rsaoff, (uint8_t *) IBOOT_IOS_LEGACY_PATCH, 16, IBOOT_IOS_LEGACY_PLEN), 16); 364 | printf ("Boot-arg conditional at %x.\n", bacondoff); 365 | if (bootargoff) { 366 | patch_list_add_patch ("BootArgs", current_image.image + bootargoff, ibootsup_off2pat_patch (bootargoff, (uint8_t *) IBOOT_DEFAULT_PWNARGS, sizeof (IBOOT_DEFAULT_BOOTARGS), sizeof (IBOOT_DEFAULT_BOOTARGS)), sizeof (IBOOT_DEFAULT_BOOTARGS)); 367 | } 368 | if (bacondoff) { 369 | patch_list_add_patch ("BootArgs Conditional", current_image.image + bacondoff, ibootsup_off2pat_patch (bacondoff, (uint8_t *) IBOOT_IOS_BA_PATCH, 16, IBOOT_IOS_BA_PLEN), 16); 370 | } 371 | 372 | /* 373 | * Dump listing. 374 | */ 375 | patch_list_iterate (); 376 | } 377 | 378 | static void 379 | ibootsup_patch_ios7_iboot (void) 380 | { 381 | int i = 0, sigoff = 0, bootargoff = 0, bacondoff = 0, img3off = 0; 382 | 383 | /* 384 | * Pass zero, scan file for signature check. 385 | */ 386 | for (i = 0; i < current_image.size; i++) { 387 | /* 388 | * Patch to 00 20 18 60 389 | */ 390 | if (!memcmp (current_image.image + i, IBOOT_IOS7_SIGPATTERN, IBOOT_IOS7_SIGLEN)) 391 | sigoff = i + IBOOT_IOS7_SIGLEN; 392 | 393 | /* 394 | * Overwrite with boot-arguments. 395 | */ 396 | if (!memcmp (current_image.image + i, IBOOT_DEFAULT_BOOTARGS, sizeof (IBOOT_DEFAULT_BOOTARGS))) 397 | bootargoff = i; 398 | 399 | /* 400 | * Conditional to allow injection of boot-args with/without RAM disk. 401 | */ 402 | if (!memcmp (current_image.image + i, IBOOT_IOS7_BA_COND, IBOOT_IOS7_BA_LEN)) 403 | bacondoff = i; 404 | 405 | /* 406 | * Allow stock image3 files. 407 | */ 408 | if (!memcmp (current_image.image + i, IBOOT_IOS7_IMG3PATCH, IBOOT_IOS7_IMG3PATCH_LEN)) 409 | img3off = i + 0x18; 410 | } 411 | 412 | printf ("Signature offset at %x.\n", sigoff); 413 | printf ("Boot-arg offset at %x.\n", bootargoff); 414 | printf ("Boot-arg-conditional offset at %x.\n", bacondoff); 415 | printf ("Image3-signature at %x\n", img3off); 416 | 417 | if (!sigoff || !img3off) { 418 | warn ("finding one of the core patches FAILED\n"); 419 | return; 420 | } 421 | 422 | /* 423 | * (Re)initialize patch list and add patches. Convert the offsets into bytepatterns. 424 | */ 425 | patch_list_initialize (); 426 | patch_list_add_patch ("Image3 Stock Image Load", current_image.image + img3off, ibootsup_off2pat_patch (img3off, (uint8_t *) IBOOT_IOS7_IMG3PATCH_PATCH, 16, IBOOT_IOS7_IMG3PATCH_PLEN), 16); 427 | patch_list_add_patch ("Signature", current_image.image + sigoff, ibootsup_off2pat_patch (sigoff, (uint8_t *) IBOOT_IOS7_SIGPATCH, 16, IBOOT_IOS7_SIGPATCH_LEN), 16); 428 | if (bootargoff) { 429 | patch_list_add_patch ("BootArgs", current_image.image + bootargoff, ibootsup_off2pat_patch (bootargoff, (uint8_t *) IBOOT_DEFAULT_PWNARGS, sizeof (IBOOT_DEFAULT_BOOTARGS), sizeof (IBOOT_DEFAULT_BOOTARGS)), sizeof (IBOOT_DEFAULT_BOOTARGS)); 430 | } 431 | if (bacondoff) { 432 | patch_list_add_patch ("BootArgs Conditional", current_image.image + bacondoff, ibootsup_off2pat_patch (bacondoff, (uint8_t *) IBOOT_IOS7_BA_COND_PATCH, 16, IBOOT_IOS7_BA_COND_LEN), 16); 433 | } 434 | 435 | patch_list_iterate (); 436 | } 437 | 438 | static void 439 | ibootsup_patch_iboot (void) 440 | { 441 | struct patch_list *head, *iter; 442 | int total_patches, i = 0, j = 0; 443 | double progress = 0.0; 444 | printf ("Patching iBoot *NOW*...\n"); 445 | 446 | if (patch_list_get_head (&head, &total_patches)) { 447 | warn ("failed to get patch list head\n"); 448 | return; 449 | } 450 | 451 | /* 452 | * Patch it! 453 | */ 454 | for (iter = head, i = 0; i < total_patches; iter = iter->next, i++) { 455 | for (j = 0; j < current_image.size; j++) { 456 | if (!memcmp (current_image.image + j, iter->patch.original, iter->patch.size)) { 457 | memcpy (current_image.image + j, iter->patch.patched, iter->patch.size); 458 | progress = ((i + 1) / (double) total_patches) * 100.0; 459 | printf ("%4.1f%% done. [(%d/%d) %-32.32s]\r", progress, i + 1, total_patches, iter->patch.name); 460 | fflush (stdout); 461 | } 462 | } 463 | } 464 | printf ("\n"); 465 | } 466 | 467 | int 468 | ibootsup_dynapatch (void) 469 | { 470 | printf ("starting dynapatch...\n"); 471 | 472 | switch (ibootsup_get_ios_version ()) { 473 | case 4: /* iOS 4. */ 474 | ibootsup_patch_ios_old_iboot (); 475 | break; 476 | case 7: /* iOS 7. */ 477 | ibootsup_patch_ios7_iboot (); 478 | break; 479 | default: 480 | warn ("iOS %d not supported yet for iBoot patcher", ibootsup_get_ios_version ()); 481 | return -1; 482 | } 483 | 484 | ibootsup_patch_iboot (); 485 | 486 | return 0; 487 | } 488 | 489 | int 490 | ibootsup_write_file (const char *filename) 491 | { 492 | struct stat buf; 493 | FILE *fp = fopen (filename, "wb"); 494 | 495 | if (!fp) 496 | return -ENOENT; 497 | if (stat (filename, &buf) > 0) 498 | return -ENOENT; 499 | 500 | fwrite ((void *) current_image.image, current_image.size, 1, fp); 501 | fclose (fp); 502 | 503 | free (current_image.image); 504 | current_image.image = NULL; 505 | current_image.size = 0; 506 | 507 | return 0; 508 | } -------------------------------------------------------------------------------- /ibootsup.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013, winocm 3 | * All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | * 19 | * $Id$ 20 | */ 21 | 22 | #ifndef __IBOOTSUP_H 23 | #define __IBOOTSUP_H 24 | 25 | int ibootsup_dynapatch (void); 26 | int ibootsup_map_file (const char *filename); 27 | int ibootsup_write_file (const char* filename); 28 | int ibootsup_map_buffer (uint8_t* buf, int size); 29 | 30 | #endif /* __IBOOTSUP_H */ -------------------------------------------------------------------------------- /img3maker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013, winocm. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * Redistributions in binary form must reproduce the above copyright notice, this 12 | * list of conditions and the following disclaimer in the documentation and/or 13 | * other materials provided with the distribution. 14 | * 15 | * If you are going to use this software in any form that does not involve 16 | * releasing the source to this project or improving it, let me know beforehand. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | /* THIS UTILITY NEEDS TO BE REDONE PROPERLY !!! */ 31 | /* cc -O2 -pipe image3maker.c -o image3maker */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | typedef enum { 46 | IMAGE3_SEPO_S5L8920 = 4, 47 | IMAGE3_SEPO_S5L8922 = 2, 48 | IMAGE3_SEPO_S5L8930 = 2, 49 | IMAGE3_SEPO_S5L8940 = 17, 50 | IMAGE3_SEPO_S5L8942 = 16, 51 | IMAGE3_SEPO_S5L8945 = 16, 52 | IMAGE3_SEPO_S5L8947 = 16, 53 | IMAGE3_SEPO_S5L8950 = 16, 54 | IMAGE3_SEPO_S5L8955 = 16, 55 | IMAGE3_SEPO_S5L8747 = 16 56 | } Image3SecurityEpoch; 57 | 58 | typedef enum { 59 | IMAGE3_SDOM_FACTORY = 0, 60 | IMAGE3_SDOM_DARWIN = 1, 61 | } Image3SecurityDomain; 62 | 63 | typedef enum { 64 | IMAGE3_PROD_DEVELOPMENT = 0, 65 | IMAGE3_PROD_PRODUCTION = 1, 66 | } Image3ProductionType; 67 | 68 | #define kImage3Magic 'Img3' 69 | 70 | /* Image types */ 71 | #define kImage3TypeKernel 'krnl' 72 | #define kImage3TypeiBoot 'ibot' 73 | #define kImage3TypeiBSS 'ibss' 74 | #define kImage3TypeiBEC 'ibec' 75 | #define kImage3TypeiLLB 'illb' 76 | #define kImage3TypeAppleLogo 'logo' 77 | #define kImage3TypeRecoveryLogo 'recm' 78 | #define kImage3TypeNeedService 'nsrv' 79 | #define kImage3TypeDiags 'diag' 80 | #define kImage3TypeTsys 'tsys' 81 | #define kImage3TypeDeviceTree 'dtre' 82 | #define kImage3TypeCharging0 'chg0' 83 | #define kImage3TypeCharging1 'chg1' 84 | #define kImage3TypeGlyphCharging 'glyC' 85 | #define kImage3TypeGlyphPlugin 'glyP' 86 | #define kImage3TypeCertificate 'cert' 87 | 88 | /* Our types. */ 89 | #define kImage3TypeGenericBoot 'gbot' 90 | #define kImage3TypeXmlDeviceTree 'xmdt' 91 | #define kImage3TypeJsonDeviceTree 'jsdt' 92 | 93 | /* Image3 Tags */ 94 | #define kImage3TagData 'DATA' 95 | #define kImage3TagType 'TYPE' 96 | #define kImage3TagCert 'CERT' 97 | #define kImage3TagSignature 'SHSH' 98 | #define kImage3TagBoard 'BORD' 99 | #define kImage3TagKeyBag 'KBAG' 100 | #define kImage3TagSecurityEpoch 'SEPO' 101 | #define kImage3TagVersion 'VERS' 102 | #define kImage3TagSecurityDomain 'SDOM' 103 | #define kImage3TagProduct 'PROD' 104 | #define kImage3TagChip 'CHIP' 105 | #define kImage3TagChipEpoch 'CEPO' 106 | #define kImage3TagECID 'ECID' 107 | 108 | typedef struct Image3Header { 109 | uint32_t magic; 110 | uint32_t size; 111 | uint32_t dataSize; 112 | } __attribute__ ((packed)) Image3Header; 113 | 114 | typedef struct Image3ShshExtension { 115 | uint32_t shshOffset; 116 | uint32_t imageType; 117 | } __attribute__ ((packed)) Image3ShshExtension; 118 | 119 | typedef struct Image3RootHeader { 120 | Image3Header header; 121 | Image3ShshExtension shshExtension; 122 | } __attribute__ ((packed)) Image3RootHeader; 123 | 124 | typedef struct Image3Keybag { 125 | uint32_t state; 126 | uint32_t type; 127 | uint8_t iv[16]; 128 | uint8_t key[32]; 129 | } __attribute__ ((packed)) Image3Keybag; 130 | 131 | typedef struct __Image3Struct { 132 | Image3RootHeader *rootHeader; 133 | void* backingData; 134 | int backingDataSize; 135 | void* backingCertificate; 136 | int backingCertificateSize; 137 | uint32_t imageType; 138 | char* imageVersion; 139 | Image3SecurityEpoch imageSecurityEpoch; 140 | Image3SecurityDomain imageDomain; 141 | Image3ProductionType imageProductionType; 142 | uint32_t imageHardwareEpoch; 143 | uint32_t imageChipType; 144 | uint32_t imageBoardType; 145 | uint64_t imageUniqueIdentifier; 146 | uint8_t* imageAESKey; 147 | uint8_t* imageAESIV; 148 | } Image3Struct; 149 | 150 | #define add_ptr2(x, y) ((uintptr_t)((uintptr_t)x + (uintptr_t)y)) 151 | 152 | #define PROGRAM_NAME "image3maker" 153 | 154 | Image3Struct image3core; 155 | 156 | static char *inputFile = NULL, *outputFile = NULL, *imageTag = NULL; 157 | static char *imageVersion = NULL, *imageDomain = NULL, *imageProduction = NULL; 158 | static char *hardwareEpoch = NULL, *chipType = NULL, *boardType = NULL; 159 | static char *uniqueIdentifier = NULL, *aesKey = NULL, *aesIv = NULL; 160 | static char *certificateBlob = NULL, *imageSecurityEpoch = NULL; 161 | 162 | static inline void hex_to_bytes(const char* hex, uint8_t** buffer, size_t* bytes) { 163 | *bytes = strlen(hex) / 2; 164 | *buffer = (uint8_t*) malloc(*bytes); 165 | size_t i; 166 | for(i = 0; i < *bytes; i++) { 167 | uint32_t byte; 168 | sscanf(hex, "%2x", &byte); 169 | (*buffer)[i] = byte; 170 | hex += 2; 171 | } 172 | } 173 | 174 | static void* map_file(char *path, int *size) 175 | { 176 | FILE *f; 177 | long sz; 178 | void *p; 179 | 180 | assert((f = fopen(path, "rb"))); 181 | 182 | fseek(f, 0, SEEK_END); 183 | sz = ftell(f); 184 | fseek(f, 0, SEEK_SET); 185 | assert(sz); 186 | 187 | assert((p = malloc(sz)) != NULL); 188 | assert((sz != (fread(p, sz, 1, f)))); 189 | 190 | assert(size); 191 | *size = (int)sz; 192 | 193 | return p; 194 | } 195 | 196 | static void print_usage(void) 197 | { 198 | printf("Usage: %s [options]\n\n", PROGRAM_NAME); 199 | printf("Generate an Image3 file.\n" 200 | "\n" 201 | " -c, --certificateBlob [file] Use file as a certificate to add to the image.\n" 202 | " -f, --dataFile [file] Use file as an input. (required)\n" 203 | " -t, --imageTag [tag] 4-byte ASCII tag for image (required)\n" 204 | " -s, --imageSecurityEpoch [epoch] Set epoch\n" 205 | " Valid epochs are: s5l8920x, s5l8922x, s5l8930x\n" 206 | " s5l8940x, s5l8942x, s5l8947x\n" 207 | " s5l8950x, s5l8955x, s5l8747x\n" 208 | " -v, --imageVersion [version] Set version string\n" 209 | " -d, --imageDomain [securityDomain] Set specified security domain (manufacturer/Darwin)\n" 210 | " -p, --imageProduction [prodValue] Mark image production value (production/development)\n" 211 | " -h, --hardwareEpoch [epoch] Set chip epoch\n" 212 | " -y, --chipType [chipType] Set chip type\n" 213 | " -b, --boardType [boardType] Set board type\n" 214 | " -e, --uniqueIdentifier [uniqueID] Set ECID for image\n" 215 | " -a, --aesKey [aesKey] Set AES key for image encryption (implies -i/--aesIv)\n" 216 | " -i, --aesIv [aesIv] Set AES IV for image encryption (implies -a/--aesKey)\n" 217 | " -o, --outputFile [file] Output image3 file\n" 218 | "\n" 219 | "Only AES256 keybags are supported by this program right now.\n" 220 | "Have fun using this thingy. (ALL VALUES FOR THINGS SHOULD BE IN HEX!!!)\n"); 221 | exit(-1); 222 | return; 223 | } 224 | 225 | static uint32_t fourcc_to_uint(char* str) 226 | { 227 | uint32_t out; 228 | assert(strlen(str) == 4); 229 | out = __builtin_bswap32(*(uint32_t*)str); 230 | return out; 231 | } 232 | 233 | static inline int round_up(int n, int m) 234 | { 235 | return (n + m - 1) & ~(m - 1); 236 | } 237 | 238 | static void *image3_reserve_version(uint32_t tag, uint32_t length) 239 | { 240 | uint32_t size, len; 241 | Image3Header* header; 242 | 243 | /* Make it even */ 244 | len = (uint32_t)round_up(length + sizeof(Image3Header), 2); 245 | size = (uint32_t)round_up(image3core.rootHeader->header.size + len, 16); 246 | 247 | /* Padding */ 248 | len += ((uint32_t)round_up(image3core.rootHeader->header.size + len, 16) - 249 | (uint32_t)round_up(image3core.rootHeader->header.size + len, 2)); 250 | 251 | /* APPLE.. */ 252 | len -= 4; 253 | size -= 4; 254 | 255 | assert((image3core.rootHeader = realloc(image3core.rootHeader, size))); 256 | 257 | header = (Image3Header*)add_ptr2(image3core.rootHeader, image3core.rootHeader->header.size); 258 | bzero((void*)(header), len); 259 | 260 | header->dataSize = length; 261 | header->size = len; 262 | header->magic = tag; 263 | 264 | image3core.rootHeader->header.size = size; 265 | image3core.rootHeader->header.dataSize += len; 266 | 267 | return (void*)(header + 1); 268 | } 269 | 270 | static void *image3_reserve_data(uint32_t tag, uint32_t length) 271 | { 272 | uint32_t size, len; 273 | Image3Header* header; 274 | 275 | /* Make it even */ 276 | len = (uint32_t)round_up(length + sizeof(Image3Header), 2); 277 | size = (uint32_t)round_up(image3core.rootHeader->header.size + len, 16); 278 | 279 | /* Padding */ 280 | len += ((uint32_t)round_up(image3core.rootHeader->header.size + len, 16) - 281 | (uint32_t)round_up(image3core.rootHeader->header.size + len, 2)); 282 | 283 | assert((image3core.rootHeader = realloc(image3core.rootHeader, size))); 284 | 285 | header = (Image3Header*)add_ptr2(image3core.rootHeader, image3core.rootHeader->header.size); 286 | bzero((void*)(header), len); 287 | 288 | header->dataSize = length; 289 | header->size = len; 290 | header->magic = tag; 291 | 292 | image3core.rootHeader->header.size = size; 293 | image3core.rootHeader->header.dataSize += len; 294 | 295 | return (void*)(header + 1); 296 | } 297 | 298 | /* This is for other tags other than data. Apple is weird like this. */ 299 | static void *image3_reserve_tag(uint32_t tag, uint32_t length) 300 | { 301 | uint32_t size, len; 302 | Image3Header* header; 303 | 304 | len = length + 24; 305 | size = image3core.rootHeader->header.size + len; 306 | 307 | assert((image3core.rootHeader = realloc(image3core.rootHeader, size))); 308 | 309 | header = (Image3Header*)add_ptr2(image3core.rootHeader, image3core.rootHeader->header.size); 310 | bzero((void*)(header), len); 311 | 312 | header->dataSize = length; 313 | header->size = len; 314 | header->magic = tag; 315 | 316 | image3core.rootHeader->header.size = size; 317 | image3core.rootHeader->header.dataSize += len; 318 | 319 | 320 | return (void*)(header + 1); 321 | } 322 | 323 | /* This is for other tags other than data. Apple is weird like this. */ 324 | static void *image3_reserve_ecid(uint32_t tag, uint32_t length) 325 | { 326 | uint32_t size, len; 327 | Image3Header* header; 328 | 329 | len = length + 20; 330 | size = image3core.rootHeader->header.size + len; 331 | 332 | assert((image3core.rootHeader = realloc(image3core.rootHeader, size))); 333 | 334 | header = (Image3Header*)add_ptr2(image3core.rootHeader, image3core.rootHeader->header.size); 335 | bzero((void*)(header), len); 336 | 337 | header->dataSize = length; 338 | header->size = len; 339 | header->magic = tag; 340 | 341 | image3core.rootHeader->header.size = size; 342 | image3core.rootHeader->header.dataSize += len; 343 | 344 | return (void*)(header + 1); 345 | } 346 | 347 | /* This is to make sure the DATA is always at 0x40. */ 348 | static void *image3_reserve_type(uint32_t tag, uint32_t length) 349 | { 350 | uint32_t size, len; 351 | Image3Header* header; 352 | 353 | len = length + 28; 354 | size = image3core.rootHeader->header.size + len; 355 | 356 | assert((image3core.rootHeader = realloc(image3core.rootHeader, size))); 357 | 358 | header = (Image3Header*)add_ptr2(image3core.rootHeader, image3core.rootHeader->header.size); 359 | header->dataSize = length; 360 | header->size = len; 361 | header->magic = tag; 362 | 363 | image3core.rootHeader->header.size = size; 364 | image3core.rootHeader->header.dataSize += len; 365 | 366 | return (void*)(header + 1); 367 | } 368 | 369 | static void create_image(void) 370 | { 371 | printf("Creating image of type \'%s\' (0x%08x)...\n", imageTag, image3core.imageType); 372 | 373 | assert((image3core.rootHeader = malloc(sizeof(Image3RootHeader)))); 374 | 375 | image3core.rootHeader->header.magic = kImage3Magic; 376 | image3core.rootHeader->shshExtension.imageType = image3core.imageType; 377 | 378 | image3core.rootHeader->header.dataSize = image3core.rootHeader->header.size = 379 | image3core.rootHeader->shshExtension.shshOffset = 0; 380 | 381 | image3core.rootHeader->header.size = sizeof(Image3RootHeader); 382 | 383 | /* DATA/TYPE tags */ 384 | uint32_t* type; 385 | void* data; 386 | 387 | type = image3_reserve_type(kImage3TagType, sizeof(uint32_t)); 388 | *type = image3core.imageType; 389 | 390 | data = image3_reserve_data(kImage3TagData, image3core.backingDataSize); 391 | memcpy(data, image3core.backingData, image3core.backingDataSize); 392 | 393 | /* Other tags */ 394 | if(imageVersion) { 395 | printf("Image Version: %s\n", imageVersion); 396 | 397 | void* version; 398 | uint32_t *length; 399 | version = image3_reserve_version(kImage3TagVersion, (uint32_t)strlen(imageVersion) + 4); 400 | length = (uint32_t*)version; 401 | *(length) = (uint32_t)strlen(imageVersion); 402 | strncpy((char*)version + sizeof(uint32_t), imageVersion, strlen(imageVersion)); 403 | } 404 | 405 | if(imageSecurityEpoch) { 406 | printf("Security Epoch: 0x%08x\n", image3core.imageSecurityEpoch); 407 | 408 | uint32_t *epoch = image3_reserve_tag(kImage3TagSecurityEpoch, sizeof(uint32_t)); 409 | *epoch = image3core.imageSecurityEpoch; 410 | } 411 | 412 | 413 | if(hardwareEpoch) { 414 | printf("Chip Epoch: 0x%08x\n", image3core.imageHardwareEpoch); 415 | 416 | uint32_t *epoch = image3_reserve_tag(kImage3TagChipEpoch, sizeof(uint32_t)); 417 | *epoch = image3core.imageHardwareEpoch; 418 | } 419 | 420 | if(imageDomain) { 421 | printf("Security Domain: 0x%08x\n", image3core.imageDomain); 422 | 423 | uint32_t *securityDomain = image3_reserve_tag(kImage3TagSecurityDomain, sizeof(uint32_t)); 424 | *securityDomain = image3core.imageDomain; 425 | } 426 | 427 | if(imageProduction) { 428 | printf("Production Type: 0x%08x\n", image3core.imageProductionType); 429 | 430 | uint32_t *imageProd = image3_reserve_tag(kImage3TagProduct, sizeof(uint32_t)); 431 | *imageProd = image3core.imageProductionType; 432 | } 433 | 434 | if(chipType) { 435 | printf("Chip Type: 0x%08x\n", image3core.imageChipType); 436 | 437 | uint32_t *chip = image3_reserve_tag(kImage3TagChip, sizeof(uint32_t)); 438 | *chip = image3core.imageChipType; 439 | } 440 | 441 | if(boardType) { 442 | printf("Board Type: 0x%08x\n", image3core.imageBoardType); 443 | 444 | uint32_t *board = image3_reserve_tag(kImage3TagBoard, sizeof(uint32_t)); 445 | *board = image3core.imageBoardType; 446 | } 447 | 448 | if(uniqueIdentifier) { 449 | printf("ECID: 0x%016llx\n", image3core.imageUniqueIdentifier); 450 | 451 | uint64_t *ecid = image3_reserve_ecid(kImage3TagECID, sizeof(uint64_t)); 452 | *ecid = image3core.imageUniqueIdentifier; 453 | } 454 | 455 | /* AES stuff... TODO */ 456 | printf("Total Size: %d bytes\n", image3core.rootHeader->header.size); 457 | printf("Data Size: %d bytes\n", image3core.rootHeader->header.dataSize); 458 | } 459 | 460 | static void output_image(void) 461 | { 462 | FILE *f; 463 | assert((f = fopen(outputFile, "wb+"))); 464 | assert(image3core.rootHeader->header.size != fwrite(image3core.rootHeader, image3core.rootHeader->header.size, 1, f)); 465 | fclose(f); 466 | } 467 | 468 | static void create_image_preprocess(void) 469 | { 470 | assert(inputFile && imageTag && outputFile); 471 | 472 | bzero((void*)&image3core, sizeof(Image3Struct)); 473 | 474 | /* Read input file */ 475 | image3core.backingData = map_file(inputFile, &image3core.backingDataSize); 476 | assert(image3core.backingDataSize); 477 | 478 | if(certificateBlob) { 479 | image3core.backingCertificate = map_file(certificateBlob, &image3core.backingCertificateSize); 480 | assert(image3core.backingCertificateSize); 481 | } 482 | 483 | /* Image tag */ 484 | image3core.imageType = fourcc_to_uint(imageTag); 485 | 486 | /* Other stuff. */ 487 | image3core.imageVersion = imageVersion; 488 | 489 | if(imageSecurityEpoch) { 490 | /* lol buffer overflow */ 491 | if(!strcasecmp(imageSecurityEpoch, "s5l8920x")) 492 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8920; 493 | else if(!strcasecmp(imageSecurityEpoch, "s5l8922x")) 494 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8922; 495 | else if(!strcasecmp(imageSecurityEpoch, "s5l8930x")) 496 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8930; 497 | else if(!strcasecmp(imageSecurityEpoch, "s5l8940x")) 498 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8940; 499 | else if(!strcasecmp(imageSecurityEpoch, "s5l8950x")) 500 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8950; 501 | else if(!strcasecmp(imageSecurityEpoch, "s5l8955x")) 502 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8955; 503 | else if(!strcasecmp(imageSecurityEpoch, "s5l8947x")) 504 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8947; 505 | else if(!strcasecmp(imageSecurityEpoch, "s5l8942x")) 506 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8942; 507 | else if(!strcasecmp(imageSecurityEpoch, "s5l8747x")) 508 | image3core.imageSecurityEpoch = IMAGE3_SEPO_S5L8747; 509 | else { 510 | printf("invalid security epoch '%s'\n", imageSecurityEpoch); 511 | exit(-1); 512 | } 513 | } 514 | 515 | /* SDOM */ 516 | if(imageDomain) { 517 | /* lol buffer overflow */ 518 | if(!strcasecmp(imageDomain, "darwin")) 519 | image3core.imageDomain = IMAGE3_SDOM_DARWIN; 520 | else if(!strcasecmp(imageDomain, "manufacturer")) 521 | image3core.imageDomain = IMAGE3_SDOM_FACTORY; 522 | else { 523 | printf("invalid domain '%s'\n", imageDomain); 524 | exit(-1); 525 | } 526 | } 527 | 528 | /* PROD */ 529 | if(imageProduction) { 530 | /* lol buffer overflow */ 531 | if(!strcasecmp(imageProduction, "production")) 532 | image3core.imageProductionType = IMAGE3_PROD_PRODUCTION; 533 | else if(!strcasecmp(imageProduction, "development")) 534 | image3core.imageProductionType = IMAGE3_PROD_DEVELOPMENT; 535 | else { 536 | printf("invalid production type '%s'\n", imageProduction); 537 | exit(-1); 538 | } 539 | } 540 | 541 | /* Other stuff */ 542 | if(hardwareEpoch) { 543 | image3core.imageHardwareEpoch = (uint32_t)strtoul((const char*)hardwareEpoch, NULL, 16); 544 | } 545 | 546 | if(chipType) { 547 | image3core.imageChipType = (uint32_t)strtoul((const char*)chipType, NULL, 16); 548 | } 549 | 550 | if(boardType) { 551 | image3core.imageBoardType = (uint32_t)strtoul((const char*)boardType, NULL, 16); 552 | } 553 | 554 | if(uniqueIdentifier) { 555 | image3core.imageUniqueIdentifier = (uint64_t)strtoull((const char*)uniqueIdentifier, NULL, 16); 556 | } 557 | 558 | /* AES key/iv */ 559 | if(aesKey && aesIv) { 560 | size_t szKey, szIv; 561 | hex_to_bytes(aesKey, &image3core.imageAESKey, &szKey); 562 | hex_to_bytes(aesIv, &image3core.imageAESIV, &szIv); 563 | assert((szKey == 32) && (szIv == 16)); 564 | } 565 | 566 | return; 567 | } 568 | 569 | static int process_options(int argc, char* argv[]) 570 | { 571 | int c = 0; 572 | 573 | while(1) { 574 | static struct option user_options[] = { 575 | {"certificateBlob", required_argument, 0, 'c'}, 576 | {"dataFile", required_argument, 0, 'f'}, 577 | {"imageTag", required_argument, 0, 't'}, 578 | {"imageVersion", required_argument, 0, 'v'}, 579 | {"imageSecurityEpoch", required_argument, 0, 's'}, 580 | {"imageDomain", required_argument, 0, 'd'}, 581 | {"imageProduction", required_argument, 0, 'p'}, 582 | {"hardwareEpoch", required_argument, 0, 'h'}, 583 | {"chipType", required_argument, 0, 'y'}, 584 | {"boardType", required_argument, 0, 'b'}, 585 | {"uniqueIdentifier", required_argument, 0, 'e'}, 586 | {"aesKey", required_argument, 0, 'a'}, 587 | {"aesIv", required_argument, 0, 'i'}, 588 | {"outputFile", required_argument, 0, 'o'}, 589 | {"help", no_argument, 0, '?'}, 590 | }; 591 | int option_index = 0; 592 | 593 | c = getopt_long(argc, argv, "c:f:t:v:d:p:h:y:b:s:e:a:i:o:", 594 | user_options, &option_index); 595 | 596 | if(c == -1) 597 | break; 598 | 599 | switch(c) { 600 | case 's': 601 | imageSecurityEpoch = optarg; 602 | break; 603 | case 'c': 604 | certificateBlob = optarg; 605 | break; 606 | case 'f': 607 | inputFile = optarg; 608 | break; 609 | case 'o': 610 | outputFile = optarg; 611 | break; 612 | case 't': 613 | imageTag = optarg; 614 | break; 615 | case 'v': 616 | imageVersion = optarg; 617 | break; 618 | case 'd': 619 | imageDomain = optarg; 620 | break; 621 | case 'p': 622 | imageProduction = optarg; 623 | break; 624 | case 'h': 625 | hardwareEpoch = optarg; 626 | break; 627 | case 'y': 628 | chipType = optarg; 629 | break; 630 | case 'b': 631 | boardType = optarg; 632 | break; 633 | case 'e': 634 | uniqueIdentifier = optarg; 635 | break; 636 | case 'a': 637 | aesKey = optarg; 638 | break; 639 | case 'i': 640 | aesIv = optarg; 641 | break; 642 | default: 643 | print_usage(); 644 | break; 645 | } 646 | } 647 | 648 | if(!inputFile) { 649 | printf("No input file\n"); 650 | print_usage(); 651 | } 652 | 653 | if(!outputFile) { 654 | printf("No output file\n"); 655 | print_usage(); 656 | } 657 | 658 | if(!imageTag) { 659 | printf("No image tag\n"); 660 | print_usage(); 661 | } 662 | 663 | return 0; 664 | } 665 | 666 | int main(int argc, char* argv[]) 667 | { 668 | process_options(argc, argv); 669 | create_image_preprocess(); 670 | create_image(); 671 | output_image(); 672 | return 0; 673 | } 674 | -------------------------------------------------------------------------------- /kdumper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014, winocm. 3 | * Hacked 2014, xerub. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | * 19 | * $Id$ 20 | */ 21 | /* 22 | * kdumper 23 | * Requires iOS 6.x or 7.x. (This version only.) 24 | * 25 | * Remap addresses: 26 | * 0x7fe00000 -> 0x9fe00000 (0x5fe00000) iBSS (jump-to only.) 27 | * 28 | * xcrun -sdk iphoneos clang kloader.c -arch armv7 -framework IOKit -framework CoreFoundation -no-integrated-as \ 29 | * -DINLINE_IT_ALL=1 -Wall -o kloader -miphoneos-version-min=6.0; ldid -Stfp0.plist kloader 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #define printf myprintf 42 | static void myprintf(const char *fmt, ...); 43 | #define PREFIX "" 44 | 45 | typedef mach_port_t io_service_t; 46 | extern mach_port_t kIOMasterPortDefault; 47 | extern mach_port_t IOPMFindPowerManagement(mach_port_t); 48 | extern kern_return_t IOPMSleepSystem(mach_port_t); 49 | 50 | /* 51 | * ARM page bits for L1 sections. 52 | */ 53 | #define L1_SHIFT 20 /* log2(1MB) */ 54 | 55 | #define L1_SECT_PROTO (1 << 1) /* 0b10 */ 56 | 57 | #define L1_SECT_B_BIT (1 << 2) 58 | #define L1_SECT_C_BIT (1 << 3) 59 | 60 | #define L1_SECT_SORDER (0) /* 0b00, not cacheable, strongly ordered. */ 61 | #define L1_SECT_SH_DEVICE (L1_SECT_B_BIT) 62 | #define L1_SECT_WT_NWA (L1_SECT_C_BIT) 63 | #define L1_SECT_WB_NWA (L1_SECT_B_BIT | L1_SECT_C_BIT) 64 | #define L1_SECT_S_BIT (1 << 16) 65 | 66 | #define L1_SECT_AP_URW (1 << 10) | (1 << 11) 67 | #define L1_SECT_PFN(x) (x & 0xFFF00000) 68 | 69 | #define L1_SECT_DEFPROT (L1_SECT_AP_URW) 70 | #define L1_SECT_DEFCACHE (L1_SECT_SORDER) 71 | 72 | #define L1_PROTO_TTE(paddr) (L1_SECT_PFN(paddr) | L1_SECT_S_BIT | L1_SECT_DEFPROT | L1_SECT_DEFCACHE | L1_SECT_PROTO) 73 | 74 | #define PFN_SHIFT 2 75 | #define TTB_OFFSET(vaddr) ((vaddr >> L1_SHIFT) << PFN_SHIFT) 76 | 77 | /* 78 | * RAM physical base begin. 79 | */ 80 | #define S5L8930_PHYS_OFF 0x40000000 81 | #define S5L8940_PHYS_OFF 0x80000000 /* Note: RAM base is identical for 8940-8955. */ 82 | 83 | uint32_t PHYS_OFF = S5L8930_PHYS_OFF; 84 | 85 | /* 86 | * Shadowmap begin and end. 15MB of shadowmap is enough for the kernel. 87 | * We don't need to invalidate unified D/I TLB or any cache lines 88 | * since the kernel is mapped as writethrough memory, and these 89 | * addresses are guaranteed to not be translated. 90 | * (Accesses will cause segmentation faults due to failure on L1 translation.) 91 | * 92 | * Clear the shadowmappings when done owning the kernel. 93 | * 94 | * 0x7ff0'0000 is also below the limit for vm_read and such, so that's also *great*. 95 | * (2048 bytes) 96 | */ 97 | #define SHADOWMAP_BEGIN 0x7f000000 98 | #define SHADOWMAP_END 0x80000000 99 | #define SHADOWMAP_GRANULARITY 0x00100000 100 | 101 | #define SHADOWMAP_SIZE_BYTES (SHADOWMAP_END - SHADOWMAP_BEGIN) 102 | 103 | #define SHADOWMAP_BEGIN_OFF TTB_OFFSET(SHADOWMAP_BEGIN) 104 | #define SHADOWMAP_END_OFF TTB_OFFSET(SHADOWMAP_END) 105 | #define SHADOWMAP_SIZE (SHADOWMAP_END_OFF - SHADOWMAP_BEGIN_OFF) 106 | 107 | #define SHADOWMAP_BEGIN_IDX (SHADOWMAP_BEGIN_OFF >> PFN_SHIFT) 108 | #define SHADOWMAP_END_IDX (SHADOWMAP_END_OFF >> PFN_SHIFT) 109 | 110 | #define TTB_SIZE 4096 111 | #define DEFAULT_KERNEL_SLIDE 0x80000000 112 | 113 | static mach_port_t kernel_task = 0; 114 | static uint32_t ttb_template[TTB_SIZE] = { }; 115 | 116 | static void *ttb_template_ptr = &ttb_template[0]; 117 | static vm_address_t kernel_base = DEFAULT_KERNEL_SLIDE; 118 | 119 | typedef struct pmap_partial_t { 120 | uint32_t tte_virt; 121 | uint32_t tte_phys; 122 | /* 123 | * ... 124 | */ 125 | } pmap_partial_t; 126 | 127 | /* --- planetbeing patchfinder --- */ 128 | 129 | static uint32_t bit_range(uint32_t x, int start, int end) 130 | { 131 | x = (x << (31 - start)) >> (31 - start); 132 | x = (x >> end); 133 | return x; 134 | } 135 | 136 | static uint32_t ror(uint32_t x, int places) 137 | { 138 | return (x >> places) | (x << (32 - places)); 139 | } 140 | 141 | static int thumb_expand_imm_c(uint16_t imm12) 142 | { 143 | if (bit_range(imm12, 11, 10) == 0) { 144 | switch (bit_range(imm12, 9, 8)) { 145 | case 0: 146 | return bit_range(imm12, 7, 0); 147 | case 1: 148 | return (bit_range(imm12, 7, 0) << 16) | bit_range(imm12, 7, 0); 149 | case 2: 150 | return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 8); 151 | case 3: 152 | return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 16) | (bit_range(imm12, 7, 0) << 8) | bit_range(imm12, 7, 0); 153 | default: 154 | return 0; 155 | } 156 | } else { 157 | uint32_t unrotated_value = 0x80 | bit_range(imm12, 6, 0); 158 | return ror(unrotated_value, bit_range(imm12, 11, 7)); 159 | } 160 | } 161 | 162 | static int insn_is_32bit(uint16_t * i) 163 | { 164 | return (*i & 0xe000) == 0xe000 && (*i & 0x1800) != 0x0; 165 | } 166 | 167 | static int insn_is_bl(uint16_t * i) 168 | { 169 | if ((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd000) == 0xd000) 170 | return 1; 171 | else if ((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd001) == 0xc000) 172 | return 1; 173 | else 174 | return 0; 175 | } 176 | 177 | static uint32_t insn_bl_imm32(uint16_t * i) 178 | { 179 | uint16_t insn0 = *i; 180 | uint16_t insn1 = *(i + 1); 181 | uint32_t s = (insn0 >> 10) & 1; 182 | uint32_t j1 = (insn1 >> 13) & 1; 183 | uint32_t j2 = (insn1 >> 11) & 1; 184 | uint32_t i1 = ~(j1 ^ s) & 1; 185 | uint32_t i2 = ~(j2 ^ s) & 1; 186 | uint32_t imm10 = insn0 & 0x3ff; 187 | uint32_t imm11 = insn1 & 0x7ff; 188 | uint32_t imm32 = (imm11 << 1) | (imm10 << 12) | (i2 << 22) | (i1 << 23) | (s ? 0xff000000 : 0); 189 | return imm32; 190 | } 191 | 192 | static int insn_is_b_conditional(uint16_t * i) 193 | { 194 | return (*i & 0xF000) == 0xD000 && (*i & 0x0F00) != 0x0F00 && (*i & 0x0F00) != 0xE; 195 | } 196 | 197 | static int insn_is_b_unconditional(uint16_t * i) 198 | { 199 | if ((*i & 0xF800) == 0xE000) 200 | return 1; 201 | else if ((*i & 0xF800) == 0xF000 && (*(i + 1) & 0xD000) == 9) 202 | return 1; 203 | else 204 | return 0; 205 | } 206 | 207 | static int insn_is_ldr_literal(uint16_t * i) 208 | { 209 | return (*i & 0xF800) == 0x4800 || (*i & 0xFF7F) == 0xF85F; 210 | } 211 | 212 | static int insn_ldr_literal_rt(uint16_t * i) 213 | { 214 | if ((*i & 0xF800) == 0x4800) 215 | return (*i >> 8) & 7; 216 | else if ((*i & 0xFF7F) == 0xF85F) 217 | return (*(i + 1) >> 12) & 0xF; 218 | else 219 | return 0; 220 | } 221 | 222 | static int insn_ldr_literal_imm(uint16_t * i) 223 | { 224 | if ((*i & 0xF800) == 0x4800) 225 | return (*i & 0xF) << 2; 226 | else if ((*i & 0xFF7F) == 0xF85F) 227 | return (*(i + 1) & 0xFFF) * (((*i & 0x0800) == 0x0800) ? 1 : -1); 228 | else 229 | return 0; 230 | } 231 | 232 | // TODO: More encodings 233 | static int insn_is_ldr_imm(uint16_t * i) 234 | { 235 | uint8_t opA = bit_range(*i, 15, 12); 236 | uint8_t opB = bit_range(*i, 11, 9); 237 | 238 | return opA == 6 && (opB & 4) == 4; 239 | } 240 | 241 | static int insn_ldr_imm_rt(uint16_t * i) 242 | { 243 | return (*i & 7); 244 | } 245 | 246 | static int insn_ldr_imm_rn(uint16_t * i) 247 | { 248 | return ((*i >> 3) & 7); 249 | } 250 | 251 | static int insn_ldr_imm_imm(uint16_t * i) 252 | { 253 | return ((*i >> 6) & 0x1F); 254 | } 255 | 256 | // TODO: More encodings 257 | static int insn_is_ldrb_imm(uint16_t * i) 258 | { 259 | return (*i & 0xF800) == 0x7800; 260 | } 261 | 262 | static int insn_ldrb_imm_rt(uint16_t * i) 263 | { 264 | return (*i & 7); 265 | } 266 | 267 | static int insn_ldrb_imm_rn(uint16_t * i) 268 | { 269 | return ((*i >> 3) & 7); 270 | } 271 | 272 | static int insn_ldrb_imm_imm(uint16_t * i) 273 | { 274 | return ((*i >> 6) & 0x1F); 275 | } 276 | 277 | static int insn_is_ldr_reg(uint16_t * i) 278 | { 279 | if ((*i & 0xFE00) == 0x5800) 280 | return 1; 281 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 282 | return 1; 283 | else 284 | return 0; 285 | } 286 | 287 | static int insn_ldr_reg_rn(uint16_t * i) 288 | { 289 | if ((*i & 0xFE00) == 0x5800) 290 | return (*i >> 3) & 0x7; 291 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 292 | return (*i & 0xF); 293 | else 294 | return 0; 295 | } 296 | 297 | int insn_ldr_reg_rt(uint16_t * i) 298 | { 299 | if ((*i & 0xFE00) == 0x5800) 300 | return *i & 0x7; 301 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 302 | return (*(i + 1) >> 12) & 0xF; 303 | else 304 | return 0; 305 | } 306 | 307 | int insn_ldr_reg_rm(uint16_t * i) 308 | { 309 | if ((*i & 0xFE00) == 0x5800) 310 | return (*i >> 6) & 0x7; 311 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 312 | return *(i + 1) & 0xF; 313 | else 314 | return 0; 315 | } 316 | 317 | static int insn_ldr_reg_lsl(uint16_t * i) 318 | { 319 | if ((*i & 0xFE00) == 0x5800) 320 | return 0; 321 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 322 | return (*(i + 1) >> 4) & 0x3; 323 | else 324 | return 0; 325 | } 326 | 327 | static int insn_is_add_reg(uint16_t * i) 328 | { 329 | if ((*i & 0xFE00) == 0x1800) 330 | return 1; 331 | else if ((*i & 0xFF00) == 0x4400) 332 | return 1; 333 | else if ((*i & 0xFFE0) == 0xEB00) 334 | return 1; 335 | else 336 | return 0; 337 | } 338 | 339 | static int insn_add_reg_rd(uint16_t * i) 340 | { 341 | if ((*i & 0xFE00) == 0x1800) 342 | return (*i & 7); 343 | else if ((*i & 0xFF00) == 0x4400) 344 | return (*i & 7) | ((*i & 0x80) >> 4); 345 | else if ((*i & 0xFFE0) == 0xEB00) 346 | return (*(i + 1) >> 8) & 0xF; 347 | else 348 | return 0; 349 | } 350 | 351 | static int insn_add_reg_rn(uint16_t * i) 352 | { 353 | if ((*i & 0xFE00) == 0x1800) 354 | return ((*i >> 3) & 7); 355 | else if ((*i & 0xFF00) == 0x4400) 356 | return (*i & 7) | ((*i & 0x80) >> 4); 357 | else if ((*i & 0xFFE0) == 0xEB00) 358 | return (*i & 0xF); 359 | else 360 | return 0; 361 | } 362 | 363 | static int insn_add_reg_rm(uint16_t * i) 364 | { 365 | if ((*i & 0xFE00) == 0x1800) 366 | return (*i >> 6) & 7; 367 | else if ((*i & 0xFF00) == 0x4400) 368 | return (*i >> 3) & 0xF; 369 | else if ((*i & 0xFFE0) == 0xEB00) 370 | return *(i + 1) & 0xF; 371 | else 372 | return 0; 373 | } 374 | 375 | static int insn_is_movt(uint16_t * i) 376 | { 377 | return (*i & 0xFBF0) == 0xF2C0 && (*(i + 1) & 0x8000) == 0; 378 | } 379 | 380 | static int insn_movt_rd(uint16_t * i) 381 | { 382 | return (*(i + 1) >> 8) & 0xF; 383 | } 384 | 385 | static int insn_movt_imm(uint16_t * i) 386 | { 387 | return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF); 388 | } 389 | 390 | static int insn_is_mov_imm(uint16_t * i) 391 | { 392 | if ((*i & 0xF800) == 0x2000) 393 | return 1; 394 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 395 | return 1; 396 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 397 | return 1; 398 | else 399 | return 0; 400 | } 401 | 402 | static int insn_mov_imm_rd(uint16_t * i) 403 | { 404 | if ((*i & 0xF800) == 0x2000) 405 | return (*i >> 8) & 7; 406 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 407 | return (*(i + 1) >> 8) & 0xF; 408 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 409 | return (*(i + 1) >> 8) & 0xF; 410 | else 411 | return 0; 412 | } 413 | 414 | static int insn_mov_imm_imm(uint16_t * i) 415 | { 416 | if ((*i & 0xF800) == 0x2000) 417 | return *i & 0xF; 418 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 419 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 420 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 421 | return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF); 422 | else 423 | return 0; 424 | } 425 | 426 | static int insn_is_cmp_imm(uint16_t * i) 427 | { 428 | if ((*i & 0xF800) == 0x2800) 429 | return 1; 430 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 431 | return 1; 432 | else 433 | return 0; 434 | } 435 | 436 | static int insn_cmp_imm_rn(uint16_t * i) 437 | { 438 | if ((*i & 0xF800) == 0x2800) 439 | return (*i >> 8) & 7; 440 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 441 | return *i & 0xF; 442 | else 443 | return 0; 444 | } 445 | 446 | static int insn_cmp_imm_imm(uint16_t * i) 447 | { 448 | if ((*i & 0xF800) == 0x2800) 449 | return *i & 0xFF; 450 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 451 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 452 | else 453 | return 0; 454 | } 455 | 456 | static int insn_is_and_imm(uint16_t * i) 457 | { 458 | return (*i & 0xFBE0) == 0xF000 && (*(i + 1) & 0x8000) == 0; 459 | } 460 | 461 | static int insn_and_imm_rn(uint16_t * i) 462 | { 463 | return *i & 0xF; 464 | } 465 | 466 | static int insn_and_imm_rd(uint16_t * i) 467 | { 468 | return (*(i + 1) >> 8) & 0xF; 469 | } 470 | 471 | static int insn_and_imm_imm(uint16_t * i) 472 | { 473 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 474 | } 475 | 476 | static int insn_is_push(uint16_t * i) 477 | { 478 | if ((*i & 0xFE00) == 0xB400) 479 | return 1; 480 | else if (*i == 0xE92D) 481 | return 1; 482 | else if (*i == 0xF84D && (*(i + 1) & 0x0FFF) == 0x0D04) 483 | return 1; 484 | else 485 | return 0; 486 | } 487 | 488 | static int insn_push_registers(uint16_t * i) 489 | { 490 | if ((*i & 0xFE00) == 0xB400) 491 | return (*i & 0x00FF) | ((*i & 0x0100) << 6); 492 | else if (*i == 0xE92D) 493 | return *(i + 1); 494 | else if (*i == 0xF84D && (*(i + 1) & 0x0FFF) == 0x0D04) 495 | return 1 << ((*(i + 1) >> 12) & 0xF); 496 | else 497 | return 0; 498 | } 499 | 500 | static int insn_is_preamble_push(uint16_t * i) 501 | { 502 | return insn_is_push(i) && (insn_push_registers(i) & (1 << 14)) != 0; 503 | } 504 | 505 | static int insn_is_str_imm(uint16_t * i) 506 | { 507 | if ((*i & 0xF800) == 0x6000) 508 | return 1; 509 | else if ((*i & 0xF800) == 0x9000) 510 | return 1; 511 | else if ((*i & 0xFFF0) == 0xF8C0) 512 | return 1; 513 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 514 | return 1; 515 | else 516 | return 0; 517 | } 518 | 519 | static int insn_str_imm_postindexed(uint16_t * i) 520 | { 521 | if ((*i & 0xF800) == 0x6000) 522 | return 1; 523 | else if ((*i & 0xF800) == 0x9000) 524 | return 1; 525 | else if ((*i & 0xFFF0) == 0xF8C0) 526 | return 1; 527 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 528 | return (*(i + 1) >> 10) & 1; 529 | else 530 | return 0; 531 | } 532 | 533 | static int insn_str_imm_wback(uint16_t * i) 534 | { 535 | if ((*i & 0xF800) == 0x6000) 536 | return 0; 537 | else if ((*i & 0xF800) == 0x9000) 538 | return 0; 539 | else if ((*i & 0xFFF0) == 0xF8C0) 540 | return 0; 541 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 542 | return (*(i + 1) >> 8) & 1; 543 | else 544 | return 0; 545 | } 546 | 547 | static int insn_str_imm_imm(uint16_t * i) 548 | { 549 | if ((*i & 0xF800) == 0x6000) 550 | return (*i & 0x07C0) >> 4; 551 | else if ((*i & 0xF800) == 0x9000) 552 | return (*i & 0xFF) << 2; 553 | else if ((*i & 0xFFF0) == 0xF8C0) 554 | return (*(i + 1) & 0xFFF); 555 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 556 | return (*(i + 1) & 0xFF); 557 | else 558 | return 0; 559 | } 560 | 561 | static int insn_str_imm_rt(uint16_t * i) 562 | { 563 | if ((*i & 0xF800) == 0x6000) 564 | return (*i & 7); 565 | else if ((*i & 0xF800) == 0x9000) 566 | return (*i >> 8) & 7; 567 | else if ((*i & 0xFFF0) == 0xF8C0) 568 | return (*(i + 1) >> 12) & 0xF; 569 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 570 | return (*(i + 1) >> 12) & 0xF; 571 | else 572 | return 0; 573 | } 574 | 575 | static int insn_str_imm_rn(uint16_t * i) 576 | { 577 | if ((*i & 0xF800) == 0x6000) 578 | return (*i >> 3) & 7; 579 | else if ((*i & 0xF800) == 0x9000) 580 | return 13; 581 | else if ((*i & 0xFFF0) == 0xF8C0) 582 | return (*i & 0xF); 583 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 584 | return (*i & 0xF); 585 | else 586 | return 0; 587 | } 588 | 589 | // Given an instruction, search backwards until an instruction is found matching the specified criterion. 590 | static uint16_t *find_last_insn_matching(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * current_instruction, int (*match_func) (uint16_t *)) 591 | { 592 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 593 | if (insn_is_32bit(current_instruction - 2) && !insn_is_32bit(current_instruction - 3)) { 594 | current_instruction -= 2; 595 | } else { 596 | --current_instruction; 597 | } 598 | 599 | if (match_func(current_instruction)) { 600 | return current_instruction; 601 | } 602 | } 603 | 604 | return NULL; 605 | } 606 | 607 | // Given an instruction and a register, find the PC-relative address that was stored inside the register by the time the instruction was reached. 608 | static uint32_t find_pc_rel_value(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * insn, int reg) 609 | { 610 | // Find the last instruction that completely wiped out this register 611 | int found = 0; 612 | uint16_t *current_instruction = insn; 613 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 614 | if (insn_is_32bit(current_instruction - 2)) { 615 | current_instruction -= 2; 616 | } else { 617 | --current_instruction; 618 | } 619 | 620 | if (insn_is_mov_imm(current_instruction) && insn_mov_imm_rd(current_instruction) == reg) { 621 | found = 1; 622 | break; 623 | } 624 | 625 | if (insn_is_ldr_literal(current_instruction) && insn_ldr_literal_rt(current_instruction) == reg) { 626 | found = 1; 627 | break; 628 | } 629 | } 630 | 631 | if (!found) 632 | return 0; 633 | 634 | // Step through instructions, executing them as a virtual machine, only caring about instructions that affect the target register and are commonly used for PC-relative addressing. 635 | uint32_t value = 0; 636 | while ((uintptr_t) current_instruction < (uintptr_t) insn) { 637 | if (insn_is_mov_imm(current_instruction) && insn_mov_imm_rd(current_instruction) == reg) { 638 | value = insn_mov_imm_imm(current_instruction); 639 | } else if (insn_is_ldr_literal(current_instruction) && insn_ldr_literal_rt(current_instruction) == reg) { 640 | value = *(uint32_t *) (kdata + (((((uintptr_t) current_instruction - (uintptr_t) kdata) + 4) & 0xFFFFFFFC) + insn_ldr_literal_imm(current_instruction))); 641 | } else if (insn_is_movt(current_instruction) && insn_movt_rd(current_instruction) == reg) { 642 | value |= insn_movt_imm(current_instruction) << 16; 643 | } else if (insn_is_add_reg(current_instruction) && insn_add_reg_rd(current_instruction) == reg) { 644 | if (insn_add_reg_rm(current_instruction) != 15 || insn_add_reg_rn(current_instruction) != reg) { 645 | // Can't handle this kind of operation! 646 | return 0; 647 | } 648 | 649 | value += ((uintptr_t) current_instruction - (uintptr_t) kdata) + 4; 650 | } 651 | 652 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 653 | } 654 | 655 | return value; 656 | } 657 | 658 | // Find PC-relative references to a certain address (relative to kdata). This is basically a virtual machine that only cares about instructions used in PC-relative addressing, so no branches, etc. 659 | static uint16_t *find_literal_ref(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * insn, uint32_t address) 660 | { 661 | uint16_t *current_instruction = insn; 662 | uint32_t value[16]; 663 | memset(value, 0, sizeof(value)); 664 | 665 | while ((uintptr_t) current_instruction < (uintptr_t) (kdata + ksize)) { 666 | if (insn_is_mov_imm(current_instruction)) { 667 | value[insn_mov_imm_rd(current_instruction)] = insn_mov_imm_imm(current_instruction); 668 | } else if (insn_is_ldr_literal(current_instruction)) { 669 | uintptr_t literal_address = (uintptr_t) kdata + ((((uintptr_t) current_instruction - (uintptr_t) kdata) + 4) & 0xFFFFFFFC) + insn_ldr_literal_imm(current_instruction); 670 | if (literal_address >= (uintptr_t) kdata && (literal_address + 4) <= ((uintptr_t) kdata + ksize)) { 671 | value[insn_ldr_literal_rt(current_instruction)] = *(uint32_t *) (literal_address); 672 | } 673 | } else if (insn_is_movt(current_instruction)) { 674 | value[insn_movt_rd(current_instruction)] |= insn_movt_imm(current_instruction) << 16; 675 | } else if (insn_is_add_reg(current_instruction)) { 676 | int reg = insn_add_reg_rd(current_instruction); 677 | if (insn_add_reg_rm(current_instruction) == 15 && insn_add_reg_rn(current_instruction) == reg) { 678 | value[reg] += ((uintptr_t) current_instruction - (uintptr_t) kdata) + 4; 679 | if (value[reg] == address) { 680 | return current_instruction; 681 | } 682 | } 683 | } 684 | 685 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 686 | } 687 | 688 | return NULL; 689 | } 690 | 691 | // This points to kernel_pmap. Use that to change the page tables if necessary. 692 | uint32_t find_pmap_location(uint32_t region, uint8_t * kdata, size_t ksize) 693 | { 694 | // Find location of the pmap_map_bd string. 695 | uint8_t *pmap_map_bd = memmem(kdata, ksize, "\"pmap_map_bd\"", sizeof("\"pmap_map_bd\"")); 696 | if (!pmap_map_bd) 697 | return 0; 698 | 699 | // Find a reference to the pmap_map_bd string. That function also references kernel_pmap 700 | uint16_t *ptr = find_literal_ref(region, kdata, ksize, (uint16_t *) kdata, (uintptr_t) pmap_map_bd - (uintptr_t) kdata); 701 | if (!ptr) 702 | return 0; 703 | 704 | // Find the beginning of it (we may have a version that throws panic after the function end). 705 | while (*ptr != 0xB5F0) { 706 | if ((uint8_t *)ptr == kdata) 707 | return 0; 708 | ptr--; 709 | } 710 | 711 | // Find the end of it. 712 | const uint8_t search_function_end[] = { 0xF0, 0xBD }; 713 | ptr = memmem(ptr, ksize - ((uintptr_t) ptr - (uintptr_t) kdata), search_function_end, sizeof(search_function_end)); 714 | if (!ptr) 715 | return 0; 716 | 717 | // Find the last BL before the end of it. The third argument to it should be kernel_pmap 718 | uint16_t *bl = find_last_insn_matching(region, kdata, ksize, ptr, insn_is_bl); 719 | if (!bl) 720 | return 0; 721 | 722 | // Find the last LDR R2, [R*] before it that's before any branches. If there are branches, then we have a version of the function that assumes kernel_pmap instead of being passed it. 723 | uint16_t *ldr_r2 = NULL; 724 | uint16_t *current_instruction = bl; 725 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 726 | if (insn_is_32bit(current_instruction - 2) && !insn_is_32bit(current_instruction - 3)) { 727 | current_instruction -= 2; 728 | } else { 729 | --current_instruction; 730 | } 731 | 732 | if (insn_ldr_imm_rt(current_instruction) == 2 && insn_ldr_imm_imm(current_instruction) == 0) { 733 | ldr_r2 = current_instruction; 734 | break; 735 | } else if (insn_is_b_conditional(current_instruction) || insn_is_b_unconditional(current_instruction)) { 736 | break; 737 | } 738 | } 739 | 740 | // The function has a third argument, which must be kernel_pmap. Find out its address 741 | if (ldr_r2) 742 | return find_pc_rel_value(region, kdata, ksize, ldr_r2, insn_ldr_imm_rn(ldr_r2)); 743 | 744 | // The function has no third argument, Follow the BL. 745 | uint32_t imm32 = insn_bl_imm32(bl); 746 | uint32_t target = ((uintptr_t) bl - (uintptr_t) kdata) + 4 + imm32; 747 | if (target > ksize) 748 | return 0; 749 | 750 | // Find the first PC-relative reference in this function. 751 | int found = 0; 752 | 753 | int rd; 754 | current_instruction = (uint16_t *) (kdata + target); 755 | while ((uintptr_t) current_instruction < (uintptr_t) (kdata + ksize)) { 756 | if (insn_is_add_reg(current_instruction) && insn_add_reg_rm(current_instruction) == 15) { 757 | found = 1; 758 | rd = insn_add_reg_rd(current_instruction); 759 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 760 | break; 761 | } 762 | 763 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 764 | } 765 | 766 | if (!found) 767 | return 0; 768 | 769 | return find_pc_rel_value(region, kdata, ksize, current_instruction, rd); 770 | } 771 | 772 | // Function to find the syscall 0 function pointer. Used to modify the syscall table to call our own code. 773 | uint32_t find_syscall0(uint32_t region, uint8_t * kdata, size_t ksize) 774 | { 775 | // Search for the preamble to syscall 1 776 | const uint8_t syscall1_search[] = { 0x90, 0xB5, 0x01, 0xAF, 0x82, 0xB0, 0x09, 0x68, 0x01, 0x24, 0x00, 0x23 }; 777 | void *ptr = memmem(kdata, ksize, syscall1_search, sizeof(syscall1_search)); 778 | if (!ptr) 779 | return 0; 780 | 781 | // Search for a pointer to syscall 1 782 | uint32_t ptr_address = (uintptr_t) ptr - (uintptr_t) kdata + region; 783 | uint32_t function = ptr_address | 1; 784 | void *syscall1_entry = memmem(kdata, ksize, &function, sizeof(function)); 785 | if (!syscall1_entry) 786 | return 0; 787 | 788 | // Calculate the address of syscall 0 from the address of the syscall 1 entry 789 | return (uintptr_t) syscall1_entry - (uintptr_t) kdata - 0x18; 790 | } 791 | 792 | // 0E E0 9F E7 FF FF FF EA C0 00 0C F1 793 | // ldr lr, [pc, lr] 794 | // b +0x0 795 | // cpsid if 796 | 797 | uint32_t find_larm_init_tramp(uint32_t region, uint8_t * kdata, size_t ksize) 798 | { 799 | const uint8_t search[] = { 0x0E, 0xE0, 0x9F, 0xE7, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0x00, 0x0C, 0xF1 }; 800 | void *ptr = memmem(kdata, ksize, search, sizeof(search)); 801 | if (!ptr) 802 | return 0; 803 | 804 | return ((uintptr_t) ptr) - ((uintptr_t) kdata); 805 | } 806 | 807 | /* --- planetbeing patchfinder --- */ 808 | 809 | uint32_t phys_addr_remap = 0x5fe00000; 810 | 811 | vm_address_t get_kernel_base() 812 | { 813 | kern_return_t ret; 814 | task_t kernel_task; 815 | vm_region_submap_info_data_64_t info; 816 | vm_size_t size; 817 | mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; 818 | unsigned int depth = 0; 819 | vm_address_t addr = 0x81200000; /* arm64: addr = 0xffffff8000000000 */ 820 | 821 | ret = task_for_pid(mach_task_self(), 0, &kernel_task); 822 | if (ret != KERN_SUCCESS) 823 | return -1; 824 | 825 | while (1) { 826 | ret = vm_region_recurse_64(kernel_task, &addr, &size, &depth, (vm_region_info_t) & info, &info_count); 827 | if (ret != KERN_SUCCESS) 828 | break; 829 | if (size > 1024 * 1024 * 1024) { 830 | /* 831 | * https://code.google.com/p/iphone-dataprotection/ 832 | * hax, sometimes on iOS7 kernel starts at +0x200000 in the 1Gb region 833 | */ 834 | pointer_t buf; 835 | mach_msg_type_number_t sz = 0; 836 | addr += 0x200000; 837 | vm_read(kernel_task, addr + 0x1000, 512, &buf, &sz); 838 | if (*((uint32_t *)buf) != 0xfeedface) { 839 | addr -= 0x200000; 840 | vm_read(kernel_task, addr + 0x1000, 512, &buf, &sz); 841 | if (*((uint32_t*)buf) != 0xfeedface) { 842 | break; 843 | } 844 | } 845 | return addr; 846 | } 847 | addr += size; 848 | } 849 | 850 | return -1; 851 | } 852 | 853 | static void generate_ttb_entries(void) 854 | { 855 | uint32_t vaddr, vaddr_end, paddr, i; 856 | 857 | paddr = PHYS_OFF; 858 | vaddr = SHADOWMAP_BEGIN; 859 | vaddr_end = SHADOWMAP_END; 860 | 861 | for (i = vaddr; i < vaddr_end; i += SHADOWMAP_GRANULARITY, paddr += SHADOWMAP_GRANULARITY) { 862 | #if SPURIOUS_DEBUG_OUTPUT 863 | printf("ProtoTTE: 0x%08x for VA 0x%08x -> PA 0x%08x\n", L1_PROTO_TTE(paddr), i, paddr); 864 | #endif 865 | ttb_template[TTB_OFFSET(i) >> PFN_SHIFT] = L1_PROTO_TTE(paddr); 866 | } 867 | 868 | /* 869 | * Remap TTE for iBoot load address. 870 | */ 871 | uint32_t ttb_remap_addr_base = 0x7fe00000; 872 | ttb_template[TTB_OFFSET(ttb_remap_addr_base) >> PFN_SHIFT] = L1_PROTO_TTE(phys_addr_remap); 873 | ttb_template[TTB_OFFSET((ttb_remap_addr_base + 1048576)) >> PFN_SHIFT] = L1_PROTO_TTE((phys_addr_remap + 1048576)); 874 | #if SPURIOUS_DEBUG_OUTPUT 875 | printf("remap -> 0x%08x => 0x%08x (TTE: 0x%08x)\n", ttb_remap_addr_base, phys_addr_remap, L1_PROTO_TTE(phys_addr_remap)); 876 | 877 | printf("TTE offset begin for shadowmap: 0x%08x\n" "TTE offset end for shadowmap: 0x%08x\n" "TTE size: 0x%08x\n", SHADOWMAP_BEGIN_OFF, SHADOWMAP_END_OFF, SHADOWMAP_SIZE); 878 | #endif 879 | 880 | printf("New TTEs generated, base address for remap: 0x%08x, physBase: 0x%08x\n", PHYS_OFF, phys_addr_remap); 881 | return; 882 | } 883 | 884 | #define DMPSIZE 0xd00000 885 | 886 | int realmain(int argc, char *argv[]) 887 | { 888 | uint32_t chunksize = 2048; 889 | 890 | /* 891 | * Get physbase. 892 | */ 893 | size_t size; 894 | sysctlbyname("kern.version", NULL, &size, NULL, 0); 895 | char *osversion = malloc(size); 896 | if (sysctlbyname("kern.version", osversion, &size, NULL, 0) == -1) { 897 | printf("fail to kern.version sysctl\n"); 898 | exit(-1); 899 | } 900 | #if SPURIOUS_DEBUG_OUTPUT 901 | printf("%s\n", osversion); 902 | #endif 903 | 904 | if (strcasestr(osversion, "s5l8930x")) { 905 | PHYS_OFF = S5L8930_PHYS_OFF; 906 | phys_addr_remap = 0x5fe00000; 907 | } else if (strcasestr(osversion, "s5l8920x") || strcasestr(osversion, "s5l8922x")) { 908 | PHYS_OFF = S5L8930_PHYS_OFF; 909 | phys_addr_remap = 0x4fe00000; 910 | } else if (strcasestr(osversion, "s5l8940x") || strcasestr(osversion, "s5l8942x") || strcasestr(osversion, "s5l8947x")) { 911 | /* 912 | * All others have the high ram base. 913 | */ 914 | PHYS_OFF = S5L8940_PHYS_OFF; 915 | phys_addr_remap = 0x9fe00000; 916 | } else if (strcasestr(osversion, "s5l8945x")) { 917 | PHYS_OFF = S5L8940_PHYS_OFF; 918 | phys_addr_remap = 0xbfe00000; 919 | } else if (strcasestr(osversion, "s5l8950x") || strcasestr(osversion, "s5l8955x")) { 920 | PHYS_OFF = S5L8940_PHYS_OFF; 921 | phys_addr_remap = 0xbfe00000; 922 | } else { 923 | printf("Bravely assuming you're on an 8940-class device (unrecognized). You are on your own.\n"); 924 | /* 925 | * All others have the high ram base. 926 | */ 927 | PHYS_OFF = S5L8940_PHYS_OFF; 928 | phys_addr_remap = 0x9fe00000; 929 | } 930 | 931 | /* 932 | * Pedanticness, though doesn't matter, after we quit the entire OS is gone lol 933 | */ 934 | free(osversion); 935 | 936 | #if SPURIOUS_DEBUG_OUTPUT 937 | printf("physOff 0x%08x remap 0x%08x\n", PHYS_OFF, phys_addr_remap); 938 | #endif 939 | 940 | /* 941 | * get kernel base. 942 | */ 943 | kernel_base = get_kernel_base(); 944 | if (kernel_base == (vm_address_t)-1) { 945 | printf("failed to get kernel_baseel base...\n"); 946 | return -1; 947 | } 948 | 949 | printf("Kernel base is 0x%08x.\n", kernel_base); 950 | 951 | /* 952 | * we can now find the kernel pmap. 953 | */ 954 | kern_return_t r = task_for_pid(mach_task_self(), 0, &kernel_task); 955 | if (r != 0) { 956 | printf("task_for_pid failed.\n"); 957 | return -1; 958 | } 959 | 960 | /* 961 | * kill 962 | */ 963 | vm_address_t addr = kernel_base + 0x1000, e = 0, sz = 0; 964 | uint8_t *p = malloc(DMPSIZE + 0x1000); 965 | pointer_t buf; 966 | 967 | if (!p) { 968 | printf("failed to malloc memory for kernel dump...\n"); 969 | return -1; 970 | } 971 | while (addr < (kernel_base + DMPSIZE)) { 972 | vm_read(kernel_task, addr, chunksize, &buf, &sz); 973 | if (!buf || sz == 0) 974 | continue; 975 | uint8_t *z = (uint8_t *) buf; 976 | addr += chunksize; 977 | bcopy(z, p + e, chunksize); 978 | e += chunksize; 979 | } 980 | 981 | /* 982 | * kernel dumped, now find pmap. 983 | */ 984 | uint32_t kernel_pmap = kernel_base + 0x1000 + find_pmap_location(kernel_base, (uint8_t *) p, DMPSIZE); 985 | printf("kernel pmap is at 0x%08x.\n", kernel_pmap); 986 | 987 | /* 988 | * Read for kernel_pmap, dereference it for pmap_store. 989 | */ 990 | vm_read(kernel_task, kernel_pmap, 2048, &buf, &sz); 991 | vm_read(kernel_task, *(vm_address_t *) (buf), 2048, &buf, &sz); 992 | 993 | /* 994 | * We now have the struct. Let's copy it out to get the TTE base (we don't really need to do this 995 | * as it should just remain constant. TTEs should be after ToKD.) 996 | */ 997 | pmap_partial_t *part = (pmap_partial_t *) buf; 998 | uint32_t tte_virt = part->tte_virt; 999 | uint32_t tte_phys = part->tte_phys; 1000 | 1001 | printf("kernel pmap details: tte_virt: 0x%08x tte_phys: 0x%08x\n", tte_virt, tte_phys); 1002 | if (PHYS_OFF != (tte_phys & ~0xFFFFFFF)) { 1003 | printf("physOff 0x%08x should be 0x%08x\n", PHYS_OFF, tte_phys & ~0xFFFFFFF); 1004 | return -1; 1005 | } 1006 | 1007 | /* 1008 | * generate TTEs. 1009 | */ 1010 | generate_ttb_entries(); 1011 | 1012 | /* 1013 | * Now, we can start reading at the TTE base and start writing in the descriptors. 1014 | */ 1015 | uint32_t tte_off = SHADOWMAP_BEGIN_OFF; 1016 | vm_read(kernel_task, tte_virt + tte_off, 2048, &buf, &sz); 1017 | bcopy((char *) ttb_template_ptr + tte_off, (void *) buf, SHADOWMAP_SIZE); 1018 | vm_write(kernel_task, tte_virt + tte_off, buf, sz); 1019 | 1020 | printf("======================================================================================\n"); 1021 | printf("!!!! Kernel TTE entries written. System stability is no longer guaranteed.\n"); 1022 | printf("!!!! Security has also been reduced by an exponential factor. You have been warned.\n"); 1023 | printf("======================================================================================\n"); 1024 | 1025 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1026 | signal(SIGINT, SIG_IGN); 1027 | 1028 | /* 1029 | * Do the dew. 1030 | */ 1031 | 1032 | printf("%x\n", *(uint32_t *) (0x7f000000 + 0x1000)); 1033 | 1034 | printf("Syncing disks.\n"); 1035 | int diskSync; 1036 | for (diskSync = 0; diskSync < 10; diskSync++) 1037 | sync(); 1038 | sleep(1); 1039 | 1040 | printf("Magic happening now. (attempted!)\n"); 1041 | FILE *f = fopen(PREFIX "/dump", "wb"); 1042 | ssize_t written = fwrite((void *)0x7ff00000, 1, 1024 * 1024, f); 1043 | fclose(f); 1044 | printf("written = %zd\n", written); 1045 | 1046 | return 0; 1047 | } 1048 | 1049 | FILE *logfile = NULL; 1050 | 1051 | static void 1052 | myprintf(const char *fmt, ...) 1053 | { 1054 | va_list ap; 1055 | va_start(ap, fmt); 1056 | vfprintf(logfile, fmt, ap); 1057 | va_end(ap); 1058 | fflush(logfile); 1059 | } 1060 | 1061 | int 1062 | main(void) 1063 | { 1064 | struct stat st; 1065 | logfile = fopen(PREFIX "/kdumper.log", "at") ? : stdout; 1066 | myprintf("-\n"); 1067 | if (time(NULL) < 0 + 15 * 60 && stat(PREFIX "/start", &st) == 0 && unlink(PREFIX "/start") == 0) { 1068 | sync(); 1069 | if (stat(PREFIX "/start", &st)) { 1070 | return realmain(0, NULL); 1071 | } 1072 | } 1073 | myprintf("NOT running\n"); 1074 | return 0; 1075 | } 1076 | -------------------------------------------------------------------------------- /kloader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014, winocm. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | * 18 | * $Id$ 19 | */ 20 | /* 21 | * kloader 22 | * Requires iOS 6.x or 7.x. (This version only.) 23 | * 24 | * Remap addresses: 25 | * 0x7fe00000 -> 0x9fe00000 (0x5fe00000) iBSS (jump-to only.) 26 | * 27 | * xcrun -sdk iphoneos clang kloader.c -arch armv7 -framework IOKit -framework CoreFoundation -no-integrated-as \ 28 | * -DINLINE_IT_ALL=1 -Wall -o kloader -miphoneos-version-min=6.0; ldid -Stfp0.plist kloader 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | typedef mach_port_t io_service_t; 42 | extern mach_port_t kIOMasterPortDefault; 43 | extern mach_port_t IOPMFindPowerManagement(mach_port_t); 44 | extern kern_return_t IOPMSleepSystem(mach_port_t); 45 | 46 | /* 47 | * ARM page bits for L1 sections. 48 | */ 49 | #define L1_SHIFT 20 /* log2(1MB) */ 50 | 51 | #define L1_SECT_PROTO (1 << 1) /* 0b10 */ 52 | 53 | #define L1_SECT_B_BIT (1 << 2) 54 | #define L1_SECT_C_BIT (1 << 3) 55 | 56 | #define L1_SECT_SORDER (0) /* 0b00, not cacheable, strongly ordered. */ 57 | #define L1_SECT_SH_DEVICE (L1_SECT_B_BIT) 58 | #define L1_SECT_WT_NWA (L1_SECT_C_BIT) 59 | #define L1_SECT_WB_NWA (L1_SECT_B_BIT | L1_SECT_C_BIT) 60 | #define L1_SECT_S_BIT (1 << 16) 61 | 62 | #define L1_SECT_AP_URW (1 << 10) | (1 << 11) 63 | #define L1_SECT_PFN(x) (x & 0xFFF00000) 64 | 65 | #define L1_SECT_DEFPROT (L1_SECT_AP_URW) 66 | #define L1_SECT_DEFCACHE (L1_SECT_SORDER) 67 | 68 | #define L1_PROTO_TTE(paddr) (L1_SECT_PFN(paddr) | L1_SECT_S_BIT | L1_SECT_DEFPROT | L1_SECT_DEFCACHE | L1_SECT_PROTO) 69 | 70 | #define PFN_SHIFT 2 71 | #define TTB_OFFSET(vaddr) ((vaddr >> L1_SHIFT) << PFN_SHIFT) 72 | 73 | /* 74 | * RAM physical base begin. 75 | */ 76 | #define S5L8930_PHYS_OFF 0x40000000 77 | #define S5L8940_PHYS_OFF 0x80000000 /* Note: RAM base is identical for 8940-8955. */ 78 | 79 | uint32_t PHYS_OFF = S5L8930_PHYS_OFF; 80 | 81 | /* 82 | * Shadowmap begin and end. 15MB of shadowmap is enough for the kernel. 83 | * We don't need to invalidate unified D/I TLB or any cache lines 84 | * since the kernel is mapped as writethrough memory, and these 85 | * addresses are guaranteed to not be translated. 86 | * (Accesses will cause segmentation faults due to failure on L1 translation.) 87 | * 88 | * Clear the shadowmappings when done owning the kernel. 89 | * 90 | * 0x7ff0'0000 is also below the limit for vm_read and such, so that's also *great*. 91 | * (2048 bytes) 92 | */ 93 | #define SHADOWMAP_BEGIN 0x7f000000 94 | #define SHADOWMAP_END 0x7ff00000 95 | #define SHADOWMAP_GRANULARITY 0x00100000 96 | 97 | #define SHADOWMAP_SIZE_BYTES (SHADOWMAP_END - SHADOWMAP_BEGIN) 98 | 99 | #define SHADOWMAP_BEGIN_OFF TTB_OFFSET(SHADOWMAP_BEGIN) 100 | #define SHADOWMAP_END_OFF TTB_OFFSET(SHADOWMAP_END) 101 | #define SHADOWMAP_SIZE (SHADOWMAP_END_OFF - SHADOWMAP_BEGIN_OFF) 102 | 103 | #define SHADOWMAP_BEGIN_IDX (SHADOWMAP_BEGIN_OFF >> PFN_SHIFT) 104 | #define SHADOWMAP_END_IDX (SHADOWMAP_END_OFF >> PFN_SHIFT) 105 | 106 | #define TTB_SIZE 4096 107 | #define DEFAULT_KERNEL_SLIDE 0x80000000 108 | 109 | static mach_port_t kernel_task = 0; 110 | static uint32_t ttb_template[TTB_SIZE] = { }; 111 | 112 | static void *ttb_template_ptr = &ttb_template[0]; 113 | static vm_address_t kernel_base = DEFAULT_KERNEL_SLIDE; 114 | 115 | typedef struct pmap_partial_t { 116 | uint32_t tte_virt; 117 | uint32_t tte_phys; 118 | /* 119 | * ... 120 | */ 121 | } pmap_partial_t; 122 | 123 | /* --- planetbeing patchfinder --- */ 124 | 125 | static uint32_t bit_range(uint32_t x, int start, int end) 126 | { 127 | x = (x << (31 - start)) >> (31 - start); 128 | x = (x >> end); 129 | return x; 130 | } 131 | 132 | static uint32_t ror(uint32_t x, int places) 133 | { 134 | return (x >> places) | (x << (32 - places)); 135 | } 136 | 137 | static int thumb_expand_imm_c(uint16_t imm12) 138 | { 139 | if (bit_range(imm12, 11, 10) == 0) { 140 | switch (bit_range(imm12, 9, 8)) { 141 | case 0: 142 | return bit_range(imm12, 7, 0); 143 | case 1: 144 | return (bit_range(imm12, 7, 0) << 16) | bit_range(imm12, 7, 0); 145 | case 2: 146 | return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 8); 147 | case 3: 148 | return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 16) | (bit_range(imm12, 7, 0) << 8) | bit_range(imm12, 7, 0); 149 | default: 150 | return 0; 151 | } 152 | } else { 153 | uint32_t unrotated_value = 0x80 | bit_range(imm12, 6, 0); 154 | return ror(unrotated_value, bit_range(imm12, 11, 7)); 155 | } 156 | } 157 | 158 | static int insn_is_32bit(uint16_t * i) 159 | { 160 | return (*i & 0xe000) == 0xe000 && (*i & 0x1800) != 0x0; 161 | } 162 | 163 | static int insn_is_bl(uint16_t * i) 164 | { 165 | if ((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd000) == 0xd000) 166 | return 1; 167 | else if ((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd001) == 0xc000) 168 | return 1; 169 | else 170 | return 0; 171 | } 172 | 173 | static uint32_t insn_bl_imm32(uint16_t * i) 174 | { 175 | uint16_t insn0 = *i; 176 | uint16_t insn1 = *(i + 1); 177 | uint32_t s = (insn0 >> 10) & 1; 178 | uint32_t j1 = (insn1 >> 13) & 1; 179 | uint32_t j2 = (insn1 >> 11) & 1; 180 | uint32_t i1 = ~(j1 ^ s) & 1; 181 | uint32_t i2 = ~(j2 ^ s) & 1; 182 | uint32_t imm10 = insn0 & 0x3ff; 183 | uint32_t imm11 = insn1 & 0x7ff; 184 | uint32_t imm32 = (imm11 << 1) | (imm10 << 12) | (i2 << 22) | (i1 << 23) | (s ? 0xff000000 : 0); 185 | return imm32; 186 | } 187 | 188 | static int insn_is_b_conditional(uint16_t * i) 189 | { 190 | return (*i & 0xF000) == 0xD000 && (*i & 0x0F00) != 0x0F00 && (*i & 0x0F00) != 0xE; 191 | } 192 | 193 | static int insn_is_b_unconditional(uint16_t * i) 194 | { 195 | if ((*i & 0xF800) == 0xE000) 196 | return 1; 197 | else if ((*i & 0xF800) == 0xF000 && (*(i + 1) & 0xD000) == 9) 198 | return 1; 199 | else 200 | return 0; 201 | } 202 | 203 | static int insn_is_ldr_literal(uint16_t * i) 204 | { 205 | return (*i & 0xF800) == 0x4800 || (*i & 0xFF7F) == 0xF85F; 206 | } 207 | 208 | static int insn_ldr_literal_rt(uint16_t * i) 209 | { 210 | if ((*i & 0xF800) == 0x4800) 211 | return (*i >> 8) & 7; 212 | else if ((*i & 0xFF7F) == 0xF85F) 213 | return (*(i + 1) >> 12) & 0xF; 214 | else 215 | return 0; 216 | } 217 | 218 | static int insn_ldr_literal_imm(uint16_t * i) 219 | { 220 | if ((*i & 0xF800) == 0x4800) 221 | return (*i & 0xF) << 2; 222 | else if ((*i & 0xFF7F) == 0xF85F) 223 | return (*(i + 1) & 0xFFF) * (((*i & 0x0800) == 0x0800) ? 1 : -1); 224 | else 225 | return 0; 226 | } 227 | 228 | // TODO: More encodings 229 | static int insn_is_ldr_imm(uint16_t * i) 230 | { 231 | uint8_t opA = bit_range(*i, 15, 12); 232 | uint8_t opB = bit_range(*i, 11, 9); 233 | 234 | return opA == 6 && (opB & 4) == 4; 235 | } 236 | 237 | static int insn_ldr_imm_rt(uint16_t * i) 238 | { 239 | return (*i & 7); 240 | } 241 | 242 | static int insn_ldr_imm_rn(uint16_t * i) 243 | { 244 | return ((*i >> 3) & 7); 245 | } 246 | 247 | static int insn_ldr_imm_imm(uint16_t * i) 248 | { 249 | return ((*i >> 6) & 0x1F); 250 | } 251 | 252 | // TODO: More encodings 253 | static int insn_is_ldrb_imm(uint16_t * i) 254 | { 255 | return (*i & 0xF800) == 0x7800; 256 | } 257 | 258 | static int insn_ldrb_imm_rt(uint16_t * i) 259 | { 260 | return (*i & 7); 261 | } 262 | 263 | static int insn_ldrb_imm_rn(uint16_t * i) 264 | { 265 | return ((*i >> 3) & 7); 266 | } 267 | 268 | static int insn_ldrb_imm_imm(uint16_t * i) 269 | { 270 | return ((*i >> 6) & 0x1F); 271 | } 272 | 273 | static int insn_is_ldr_reg(uint16_t * i) 274 | { 275 | if ((*i & 0xFE00) == 0x5800) 276 | return 1; 277 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 278 | return 1; 279 | else 280 | return 0; 281 | } 282 | 283 | static int insn_ldr_reg_rn(uint16_t * i) 284 | { 285 | if ((*i & 0xFE00) == 0x5800) 286 | return (*i >> 3) & 0x7; 287 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 288 | return (*i & 0xF); 289 | else 290 | return 0; 291 | } 292 | 293 | int insn_ldr_reg_rt(uint16_t * i) 294 | { 295 | if ((*i & 0xFE00) == 0x5800) 296 | return *i & 0x7; 297 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 298 | return (*(i + 1) >> 12) & 0xF; 299 | else 300 | return 0; 301 | } 302 | 303 | int insn_ldr_reg_rm(uint16_t * i) 304 | { 305 | if ((*i & 0xFE00) == 0x5800) 306 | return (*i >> 6) & 0x7; 307 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 308 | return *(i + 1) & 0xF; 309 | else 310 | return 0; 311 | } 312 | 313 | static int insn_ldr_reg_lsl(uint16_t * i) 314 | { 315 | if ((*i & 0xFE00) == 0x5800) 316 | return 0; 317 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 318 | return (*(i + 1) >> 4) & 0x3; 319 | else 320 | return 0; 321 | } 322 | 323 | static int insn_is_add_reg(uint16_t * i) 324 | { 325 | if ((*i & 0xFE00) == 0x1800) 326 | return 1; 327 | else if ((*i & 0xFF00) == 0x4400) 328 | return 1; 329 | else if ((*i & 0xFFE0) == 0xEB00) 330 | return 1; 331 | else 332 | return 0; 333 | } 334 | 335 | static int insn_add_reg_rd(uint16_t * i) 336 | { 337 | if ((*i & 0xFE00) == 0x1800) 338 | return (*i & 7); 339 | else if ((*i & 0xFF00) == 0x4400) 340 | return (*i & 7) | ((*i & 0x80) >> 4); 341 | else if ((*i & 0xFFE0) == 0xEB00) 342 | return (*(i + 1) >> 8) & 0xF; 343 | else 344 | return 0; 345 | } 346 | 347 | static int insn_add_reg_rn(uint16_t * i) 348 | { 349 | if ((*i & 0xFE00) == 0x1800) 350 | return ((*i >> 3) & 7); 351 | else if ((*i & 0xFF00) == 0x4400) 352 | return (*i & 7) | ((*i & 0x80) >> 4); 353 | else if ((*i & 0xFFE0) == 0xEB00) 354 | return (*i & 0xF); 355 | else 356 | return 0; 357 | } 358 | 359 | static int insn_add_reg_rm(uint16_t * i) 360 | { 361 | if ((*i & 0xFE00) == 0x1800) 362 | return (*i >> 6) & 7; 363 | else if ((*i & 0xFF00) == 0x4400) 364 | return (*i >> 3) & 0xF; 365 | else if ((*i & 0xFFE0) == 0xEB00) 366 | return *(i + 1) & 0xF; 367 | else 368 | return 0; 369 | } 370 | 371 | static int insn_is_movt(uint16_t * i) 372 | { 373 | return (*i & 0xFBF0) == 0xF2C0 && (*(i + 1) & 0x8000) == 0; 374 | } 375 | 376 | static int insn_movt_rd(uint16_t * i) 377 | { 378 | return (*(i + 1) >> 8) & 0xF; 379 | } 380 | 381 | static int insn_movt_imm(uint16_t * i) 382 | { 383 | return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF); 384 | } 385 | 386 | static int insn_is_mov_imm(uint16_t * i) 387 | { 388 | if ((*i & 0xF800) == 0x2000) 389 | return 1; 390 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 391 | return 1; 392 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 393 | return 1; 394 | else 395 | return 0; 396 | } 397 | 398 | static int insn_mov_imm_rd(uint16_t * i) 399 | { 400 | if ((*i & 0xF800) == 0x2000) 401 | return (*i >> 8) & 7; 402 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 403 | return (*(i + 1) >> 8) & 0xF; 404 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 405 | return (*(i + 1) >> 8) & 0xF; 406 | else 407 | return 0; 408 | } 409 | 410 | static int insn_mov_imm_imm(uint16_t * i) 411 | { 412 | if ((*i & 0xF800) == 0x2000) 413 | return *i & 0xF; 414 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 415 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 416 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 417 | return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF); 418 | else 419 | return 0; 420 | } 421 | 422 | static int insn_is_cmp_imm(uint16_t * i) 423 | { 424 | if ((*i & 0xF800) == 0x2800) 425 | return 1; 426 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 427 | return 1; 428 | else 429 | return 0; 430 | } 431 | 432 | static int insn_cmp_imm_rn(uint16_t * i) 433 | { 434 | if ((*i & 0xF800) == 0x2800) 435 | return (*i >> 8) & 7; 436 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 437 | return *i & 0xF; 438 | else 439 | return 0; 440 | } 441 | 442 | static int insn_cmp_imm_imm(uint16_t * i) 443 | { 444 | if ((*i & 0xF800) == 0x2800) 445 | return *i & 0xFF; 446 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 447 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 448 | else 449 | return 0; 450 | } 451 | 452 | static int insn_is_and_imm(uint16_t * i) 453 | { 454 | return (*i & 0xFBE0) == 0xF000 && (*(i + 1) & 0x8000) == 0; 455 | } 456 | 457 | static int insn_and_imm_rn(uint16_t * i) 458 | { 459 | return *i & 0xF; 460 | } 461 | 462 | static int insn_and_imm_rd(uint16_t * i) 463 | { 464 | return (*(i + 1) >> 8) & 0xF; 465 | } 466 | 467 | static int insn_and_imm_imm(uint16_t * i) 468 | { 469 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 470 | } 471 | 472 | static int insn_is_push(uint16_t * i) 473 | { 474 | if ((*i & 0xFE00) == 0xB400) 475 | return 1; 476 | else if (*i == 0xE92D) 477 | return 1; 478 | else if (*i == 0xF84D && (*(i + 1) & 0x0FFF) == 0x0D04) 479 | return 1; 480 | else 481 | return 0; 482 | } 483 | 484 | static int insn_push_registers(uint16_t * i) 485 | { 486 | if ((*i & 0xFE00) == 0xB400) 487 | return (*i & 0x00FF) | ((*i & 0x0100) << 6); 488 | else if (*i == 0xE92D) 489 | return *(i + 1); 490 | else if (*i == 0xF84D && (*(i + 1) & 0x0FFF) == 0x0D04) 491 | return 1 << ((*(i + 1) >> 12) & 0xF); 492 | else 493 | return 0; 494 | } 495 | 496 | static int insn_is_preamble_push(uint16_t * i) 497 | { 498 | return insn_is_push(i) && (insn_push_registers(i) & (1 << 14)) != 0; 499 | } 500 | 501 | static int insn_is_str_imm(uint16_t * i) 502 | { 503 | if ((*i & 0xF800) == 0x6000) 504 | return 1; 505 | else if ((*i & 0xF800) == 0x9000) 506 | return 1; 507 | else if ((*i & 0xFFF0) == 0xF8C0) 508 | return 1; 509 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 510 | return 1; 511 | else 512 | return 0; 513 | } 514 | 515 | static int insn_str_imm_postindexed(uint16_t * i) 516 | { 517 | if ((*i & 0xF800) == 0x6000) 518 | return 1; 519 | else if ((*i & 0xF800) == 0x9000) 520 | return 1; 521 | else if ((*i & 0xFFF0) == 0xF8C0) 522 | return 1; 523 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 524 | return (*(i + 1) >> 10) & 1; 525 | else 526 | return 0; 527 | } 528 | 529 | static int insn_str_imm_wback(uint16_t * i) 530 | { 531 | if ((*i & 0xF800) == 0x6000) 532 | return 0; 533 | else if ((*i & 0xF800) == 0x9000) 534 | return 0; 535 | else if ((*i & 0xFFF0) == 0xF8C0) 536 | return 0; 537 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 538 | return (*(i + 1) >> 8) & 1; 539 | else 540 | return 0; 541 | } 542 | 543 | static int insn_str_imm_imm(uint16_t * i) 544 | { 545 | if ((*i & 0xF800) == 0x6000) 546 | return (*i & 0x07C0) >> 4; 547 | else if ((*i & 0xF800) == 0x9000) 548 | return (*i & 0xFF) << 2; 549 | else if ((*i & 0xFFF0) == 0xF8C0) 550 | return (*(i + 1) & 0xFFF); 551 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 552 | return (*(i + 1) & 0xFF); 553 | else 554 | return 0; 555 | } 556 | 557 | static int insn_str_imm_rt(uint16_t * i) 558 | { 559 | if ((*i & 0xF800) == 0x6000) 560 | return (*i & 7); 561 | else if ((*i & 0xF800) == 0x9000) 562 | return (*i >> 8) & 7; 563 | else if ((*i & 0xFFF0) == 0xF8C0) 564 | return (*(i + 1) >> 12) & 0xF; 565 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 566 | return (*(i + 1) >> 12) & 0xF; 567 | else 568 | return 0; 569 | } 570 | 571 | static int insn_str_imm_rn(uint16_t * i) 572 | { 573 | if ((*i & 0xF800) == 0x6000) 574 | return (*i >> 3) & 7; 575 | else if ((*i & 0xF800) == 0x9000) 576 | return 13; 577 | else if ((*i & 0xFFF0) == 0xF8C0) 578 | return (*i & 0xF); 579 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 580 | return (*i & 0xF); 581 | else 582 | return 0; 583 | } 584 | 585 | // Given an instruction, search backwards until an instruction is found matching the specified criterion. 586 | static uint16_t *find_last_insn_matching(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * current_instruction, int (*match_func) (uint16_t *)) 587 | { 588 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 589 | if (insn_is_32bit(current_instruction - 2) && !insn_is_32bit(current_instruction - 3)) { 590 | current_instruction -= 2; 591 | } else { 592 | --current_instruction; 593 | } 594 | 595 | if (match_func(current_instruction)) { 596 | return current_instruction; 597 | } 598 | } 599 | 600 | return NULL; 601 | } 602 | 603 | // Given an instruction and a register, find the PC-relative address that was stored inside the register by the time the instruction was reached. 604 | static uint32_t find_pc_rel_value(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * insn, int reg) 605 | { 606 | // Find the last instruction that completely wiped out this register 607 | int found = 0; 608 | uint16_t *current_instruction = insn; 609 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 610 | if (insn_is_32bit(current_instruction - 2)) { 611 | current_instruction -= 2; 612 | } else { 613 | --current_instruction; 614 | } 615 | 616 | if (insn_is_mov_imm(current_instruction) && insn_mov_imm_rd(current_instruction) == reg) { 617 | found = 1; 618 | break; 619 | } 620 | 621 | if (insn_is_ldr_literal(current_instruction) && insn_ldr_literal_rt(current_instruction) == reg) { 622 | found = 1; 623 | break; 624 | } 625 | } 626 | 627 | if (!found) 628 | return 0; 629 | 630 | // Step through instructions, executing them as a virtual machine, only caring about instructions that affect the target register and are commonly used for PC-relative addressing. 631 | uint32_t value = 0; 632 | while ((uintptr_t) current_instruction < (uintptr_t) insn) { 633 | if (insn_is_mov_imm(current_instruction) && insn_mov_imm_rd(current_instruction) == reg) { 634 | value = insn_mov_imm_imm(current_instruction); 635 | } else if (insn_is_ldr_literal(current_instruction) && insn_ldr_literal_rt(current_instruction) == reg) { 636 | value = *(uint32_t *) (kdata + (((((uintptr_t) current_instruction - (uintptr_t) kdata) + 4) & 0xFFFFFFFC) + insn_ldr_literal_imm(current_instruction))); 637 | } else if (insn_is_movt(current_instruction) && insn_movt_rd(current_instruction) == reg) { 638 | value |= insn_movt_imm(current_instruction) << 16; 639 | } else if (insn_is_add_reg(current_instruction) && insn_add_reg_rd(current_instruction) == reg) { 640 | if (insn_add_reg_rm(current_instruction) != 15 || insn_add_reg_rn(current_instruction) != reg) { 641 | // Can't handle this kind of operation! 642 | return 0; 643 | } 644 | 645 | value += ((uintptr_t) current_instruction - (uintptr_t) kdata) + 4; 646 | } 647 | 648 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 649 | } 650 | 651 | return value; 652 | } 653 | 654 | // Find PC-relative references to a certain address (relative to kdata). This is basically a virtual machine that only cares about instructions used in PC-relative addressing, so no branches, etc. 655 | static uint16_t *find_literal_ref(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * insn, uint32_t address) 656 | { 657 | uint16_t *current_instruction = insn; 658 | uint32_t value[16]; 659 | memset(value, 0, sizeof(value)); 660 | 661 | while ((uintptr_t) current_instruction < (uintptr_t) (kdata + ksize)) { 662 | if (insn_is_mov_imm(current_instruction)) { 663 | value[insn_mov_imm_rd(current_instruction)] = insn_mov_imm_imm(current_instruction); 664 | } else if (insn_is_ldr_literal(current_instruction)) { 665 | uintptr_t literal_address = (uintptr_t) kdata + ((((uintptr_t) current_instruction - (uintptr_t) kdata) + 4) & 0xFFFFFFFC) + insn_ldr_literal_imm(current_instruction); 666 | if (literal_address >= (uintptr_t) kdata && (literal_address + 4) <= ((uintptr_t) kdata + ksize)) { 667 | value[insn_ldr_literal_rt(current_instruction)] = *(uint32_t *) (literal_address); 668 | } 669 | } else if (insn_is_movt(current_instruction)) { 670 | value[insn_movt_rd(current_instruction)] |= insn_movt_imm(current_instruction) << 16; 671 | } else if (insn_is_add_reg(current_instruction)) { 672 | int reg = insn_add_reg_rd(current_instruction); 673 | if (insn_add_reg_rm(current_instruction) == 15 && insn_add_reg_rn(current_instruction) == reg) { 674 | value[reg] += ((uintptr_t) current_instruction - (uintptr_t) kdata) + 4; 675 | if (value[reg] == address) { 676 | return current_instruction; 677 | } 678 | } 679 | } 680 | 681 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 682 | } 683 | 684 | return NULL; 685 | } 686 | 687 | // This points to kernel_pmap. Use that to change the page tables if necessary. 688 | uint32_t find_pmap_location(uint32_t region, uint8_t * kdata, size_t ksize) 689 | { 690 | // Find location of the pmap_map_bd string. 691 | uint8_t *pmap_map_bd = memmem(kdata, ksize, "\"pmap_map_bd\"", sizeof("\"pmap_map_bd\"")); 692 | if (!pmap_map_bd) 693 | return 0; 694 | 695 | // Find a reference to the pmap_map_bd string. That function also references kernel_pmap 696 | uint16_t *ptr = find_literal_ref(region, kdata, ksize, (uint16_t *) kdata, (uintptr_t) pmap_map_bd - (uintptr_t) kdata); 697 | if (!ptr) 698 | return 0; 699 | 700 | // Find the beginning of it (we may have a version that throws panic after the function end). 701 | while (*ptr != 0xB5F0) { 702 | if ((uint8_t *)ptr == kdata) 703 | return 0; 704 | ptr--; 705 | } 706 | 707 | // Find the end of it. 708 | const uint8_t search_function_end[] = { 0xF0, 0xBD }; 709 | ptr = memmem(ptr, ksize - ((uintptr_t) ptr - (uintptr_t) kdata), search_function_end, sizeof(search_function_end)); 710 | if (!ptr) 711 | return 0; 712 | 713 | // Find the last BL before the end of it. The third argument to it should be kernel_pmap 714 | uint16_t *bl = find_last_insn_matching(region, kdata, ksize, ptr, insn_is_bl); 715 | if (!bl) 716 | return 0; 717 | 718 | // Find the last LDR R2, [R*] before it that's before any branches. If there are branches, then we have a version of the function that assumes kernel_pmap instead of being passed it. 719 | uint16_t *ldr_r2 = NULL; 720 | uint16_t *current_instruction = bl; 721 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 722 | if (insn_is_32bit(current_instruction - 2) && !insn_is_32bit(current_instruction - 3)) { 723 | current_instruction -= 2; 724 | } else { 725 | --current_instruction; 726 | } 727 | 728 | if (insn_ldr_imm_rt(current_instruction) == 2 && insn_ldr_imm_imm(current_instruction) == 0) { 729 | ldr_r2 = current_instruction; 730 | break; 731 | } else if (insn_is_b_conditional(current_instruction) || insn_is_b_unconditional(current_instruction)) { 732 | break; 733 | } 734 | } 735 | 736 | // The function has a third argument, which must be kernel_pmap. Find out its address 737 | if (ldr_r2) 738 | return find_pc_rel_value(region, kdata, ksize, ldr_r2, insn_ldr_imm_rn(ldr_r2)); 739 | 740 | // The function has no third argument, Follow the BL. 741 | uint32_t imm32 = insn_bl_imm32(bl); 742 | uint32_t target = ((uintptr_t) bl - (uintptr_t) kdata) + 4 + imm32; 743 | if (target > ksize) 744 | return 0; 745 | 746 | // Find the first PC-relative reference in this function. 747 | int found = 0; 748 | 749 | int rd; 750 | current_instruction = (uint16_t *) (kdata + target); 751 | while ((uintptr_t) current_instruction < (uintptr_t) (kdata + ksize)) { 752 | if (insn_is_add_reg(current_instruction) && insn_add_reg_rm(current_instruction) == 15) { 753 | found = 1; 754 | rd = insn_add_reg_rd(current_instruction); 755 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 756 | break; 757 | } 758 | 759 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 760 | } 761 | 762 | if (!found) 763 | return 0; 764 | 765 | return find_pc_rel_value(region, kdata, ksize, current_instruction, rd); 766 | } 767 | 768 | // Function to find the syscall 0 function pointer. Used to modify the syscall table to call our own code. 769 | uint32_t find_syscall0(uint32_t region, uint8_t * kdata, size_t ksize) 770 | { 771 | // Search for the preamble to syscall 1 772 | const uint8_t syscall1_search[] = { 0x90, 0xB5, 0x01, 0xAF, 0x82, 0xB0, 0x09, 0x68, 0x01, 0x24, 0x00, 0x23 }; 773 | void *ptr = memmem(kdata, ksize, syscall1_search, sizeof(syscall1_search)); 774 | if (!ptr) 775 | return 0; 776 | 777 | // Search for a pointer to syscall 1 778 | uint32_t ptr_address = (uintptr_t) ptr - (uintptr_t) kdata + region; 779 | uint32_t function = ptr_address | 1; 780 | void *syscall1_entry = memmem(kdata, ksize, &function, sizeof(function)); 781 | if (!syscall1_entry) 782 | return 0; 783 | 784 | // Calculate the address of syscall 0 from the address of the syscall 1 entry 785 | return (uintptr_t) syscall1_entry - (uintptr_t) kdata - 0x18; 786 | } 787 | 788 | // 0E E0 9F E7 FF FF FF EA C0 00 0C F1 789 | // ldr lr, [pc, lr] 790 | // b +0x0 791 | // cpsid if 792 | 793 | uint32_t find_larm_init_tramp(uint32_t region, uint8_t * kdata, size_t ksize) 794 | { 795 | const uint8_t search[] = { 0x0E, 0xE0, 0x9F, 0xE7, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0x00, 0x0C, 0xF1 }; 796 | void *ptr = memmem(kdata, ksize, search, sizeof(search)); 797 | if (!ptr) 798 | return 0; 799 | 800 | return ((uintptr_t) ptr) - ((uintptr_t) kdata); 801 | } 802 | 803 | /* --- planetbeing patchfinder --- */ 804 | 805 | uint32_t phys_addr_remap = 0x5fe00000; 806 | 807 | vm_address_t get_kernel_base() 808 | { 809 | kern_return_t ret; 810 | task_t kernel_task; 811 | vm_region_submap_info_data_64_t info; 812 | vm_size_t size; 813 | mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; 814 | unsigned int depth = 0; 815 | vm_address_t addr = 0x81200000; /* arm64: addr = 0xffffff8000000000 */ 816 | 817 | ret = task_for_pid(mach_task_self(), 0, &kernel_task); 818 | if (ret != KERN_SUCCESS) 819 | return -1; 820 | 821 | while (1) { 822 | ret = vm_region_recurse_64(kernel_task, &addr, &size, &depth, (vm_region_info_t) & info, &info_count); 823 | if (ret != KERN_SUCCESS) 824 | break; 825 | if (size > 1024 * 1024 * 1024) { 826 | /* 827 | * https://code.google.com/p/iphone-dataprotection/ 828 | * hax, sometimes on iOS7 kernel starts at +0x200000 in the 1Gb region 829 | */ 830 | pointer_t buf; 831 | mach_msg_type_number_t sz = 0; 832 | addr += 0x200000; 833 | vm_read(kernel_task, addr + 0x1000, 512, &buf, &sz); 834 | if (*((uint32_t *)buf) != 0xfeedface) { 835 | addr -= 0x200000; 836 | vm_read(kernel_task, addr + 0x1000, 512, &buf, &sz); 837 | if (*((uint32_t*)buf) != 0xfeedface) { 838 | break; 839 | } 840 | } 841 | return addr; 842 | } 843 | addr += size; 844 | } 845 | 846 | return -1; 847 | } 848 | 849 | static void generate_ttb_entries(void) 850 | { 851 | uint32_t vaddr, vaddr_end, paddr, i; 852 | 853 | paddr = PHYS_OFF; 854 | vaddr = SHADOWMAP_BEGIN; 855 | vaddr_end = SHADOWMAP_END; 856 | 857 | for (i = vaddr; i <= vaddr_end; i += SHADOWMAP_GRANULARITY, paddr += SHADOWMAP_GRANULARITY) { 858 | #if SPURIOUS_DEBUG_OUTPUT 859 | printf("ProtoTTE: 0x%08x for VA 0x%08x -> PA 0x%08x\n", L1_PROTO_TTE(paddr), i, paddr); 860 | #endif 861 | ttb_template[TTB_OFFSET(i) >> PFN_SHIFT] = L1_PROTO_TTE(paddr); 862 | } 863 | 864 | /* 865 | * Remap TTE for iBoot load address. 866 | */ 867 | uint32_t ttb_remap_addr_base = 0x7fe00000; 868 | ttb_template[TTB_OFFSET(ttb_remap_addr_base) >> PFN_SHIFT] = L1_PROTO_TTE(phys_addr_remap); 869 | #if SPURIOUS_DEBUG_OUTPUT 870 | printf("remap -> 0x%08x => 0x%08x (TTE: 0x%08x)\n", ttb_remap_addr_base, phys_addr_remap, L1_PROTO_TTE(phys_addr_remap)); 871 | 872 | printf("TTE offset begin for shadowmap: 0x%08x\n" "TTE offset end for shadowmap: 0x%08x\n" "TTE size: 0x%08x\n", SHADOWMAP_BEGIN_OFF, SHADOWMAP_END_OFF, SHADOWMAP_SIZE); 873 | #endif 874 | 875 | printf("New TTEs generated, base address for remap: 0x%08x, physBase: 0x%08x\n", PHYS_OFF, phys_addr_remap); 876 | return; 877 | } 878 | 879 | #define DMPSIZE 0xd00000 880 | extern char shellcode_begin[], shellcode_end[]; 881 | extern uint32_t larm_init_tramp; 882 | extern uint32_t flush_dcache, invalidate_icache; 883 | extern uint32_t kern_base, kern_tramp_phys; 884 | 885 | int main(int argc, char *argv[]) 886 | { 887 | uint32_t chunksize = 2048; 888 | struct stat st; 889 | 890 | if (argc != 2) { 891 | printf("usage: %s [loadfile]\n" "This will destroy the current running OS instance and fire up the loaded image.\n" "You have been warned.\n", argv[0]); 892 | return -1; 893 | } 894 | 895 | if (stat(argv[1], &st) == -1) { 896 | printf("Failed to open %s.\n", argv[1]); 897 | return -1; 898 | } 899 | 900 | /* 901 | * Get physbase. 902 | */ 903 | size_t size; 904 | sysctlbyname("kern.version", NULL, &size, NULL, 0); 905 | char *osversion = malloc(size); 906 | if (sysctlbyname("kern.version", osversion, &size, NULL, 0) == -1) { 907 | printf("fail to kern.version sysctl\n"); 908 | exit(-1); 909 | } 910 | #if SPURIOUS_DEBUG_OUTPUT 911 | printf("%s\n", osversion); 912 | #endif 913 | 914 | if (strcasestr(osversion, "s5l8930x")) { 915 | PHYS_OFF = S5L8930_PHYS_OFF; 916 | phys_addr_remap = 0x5fe00000; 917 | } else if (strcasestr(osversion, "s5l8920x") || strcasestr(osversion, "s5l8922x")) { 918 | PHYS_OFF = S5L8930_PHYS_OFF; 919 | phys_addr_remap = 0x4fe00000; 920 | } else if (strcasestr(osversion, "s5l8940x") || strcasestr(osversion, "s5l8942x") || strcasestr(osversion, "s5l8947x")) { 921 | /* 922 | * All others have the high ram base. 923 | */ 924 | PHYS_OFF = S5L8940_PHYS_OFF; 925 | phys_addr_remap = 0x9fe00000; 926 | } else if (strcasestr(osversion, "s5l8945x")) { 927 | PHYS_OFF = S5L8940_PHYS_OFF; 928 | phys_addr_remap = 0xbfe00000; 929 | } else if (strcasestr(osversion, "s5l8950x") || strcasestr(osversion, "s5l8955x")) { 930 | PHYS_OFF = S5L8940_PHYS_OFF; 931 | phys_addr_remap = 0xbfe00000; 932 | } else { 933 | printf("Bravely assuming you're on an 8940-class device (unrecognized). You are on your own.\n"); 934 | /* 935 | * All others have the high ram base. 936 | */ 937 | PHYS_OFF = S5L8940_PHYS_OFF; 938 | phys_addr_remap = 0x9fe00000; 939 | } 940 | 941 | /* 942 | * Pedanticness, though doesn't matter, after we quit the entire OS is gone lol 943 | */ 944 | free(osversion); 945 | 946 | #if SPURIOUS_DEBUG_OUTPUT 947 | printf("physOff 0x%08x remap 0x%08x\n", PHYS_OFF, phys_addr_remap); 948 | #endif 949 | 950 | /* 951 | * get kernel base. 952 | */ 953 | kernel_base = get_kernel_base(); 954 | if (kernel_base == (vm_address_t)-1) { 955 | printf("failed to get kernel_baseel base...\n"); 956 | return -1; 957 | } 958 | 959 | printf("Kernel base is 0x%08x.\n", kernel_base); 960 | 961 | /* 962 | * we can now find the kernel pmap. 963 | */ 964 | kern_return_t r = task_for_pid(mach_task_self(), 0, &kernel_task); 965 | if (r != 0) { 966 | printf("task_for_pid failed.\n"); 967 | return -1; 968 | } 969 | 970 | /* 971 | * kill 972 | */ 973 | vm_address_t addr = kernel_base + 0x1000, e = 0, sz = 0; 974 | uint8_t *p = malloc(DMPSIZE + 0x1000); 975 | pointer_t buf; 976 | 977 | if (!p) { 978 | printf("failed to malloc memory for kernel dump...\n"); 979 | return -1; 980 | } 981 | while (addr < (kernel_base + DMPSIZE)) { 982 | vm_read(kernel_task, addr, chunksize, &buf, &sz); 983 | if (!buf || sz == 0) 984 | continue; 985 | uint8_t *z = (uint8_t *) buf; 986 | addr += chunksize; 987 | bcopy(z, p + e, chunksize); 988 | e += chunksize; 989 | } 990 | 991 | /* 992 | * kernel dumped, now find pmap. 993 | */ 994 | uint32_t kernel_pmap = kernel_base + 0x1000 + find_pmap_location(kernel_base, (uint8_t *) p, DMPSIZE); 995 | printf("kernel pmap is at 0x%08x.\n", kernel_pmap); 996 | 997 | /* 998 | * Read for kernel_pmap, dereference it for pmap_store. 999 | */ 1000 | vm_read(kernel_task, kernel_pmap, 2048, &buf, &sz); 1001 | vm_read(kernel_task, *(vm_address_t *) (buf), 2048, &buf, &sz); 1002 | 1003 | /* 1004 | * We now have the struct. Let's copy it out to get the TTE base (we don't really need to do this 1005 | * as it should just remain constant. TTEs should be after ToKD.) 1006 | */ 1007 | pmap_partial_t *part = (pmap_partial_t *) buf; 1008 | uint32_t tte_virt = part->tte_virt; 1009 | uint32_t tte_phys = part->tte_phys; 1010 | 1011 | printf("kernel pmap details: tte_virt: 0x%08x tte_phys: 0x%08x\n", tte_virt, tte_phys); 1012 | if (PHYS_OFF != (tte_phys & ~0xFFFFFFF)) { 1013 | printf("physOff 0x%08x should be 0x%08x\n", PHYS_OFF, tte_phys & ~0xFFFFFFF); 1014 | return -1; 1015 | } 1016 | 1017 | /* 1018 | * generate TTEs. 1019 | */ 1020 | generate_ttb_entries(); 1021 | 1022 | /* 1023 | * Now, we can start reading at the TTE base and start writing in the descriptors. 1024 | */ 1025 | uint32_t tte_off = SHADOWMAP_BEGIN_OFF; 1026 | vm_read(kernel_task, tte_virt + tte_off, 2048, &buf, &sz); 1027 | bcopy((char *) ttb_template_ptr + tte_off, (void *) buf, SHADOWMAP_SIZE); 1028 | vm_write(kernel_task, tte_virt + tte_off, buf, sz); 1029 | 1030 | printf("======================================================================================\n"); 1031 | printf("!!!! Kernel TTE entries written. System stability is no longer guaranteed.\n"); 1032 | printf("!!!! Security has also been reduced by an exponential factor. You have been warned.\n"); 1033 | printf("======================================================================================\n"); 1034 | 1035 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1036 | signal(SIGINT, SIG_IGN); 1037 | 1038 | /* 1039 | * remap_address = 0x7ff00000 1040 | */ 1041 | FILE *f = fopen(argv[1], "rb"); 1042 | if (!f) { 1043 | printf("Failed to open iBEC. Rebooting momentarily...\n"); 1044 | sleep(3); 1045 | reboot(0); 1046 | } 1047 | 1048 | fseek(f, 0, SEEK_END); 1049 | int length = ftell(f); 1050 | fseek(f, 0, SEEK_SET); 1051 | void *vp = malloc(length); 1052 | fread(vp, length, 1, f); 1053 | fclose(f); 1054 | printf("Read bootloader into buffer %p, length %d\n", vp, length); 1055 | 1056 | bcopy((void *) vp, (void *) 0x7fe00000, length); 1057 | 1058 | /* 1059 | * Verify ARM header. 1060 | */ 1061 | if (*(uint32_t *) 0x7fe00000 != 0xea00000e) { 1062 | printf("This doesn't seem like an ARM image, perhaps it failed to copy? Continuing though.\n"); 1063 | } 1064 | 1065 | printf("Image information: %s\n", (char *) 0x7fe00000 + 0x200); 1066 | printf("Image information: %s\n", (char *) 0x7fe00000 + 0x240); 1067 | printf("Image information: %s\n", (char *) 0x7fe00000 + 0x280); 1068 | 1069 | free(vp); 1070 | 1071 | /* 1072 | * iBEC copied, we need to copy over the shellcode now. 1073 | */ 1074 | uint32_t sysent_common = 0x1000 + find_syscall0(kernel_base + 0x1000, (uint8_t *) p, DMPSIZE) + SHADOWMAP_BEGIN; 1075 | printf("sysent_common_base: 0x%08x\n", sysent_common); 1076 | 1077 | /* 1078 | * fuck evasi0n7 1079 | */ 1080 | if (*(uint32_t *) (sysent_common) == 0) { 1081 | printf("iOS 7 detected, adjusting base to 0x%08x = 0x%08x\n", sysent_common, *(uint32_t *) (sysent_common)); 1082 | sysent_common += 4; 1083 | if (*(uint32_t *) (sysent_common) == 0) { 1084 | printf("Something is severely wrong (blaming iOS 7 anyhow). Rebooting momentarily.\n"); 1085 | sleep(3); 1086 | reboot(0); 1087 | } 1088 | } 1089 | 1090 | /* 1091 | * Set offsets. 1092 | */ 1093 | larm_init_tramp = 0x1000 + find_larm_init_tramp(kernel_base + 0x1000, (uint8_t *) p, DMPSIZE) + SHADOWMAP_BEGIN; 1094 | 1095 | kern_base = kernel_base; 1096 | kern_tramp_phys = phys_addr_remap; 1097 | 1098 | #if 0 1099 | 1100 | printf("larm_init_tramp is at 0x%08x\n", larm_init_tramp); 1101 | bcopy(shellcode_begin, (void *) 0x7f000c00, shellcode_end - shellcode_begin); 1102 | *(uint32_t *) sysent_common = 0x7f000c01; 1103 | 1104 | printf("Running shellcode now.\n"); 1105 | syscall(0); 1106 | 1107 | #else 1108 | 1109 | static uint32_t arm[2] = { 0xe51ff004, 0 }; 1110 | arm[1] = phys_addr_remap; 1111 | // Requires D-cache writeback. 1112 | printf("Tramp %x COMMMAP\n", larm_init_tramp); 1113 | printf("%lx, %lx\n", *(uintptr_t *) (larm_init_tramp), *(uintptr_t *) (larm_init_tramp + 4)); 1114 | printf("%x\n", *(uint32_t *) (0x7f000000 + 0x1000)); 1115 | bcopy((void *) arm, (void *) larm_init_tramp, sizeof(arm)); 1116 | printf("%lx, %lx\n", *(uintptr_t *) (larm_init_tramp), *(uintptr_t *) (larm_init_tramp + 4)); 1117 | printf("%x\n", *(uint32_t *) (0x7f000000 + 0x1000)); 1118 | 1119 | #endif 1120 | 1121 | printf("Syncing disks.\n"); 1122 | int diskSync; 1123 | for (diskSync = 0; diskSync < 10; diskSync++) 1124 | sync(); 1125 | sleep(1); 1126 | 1127 | while (1) { 1128 | printf("Magic happening now. (attempted!)\n"); 1129 | mach_port_t fb = IOPMFindPowerManagement(MACH_PORT_NULL); 1130 | if (fb != MACH_PORT_NULL) { 1131 | kern_return_t kr = IOPMSleepSystem(fb); 1132 | if (kr) { 1133 | err(1, "IOPMSleepSystem returned %x\n", kr); 1134 | } 1135 | } else { 1136 | err(1, "failed to get PM root port\n"); 1137 | } 1138 | sleep(3); 1139 | } 1140 | 1141 | return 0; 1142 | } 1143 | 1144 | /* how evil can you get???? */ 1145 | #if INLINE_IT_ALL 1146 | /* hey, you gotta compile with -no-integrated-as */ 1147 | #ifdef __arm__ 1148 | __asm__("\n" 1149 | " .code 16\n" 1150 | " .thumb_func\n" 1151 | " .align 2\n" 1152 | " .data\n" 1153 | " .globl _shellcode_begin\n" 1154 | " .globl _shellcode_end\n" 1155 | " .globl _larm_init_tramp\n" 1156 | " .globl _flush_dcache\n" 1157 | " .globl _invalidate_icache\n" 1158 | " .globl _kern_tramp_phys\n" 1159 | " .globl _kern_base\n" 1160 | "_shellcode_begin:\n" 1161 | " mrs r12, cpsr\n" 1162 | " cpsid if\n" 1163 | " ldr r0, 0f\n" 1164 | " ldr r1, _kern_tramp_phys\n" 1165 | " ldr r2, _larm_init_tramp\n" 1166 | " str r0, [r2]\n" 1167 | " str r1, [r2, #4]\n" 1168 | " ldr r0, _kern_base\n" 1169 | " @ Clear cache to PoC\n" 1170 | " ldr r2, _larm_init_tramp\n" 1171 | " bic r2, r2, #((1 << 6) - 1)\n" 1172 | " mcr p15, 0, r2, c7, c14, 1\n" 1173 | " mov r1, #256\n" 1174 | ".Lloop:\n" 1175 | " add r2, r2, #(1 << 6)\n" 1176 | " mcr p15, 0, r2, c7, c14, 1\n" 1177 | " subs r1, r1, #1\n" 1178 | " bne .Lloop\n" 1179 | " msr cpsr_c, r12\n" 1180 | " movs r0, #0\n" 1181 | " bx lr\n" 1182 | " .align 2\n" 1183 | "0: .long 0xe51ff004\n" 1184 | "_kern_tramp_phys: .long 0x9bf00000\n" 1185 | "_kern_base: .long 0xdeadbeef\n" 1186 | "_larm_init_tramp: .long 0xdeadbeef\n" 1187 | "_flush_dcache: .long 0xdeadbeef\n" 1188 | "_invalidate_icache: .long 0xdeadbeef\n" 1189 | "_shellcode_end:\n" 1190 | " mov r8, r8\n"); 1191 | #else 1192 | #error - this is only for ARM.. 1193 | #endif 1194 | #endif 1195 | -------------------------------------------------------------------------------- /multi_kloader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014, winocm. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | * 18 | * $Id$ 19 | */ 20 | /* 21 | * multi_kloader 22 | * Requires iOS 6.x or higher. (This version only.) 23 | * 24 | * Designed to chain both iBSS + iBEC, not just one. 25 | * 26 | * Remap addresses: 27 | * 0x7fe00000 -> 0x9fe00000 (0x5fe00000) iBSS (jump-to) 28 | * 0x7fd00000 -> 0x9fd00000 (0x5fd00000) iBEC 29 | * 30 | * 31 | * xcrun -sdk iphoneos clang kloader.c -arch armv7 -framework IOKit -framework CoreFoundation -no-integrated-as \ 32 | * -DINLINE_IT_ALL=1 -Wall -o kloader -miphoneos-version-min=6.0; ldid -Stfp0.plist kloader 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | typedef mach_port_t io_service_t; 46 | extern mach_port_t kIOMasterPortDefault; 47 | extern mach_port_t IOPMFindPowerManagement(mach_port_t); 48 | extern kern_return_t IOPMSleepSystem(mach_port_t); 49 | 50 | /* 51 | * ARM page bits for L1 sections. 52 | */ 53 | #define L1_SHIFT 20 /* log2(1MB) */ 54 | 55 | #define L1_SECT_PROTO (1 << 1) /* 0b10 */ 56 | 57 | #define L1_SECT_B_BIT (1 << 2) 58 | #define L1_SECT_C_BIT (1 << 3) 59 | 60 | #define L1_SECT_SORDER (0) /* 0b00, not cacheable, strongly ordered. */ 61 | #define L1_SECT_SH_DEVICE (L1_SECT_B_BIT) 62 | #define L1_SECT_WT_NWA (L1_SECT_C_BIT) 63 | #define L1_SECT_WB_NWA (L1_SECT_B_BIT | L1_SECT_C_BIT) 64 | #define L1_SECT_S_BIT (1 << 16) 65 | 66 | #define L1_SECT_AP_URW (1 << 10) | (1 << 11) 67 | #define L1_SECT_PFN(x) (x & 0xFFF00000) 68 | 69 | #define L1_SECT_DEFPROT (L1_SECT_AP_URW) 70 | #define L1_SECT_DEFCACHE (L1_SECT_SORDER) 71 | 72 | #define L1_PROTO_TTE(paddr) (L1_SECT_PFN(paddr) | L1_SECT_S_BIT | L1_SECT_DEFPROT | L1_SECT_DEFCACHE | L1_SECT_PROTO) 73 | 74 | #define PFN_SHIFT 2 75 | #define TTB_OFFSET(vaddr) ((vaddr >> L1_SHIFT) << PFN_SHIFT) 76 | 77 | /* 78 | * RAM physical base begin. 79 | */ 80 | #define S5L8930_PHYS_OFF 0x40000000 81 | #define S5L8940_PHYS_OFF 0x80000000 /* Note: RAM base is identical for 8940-8955. */ 82 | 83 | uint32_t PHYS_OFF = S5L8930_PHYS_OFF; 84 | 85 | /* 86 | * Shadowmap begin and end. 15MB of shadowmap is enough for the kernel. 87 | * We don't need to invalidate unified D/I TLB or any cache lines 88 | * since the kernel is mapped as writethrough memory, and these 89 | * addresses are guaranteed to not be translated. 90 | * (Accesses will cause segmentation faults due to failure on L1 translation.) 91 | * 92 | * Clear the shadowmappings when done owning the kernel. 93 | * 94 | * 0x7ff0'0000 is also below the limit for vm_read and such, so that's also *great*. 95 | * (2048 bytes) 96 | */ 97 | #define SHADOWMAP_BEGIN 0x7f000000 98 | #define SHADOWMAP_END 0x7ff00000 99 | #define SHADOWMAP_GRANULARITY 0x00100000 100 | 101 | #define SHADOWMAP_SIZE_BYTES (SHADOWMAP_END - SHADOWMAP_BEGIN) 102 | 103 | #define SHADOWMAP_BEGIN_OFF TTB_OFFSET(SHADOWMAP_BEGIN) 104 | #define SHADOWMAP_END_OFF TTB_OFFSET(SHADOWMAP_END) 105 | #define SHADOWMAP_SIZE (SHADOWMAP_END_OFF - SHADOWMAP_BEGIN_OFF) 106 | 107 | #define SHADOWMAP_BEGIN_IDX (SHADOWMAP_BEGIN_OFF >> PFN_SHIFT) 108 | #define SHADOWMAP_END_IDX (SHADOWMAP_END_OFF >> PFN_SHIFT) 109 | 110 | #define TTB_SIZE 4096 111 | #define DEFAULT_KERNEL_SLIDE 0x80000000 112 | 113 | static mach_port_t kernel_task = 0; 114 | static uint32_t ttb_template[TTB_SIZE] = { }; 115 | 116 | static void *ttb_template_ptr = &ttb_template[0]; 117 | static vm_address_t kernel_base = DEFAULT_KERNEL_SLIDE; 118 | 119 | typedef struct pmap_partial_t { 120 | uint32_t tte_virt; 121 | uint32_t tte_phys; 122 | /* 123 | * ... 124 | */ 125 | } pmap_partial_t; 126 | 127 | /* --- planetbeing patchfinder --- */ 128 | 129 | static uint32_t bit_range(uint32_t x, int start, int end) 130 | { 131 | x = (x << (31 - start)) >> (31 - start); 132 | x = (x >> end); 133 | return x; 134 | } 135 | 136 | static uint32_t ror(uint32_t x, int places) 137 | { 138 | return (x >> places) | (x << (32 - places)); 139 | } 140 | 141 | static int thumb_expand_imm_c(uint16_t imm12) 142 | { 143 | if (bit_range(imm12, 11, 10) == 0) { 144 | switch (bit_range(imm12, 9, 8)) { 145 | case 0: 146 | return bit_range(imm12, 7, 0); 147 | case 1: 148 | return (bit_range(imm12, 7, 0) << 16) | bit_range(imm12, 7, 0); 149 | case 2: 150 | return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 8); 151 | case 3: 152 | return (bit_range(imm12, 7, 0) << 24) | (bit_range(imm12, 7, 0) << 16) | (bit_range(imm12, 7, 0) << 8) | bit_range(imm12, 7, 0); 153 | default: 154 | return 0; 155 | } 156 | } else { 157 | uint32_t unrotated_value = 0x80 | bit_range(imm12, 6, 0); 158 | return ror(unrotated_value, bit_range(imm12, 11, 7)); 159 | } 160 | } 161 | 162 | static int insn_is_32bit(uint16_t * i) 163 | { 164 | return (*i & 0xe000) == 0xe000 && (*i & 0x1800) != 0x0; 165 | } 166 | 167 | static int insn_is_bl(uint16_t * i) 168 | { 169 | if ((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd000) == 0xd000) 170 | return 1; 171 | else if ((*i & 0xf800) == 0xf000 && (*(i + 1) & 0xd001) == 0xc000) 172 | return 1; 173 | else 174 | return 0; 175 | } 176 | 177 | static uint32_t insn_bl_imm32(uint16_t * i) 178 | { 179 | uint16_t insn0 = *i; 180 | uint16_t insn1 = *(i + 1); 181 | uint32_t s = (insn0 >> 10) & 1; 182 | uint32_t j1 = (insn1 >> 13) & 1; 183 | uint32_t j2 = (insn1 >> 11) & 1; 184 | uint32_t i1 = ~(j1 ^ s) & 1; 185 | uint32_t i2 = ~(j2 ^ s) & 1; 186 | uint32_t imm10 = insn0 & 0x3ff; 187 | uint32_t imm11 = insn1 & 0x7ff; 188 | uint32_t imm32 = (imm11 << 1) | (imm10 << 12) | (i2 << 22) | (i1 << 23) | (s ? 0xff000000 : 0); 189 | return imm32; 190 | } 191 | 192 | static int insn_is_b_conditional(uint16_t * i) 193 | { 194 | return (*i & 0xF000) == 0xD000 && (*i & 0x0F00) != 0x0F00 && (*i & 0x0F00) != 0xE; 195 | } 196 | 197 | static int insn_is_b_unconditional(uint16_t * i) 198 | { 199 | if ((*i & 0xF800) == 0xE000) 200 | return 1; 201 | else if ((*i & 0xF800) == 0xF000 && (*(i + 1) & 0xD000) == 9) 202 | return 1; 203 | else 204 | return 0; 205 | } 206 | 207 | static int insn_is_ldr_literal(uint16_t * i) 208 | { 209 | return (*i & 0xF800) == 0x4800 || (*i & 0xFF7F) == 0xF85F; 210 | } 211 | 212 | static int insn_ldr_literal_rt(uint16_t * i) 213 | { 214 | if ((*i & 0xF800) == 0x4800) 215 | return (*i >> 8) & 7; 216 | else if ((*i & 0xFF7F) == 0xF85F) 217 | return (*(i + 1) >> 12) & 0xF; 218 | else 219 | return 0; 220 | } 221 | 222 | static int insn_ldr_literal_imm(uint16_t * i) 223 | { 224 | if ((*i & 0xF800) == 0x4800) 225 | return (*i & 0xF) << 2; 226 | else if ((*i & 0xFF7F) == 0xF85F) 227 | return (*(i + 1) & 0xFFF) * (((*i & 0x0800) == 0x0800) ? 1 : -1); 228 | else 229 | return 0; 230 | } 231 | 232 | // TODO: More encodings 233 | static int insn_is_ldr_imm(uint16_t * i) 234 | { 235 | uint8_t opA = bit_range(*i, 15, 12); 236 | uint8_t opB = bit_range(*i, 11, 9); 237 | 238 | return opA == 6 && (opB & 4) == 4; 239 | } 240 | 241 | static int insn_ldr_imm_rt(uint16_t * i) 242 | { 243 | return (*i & 7); 244 | } 245 | 246 | static int insn_ldr_imm_rn(uint16_t * i) 247 | { 248 | return ((*i >> 3) & 7); 249 | } 250 | 251 | static int insn_ldr_imm_imm(uint16_t * i) 252 | { 253 | return ((*i >> 6) & 0x1F); 254 | } 255 | 256 | // TODO: More encodings 257 | static int insn_is_ldrb_imm(uint16_t * i) 258 | { 259 | return (*i & 0xF800) == 0x7800; 260 | } 261 | 262 | static int insn_ldrb_imm_rt(uint16_t * i) 263 | { 264 | return (*i & 7); 265 | } 266 | 267 | static int insn_ldrb_imm_rn(uint16_t * i) 268 | { 269 | return ((*i >> 3) & 7); 270 | } 271 | 272 | static int insn_ldrb_imm_imm(uint16_t * i) 273 | { 274 | return ((*i >> 6) & 0x1F); 275 | } 276 | 277 | static int insn_is_ldr_reg(uint16_t * i) 278 | { 279 | if ((*i & 0xFE00) == 0x5800) 280 | return 1; 281 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 282 | return 1; 283 | else 284 | return 0; 285 | } 286 | 287 | static int insn_ldr_reg_rn(uint16_t * i) 288 | { 289 | if ((*i & 0xFE00) == 0x5800) 290 | return (*i >> 3) & 0x7; 291 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 292 | return (*i & 0xF); 293 | else 294 | return 0; 295 | } 296 | 297 | int insn_ldr_reg_rt(uint16_t * i) 298 | { 299 | if ((*i & 0xFE00) == 0x5800) 300 | return *i & 0x7; 301 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 302 | return (*(i + 1) >> 12) & 0xF; 303 | else 304 | return 0; 305 | } 306 | 307 | int insn_ldr_reg_rm(uint16_t * i) 308 | { 309 | if ((*i & 0xFE00) == 0x5800) 310 | return (*i >> 6) & 0x7; 311 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 312 | return *(i + 1) & 0xF; 313 | else 314 | return 0; 315 | } 316 | 317 | static int insn_ldr_reg_lsl(uint16_t * i) 318 | { 319 | if ((*i & 0xFE00) == 0x5800) 320 | return 0; 321 | else if ((*i & 0xFFF0) == 0xF850 && (*(i + 1) & 0x0FC0) == 0x0000) 322 | return (*(i + 1) >> 4) & 0x3; 323 | else 324 | return 0; 325 | } 326 | 327 | static int insn_is_add_reg(uint16_t * i) 328 | { 329 | if ((*i & 0xFE00) == 0x1800) 330 | return 1; 331 | else if ((*i & 0xFF00) == 0x4400) 332 | return 1; 333 | else if ((*i & 0xFFE0) == 0xEB00) 334 | return 1; 335 | else 336 | return 0; 337 | } 338 | 339 | static int insn_add_reg_rd(uint16_t * i) 340 | { 341 | if ((*i & 0xFE00) == 0x1800) 342 | return (*i & 7); 343 | else if ((*i & 0xFF00) == 0x4400) 344 | return (*i & 7) | ((*i & 0x80) >> 4); 345 | else if ((*i & 0xFFE0) == 0xEB00) 346 | return (*(i + 1) >> 8) & 0xF; 347 | else 348 | return 0; 349 | } 350 | 351 | static int insn_add_reg_rn(uint16_t * i) 352 | { 353 | if ((*i & 0xFE00) == 0x1800) 354 | return ((*i >> 3) & 7); 355 | else if ((*i & 0xFF00) == 0x4400) 356 | return (*i & 7) | ((*i & 0x80) >> 4); 357 | else if ((*i & 0xFFE0) == 0xEB00) 358 | return (*i & 0xF); 359 | else 360 | return 0; 361 | } 362 | 363 | static int insn_add_reg_rm(uint16_t * i) 364 | { 365 | if ((*i & 0xFE00) == 0x1800) 366 | return (*i >> 6) & 7; 367 | else if ((*i & 0xFF00) == 0x4400) 368 | return (*i >> 3) & 0xF; 369 | else if ((*i & 0xFFE0) == 0xEB00) 370 | return *(i + 1) & 0xF; 371 | else 372 | return 0; 373 | } 374 | 375 | static int insn_is_movt(uint16_t * i) 376 | { 377 | return (*i & 0xFBF0) == 0xF2C0 && (*(i + 1) & 0x8000) == 0; 378 | } 379 | 380 | static int insn_movt_rd(uint16_t * i) 381 | { 382 | return (*(i + 1) >> 8) & 0xF; 383 | } 384 | 385 | static int insn_movt_imm(uint16_t * i) 386 | { 387 | return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF); 388 | } 389 | 390 | static int insn_is_mov_imm(uint16_t * i) 391 | { 392 | if ((*i & 0xF800) == 0x2000) 393 | return 1; 394 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 395 | return 1; 396 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 397 | return 1; 398 | else 399 | return 0; 400 | } 401 | 402 | static int insn_mov_imm_rd(uint16_t * i) 403 | { 404 | if ((*i & 0xF800) == 0x2000) 405 | return (*i >> 8) & 7; 406 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 407 | return (*(i + 1) >> 8) & 0xF; 408 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 409 | return (*(i + 1) >> 8) & 0xF; 410 | else 411 | return 0; 412 | } 413 | 414 | static int insn_mov_imm_imm(uint16_t * i) 415 | { 416 | if ((*i & 0xF800) == 0x2000) 417 | return *i & 0xF; 418 | else if ((*i & 0xFBEF) == 0xF04F && (*(i + 1) & 0x8000) == 0) 419 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 420 | else if ((*i & 0xFBF0) == 0xF240 && (*(i + 1) & 0x8000) == 0) 421 | return ((*i & 0xF) << 12) | ((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF); 422 | else 423 | return 0; 424 | } 425 | 426 | static int insn_is_cmp_imm(uint16_t * i) 427 | { 428 | if ((*i & 0xF800) == 0x2800) 429 | return 1; 430 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 431 | return 1; 432 | else 433 | return 0; 434 | } 435 | 436 | static int insn_cmp_imm_rn(uint16_t * i) 437 | { 438 | if ((*i & 0xF800) == 0x2800) 439 | return (*i >> 8) & 7; 440 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 441 | return *i & 0xF; 442 | else 443 | return 0; 444 | } 445 | 446 | static int insn_cmp_imm_imm(uint16_t * i) 447 | { 448 | if ((*i & 0xF800) == 0x2800) 449 | return *i & 0xFF; 450 | else if ((*i & 0xFBF0) == 0xF1B0 && (*(i + 1) & 0x8F00) == 0x0F00) 451 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 452 | else 453 | return 0; 454 | } 455 | 456 | static int insn_is_and_imm(uint16_t * i) 457 | { 458 | return (*i & 0xFBE0) == 0xF000 && (*(i + 1) & 0x8000) == 0; 459 | } 460 | 461 | static int insn_and_imm_rn(uint16_t * i) 462 | { 463 | return *i & 0xF; 464 | } 465 | 466 | static int insn_and_imm_rd(uint16_t * i) 467 | { 468 | return (*(i + 1) >> 8) & 0xF; 469 | } 470 | 471 | static int insn_and_imm_imm(uint16_t * i) 472 | { 473 | return thumb_expand_imm_c(((*i & 0x0400) << 1) | ((*(i + 1) & 0x7000) >> 4) | (*(i + 1) & 0xFF)); 474 | } 475 | 476 | static int insn_is_push(uint16_t * i) 477 | { 478 | if ((*i & 0xFE00) == 0xB400) 479 | return 1; 480 | else if (*i == 0xE92D) 481 | return 1; 482 | else if (*i == 0xF84D && (*(i + 1) & 0x0FFF) == 0x0D04) 483 | return 1; 484 | else 485 | return 0; 486 | } 487 | 488 | static int insn_push_registers(uint16_t * i) 489 | { 490 | if ((*i & 0xFE00) == 0xB400) 491 | return (*i & 0x00FF) | ((*i & 0x0100) << 6); 492 | else if (*i == 0xE92D) 493 | return *(i + 1); 494 | else if (*i == 0xF84D && (*(i + 1) & 0x0FFF) == 0x0D04) 495 | return 1 << ((*(i + 1) >> 12) & 0xF); 496 | else 497 | return 0; 498 | } 499 | 500 | static int insn_is_preamble_push(uint16_t * i) 501 | { 502 | return insn_is_push(i) && (insn_push_registers(i) & (1 << 14)) != 0; 503 | } 504 | 505 | static int insn_is_str_imm(uint16_t * i) 506 | { 507 | if ((*i & 0xF800) == 0x6000) 508 | return 1; 509 | else if ((*i & 0xF800) == 0x9000) 510 | return 1; 511 | else if ((*i & 0xFFF0) == 0xF8C0) 512 | return 1; 513 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 514 | return 1; 515 | else 516 | return 0; 517 | } 518 | 519 | static int insn_str_imm_postindexed(uint16_t * i) 520 | { 521 | if ((*i & 0xF800) == 0x6000) 522 | return 1; 523 | else if ((*i & 0xF800) == 0x9000) 524 | return 1; 525 | else if ((*i & 0xFFF0) == 0xF8C0) 526 | return 1; 527 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 528 | return (*(i + 1) >> 10) & 1; 529 | else 530 | return 0; 531 | } 532 | 533 | static int insn_str_imm_wback(uint16_t * i) 534 | { 535 | if ((*i & 0xF800) == 0x6000) 536 | return 0; 537 | else if ((*i & 0xF800) == 0x9000) 538 | return 0; 539 | else if ((*i & 0xFFF0) == 0xF8C0) 540 | return 0; 541 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 542 | return (*(i + 1) >> 8) & 1; 543 | else 544 | return 0; 545 | } 546 | 547 | static int insn_str_imm_imm(uint16_t * i) 548 | { 549 | if ((*i & 0xF800) == 0x6000) 550 | return (*i & 0x07C0) >> 4; 551 | else if ((*i & 0xF800) == 0x9000) 552 | return (*i & 0xFF) << 2; 553 | else if ((*i & 0xFFF0) == 0xF8C0) 554 | return (*(i + 1) & 0xFFF); 555 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 556 | return (*(i + 1) & 0xFF); 557 | else 558 | return 0; 559 | } 560 | 561 | static int insn_str_imm_rt(uint16_t * i) 562 | { 563 | if ((*i & 0xF800) == 0x6000) 564 | return (*i & 7); 565 | else if ((*i & 0xF800) == 0x9000) 566 | return (*i >> 8) & 7; 567 | else if ((*i & 0xFFF0) == 0xF8C0) 568 | return (*(i + 1) >> 12) & 0xF; 569 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 570 | return (*(i + 1) >> 12) & 0xF; 571 | else 572 | return 0; 573 | } 574 | 575 | static int insn_str_imm_rn(uint16_t * i) 576 | { 577 | if ((*i & 0xF800) == 0x6000) 578 | return (*i >> 3) & 7; 579 | else if ((*i & 0xF800) == 0x9000) 580 | return 13; 581 | else if ((*i & 0xFFF0) == 0xF8C0) 582 | return (*i & 0xF); 583 | else if ((*i & 0xFFF0) == 0xF840 && (*(i + 1) & 0x0800) == 0x0800) 584 | return (*i & 0xF); 585 | else 586 | return 0; 587 | } 588 | 589 | // Given an instruction, search backwards until an instruction is found matching the specified criterion. 590 | static uint16_t *find_last_insn_matching(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * current_instruction, int (*match_func) (uint16_t *)) 591 | { 592 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 593 | if (insn_is_32bit(current_instruction - 2) && !insn_is_32bit(current_instruction - 3)) { 594 | current_instruction -= 2; 595 | } else { 596 | --current_instruction; 597 | } 598 | 599 | if (match_func(current_instruction)) { 600 | return current_instruction; 601 | } 602 | } 603 | 604 | return NULL; 605 | } 606 | 607 | // Given an instruction and a register, find the PC-relative address that was stored inside the register by the time the instruction was reached. 608 | static uint32_t find_pc_rel_value(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * insn, int reg) 609 | { 610 | // Find the last instruction that completely wiped out this register 611 | int found = 0; 612 | uint16_t *current_instruction = insn; 613 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 614 | if (insn_is_32bit(current_instruction - 2)) { 615 | current_instruction -= 2; 616 | } else { 617 | --current_instruction; 618 | } 619 | 620 | if (insn_is_mov_imm(current_instruction) && insn_mov_imm_rd(current_instruction) == reg) { 621 | found = 1; 622 | break; 623 | } 624 | 625 | if (insn_is_ldr_literal(current_instruction) && insn_ldr_literal_rt(current_instruction) == reg) { 626 | found = 1; 627 | break; 628 | } 629 | } 630 | 631 | if (!found) 632 | return 0; 633 | 634 | // Step through instructions, executing them as a virtual machine, only caring about instructions that affect the target register and are commonly used for PC-relative addressing. 635 | uint32_t value = 0; 636 | while ((uintptr_t) current_instruction < (uintptr_t) insn) { 637 | if (insn_is_mov_imm(current_instruction) && insn_mov_imm_rd(current_instruction) == reg) { 638 | value = insn_mov_imm_imm(current_instruction); 639 | } else if (insn_is_ldr_literal(current_instruction) && insn_ldr_literal_rt(current_instruction) == reg) { 640 | value = *(uint32_t *) (kdata + (((((uintptr_t) current_instruction - (uintptr_t) kdata) + 4) & 0xFFFFFFFC) + insn_ldr_literal_imm(current_instruction))); 641 | } else if (insn_is_movt(current_instruction) && insn_movt_rd(current_instruction) == reg) { 642 | value |= insn_movt_imm(current_instruction) << 16; 643 | } else if (insn_is_add_reg(current_instruction) && insn_add_reg_rd(current_instruction) == reg) { 644 | if (insn_add_reg_rm(current_instruction) != 15 || insn_add_reg_rn(current_instruction) != reg) { 645 | // Can't handle this kind of operation! 646 | return 0; 647 | } 648 | 649 | value += ((uintptr_t) current_instruction - (uintptr_t) kdata) + 4; 650 | } 651 | 652 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 653 | } 654 | 655 | return value; 656 | } 657 | 658 | // Find PC-relative references to a certain address (relative to kdata). This is basically a virtual machine that only cares about instructions used in PC-relative addressing, so no branches, etc. 659 | static uint16_t *find_literal_ref(uint32_t region, uint8_t * kdata, size_t ksize, uint16_t * insn, uint32_t address) 660 | { 661 | uint16_t *current_instruction = insn; 662 | uint32_t value[16]; 663 | memset(value, 0, sizeof(value)); 664 | 665 | while ((uintptr_t) current_instruction < (uintptr_t) (kdata + ksize)) { 666 | if (insn_is_mov_imm(current_instruction)) { 667 | value[insn_mov_imm_rd(current_instruction)] = insn_mov_imm_imm(current_instruction); 668 | } else if (insn_is_ldr_literal(current_instruction)) { 669 | uintptr_t literal_address = (uintptr_t) kdata + ((((uintptr_t) current_instruction - (uintptr_t) kdata) + 4) & 0xFFFFFFFC) + insn_ldr_literal_imm(current_instruction); 670 | if (literal_address >= (uintptr_t) kdata && (literal_address + 4) <= ((uintptr_t) kdata + ksize)) { 671 | value[insn_ldr_literal_rt(current_instruction)] = *(uint32_t *) (literal_address); 672 | } 673 | } else if (insn_is_movt(current_instruction)) { 674 | value[insn_movt_rd(current_instruction)] |= insn_movt_imm(current_instruction) << 16; 675 | } else if (insn_is_add_reg(current_instruction)) { 676 | int reg = insn_add_reg_rd(current_instruction); 677 | if (insn_add_reg_rm(current_instruction) == 15 && insn_add_reg_rn(current_instruction) == reg) { 678 | value[reg] += ((uintptr_t) current_instruction - (uintptr_t) kdata) + 4; 679 | if (value[reg] == address) { 680 | return current_instruction; 681 | } 682 | } 683 | } 684 | 685 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 686 | } 687 | 688 | return NULL; 689 | } 690 | 691 | // This points to kernel_pmap. Use that to change the page tables if necessary. 692 | uint32_t find_pmap_location(uint32_t region, uint8_t * kdata, size_t ksize) 693 | { 694 | // Find location of the pmap_map_bd string. 695 | uint8_t *pmap_map_bd = memmem(kdata, ksize, "\"pmap_map_bd\"", sizeof("\"pmap_map_bd\"")); 696 | if (!pmap_map_bd) 697 | return 0; 698 | 699 | // Find a reference to the pmap_map_bd string. That function also references kernel_pmap 700 | uint16_t *ptr = find_literal_ref(region, kdata, ksize, (uint16_t *) kdata, (uintptr_t) pmap_map_bd - (uintptr_t) kdata); 701 | if (!ptr) 702 | return 0; 703 | 704 | // Find the beginning of it (we may have a version that throws panic after the function end). 705 | while (*ptr != 0xB5F0) { 706 | if ((uint8_t *)ptr == kdata) 707 | return 0; 708 | ptr--; 709 | } 710 | 711 | // Find the end of it. 712 | const uint8_t search_function_end[] = { 0xF0, 0xBD }; 713 | ptr = memmem(ptr, ksize - ((uintptr_t) ptr - (uintptr_t) kdata), search_function_end, sizeof(search_function_end)); 714 | if (!ptr) 715 | return 0; 716 | 717 | // Find the last BL before the end of it. The third argument to it should be kernel_pmap 718 | uint16_t *bl = find_last_insn_matching(region, kdata, ksize, ptr, insn_is_bl); 719 | if (!bl) 720 | return 0; 721 | 722 | // Find the last LDR R2, [R*] before it that's before any branches. If there are branches, then we have a version of the function that assumes kernel_pmap instead of being passed it. 723 | uint16_t *ldr_r2 = NULL; 724 | uint16_t *current_instruction = bl; 725 | while ((uintptr_t) current_instruction > (uintptr_t) kdata) { 726 | if (insn_is_32bit(current_instruction - 2) && !insn_is_32bit(current_instruction - 3)) { 727 | current_instruction -= 2; 728 | } else { 729 | --current_instruction; 730 | } 731 | 732 | if (insn_ldr_imm_rt(current_instruction) == 2 && insn_ldr_imm_imm(current_instruction) == 0) { 733 | ldr_r2 = current_instruction; 734 | break; 735 | } else if (insn_is_b_conditional(current_instruction) || insn_is_b_unconditional(current_instruction)) { 736 | break; 737 | } 738 | } 739 | 740 | // The function has a third argument, which must be kernel_pmap. Find out its address 741 | if (ldr_r2) 742 | return find_pc_rel_value(region, kdata, ksize, ldr_r2, insn_ldr_imm_rn(ldr_r2)); 743 | 744 | // The function has no third argument, Follow the BL. 745 | uint32_t imm32 = insn_bl_imm32(bl); 746 | uint32_t target = ((uintptr_t) bl - (uintptr_t) kdata) + 4 + imm32; 747 | if (target > ksize) 748 | return 0; 749 | 750 | // Find the first PC-relative reference in this function. 751 | int found = 0; 752 | 753 | int rd; 754 | current_instruction = (uint16_t *) (kdata + target); 755 | while ((uintptr_t) current_instruction < (uintptr_t) (kdata + ksize)) { 756 | if (insn_is_add_reg(current_instruction) && insn_add_reg_rm(current_instruction) == 15) { 757 | found = 1; 758 | rd = insn_add_reg_rd(current_instruction); 759 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 760 | break; 761 | } 762 | 763 | current_instruction += insn_is_32bit(current_instruction) ? 2 : 1; 764 | } 765 | 766 | if (!found) 767 | return 0; 768 | 769 | return find_pc_rel_value(region, kdata, ksize, current_instruction, rd); 770 | } 771 | 772 | // Function to find the syscall 0 function pointer. Used to modify the syscall table to call our own code. 773 | uint32_t find_syscall0(uint32_t region, uint8_t * kdata, size_t ksize) 774 | { 775 | // Search for the preamble to syscall 1 776 | const uint8_t syscall1_search[] = { 0x90, 0xB5, 0x01, 0xAF, 0x82, 0xB0, 0x09, 0x68, 0x01, 0x24, 0x00, 0x23 }; 777 | void *ptr = memmem(kdata, ksize, syscall1_search, sizeof(syscall1_search)); 778 | if (!ptr) 779 | return 0; 780 | 781 | // Search for a pointer to syscall 1 782 | uint32_t ptr_address = (uintptr_t) ptr - (uintptr_t) kdata + region; 783 | uint32_t function = ptr_address | 1; 784 | void *syscall1_entry = memmem(kdata, ksize, &function, sizeof(function)); 785 | if (!syscall1_entry) 786 | return 0; 787 | 788 | // Calculate the address of syscall 0 from the address of the syscall 1 entry 789 | return (uintptr_t) syscall1_entry - (uintptr_t) kdata - 0x18; 790 | } 791 | 792 | // 0E E0 9F E7 FF FF FF EA C0 00 0C F1 793 | // ldr lr, [pc, lr] 794 | // b +0x0 795 | // cpsid if 796 | 797 | uint32_t find_larm_init_tramp(uint32_t region, uint8_t * kdata, size_t ksize) 798 | { 799 | const uint8_t search[] = { 0x0E, 0xE0, 0x9F, 0xE7, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0x00, 0x0C, 0xF1 }; 800 | void *ptr = memmem(kdata, ksize, search, sizeof(search)); 801 | if (!ptr) 802 | return 0; 803 | 804 | return ((uintptr_t) ptr) - ((uintptr_t) kdata); 805 | } 806 | 807 | /* --- planetbeing patchfinder --- */ 808 | 809 | uint32_t phys_addr_remap = 0x5fe00000; 810 | 811 | vm_address_t get_kernel_base() 812 | { 813 | kern_return_t ret; 814 | task_t kernel_task; 815 | vm_region_submap_info_data_64_t info; 816 | vm_size_t size; 817 | mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; 818 | unsigned int depth = 0; 819 | vm_address_t addr = 0x81200000; 820 | 821 | ret = task_for_pid(mach_task_self(), 0, &kernel_task); 822 | if (ret != KERN_SUCCESS) 823 | return -1; 824 | 825 | while (1) { 826 | ret = vm_region_recurse_64(kernel_task, &addr, &size, &depth, (vm_region_info_t) & info, &info_count); 827 | if (ret != KERN_SUCCESS) 828 | break; 829 | if (size > 1024 * 1024 * 1024){ 830 | /* 831 | * https://code.google.com/p/iphone-dataprotection/ 832 | * hax, sometimes on iOS7 kernel starts at +0x200000 in the 1Gb region 833 | */ 834 | pointer_t buf; 835 | mach_msg_type_number_t sz = 0; 836 | addr += 0x200000; 837 | vm_read(kernel_task, addr + 0x1000, 512, &buf, &sz); 838 | if (*((uint32_t *)buf) != 0xfeedface) { 839 | addr -= 0x200000; 840 | vm_read(kernel_task, addr + 0x1000, 512, &buf, &sz); 841 | if (*((uint32_t*)buf) != 0xfeedface) { 842 | break; 843 | } 844 | } 845 | return addr; 846 | } 847 | addr += size; 848 | } 849 | 850 | return -1; 851 | } 852 | 853 | static void generate_ttb_entries(void) 854 | { 855 | uint32_t vaddr, vaddr_end, paddr, i; 856 | 857 | paddr = PHYS_OFF; 858 | vaddr = SHADOWMAP_BEGIN; 859 | vaddr_end = SHADOWMAP_END; 860 | 861 | for (i = vaddr; i <= vaddr_end; i += SHADOWMAP_GRANULARITY, paddr += SHADOWMAP_GRANULARITY) { 862 | #if SPURIOUS_DEBUG_OUTPUT 863 | printf("ProtoTTE: 0x%08x for VA 0x%08x -> PA 0x%08x\n", L1_PROTO_TTE(paddr), i, paddr); 864 | #endif 865 | ttb_template[TTB_OFFSET(i) >> PFN_SHIFT] = L1_PROTO_TTE(paddr); 866 | } 867 | 868 | /* 869 | * Remap TTE for iBoot load address. 870 | */ 871 | uint32_t ttb_remap_addr_base = 0x7fe00000; 872 | ttb_template[TTB_OFFSET(ttb_remap_addr_base) >> PFN_SHIFT] = L1_PROTO_TTE(phys_addr_remap); 873 | ttb_template[TTB_OFFSET(ttb_remap_addr_base - 1048576) >> PFN_SHIFT] = L1_PROTO_TTE(phys_addr_remap - (1048576)); 874 | 875 | #if SPURIOUS_DEBUG_OUTPUT 876 | printf("remap -> 0x%08x => 0x%08x (TTE: 0x%08x)\n", ttb_remap_addr_base, phys_addr_remap, L1_PROTO_TTE(phys_addr_remap)); 877 | 878 | printf("TTE offset begin for shadowmap: 0x%08x\n" "TTE offset end for shadowmap: 0x%08x\n" "TTE size: 0x%08x\n", SHADOWMAP_BEGIN_OFF, SHADOWMAP_END_OFF, SHADOWMAP_SIZE); 879 | #endif 880 | 881 | printf("New TTEs generated, base address for remap: 0x%08x, physBase: 0x%08x\n", PHYS_OFF, phys_addr_remap); 882 | printf("[multi_kloader] 0x%08x => 0x%08x\n", ttb_remap_addr_base - 1048576, phys_addr_remap - (1048576)); 883 | return; 884 | } 885 | 886 | #define DMPSIZE 0xc00000 887 | extern char *shellcode_begin, shellcode_end; 888 | extern uint32_t larm_init_tramp; 889 | extern uint32_t flush_dcache, invalidate_icache; 890 | extern uint32_t kern_base, kern_tramp_phys; 891 | 892 | int main(int argc, char *argv[]) 893 | { 894 | uint32_t chunksize = 2048; 895 | struct stat st; 896 | 897 | if (argc != 3) { 898 | printf("usage: %s [loadfile] [loadfile2]\n" 899 | "This will destroy the current running OS instance and fire up the loaded image.\n" 900 | "You have been warned.\n", argv[0]); 901 | return -1; 902 | } 903 | 904 | if (stat(argv[1], &st) == -1) { 905 | printf("Failed to open %s.\n", argv[1]); 906 | return -1; 907 | } 908 | 909 | if (stat(argv[2], &st) == -1) { 910 | printf("Failed to open %s.\n", argv[2]); 911 | return -1; 912 | } 913 | 914 | /* 915 | * Get physbase. 916 | */ 917 | size_t size; 918 | sysctlbyname("kern.version", NULL, &size, NULL, 0); 919 | char *osversion = malloc(size); 920 | if (sysctlbyname("kern.version", osversion, &size, NULL, 0) == -1) { 921 | printf("fail to kern.version sysctl\n"); 922 | exit(-1); 923 | } 924 | #if SPURIOUS_DEBUG_OUTPUT 925 | printf("%s\n", osversion); 926 | #endif 927 | 928 | if (strcasestr(osversion, "s5l8930x")) { 929 | PHYS_OFF = S5L8930_PHYS_OFF; 930 | phys_addr_remap = 0x5fe00000; 931 | } else if (strcasestr(osversion, "s5l8920x") || strcasestr(osversion, "s5l8922x")) { 932 | PHYS_OFF = S5L8930_PHYS_OFF; 933 | phys_addr_remap = 0x4fe00000; 934 | } else if (strcasestr(osversion, "s5l8940x") || strcasestr(osversion, "s5l8942x") || strcasestr(osversion, "s5l8947x")) { 935 | /* 936 | * All others have the high ram base. 937 | */ 938 | PHYS_OFF = S5L8940_PHYS_OFF; 939 | phys_addr_remap = 0x9fe00000; 940 | } else if (strcasestr(osversion, "s5l8945x")) { 941 | PHYS_OFF = S5L8940_PHYS_OFF; 942 | phys_addr_remap = 0xbfe00000; 943 | } else if (strcasestr(osversion, "s5l8950x") || strcasestr(osversion, "s5l8955x")) { 944 | PHYS_OFF = S5L8940_PHYS_OFF; 945 | phys_addr_remap = 0xbfe00000; 946 | } else { 947 | printf("Bravely assuming you're on an 8940-class device (unrecognized). You are on your own.\n"); 948 | /* 949 | * All others have the high ram base. 950 | */ 951 | PHYS_OFF = S5L8940_PHYS_OFF; 952 | phys_addr_remap = 0x9fe00000; 953 | } 954 | 955 | /* 956 | * Pedanticness, though doesn't matter, after we quit the entire OS is gone lol 957 | */ 958 | free(osversion); 959 | 960 | #if SPURIOUS_DEBUG_OUTPUT 961 | printf("physOff 0x%08x remap 0x%08x\n", PHYS_OFF, phys_addr_remap); 962 | #endif 963 | 964 | 965 | /* 966 | * get kernel base. 967 | */ 968 | kernel_base = get_kernel_base(); 969 | if (kernel_base == -1) { 970 | printf("failed to get kernel_baseel base...\n"); 971 | return -1; 972 | } 973 | 974 | printf("Kernel base is 0x%08x.\n", kernel_base); 975 | 976 | /* 977 | * we can now find the kernel pmap. 978 | */ 979 | kern_return_t r = task_for_pid(mach_task_self(), 0, &kernel_task); 980 | if (r != 0) { 981 | printf("task_for_pid failed.\n"); 982 | return -1; 983 | } 984 | 985 | /* 986 | * kill 987 | */ 988 | vm_address_t addr = kernel_base + 0x1000, e = 0, sz = 0; 989 | uint8_t *p = malloc(DMPSIZE + 0x1000); 990 | pointer_t buf; 991 | 992 | if (!p) { 993 | printf("failed to malloc memory for kernel dump...\n"); 994 | return -1; 995 | } 996 | while (addr < (kernel_base + DMPSIZE)) { 997 | vm_read(kernel_task, addr, chunksize, &buf, &sz); 998 | if (!buf || sz == 0) 999 | continue; 1000 | uint8_t *z = (uint8_t *) buf; 1001 | addr += chunksize; 1002 | bcopy(z, p + e, chunksize); 1003 | e += chunksize; 1004 | } 1005 | 1006 | /* 1007 | * kernel dumped, now find pmap. 1008 | */ 1009 | uint32_t kernel_pmap = kernel_base + 0x1000 + find_pmap_location(kernel_base, (uint8_t *) p, DMPSIZE); 1010 | printf("kernel pmap is at 0x%08x.\n", kernel_pmap); 1011 | 1012 | /* 1013 | * Read for kernel_pmap, dereference it for pmap_store. 1014 | */ 1015 | vm_read(kernel_task, kernel_pmap, 2048, &buf, &sz); 1016 | vm_read(kernel_task, *(vm_address_t *) (buf), 2048, &buf, &sz); 1017 | 1018 | /* 1019 | * We now have the struct. Let's copy it out to get the TTE base (we don't really need to do this 1020 | * as it should just remain constant. TTEs should be after ToKD.) 1021 | */ 1022 | pmap_partial_t *part = (pmap_partial_t *) buf; 1023 | uint32_t tte_virt = part->tte_virt; 1024 | uint32_t tte_phys = part->tte_phys; 1025 | 1026 | printf("kernel pmap details: tte_virt: 0x%08x tte_phys: 0x%08x\n", tte_virt, tte_phys); 1027 | if (PHYS_OFF != (tte_phys & ~0xFFFFFFF)) { 1028 | printf("physOff 0x%08x should be 0x%08x\n", PHYS_OFF, tte_phys & ~0xFFFFFFF); 1029 | return -1; 1030 | } 1031 | 1032 | /* 1033 | * generate TTEs. 1034 | */ 1035 | generate_ttb_entries(); 1036 | /* 1037 | * Now, we can start reading at the TTE base and start writing in the descriptors. 1038 | */ 1039 | uint32_t tte_off = SHADOWMAP_BEGIN_OFF; 1040 | vm_read(kernel_task, tte_virt + tte_off, 2048, &buf, &sz); 1041 | bcopy((char *) ttb_template_ptr + tte_off, (void *) buf, SHADOWMAP_SIZE); 1042 | vm_write(kernel_task, tte_virt + tte_off, buf, sz); 1043 | 1044 | printf("======================================================================================\n"); 1045 | printf("!!!! Kernel TTE entries written. System stability is no longer guaranteed.\n"); 1046 | printf("!!!! Security has also been reduced by an exponential factor. You have been warned.\n"); 1047 | printf("======================================================================================\n"); 1048 | 1049 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1050 | signal(SIGINT, SIG_IGN); 1051 | 1052 | /* 1053 | * remap_address = 0x7ff00000 1054 | */ 1055 | FILE *f = fopen(argv[1], "rb"); 1056 | if (!f) { 1057 | printf("Failed to open iBSS. Rebooting momentarily...\n"); 1058 | sleep(3); 1059 | reboot(0); 1060 | } 1061 | 1062 | fseek(f, 0, SEEK_END); 1063 | int length = ftell(f); 1064 | fseek(f, 0, SEEK_SET); 1065 | void *vp = malloc(length); 1066 | fread(vp, length, 1, f); 1067 | fclose(f); 1068 | printf("Read bootloader into buffer %p, length %d\n", vp, length); 1069 | 1070 | bcopy((void *) vp, (void *) 0x7fe00000, length); 1071 | 1072 | /* 1073 | * Verify ARM header. 1074 | */ 1075 | if (*(uint32_t *) 0x7fe00000 != 0xea00000e) { 1076 | printf("This doesn't seem like an ARM image, perhaps it failed to copy? Continuing though.\n"); 1077 | } 1078 | 1079 | printf("Image information: %s\n", (char *) 0x7fe00000 + 0x200); 1080 | printf("Image information: %s\n", (char *) 0x7fe00000 + 0x240); 1081 | printf("Image information: %s\n", (char *) 0x7fe00000 + 0x280); 1082 | 1083 | free(vp); 1084 | 1085 | /* 1086 | * Second image at 0x7fd00000. 1087 | */ 1088 | f = fopen(argv[2], "rb"); 1089 | if (!f) { 1090 | printf("Failed to open iBEC. Rebooting momentarily...\n"); 1091 | sleep(3); 1092 | reboot(0); 1093 | } 1094 | 1095 | fseek(f, 0, SEEK_END); 1096 | length = ftell(f); 1097 | fseek(f, 0, SEEK_SET); 1098 | vp = malloc(length); 1099 | fread(vp, length, 1, f); 1100 | fclose(f); 1101 | printf("Read bootloader into buffer %p, length %d\n", vp, length); 1102 | 1103 | bcopy((void *) vp, (void *) 0x7fd00000, length); 1104 | 1105 | /* 1106 | * Verify ARM header. 1107 | */ 1108 | if (*(uint32_t *) 0x7fd00000 != 0xea00000e) { 1109 | printf("This doesn't seem like an ARM image, perhaps it failed to copy? Continuing though.\n"); 1110 | } 1111 | 1112 | printf("Image information: %s\n", (char *) 0x7fd00000 + 0x200); 1113 | printf("Image information: %s\n", (char *) 0x7fd00000 + 0x240); 1114 | printf("Image information: %s\n", (char *) 0x7fd00000 + 0x280); 1115 | 1116 | free(vp); 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | /* 1123 | * iBEC copied, we need to copy over the shellcode now. 1124 | */ 1125 | uint32_t sysent_common = 0x1000 + find_syscall0(kernel_base + 0x1000, (uint8_t *) p, DMPSIZE) + SHADOWMAP_BEGIN; 1126 | printf("sysent_common_base: 0x%08x\n", sysent_common); 1127 | 1128 | /* 1129 | * fuck evasi0n7 1130 | */ 1131 | if (*(uint32_t *) (sysent_common) == 0) { 1132 | printf("iOS 7 detected, adjusting base to 0x%08x = 0x%08x\n", sysent_common, *(uint32_t *) (sysent_common)); 1133 | sysent_common += 4; 1134 | if (*(uint32_t *) (sysent_common) == 0) { 1135 | printf("Something is severely wrong (blaming iOS 7 anyhow). Rebooting momentarily.\n"); 1136 | sleep(3); 1137 | reboot(0); 1138 | } 1139 | } 1140 | 1141 | /* 1142 | * Set offsets. 1143 | */ 1144 | larm_init_tramp = 0x1000 + find_larm_init_tramp(kernel_base + 0x1000, (uint8_t *) p, DMPSIZE) + SHADOWMAP_BEGIN; 1145 | 1146 | kern_base = kernel_base; 1147 | kern_tramp_phys = phys_addr_remap; 1148 | 1149 | #if 0 1150 | 1151 | printf("larm_init_tramp is at 0x%08x\n", larm_init_tramp); 1152 | bcopy((void *) &shellcode_begin, (void *) 0x7f000c00, (uint32_t) ((uintptr_t) & shellcode_end - (uintptr_t) & shellcode_begin)); 1153 | *(uint32_t *) sysent_common = 0x7f000c01; 1154 | 1155 | printf("Running shellcode now.\n"); 1156 | syscall(0); 1157 | 1158 | printf("Syncing disks.\n"); 1159 | int diskSync; 1160 | for (diskSync = 0; diskSync < 10; diskSync++) 1161 | sync(); 1162 | sleep(1); 1163 | 1164 | #else 1165 | static uint32_t arm[2] = { 0xe51ff004, 0 }; 1166 | arm[1] = phys_addr_remap; 1167 | // Requires D-cache writeback. 1168 | printf("Tramp %x COMMMAP\n", larm_init_tramp); 1169 | printf("%lx, %lx\n", *(uintptr_t *) (larm_init_tramp), *(uintptr_t *) (larm_init_tramp + 4)); 1170 | printf("%x\n", *(uint32_t *) (0x7f000000 + 0x1000)); 1171 | bcopy((void *) arm, (void *) larm_init_tramp, sizeof(arm)); 1172 | printf("%lx, %lx\n", *(uintptr_t *) (larm_init_tramp), *(uintptr_t *) (larm_init_tramp + 4)); 1173 | printf("%x\n", *(uint32_t *) (0x7f000000 + 0x1000)); 1174 | 1175 | #endif 1176 | 1177 | printf("Syncing disks.\n"); 1178 | int diskSync; 1179 | for (diskSync = 0; diskSync < 10; diskSync++) 1180 | sync(); 1181 | sleep(1); 1182 | 1183 | 1184 | while (1) { 1185 | printf("Magic happening now. (attempted!)\n"); 1186 | mach_port_t fb = IOPMFindPowerManagement(MACH_PORT_NULL); 1187 | if (fb != MACH_PORT_NULL) { 1188 | kern_return_t kr = IOPMSleepSystem(fb); 1189 | if (kr) { 1190 | err(1, "IOPMSleepSystem returned %x\n", kr); 1191 | } 1192 | } else { 1193 | err(1, "failed to get PM root port\n"); 1194 | } 1195 | sleep(3); 1196 | } 1197 | 1198 | return 0; 1199 | } 1200 | 1201 | /* how evil can you get???? */ 1202 | #if INLINE_IT_ALL 1203 | /* hey, you gotta compile with -no-integrated-as */ 1204 | #ifdef __arm__ 1205 | __asm__("\n" 1206 | " .code 16\n" 1207 | " .thumb_func\n" 1208 | " .align 2\n" 1209 | " .data\n" 1210 | " .globl _shellcode_begin\n" 1211 | " .globl _shellcode_end\n" 1212 | " .globl _larm_init_tramp\n" 1213 | " .globl _flush_dcache\n" 1214 | " .globl _invalidate_icache\n" 1215 | " .globl _kern_tramp_phys\n" 1216 | " .globl _kern_base\n" 1217 | "_shellcode_begin:\n" 1218 | " mrs r12, cpsr\n" 1219 | " cpsid if\n" 1220 | " ldr r0, 0f\n" 1221 | " ldr r1, _kern_tramp_phys\n" 1222 | " ldr r2, _larm_init_tramp\n" 1223 | " str r0, [r2]\n" 1224 | " str r1, [r2, #4]\n" 1225 | " ldr r0, _kern_base\n" 1226 | " @ Clear cache to PoC\n" 1227 | " ldr r2, _larm_init_tramp\n" 1228 | " bic r2, r2, #((1 << 6) - 1)\n" 1229 | " mcr p15, 0, r2, c7, c14, 1\n" 1230 | " mov r1, #256\n" 1231 | ".Lloop:\n" 1232 | " add r2, r2, #(1 << 6)\n" 1233 | " mcr p15, 0, r2, c7, c14, 1\n" 1234 | " subs r1, r1, #1\n" 1235 | " bne .Lloop\n" 1236 | " msr cpsr_c, r12\n" 1237 | " movs r0, #0\n" 1238 | " bx lr\n" 1239 | " .align 2\n" 1240 | "0: .long 0xe51ff004\n" 1241 | "_kern_tramp_phys: .long 0x9bf00000\n" 1242 | "_kern_base: .long 0xdeadbeef\n" 1243 | "_larm_init_tramp: .long 0xdeadbeef\n" 1244 | "_flush_dcache: .long 0xdeadbeef\n" 1245 | "_invalidate_icache: .long 0xdeadbeef\n" 1246 | "_shellcode_end:\n" 1247 | " nop\n"); 1248 | #else 1249 | #error - this is only for ARM.. 1250 | #endif 1251 | #endif 1252 | -------------------------------------------------------------------------------- /patch.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013, winocm 3 | * All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | * 19 | * $Id$ 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include "structs.h" 33 | #include "patch.h" 34 | #include "util.h" 35 | 36 | static boolean_t patch_list_initialized = FALSE; 37 | 38 | static struct patch_list_root patch_list_store; 39 | static struct patch_list *patch_list_head; 40 | static struct patch_list *patch_list_current_node; 41 | 42 | static struct patch_list *patch_list_object_allocate (void); 43 | static void patch_list_add_object (struct patch_list *); 44 | 45 | static inline char * 46 | patch_list_dump_hex (uint8_t * p, int size) 47 | { 48 | int i = 0, fixed_up = size * 2 + 1; 49 | char *buffer = _xmalloc (fixed_up); 50 | for (i = 0; i < size; i++) { 51 | snprintf (buffer, fixed_up, "%s%02X", buffer, p[i]); 52 | } 53 | buffer[fixed_up - 1] = '\0'; 54 | return buffer; 55 | } 56 | 57 | static struct patch_list * 58 | patch_list_object_allocate (void) 59 | { 60 | return (struct patch_list *) _xmalloc (sizeof (struct patch_list)); 61 | } 62 | 63 | static void 64 | patch_list_add_object (struct patch_list *object) 65 | { 66 | patch_list_current_node->next = object; 67 | patch_list_current_node = object; 68 | if (patch_list_store.total == 0) 69 | patch_list_head = patch_list_current_node; 70 | patch_list_store.total++; 71 | return; 72 | } 73 | 74 | void 75 | patch_list_iterate (void) 76 | { 77 | int i; 78 | struct patch_list *iter = patch_list_head; 79 | printf ("Total patches: %d\n", patch_list_store.total); 80 | for (iter = patch_list_head, i = 0; i < patch_list_store.total; iter = iter->next, i++) { 81 | printf ("Patch at %p\nName: %s\nSearch for: %s\nReplace with: %s\nSize: %d\n", 82 | iter, iter->patch.name, patch_list_dump_hex (iter->patch.original, iter->patch.size), 83 | patch_list_dump_hex (iter->patch.patched, iter->patch.size), iter->patch.size); 84 | } 85 | } 86 | 87 | int 88 | patch_list_get_head(struct patch_list** object_export, int* size) 89 | { 90 | if (!patch_list_initialized) 91 | return -EPERM; 92 | 93 | *object_export = patch_list_head; 94 | *size = patch_list_store.total; 95 | 96 | return 0; 97 | } 98 | 99 | int 100 | patch_list_initialize (void) 101 | { 102 | bzero (&patch_list_store, sizeof (struct patch_list_root)); 103 | patch_list_head = (struct patch_list *) &patch_list_store; 104 | patch_list_current_node = patch_list_head; 105 | patch_list_initialized = TRUE; 106 | return 0; 107 | } 108 | 109 | int 110 | patch_list_add_patch (const char *name, uint8_t * original, uint8_t * patched, int size) 111 | { 112 | struct patch_list *object; 113 | 114 | if (!patch_list_initialized) 115 | return -EACCES; 116 | 117 | object = patch_list_object_allocate (); 118 | 119 | /* 120 | * We don't verify the size of the objects being patched, you should do 121 | * that. 122 | */ 123 | object->patch.original = original; 124 | object->patch.patched = patched; 125 | object->patch.name = strdup (name); 126 | object->patch.size = size; 127 | object->next = object; 128 | 129 | patch_list_add_object (object); 130 | 131 | return 0; 132 | } -------------------------------------------------------------------------------- /patch.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013, winocm 3 | * All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | * 19 | * $Id$ 20 | */ 21 | 22 | #ifndef __PATCH_H 23 | #define __PATCH_H 24 | 25 | int patch_list_add_patch (const char*, uint8_t*, uint8_t*, int); 26 | int patch_list_initialize (void); 27 | void patch_list_iterate (void); 28 | int patch_list_get_head(struct patch_list**, int*); 29 | 30 | #endif /* __PATCH_H */ -------------------------------------------------------------------------------- /structs.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013, winocm 3 | * All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | * 19 | * $Id$ 20 | */ 21 | 22 | #ifndef __STRUCTS_H 23 | #define __STRUCTS_H 24 | 25 | typedef enum 26 | { 27 | DEVICE_BOOT_STAGE_SECUREROM = 0, 28 | DEVICE_BOOT_STAGE_DFU_EMULATION, 29 | DEVICE_BOOT_STAGE_IBOOT, 30 | DEVICE_BOOT_STAGE_DEVICE_OS 31 | } device_boot_stage; 32 | 33 | typedef enum 34 | { 35 | CHIP_FAMILY_TYPE_DEVELOPMENT = 1, /* 0b01 */ 36 | CHIP_FAMILY_TYPE_PRODUCTION = 3 /* 0b11 */ 37 | } chip_family; 38 | 39 | typedef enum 40 | { 41 | FALSE, 42 | TRUE 43 | } boolean_t; 44 | 45 | struct device_information 46 | { 47 | uint16_t chip_id; 48 | uint32_t chip_epoch; 49 | chip_family chip_family; 50 | uint32_t board_id; 51 | device_boot_stage boot_stage; 52 | void *device_usb_context; /* Abstracted. */ 53 | }; 54 | 55 | struct iboot_interval { 56 | int low_bound, high_bound; 57 | int os_version; 58 | }; 59 | 60 | struct kernel_interval { 61 | int low_bound, high_bound; 62 | float os_version; 63 | }; 64 | 65 | struct generic_patch 66 | { 67 | uint8_t *original; 68 | uint8_t *patched; 69 | int size; 70 | char* name; 71 | }; 72 | 73 | struct patch_list 74 | { 75 | struct patch_list *next; 76 | struct generic_patch patch; 77 | }; 78 | 79 | struct patch_list_root 80 | { 81 | struct patch_list *next; 82 | struct generic_patch patch; 83 | int total; 84 | char* name; 85 | }; 86 | 87 | struct mapped_image { 88 | uint8_t* image; 89 | int size; 90 | }; 91 | 92 | extern struct device_information device_information_context; 93 | 94 | #define CHIP_ID_S5L8900X 0x8900 95 | #define CHIP_ID_S5L8920X 0x8920 96 | #define CHIP_ID_S5L8922X 0x8922 97 | #define CHIP_ID_S5L8930X 0x8930 98 | #define CHIP_ID_S5L8940X 0x8940 99 | #define CHIP_ID_S5L8945X 0x8945 100 | #define CHIP_ID_S5L8950X 0x8950 101 | #define CHIP_ID_S5L8955X 0x8955 102 | #define CHIP_ID_S5L8960X 0x8960 103 | #define CHIP_ID_S5L8720X 0x8720 104 | #define CHIP_ID_S5L8747X 0x8747 105 | #define CHIP_ID_MASK 0xFF00 106 | 107 | #define IS_IDEVICE_8900(chip_id) (((chip_id & CHIP_ID_MASK) == 0x8900)) 108 | #define IS_IDEVICE_8700(chip_id) (((chip_id & CHIP_ID_MASK) == 0x8700)) 109 | 110 | #endif /* __STRUCTS_H */ 111 | -------------------------------------------------------------------------------- /tfp0.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | get-task-allow 6 | 7 | run-unsigned-code 8 | 9 | task_for_pid-allow 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013, winocm 3 | * All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | * 19 | * $Id$ 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "util.h" 32 | 33 | void * 34 | _xmalloc (size_t size) 35 | { 36 | void *p = malloc (size); 37 | if (!p) 38 | err (-1, "cannot allocate chunk"); 39 | bzero (p, size); 40 | return p; 41 | } -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013, winocm 3 | * All rights reserved. 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | * 19 | * $Id$ 20 | */ 21 | 22 | #ifndef __UTIL_H 23 | #define __UTIL_H 24 | 25 | /* Borrowed from Microsoft. */ 26 | #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1] 27 | 28 | void * _xmalloc (size_t); 29 | 30 | #endif /* __UTIL_H */ --------------------------------------------------------------------------------