├── .gitignore ├── ChoicyLoader.m ├── LICENSE.md ├── Makefile ├── README.md ├── control ├── postinst ├── Makefile └── main.m ├── postrm ├── Makefile └── main.m └── triggers /.gitignore: -------------------------------------------------------------------------------- 1 | .theos/ 2 | .DS_Store 3 | packages/ -------------------------------------------------------------------------------- /ChoicyLoader.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Lars Fröder 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import 23 | 24 | __attribute__((constructor)) 25 | static void init(void) 26 | { 27 | CFStringRef securityIdentifier = CFStringCreateWithCString(kCFAllocatorDefault, "com.apple.Security", kCFStringEncodingUTF8); 28 | CFBundleRef securityBundle = CFBundleGetBundleWithIdentifier(securityIdentifier); 29 | CFRelease(securityIdentifier); 30 | 31 | if(!securityBundle) 32 | { 33 | return; 34 | } 35 | 36 | //Choicy 1.1.3 and below 37 | if(access("/Library/MobileSubstrate/DynamicLibraries/000_Choicy.dylib", F_OK) != -1) 38 | { 39 | dlopen("/Library/MobileSubstrate/DynamicLibraries/000_Choicy.dylib", RTLD_NOW); 40 | } 41 | 42 | //Choicy 1.2 and above 43 | if(access("/Library/MobileSubstrate/DynamicLibraries/ Choicy.dylib", F_OK) != -1) 44 | { 45 | dlopen("/Library/MobileSubstrate/DynamicLibraries/ Choicy.dylib", RTLD_NOW); 46 | } 47 | 48 | //If Crane is installed, load it after Choicy 49 | if(access("/Library/MobileSubstrate/DynamicLibraries/ Crane.dylib", F_OK) != -1) 50 | { 51 | dlopen("/Library/MobileSubstrate/DynamicLibraries/ Crane.dylib", RTLD_NOW); 52 | } 53 | 54 | //Load Substrate 55 | if(access("/usr/lib/substrate/SubstrateLoader_orig.dylib", F_OK) != -1) 56 | { 57 | dlopen("/usr/lib/substrate/SubstrateLoader_orig.dylib", RTLD_NOW); 58 | } 59 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Lars Fröder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include $(THEOS)/makefiles/common.mk 2 | 3 | LIBRARY_NAME = ChoicyLoader 4 | 5 | ChoicyLoader_FILES = ChoicyLoader.m 6 | ChoicyLoader_CFLAGS = -DTHEOS_LEAN_AND_MEAN # <- this makes theos not link against anything by default (we do not want to link UIKit cause we load system wide) 7 | ChoicyLoader_FRAMEWORKS = CoreFoundation 8 | 9 | include $(THEOS_MAKE_PATH)/library.mk 10 | SUBPROJECTS = postinst postrm 11 | include $(THEOS_MAKE_PATH)/aggregate.mk 12 | 13 | #using a layout directory somehow doesn't work if the postinst/postrm's are subprojects 14 | internal-stage:: 15 | $(ECHO_NOTHING)cp triggers $(THEOS_STAGING_DIR)/DEBIAN$(ECHO_END) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChoicyLoader 2 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.opa334.choicyloader 2 | Name: ChoicyLoader 3 | Depends: com.opa334.choicy 4 | Version: 1.2.3 5 | Conflicts: science.xnu.substitute, com.ex.substitute, org.coolstar.tweakinject, org.coolstar.libhooker 6 | Architecture: iphoneos-arm 7 | Description: Hacky workaround to always load Choicy first 8 | Depiction: https://opa334.github.io/depic/ChoicyLoader/index.html 9 | Maintainer: opa334 10 | Author: opa334 11 | Section: System 12 | -------------------------------------------------------------------------------- /postinst/Makefile: -------------------------------------------------------------------------------- 1 | include $(THEOS)/makefiles/common.mk 2 | 3 | TOOL_NAME = postinst 4 | 5 | postinst_FILES = main.m 6 | postinst_CFLAGS += -fvisibility=hidden -DPOSTINST -fobjc-arc 7 | postinst_FRAMEWORKS = CoreFoundation 8 | postinst_INSTALL_PATH = /DEBIAN 9 | 10 | include $(THEOS_MAKE_PATH)/tool.mk 11 | 12 | include $(THEOS_MAKE_PATH)/aggregate.mk -------------------------------------------------------------------------------- /postinst/main.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Lars Fröder 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include 22 | 23 | int hookingPlatform = 0; 24 | 25 | int main(int argc, char *argv[], char *envp[]) 26 | { 27 | if (geteuid() != 0) 28 | { 29 | printf("ERROR: This tool needs to be run as root.\n"); 30 | return 1; 31 | } 32 | 33 | if(![[NSFileManager defaultManager] fileExistsAtPath:@"/usr/lib/substrate/SubstrateInserter.dylib"]) 34 | { 35 | printf("ERROR: Substrate not found\n"); 36 | printf("ChoicyLoader DOES NOT DO ANYTHING ON YOUR DEVICE AND IS NOT NEEDED, PLEASE UNINSTALL IT.\n"); 37 | printf("ChoicyLoader DOES NOT DO ANYTHING ON YOUR DEVICE AND IS NOT NEEDED, PLEASE UNINSTALL IT.\n"); 38 | printf("ChoicyLoader DOES NOT DO ANYTHING ON YOUR DEVICE AND IS NOT NEEDED, PLEASE UNINSTALL IT.\n"); 39 | return 0; 40 | } 41 | 42 | NSString* targetPath = @"/usr/lib/substrate/SubstrateLoader.dylib"; 43 | 44 | NSString* origPath = [[[targetPath stringByDeletingPathExtension] stringByAppendingString:@"_orig"] stringByAppendingPathExtension:[targetPath pathExtension]]; 45 | 46 | if(![[NSFileManager defaultManager] fileExistsAtPath:@"/usr/lib/ChoicyLoader.dylib"]) 47 | { 48 | printf("ERROR: /usr/lib/ChoicyLoader.dylib does not exist.\n"); 49 | return -1; 50 | } 51 | 52 | if(![[NSFileManager defaultManager] fileExistsAtPath:targetPath]) 53 | { 54 | printf("ERROR: %s does not exist.\n", [targetPath UTF8String]); 55 | return -1; 56 | } 57 | 58 | NSDictionary* targetLoaderAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:targetPath error:nil]; 59 | 60 | if([[targetLoaderAttributes objectForKey:NSFileType] isEqualToString:NSFileTypeSymbolicLink]) 61 | { 62 | printf("ERROR: %s is already a symbolic link, ChoicyLoader is likely already enabled.\n", [targetPath UTF8String]); 63 | return 0; 64 | } 65 | 66 | NSError* error; 67 | 68 | if([[NSFileManager defaultManager] fileExistsAtPath:origPath]) 69 | { 70 | printf("%s already exists and %s is not a symbolic link, removing %s...\n", origPath.lastPathComponent.UTF8String, targetPath.lastPathComponent.UTF8String, origPath.lastPathComponent.UTF8String); 71 | [[NSFileManager defaultManager] removeItemAtPath:origPath error:&error]; 72 | if(error) 73 | { 74 | printf("ERROR: Removing %s failed: %s.\n", origPath.lastPathComponent.UTF8String, error.description.UTF8String); 75 | return 2; 76 | } 77 | } 78 | 79 | [[NSFileManager defaultManager] moveItemAtPath:targetPath toPath:origPath error:&error]; 80 | if(error) 81 | { 82 | printf("ERROR: Renaming %s to %s failed: %s.\n", targetPath.lastPathComponent.UTF8String, origPath.lastPathComponent.UTF8String, error.description.UTF8String); 83 | return 2; 84 | } 85 | 86 | [[NSFileManager defaultManager] createSymbolicLinkAtPath:targetPath withDestinationPath:@"/usr/lib/ChoicyLoader.dylib" error:&error]; 87 | if(error) 88 | { 89 | printf("ERROR: Creating %s symbolic link failed: %s.\n", targetPath.lastPathComponent.UTF8String, error.description.UTF8String); 90 | return 2; 91 | } 92 | 93 | printf("Sucessfully enabled ChoicyLoader!\n"); 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /postrm/Makefile: -------------------------------------------------------------------------------- 1 | include $(THEOS)/makefiles/common.mk 2 | 3 | TOOL_NAME = postrm 4 | 5 | postrm_FILES = main.m 6 | postrm_CFLAGS += -fvisibility=hidden -DPOSTRM -fobjc-arc 7 | postrm_FRAMEWORKS = CoreFoundation 8 | postrm_INSTALL_PATH = /DEBIAN 9 | 10 | include $(THEOS_MAKE_PATH)/tool.mk 11 | 12 | include $(THEOS_MAKE_PATH)/aggregate.mk -------------------------------------------------------------------------------- /postrm/main.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Lars Fröder 2 | 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include 22 | 23 | //0: did nothing, -1: error, 1: success 24 | int disableChoicyLoader(NSString* loaderPath) 25 | { 26 | NSString* origPath = [[[loaderPath stringByDeletingPathExtension] stringByAppendingString:@"_orig"] stringByAppendingPathExtension:[loaderPath pathExtension]]; 27 | 28 | NSError* error; 29 | NSDictionary* loaderAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:loaderPath error:&error]; 30 | 31 | if(![[loaderAttributes objectForKey:NSFileType] isEqualToString:NSFileTypeSymbolicLink]) 32 | { 33 | printf("%s is not a symbolic link, ChoicyLoader is likely already disabled.\n", loaderPath.UTF8String); 34 | return 0; 35 | } 36 | 37 | if(![[NSFileManager defaultManager] fileExistsAtPath:origPath]) 38 | { 39 | printf("%s does not exist, ChoicyLoader is likely already disabled.\n", origPath.UTF8String); 40 | return 0; 41 | } 42 | 43 | [[NSFileManager defaultManager] removeItemAtPath:loaderPath error:&error]; 44 | if(error) 45 | { 46 | printf("ERROR: Removing %s symlink failed: %s.\n", loaderPath.lastPathComponent.UTF8String, error.description.UTF8String); 47 | return -1; 48 | } 49 | 50 | [[NSFileManager defaultManager] moveItemAtPath:origPath toPath:loaderPath error:&error]; 51 | if(error) 52 | { 53 | printf("ERROR: Moving %s back failed: %s.\n", loaderPath.lastPathComponent.UTF8String, error.description.UTF8String); 54 | return -1; 55 | } 56 | 57 | return 1; 58 | } 59 | 60 | int main(int argc, char *argv[], char *envp[]) 61 | { 62 | if (geteuid() != 0) 63 | { 64 | printf("ERROR: This tool needs to be run as root.\n"); 65 | return 1; 66 | } 67 | 68 | if(![[NSFileManager defaultManager] fileExistsAtPath:@"/usr/lib/substrate/SubstrateInserter.dylib"]) 69 | { 70 | printf("Substrate not found. Looking for a deprecated Substitute installation...\n"); 71 | 72 | int ret = disableChoicyLoader(@"/usr/lib/substitute-loader.dylib"); 73 | 74 | if(ret == 1) 75 | { 76 | printf("Sucessfully reverted deprecated Substitute installation!\n"); 77 | } 78 | else if(ret == 0) 79 | { 80 | printf("Deprecated Substitute installation not found, all good\n"); 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | int ret = disableChoicyLoader(@"/usr/lib/substrate/SubstrateLoader.dylib"); 87 | 88 | if(ret == 1) 89 | { 90 | printf("Sucessfully disabled ChoicyLoader!\n"); 91 | } 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /triggers: -------------------------------------------------------------------------------- 1 | interest /usr/lib/substrate/SubstrateLoader.dylib 2 | --------------------------------------------------------------------------------