-
Notifications
You must be signed in to change notification settings - Fork 35
/
Sideloaded.x
151 lines (126 loc) · 5.43 KB
/
Sideloaded.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// https://github.com/PoomSmart/IAmYouTube/blob/main/Tweak.x
// Allows low latency player while sideloaded
#import <Foundation/Foundation.h>
#import <dlfcn.h>
#import <mach-o/dyld.h>
#import "fishhook/fishhook.h"
#define TW_BUNDLE_ID @"tv.twitch"
#define TW_NAME @"Twitch"
%hook NSBundle
- (NSString *)bundleIdentifier {
NSArray *address = [NSThread callStackReturnAddresses];
Dl_info info;
if (dladdr((void *)[address[2] longLongValue], &info) == 0) return %orig;
NSString *path = [NSString stringWithUTF8String:info.dli_fname];
if ([path hasPrefix:NSBundle.mainBundle.bundlePath]) return TW_BUNDLE_ID;
return %orig;
}
- (id)objectForInfoDictionaryKey:(NSString *)key {
if ([key isEqualToString:@"CFBundleIdentifier"]) return TW_BUNDLE_ID;
if ([key isEqualToString:@"CFBundleDisplayName"] || [key isEqualToString:@"CFBundleName"])
return TW_NAME;
return %orig;
}
%end
// https://github.com/opa334/IGSideloadFix
NSString *keychainAccessGroup;
NSURL *fakeGroupContainerURL;
void createDirectoryIfNotExists(NSURL *URL) {
if (![URL checkResourceIsReachableAndReturnError:nil]) {
[[NSFileManager defaultManager] createDirectoryAtURL:URL
withIntermediateDirectories:YES
attributes:nil
error:nil];
}
}
%group SideloadedFixes
%hook NSFileManager
- (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier {
NSURL *fakeURL = [fakeGroupContainerURL URLByAppendingPathComponent:groupIdentifier];
createDirectoryIfNotExists(fakeURL);
createDirectoryIfNotExists([fakeURL URLByAppendingPathComponent:@"Library"]);
createDirectoryIfNotExists([fakeURL URLByAppendingPathComponent:@"Library/Caches"]);
return fakeURL;
}
%end
static void loadKeychainAccessGroup() {
NSDictionary *dummyItem = @{
(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrAccount : @"dummyItem",
(__bridge id)kSecAttrService : @"dummyService",
(__bridge id)kSecReturnAttributes : @YES,
};
CFTypeRef result;
OSStatus ret = SecItemCopyMatching((__bridge CFDictionaryRef)dummyItem, &result);
if (ret == -25300) {
ret = SecItemAdd((__bridge CFDictionaryRef)dummyItem, &result);
}
if (ret == 0 && result) {
NSDictionary *resultDict = (__bridge id)result;
keychainAccessGroup = resultDict[(__bridge id)kSecAttrAccessGroup];
NSLog(@"loaded keychainAccessGroup: %@", keychainAccessGroup);
}
}
%end
static OSStatus (*orig_SecItemAdd)(CFDictionaryRef, CFTypeRef *);
static OSStatus hook_SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) {
if (CFDictionaryContainsKey(attributes, kSecAttrAccessGroup)) {
CFMutableDictionaryRef mutableAttributes =
CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, attributes);
CFDictionarySetValue(mutableAttributes, kSecAttrAccessGroup,
(__bridge void *)keychainAccessGroup);
attributes = CFDictionaryCreateCopy(kCFAllocatorDefault, mutableAttributes);
}
return orig_SecItemAdd(attributes, result);
}
static OSStatus (*orig_SecItemCopyMatching)(CFDictionaryRef, CFTypeRef *);
static OSStatus hook_SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result) {
if (CFDictionaryContainsKey(query, kSecAttrAccessGroup)) {
CFMutableDictionaryRef mutableQuery =
CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
CFDictionarySetValue(mutableQuery, kSecAttrAccessGroup, (__bridge void *)keychainAccessGroup);
query = CFDictionaryCreateCopy(kCFAllocatorDefault, mutableQuery);
}
return orig_SecItemCopyMatching(query, result);
}
static OSStatus (*orig_SecItemUpdate)(CFDictionaryRef, CFDictionaryRef);
static OSStatus hook_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate) {
if (CFDictionaryContainsKey(query, kSecAttrAccessGroup)) {
CFMutableDictionaryRef mutableQuery =
CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
CFDictionarySetValue(mutableQuery, kSecAttrAccessGroup, (__bridge void *)keychainAccessGroup);
query = CFDictionaryCreateCopy(kCFAllocatorDefault, mutableQuery);
}
return orig_SecItemUpdate(query, attributesToUpdate);
}
static OSStatus (*orig_SecItemDelete)(CFDictionaryRef);
static OSStatus hook_SecItemDelete(CFDictionaryRef query) {
if (CFDictionaryContainsKey(query, kSecAttrAccessGroup)) {
CFMutableDictionaryRef mutableQuery =
CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query);
CFDictionarySetValue(mutableQuery, kSecAttrAccessGroup, (__bridge void *)keychainAccessGroup);
query = CFDictionaryCreateCopy(kCFAllocatorDefault, mutableQuery);
}
return orig_SecItemDelete(query);
}
static void initSideloadedFixes() {
fakeGroupContainerURL =
[NSURL fileURLWithPath:[NSHomeDirectory()
stringByAppendingPathComponent:@"Documents/FakeGroupContainers"]
isDirectory:YES];
loadKeychainAccessGroup();
rebind_symbols(
(struct rebinding[]){
{"SecItemAdd", (void *)hook_SecItemAdd, (void **)&orig_SecItemAdd},
{"SecItemCopyMatching", (void *)hook_SecItemCopyMatching,
(void **)&orig_SecItemCopyMatching},
{"SecItemUpdate", (void *)hook_SecItemUpdate, (void **)&orig_SecItemUpdate},
{"SecItemDelete", (void *)hook_SecItemDelete, (void **)&orig_SecItemDelete},
},
4);
%init(SideloadedFixes);
}
%ctor {
%init;
initSideloadedFixes();
}