TrollStore/RootHelper/uicache.m

255 lines
10 KiB
Mathematica
Raw Normal View History

2022-09-02 23:19:48 +08:00
@import Foundation;
@import CoreServices;
#import "CoreServices.h"
#import <objc/runtime.h>
#import "dlfcn.h"
2022-11-21 01:27:14 +08:00
#import <TSUtil.h>
2022-11-30 06:46:01 +08:00
#import <version.h>
2022-09-02 23:19:48 +08:00
2022-09-04 00:49:53 +08:00
// uicache on steroids
2022-10-19 03:38:43 +08:00
extern NSSet<NSString*>* immutableAppBundleIdentifiers(void);
extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath);
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
NSDictionary *constructGroupsContainersForEntitlements(NSDictionary *entitlements, BOOL systemGroups) {
if (!entitlements) return nil;
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
NSString *entitlementForGroups;
2023-01-26 07:39:58 +08:00
Class mcmClass;
2023-11-28 19:02:31 +08:00
if (systemGroups) {
2022-09-04 00:49:53 +08:00
entitlementForGroups = @"com.apple.security.system-groups";
2023-01-26 07:39:58 +08:00
mcmClass = [MCMSystemDataContainer class];
2022-09-04 00:49:53 +08:00
}
2023-11-28 19:02:31 +08:00
else {
2022-09-04 00:49:53 +08:00
entitlementForGroups = @"com.apple.security.application-groups";
2023-01-26 07:39:58 +08:00
mcmClass = [MCMSharedDataContainer class];
2022-09-04 00:49:53 +08:00
}
2023-11-28 19:02:31 +08:00
NSArray *groupIDs = entitlements[entitlementForGroups];
if (groupIDs && [groupIDs isKindOfClass:[NSArray class]]) {
NSMutableDictionary *groupContainers = [NSMutableDictionary new];
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
for (NSString *groupID in groupIDs) {
MCMContainer *container = [mcmClass containerWithIdentifier:groupID createIfNecessary:YES existed:nil error:nil];
if (container.url) {
2022-09-04 00:49:53 +08:00
groupContainers[groupID] = container.url.path;
}
}
return groupContainers.copy;
}
return nil;
}
BOOL constructContainerizationForEntitlements(NSDictionary *entitlements, NSString **customContainerOut) {
2023-11-28 19:02:31 +08:00
NSNumber *noContainer = entitlements[@"com.apple.private.security.no-container"];
if (noContainer && [noContainer isKindOfClass:[NSNumber class]]) {
if (noContainer.boolValue) {
2022-09-04 00:49:53 +08:00
return NO;
}
}
NSObject *containerRequired = entitlements[@"com.apple.private.security.container-required"];
2023-11-28 19:02:31 +08:00
if (containerRequired && [containerRequired isKindOfClass:[NSNumber class]]) {
if (!((NSNumber *)containerRequired).boolValue) {
2022-09-04 00:49:53 +08:00
return NO;
}
}
else if (containerRequired && [containerRequired isKindOfClass:[NSString class]]) {
*customContainerOut = (NSString *)containerRequired;
}
2022-09-04 00:49:53 +08:00
return YES;
}
2023-11-28 19:02:31 +08:00
NSString *constructTeamIdentifierForEntitlements(NSDictionary *entitlements) {
NSString *teamIdentifier = entitlements[@"com.apple.developer.team-identifier"];
if (teamIdentifier && [teamIdentifier isKindOfClass:[NSString class]]) {
2022-09-04 00:49:53 +08:00
return teamIdentifier;
}
return nil;
}
2023-11-28 19:02:31 +08:00
NSDictionary *constructEnvironmentVariablesForContainerPath(NSString *containerPath, BOOL isContainerized) {
NSString *homeDir = isContainerized ? containerPath : @"/var/mobile";
NSString *tmpDir = isContainerized ? [containerPath stringByAppendingPathComponent:@"tmp"] : @"/var/tmp";
2022-09-04 00:49:53 +08:00
return @{
2023-11-28 19:02:31 +08:00
@"CFFIXED_USER_HOME" : homeDir,
@"HOME" : homeDir,
2022-09-04 00:49:53 +08:00
@"TMPDIR" : tmpDir
};
}
bool registerPath(NSString *path, BOOL unregister, BOOL forceSystem) {
if (!path) return false;
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
LSApplicationWorkspace *workspace = [LSApplicationWorkspace defaultWorkspace];
if (unregister && ![[NSFileManager defaultManager] fileExistsAtPath:path]) {
LSApplicationProxy *app = [LSApplicationProxy applicationProxyForIdentifier:path];
if (app.bundleURL) {
2022-09-04 00:49:53 +08:00
path = [app bundleURL].path;
}
}
2023-11-28 19:02:31 +08:00
path = path.stringByResolvingSymlinksInPath.stringByStandardizingPath;
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
NSDictionary *appInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]];
NSString *appBundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"];
2022-09-04 00:49:53 +08:00
if([immutableAppBundleIdentifiers() containsObject:appBundleID.lowercaseString]) return false;
2022-10-18 02:30:49 +08:00
2023-11-28 19:02:31 +08:00
if (appBundleID && !unregister) {
NSString *appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]];
NSDictionary *entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath);
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;
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
BOOL isRemovableSystemApp = [[NSFileManager defaultManager] fileExistsAtPath:[@"/System/Library/AppSignatures" stringByAppendingPathComponent:appBundleID]];
BOOL registerAsUser = [path hasPrefix:@"/var/containers"] && !isRemovableSystemApp && !forceSystem;
NSMutableDictionary *dictToRegister = [NSMutableDictionary dictionary];
2022-09-04 00:49:53 +08:00
// Add entitlements
2023-11-28 19:02:31 +08:00
if (entitlements) {
2022-09-04 00:49:53 +08:00
dictToRegister[@"Entitlements"] = entitlements;
}
// Misc
2023-11-28 19:02:31 +08:00
dictToRegister[@"ApplicationType"] = registerAsUser ? @"User" : @"System";
2022-09-04 00:49:53 +08:00
dictToRegister[@"CFBundleIdentifier"] = appBundleID;
dictToRegister[@"CodeInfoIdentifier"] = appBundleID;
dictToRegister[@"CompatibilityState"] = @0;
2023-11-28 19:02:31 +08:00
dictToRegister[@"IsContainerized"] = @(appContainerized);
if (containerPath) {
2022-09-04 00:49:53 +08:00
dictToRegister[@"Container"] = containerPath;
2023-11-28 19:02:31 +08:00
dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath, appContainerized);
2022-09-04 00:49:53 +08:00
}
2023-11-28 19:41:53 +08:00
dictToRegister[@"IsDeletable"] = @(![appBundleID isEqualToString:@"com.opa334.TrollStore"] && kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_15_0);
2022-09-04 00:49:53 +08:00
dictToRegister[@"Path"] = path;
2023-11-28 19:02:31 +08:00
2022-09-05 20:48:06 +08:00
dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
dictToRegister[@"SignatureVersion"] = @132352;
dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
2022-09-10 02:22:34 +08:00
dictToRegister[@"IsAdHocSigned"] = @YES;
dictToRegister[@"LSInstallType"] = @1;
2022-09-22 23:38:58 +08:00
dictToRegister[@"HasMIDBasedSINF"] = @0;
dictToRegister[@"MissingSINF"] = @0;
dictToRegister[@"FamilyID"] = @0;
dictToRegister[@"IsOnDemandInstallCapable"] = @0;
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
NSString *teamIdentifier = constructTeamIdentifierForEntitlements(entitlements);
if (teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier;
2022-09-04 00:49:53 +08:00
// Add group containers
2023-11-28 19:02:31 +08:00
NSDictionary *appGroupContainers = constructGroupsContainersForEntitlements(entitlements, NO);
NSDictionary *systemGroupContainers = constructGroupsContainersForEntitlements(entitlements, YES);
NSMutableDictionary *groupContainers = [NSMutableDictionary new];
2022-09-04 00:49:53 +08:00
[groupContainers addEntriesFromDictionary:appGroupContainers];
[groupContainers addEntriesFromDictionary:systemGroupContainers];
2023-11-28 19:02:31 +08:00
if (groupContainers.count) {
if (appGroupContainers.count) {
2022-09-04 00:49:53 +08:00
dictToRegister[@"HasAppGroupContainers"] = @YES;
}
2023-11-28 19:02:31 +08:00
if (systemGroupContainers.count) {
2022-09-04 00:49:53 +08:00
dictToRegister[@"HasSystemGroupContainers"] = @YES;
}
dictToRegister[@"GroupContainers"] = groupContainers.copy;
}
// Add plugins
2023-11-28 19:02:31 +08:00
NSString *pluginsPath = [path stringByAppendingPathComponent:@"PlugIns"];
NSArray *plugins = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pluginsPath error:nil];
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
NSMutableDictionary *bundlePlugins = [NSMutableDictionary dictionary];
for (NSString *pluginName in plugins) {
NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:pluginName];
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
NSDictionary *pluginInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[pluginPath stringByAppendingPathComponent:@"Info.plist"]];
NSString *pluginBundleID = [pluginInfoPlist objectForKey:@"CFBundleIdentifier"];
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
if (!pluginBundleID) continue;
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];
2023-11-28 19:02:31 +08:00
NSString *pluginContainerPath = [pluginContainer url].path;
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
NSMutableDictionary *pluginDict = [NSMutableDictionary dictionary];
2022-09-04 00:49:53 +08:00
// Add entitlements
2023-11-28 19:02:31 +08:00
if (pluginEntitlements) {
2022-09-04 00:49:53 +08:00
pluginDict[@"Entitlements"] = pluginEntitlements;
}
// Misc
pluginDict[@"ApplicationType"] = @"PluginKitPlugin";
pluginDict[@"CFBundleIdentifier"] = pluginBundleID;
pluginDict[@"CodeInfoIdentifier"] = pluginBundleID;
pluginDict[@"CompatibilityState"] = @0;
2023-11-28 19:02:31 +08:00
pluginDict[@"IsContainerized"] = @(pluginContainerized);
if (pluginContainerPath) {
2022-09-04 00:49:53 +08:00
pluginDict[@"Container"] = pluginContainerPath;
2023-11-28 19:02:31 +08:00
pluginDict[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(pluginContainerPath, pluginContainerized);
2022-09-04 00:49:53 +08:00
}
pluginDict[@"Path"] = pluginPath;
pluginDict[@"PluginOwnerBundleID"] = appBundleID;
2022-09-05 20:48:06 +08:00
pluginDict[@"SignerOrganization"] = @"Apple Inc.";
pluginDict[@"SignatureVersion"] = @132352;
pluginDict[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
2022-09-04 00:49:53 +08:00
2023-11-28 19:02:31 +08:00
NSString *pluginTeamIdentifier = constructTeamIdentifierForEntitlements(pluginEntitlements);
if (pluginTeamIdentifier) pluginDict[@"TeamIdentifier"] = pluginTeamIdentifier;
2022-09-04 00:49:53 +08:00
// Add plugin group containers
2023-11-28 19:02:31 +08:00
NSDictionary *pluginAppGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, NO);
NSDictionary *pluginSystemGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, YES);
NSMutableDictionary *pluginGroupContainers = [NSMutableDictionary new];
2022-09-04 00:49:53 +08:00
[pluginGroupContainers addEntriesFromDictionary:pluginAppGroupContainers];
[pluginGroupContainers addEntriesFromDictionary:pluginSystemGroupContainers];
2023-11-28 19:02:31 +08:00
if (pluginGroupContainers.count) {
if (pluginAppGroupContainers.count) {
2022-09-04 00:49:53 +08:00
pluginDict[@"HasAppGroupContainers"] = @YES;
}
2023-11-28 19:02:31 +08:00
if (pluginSystemGroupContainers.count) {
2022-09-04 00:49:53 +08:00
pluginDict[@"HasSystemGroupContainers"] = @YES;
}
pluginDict[@"GroupContainers"] = pluginGroupContainers.copy;
}
[bundlePlugins setObject:pluginDict forKey:pluginBundleID];
}
[dictToRegister setObject:bundlePlugins forKey:@"_LSBundlePlugins"];
2023-11-28 19:02:31 +08:00
if (![workspace registerApplicationDictionary:dictToRegister]) {
2022-09-04 00:49:53 +08:00
NSLog(@"Error: Unable to register %@", path);
NSLog(@"Used dictionary: {");
[dictToRegister enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSObject *obj, BOOL *stop) {
NSLog(@"%@ = %@", key, obj);
}];
NSLog(@"}");
return false;
2022-09-04 00:49:53 +08:00
}
2023-11-28 19:02:31 +08:00
} else {
NSURL *url = [NSURL fileURLWithPath:path];
if (![workspace unregisterApplication:url]) {
NSLog(@"Error: Unable to register %@", path);
return false;
2022-09-04 00:49:53 +08:00
}
}
return true;
}