TrollStore/RootHelper/uicache.m

265 lines
9.0 KiB
Objective-C

@import Foundation;
@import CoreServices;
#import "CoreServices.h"
#import <objc/runtime.h>
#import "dlfcn.h"
#import <TSUtil.h>
#import <version.h>
// uicache on steroids
extern NSSet<NSString*>* immutableAppBundleIdentifiers(void);
extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath);
NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups)
{
if(!entitlements) return nil;
NSString* entitlementForGroups;
Class mcmClass;
if(systemGroups)
{
entitlementForGroups = @"com.apple.security.system-groups";
mcmClass = [MCMSystemDataContainer class];
}
else
{
entitlementForGroups = @"com.apple.security.application-groups";
mcmClass = [MCMSharedDataContainer class];
}
NSArray* groupIDs = entitlements[entitlementForGroups];
if(groupIDs && [groupIDs isKindOfClass:[NSArray class]])
{
NSMutableDictionary* groupContainers = [NSMutableDictionary new];
for(NSString* groupID in groupIDs)
{
MCMContainer* container = [mcmClass containerWithIdentifier:groupID createIfNecessary:YES existed:nil error:nil];
if(container.url)
{
groupContainers[groupID] = container.url.path;
}
}
return groupContainers.copy;
}
return nil;
}
BOOL constructContainerizationForEntitlements(NSDictionary* entitlements)
{
NSNumber* noContainer = entitlements[@"com.apple.private.security.no-container"];
if(noContainer && [noContainer isKindOfClass:[NSNumber class]])
{
if(noContainer.boolValue)
{
return NO;
}
}
NSNumber* containerRequired = entitlements[@"com.apple.private.security.container-required"];
if(containerRequired && [containerRequired isKindOfClass:[NSNumber class]])
{
if(!containerRequired.boolValue)
{
return NO;
}
}
return YES;
}
NSString* constructTeamIdentifierForEntitlements(NSDictionary* entitlements)
{
NSString* teamIdentifier = entitlements[@"com.apple.developer.team-identifier"];
if(teamIdentifier && [teamIdentifier isKindOfClass:[NSString class]])
{
return teamIdentifier;
}
return nil;
}
NSDictionary* constructEnvironmentVariablesForContainerPath(NSString* containerPath)
{
NSString* tmpDir = [containerPath stringByAppendingPathComponent:@"tmp"];
return @{
@"CFFIXED_USER_HOME" : containerPath,
@"HOME" : containerPath,
@"TMPDIR" : tmpDir
};
}
void registerPath(NSString* path, BOOL unregister, BOOL system)
{
if(!path) return;
LSApplicationWorkspace* workspace = [LSApplicationWorkspace defaultWorkspace];
if(unregister && ![[NSFileManager defaultManager] fileExistsAtPath:path])
{
LSApplicationProxy* app = [LSApplicationProxy applicationProxyForIdentifier:path];
if(app.bundleURL)
{
path = [app bundleURL].path;
}
}
path = [path stringByResolvingSymlinksInPath];
NSDictionary* appInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]];
NSString* appBundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"];
if([immutableAppBundleIdentifiers() containsObject:appBundleID.lowercaseString]) return;
if(appBundleID && !unregister)
{
MCMContainer* appContainer = [NSClassFromString(@"MCMAppDataContainer") containerWithIdentifier:appBundleID createIfNecessary:YES existed:nil error:nil];
NSString* containerPath = [appContainer url].path;
NSMutableDictionary* dictToRegister = [NSMutableDictionary dictionary];
// Add entitlements
NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]];
NSDictionary* entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath);
if(entitlements)
{
dictToRegister[@"Entitlements"] = entitlements;
}
// Misc
dictToRegister[@"ApplicationType"] = system ? @"System" : @"User";
dictToRegister[@"CFBundleIdentifier"] = appBundleID;
dictToRegister[@"CodeInfoIdentifier"] = appBundleID;
dictToRegister[@"CompatibilityState"] = @0;
if(containerPath)
{
dictToRegister[@"Container"] = containerPath;
dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath);
}
dictToRegister[@"IsDeletable"] = @(![appBundleID isEqualToString:@"com.opa334.TrollStore"] && kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_15_0);
dictToRegister[@"Path"] = path;
dictToRegister[@"IsContainerized"] = @(constructContainerizationForEntitlements(entitlements));
dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
dictToRegister[@"SignatureVersion"] = @132352;
dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
dictToRegister[@"IsAdHocSigned"] = @YES;
dictToRegister[@"LSInstallType"] = @1;
dictToRegister[@"HasMIDBasedSINF"] = @0;
dictToRegister[@"MissingSINF"] = @0;
dictToRegister[@"FamilyID"] = @0;
dictToRegister[@"IsOnDemandInstallCapable"] = @0;
NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements);
if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier;
// Add group containers
NSDictionary* appGroupContainers = constructGroupsContainersForEntitlements(entitlements, NO);
NSDictionary* systemGroupContainers = constructGroupsContainersForEntitlements(entitlements, YES);
NSMutableDictionary* groupContainers = [NSMutableDictionary new];
[groupContainers addEntriesFromDictionary:appGroupContainers];
[groupContainers addEntriesFromDictionary:systemGroupContainers];
if(groupContainers.count)
{
if(appGroupContainers.count)
{
dictToRegister[@"HasAppGroupContainers"] = @YES;
}
if(systemGroupContainers.count)
{
dictToRegister[@"HasSystemGroupContainers"] = @YES;
}
dictToRegister[@"GroupContainers"] = groupContainers.copy;
}
// Add plugins
NSString* pluginsPath = [path stringByAppendingPathComponent:@"PlugIns"];
NSArray* plugins = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pluginsPath error:nil];
NSMutableDictionary* bundlePlugins = [NSMutableDictionary dictionary];
for (NSString* pluginName in plugins)
{
NSString* pluginPath = [pluginsPath stringByAppendingPathComponent:pluginName];
NSDictionary* pluginInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[pluginPath stringByAppendingPathComponent:@"Info.plist"]];
NSString* pluginBundleID = [pluginInfoPlist objectForKey:@"CFBundleIdentifier"];
if(!pluginBundleID) continue;
MCMContainer* pluginContainer = [NSClassFromString(@"MCMPluginKitPluginDataContainer") containerWithIdentifier:pluginBundleID createIfNecessary:YES existed:nil error:nil];
NSString* pluginContainerPath = [pluginContainer url].path;
NSMutableDictionary* pluginDict = [NSMutableDictionary dictionary];
// Add entitlements
NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]];
NSDictionary* pluginEntitlements = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath);
if(pluginEntitlements)
{
pluginDict[@"Entitlements"] = pluginEntitlements;
}
// Misc
pluginDict[@"ApplicationType"] = @"PluginKitPlugin";
pluginDict[@"CFBundleIdentifier"] = pluginBundleID;
pluginDict[@"CodeInfoIdentifier"] = pluginBundleID;
pluginDict[@"CompatibilityState"] = @0;
if(pluginContainerPath)
{
pluginDict[@"Container"] = pluginContainerPath;
pluginDict[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(pluginContainerPath);
}
pluginDict[@"Path"] = pluginPath;
pluginDict[@"PluginOwnerBundleID"] = appBundleID;
pluginDict[@"IsContainerized"] = @(constructContainerizationForEntitlements(pluginEntitlements));
pluginDict[@"SignerOrganization"] = @"Apple Inc.";
pluginDict[@"SignatureVersion"] = @132352;
pluginDict[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
NSString* pluginTeamIdentifier = constructTeamIdentifierForEntitlements(pluginEntitlements);
if(pluginTeamIdentifier) pluginDict[@"TeamIdentifier"] = pluginTeamIdentifier;
// Add plugin group containers
NSDictionary* pluginAppGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, NO);
NSDictionary* pluginSystemGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, NO);
NSMutableDictionary* pluginGroupContainers = [NSMutableDictionary new];
[pluginGroupContainers addEntriesFromDictionary:pluginAppGroupContainers];
[pluginGroupContainers addEntriesFromDictionary:pluginSystemGroupContainers];
if(pluginGroupContainers.count)
{
if(pluginAppGroupContainers.count)
{
pluginDict[@"HasAppGroupContainers"] = @YES;
}
if(pluginSystemGroupContainers.count)
{
pluginDict[@"HasSystemGroupContainers"] = @YES;
}
pluginDict[@"GroupContainers"] = pluginGroupContainers.copy;
}
[bundlePlugins setObject:pluginDict forKey:pluginBundleID];
}
[dictToRegister setObject:bundlePlugins forKey:@"_LSBundlePlugins"];
if(![workspace registerApplicationDictionary:dictToRegister])
{
NSLog(@"Error: Unable to register %@", path);
}
}
else
{
NSURL* url = [NSURL fileURLWithPath:path];
if(![workspace unregisterApplication:url])
{
NSLog(@"Error: Unable to unregister %@", path);
}
}
}