mirror of https://github.com/opa334/TrollStore.git
Fix every installed app getting assigned the same data container
This commit is contained in:
parent
3fe3e7f241
commit
1699abd9ab
|
@ -562,29 +562,89 @@ int signApp(NSString* appPath)
|
||||||
NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@, continuing anways...", mainExecutablePath);
|
NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@, continuing anways...", mainExecutablePath);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
int (^signFile)(NSString *, NSDictionary *) = ^(NSString *filePath, NSDictionary *entitlements) {
|
NSURL* fileURL;
|
||||||
NSLog(@"Checking %@", filePath);
|
NSDirectoryEnumerator *enumerator;
|
||||||
|
|
||||||
|
// Due to how the new CT bug works, in order for data containers to work properly we need to add the
|
||||||
|
// com.apple.private.security.container-required=<bundle-identifier> entitlement to every binary inside a bundle
|
||||||
|
// For this we will want to first collect info about all the bundles in the app by seeking for Info.plist files and adding the ent to the main binary
|
||||||
|
enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil];
|
||||||
|
while(fileURL = [enumerator nextObject])
|
||||||
|
{
|
||||||
|
NSString *filePath = fileURL.path;
|
||||||
|
if ([filePath.lastPathComponent isEqualToString:@"Info.plist"]) {
|
||||||
|
NSDictionary *infoDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
|
||||||
|
if (!infoDict) continue;
|
||||||
|
NSString *bundleId = infoDict[@"CFBundleIdentifier"];
|
||||||
|
NSString *bundleExecutable = infoDict[@"CFBundleExecutable"];
|
||||||
|
if (!bundleId || !bundleExecutable) continue;
|
||||||
|
NSString *bundleMainExecutablePath = [[filePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:bundleExecutable];
|
||||||
|
if (![[NSFileManager defaultManager] fileExistsAtPath:bundleMainExecutablePath]) continue;
|
||||||
|
|
||||||
|
NSString *packageType = infoDict[@"CFBundlePackageType"];
|
||||||
|
|
||||||
|
// We don't care about frameworks (yet)
|
||||||
|
if ([packageType isEqualToString:@"FMWK"]) continue;
|
||||||
|
|
||||||
|
NSMutableDictionary *entitlementsToUse = dumpEntitlementsFromBinaryAtPath(bundleMainExecutablePath).mutableCopy;
|
||||||
|
if (isSameFile(bundleMainExecutablePath, mainExecutablePath)) {
|
||||||
|
// In the case where the main executable of the app currently has no entitlements at all
|
||||||
|
// We want to ensure it gets signed with fallback entitlements
|
||||||
|
// These mimic the entitlements that Xcodes gives every app it signs
|
||||||
|
if (!entitlementsToUse) {
|
||||||
|
entitlementsToUse = @{
|
||||||
|
@"application-identifier" : @"TROLLTROLL.*",
|
||||||
|
@"com.apple.developer.team-identifier" : @"TROLLTROLL",
|
||||||
|
@"get-task-allow" : (__bridge id)kCFBooleanTrue,
|
||||||
|
@"keychain-access-groups" : @[
|
||||||
|
@"TROLLTROLL.*",
|
||||||
|
@"com.apple.token"
|
||||||
|
],
|
||||||
|
}.mutableCopy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entitlementsToUse) entitlementsToUse = [NSMutableDictionary new];
|
||||||
|
|
||||||
|
NSObject *containerRequiredO = entitlementsToUse[@"com.apple.private.security.container-required"];
|
||||||
|
BOOL containerRequired = YES;
|
||||||
|
if (containerRequiredO && [containerRequiredO isKindOfClass:[NSNumber class]]) {
|
||||||
|
containerRequired = [(NSNumber *)containerRequiredO boolValue];
|
||||||
|
}
|
||||||
|
else if (containerRequiredO && [containerRequiredO isKindOfClass:[NSString class]]) {
|
||||||
|
// Keep whatever is in it if it's a string...
|
||||||
|
containerRequired = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containerRequired) {
|
||||||
|
NSObject *noContainerO = entitlementsToUse[@"com.apple.private.security.no-container"];
|
||||||
|
BOOL noContainer = NO;
|
||||||
|
if (noContainerO && [noContainerO isKindOfClass:[NSNumber class]]) {
|
||||||
|
noContainer = [(NSNumber *)noContainerO boolValue];
|
||||||
|
}
|
||||||
|
if (!noContainer) {
|
||||||
|
entitlementsToUse[@"com.apple.private.security.container-required"] = bundleId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signAdhoc(bundleMainExecutablePath, entitlementsToUse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All entitlement related issues should be fixed at this point, so all we need to do is sign the entire bundle
|
||||||
|
// And then apply the CoreTrust bypass to all executables
|
||||||
|
// XXX: This only works because we're using ldid at the moment and that recursively signs everything
|
||||||
|
signAdhoc(appPath, nil);
|
||||||
|
|
||||||
|
enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil];
|
||||||
|
while(fileURL = [enumerator nextObject])
|
||||||
|
{
|
||||||
|
NSString *filePath = fileURL.path;
|
||||||
FAT *fat = fat_init_from_path(filePath.fileSystemRepresentation);
|
FAT *fat = fat_init_from_path(filePath.fileSystemRepresentation);
|
||||||
if (fat) {
|
if (fat) {
|
||||||
NSLog(@"%@ is binary", filePath);
|
NSLog(@"%@ is binary", filePath);
|
||||||
fat_free(fat);
|
|
||||||
|
|
||||||
// First attempt ad hoc signing
|
|
||||||
int r = signAdhoc(filePath, entitlements);
|
|
||||||
if (r != 0) {
|
|
||||||
// If it doesn't work it's not a big deal, that usually happens when the binary had the bypass applied already (Don't ask me why)
|
|
||||||
NSLog(@"[%@] Adhoc signing failed with error code %d, continuing anyways...\n", filePath, r);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NSLog(@"[%@] Adhoc signing worked!\n", filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
fat = fat_init_from_path(filePath.fileSystemRepresentation);
|
|
||||||
if (!fat) return 175; // This should never happen, if it does then everything is fucked
|
|
||||||
|
|
||||||
// Now apply CoreTrust bypass to best slice
|
|
||||||
MachO *machoForExtraction = fat_find_preferred_slice(fat);
|
MachO *machoForExtraction = fat_find_preferred_slice(fat);
|
||||||
if (machoForExtraction) {
|
if (machoForExtraction) {
|
||||||
|
// Extract best slice
|
||||||
NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
|
NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
|
||||||
MemoryStream *sliceStream = macho_get_stream(machoForExtraction);
|
MemoryStream *sliceStream = macho_get_stream(machoForExtraction);
|
||||||
MemoryStream *sliceOutStream = file_stream_init_from_path(tmpPath.fileSystemRepresentation, 0, 0, FILE_STREAM_FLAG_WRITABLE | FILE_STREAM_FLAG_AUTO_EXPAND);
|
MemoryStream *sliceOutStream = file_stream_init_from_path(tmpPath.fileSystemRepresentation, 0, 0, FILE_STREAM_FLAG_WRITABLE | FILE_STREAM_FLAG_AUTO_EXPAND);
|
||||||
|
@ -592,12 +652,10 @@ int signApp(NSString* appPath)
|
||||||
memory_stream_copy_data(sliceStream, 0, sliceOutStream, 0, memory_stream_get_size(sliceStream));
|
memory_stream_copy_data(sliceStream, 0, sliceOutStream, 0, memory_stream_get_size(sliceStream));
|
||||||
memory_stream_free(sliceOutStream);
|
memory_stream_free(sliceOutStream);
|
||||||
|
|
||||||
// Now we have the single slice at tmpPath, which we will sign and apply the bypass, then copy over the original file
|
// Now we have the best slice at tmpPath, which we will apply the bypass to, then copy it over the original file
|
||||||
|
// We loose all other slices doing that but they aren't a loss as they wouldn't run either way
|
||||||
NSLog(@"[%@] Adhoc signing...", filePath);
|
|
||||||
|
|
||||||
NSLog(@"[%@] Applying CoreTrust bypass...", filePath);
|
NSLog(@"[%@] Applying CoreTrust bypass...", filePath);
|
||||||
r = apply_coretrust_bypass(tmpPath.fileSystemRepresentation);
|
int r = apply_coretrust_bypass(tmpPath.fileSystemRepresentation);
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
NSLog(@"[%@] Applied CoreTrust bypass!", filePath);
|
NSLog(@"[%@] Applied CoreTrust bypass!", filePath);
|
||||||
}
|
}
|
||||||
|
@ -614,39 +672,9 @@ int signApp(NSString* appPath)
|
||||||
}
|
}
|
||||||
fat_free(fat);
|
fat_free(fat);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
NSURL* fileURL;
|
|
||||||
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil];
|
|
||||||
while(fileURL = [enumerator nextObject])
|
|
||||||
{
|
|
||||||
NSString *filePath = fileURL.path;
|
|
||||||
if (isSameFile(filePath, mainExecutablePath)) {
|
|
||||||
// Skip main executable, we will sign it at the end
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int r = signFile(filePath, nil);
|
|
||||||
if (r != 0) return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the case where the main executable currently has no entitlements at all
|
return 0;
|
||||||
// We want to ensure it gets signed with fallback entitlements
|
|
||||||
// These mimic the entitlements that Xcodes gives every app it signs
|
|
||||||
NSDictionary *entitlementsToUse = nil;
|
|
||||||
NSDictionary* mainExecutableEntitlements = dumpEntitlementsFromBinaryAtPath(mainExecutablePath);
|
|
||||||
if (!mainExecutableEntitlements) {
|
|
||||||
entitlementsToUse = @{
|
|
||||||
@"application-identifier" : @"TROLLTROLL.*",
|
|
||||||
@"com.apple.developer.team-identifier" : @"TROLLTROLL",
|
|
||||||
@"get-task-allow" : (__bridge id)kCFBooleanTrue,
|
|
||||||
@"keychain-access-groups" : @[
|
|
||||||
@"TROLLTROLL.*",
|
|
||||||
@"com.apple.token"
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return signFile(mainExecutablePath, entitlementsToUse);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue