mirror of https://github.com/opa334/TrollStore.git
Compare commits
5 Commits
3fe3e7f241
...
9e27e74fc9
Author | SHA1 | Date |
---|---|---|
opa334 | 9e27e74fc9 | |
opa334 | 18612495b3 | |
opa334 | a22414d34a | |
opa334 | accf995dfc | |
opa334 | 1699abd9ab |
|
@ -1,6 +1,6 @@
|
||||||
Package: com.opa334.trollstoreroothelper
|
Package: com.opa334.trollstoreroothelper
|
||||||
Name: trollstoreroothelper
|
Name: trollstoreroothelper
|
||||||
Version: 2.0.5
|
Version: 2.0.6
|
||||||
Architecture: iphoneos-arm
|
Architecture: iphoneos-arm
|
||||||
Description: An awesome tool of some sort!!
|
Description: An awesome tool of some sort!!
|
||||||
Maintainer: opa334
|
Maintainer: opa334
|
||||||
|
|
|
@ -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;
|
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
|
|
||||||
// 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
|
||||||
|
|
||||||
|
|
|
@ -11,33 +11,27 @@
|
||||||
extern NSSet<NSString*>* immutableAppBundleIdentifiers(void);
|
extern NSSet<NSString*>* immutableAppBundleIdentifiers(void);
|
||||||
extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath);
|
extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath);
|
||||||
|
|
||||||
NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups)
|
NSDictionary *constructGroupsContainersForEntitlements(NSDictionary *entitlements, BOOL systemGroups) {
|
||||||
{
|
|
||||||
if (!entitlements) return nil;
|
if (!entitlements) return nil;
|
||||||
|
|
||||||
NSString *entitlementForGroups;
|
NSString *entitlementForGroups;
|
||||||
Class mcmClass;
|
Class mcmClass;
|
||||||
if(systemGroups)
|
if (systemGroups) {
|
||||||
{
|
|
||||||
entitlementForGroups = @"com.apple.security.system-groups";
|
entitlementForGroups = @"com.apple.security.system-groups";
|
||||||
mcmClass = [MCMSystemDataContainer class];
|
mcmClass = [MCMSystemDataContainer class];
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
entitlementForGroups = @"com.apple.security.application-groups";
|
entitlementForGroups = @"com.apple.security.application-groups";
|
||||||
mcmClass = [MCMSharedDataContainer class];
|
mcmClass = [MCMSharedDataContainer class];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSArray *groupIDs = entitlements[entitlementForGroups];
|
NSArray *groupIDs = entitlements[entitlementForGroups];
|
||||||
if(groupIDs && [groupIDs isKindOfClass:[NSArray class]])
|
if (groupIDs && [groupIDs isKindOfClass:[NSArray class]]) {
|
||||||
{
|
|
||||||
NSMutableDictionary *groupContainers = [NSMutableDictionary new];
|
NSMutableDictionary *groupContainers = [NSMutableDictionary new];
|
||||||
|
|
||||||
for(NSString* groupID in groupIDs)
|
for (NSString *groupID in groupIDs) {
|
||||||
{
|
|
||||||
MCMContainer *container = [mcmClass containerWithIdentifier:groupID createIfNecessary:YES existed:nil error:nil];
|
MCMContainer *container = [mcmClass containerWithIdentifier:groupID createIfNecessary:YES existed:nil error:nil];
|
||||||
if(container.url)
|
if (container.url) {
|
||||||
{
|
|
||||||
groupContainers[groupID] = container.url.path;
|
groupContainers[groupID] = container.url.path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,100 +42,98 @@ NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlement
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL constructContainerizationForEntitlements(NSDictionary* entitlements)
|
BOOL constructContainerizationForEntitlements(NSDictionary *entitlements, NSString **customContainerOut) {
|
||||||
{
|
|
||||||
NSNumber *noContainer = entitlements[@"com.apple.private.security.no-container"];
|
NSNumber *noContainer = entitlements[@"com.apple.private.security.no-container"];
|
||||||
if(noContainer && [noContainer isKindOfClass:[NSNumber class]])
|
if (noContainer && [noContainer isKindOfClass:[NSNumber class]]) {
|
||||||
{
|
if (noContainer.boolValue) {
|
||||||
if(noContainer.boolValue)
|
|
||||||
{
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NSNumber* containerRequired = entitlements[@"com.apple.private.security.container-required"];
|
NSObject *containerRequired = entitlements[@"com.apple.private.security.container-required"];
|
||||||
if(containerRequired && [containerRequired isKindOfClass:[NSNumber class]])
|
if (containerRequired && [containerRequired isKindOfClass:[NSNumber class]]) {
|
||||||
{
|
if (!((NSNumber *)containerRequired).boolValue) {
|
||||||
if(!containerRequired.boolValue)
|
|
||||||
{
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (containerRequired && [containerRequired isKindOfClass:[NSString class]]) {
|
||||||
|
*customContainerOut = (NSString *)containerRequired;
|
||||||
|
}
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* constructTeamIdentifierForEntitlements(NSDictionary* entitlements)
|
NSString *constructTeamIdentifierForEntitlements(NSDictionary *entitlements) {
|
||||||
{
|
|
||||||
NSString *teamIdentifier = entitlements[@"com.apple.developer.team-identifier"];
|
NSString *teamIdentifier = entitlements[@"com.apple.developer.team-identifier"];
|
||||||
if(teamIdentifier && [teamIdentifier isKindOfClass:[NSString class]])
|
if (teamIdentifier && [teamIdentifier isKindOfClass:[NSString class]]) {
|
||||||
{
|
|
||||||
return teamIdentifier;
|
return teamIdentifier;
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSDictionary* constructEnvironmentVariablesForContainerPath(NSString* containerPath)
|
NSDictionary *constructEnvironmentVariablesForContainerPath(NSString *containerPath, BOOL isContainerized) {
|
||||||
{
|
NSString *homeDir = isContainerized ? containerPath : @"/var/mobile";
|
||||||
NSString* tmpDir = [containerPath stringByAppendingPathComponent:@"tmp"];
|
NSString *tmpDir = isContainerized ? [containerPath stringByAppendingPathComponent:@"tmp"] : @"/var/tmp";
|
||||||
return @{
|
return @{
|
||||||
@"CFFIXED_USER_HOME" : containerPath,
|
@"CFFIXED_USER_HOME" : homeDir,
|
||||||
@"HOME" : containerPath,
|
@"HOME" : homeDir,
|
||||||
@"TMPDIR" : tmpDir
|
@"TMPDIR" : tmpDir
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerPath(NSString* path, BOOL unregister, BOOL system)
|
void registerPath(NSString *path, BOOL unregister, BOOL forceSystem) {
|
||||||
{
|
|
||||||
if (!path) return;
|
if (!path) return;
|
||||||
|
|
||||||
LSApplicationWorkspace *workspace = [LSApplicationWorkspace defaultWorkspace];
|
LSApplicationWorkspace *workspace = [LSApplicationWorkspace defaultWorkspace];
|
||||||
if(unregister && ![[NSFileManager defaultManager] fileExistsAtPath:path])
|
if (unregister && ![[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||||
{
|
|
||||||
LSApplicationProxy *app = [LSApplicationProxy applicationProxyForIdentifier:path];
|
LSApplicationProxy *app = [LSApplicationProxy applicationProxyForIdentifier:path];
|
||||||
if(app.bundleURL)
|
if (app.bundleURL) {
|
||||||
{
|
|
||||||
path = [app bundleURL].path;
|
path = [app bundleURL].path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path = [path stringByResolvingSymlinksInPath];
|
path = path.stringByResolvingSymlinksInPath.stringByStandardizingPath;
|
||||||
|
|
||||||
NSDictionary *appInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]];
|
NSDictionary *appInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]];
|
||||||
NSString *appBundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"];
|
NSString *appBundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"];
|
||||||
|
|
||||||
if([immutableAppBundleIdentifiers() containsObject:appBundleID.lowercaseString]) return;
|
if([immutableAppBundleIdentifiers() containsObject:appBundleID.lowercaseString]) return;
|
||||||
|
|
||||||
if(appBundleID && !unregister)
|
if (appBundleID && !unregister) {
|
||||||
{
|
NSString *appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]];
|
||||||
MCMContainer* appContainer = [NSClassFromString(@"MCMAppDataContainer") containerWithIdentifier:appBundleID createIfNecessary:YES existed:nil error:nil];
|
NSDictionary *entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath);
|
||||||
NSString* containerPath = [appContainer url].path;
|
|
||||||
|
NSString *appDataContainerID = appBundleID;
|
||||||
|
BOOL appContainerized = constructContainerizationForEntitlements(entitlements, &appDataContainerID);
|
||||||
|
|
||||||
|
MCMContainer *appDataContainer = [NSClassFromString(@"MCMAppDataContainer") containerWithIdentifier:appDataContainerID createIfNecessary:YES existed:nil error:nil];
|
||||||
|
NSString *containerPath = [appDataContainer url].path;
|
||||||
|
|
||||||
|
BOOL isRemovableSystemApp = [[NSFileManager defaultManager] fileExistsAtPath:[@"/System/Library/AppSignatures" stringByAppendingPathComponent:appBundleID]];
|
||||||
|
BOOL registerAsUser = [path hasPrefix:@"/var/containers"] && !isRemovableSystemApp && !forceSystem;
|
||||||
|
|
||||||
NSMutableDictionary *dictToRegister = [NSMutableDictionary dictionary];
|
NSMutableDictionary *dictToRegister = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
// Add entitlements
|
// Add entitlements
|
||||||
|
|
||||||
NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]];
|
if (entitlements) {
|
||||||
NSDictionary* entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath);
|
|
||||||
if(entitlements)
|
|
||||||
{
|
|
||||||
dictToRegister[@"Entitlements"] = entitlements;
|
dictToRegister[@"Entitlements"] = entitlements;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
|
|
||||||
dictToRegister[@"ApplicationType"] = system ? @"System" : @"User";
|
dictToRegister[@"ApplicationType"] = registerAsUser ? @"User" : @"System";
|
||||||
dictToRegister[@"CFBundleIdentifier"] = appBundleID;
|
dictToRegister[@"CFBundleIdentifier"] = appBundleID;
|
||||||
dictToRegister[@"CodeInfoIdentifier"] = appBundleID;
|
dictToRegister[@"CodeInfoIdentifier"] = appBundleID;
|
||||||
dictToRegister[@"CompatibilityState"] = @0;
|
dictToRegister[@"CompatibilityState"] = @0;
|
||||||
if(containerPath)
|
dictToRegister[@"IsContainerized"] = @(appContainerized);
|
||||||
{
|
if (containerPath) {
|
||||||
dictToRegister[@"Container"] = containerPath;
|
dictToRegister[@"Container"] = containerPath;
|
||||||
dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath);
|
dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath, appContainerized);
|
||||||
}
|
}
|
||||||
dictToRegister[@"IsDeletable"] = @(![appBundleID isEqualToString:@"com.opa334.TrollStore"] && kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_15_0);
|
dictToRegister[@"IsDeletable"] = @(registerAsUser || isRemovableSystemApp);
|
||||||
dictToRegister[@"Path"] = path;
|
dictToRegister[@"Path"] = path;
|
||||||
dictToRegister[@"IsContainerized"] = @(constructContainerizationForEntitlements(entitlements));
|
|
||||||
dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
|
dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
|
||||||
dictToRegister[@"SignatureVersion"] = @132352;
|
dictToRegister[@"SignatureVersion"] = @132352;
|
||||||
dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
|
dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
|
||||||
|
@ -162,14 +154,11 @@ void registerPath(NSString* path, BOOL unregister, BOOL system)
|
||||||
NSMutableDictionary *groupContainers = [NSMutableDictionary new];
|
NSMutableDictionary *groupContainers = [NSMutableDictionary new];
|
||||||
[groupContainers addEntriesFromDictionary:appGroupContainers];
|
[groupContainers addEntriesFromDictionary:appGroupContainers];
|
||||||
[groupContainers addEntriesFromDictionary:systemGroupContainers];
|
[groupContainers addEntriesFromDictionary:systemGroupContainers];
|
||||||
if(groupContainers.count)
|
if (groupContainers.count) {
|
||||||
{
|
if (appGroupContainers.count) {
|
||||||
if(appGroupContainers.count)
|
|
||||||
{
|
|
||||||
dictToRegister[@"HasAppGroupContainers"] = @YES;
|
dictToRegister[@"HasAppGroupContainers"] = @YES;
|
||||||
}
|
}
|
||||||
if(systemGroupContainers.count)
|
if (systemGroupContainers.count) {
|
||||||
{
|
|
||||||
dictToRegister[@"HasSystemGroupContainers"] = @YES;
|
dictToRegister[@"HasSystemGroupContainers"] = @YES;
|
||||||
}
|
}
|
||||||
dictToRegister[@"GroupContainers"] = groupContainers.copy;
|
dictToRegister[@"GroupContainers"] = groupContainers.copy;
|
||||||
|
@ -181,25 +170,25 @@ void registerPath(NSString* path, BOOL unregister, BOOL system)
|
||||||
NSArray *plugins = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pluginsPath error:nil];
|
NSArray *plugins = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pluginsPath error:nil];
|
||||||
|
|
||||||
NSMutableDictionary *bundlePlugins = [NSMutableDictionary dictionary];
|
NSMutableDictionary *bundlePlugins = [NSMutableDictionary dictionary];
|
||||||
for (NSString* pluginName in plugins)
|
for (NSString *pluginName in plugins) {
|
||||||
{
|
|
||||||
NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:pluginName];
|
NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:pluginName];
|
||||||
|
|
||||||
NSDictionary *pluginInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[pluginPath stringByAppendingPathComponent:@"Info.plist"]];
|
NSDictionary *pluginInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[pluginPath stringByAppendingPathComponent:@"Info.plist"]];
|
||||||
NSString *pluginBundleID = [pluginInfoPlist objectForKey:@"CFBundleIdentifier"];
|
NSString *pluginBundleID = [pluginInfoPlist objectForKey:@"CFBundleIdentifier"];
|
||||||
|
|
||||||
if (!pluginBundleID) continue;
|
if (!pluginBundleID) continue;
|
||||||
MCMContainer* pluginContainer = [NSClassFromString(@"MCMPluginKitPluginDataContainer") containerWithIdentifier:pluginBundleID createIfNecessary:YES existed:nil error:nil];
|
NSString *pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]];
|
||||||
|
NSDictionary *pluginEntitlements = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath);
|
||||||
|
NSString *pluginDataContainerID = pluginBundleID;
|
||||||
|
BOOL pluginContainerized = constructContainerizationForEntitlements(pluginEntitlements, &pluginDataContainerID);
|
||||||
|
|
||||||
|
MCMContainer *pluginContainer = [NSClassFromString(@"MCMPluginKitPluginDataContainer") containerWithIdentifier:pluginDataContainerID createIfNecessary:YES existed:nil error:nil];
|
||||||
NSString *pluginContainerPath = [pluginContainer url].path;
|
NSString *pluginContainerPath = [pluginContainer url].path;
|
||||||
|
|
||||||
NSMutableDictionary *pluginDict = [NSMutableDictionary dictionary];
|
NSMutableDictionary *pluginDict = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
// Add entitlements
|
// Add entitlements
|
||||||
|
if (pluginEntitlements) {
|
||||||
NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]];
|
|
||||||
NSDictionary* pluginEntitlements = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath);
|
|
||||||
if(pluginEntitlements)
|
|
||||||
{
|
|
||||||
pluginDict[@"Entitlements"] = pluginEntitlements;
|
pluginDict[@"Entitlements"] = pluginEntitlements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,14 +198,14 @@ void registerPath(NSString* path, BOOL unregister, BOOL system)
|
||||||
pluginDict[@"CFBundleIdentifier"] = pluginBundleID;
|
pluginDict[@"CFBundleIdentifier"] = pluginBundleID;
|
||||||
pluginDict[@"CodeInfoIdentifier"] = pluginBundleID;
|
pluginDict[@"CodeInfoIdentifier"] = pluginBundleID;
|
||||||
pluginDict[@"CompatibilityState"] = @0;
|
pluginDict[@"CompatibilityState"] = @0;
|
||||||
if(pluginContainerPath)
|
|
||||||
{
|
pluginDict[@"IsContainerized"] = @(pluginContainerized);
|
||||||
|
if (pluginContainerPath) {
|
||||||
pluginDict[@"Container"] = pluginContainerPath;
|
pluginDict[@"Container"] = pluginContainerPath;
|
||||||
pluginDict[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(pluginContainerPath);
|
pluginDict[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(pluginContainerPath, pluginContainerized);
|
||||||
}
|
}
|
||||||
pluginDict[@"Path"] = pluginPath;
|
pluginDict[@"Path"] = pluginPath;
|
||||||
pluginDict[@"PluginOwnerBundleID"] = appBundleID;
|
pluginDict[@"PluginOwnerBundleID"] = appBundleID;
|
||||||
pluginDict[@"IsContainerized"] = @(constructContainerizationForEntitlements(pluginEntitlements));
|
|
||||||
pluginDict[@"SignerOrganization"] = @"Apple Inc.";
|
pluginDict[@"SignerOrganization"] = @"Apple Inc.";
|
||||||
pluginDict[@"SignatureVersion"] = @132352;
|
pluginDict[@"SignatureVersion"] = @132352;
|
||||||
pluginDict[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
|
pluginDict[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
|
||||||
|
@ -231,14 +220,11 @@ void registerPath(NSString* path, BOOL unregister, BOOL system)
|
||||||
NSMutableDictionary *pluginGroupContainers = [NSMutableDictionary new];
|
NSMutableDictionary *pluginGroupContainers = [NSMutableDictionary new];
|
||||||
[pluginGroupContainers addEntriesFromDictionary:pluginAppGroupContainers];
|
[pluginGroupContainers addEntriesFromDictionary:pluginAppGroupContainers];
|
||||||
[pluginGroupContainers addEntriesFromDictionary:pluginSystemGroupContainers];
|
[pluginGroupContainers addEntriesFromDictionary:pluginSystemGroupContainers];
|
||||||
if(pluginGroupContainers.count)
|
if (pluginGroupContainers.count) {
|
||||||
{
|
if (pluginAppGroupContainers.count) {
|
||||||
if(pluginAppGroupContainers.count)
|
|
||||||
{
|
|
||||||
pluginDict[@"HasAppGroupContainers"] = @YES;
|
pluginDict[@"HasAppGroupContainers"] = @YES;
|
||||||
}
|
}
|
||||||
if(pluginSystemGroupContainers.count)
|
if (pluginSystemGroupContainers.count) {
|
||||||
{
|
|
||||||
pluginDict[@"HasSystemGroupContainers"] = @YES;
|
pluginDict[@"HasSystemGroupContainers"] = @YES;
|
||||||
}
|
}
|
||||||
pluginDict[@"GroupContainers"] = pluginGroupContainers.copy;
|
pluginDict[@"GroupContainers"] = pluginGroupContainers.copy;
|
||||||
|
@ -248,17 +234,13 @@ void registerPath(NSString* path, BOOL unregister, BOOL system)
|
||||||
}
|
}
|
||||||
[dictToRegister setObject:bundlePlugins forKey:@"_LSBundlePlugins"];
|
[dictToRegister setObject:bundlePlugins forKey:@"_LSBundlePlugins"];
|
||||||
|
|
||||||
if(![workspace registerApplicationDictionary:dictToRegister])
|
if (![workspace registerApplicationDictionary:dictToRegister]) {
|
||||||
{
|
NSLog(@"Error: Unable to register %@", path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSURL *url = [NSURL fileURLWithPath:path];
|
||||||
|
if (![workspace unregisterApplication:url]) {
|
||||||
NSLog(@"Error: Unable to register %@", path);
|
NSLog(@"Error: Unable to register %@", path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
NSURL* url = [NSURL fileURLWithPath:path];
|
|
||||||
if(![workspace unregisterApplication:url])
|
|
||||||
{
|
|
||||||
NSLog(@"Error: Unable to unregister %@", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
<string>iPhoneOS</string>
|
<string>iPhoneOS</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2.0.5</string>
|
<string>2.0.6</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIDeviceFamily</key>
|
<key>UIDeviceFamily</key>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Package: com.opa334.trollstorehelper
|
Package: com.opa334.trollstorehelper
|
||||||
Name: TrollStore Helper
|
Name: TrollStore Helper
|
||||||
Version: 2.0.5
|
Version: 2.0.6
|
||||||
Architecture: iphoneos-arm
|
Architecture: iphoneos-arm
|
||||||
Description: Helper utility to install and manage TrollStore!
|
Description: Helper utility to install and manage TrollStore!
|
||||||
Maintainer: opa334
|
Maintainer: opa334
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
<string>iPhoneOS</string>
|
<string>iPhoneOS</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2.0.5</string>
|
<string>2.0.6</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIDeviceFamily</key>
|
<key>UIDeviceFamily</key>
|
||||||
|
|
|
@ -849,16 +849,37 @@ extern UIImage* imageWithSize(UIImage* image, CGSize size);
|
||||||
__block NSMutableArray* accessibleContainers = [NSMutableArray new]; //array by design, should be ordered
|
__block NSMutableArray* accessibleContainers = [NSMutableArray new]; //array by design, should be ordered
|
||||||
if(!unrestrictedContainerAccess)
|
if(!unrestrictedContainerAccess)
|
||||||
{
|
{
|
||||||
|
__block NSString *dataContainer = nil;
|
||||||
|
|
||||||
|
// If com.apple.private.security.container-required Entitlement is a string, prefer it to CFBundleIdentifier
|
||||||
|
[self enumerateAllEntitlements:^(NSString *key, NSObject *value, BOOL *stop) {
|
||||||
|
if([key isEqualToString:@"com.apple.private.security.container-required"])
|
||||||
|
{
|
||||||
|
NSString* valueString = (NSString*)value;
|
||||||
|
if(valueString && [valueString isKindOfClass:NSString.class])
|
||||||
|
{
|
||||||
|
dataContainer = valueString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Else take CFBundleIdentifier
|
||||||
|
if (!dataContainer) {
|
||||||
[self enumerateAllInfoDictionaries:^(NSString *key, NSObject *value, BOOL *stop) {
|
[self enumerateAllInfoDictionaries:^(NSString *key, NSObject *value, BOOL *stop) {
|
||||||
if([key isEqualToString:@"CFBundleIdentifier"])
|
if([key isEqualToString:@"CFBundleIdentifier"])
|
||||||
{
|
{
|
||||||
NSString* valueStr = (NSString*)value;
|
NSString* valueStr = (NSString*)value;
|
||||||
if([valueStr isKindOfClass:NSString.class])
|
if([valueStr isKindOfClass:NSString.class])
|
||||||
{
|
{
|
||||||
[accessibleContainers addObject:valueStr];
|
dataContainer = valueStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataContainer) {
|
||||||
|
[accessibleContainers addObject:dataContainer];
|
||||||
|
}
|
||||||
|
|
||||||
[self enumerateAllEntitlements:^(NSString *key, NSObject *value, BOOL *stop)
|
[self enumerateAllEntitlements:^(NSString *key, NSObject *value, BOOL *stop)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Package: com.opa334.trollstore
|
Package: com.opa334.trollstore
|
||||||
Name: TrollStore
|
Name: TrollStore
|
||||||
Version: 2.0.5
|
Version: 2.0.6
|
||||||
Architecture: iphoneos-arm
|
Architecture: iphoneos-arm
|
||||||
Description: An awesome application!
|
Description: An awesome application!
|
||||||
Maintainer: opa334
|
Maintainer: opa334
|
||||||
|
|
Loading…
Reference in New Issue