├── LICENSE ├── Makefile ├── maphys.c └── tfp0.plist /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | all: 3 | xcrun -sdk iphoneos clang -arch arm64 -mios-version-min=10.0 -Weverything maphys.c -o maphys -framework IOKit -framework CoreFoundation -lcompression -O2 4 | 5 | clean: 6 | $(RM) maphys 7 | -------------------------------------------------------------------------------- /maphys.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2020 0x7ff 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define LZSS_F (18) 25 | #define LZSS_N (4096) 26 | #define LZSS_THRESHOLD (2) 27 | #define IPC_ENTRY_SZ (0x18) 28 | #define PMAP_MIN_OFF (0x10) 29 | #define PMAP_MAX_OFF (0x18) 30 | #define VM_MAP_PMAP_OFF (0x48) 31 | #define KCOMP_HDR_PAD_SZ (0x16C) 32 | #define USER_CLIENT_TRAP_OFF (0x40) 33 | #define IPC_SPACE_IS_TABLE_OFF (0x20) 34 | #define IPC_ENTRY_IE_OBJECT_OFF (0x0) 35 | #define PROC_P_LIST_LE_PREV_OFF (0x8) 36 | #define IPC_PORT_IP_KOBJECT_OFF (0x68) 37 | #define PROC_P_LIST_LH_FIRST_OFF (0x0) 38 | #define IPC_SPACE_IS_TABLE_SZ_OFF (0x14) 39 | #define kCFCoreFoundationVersionNumber_iOS_10_0_b5 (1348) 40 | #define kCFCoreFoundationVersionNumber_iOS_13_0_b2 (1656) 41 | #define kCFCoreFoundationVersionNumber_iOS_11_0_b1 (1429.15) 42 | #define kCFCoreFoundationVersionNumber_iOS_12_0_b1 (1535.13) 43 | #define kCFCoreFoundationVersionNumber_iOS_13_0_b1 (1652.20) 44 | #define BOOT_PATH "/System/Library/Caches/com.apple.kernelcaches/kernelcache" 45 | 46 | #define DER_INT (0x2U) 47 | #define DER_SEQ (0x30U) 48 | #define DER_IA5_STR (0x16U) 49 | #define DER_OCTET_STR (0x4U) 50 | #define KADDR_FMT "0x%" PRIX64 51 | #define VM_KERN_MEMORY_CPU (9) 52 | #define RD(a) extract32(a, 0, 5) 53 | #define RN(a) extract32(a, 5, 5) 54 | #define BCOPY_PHYS_DST_PHYS (1U) 55 | #define BCOPY_PHYS_SRC_PHYS (2U) 56 | #define KCOMP_HDR_MAGIC (0x636F6D70U) 57 | #define IS_NOP(a) ((a) == 0xD503201FU) 58 | #define IS_RET(a) ((a) == 0xD65F03C0U) 59 | #define ADRP_ADDR(a) ((a) & ~0xFFFULL) 60 | #define ADRP_IMM(a) (ADR_IMM(a) << 12U) 61 | #define IO_OBJECT_NULL ((io_object_t)0) 62 | #define MAX_VTAB_SZ (vm_kernel_page_size) 63 | #define ADD_X_IMM(a) extract32(a, 10, 12) 64 | #define KCOMP_HDR_TYPE_LZSS (0x6C7A7373U) 65 | #define FAULT_MAGIC (0xAAAAAAAAAAAAAAAAULL) 66 | #define MOV_W_ZHW_IMM(a) extract32(a, 5, 16) 67 | #define BL_IMM(a) (sextract64(a, 0, 26) << 2U) 68 | #define LDR_X_IMM(a) (sextract64(a, 5, 19) << 2U) 69 | #define IS_BL(a) (((a) & 0xFC000000U) == 0x94000000U) 70 | #define IS_ADR(a) (((a) & 0x9F000000U) == 0x10000000U) 71 | #define IS_ADRP(a) (((a) & 0x9F000000U) == 0x90000000U) 72 | #define IS_ADD_X(a) (((a) & 0xFFC00000U) == 0x91000000U) 73 | #define IS_LDR_X(a) (((a) & 0xFF000000U) == 0x58000000U) 74 | #define IS_MOV_X(a) (((a) & 0xFFE00000U) == 0xAA000000U) 75 | #define LDR_W_UNSIGNED_IMM(a) (extract32(a, 10, 12) << 2U) 76 | #define LDR_X_UNSIGNED_IMM(a) (extract32(a, 10, 12) << 3U) 77 | #define IS_MOV_W_ZHW(a) (((a) & 0xFFE00000U) == 0x52800000U) 78 | #define IS_LDR_W_UNSIGNED_IMM(a) (((a) & 0xFFC00000U) == 0xB9400000U) 79 | #define IS_LDR_X_UNSIGNED_IMM(a) (((a) & 0xFFC00000U) == 0xF9400000U) 80 | #define ADR_IMM(a) ((sextract64(a, 5, 19) << 2U) | extract32(a, 29, 2)) 81 | 82 | #ifndef SECT_CSTRING 83 | # define SECT_CSTRING "__cstring" 84 | #endif 85 | 86 | #ifndef SEG_TEXT_EXEC 87 | # define SEG_TEXT_EXEC "__TEXT_EXEC" 88 | #endif 89 | 90 | #ifndef MIN 91 | # define MIN(a, b) ((a) < (b) ? (a) : (b)) 92 | #endif 93 | 94 | typedef uint64_t kaddr_t; 95 | typedef mach_port_t io_object_t; 96 | typedef uint32_t ipc_entry_num_t; 97 | typedef io_object_t io_service_t, io_connect_t; 98 | 99 | typedef struct { 100 | struct section_64 s64; 101 | const char *data; 102 | } sec_64_t; 103 | 104 | typedef struct { 105 | struct symtab_command cmd_symtab; 106 | sec_64_t sec_text, sec_cstring; 107 | kaddr_t base, kslide; 108 | const char *kernel; 109 | size_t kernel_sz; 110 | char *data; 111 | } pfinder_t; 112 | 113 | typedef struct { 114 | kaddr_t obj, func, delta; 115 | } io_external_trap_t; 116 | 117 | kern_return_t 118 | IOServiceClose(io_connect_t); 119 | 120 | kern_return_t 121 | IOObjectRelease(io_object_t); 122 | 123 | CFMutableDictionaryRef 124 | IOServiceMatching(const char *); 125 | 126 | io_service_t 127 | IOServiceGetMatchingService(mach_port_t, CFDictionaryRef); 128 | 129 | kern_return_t 130 | mach_vm_deallocate(vm_map_t, mach_vm_address_t, mach_vm_size_t); 131 | 132 | kern_return_t 133 | IOServiceOpen(io_service_t, task_port_t, uint32_t, io_connect_t *); 134 | 135 | kern_return_t 136 | mach_vm_allocate(vm_map_t, mach_vm_address_t *, mach_vm_size_t, int); 137 | 138 | kern_return_t 139 | mach_vm_copy(vm_map_t, mach_vm_address_t, mach_vm_size_t, mach_vm_address_t); 140 | 141 | kern_return_t 142 | mach_vm_write(vm_map_t, mach_vm_address_t, vm_offset_t, mach_msg_type_number_t); 143 | 144 | kern_return_t 145 | IOConnectTrap6(io_connect_t, uint32_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); 146 | 147 | kern_return_t 148 | mach_vm_read_overwrite(vm_map_t, mach_vm_address_t, mach_vm_size_t, mach_vm_address_t, mach_vm_size_t *); 149 | 150 | kern_return_t 151 | mach_vm_machine_attribute(vm_map_t, mach_vm_address_t, mach_vm_size_t, vm_machine_attribute_t, vm_machine_attribute_val_t *); 152 | 153 | kern_return_t 154 | mach_vm_region(vm_map_t, mach_vm_address_t *, mach_vm_size_t *, vm_region_flavor_t, vm_region_info_t, mach_msg_type_number_t *, mach_port_t *); 155 | 156 | extern const mach_port_t kIOMasterPortDefault; 157 | 158 | static task_t tfp0 = MACH_PORT_NULL; 159 | static io_connect_t g_conn = IO_OBJECT_NULL; 160 | static size_t task_map_off, proc_task_off, proc_p_pid_off, task_itk_space_off, cpu_data_rtclock_datap_off, vtab_get_ext_trap_for_idx_off; 161 | static kaddr_t kernproc, csblob_get_cdhash, pmap_find_phys, bcopy_phys, our_task, orig_vtab, fake_vtab, user_client, kernel_pmap, kernel_pmap_min, kernel_pmap_max; 162 | 163 | static uint32_t 164 | extract32(uint32_t val, unsigned start, unsigned len) { 165 | return (val >> start) & (~0U >> (32U - len)); 166 | } 167 | 168 | static uint64_t 169 | sextract64(uint64_t val, unsigned start, unsigned len) { 170 | return (uint64_t)((int64_t)(val << (64U - len - start)) >> (64U - len)); 171 | } 172 | 173 | static size_t 174 | decompress_lzss(const uint8_t *src, size_t src_len, uint8_t *dst, size_t dst_len) { 175 | const uint8_t *src_end = src + src_len, *dst_start = dst, *dst_end = dst + dst_len; 176 | uint16_t i, r = LZSS_N - LZSS_F, flags = 0; 177 | uint8_t text_buf[LZSS_N + LZSS_F - 1], j; 178 | 179 | memset(text_buf, ' ', r); 180 | while(src != src_end && dst != dst_end) { 181 | if(((flags >>= 1U) & 0x100U) == 0) { 182 | flags = *src++ | 0xFF00U; 183 | if(src == src_end) { 184 | break; 185 | } 186 | } 187 | if((flags & 1U) != 0) { 188 | text_buf[r++] = *dst++ = *src++; 189 | r &= LZSS_N - 1U; 190 | } else { 191 | i = *src++; 192 | if(src == src_end) { 193 | break; 194 | } 195 | j = *src++; 196 | i |= (j & 0xF0U) << 4U; 197 | j = (j & 0xFU) + LZSS_THRESHOLD; 198 | do { 199 | *dst++ = text_buf[r++] = text_buf[i++ & (LZSS_N - 1U)]; 200 | r &= LZSS_N - 1U; 201 | } while(j-- != 0 && dst != dst_end); 202 | } 203 | } 204 | return (size_t)(dst - dst_start); 205 | } 206 | 207 | static const uint8_t * 208 | der_decode(uint8_t tag, const uint8_t *der, const uint8_t *der_end, size_t *out_len) { 209 | size_t der_len; 210 | 211 | if(der_end - der > 2 && tag == *der++) { 212 | if(((der_len = *der++) & 0x80U) != 0) { 213 | *out_len = 0; 214 | if((der_len &= 0x7FU) <= sizeof(*out_len) && (size_t)(der_end - der) >= der_len) { 215 | while(der_len-- != 0) { 216 | *out_len = (*out_len << 8U) | *der++; 217 | } 218 | } 219 | } else { 220 | *out_len = der_len; 221 | } 222 | if(*out_len != 0 && (size_t)(der_end - der) >= *out_len) { 223 | return der; 224 | } 225 | } 226 | return NULL; 227 | } 228 | 229 | static const uint8_t * 230 | der_decode_seq(const uint8_t *der, const uint8_t *der_end, const uint8_t **seq_end) { 231 | size_t der_len; 232 | 233 | if((der = der_decode(DER_SEQ, der, der_end, &der_len)) != NULL) { 234 | *seq_end = der + der_len; 235 | } 236 | return der; 237 | } 238 | 239 | static const uint8_t * 240 | der_decode_uint64(const uint8_t *der, const uint8_t *der_end, uint64_t *r) { 241 | size_t der_len; 242 | 243 | if((der = der_decode(DER_INT, der, der_end, &der_len)) != NULL && (*der & 0x80U) == 0 && (der_len <= sizeof(*r) || (--der_len == sizeof(*r) && *der++ == 0))) { 244 | *r = 0; 245 | while(der_len-- != 0) { 246 | *r = (*r << 8U) | *der++; 247 | } 248 | return der; 249 | } 250 | return NULL; 251 | } 252 | 253 | static void * 254 | kdecompress(const void *src, size_t src_len, size_t *dst_len) { 255 | const uint8_t *der, *octet, *der_end, *src_end = (const uint8_t *)src + src_len; 256 | struct { 257 | uint32_t magic, type, adler32, uncomp_sz, comp_sz; 258 | uint8_t pad[KCOMP_HDR_PAD_SZ]; 259 | } kcomp_hdr; 260 | size_t der_len; 261 | uint64_t r; 262 | void *dst; 263 | 264 | if((der = der_decode_seq(src, src_end, &der_end)) != NULL && (der = der_decode(DER_IA5_STR, der, der_end, &der_len)) != NULL && der_len == 4 && (memcmp(der, "IMG4", der_len) != 0 || ((der = der_decode_seq(der + der_len, src_end, &der_end)) != NULL && (der = der_decode(DER_IA5_STR, der, der_end, &der_len)) != NULL && der_len == 4)) && memcmp(der, "IM4P", der_len) == 0 && (der = der_decode(DER_IA5_STR, der + der_len, der_end, &der_len)) != NULL && der_len == 4 && memcmp(der, "krnl", der_len) == 0 && (der = der_decode(DER_IA5_STR, der + der_len, der_end, &der_len)) != NULL && (der = der_decode(DER_OCTET_STR, der + der_len, der_end, &der_len)) != NULL && der_len > sizeof(kcomp_hdr)) { 265 | octet = der; 266 | memcpy(&kcomp_hdr, octet, sizeof(kcomp_hdr)); 267 | if(kcomp_hdr.magic == __builtin_bswap32(KCOMP_HDR_MAGIC)) { 268 | if(kcomp_hdr.type == __builtin_bswap32(KCOMP_HDR_TYPE_LZSS) && (kcomp_hdr.comp_sz = __builtin_bswap32(kcomp_hdr.comp_sz)) <= der_len - sizeof(kcomp_hdr) && (kcomp_hdr.uncomp_sz = __builtin_bswap32(kcomp_hdr.uncomp_sz)) != 0 && (dst = malloc(kcomp_hdr.uncomp_sz)) != NULL) { 269 | if(decompress_lzss(octet + sizeof(kcomp_hdr), kcomp_hdr.comp_sz, dst, kcomp_hdr.uncomp_sz) == kcomp_hdr.uncomp_sz) { 270 | *dst_len = kcomp_hdr.uncomp_sz; 271 | return dst; 272 | } 273 | free(dst); 274 | } 275 | } else if((der = der_decode_seq(der + der_len, src_end, &der_end)) != NULL && (der = der_decode_uint64(der, der_end, &r)) != NULL && r == 1 && der_decode_uint64(der, der_end, &r) != NULL && r != 0 && (dst = malloc(r)) != NULL) { 276 | if(compression_decode_buffer(dst, r, octet, der_len, NULL, COMPRESSION_LZFSE) == r) { 277 | *dst_len = r; 278 | return dst; 279 | } 280 | free(dst); 281 | } 282 | } 283 | return NULL; 284 | } 285 | 286 | static kern_return_t 287 | init_tfp0(void) { 288 | kern_return_t ret = task_for_pid(mach_task_self(), 0, &tfp0); 289 | mach_port_t host; 290 | pid_t pid; 291 | 292 | if(ret != KERN_SUCCESS) { 293 | host = mach_host_self(); 294 | if(MACH_PORT_VALID(host)) { 295 | printf("host: 0x%" PRIX32 "\n", host); 296 | ret = host_get_special_port(host, HOST_LOCAL_NODE, 4, &tfp0); 297 | mach_port_deallocate(mach_task_self(), host); 298 | } 299 | } 300 | if(ret == KERN_SUCCESS && MACH_PORT_VALID(tfp0)) { 301 | if(pid_for_task(tfp0, &pid) == KERN_SUCCESS && pid == 0) { 302 | return ret; 303 | } 304 | mach_port_deallocate(mach_task_self(), tfp0); 305 | } 306 | return KERN_FAILURE; 307 | } 308 | 309 | static kern_return_t 310 | kread_buf(kaddr_t addr, void *buf, mach_vm_size_t sz) { 311 | mach_vm_address_t p = (mach_vm_address_t)buf; 312 | mach_vm_size_t read_sz, out_sz = 0; 313 | 314 | while(sz != 0) { 315 | read_sz = MIN(sz, vm_kernel_page_size - (addr & vm_kernel_page_mask)); 316 | if(mach_vm_read_overwrite(tfp0, addr, read_sz, p, &out_sz) != KERN_SUCCESS || out_sz != read_sz) { 317 | return KERN_FAILURE; 318 | } 319 | p += read_sz; 320 | sz -= read_sz; 321 | addr += read_sz; 322 | } 323 | return KERN_SUCCESS; 324 | } 325 | 326 | static kern_return_t 327 | kread_addr(kaddr_t addr, kaddr_t *val) { 328 | return kread_buf(addr, val, sizeof(*val)); 329 | } 330 | 331 | static kern_return_t 332 | kwrite_buf(kaddr_t addr, const void *buf, mach_msg_type_number_t sz) { 333 | vm_machine_attribute_val_t mattr_val = MATTR_VAL_CACHE_FLUSH; 334 | mach_vm_address_t p = (mach_vm_address_t)buf; 335 | mach_msg_type_number_t write_sz; 336 | 337 | while(sz != 0) { 338 | write_sz = (mach_msg_type_number_t)MIN(sz, vm_kernel_page_size - (addr & vm_kernel_page_mask)); 339 | if(mach_vm_write(tfp0, addr, p, write_sz) != KERN_SUCCESS || mach_vm_machine_attribute(tfp0, addr, write_sz, MATTR_CACHE, &mattr_val) != KERN_SUCCESS) { 340 | return KERN_FAILURE; 341 | } 342 | p += write_sz; 343 | sz -= write_sz; 344 | addr += write_sz; 345 | } 346 | return KERN_SUCCESS; 347 | } 348 | 349 | static kern_return_t 350 | kwrite_addr(kaddr_t addr, kaddr_t val) { 351 | return kwrite_buf(addr, &val, sizeof(val)); 352 | } 353 | 354 | static kern_return_t 355 | kalloc(mach_vm_size_t sz, kaddr_t *addr) { 356 | return mach_vm_allocate(tfp0, addr, sz, VM_FLAGS_ANYWHERE); 357 | } 358 | 359 | static kern_return_t 360 | kfree(kaddr_t addr, mach_vm_size_t sz) { 361 | return mach_vm_deallocate(tfp0, addr, sz); 362 | } 363 | 364 | static kern_return_t 365 | find_section(const char *p, struct segment_command_64 sg64, const char *sect_name, struct section_64 *sp) { 366 | for(; sg64.nsects-- != 0; p += sizeof(*sp)) { 367 | memcpy(sp, p, sizeof(*sp)); 368 | if((sp->flags & SECTION_TYPE) != S_ZEROFILL) { 369 | if(sp->offset < sg64.fileoff || sp->size > sg64.filesize || sp->offset - sg64.fileoff > sg64.filesize - sp->size) { 370 | break; 371 | } 372 | if(sp->size != 0 && strncmp(sp->segname, sg64.segname, sizeof(sp->segname)) == 0 && strncmp(sp->sectname, sect_name, sizeof(sp->sectname)) == 0) { 373 | return KERN_SUCCESS; 374 | } 375 | } 376 | } 377 | return KERN_FAILURE; 378 | } 379 | 380 | static void 381 | sec_reset(sec_64_t *sec) { 382 | memset(&sec->s64, '\0', sizeof(sec->s64)); 383 | sec->data = NULL; 384 | } 385 | 386 | static kern_return_t 387 | sec_read_buf(sec_64_t sec, kaddr_t addr, void *buf, size_t sz) { 388 | size_t off; 389 | 390 | if(addr < sec.s64.addr || sz > sec.s64.size || (off = addr - sec.s64.addr) > sec.s64.size - sz) { 391 | return KERN_FAILURE; 392 | } 393 | memcpy(buf, sec.data + off, sz); 394 | return KERN_SUCCESS; 395 | } 396 | 397 | static void 398 | pfinder_reset(pfinder_t *pfinder) { 399 | pfinder->base = 0; 400 | pfinder->kslide = 0; 401 | pfinder->data = NULL; 402 | pfinder->kernel = NULL; 403 | pfinder->kernel_sz = 0; 404 | sec_reset(&pfinder->sec_text); 405 | sec_reset(&pfinder->sec_cstring); 406 | memset(&pfinder->cmd_symtab, '\0', sizeof(pfinder->cmd_symtab)); 407 | } 408 | 409 | static void 410 | pfinder_term(pfinder_t *pfinder) { 411 | free(pfinder->data); 412 | pfinder_reset(pfinder); 413 | } 414 | 415 | static kern_return_t 416 | pfinder_init_file(pfinder_t *pfinder, const char *filename) { 417 | struct symtab_command cmd_symtab; 418 | kern_return_t ret = KERN_FAILURE; 419 | struct segment_command_64 sg64; 420 | struct mach_header_64 mh64; 421 | struct load_command lc; 422 | struct section_64 s64; 423 | struct fat_header fh; 424 | struct stat stat_buf; 425 | struct fat_arch fa; 426 | const char *p, *e; 427 | size_t len; 428 | void *m; 429 | int fd; 430 | 431 | pfinder_reset(pfinder); 432 | if((fd = open(filename, O_RDONLY | O_CLOEXEC)) != -1) { 433 | if(fstat(fd, &stat_buf) != -1 && stat_buf.st_size > 0) { 434 | len = (size_t)stat_buf.st_size; 435 | if((m = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)) != MAP_FAILED) { 436 | if((pfinder->data = kdecompress(m, len, &pfinder->kernel_sz)) != NULL && pfinder->kernel_sz > sizeof(fh) + sizeof(mh64)) { 437 | pfinder->kernel = pfinder->data; 438 | memcpy(&fh, pfinder->kernel, sizeof(fh)); 439 | if(fh.magic == __builtin_bswap32(FAT_MAGIC) && (fh.nfat_arch = __builtin_bswap32(fh.nfat_arch)) < (pfinder->kernel_sz - sizeof(fh)) / sizeof(fa)) { 440 | for(p = pfinder->kernel + sizeof(fh); fh.nfat_arch-- != 0; p += sizeof(fa)) { 441 | memcpy(&fa, p, sizeof(fa)); 442 | if(fa.cputype == (cpu_type_t)__builtin_bswap32(CPU_TYPE_ARM64) && (fa.offset = __builtin_bswap32(fa.offset)) < pfinder->kernel_sz && (fa.size = __builtin_bswap32(fa.size)) <= pfinder->kernel_sz - fa.offset && fa.size > sizeof(mh64)) { 443 | pfinder->kernel_sz = fa.size; 444 | pfinder->kernel += fa.offset; 445 | break; 446 | } 447 | } 448 | } 449 | memcpy(&mh64, pfinder->kernel, sizeof(mh64)); 450 | if(mh64.magic == MH_MAGIC_64 && mh64.cputype == CPU_TYPE_ARM64 && mh64.filetype == MH_EXECUTE && mh64.sizeofcmds < pfinder->kernel_sz - sizeof(mh64)) { 451 | for(p = pfinder->kernel + sizeof(mh64), e = p + mh64.sizeofcmds; mh64.ncmds-- != 0 && (size_t)(e - p) >= sizeof(lc); p += lc.cmdsize) { 452 | memcpy(&lc, p, sizeof(lc)); 453 | if(lc.cmdsize < sizeof(lc) || (size_t)(e - p) < lc.cmdsize) { 454 | break; 455 | } 456 | if(lc.cmd == LC_SEGMENT_64) { 457 | if(lc.cmdsize < sizeof(sg64)) { 458 | break; 459 | } 460 | memcpy(&sg64, p, sizeof(sg64)); 461 | if(sg64.vmsize == 0) { 462 | continue; 463 | } 464 | if(sg64.nsects != (lc.cmdsize - sizeof(sg64)) / sizeof(s64) || sg64.fileoff > pfinder->kernel_sz || sg64.filesize > pfinder->kernel_sz - sg64.fileoff) { 465 | break; 466 | } 467 | if(sg64.fileoff == 0 && sg64.filesize != 0) { 468 | if(pfinder->base != 0) { 469 | break; 470 | } 471 | pfinder->base = sg64.vmaddr; 472 | printf("base: " KADDR_FMT "\n", sg64.vmaddr); 473 | } 474 | if(strncmp(sg64.segname, SEG_TEXT_EXEC, sizeof(sg64.segname)) == 0) { 475 | if(find_section(p + sizeof(sg64), sg64, SECT_TEXT, &s64) != KERN_SUCCESS) { 476 | break; 477 | } 478 | pfinder->sec_text.s64 = s64; 479 | pfinder->sec_text.data = pfinder->kernel + s64.offset; 480 | printf("sec_text_addr: " KADDR_FMT ", sec_text_off: 0x%" PRIX32 ", sec_text_sz: 0x%" PRIX64 "\n", s64.addr, s64.offset, s64.size); 481 | } else if(strncmp(sg64.segname, SEG_TEXT, sizeof(sg64.segname)) == 0) { 482 | if(find_section(p + sizeof(sg64), sg64, SECT_CSTRING, &s64) != KERN_SUCCESS || pfinder->kernel[s64.offset + s64.size - 1] != '\0') { 483 | break; 484 | } 485 | pfinder->sec_cstring.s64 = s64; 486 | pfinder->sec_cstring.data = pfinder->kernel + s64.offset; 487 | printf("sec_cstring_addr: " KADDR_FMT ", sec_cstring_off: 0x%" PRIX32 ", sec_cstring_sz: 0x%" PRIX64 "\n", s64.addr, s64.offset, s64.size); 488 | } 489 | } else if(lc.cmd == LC_SYMTAB) { 490 | if(lc.cmdsize != sizeof(cmd_symtab)) { 491 | break; 492 | } 493 | memcpy(&cmd_symtab, p, sizeof(cmd_symtab)); 494 | printf("cmd_symtab_symoff: 0x%" PRIX32 ", cmd_symtab_nsyms: 0x%" PRIX32 ", cmd_symtab_stroff: 0x%" PRIX32 "\n", cmd_symtab.symoff, cmd_symtab.nsyms, cmd_symtab.stroff); 495 | if(cmd_symtab.nsyms != 0 && (cmd_symtab.symoff > pfinder->kernel_sz || cmd_symtab.nsyms > (pfinder->kernel_sz - cmd_symtab.symoff) / sizeof(struct nlist_64) || cmd_symtab.stroff > pfinder->kernel_sz || cmd_symtab.strsize > pfinder->kernel_sz - cmd_symtab.stroff || cmd_symtab.strsize == 0 || pfinder->kernel[cmd_symtab.stroff + cmd_symtab.strsize - 1] != '\0')) { 496 | break; 497 | } 498 | pfinder->cmd_symtab = cmd_symtab; 499 | } 500 | if(pfinder->base != 0 && pfinder->sec_text.s64.size != 0 && pfinder->sec_cstring.s64.size != 0 && pfinder->cmd_symtab.cmdsize != 0) { 501 | ret = KERN_SUCCESS; 502 | break; 503 | } 504 | } 505 | } 506 | } 507 | munmap(m, len); 508 | } 509 | } 510 | close(fd); 511 | } 512 | if(ret != KERN_SUCCESS) { 513 | pfinder_term(pfinder); 514 | } 515 | return ret; 516 | } 517 | 518 | static kaddr_t 519 | pfinder_xref_rd(pfinder_t pfinder, uint32_t rd, kaddr_t start, kaddr_t to) { 520 | kaddr_t x[32] = { 0 }; 521 | uint32_t insn; 522 | 523 | for(; sec_read_buf(pfinder.sec_text, start, &insn, sizeof(insn)) == KERN_SUCCESS; start += sizeof(insn)) { 524 | if(IS_LDR_X(insn)) { 525 | x[RD(insn)] = start + LDR_X_IMM(insn); 526 | } else if(IS_ADR(insn)) { 527 | x[RD(insn)] = start + ADR_IMM(insn); 528 | } else if(IS_ADD_X(insn)) { 529 | x[RD(insn)] = x[RN(insn)] + ADD_X_IMM(insn); 530 | } else if(IS_LDR_W_UNSIGNED_IMM(insn)) { 531 | x[RD(insn)] = x[RN(insn)] + LDR_W_UNSIGNED_IMM(insn); 532 | } else if(IS_LDR_X_UNSIGNED_IMM(insn)) { 533 | x[RD(insn)] = x[RN(insn)] + LDR_X_UNSIGNED_IMM(insn); 534 | } else { 535 | if(IS_ADRP(insn)) { 536 | x[RD(insn)] = ADRP_ADDR(start) + ADRP_IMM(insn); 537 | } 538 | continue; 539 | } 540 | if(RD(insn) == rd) { 541 | if(to == 0) { 542 | if(x[rd] < pfinder.base) { 543 | break; 544 | } 545 | return x[rd]; 546 | } 547 | if(x[rd] == to) { 548 | return start; 549 | } 550 | } 551 | } 552 | return 0; 553 | } 554 | 555 | static kaddr_t 556 | pfinder_xref_str(pfinder_t pfinder, const char *str, uint32_t rd) { 557 | const char *p, *e; 558 | size_t len; 559 | 560 | for(p = pfinder.sec_cstring.data, e = p + pfinder.sec_cstring.s64.size; p != e; p += len) { 561 | len = strlen(p) + 1; 562 | if(strncmp(str, p, len) == 0) { 563 | return pfinder_xref_rd(pfinder, rd, pfinder.sec_text.s64.addr, pfinder.sec_cstring.s64.addr + (kaddr_t)(p - pfinder.sec_cstring.data)); 564 | } 565 | } 566 | return 0; 567 | } 568 | 569 | static kaddr_t 570 | pfinder_sym(pfinder_t pfinder, const char *sym) { 571 | const char *p, *strtab = pfinder.kernel + pfinder.cmd_symtab.stroff; 572 | struct nlist_64 nl64; 573 | 574 | for(p = pfinder.kernel + pfinder.cmd_symtab.symoff; pfinder.cmd_symtab.nsyms-- != 0; p += sizeof(nl64)) { 575 | memcpy(&nl64, p, sizeof(nl64)); 576 | if(nl64.n_un.n_strx != 0 && nl64.n_un.n_strx < pfinder.cmd_symtab.strsize && (nl64.n_type & (N_STAB | N_TYPE)) == N_SECT && nl64.n_value >= pfinder.base && strcmp(strtab + nl64.n_un.n_strx, sym) == 0) { 577 | return nl64.n_value + pfinder.kslide; 578 | } 579 | } 580 | return 0; 581 | } 582 | 583 | static kaddr_t 584 | pfinder_rtclock_data(pfinder_t pfinder) { 585 | kaddr_t ref = pfinder_sym(pfinder, "_RTClockData"); 586 | uint32_t insns[3]; 587 | 588 | if(ref != 0) { 589 | return ref; 590 | } 591 | for(ref = pfinder_xref_str(pfinder, "assert_wait_timeout_with_leeway", 8); sec_read_buf(pfinder.sec_text, ref, insns, sizeof(insns)) == KERN_SUCCESS; ref -= sizeof(*insns)) { 592 | if(IS_ADRP(insns[0]) && IS_NOP(insns[1]) && IS_LDR_W_UNSIGNED_IMM(insns[2])) { 593 | return pfinder_xref_rd(pfinder, RD(insns[2]), ref, 0); 594 | } 595 | } 596 | return 0; 597 | } 598 | 599 | static kaddr_t 600 | pfinder_kernproc(pfinder_t pfinder) { 601 | kaddr_t ref = pfinder_sym(pfinder, "_kernproc"); 602 | uint32_t insns[2]; 603 | 604 | if(ref != 0) { 605 | return ref; 606 | } 607 | for(ref = pfinder_xref_str(pfinder, "\"Should never have an EVFILT_READ except for reg or fifo.\"", 0); sec_read_buf(pfinder.sec_text, ref, insns, sizeof(insns)) == KERN_SUCCESS; ref -= sizeof(*insns)) { 608 | if(IS_ADRP(insns[0]) && IS_LDR_X_UNSIGNED_IMM(insns[1]) && RD(insns[1]) == 3) { 609 | return pfinder_xref_rd(pfinder, RD(insns[1]), ref, 0); 610 | } 611 | } 612 | return 0; 613 | } 614 | 615 | static kaddr_t 616 | pfinder_csblob_get_cdhash(pfinder_t pfinder) { 617 | kaddr_t ref = pfinder_sym(pfinder, "_csblob_get_cdhash"); 618 | uint32_t insns[2]; 619 | 620 | if(ref != 0) { 621 | return ref; 622 | } 623 | for(ref = pfinder.sec_text.s64.addr; sec_read_buf(pfinder.sec_text, ref, insns, sizeof(insns)) == KERN_SUCCESS; ref += sizeof(*insns)) { 624 | if(IS_ADD_X(insns[0]) && RD(insns[0]) == 0 && RN(insns[0]) == 0 && ADD_X_IMM(insns[0]) == USER_CLIENT_TRAP_OFF && IS_RET(insns[1])) { 625 | return ref; 626 | } 627 | } 628 | return 0; 629 | } 630 | 631 | static kaddr_t 632 | pfinder_pmap_find_phys(pfinder_t pfinder) { 633 | kaddr_t ref = pfinder_sym(pfinder, "_pmap_find_phys"); 634 | uint32_t insns[2]; 635 | 636 | if(ref != 0) { 637 | return ref; 638 | } 639 | for(ref = pfinder_xref_str(pfinder, "Kext %s - page %p is not backed by physical memory.", 2); sec_read_buf(pfinder.sec_text, ref, insns, sizeof(insns)) == KERN_SUCCESS; ref -= sizeof(*insns)) { 640 | if(IS_MOV_X(insns[0]) && RD(insns[0]) == 1 && IS_BL(insns[1])) { 641 | return ref + sizeof(*insns) + BL_IMM(insns[1]); 642 | } 643 | } 644 | return 0; 645 | } 646 | 647 | static kaddr_t 648 | pfinder_bcopy_phys(pfinder_t pfinder) { 649 | kaddr_t ref = pfinder_sym(pfinder, "_bcopy_phys"); 650 | uint32_t insns[3]; 651 | size_t i; 652 | 653 | if(ref != 0) { 654 | return ref; 655 | } 656 | for(ref = pfinder_xref_str(pfinder, "\"mdevstrategy: sink address %016llX not mapped\\n\"", 0); sec_read_buf(pfinder.sec_text, ref, insns, sizeof(insns)) == KERN_SUCCESS; ref -= sizeof(*insns)) { 657 | if(IS_MOV_X(insns[0]) && RD(insns[0]) == 2) { 658 | i = IS_MOV_W_ZHW(insns[1]) && RD(insns[1]) == 3 && MOV_W_ZHW_IMM(insns[1]) == (BCOPY_PHYS_SRC_PHYS | BCOPY_PHYS_DST_PHYS) ? 2 : 1; 659 | if(IS_BL(insns[i])) { 660 | return ref + i * sizeof(*insns) + BL_IMM(insns[i]); 661 | } 662 | } 663 | } 664 | return 0; 665 | } 666 | 667 | static kaddr_t 668 | pfinder_init_kbase(pfinder_t *pfinder) { 669 | mach_msg_type_number_t cnt = TASK_DYLD_INFO_COUNT; 670 | kaddr_t addr, rtclock_data, rtclock_data_slid; 671 | vm_region_extended_info_data_t extended_info; 672 | task_dyld_info_data_t dyld_info; 673 | struct mach_header_64 mh64; 674 | mach_port_t object_name; 675 | mach_vm_size_t sz; 676 | 677 | if(task_info(tfp0, TASK_DYLD_INFO, (task_info_t)&dyld_info, &cnt) == KERN_SUCCESS) { 678 | pfinder->kslide = dyld_info.all_image_info_size; 679 | } 680 | if(pfinder->kslide == 0 && (rtclock_data = pfinder_rtclock_data(*pfinder)) != 0) { 681 | printf("rtclock_data: " KADDR_FMT "\n", rtclock_data); 682 | cnt = VM_REGION_EXTENDED_INFO_COUNT; 683 | for(addr = 0; mach_vm_region(tfp0, &addr, &sz, VM_REGION_EXTENDED_INFO, (vm_region_info_t)&extended_info, &cnt, &object_name) == KERN_SUCCESS; addr += sz) { 684 | mach_port_deallocate(mach_task_self(), object_name); 685 | if(extended_info.protection == VM_PROT_DEFAULT && extended_info.user_tag == VM_KERN_MEMORY_CPU) { 686 | if(kread_addr(addr + cpu_data_rtclock_datap_off, &rtclock_data_slid) == KERN_SUCCESS && rtclock_data_slid > rtclock_data) { 687 | pfinder->kslide = rtclock_data_slid - rtclock_data; 688 | } 689 | break; 690 | } 691 | } 692 | } 693 | if(pfinder->base + pfinder->kslide > pfinder->base && kread_buf(pfinder->base + pfinder->kslide, &mh64, sizeof(mh64)) == KERN_SUCCESS && mh64.magic == MH_MAGIC_64 && mh64.cputype == CPU_TYPE_ARM64 && mh64.filetype == MH_EXECUTE) { 694 | pfinder->sec_text.s64.addr += pfinder->kslide; 695 | pfinder->sec_cstring.s64.addr += pfinder->kslide; 696 | printf("kbase: " KADDR_FMT ", kslide: " KADDR_FMT "\n", pfinder->base + pfinder->kslide, pfinder->kslide); 697 | return KERN_SUCCESS; 698 | } 699 | return KERN_FAILURE; 700 | } 701 | 702 | static kern_return_t 703 | pfinder_init_offsets(void) { 704 | kern_return_t ret = KERN_FAILURE; 705 | pfinder_t pfinder; 706 | 707 | task_map_off = 0x20; 708 | proc_task_off = 0x18; 709 | proc_p_pid_off = 0x10; 710 | task_itk_space_off = 0x290; 711 | cpu_data_rtclock_datap_off = 0x1D8; 712 | vtab_get_ext_trap_for_idx_off = 0x5B8; 713 | if(kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_10_0_b5) { 714 | task_itk_space_off = 0x300; 715 | if(kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_11_0_b1) { 716 | task_itk_space_off = 0x308; 717 | cpu_data_rtclock_datap_off = 0x1A8; 718 | if(kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_12_0_b1) { 719 | proc_task_off = 0x10; 720 | proc_p_pid_off = 0x60; 721 | task_itk_space_off = 0x300; 722 | #ifdef __arm64e__ 723 | cpu_data_rtclock_datap_off = 0x190; 724 | #else 725 | cpu_data_rtclock_datap_off = 0x198; 726 | #endif 727 | if(kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_13_0_b1) { 728 | task_map_off = 0x28; 729 | task_itk_space_off = 0x320; 730 | vtab_get_ext_trap_for_idx_off = 0x5C0; 731 | if(kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_13_0_b2) { 732 | proc_p_pid_off = 0x68; 733 | } 734 | } 735 | } 736 | } 737 | } 738 | if(pfinder_init_file(&pfinder, BOOT_PATH) == KERN_SUCCESS) { 739 | if(pfinder_init_kbase(&pfinder) == KERN_SUCCESS && (kernproc = pfinder_kernproc(pfinder)) != 0) { 740 | printf("kernproc: " KADDR_FMT "\n", kernproc); 741 | if((csblob_get_cdhash = pfinder_csblob_get_cdhash(pfinder)) != 0) { 742 | printf("csblob_get_cdhash: " KADDR_FMT "\n", csblob_get_cdhash); 743 | if((pmap_find_phys = pfinder_pmap_find_phys(pfinder)) != 0) { 744 | printf("pmap_find_phys: " KADDR_FMT "\n", pmap_find_phys); 745 | if((bcopy_phys = pfinder_bcopy_phys(pfinder)) != 0) { 746 | printf("bcopy_phys: " KADDR_FMT "\n", bcopy_phys); 747 | ret = KERN_SUCCESS; 748 | } 749 | } 750 | } 751 | } 752 | pfinder_term(&pfinder); 753 | } 754 | return ret; 755 | } 756 | 757 | static kern_return_t 758 | find_task(pid_t pid, kaddr_t *task) { 759 | pid_t cur_pid; 760 | kaddr_t proc; 761 | 762 | if(kread_addr(kernproc + PROC_P_LIST_LH_FIRST_OFF, &proc) == KERN_SUCCESS) { 763 | while(proc != 0 && kread_buf(proc + proc_p_pid_off, &cur_pid, sizeof(cur_pid)) == KERN_SUCCESS) { 764 | if(cur_pid == pid) { 765 | return kread_addr(proc + proc_task_off, task); 766 | } 767 | if(pid == 0 || kread_addr(proc + PROC_P_LIST_LE_PREV_OFF, &proc) != KERN_SUCCESS) { 768 | break; 769 | } 770 | } 771 | } 772 | return KERN_FAILURE; 773 | } 774 | 775 | static kern_return_t 776 | lookup_ipc_port(mach_port_name_t port_name, kaddr_t *ipc_port) { 777 | ipc_entry_num_t port_idx, is_table_sz; 778 | kaddr_t itk_space, is_table; 779 | 780 | if(MACH_PORT_VALID(port_name) && kread_addr(our_task + task_itk_space_off, &itk_space) == KERN_SUCCESS) { 781 | printf("itk_space: " KADDR_FMT "\n", itk_space); 782 | if(kread_buf(itk_space + IPC_SPACE_IS_TABLE_SZ_OFF, &is_table_sz, sizeof(is_table_sz)) == KERN_SUCCESS) { 783 | printf("is_table_sz: 0x%" PRIX32 "\n", is_table_sz); 784 | if((port_idx = MACH_PORT_INDEX(port_name)) < is_table_sz && kread_addr(itk_space + IPC_SPACE_IS_TABLE_OFF, &is_table) == KERN_SUCCESS) { 785 | printf("is_table: " KADDR_FMT "\n", is_table); 786 | return kread_addr(is_table + port_idx * IPC_ENTRY_SZ + IPC_ENTRY_IE_OBJECT_OFF, ipc_port); 787 | } 788 | } 789 | } 790 | return KERN_FAILURE; 791 | } 792 | 793 | static kern_return_t 794 | lookup_io_object(io_object_t object, kaddr_t *ip_kobject) { 795 | kaddr_t ipc_port; 796 | 797 | if(lookup_ipc_port(object, &ipc_port) == KERN_SUCCESS) { 798 | printf("ipc_port: " KADDR_FMT "\n", ipc_port); 799 | return kread_addr(ipc_port + IPC_PORT_IP_KOBJECT_OFF, ip_kobject); 800 | } 801 | return KERN_FAILURE; 802 | } 803 | 804 | static io_connect_t 805 | get_conn(const char *name) { 806 | io_service_t serv = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(name)); 807 | io_connect_t conn = IO_OBJECT_NULL; 808 | 809 | if(serv != IO_OBJECT_NULL) { 810 | printf("serv: 0x%" PRIX32 "\n", serv); 811 | if(IOServiceOpen(serv, mach_task_self(), 0, &conn) != KERN_SUCCESS) { 812 | conn = IO_OBJECT_NULL; 813 | } 814 | IOObjectRelease(serv); 815 | } 816 | return conn; 817 | } 818 | 819 | static void 820 | kcall_term(void) { 821 | io_external_trap_t trap = { 0 }; 822 | 823 | kwrite_addr(user_client, orig_vtab); 824 | kfree(fake_vtab, MAX_VTAB_SZ); 825 | kwrite_buf(user_client + USER_CLIENT_TRAP_OFF, &trap, sizeof(trap)); 826 | IOServiceClose(g_conn); 827 | } 828 | 829 | static kern_return_t 830 | kcall_init(void) { 831 | if((g_conn = get_conn("AppleKeyStore")) != IO_OBJECT_NULL) { 832 | printf("g_conn: 0x%" PRIX32 "\n", g_conn); 833 | if(find_task(getpid(), &our_task) == KERN_SUCCESS) { 834 | printf("our_task: " KADDR_FMT "\n", our_task); 835 | if(lookup_io_object(g_conn, &user_client) == KERN_SUCCESS) { 836 | printf("user_client: " KADDR_FMT "\n", user_client); 837 | if(kread_addr(user_client, &orig_vtab) == KERN_SUCCESS) { 838 | printf("orig_vtab: " KADDR_FMT "\n", orig_vtab); 839 | if(kalloc(MAX_VTAB_SZ, &fake_vtab) == KERN_SUCCESS) { 840 | printf("fake_vtab: " KADDR_FMT "\n", fake_vtab); 841 | if(mach_vm_copy(tfp0, orig_vtab, MAX_VTAB_SZ, fake_vtab) == KERN_SUCCESS && kwrite_addr(fake_vtab + vtab_get_ext_trap_for_idx_off, csblob_get_cdhash) == KERN_SUCCESS && kwrite_addr(user_client, fake_vtab) == KERN_SUCCESS) { 842 | return KERN_SUCCESS; 843 | } 844 | kfree(fake_vtab, MAX_VTAB_SZ); 845 | } 846 | } 847 | } 848 | } 849 | IOServiceClose(g_conn); 850 | } 851 | return KERN_FAILURE; 852 | } 853 | 854 | static kern_return_t 855 | kcall(kern_return_t *ret, kaddr_t func, size_t argc, ...) { 856 | io_external_trap_t trap; 857 | kaddr_t args[7] = { 1 }; 858 | va_list ap; 859 | size_t i; 860 | 861 | va_start(ap, argc); 862 | for(i = 0; i < MIN(argc, 7); ++i) { 863 | args[i] = va_arg(ap, kaddr_t); 864 | } 865 | va_end(ap); 866 | trap.obj = args[0]; 867 | trap.func = func; 868 | trap.delta = 0; 869 | if(kwrite_buf(user_client + USER_CLIENT_TRAP_OFF, &trap, sizeof(trap)) == KERN_SUCCESS) { 870 | *ret = IOConnectTrap6(g_conn, 0, args[1], args[2], args[3], args[4], args[5], args[6]); 871 | return KERN_SUCCESS; 872 | } 873 | return KERN_FAILURE; 874 | } 875 | 876 | static kern_return_t 877 | phys_init(void) { 878 | kaddr_t kernel_task, kernel_map; 879 | 880 | if(find_task(0, &kernel_task) == KERN_SUCCESS) { 881 | printf("kernel_task: " KADDR_FMT "\n", kernel_task); 882 | if(kread_addr(kernel_task + task_map_off, &kernel_map) == KERN_SUCCESS) { 883 | printf("kernel_map: " KADDR_FMT "\n", kernel_map); 884 | if(kread_addr(kernel_map + VM_MAP_PMAP_OFF, &kernel_pmap) == KERN_SUCCESS) { 885 | printf("kernel_pmap: " KADDR_FMT "\n", kernel_pmap); 886 | if(kread_addr(kernel_pmap + PMAP_MIN_OFF, &kernel_pmap_min) == KERN_SUCCESS) { 887 | printf("kernel_pmap_min: " KADDR_FMT "\n", kernel_pmap_min); 888 | if(kread_addr(kernel_pmap + PMAP_MAX_OFF, &kernel_pmap_max) == KERN_SUCCESS) { 889 | printf("kernel_pmap_max: " KADDR_FMT "\n", kernel_pmap_max); 890 | return KERN_SUCCESS; 891 | } 892 | } 893 | } 894 | } 895 | } 896 | return KERN_FAILURE; 897 | } 898 | 899 | static kern_return_t 900 | phys_copy(kaddr_t src, kaddr_t dst, mach_vm_size_t sz) { 901 | vm_machine_attribute_val_t mattr_val = MATTR_VAL_CACHE_FLUSH; 902 | kaddr_t phys_src = src, phys_dst = dst; 903 | bool is_virt_src, is_virt_dst; 904 | mach_vm_size_t copy_sz; 905 | kern_return_t ret; 906 | 907 | while(sz != 0) { 908 | is_virt_src = src >= kernel_pmap_min && src < kernel_pmap_max; 909 | if(is_virt_src) { 910 | if(kcall(&ret, pmap_find_phys, 2, kernel_pmap, src) != KERN_SUCCESS || ret <= 0) { 911 | return KERN_FAILURE; 912 | } 913 | phys_src = ((kaddr_t)ret << vm_kernel_page_shift) | (src & vm_kernel_page_mask); 914 | printf("phys_src: " KADDR_FMT "\n", phys_src); 915 | } 916 | is_virt_dst = dst >= kernel_pmap_min && dst < kernel_pmap_max; 917 | if(is_virt_dst) { 918 | if(kcall(&ret, pmap_find_phys, 2, kernel_pmap, dst) != KERN_SUCCESS || ret <= 0) { 919 | if(kwrite_addr(dst, FAULT_MAGIC) != KERN_SUCCESS || kcall(&ret, pmap_find_phys, 2, kernel_pmap, dst) != KERN_SUCCESS || ret <= 0) { 920 | return KERN_FAILURE; 921 | } 922 | } 923 | phys_dst = ((kaddr_t)ret << vm_kernel_page_shift) | (dst & vm_kernel_page_mask); 924 | printf("phys_dst: " KADDR_FMT "\n", phys_dst); 925 | } 926 | copy_sz = MIN(sz, MIN(vm_kernel_page_size - (phys_src & vm_kernel_page_mask), vm_kernel_page_size - (phys_dst & vm_kernel_page_mask))); 927 | if(((phys_src | phys_dst | copy_sz) % sizeof(kaddr_t)) != 0 || kcall(&ret, bcopy_phys, 4, phys_src, phys_dst, copy_sz, BCOPY_PHYS_SRC_PHYS | BCOPY_PHYS_DST_PHYS) != KERN_SUCCESS) { 928 | return KERN_FAILURE; 929 | } 930 | if(is_virt_dst && mach_vm_machine_attribute(tfp0, dst, copy_sz, MATTR_CACHE, &mattr_val) != KERN_SUCCESS) { 931 | return KERN_FAILURE; 932 | } 933 | src += copy_sz; 934 | dst += copy_sz; 935 | sz -= copy_sz; 936 | } 937 | return KERN_SUCCESS; 938 | } 939 | 940 | static void 941 | phys_test(void) { 942 | kaddr_t virt_src, virt_dst; 943 | 944 | if(kalloc(vm_kernel_page_size, &virt_src) == KERN_SUCCESS) { 945 | printf("virt_src: " KADDR_FMT "\n", virt_src); 946 | if(kwrite_addr(virt_src, FAULT_MAGIC) == KERN_SUCCESS) { 947 | if(kalloc(vm_kernel_page_size, &virt_dst) == KERN_SUCCESS) { 948 | printf("virt_dst: " KADDR_FMT "\n", virt_dst); 949 | if(phys_copy(virt_src, virt_dst, vm_kernel_page_size) == KERN_SUCCESS) { 950 | printf("Copied 0x%lx bytes from " KADDR_FMT " to " KADDR_FMT "\n", vm_kernel_page_size, virt_src, virt_dst); 951 | } 952 | kfree(virt_dst, vm_kernel_page_size); 953 | } 954 | } 955 | kfree(virt_src, vm_kernel_page_size); 956 | } 957 | } 958 | 959 | int 960 | main(void) { 961 | kern_return_t ret; 962 | 963 | if(init_tfp0() == KERN_SUCCESS) { 964 | printf("tfp0: 0x%" PRIX32 "\n", tfp0); 965 | if(pfinder_init_offsets() == KERN_SUCCESS && kcall_init() == KERN_SUCCESS) { 966 | if(kcall(&ret, csblob_get_cdhash, 1, USER_CLIENT_TRAP_OFF) == KERN_SUCCESS) { 967 | printf("csblob_get_cdhash(USER_CLIENT_TRAP_OFF): 0x%" PRIX32 "\n", ret); 968 | if(phys_init() == KERN_SUCCESS) { 969 | phys_test(); 970 | } 971 | } 972 | kcall_term(); 973 | } 974 | mach_port_deallocate(mach_task_self(), tfp0); 975 | } 976 | } 977 | -------------------------------------------------------------------------------- /tfp0.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | get-task-allow 6 | 7 | task_for_pid-allow 8 | 9 | platform-application 10 | 11 | com.apple.private.security.no-container 12 | 13 | 14 | 15 | --------------------------------------------------------------------------------