-
Notifications
You must be signed in to change notification settings - Fork 48
/
Tweak.x
130 lines (113 loc) · 4.75 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
128
129
130
#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);
static NSString *systemDebugserverPath;
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"] || [program isEqualToString:@"/usr/libexec/debugserver"]) {
LOG("Found launch %@", program);
systemDebugserverPath = [program copy];
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 system debugserver at %@ with mobile", systemDebugserverPath);
programArgs[0] = systemDebugserverPath;
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
);
}