diff --git a/Application/Dopamine/Jailbreak/DOJailbreaker.m b/Application/Dopamine/Jailbreak/DOJailbreaker.m index 2d12a87b7..42cad58d0 100644 --- a/Application/Dopamine/Jailbreak/DOJailbreaker.m +++ b/Application/Dopamine/Jailbreak/DOJailbreaker.m @@ -384,7 +384,7 @@ - (NSError *)createFakeLib cdhash_t *cdhashes = NULL; uint32_t cdhashesCount = 0; - macho_collect_untrusted_cdhashes(JBRootPath("/basebin/.fakelib/dyld"), NULL, NULL, &cdhashes, &cdhashesCount); + macho_collect_untrusted_cdhashes(JBRootPath("/basebin/.fakelib/dyld"), NULL, NULL, NULL, NULL, 0, &cdhashes, &cdhashesCount); if (cdhashesCount != 1) return [NSError errorWithDomain:JBErrorDomain code:JBErrorCodeFailedInitFakeLib userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Got unexpected number of cdhashes for dyld???: %d", cdhashesCount]}]; trustcache_file_v1 *dyldTCFile = NULL; diff --git a/BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c b/BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c index 82cc5ca42..4b6483639 100644 --- a/BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c +++ b/BaseBin/launchdhook/src/jbserver/jbdomain_systemwide.c @@ -67,7 +67,7 @@ static int systemwide_get_boot_uuid(char **bootUUIDOut) return 0; } -static int trust_file(const char *filePath, const char *dlopenCallerImagePath, const char *dlopenCallerExecutablePath) +static int trust_file(const char *filePath, const char *dlopenCallerImagePath, const char *dlopenCallerExecutablePath, xpc_object_t preferredArchsArray) { // Shared logic between client and server, implemented in client // This should essentially mean these files never reach us in the first place @@ -76,9 +76,23 @@ static int trust_file(const char *filePath, const char *dlopenCallerImagePath, c if (can_skip_trusting_file(filePath, (bool)dlopenCallerExecutablePath, false)) return -1; + size_t preferredArchCount = 0; + if (preferredArchsArray) preferredArchCount = xpc_array_get_count(preferredArchsArray); + uint32_t preferredArchTypes[preferredArchCount]; + uint32_t preferredArchSubtypes[preferredArchCount]; + for (size_t i = 0; i < preferredArchCount; i++) { + preferredArchTypes[i] = 0; + preferredArchSubtypes[i] = UINT32_MAX; + xpc_object_t arch = xpc_array_get_value(preferredArchsArray, i); + if (xpc_get_type(arch) == XPC_TYPE_DICTIONARY) { + preferredArchTypes[i] = xpc_dictionary_get_uint64(arch, "type"); + preferredArchSubtypes[i] = xpc_dictionary_get_uint64(arch, "subtype"); + } + } + cdhash_t *cdhashes = NULL; uint32_t cdhashesCount = 0; - macho_collect_untrusted_cdhashes(filePath, dlopenCallerImagePath, dlopenCallerExecutablePath, &cdhashes, &cdhashesCount); + macho_collect_untrusted_cdhashes(filePath, dlopenCallerImagePath, dlopenCallerExecutablePath, preferredArchTypes, preferredArchSubtypes, preferredArchCount, &cdhashes, &cdhashesCount); if (cdhashes && cdhashesCount > 0) { jb_trustcache_add_cdhashes(cdhashes, cdhashesCount); free(cdhashes); @@ -87,9 +101,9 @@ static int trust_file(const char *filePath, const char *dlopenCallerImagePath, c } // Not static because launchd will directly call this from it's posix_spawn hook -int systemwide_trust_binary(const char *binaryPath) +int systemwide_trust_binary(const char *binaryPath, xpc_object_t preferredArchsArray) { - return trust_file(binaryPath, NULL, NULL); + return trust_file(binaryPath, NULL, NULL, preferredArchsArray); } static int systemwide_trust_library(audit_token_t *processToken, const char *libraryPath, const char *callerLibraryPath) @@ -105,7 +119,7 @@ static int systemwide_trust_library(audit_token_t *processToken, const char *lib // This is to support dlopen("@executable_path/whatever", RTLD_NOW) and stuff like that // (Yes that is a thing >.<) // Also we need to pass the path of the image that called dlopen due to @loader_path, sigh... - return trust_file(libraryPath, callerLibraryPath, callerPath); + return trust_file(libraryPath, callerLibraryPath, callerPath, NULL); } static int systemwide_process_checkin(audit_token_t *processToken, char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut) @@ -343,6 +357,7 @@ struct jbserver_domain gSystemwideDomain = { .handler = systemwide_trust_binary, .args = (jbserver_arg[]){ { .name = "binary-path", .type = JBS_TYPE_STRING, .out = false }, + { .name = "preferred-archs", .type = JBS_TYPE_ARRAY, .out = false }, { 0 }, }, }, diff --git a/BaseBin/launchdhook/src/spawn_hook.c b/BaseBin/launchdhook/src/spawn_hook.c index 00869046f..76ae8c0cd 100644 --- a/BaseBin/launchdhook/src/spawn_hook.c +++ b/BaseBin/launchdhook/src/spawn_hook.c @@ -10,7 +10,7 @@ #include extern char **environ; -extern int systemwide_trust_binary(const char *binaryPath); +extern int systemwide_trust_binary(const char *binaryPath, xpc_object_t preferredArchsArray); extern int platform_set_process_debugged(uint64_t pid, bool fullyDebugged); #define LOG_PROCESS_LAUNCHES 0 diff --git a/BaseBin/libjailbreak/src/jbclient_xpc.c b/BaseBin/libjailbreak/src/jbclient_xpc.c index 01a3c4a09..63b83a283 100644 --- a/BaseBin/libjailbreak/src/jbclient_xpc.c +++ b/BaseBin/libjailbreak/src/jbclient_xpc.c @@ -184,7 +184,7 @@ char *realafpath(const char *restrict path, char *restrict resolved_path) } } -int jbclient_trust_binary(const char *binaryPath) +int jbclient_trust_binary(const char *binaryPath, xpc_object_t preferredArchsArray) { if (!binaryPath) return -1; @@ -195,6 +195,9 @@ int jbclient_trust_binary(const char *binaryPath) xpc_object_t xargs = xpc_dictionary_create_empty(); xpc_dictionary_set_string(xargs, "binary-path", absolutePath); + if (preferredArchsArray) { + xpc_dictionary_set_value(xargs, "preferred-archs", preferredArchsArray); + } xpc_object_t xreply = jbserver_xpc_send(JBS_DOMAIN_SYSTEMWIDE, JBS_SYSTEMWIDE_TRUST_BINARY, xargs); xpc_release(xargs); if (xreply) { diff --git a/BaseBin/libjailbreak/src/jbclient_xpc.h b/BaseBin/libjailbreak/src/jbclient_xpc.h index 501f905d3..c4601a473 100644 --- a/BaseBin/libjailbreak/src/jbclient_xpc.h +++ b/BaseBin/libjailbreak/src/jbclient_xpc.h @@ -12,7 +12,7 @@ xpc_object_t jbserver_xpc_send(uint64_t domain, uint64_t action, xpc_object_t xa char *jbclient_get_jbroot(void); char *jbclient_get_boot_uuid(void); -int jbclient_trust_binary(const char *binaryPath); +int jbclient_trust_binary(const char *binaryPath, xpc_object_t preferredArchsArray); int jbclient_trust_library(const char *libraryPath, void *addressInCaller); int jbclient_process_checkin(char **rootPathOut, char **bootUUIDOut, char **sandboxExtensionsOut, bool *fullyDebuggedOut); int jbclient_fork_fix(uint64_t childPid); diff --git a/BaseBin/libjailbreak/src/signatures.h b/BaseBin/libjailbreak/src/signatures.h index 1022ed104..b4518ce00 100644 --- a/BaseBin/libjailbreak/src/signatures.h +++ b/BaseBin/libjailbreak/src/signatures.h @@ -4,6 +4,6 @@ #include typedef uint8_t cdhash_t[CS_CDHASH_LEN]; -void macho_collect_untrusted_cdhashes(const char *path, const char *callerImagePath, const char *callerExecutablePath, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut); +void macho_collect_untrusted_cdhashes(const char *path, const char *callerImagePath, const char *callerExecutablePath, uint32_t *preferredArchTypes, uint32_t *preferredArchSubtypes, size_t preferredArchCount, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut); #endif \ No newline at end of file diff --git a/BaseBin/libjailbreak/src/signatures.m b/BaseBin/libjailbreak/src/signatures.m index 9af65f75f..8e19959ec 100644 --- a/BaseBin/libjailbreak/src/signatures.m +++ b/BaseBin/libjailbreak/src/signatures.m @@ -114,7 +114,7 @@ bool csd_superblob_is_adhoc_signed(CS_DecodedSuperBlob *superblob) } } -void macho_collect_untrusted_cdhashes(const char *path, const char *callerImagePath, const char *callerExecutablePath, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut) +void macho_collect_untrusted_cdhashes(const char *path, const char *callerImagePath, const char *callerExecutablePath, uint32_t *preferredArchTypes, uint32_t *preferredArchSubtypes, size_t preferredArchCount, cdhash_t **cdhashesOut, uint32_t *cdhashCountOut) { @autoreleasepool { if (!path) return; @@ -140,7 +140,16 @@ void macho_collect_untrusted_cdhashes(const char *path, const char *callerImageP if (!callerExecutablePath) { FAT *mainFAT = fat_init_from_path(path); if (mainFAT) { - MachO *mainMachO = ljb_fat_find_preferred_slice(mainFAT); + MachO *mainMachO = NULL; + if (preferredArchCount > 0) { + for (size_t i = 0; i < preferredArchCount; i++) { + if (preferredArchTypes[i] != 0 && preferredArchSubtypes[i] != UINT32_MAX) { + mainMachO = fat_find_slice(mainFAT, preferredArchTypes[i], preferredArchSubtypes[i]); + if (mainMachO) break; + } + } + } + if (!mainMachO) mainMachO = ljb_fat_find_preferred_slice(mainFAT); if (mainMachO) { if (macho_get_filetype(mainMachO) == MH_EXECUTE) { callerExecutablePath = path; @@ -160,7 +169,18 @@ void macho_collect_untrusted_cdhashes(const char *path, const char *callerImageP NSString *resolvedBinaryPath = resolveDependencyPath(binaryPath, sourceImagePath, sourceExecutablePath); FAT *fat = fat_init_from_path(resolvedBinaryPath.fileSystemRepresentation); if (!fat) return; - MachO *macho = ljb_fat_find_preferred_slice(fat); + MachO *macho = NULL; + if ([binaryPath isEqualToString:sourceExecutablePath]) { + if (preferredArchCount > 0) { + for (size_t i = 0; i < preferredArchCount; i++) { + if (preferredArchTypes[i] != 0 && preferredArchSubtypes[i] != UINT32_MAX) { + macho = fat_find_slice(fat, preferredArchTypes[i], preferredArchSubtypes[i]); + if (macho) break; + } + } + } + } + if (!macho) macho = ljb_fat_find_preferred_slice(fat); if (!macho) { fat_free(fat); return; diff --git a/BaseBin/libjailbreak/src/util.h b/BaseBin/libjailbreak/src/util.h index b095ab266..b1fa14216 100644 --- a/BaseBin/libjailbreak/src/util.h +++ b/BaseBin/libjailbreak/src/util.h @@ -53,7 +53,7 @@ int exec_cmd_suspended(pid_t *pidOut, const char *binary, ...); int exec_cmd_root(const char *binary, ...); #define exec_cmd_trusted(x, args ...) ({ \ - jbclient_trust_binary(x); \ + jbclient_trust_binary(x, NULL); \ int retval; \ retval = exec_cmd(x, args); \ retval; \ diff --git a/BaseBin/systemhook/src/common.c b/BaseBin/systemhook/src/common.c index fcad8cb98..59587ac5f 100644 --- a/BaseBin/systemhook/src/common.c +++ b/BaseBin/systemhook/src/common.c @@ -233,7 +233,7 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, char *const argv[restrict], char *const envp[restrict], void *orig, - int (*trust_binary)(const char *), + int (*trust_binary)(const char *path, xpc_object_t preferredArchsArray), int (*set_process_debugged)(uint64_t pid, bool fullyDebugged)) { int (*pspawn_orig)(pid_t *restrict, const char *restrict, const posix_spawn_file_actions_t *restrict, const posix_spawnattr_t *restrict, char *const[restrict], char *const[restrict]) = orig; @@ -244,8 +244,38 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, kBinaryConfig binaryConfig = configForBinary(path, argv); if (!(binaryConfig & kBinaryConfigDontProcess)) { + + bool preferredArchsSet = false; + cpu_type_t preferredTypes[4]; + cpu_subtype_t preferredSubtypes[4]; + size_t sizeOut = 0; + if (posix_spawnattr_getarchpref_np(attrp, 4, preferredTypes, preferredSubtypes, &sizeOut) == 0) { + for (size_t i = 0; i < sizeOut; i++) { + if (preferredTypes[i] != 0 || preferredSubtypes[i] != UINT32_MAX) { + preferredArchsSet = true; + break; + } + } + } + + xpc_object_t preferredArchsArray = NULL; + if (preferredArchsSet) { + preferredArchsArray = xpc_array_create_empty(); + for (size_t i = 0; i < sizeOut; i++) { + xpc_object_t curArch = xpc_dictionary_create_empty(); + xpc_dictionary_set_uint64(curArch, "type", preferredTypes[i]); + xpc_dictionary_set_uint64(curArch, "subtype", preferredSubtypes[i]); + xpc_array_set_value(preferredArchsArray, XPC_ARRAY_APPEND, curArch); + xpc_release(curArch); + } + } + // Upload binary to trustcache if needed - trust_binary(path); + trust_binary(path, preferredArchsArray); + + if (preferredArchsArray) { + xpc_release(preferredArchsArray); + } } const char *existingLibraryInserts = envbuf_getenv((const char **)envp, "DYLD_INSERT_LIBRARIES"); @@ -256,7 +286,7 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, systemHookAlreadyInserted = true; } else { - trust_binary(existingLibraryInsert); + trust_binary(existingLibraryInsert, NULL); } }); } diff --git a/BaseBin/systemhook/src/common.h b/BaseBin/systemhook/src/common.h index 1aa2450ff..6e7399519 100644 --- a/BaseBin/systemhook/src/common.h +++ b/BaseBin/systemhook/src/common.h @@ -16,5 +16,5 @@ int spawn_hook_common(pid_t *restrict pid, const char *restrict path, char *const argv[restrict], char *const envp[restrict], void *orig, - int (*trust_binary)(const char *), + int (*trust_binary)(const char *path, xpc_object_t preferredArchsArray), int (*set_process_debugged)(uint64_t pid, bool fullyDebugged)); \ No newline at end of file diff --git a/BaseBin/systemhook/src/objc.m b/BaseBin/systemhook/src/objc.m index 485dc1cb9..c9f085a61 100644 --- a/BaseBin/systemhook/src/objc.m +++ b/BaseBin/systemhook/src/objc.m @@ -36,7 +36,7 @@ bool NSConcreteTask_launchWithDictionary_error__hook(id self, id sender, NSDicti NSString *executablePath = __objc_msgSend_1(dictionary, @selector(objectForKey:), keyExecutablePath); if (executablePath) { const char *executablePathC = __objc_msgSend_0(executablePath, @selector(UTF8String)); - jbclient_trust_binary(executablePathC); + jbclient_trust_binary(executablePathC, NULL); } NSDictionary *existingEnvironment = __objc_msgSend_1(dictionary, @selector(objectForKey:), keyEnvironmentDict);