forked from lemon4ex/XcodeRootDebug
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathTweak.x
127 lines (111 loc) · 4.63 KB
/
Tweak.x
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSUserDefaults+Private.h>
#include <unistd.h>
#include <substrate.h>
extern char **environ;
#define LOG(fmt, ...) NSLog(@"[XcodeRootDebug] " fmt "\n", ##__VA_ARGS__)
static NSString * nsDomainString = @"com.byteage.xcoderootdebug";
static NSString * nsNotificationString = @"com.byteage.xcoderootdebug/preferences.changed";
static BOOL enabled;
static NSString *debugserverPath;
static BOOL isRootUser;
static void reloadSettings() {
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:@"/private/var/mobile/Library/Preferences/com.byteage.xcoderootdebug.plist"];
NSNumber * enabledValue = (NSNumber *)[settings objectForKey:@"enabled"];
enabled = (enabledValue)? [enabledValue boolValue] : YES;
debugserverPath = [settings objectForKey:@"debugserverPath"];
if(!debugserverPath.length) {
debugserverPath = @"/usr/bin/debugserver";
}
NSNumber * isRootUserValue = (NSNumber *)[settings objectForKey:@"isRootUser"];
isRootUser = (isRootUserValue)? [isRootUserValue boolValue] : YES;
}
static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
// kill self
exit(0);
}
// If the compiler understands __arm64e__, assume it's paired with an SDK that has
// ptrauth.h. Otherwise, it'll probably error if we try to include it so don't.
#if __arm64e__
#include <ptrauth.h>
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
// Given a pointer to instructions, sign it so you can call it like a normal fptr.
static void *make_sym_callable(void *ptr) {
#if __arm64e__
ptr = ptrauth_sign_unauthenticated(ptrauth_strip(ptr, ptrauth_key_function_pointer), ptrauth_key_function_pointer, 0);
#endif
return ptr;
}
// Given a function pointer, strip the PAC so you can read the instructions.
static void *make_sym_readable(void *ptr) {
#if __arm64e__
ptr = ptrauth_strip(ptr, ptrauth_key_function_pointer);
#endif
return ptr;
}
#pragma clang diagnostic pop
typedef CFTypeRef AuthorizationRef;
bool (*original_SMJobSubmit)(CFStringRef domain, CFDictionaryRef job, AuthorizationRef auth, CFErrorRef _Nullable *error);
bool hooked_SMJobSubmit(CFStringRef domain, CFDictionaryRef job, AuthorizationRef auth, CFErrorRef _Nullable *error) {
LOG(@"Enter hooked_SMJobSubmit %@", job);
NSMutableDictionary *newJobInfo = [NSMutableDictionary dictionaryWithDictionary:(__bridge NSDictionary *)job];
NSMutableArray *programArgs = [newJobInfo[@"ProgramArguments"] mutableCopy];
NSString *program = programArgs[0];
if (enabled) {
if([program isEqualToString:@"/Developer/usr/bin/debugserver"]) {
LOG("Found launch /Developer/usr/bin/debugserver");
if(debugserverPath.length > 0 && access(debugserverPath.UTF8String, F_OK) == 0){
LOG("Change to launch %@", debugserverPath);
programArgs[0] = debugserverPath;
newJobInfo[@"ProgramArguments"] = programArgs;
} else {
LOG("Debug Server does not exist at %@", debugserverPath);
}
if(isRootUser) {
LOG("Change to launch with root");
newJobInfo[@"UserName"] = @"root";
} else {
newJobInfo[@"UserName"] = @"mobile";
}
LOG(@"Now SMJobSubmit %@", newJobInfo);
} else if([program isEqualToString:debugserverPath]) {
LOG("Found launch %@",debugserverPath);
if(isRootUser) {
LOG("Change to launch with root");
newJobInfo[@"UserName"] = @"root";
} else {
newJobInfo[@"UserName"] = @"mobile";
}
LOG(@"Now SMJobSubmit %@", newJobInfo);
}
} else {
if([program isEqualToString:debugserverPath]) {
LOG("Found launch %@",debugserverPath);
LOG("Restore launch /Developer/usr/bin/debugserver with mobile");
programArgs[0] = @"/Developer/usr/bin/debugserver";
newJobInfo[@"ProgramArguments"] = programArgs;
newJobInfo[@"UserName"] = @"mobile";
LOG(@"Now SMJobSubmit %@", newJobInfo);
}
}
LOG(@"New SMJobSubmit %@", newJobInfo);
return original_SMJobSubmit(domain, (__bridge CFDictionaryRef)newJobInfo, auth, error);
}
%ctor {
LOG(@"loaded in %s (%d)", getprogname(), getpid());
reloadSettings();
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, notificationCallback, (CFStringRef)nsNotificationString, NULL, CFNotificationSuspensionBehaviorCoalesce);
MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/ServiceManagement.framework/ServiceManagement");
if (!image) {
LOG("ServiceManagement framework not found, it is impossible");
return;
}
MSHookFunction(
MSFindSymbol(image, "_SMJobSubmit"),
(void *)hooked_SMJobSubmit,
(void **)&original_SMJobSubmit
);
}