2022-09-02 23:19:48 +08:00
# import < stdio . h >
# import "unarchive.h"
@ import Foundation ;
# import "uicache.h"
# import < sys / stat . h >
# import < dlfcn . h >
# import < spawn . h >
# import < objc / runtime . h >
2022-10-12 04:57:08 +08:00
# import < TSUtil . h >
2022-09-04 06:48:40 +08:00
# import < sys / utsname . h >
2022-11-01 06:39:28 +08:00
# import < mach - o / loader . h >
# import < mach - o / fat . h >
2023-11-27 00:51:03 +08:00
# ifndef EMBEDDED_ROOT _HELPER
2023-11-27 03:43:30 +08:00
# import "codesign.h"
2023-11-27 00:43:01 +08:00
# import "coretrust_bug.h"
2023-11-27 01:29:32 +08:00
# import < choma / FAT . h >
# import < choma / MachO . h >
# import < choma / FileStream . h >
# import < choma / Host . h >
2023-11-27 00:51:03 +08:00
# endif
2022-09-02 23:19:48 +08:00
# import < SpringBoardServices / SpringBoardServices . h >
2022-09-06 03:39:17 +08:00
# import < Security / Security . h >
2022-09-05 04:18:59 +08:00
2022-10-12 04:57:08 +08:00
# ifdef EMBEDDED_ROOT _HELPER
2022-10-07 07:25:20 +08:00
# define MAIN_NAME rootHelperMain
# else
# define MAIN_NAME main
# endif
2022-09-05 04:18:59 +08:00
2022-11-20 22:33:54 +08:00
void cleanRestrictions ( void ) ;
2022-09-05 21:09:31 +08:00
extern mach_msg _return _t SBReloadIconForIdentifier ( mach_port _t machport , const char * identifier ) ;
@ interface SBSHomeScreenService : NSObject
- ( void ) reloadIcons ;
@ end
extern NSString * BKSActivateForEventOptionTypeBackgroundContentFetching ;
extern NSString * BKSOpenApplicationOptionKeyActivateForEvent ;
2022-09-05 04:18:59 +08:00
2022-09-05 21:09:31 +08:00
extern void BKSTerminateApplicationForReasonAndReportWithDescription ( NSString * bundleID , int reasonID , bool report , NSString * description ) ;
2022-09-05 04:18:59 +08:00
2022-09-02 23:19:48 +08:00
# define kCFPreferencesNoContainer CFSTR ( "kCFPreferencesNoContainer" )
typedef CFPropertyListRef ( * _CFPreferencesCopyValueWithContainerType ) ( CFStringRef key , CFStringRef applicationID , CFStringRef userName , CFStringRef hostName , CFStringRef containerPath ) ;
typedef void ( * _CFPreferencesSetValueWithContainerType ) ( CFStringRef key , CFPropertyListRef value , CFStringRef applicationID , CFStringRef userName , CFStringRef hostName , CFStringRef containerPath ) ;
typedef Boolean ( * _CFPreferencesSynchronizeWithContainerType ) ( CFStringRef applicationID , CFStringRef userName , CFStringRef hostName , CFStringRef containerPath ) ;
typedef CFArrayRef ( * _CFPreferencesCopyKeyListWithContainerType ) ( CFStringRef applicationID , CFStringRef userName , CFStringRef hostName , CFStringRef containerPath ) ;
typedef CFDictionaryRef ( * _CFPreferencesCopyMultipleWithContainerType ) ( CFArrayRef keysToFetch , CFStringRef applicationID , CFStringRef userName , CFStringRef hostName , CFStringRef containerPath ) ;
BOOL _installPersistenceHelper ( LSApplicationProxy * appProxy , NSString * sourcePersistenceHelper , NSString * sourceRootHelper ) ;
2022-09-10 02:22:34 +08:00
NSArray < LSApplicationProxy * > * applicationsWithGroupId ( NSString * groupId )
{
LSEnumerator * enumerator = [ LSEnumerator enumeratorForApplicationProxiesWithOptions : 0 ] ;
enumerator . predicate = [ NSPredicate predicateWithFormat : @ "groupContainerURLs[%@] != nil" , groupId ] ;
return enumerator . allObjects ;
}
2022-11-30 06:46:01 +08:00
NSSet < NSString * > * systemURLSchemes ( void )
2022-09-10 02:22:34 +08:00
{
LSEnumerator * enumerator = [ LSEnumerator enumeratorForApplicationProxiesWithOptions : 0 ] ;
2022-11-30 06:46:01 +08:00
NSMutableSet * systemURLSchemesSet = [ NSMutableSet new ] ;
2022-09-10 02:22:34 +08:00
LSApplicationProxy * proxy ;
while ( proxy = [ enumerator nextObject ] )
{
2022-11-30 06:46:01 +08:00
if ( isRemovableSystemApp ( proxy . bundleIdentifier ) || ! [ proxy . bundleURL . path hasPrefix : @ "/private/var/containers" ] )
2022-11-20 06:22:20 +08:00
{
2022-11-30 06:46:01 +08:00
for ( NSString * claimedURLScheme in proxy . claimedURLSchemes )
2022-11-20 06:22:20 +08:00
{
2022-11-30 06:46:01 +08:00
if ( [ claimedURLScheme isKindOfClass : NSString . class ] )
{
[ systemURLSchemesSet addObject : claimedURLScheme . lowercaseString ] ;
}
2022-11-20 06:22:20 +08:00
}
}
2022-09-10 02:22:34 +08:00
}
2022-11-30 06:46:01 +08:00
return systemURLSchemesSet . copy ;
2022-09-10 02:22:34 +08:00
}
2022-10-19 03:38:43 +08:00
NSSet < NSString * > * immutableAppBundleIdentifiers ( void )
2022-10-18 02:30:49 +08:00
{
NSMutableSet * systemAppIdentifiers = [ NSMutableSet new ] ;
2022-10-19 03:38:43 +08:00
LSEnumerator * enumerator = [ LSEnumerator enumeratorForApplicationProxiesWithOptions : 0 ] ;
LSApplicationProxy * appProxy ;
while ( appProxy = [ enumerator nextObject ] )
2022-10-18 02:30:49 +08:00
{
2022-10-19 03:38:43 +08:00
if ( appProxy . installed )
{
if ( ! [ appProxy . bundleURL . path hasPrefix : @ "/private/var/containers" ] )
{
[ systemAppIdentifiers addObject : appProxy . bundleIdentifier . lowercaseString ] ;
}
}
2022-10-18 02:30:49 +08:00
}
return systemAppIdentifiers . copy ;
}
2022-09-02 23:19:48 +08:00
NSDictionary * infoDictionaryForAppPath ( NSString * appPath )
{
2022-11-20 06:22:20 +08:00
if ( ! appPath ) return nil ;
2022-09-02 23:19:48 +08:00
NSString * infoPlistPath = [ appPath stringByAppendingPathComponent : @ "Info.plist" ] ;
return [ NSDictionary dictionaryWithContentsOfFile : infoPlistPath ] ;
}
NSString * appIdForAppPath ( NSString * appPath )
{
2022-11-20 06:22:20 +08:00
if ( ! appPath ) return nil ;
2022-09-02 23:19:48 +08:00
return infoDictionaryForAppPath ( appPath ) [ @ "CFBundleIdentifier" ] ;
}
2022-09-10 02:22:34 +08:00
NSString * appMainExecutablePathForAppPath ( NSString * appPath )
{
2022-11-20 06:22:20 +08:00
if ( ! appPath ) return nil ;
2022-09-10 02:22:34 +08:00
return [ appPath stringByAppendingPathComponent : infoDictionaryForAppPath ( appPath ) [ @ "CFBundleExecutable" ] ] ;
}
NSString * appPathForAppId ( NSString * appId )
2022-09-02 23:19:48 +08:00
{
2022-11-20 06:22:20 +08:00
if ( ! appId ) return nil ;
2022-09-02 23:19:48 +08:00
for ( NSString * appPath in trollStoreInstalledAppBundlePaths ( ) )
{
if ( [ appIdForAppPath ( appPath ) isEqualToString : appId ] )
{
return appPath ;
}
}
return nil ;
}
2023-01-21 20:52:39 +08:00
NSString * findAppNameInBundlePath ( NSString * bundlePath )
{
NSArray * bundleItems = [ [ NSFileManager defaultManager ] contentsOfDirectoryAtPath : bundlePath error : nil ] ;
for ( NSString * bundleItem in bundleItems )
{
if ( [ bundleItem . pathExtension isEqualToString : @ "app" ] )
{
return bundleItem ;
}
}
return nil ;
}
NSString * findAppPathInBundlePath ( NSString * bundlePath )
{
NSString * appName = findAppNameInBundlePath ( bundlePath ) ;
if ( ! appName ) return nil ;
return [ bundlePath stringByAppendingPathComponent : appName ] ;
}
NSURL * findAppURLInBundleURL ( NSURL * bundleURL )
{
NSString * appName = findAppNameInBundlePath ( bundleURL . path ) ;
if ( ! appName ) return nil ;
return [ bundleURL URLByAppendingPathComponent : appName ] ;
}
2022-11-01 06:39:28 +08:00
BOOL isMachoFile ( NSString * filePath )
{
2022-11-20 06:22:20 +08:00
FILE * file = fopen ( filePath . fileSystemRepresentation , "r" ) ;
2022-11-01 06:39:28 +08:00
if ( ! file ) return NO ;
fseek ( file , 0 , SEEK_SET ) ;
uint32_t magic ;
fread ( & magic , sizeof ( uint32_t ) , 1 , file ) ;
fclose ( file ) ;
return magic = = FAT_MAGIC || magic = = FAT_CIGAM || magic = = MH_MAGIC _64 || magic = = MH_CIGAM _64 ;
}
void fixPermissionsOfAppBundle ( NSString * appBundlePath )
{
// Apply correct permissions ( First run , set everything to 644 , owner 33 )
NSURL * fileURL ;
NSDirectoryEnumerator * enumerator = [ [ NSFileManager defaultManager ] enumeratorAtURL : [ NSURL fileURLWithPath : appBundlePath ] includingPropertiesForKeys : nil options : 0 errorHandler : nil ] ;
while ( fileURL = [ enumerator nextObject ] )
{
NSString * filePath = fileURL . path ;
2022-11-20 06:22:20 +08:00
chown ( filePath . fileSystemRepresentation , 33 , 33 ) ;
chmod ( filePath . fileSystemRepresentation , 0644 ) ;
2022-11-01 06:39:28 +08:00
}
// Apply correct permissions ( Second run , set executables and directories to 0755 )
enumerator = [ [ NSFileManager defaultManager ] enumeratorAtURL : [ NSURL fileURLWithPath : appBundlePath ] includingPropertiesForKeys : nil options : 0 errorHandler : nil ] ;
while ( fileURL = [ enumerator nextObject ] )
{
NSString * filePath = fileURL . path ;
BOOL isDir ;
[ [ NSFileManager defaultManager ] fileExistsAtPath : fileURL . path isDirectory : & isDir ] ;
if ( isDir || isMachoFile ( filePath ) )
{
2022-11-20 06:22:20 +08:00
chmod ( filePath . fileSystemRepresentation , 0755 ) ;
2022-11-01 06:39:28 +08:00
}
}
2022-11-20 06:22:20 +08:00
}
NSArray * TSURLScheme ( void )
{
return @ [
@ {
@ "CFBundleURLName" : @ "com.apple.Magnifier" ,
@ "CFBundleURLSchemes" : @ [
@ "apple-magnifier"
]
}
] ;
}
2022-11-01 06:39:28 +08:00
2022-11-20 06:22:20 +08:00
BOOL getTSURLSchemeState ( NSString * customAppPath )
{
NSString * pathToUse = customAppPath ? : trollStoreAppPath ( ) ;
NSDictionary * trollStoreInfoDict = infoDictionaryForAppPath ( pathToUse ) ;
return ( BOOL ) trollStoreInfoDict [ @ "CFBundleURLTypes" ] ;
2022-11-01 06:39:28 +08:00
}
2022-11-20 06:22:20 +08:00
void setTSURLSchemeState ( BOOL newState , NSString * customAppPath )
{
NSString * tsAppPath = trollStoreAppPath ( ) ;
NSString * pathToUse = customAppPath ? : tsAppPath ;
if ( newState ! = getTSURLSchemeState ( pathToUse ) )
{
NSDictionary * trollStoreInfoDict = infoDictionaryForAppPath ( pathToUse ) ;
NSMutableDictionary * trollStoreInfoDictM = trollStoreInfoDict . mutableCopy ;
if ( newState )
{
trollStoreInfoDictM [ @ "CFBundleURLTypes" ] = TSURLScheme ( ) ;
}
else
{
[ trollStoreInfoDictM removeObjectForKey : @ "CFBundleURLTypes" ] ;
}
NSString * outPath = [ pathToUse stringByAppendingPathComponent : @ "Info.plist" ] ;
[ trollStoreInfoDictM . copy writeToURL : [ NSURL fileURLWithPath : outPath ] error : nil ] ;
}
}
2023-11-28 08:04:40 +08:00
void installLdid ( NSString * ldidToCopyPath , NSString * ldidVersion )
{
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : ldidToCopyPath ] ) return ;
NSString * ldidPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "ldid" ] ;
NSString * ldidVersionPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "ldid.version" ] ;
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : ldidPath ] )
{
[ [ NSFileManager defaultManager ] removeItemAtPath : ldidPath error : nil ] ;
}
[ [ NSFileManager defaultManager ] copyItemAtPath : ldidToCopyPath toPath : ldidPath error : nil ] ;
NSData * ldidVersionData = [ ldidVersion dataUsingEncoding : NSUTF8StringEncoding ] ;
[ ldidVersionData writeToFile : ldidVersionPath atomically : YES ] ;
chmod ( ldidPath . fileSystemRepresentation , 0755 ) ;
chmod ( ldidVersionPath . fileSystemRepresentation , 0644 ) ;
}
BOOL isLdidInstalled ( void )
{
NSString * ldidPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "ldid" ] ;
return [ [ NSFileManager defaultManager ] fileExistsAtPath : ldidPath ] ;
}
int runLdid ( NSArray * args , NSString * * output , NSString * * errorOutput )
{
NSString * ldidPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "ldid" ] ;
NSMutableArray * argsM = args . mutableCopy ? : [ NSMutableArray new ] ;
[ argsM insertObject : ldidPath . lastPathComponent atIndex : 0 ] ;
NSUInteger argCount = [ argsM count ] ;
char * * argsC = ( char * * ) malloc ( ( argCount + 1 ) * sizeof ( char * ) ) ;
for ( NSUInteger i = 0 ; i < argCount ; i + + )
{
argsC [ i ] = strdup ( [ [ argsM objectAtIndex : i ] UTF8String ] ) ;
}
argsC [ argCount ] = NULL ;
posix_spawn _file _actions _t action ;
posix_spawn _file _actions _init ( & action ) ;
int outErr [ 2 ] ;
pipe ( outErr ) ;
posix_spawn _file _actions _adddup2 ( & action , outErr [ 1 ] , STDERR_FILENO ) ;
posix_spawn _file _actions _addclose ( & action , outErr [ 0 ] ) ;
int out [ 2 ] ;
pipe ( out ) ;
posix_spawn _file _actions _adddup2 ( & action , out [ 1 ] , STDOUT_FILENO ) ;
posix_spawn _file _actions _addclose ( & action , out [ 0 ] ) ;
pid_t task_pid ;
int status = -200 ;
int spawnError = posix_spawn ( & task_pid , [ ldidPath fileSystemRepresentation ] , & action , NULL , ( char * const * ) argsC , NULL ) ;
for ( NSUInteger i = 0 ; i < argCount ; i + + )
{
free ( argsC [ i ] ) ;
}
free ( argsC ) ;
if ( spawnError ! = 0 )
{
NSLog ( @ "posix_spawn error %d\n" , spawnError ) ;
return spawnError ;
}
do
{
if ( waitpid ( task_pid , & status , 0 ) ! = -1 ) {
// printf ( "Child status %dn" , WEXITSTATUS ( status ) ) ;
} else
{
perror ( "waitpid" ) ;
return -222 ;
}
} while ( ! WIFEXITED ( status ) && ! WIFSIGNALED ( status ) ) ;
close ( outErr [ 1 ] ) ;
close ( out [ 1 ] ) ;
NSString * ldidOutput = getNSStringFromFile ( out [ 0 ] ) ;
if ( output )
{
* output = ldidOutput ;
}
NSString * ldidErrorOutput = getNSStringFromFile ( outErr [ 0 ] ) ;
if ( errorOutput )
{
* errorOutput = ldidErrorOutput ;
}
return WEXITSTATUS ( status ) ;
}
2022-09-06 03:39:17 +08:00
BOOL certificateHasDataForExtensionOID ( SecCertificateRef certificate , CFStringRef oidString )
{
2022-09-06 07:04:45 +08:00
if ( certificate = = NULL || oidString = = NULL )
{
NSLog ( @ "[certificateHasDataForExtensionOID] attempted to check null certificate or OID" ) ;
return NO ;
}
CFDataRef extensionData = SecCertificateCopyExtensionValue ( certificate , oidString , NULL ) ;
if ( extensionData ! = NULL )
{
CFRelease ( extensionData ) ;
return YES ;
}
return NO ;
2022-09-06 03:39:17 +08:00
}
2022-09-05 21:09:31 +08:00
2022-09-06 03:39:17 +08:00
BOOL codeCertChainContainsFakeAppStoreExtensions ( SecStaticCodeRef codeRef )
{
2022-09-06 07:04:45 +08:00
if ( codeRef = = NULL )
{
NSLog ( @ "[codeCertChainContainsFakeAppStoreExtensions] attempted to check cert chain of null static code object" ) ;
return NO ;
}
CFDictionaryRef signingInfo = NULL ;
OSStatus result ;
2022-09-06 03:39:17 +08:00
2022-09-06 07:04:45 +08:00
result = SecCodeCopySigningInformation ( codeRef , kSecCSSigningInformation , & signingInfo ) ;
if ( result ! = errSecSuccess )
{
NSLog ( @ "[codeCertChainContainsFakeAppStoreExtensions] failed to copy signing info from static code" ) ;
return NO ;
}
CFArrayRef certificates = CFDictionaryGetValue ( signingInfo , kSecCodeInfoCertificates ) ;
2022-09-06 07:04:10 +08:00
if ( certificates = = NULL || CFArrayGetCount ( certificates ) = = 0 )
{
return NO ;
}
2022-09-06 03:39:17 +08:00
2022-09-06 07:04:45 +08:00
// If we match the standard Apple policy , we are signed properly , but we haven ' t been deliberately signed with a custom root
SecPolicyRef appleAppStorePolicy = SecPolicyCreateWithProperties ( kSecPolicyAppleiPhoneApplicationSigning , NULL ) ;
SecTrustRef trust = NULL ;
SecTrustCreateWithCertificates ( certificates , appleAppStorePolicy , & trust ) ;
if ( SecTrustEvaluateWithError ( trust , nil ) )
{
CFRelease ( trust ) ;
CFRelease ( appleAppStorePolicy ) ;
CFRelease ( signingInfo ) ;
NSLog ( @ "[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (App Store)" ) ;
return NO ;
}
// We haven ' t matched Apple , so keep going . Is the app profile signed ?
CFRelease ( appleAppStorePolicy ) ;
SecPolicyRef appleProfileSignedPolicy = SecPolicyCreateWithProperties ( kSecPolicyAppleiPhoneProfileApplicationSigning , NULL ) ;
if ( SecTrustSetPolicies ( trust , appleProfileSignedPolicy ) ! = errSecSuccess )
{
NSLog ( @ "[codeCertChainContainsFakeAppStoreExtensions] error replacing trust policy to check for profile-signed app" ) ;
CFRelease ( trust ) ;
CFRelease ( signingInfo ) ;
return NO ;
}
if ( SecTrustEvaluateWithError ( trust , nil ) )
{
CFRelease ( trust ) ;
CFRelease ( appleProfileSignedPolicy ) ;
CFRelease ( signingInfo ) ;
NSLog ( @ "[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple (profile-signed)" ) ;
return NO ;
}
// Still haven ' t matched Apple . Are we using a custom root that would take the App Store fastpath ?
CFRelease ( appleProfileSignedPolicy ) ;
// Cert chain should be of length 3
if ( CFArrayGetCount ( certificates ) ! = 3 )
{
CFRelease ( signingInfo ) ;
NSLog ( @ "[codeCertChainContainsFakeAppStoreExtensions] certificate chain length != 3" ) ;
return NO ;
}
// AppleCodeSigning only checks for the codeSigning EKU by default
SecPolicyRef customRootPolicy = SecPolicyCreateWithProperties ( kSecPolicyAppleCodeSigning , NULL ) ;
SecPolicySetOptionsValue ( customRootPolicy , CFSTR ( "LeafMarkerOid" ) , CFSTR ( "1.2.840.113635.100.6.1.3" ) ) ;
if ( SecTrustSetPolicies ( trust , customRootPolicy ) ! = errSecSuccess )
{
NSLog ( @ "[codeCertChainContainsFakeAppStoreExtensions] error replacing trust policy to check for custom root" ) ;
CFRelease ( trust ) ;
CFRelease ( signingInfo ) ;
return NO ;
}
// Need to add our certificate chain to the anchor as it is expected to be a self - signed root
SecTrustSetAnchorCertificates ( trust , certificates ) ;
BOOL evaluatesToCustomAnchor = SecTrustEvaluateWithError ( trust , nil ) ;
NSLog ( @ "[codeCertChainContainsFakeAppStoreExtensions] app signed with non-Apple certificate %@ using valid custom certificates" , evaluatesToCustomAnchor ? @ "IS" : @ "is NOT" ) ;
CFRelease ( trust ) ;
CFRelease ( customRootPolicy ) ;
CFRelease ( signingInfo ) ;
return evaluatesToCustomAnchor ;
2022-09-04 00:49:53 +08:00
}
2023-11-27 04:41:10 +08:00
BOOL isSameFile ( NSString * path1 , NSString * path2 )
{
struct stat sb1 ;
struct stat sb2 ;
stat ( path1 . fileSystemRepresentation , & sb1 ) ;
stat ( path2 . fileSystemRepresentation , & sb2 ) ;
return sb1 . st_ino = = sb2 . st_ino ;
}
2023-11-27 01:29:32 +08:00
# ifdef EMBEDDED_ROOT _HELPER
// The embedded root helper is not able to sign apps
// But it does not need that functionality anyways
int signApp ( NSString * appPath )
{
return -1 ;
}
# else
2023-11-28 08:04:40 +08:00
int signAdhoc ( NSString * filePath , NSDictionary * entitlements )
{
2023-11-28 10:36:02 +08:00
// if ( @ available ( iOS 16 , * ) ) {
// return codesign_sign _adhoc ( filePath . fileSystemRepresentation , true , entitlements ) ;
// }
2023-11-28 08:04:40 +08:00
// If iOS 14 is so great , how come there is no iOS 14 2 ? ? ? ? ?
2023-11-28 10:36:02 +08:00
// else {
2023-11-28 08:04:40 +08:00
if ( ! isLdidInstalled ( ) ) return 173 ;
NSString * entitlementsPath = nil ;
NSString * signArg = @ "-s" ;
NSString * errorOutput ;
if ( entitlements )
{
NSData * entitlementsXML = [ NSPropertyListSerialization dataWithPropertyList : entitlements format : NSPropertyListXMLFormat_v1 _0 options : 0 error : nil ] ;
if ( entitlementsXML ) {
entitlementsPath = [ [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : [ NSUUID UUID ] . UUIDString ] stringByAppendingPathExtension : @ "plist" ] ;
[ entitlementsXML writeToFile : entitlementsPath atomically : NO ] ;
signArg = [ @ "-S" stringByAppendingString : entitlementsPath ] ;
}
}
int ldidRet = runLdid ( @ [ signArg , filePath ] , nil , & errorOutput ) ;
if ( entitlementsPath ) {
[ [ NSFileManager defaultManager ] removeItemAtPath : entitlementsPath error : nil ] ;
}
NSLog ( @ "ldid exited with status %d" , ldidRet ) ;
NSLog ( @ "- ldid error output start -" ) ;
printMultilineNSString ( errorOutput ) ;
NSLog ( @ "- ldid error output end -" ) ;
if ( ldidRet = = 0 )
{
return 0 ;
}
else
{
return 175 ;
}
2023-11-28 10:36:02 +08:00
// }
2023-11-28 08:04:40 +08:00
}
2022-09-10 02:22:34 +08:00
int signApp ( NSString * appPath )
2022-09-02 23:19:48 +08:00
{
2022-09-10 02:22:34 +08:00
NSDictionary * appInfoDict = infoDictionaryForAppPath ( appPath ) ;
if ( ! appInfoDict ) return 172 ;
2022-09-02 23:19:48 +08:00
2023-11-27 04:41:10 +08:00
NSString * mainExecutablePath = appMainExecutablePathForAppPath ( appPath ) ;
if ( ! mainExecutablePath ) return 176 ;
2022-09-02 23:19:48 +08:00
2023-11-27 04:41:10 +08:00
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : mainExecutablePath ] ) return 174 ;
2023-11-29 05:44:12 +08:00
// Check if the bundle has had a supported exploit pre - applied
EXPLOIT_TYPE declaredPreAppliedExploitType = getDeclaredExploitTypeFromInfoDictionary ( appInfoDict ) ;
if ( isPlatformVulnerableToExploitType ( declaredPreAppliedExploitType ) )
2022-09-06 07:04:45 +08:00
{
2023-11-29 05:44:12 +08:00
NSLog ( @ "[signApp] taking fast path for app which declares use of a supported pre-applied exploit (%@)" , mainExecutablePath ) ;
return 0 ;
}
else
{
NSLog ( @ "[signApp] app (%@) declares use of a pre-applied exploit that is not supported on this device. Proceeding to re-sign..." , mainExecutablePath ) ;
2022-09-06 07:04:45 +08:00
}
2023-01-21 20:52:39 +08:00
2023-11-29 05:44:12 +08:00
// If the app doesn ' t declare a pre - applied exploit , and the host supports fake custom root certs ,
// we can also skip doing any work here when that app is signed with fake roots
// If not , with the new bypass , a previously modified binary should failed to be adhoc signed , and
// reapplying the bypass should produce an identical binary
if ( isPlatformVulnerableToExploitType ( EXPLOIT_TYPE _CUSTOM _ROOT _CERTIFICATE _V1 ) )
2023-11-27 04:41:10 +08:00
{
2023-11-29 05:44:12 +08:00
SecStaticCodeRef codeRef = getStaticCodeRef ( mainExecutablePath ) ;
if ( codeRef ! = NULL )
2023-11-27 04:41:10 +08:00
{
2023-11-29 05:44:12 +08:00
if ( codeCertChainContainsFakeAppStoreExtensions ( codeRef ) )
{
NSLog ( @ "[signApp] taking fast path for app signed using a custom root certificate (%@)" , mainExecutablePath ) ;
CFRelease ( codeRef ) ;
return 0 ;
}
2023-11-27 04:41:10 +08:00
CFRelease ( codeRef ) ;
}
}
2023-11-27 01:29:32 +08:00
2023-11-28 18:54:12 +08:00
NSURL * fileURL ;
NSDirectoryEnumerator * enumerator ;
2023-11-28 09:27:12 +08:00
2023-11-28 18:54:12 +08:00
// 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 ;
}
2023-11-28 09:27:12 +08:00
}
2023-11-28 18:54:12 +08:00
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 ;
2023-11-28 09:27:12 +08:00
}
2023-11-28 18:54:12 +08:00
if ( containerRequired ) {
NSObject * noContainerO = entitlementsToUse [ @ "com.apple.private.security.no-container" ] ;
BOOL noContainer = NO ;
if ( noContainerO && [ noContainerO isKindOfClass : [ NSNumber class ] ] ) {
noContainer = [ ( NSNumber * ) noContainerO boolValue ] ;
}
2023-11-28 21:12:45 +08:00
NSObject * noSandboxO = entitlementsToUse [ @ "com.apple.private.security.no-sandbox" ] ;
BOOL noSandbox = NO ;
if ( noSandboxO && [ noSandboxO isKindOfClass : [ NSNumber class ] ] ) {
noSandbox = [ ( NSNumber * ) noSandboxO boolValue ] ;
}
if ( ! noContainer && ! noSandbox ) {
2023-11-28 18:54:12 +08:00
entitlementsToUse [ @ "com.apple.private.security.container-required" ] = bundleId ;
}
}
signAdhoc ( bundleMainExecutablePath , entitlementsToUse ) ;
}
}
2023-11-28 09:27:12 +08:00
2023-11-28 18:54:12 +08:00
// 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 ) ;
if ( fat ) {
NSLog ( @ "%@ is binary" , filePath ) ;
2023-11-27 01:29:32 +08:00
MachO * machoForExtraction = fat_find _preferred _slice ( fat ) ;
if ( machoForExtraction ) {
2023-11-28 18:54:12 +08:00
// Extract best slice
2023-11-27 01:29:32 +08:00
NSString * tmpPath = [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : [ NSUUID UUID ] . UUIDString ] ;
MemoryStream * sliceStream = macho_get _stream ( machoForExtraction ) ;
2023-11-27 03:43:30 +08:00
MemoryStream * sliceOutStream = file_stream _init _from _path ( tmpPath . fileSystemRepresentation , 0 , 0 , FILE_STREAM _FLAG _WRITABLE | FILE_STREAM _FLAG _AUTO _EXPAND ) ;
if ( sliceOutStream ) {
memory_stream _copy _data ( sliceStream , 0 , sliceOutStream , 0 , memory_stream _get _size ( sliceStream ) ) ;
memory_stream _free ( sliceOutStream ) ;
2023-11-28 18:54:12 +08:00
// 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
2023-11-27 03:43:30 +08:00
NSLog ( @ "[%@] Applying CoreTrust bypass..." , filePath ) ;
2023-11-28 18:54:12 +08:00
int r = apply_coretrust _bypass ( tmpPath . fileSystemRepresentation ) ;
2023-11-27 03:43:30 +08:00
if ( r = = 0 ) {
NSLog ( @ "[%@] Applied CoreTrust bypass!" , filePath ) ;
}
else {
NSLog ( @ "[%@] CoreTrust bypass failed!!! :(" , filePath ) ;
fat_free ( fat ) ;
return 175 ;
}
// tempFile is now signed , overwrite original file at filePath with it
[ [ NSFileManager defaultManager ] removeItemAtPath : filePath error : nil ] ;
[ [ NSFileManager defaultManager ] moveItemAtPath : tmpPath toPath : filePath error : nil ] ;
2023-11-27 01:29:32 +08:00
}
}
fat_free ( fat ) ;
}
}
2023-11-28 18:54:12 +08:00
return 0 ;
2022-09-02 23:19:48 +08:00
}
2023-11-27 01:29:32 +08:00
# endif
2022-09-02 23:19:48 +08:00
2022-09-04 21:37:49 +08:00
void applyPatchesToInfoDictionary ( NSString * appPath )
{
NSURL * appURL = [ NSURL fileURLWithPath : appPath ] ;
NSURL * infoPlistURL = [ appURL URLByAppendingPathComponent : @ "Info.plist" ] ;
NSMutableDictionary * infoDictM = [ [ NSDictionary dictionaryWithContentsOfURL : infoPlistURL error : nil ] mutableCopy ] ;
if ( ! infoDictM ) return ;
2022-09-10 02:22:34 +08:00
// Enable Notifications
2022-09-04 21:37:49 +08:00
infoDictM [ @ "SBAppUsesLocalNotifications" ] = @ 1 ;
2022-09-10 02:22:34 +08:00
// Remove system claimed URL schemes if existant
2022-11-30 06:46:01 +08:00
NSSet * appleSchemes = systemURLSchemes ( ) ;
2022-09-10 02:22:34 +08:00
NSArray * CFBundleURLTypes = infoDictM [ @ "CFBundleURLTypes" ] ;
if ( [ CFBundleURLTypes isKindOfClass : [ NSArray class ] ] )
{
NSMutableArray * CFBundleURLTypesM = [ NSMutableArray new ] ;
for ( NSDictionary * URLType in CFBundleURLTypes )
{
if ( ! [ URLType isKindOfClass : [ NSDictionary class ] ] ) continue ;
NSMutableDictionary * modifiedURLType = URLType . mutableCopy ;
NSArray * URLSchemes = URLType [ @ "CFBundleURLSchemes" ] ;
if ( URLSchemes )
{
NSMutableSet * URLSchemesSet = [ NSMutableSet setWithArray : URLSchemes ] ;
2022-11-20 06:22:20 +08:00
for ( NSString * existingURLScheme in [ URLSchemesSet copy ] )
{
if ( ! [ existingURLScheme isKindOfClass : [ NSString class ] ] )
{
[ URLSchemesSet removeObject : existingURLScheme ] ;
continue ;
}
if ( [ appleSchemes containsObject : existingURLScheme . lowercaseString ] )
{
[ URLSchemesSet removeObject : existingURLScheme ] ;
}
}
2022-09-10 02:22:34 +08:00
modifiedURLType [ @ "CFBundleURLSchemes" ] = [ URLSchemesSet allObjects ] ;
}
[ CFBundleURLTypesM addObject : modifiedURLType . copy ] ;
}
infoDictM [ @ "CFBundleURLTypes" ] = CFBundleURLTypesM . copy ;
}
2022-09-04 21:37:49 +08:00
[ infoDictM writeToURL : infoPlistURL error : nil ] ;
}
2022-09-03 09:08:59 +08:00
// 170 : failed to create container for app bundle
// 171 : a non trollstore app with the same identifier is already installled
// 172 : no info . plist found in app
2023-11-28 08:04:40 +08:00
// 173 : app is not signed and cannot be signed because ldid not installed or didn ' t work
2022-09-10 02:22:34 +08:00
// 174 :
2023-01-21 20:52:39 +08:00
int installApp ( NSString * appPackagePath , BOOL sign , BOOL force , BOOL isTSUpdate , BOOL useInstalldMethod )
2022-09-02 23:19:48 +08:00
{
2022-09-04 00:49:53 +08:00
NSLog ( @ "[installApp force = %d]" , force ) ;
2022-11-20 06:22:20 +08:00
NSString * appPayloadPath = [ appPackagePath stringByAppendingPathComponent : @ "Payload" ] ;
2023-01-26 07:39:58 +08:00
NSString * appBundleToInstallPath = findAppPathInBundlePath ( appPayloadPath ) ;
2023-01-21 20:52:39 +08:00
if ( ! appBundleToInstallPath ) return 167 ;
2022-09-10 02:22:34 +08:00
2023-01-21 20:52:39 +08:00
NSString * appId = appIdForAppPath ( appBundleToInstallPath ) ;
2022-09-10 02:22:34 +08:00
if ( ! appId ) return 176 ;
2022-11-20 06:22:20 +08:00
if ( ( [ appId . lowercaseString isEqualToString : @ "com.opa334.trollstore" ] && ! isTSUpdate ) || [ immutableAppBundleIdentifiers ( ) containsObject : appId . lowercaseString ] )
2022-10-18 02:30:49 +08:00
{
return 179 ;
}
2022-09-02 23:19:48 +08:00
2023-01-21 20:52:39 +08:00
if ( ! infoDictionaryForAppPath ( appBundleToInstallPath ) ) return 172 ;
2022-11-20 06:22:20 +08:00
if ( ! isTSUpdate )
2022-10-18 02:30:49 +08:00
{
2023-01-21 20:52:39 +08:00
applyPatchesToInfoDictionary ( appBundleToInstallPath ) ;
2022-10-18 02:30:49 +08:00
}
2022-09-04 21:37:49 +08:00
2022-09-02 23:19:48 +08:00
if ( sign )
{
2023-01-21 20:52:39 +08:00
int signRet = signApp ( appBundleToInstallPath ) ;
2022-09-10 02:22:34 +08:00
if ( signRet ! = 0 ) return signRet ;
2022-09-02 23:19:48 +08:00
}
2023-01-26 07:39:58 +08:00
MCMAppContainer * appContainer = [ MCMAppContainer containerWithIdentifier : appId createIfNecessary : NO existed : nil error : nil ] ;
2023-01-21 20:52:39 +08:00
if ( appContainer )
2022-11-23 03:46:01 +08:00
{
2023-01-21 20:52:39 +08:00
// App update
// Replace existing bundle with new version
2022-11-20 06:22:20 +08:00
2023-01-21 20:52:39 +08:00
// Check if the existing app bundle is empty
NSURL * bundleContainerURL = appContainer . url ;
NSURL * appBundleURL = findAppURLInBundleURL ( bundleContainerURL ) ;
2022-09-02 23:19:48 +08:00
2023-01-21 20:52:39 +08:00
// Make sure the installed app is a TrollStore app or the container is empty ( or the force flag is set )
NSURL * trollStoreMarkURL = [ bundleContainerURL URLByAppendingPathComponent : @ "_TrollStore" ] ;
2023-01-26 07:39:58 +08:00
if ( appBundleURL && ! [ trollStoreMarkURL checkResourceIsReachableAndReturnError : nil ] && ! force )
2022-09-22 23:38:58 +08:00
{
2023-01-21 20:52:39 +08:00
NSLog ( @ "[installApp] already installed and not a TrollStore app... bailing out" ) ;
return 171 ;
2022-09-22 23:38:58 +08:00
}
2023-01-21 20:52:39 +08:00
// Terminate app if it ' s still running
if ( ! isTSUpdate )
{
BKSTerminateApplicationForReasonAndReportWithDescription ( appId , 5 , false , @ "TrollStore - App updated" ) ;
}
2022-09-02 23:19:48 +08:00
2023-01-21 20:52:39 +08:00
NSLog ( @ "[installApp] replacing existing app with new version" ) ;
2022-11-23 03:46:01 +08:00
2023-01-21 20:52:39 +08:00
// Delete existing . app directory if it exists
if ( appBundleURL )
{
[ [ NSFileManager defaultManager ] removeItemAtURL : appBundleURL error : nil ] ;
}
2022-09-02 23:19:48 +08:00
2023-01-21 20:52:39 +08:00
NSString * newAppBundlePath = [ bundleContainerURL . path stringByAppendingPathComponent : appBundleToInstallPath . lastPathComponent ] ;
NSLog ( @ "[installApp] new app path: %@" , newAppBundlePath ) ;
2022-11-23 03:46:01 +08:00
2023-01-21 20:52:39 +08:00
// Install new version into existing app bundle
NSError * copyError ;
BOOL suc = [ [ NSFileManager defaultManager ] copyItemAtPath : appBundleToInstallPath toPath : newAppBundlePath error : & copyError ] ;
if ( ! suc )
2022-09-30 03:00:11 +08:00
{
2023-01-21 20:52:39 +08:00
NSLog ( @ "[installApp] Error copying new version during update: %@" , copyError ) ;
return 178 ;
2022-11-20 06:22:20 +08:00
}
2023-01-21 20:52:39 +08:00
}
else
{
// Initial app install
BOOL systemMethodSuccessful = NO ;
if ( useInstalldMethod )
{
// System method
// Do initial placeholder installation using LSApplicationWorkspace
NSLog ( @ "[installApp] doing placeholder installation using LSApplicationWorkspace" ) ;
2023-01-26 07:39:58 +08:00
// The installApplication API ( re ) moves the app bundle , so in order to be able to later
// fall back to the custom method , we need to make a temporary copy just for using it on this API once
// Yeah this sucks , but there is no better solution unfortunately
NSError * tmpCopyError ;
NSString * lsAppPackageTmpCopy = [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : [ NSUUID UUID ] . UUIDString ] ;
if ( ! [ [ NSFileManager defaultManager ] copyItemAtPath : appPackagePath toPath : lsAppPackageTmpCopy error : & tmpCopyError ] )
{
NSLog ( @ "failed to make temporary copy of app packge: %@" , tmpCopyError ) ;
return 170 ;
}
2023-01-21 20:52:39 +08:00
NSError * installError ;
@ try
{
2023-01-26 07:39:58 +08:00
systemMethodSuccessful = [ [ LSApplicationWorkspace defaultWorkspace ] installApplication : [ NSURL fileURLWithPath : lsAppPackageTmpCopy ] withOptions : @ {
2023-01-21 20:52:39 +08:00
LSInstallTypeKey : @ 1 ,
@ "PackageType" : @ "Placeholder"
} error : & installError ] ;
}
@ catch ( NSException * e )
{
NSLog ( @ "[installApp] encountered expection %@ while trying to do placeholder install" , e ) ;
systemMethodSuccessful = NO ;
}
2022-11-23 03:46:01 +08:00
2023-01-21 20:52:39 +08:00
if ( ! systemMethodSuccessful )
{
NSLog ( @ "[installApp] encountered error %@ while trying to do placeholder install" , installError ) ;
}
2023-01-26 07:39:58 +08:00
[ [ NSFileManager defaultManager ] removeItemAtPath : lsAppPackageTmpCopy error : nil ] ;
2023-01-21 20:52:39 +08:00
}
2023-01-26 07:39:58 +08:00
2023-01-21 20:52:39 +08:00
if ( ! systemMethodSuccessful )
2022-11-20 06:22:20 +08:00
{
2023-01-21 20:52:39 +08:00
// Custom method
// Manually create app bundle via MCM apis and move app there
NSLog ( @ "[installApp] doing custom installation using MCMAppContainer" ) ;
NSError * mcmError ;
2023-01-26 07:39:58 +08:00
appContainer = [ MCMAppContainer containerWithIdentifier : appId createIfNecessary : YES existed : nil error : & mcmError ] ;
2023-01-21 20:52:39 +08:00
if ( ! appContainer || mcmError )
2022-11-23 03:46:01 +08:00
{
2023-01-21 20:52:39 +08:00
NSLog ( @ "[installApp] failed to create app container for %@: %@" , appId , mcmError ) ;
return 170 ;
}
else
{
NSLog ( @ "[installApp] created app container: %@" , appContainer ) ;
2022-11-23 03:46:01 +08:00
}
2022-09-30 03:00:11 +08:00
2023-01-21 20:52:39 +08:00
NSString * newAppBundlePath = [ appContainer . url . path stringByAppendingPathComponent : appBundleToInstallPath . lastPathComponent ] ;
NSLog ( @ "[installApp] new app path: %@" , newAppBundlePath ) ;
NSError * copyError ;
BOOL suc = [ [ NSFileManager defaultManager ] copyItemAtPath : appBundleToInstallPath toPath : newAppBundlePath error : & copyError ] ;
if ( ! suc )
{
NSLog ( @ "[installApp] Failed to copy app bundle for app %@, error: %@" , appId , copyError ) ;
return 178 ;
}
2022-11-23 03:46:01 +08:00
}
2022-11-21 01:27:14 +08:00
}
2022-09-02 23:19:48 +08:00
2023-01-26 07:39:58 +08:00
appContainer = [ MCMAppContainer containerWithIdentifier : appId createIfNecessary : NO existed : nil error : nil ] ;
2023-01-21 20:52:39 +08:00
// Mark app as TrollStore app
NSURL * trollStoreMarkURL = [ appContainer . url URLByAppendingPathComponent : @ "_TrollStore" ] ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : trollStoreMarkURL . path ] )
2022-11-23 03:46:01 +08:00
{
2023-01-21 20:52:39 +08:00
NSError * creationError ;
NSData * emptyData = [ NSData data ] ;
BOOL marked = [ emptyData writeToURL : trollStoreMarkURL options : 0 error : & creationError ] ;
if ( ! marked )
{
NSLog ( @ "[installApp] failed to mark %@ as TrollStore app by creating %@, error: %@" , appId , trollStoreMarkURL . path , creationError ) ;
return 177 ;
}
2022-09-02 23:19:48 +08:00
}
2023-01-21 20:52:39 +08:00
// At this point the ( new version of the ) app is installed but still needs to be registered
// Also permissions need to be fixed
NSURL * updatedAppURL = findAppURLInBundleURL ( appContainer . url ) ;
fixPermissionsOfAppBundle ( updatedAppURL . path ) ;
registerPath ( updatedAppURL . path , 0 , YES ) ;
return 0 ;
2022-11-20 06:22:20 +08:00
}
2023-01-21 20:52:39 +08:00
int uninstallApp ( NSString * appPath , NSString * appId , BOOL useCustomMethod )
2022-11-20 06:22:20 +08:00
{
BOOL deleteSuc = NO ;
if ( ! appId && appPath )
{
// Special case , something is wrong about this app
// Most likely the Info . plist is missing
// ( Hopefully this never happens )
deleteSuc = [ [ NSFileManager defaultManager ] removeItemAtPath : [ appPath stringByDeletingLastPathComponent ] error : nil ] ;
2022-11-30 06:46:01 +08:00
registerPath ( appPath , YES , YES ) ;
2022-11-20 22:33:54 +08:00
return 0 ;
2022-11-20 06:22:20 +08:00
}
if ( appId )
{
2022-11-21 20:27:09 +08:00
LSApplicationProxy * appProxy = [ LSApplicationProxy applicationProxyForIdentifier : appId ] ;
2023-11-27 00:39:02 +08:00
// delete data container
if ( appProxy . dataContainerURL ) {
[ [ NSFileManager defaultManager ] removeItemAtURL : appProxy . dataContainerURL error : nil ] ;
}
2022-11-21 20:27:09 +08:00
// delete group container paths
[ [ appProxy groupContainerURLs ] enumerateKeysAndObjectsUsingBlock : ^ ( NSString * groupId , NSURL * groupURL , BOOL * stop )
{
// If another app still has this group , don ' t delete it
NSArray < LSApplicationProxy * > * appsWithGroup = applicationsWithGroupId ( groupId ) ;
if ( appsWithGroup . count > 1 )
{
NSLog ( @ "[uninstallApp] not deleting %@, appsWithGroup.count:%lu" , groupURL , appsWithGroup . count ) ;
return ;
}
NSLog ( @ "[uninstallApp] deleting %@" , groupURL ) ;
[ [ NSFileManager defaultManager ] removeItemAtURL : groupURL error : nil ] ;
} ] ;
// delete app plugin paths
for ( LSPlugInKitProxy * pluginProxy in appProxy . plugInKitPlugins )
{
NSURL * pluginURL = pluginProxy . dataContainerURL ;
if ( pluginURL )
{
NSLog ( @ "[uninstallApp] deleting %@" , pluginURL ) ;
[ [ NSFileManager defaultManager ] removeItemAtURL : pluginURL error : nil ] ;
}
}
2023-01-21 20:52:39 +08:00
BOOL systemMethodSuccessful = NO ;
if ( ! useCustomMethod )
{
systemMethodSuccessful = [ [ LSApplicationWorkspace defaultWorkspace ] uninstallApplication : appId withOptions : nil ] ;
}
if ( ! systemMethodSuccessful )
{
deleteSuc = [ [ NSFileManager defaultManager ] removeItemAtPath : [ appPath stringByDeletingLastPathComponent ] error : nil ] ;
registerPath ( appPath , YES , YES ) ;
}
else
{
deleteSuc = systemMethodSuccessful ;
}
2022-11-20 06:22:20 +08:00
}
2022-09-02 23:19:48 +08:00
2022-09-03 09:08:59 +08:00
if ( deleteSuc )
{
2022-11-20 22:33:54 +08:00
cleanRestrictions ( ) ;
2022-09-03 09:08:59 +08:00
return 0 ;
}
else
{
return 1 ;
}
2022-09-02 23:19:48 +08:00
}
2023-01-21 20:52:39 +08:00
int uninstallAppByPath ( NSString * appPath , BOOL useCustomMethod )
2022-09-10 02:22:34 +08:00
{
2022-11-20 06:22:20 +08:00
if ( ! appPath ) return 1 ;
2022-09-10 02:22:34 +08:00
2022-11-20 06:22:20 +08:00
NSString * standardizedAppPath = appPath . stringByStandardizingPath ;
2022-09-10 02:22:34 +08:00
2022-11-20 06:22:20 +08:00
if ( ! [ standardizedAppPath hasPrefix : @ "/var/containers/Bundle/Application/" ] && standardizedAppPath . pathComponents . count = = 5 )
2022-09-10 02:22:34 +08:00
{
2022-11-20 06:22:20 +08:00
return 1 ;
2022-09-10 02:22:34 +08:00
}
2022-11-20 06:22:20 +08:00
NSString * appId = appIdForAppPath ( standardizedAppPath ) ;
2023-01-21 20:52:39 +08:00
return uninstallApp ( appPath , appId , useCustomMethod ) ;
2022-09-04 21:37:49 +08:00
}
2023-01-21 20:52:39 +08:00
int uninstallAppById ( NSString * appId , BOOL useCustomMethod )
2022-09-04 21:37:49 +08:00
{
if ( ! appId ) return 1 ;
2022-09-10 02:22:34 +08:00
NSString * appPath = appPathForAppId ( appId ) ;
2022-09-04 21:37:49 +08:00
if ( ! appPath ) return 1 ;
2023-01-21 20:52:39 +08:00
return uninstallApp ( appPath , appId , useCustomMethod ) ;
2022-09-04 21:37:49 +08:00
}
2022-09-03 09:08:59 +08:00
// 166 : IPA does not exist or is not accessible
// 167 : IPA does not appear to contain an app
2023-01-21 20:52:39 +08:00
int installIpa ( NSString * ipaPath , BOOL force , BOOL useInstalldMethod )
2022-09-02 23:19:48 +08:00
{
2022-11-20 22:33:54 +08:00
cleanRestrictions ( ) ;
2022-09-03 09:08:59 +08:00
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : ipaPath ] ) return 166 ;
2022-09-02 23:19:48 +08:00
BOOL suc = NO ;
2022-11-20 06:22:20 +08:00
NSString * tmpPackagePath = [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : [ NSUUID UUID ] . UUIDString ] ;
2022-09-02 23:19:48 +08:00
2022-11-20 06:22:20 +08:00
suc = [ [ NSFileManager defaultManager ] createDirectoryAtPath : tmpPackagePath withIntermediateDirectories : NO attributes : nil error : nil ] ;
2022-09-03 09:08:59 +08:00
if ( ! suc ) return 1 ;
2022-09-02 23:19:48 +08:00
2022-11-20 06:22:20 +08:00
int extractRet = extract ( ipaPath , tmpPackagePath ) ;
if ( extractRet ! = 0 )
2022-09-02 23:19:48 +08:00
{
2022-11-20 06:22:20 +08:00
[ [ NSFileManager defaultManager ] removeItemAtPath : tmpPackagePath error : nil ] ;
return 168 ;
2022-09-02 23:19:48 +08:00
}
2022-10-18 02:30:49 +08:00
2023-01-21 20:52:39 +08:00
int ret = installApp ( tmpPackagePath , YES , force , NO , useInstalldMethod ) ;
2022-09-02 23:19:48 +08:00
2022-11-20 06:22:20 +08:00
[ [ NSFileManager defaultManager ] removeItemAtPath : tmpPackagePath error : nil ] ;
2022-09-02 23:19:48 +08:00
2022-09-03 09:08:59 +08:00
return ret ;
2022-09-02 23:19:48 +08:00
}
2023-01-21 20:52:39 +08:00
void uninstallAllApps ( BOOL useCustomMethod )
2022-09-02 23:19:48 +08:00
{
for ( NSString * appPath in trollStoreInstalledAppBundlePaths ( ) )
{
2023-01-21 20:52:39 +08:00
uninstallAppById ( appIdForAppPath ( appPath ) , useCustomMethod ) ;
2022-09-02 23:19:48 +08:00
}
}
2022-11-20 06:22:20 +08:00
int uninstallTrollStore ( BOOL unregister )
2022-09-02 23:19:48 +08:00
{
NSString * trollStore = trollStorePath ( ) ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : trollStore ] ) return NO ;
if ( unregister )
{
2022-11-30 06:46:01 +08:00
registerPath ( trollStoreAppPath ( ) , YES , YES ) ;
2022-09-02 23:19:48 +08:00
}
return [ [ NSFileManager defaultManager ] removeItemAtPath : trollStore error : nil ] ;
}
2022-11-20 06:22:20 +08:00
int installTrollStore ( NSString * pathToTar )
2022-09-02 23:19:48 +08:00
{
_CFPreferencesSetValueWithContainerType _CFPreferencesSetValueWithContainer = ( _CFPreferencesSetValueWithContainerType ) dlsym ( RTLD_DEFAULT , "_CFPreferencesSetValueWithContainer" ) ;
_CFPreferencesSynchronizeWithContainerType _CFPreferencesSynchronizeWithContainer = ( _CFPreferencesSynchronizeWithContainerType ) dlsym ( RTLD_DEFAULT , "_CFPreferencesSynchronizeWithContainer" ) ;
2022-11-20 06:22:20 +08:00
_CFPreferencesSetValueWithContainer ( CFSTR ( "SBShowNonDefaultSystemApps" ) , kCFBooleanTrue , CFSTR ( "com.apple.springboard" ) , CFSTR ( "mobile" ) , kCFPreferencesAnyHost , kCFPreferencesNoContainer ) ;
_CFPreferencesSynchronizeWithContainer ( CFSTR ( "com.apple.springboard" ) , CFSTR ( "mobile" ) , kCFPreferencesAnyHost , kCFPreferencesNoContainer ) ;
2022-09-02 23:19:48 +08:00
2022-09-03 09:08:59 +08:00
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : pathToTar ] ) return 1 ;
if ( ! [ pathToTar . pathExtension isEqualToString : @ "tar" ] ) return 1 ;
2022-09-02 23:19:48 +08:00
2022-11-20 06:22:20 +08:00
NSString * tmpPackagePath = [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : [ NSUUID UUID ] . UUIDString ] ;
NSString * tmpPayloadPath = [ tmpPackagePath stringByAppendingPathComponent : @ "Payload" ] ;
BOOL suc = [ [ NSFileManager defaultManager ] createDirectoryAtPath : tmpPayloadPath withIntermediateDirectories : YES attributes : nil error : nil ] ;
2022-09-03 09:08:59 +08:00
if ( ! suc ) return 1 ;
2022-09-02 23:19:48 +08:00
2022-11-20 06:22:20 +08:00
int extractRet = extract ( pathToTar , tmpPayloadPath ) ;
if ( extractRet ! = 0 )
{
[ [ NSFileManager defaultManager ] removeItemAtPath : tmpPackagePath error : nil ] ;
return 169 ;
}
2022-09-02 23:19:48 +08:00
2022-11-20 06:22:20 +08:00
NSString * tmpTrollStorePath = [ tmpPayloadPath stringByAppendingPathComponent : @ "TrollStore.app" ] ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : tmpTrollStorePath ] ) return 1 ;
2022-09-02 23:19:48 +08:00
2023-11-28 10:36:02 +08:00
// if ( @ available ( iOS 16 , * ) ) { } else {
2023-11-28 08:04:40 +08:00
// Transfer existing ldid installation if it exists
// But only if the to - be - installed version of TrollStore is 1.5 .0 or above
// This is to make it possible to downgrade to older versions still
NSString * toInstallInfoPlistPath = [ tmpTrollStorePath stringByAppendingPathComponent : @ "Info.plist" ] ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : toInstallInfoPlistPath ] ) return 1 ;
NSDictionary * toInstallInfoDict = [ NSDictionary dictionaryWithContentsOfFile : toInstallInfoPlistPath ] ;
NSString * toInstallVersion = toInstallInfoDict [ @ "CFBundleVersion" ] ;
NSComparisonResult result = [ @ "1.5.0" compare : toInstallVersion options : NSNumericSearch ] ;
if ( result ! = NSOrderedDescending )
{
NSString * existingLdidPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "ldid" ] ;
NSString * existingLdidVersionPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "ldid.version" ] ;
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : existingLdidPath ] )
{
NSString * tmpLdidPath = [ tmpTrollStorePath stringByAppendingPathComponent : @ "ldid" ] ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : tmpLdidPath ] )
{
[ [ NSFileManager defaultManager ] copyItemAtPath : existingLdidPath toPath : tmpLdidPath error : nil ] ;
}
}
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : existingLdidVersionPath ] )
{
NSString * tmpLdidVersionPath = [ tmpTrollStorePath stringByAppendingPathComponent : @ "ldid.version" ] ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : tmpLdidVersionPath ] )
{
[ [ NSFileManager defaultManager ] copyItemAtPath : existingLdidVersionPath toPath : tmpLdidVersionPath error : nil ] ;
}
}
}
2023-11-28 10:36:02 +08:00
// }
2023-11-28 08:04:40 +08:00
2022-11-20 06:22:20 +08:00
// Merge existing URL scheme settings value
if ( ! getTSURLSchemeState ( nil ) )
{
setTSURLSchemeState ( NO , tmpTrollStorePath ) ;
}
2022-10-12 04:57:08 +08:00
// Update system app persistence helper if used
LSApplicationProxy * persistenceHelperApp = findPersistenceHelperApp ( PERSISTENCE_HELPER _TYPE _SYSTEM ) ;
2022-09-02 23:19:48 +08:00
if ( persistenceHelperApp )
{
2022-11-20 06:22:20 +08:00
NSString * trollStorePersistenceHelper = [ tmpTrollStorePath stringByAppendingPathComponent : @ "PersistenceHelper" ] ;
NSString * trollStoreRootHelper = [ tmpTrollStorePath stringByAppendingPathComponent : @ "trollstorehelper" ] ;
2022-09-02 23:19:48 +08:00
_installPersistenceHelper ( persistenceHelperApp , trollStorePersistenceHelper , trollStoreRootHelper ) ;
}
2023-01-21 20:52:39 +08:00
int ret = installApp ( tmpPackagePath , NO , YES , YES , YES ) ;
2022-11-20 06:22:20 +08:00
NSLog ( @ "[installTrollStore] installApp => %d" , ret ) ;
[ [ NSFileManager defaultManager ] removeItemAtPath : tmpPackagePath error : nil ] ;
return ret ;
2022-09-02 23:19:48 +08:00
}
2022-11-30 06:46:01 +08:00
void refreshAppRegistrations ( BOOL system )
2022-09-02 23:19:48 +08:00
{
2022-12-02 06:21:39 +08:00
registerPath ( trollStoreAppPath ( ) , NO , system ) ;
2022-09-02 23:19:48 +08:00
2022-11-30 06:46:01 +08:00
// the reason why there is even an option to register everything as user
// is because it fixes an issue where app permissions would reset during an icon cache reload
2022-09-02 23:19:48 +08:00
for ( NSString * appPath in trollStoreInstalledAppBundlePaths ( ) )
{
2022-11-30 06:46:01 +08:00
registerPath ( appPath , NO , system ) ;
2022-09-02 23:19:48 +08:00
}
}
BOOL _installPersistenceHelper ( LSApplicationProxy * appProxy , NSString * sourcePersistenceHelper , NSString * sourceRootHelper )
{
NSLog ( @ "_installPersistenceHelper(%@, %@, %@)" , appProxy , sourcePersistenceHelper , sourceRootHelper ) ;
NSString * executablePath = appProxy . canonicalExecutablePath ;
NSString * bundlePath = appProxy . bundleURL . path ;
if ( ! executablePath )
{
NSBundle * appBundle = [ NSBundle bundleWithPath : bundlePath ] ;
executablePath = [ bundlePath stringByAppendingPathComponent : [ appBundle objectForInfoDictionaryKey : @ "CFBundleExecutable" ] ] ;
}
NSString * markPath = [ bundlePath stringByAppendingPathComponent : @ ".TrollStorePersistenceHelper" ] ;
2022-10-12 04:57:08 +08:00
NSString * rootHelperPath = [ bundlePath stringByAppendingPathComponent : @ "trollstorehelper" ] ;
2022-09-02 23:19:48 +08:00
// remove existing persistence helper binary if exists
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : markPath ] && [ [ NSFileManager defaultManager ] fileExistsAtPath : executablePath ] )
{
[ [ NSFileManager defaultManager ] removeItemAtPath : executablePath error : nil ] ;
}
// remove existing root helper binary if exists
2022-10-12 04:57:08 +08:00
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : rootHelperPath ] )
2022-09-02 23:19:48 +08:00
{
2022-10-12 04:57:08 +08:00
[ [ NSFileManager defaultManager ] removeItemAtPath : rootHelperPath error : nil ] ;
2022-09-02 23:19:48 +08:00
}
// install new persistence helper binary
if ( ! [ [ NSFileManager defaultManager ] copyItemAtPath : sourcePersistenceHelper toPath : executablePath error : nil ] )
{
return NO ;
}
2022-11-20 06:22:20 +08:00
chmod ( executablePath . fileSystemRepresentation , 0755 ) ;
chown ( executablePath . fileSystemRepresentation , 33 , 33 ) ;
2022-09-02 23:19:48 +08:00
NSError * error ;
2022-10-12 04:57:08 +08:00
if ( ! [ [ NSFileManager defaultManager ] copyItemAtPath : sourceRootHelper toPath : rootHelperPath error : & error ] )
2022-09-02 23:19:48 +08:00
{
NSLog ( @ "error copying root helper: %@" , error ) ;
}
2022-11-20 06:22:20 +08:00
chmod ( rootHelperPath . fileSystemRepresentation , 0755 ) ;
chown ( rootHelperPath . fileSystemRepresentation , 0 , 0 ) ;
2022-09-02 23:19:48 +08:00
// mark system app as persistence helper
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : markPath ] )
{
[ [ NSFileManager defaultManager ] createFileAtPath : markPath contents : [ NSData data ] attributes : nil ] ;
}
return YES ;
}
void installPersistenceHelper ( NSString * systemAppId )
{
2022-10-12 04:57:08 +08:00
if ( findPersistenceHelperApp ( PERSISTENCE_HELPER _TYPE _ALL ) ) return ;
2022-09-02 23:19:48 +08:00
NSString * persistenceHelperBinary = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "PersistenceHelper" ] ;
NSString * rootHelperBinary = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "trollstorehelper" ] ;
LSApplicationProxy * appProxy = [ LSApplicationProxy applicationProxyForIdentifier : systemAppId ] ;
if ( ! appProxy || ! [ appProxy . bundleType isEqualToString : @ "System" ] ) return ;
NSString * executablePath = appProxy . canonicalExecutablePath ;
NSString * bundlePath = appProxy . bundleURL . path ;
NSString * backupPath = [ bundlePath stringByAppendingPathComponent : [ [ executablePath lastPathComponent ] stringByAppendingString : @ "_TROLLSTORE_BACKUP" ] ] ;
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : backupPath ] ) return ;
if ( ! [ [ NSFileManager defaultManager ] moveItemAtPath : executablePath toPath : backupPath error : nil ] ) return ;
if ( ! _installPersistenceHelper ( appProxy , persistenceHelperBinary , rootHelperBinary ) )
{
[ [ NSFileManager defaultManager ] moveItemAtPath : backupPath toPath : executablePath error : nil ] ;
return ;
}
BKSTerminateApplicationForReasonAndReportWithDescription ( systemAppId , 5 , false , @ "TrollStore - Reload persistence helper" ) ;
}
2022-10-12 04:57:08 +08:00
void unregisterUserPersistenceHelper ( )
{
LSApplicationProxy * userAppProxy = findPersistenceHelperApp ( PERSISTENCE_HELPER _TYPE _USER ) ;
if ( userAppProxy )
{
NSString * markPath = [ userAppProxy . bundleURL . path stringByAppendingPathComponent : @ ".TrollStorePersistenceHelper" ] ;
[ [ NSFileManager defaultManager ] removeItemAtPath : markPath error : nil ] ;
}
}
2022-09-02 23:19:48 +08:00
void uninstallPersistenceHelper ( void )
{
2022-10-12 04:57:08 +08:00
LSApplicationProxy * systemAppProxy = findPersistenceHelperApp ( PERSISTENCE_HELPER _TYPE _SYSTEM ) ;
if ( systemAppProxy )
2022-09-02 23:19:48 +08:00
{
2022-10-12 04:57:08 +08:00
NSString * executablePath = systemAppProxy . canonicalExecutablePath ;
NSString * bundlePath = systemAppProxy . bundleURL . path ;
2022-09-02 23:19:48 +08:00
NSString * backupPath = [ bundlePath stringByAppendingPathComponent : [ [ executablePath lastPathComponent ] stringByAppendingString : @ "_TROLLSTORE_BACKUP" ] ] ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : backupPath ] ) return ;
NSString * helperPath = [ bundlePath stringByAppendingPathComponent : @ "trollstorehelper" ] ;
NSString * markPath = [ bundlePath stringByAppendingPathComponent : @ ".TrollStorePersistenceHelper" ] ;
[ [ NSFileManager defaultManager ] removeItemAtPath : executablePath error : nil ] ;
[ [ NSFileManager defaultManager ] removeItemAtPath : markPath error : nil ] ;
[ [ NSFileManager defaultManager ] removeItemAtPath : helperPath error : nil ] ;
[ [ NSFileManager defaultManager ] moveItemAtPath : backupPath toPath : executablePath error : nil ] ;
2022-10-12 04:57:08 +08:00
BKSTerminateApplicationForReasonAndReportWithDescription ( systemAppProxy . bundleIdentifier , 5 , false , @ "TrollStore - Reload persistence helper" ) ;
}
LSApplicationProxy * userAppProxy = findPersistenceHelperApp ( PERSISTENCE_HELPER _TYPE _USER ) ;
if ( userAppProxy )
{
unregisterUserPersistenceHelper ( ) ;
2022-09-02 23:19:48 +08:00
}
}
2022-10-12 04:57:08 +08:00
void registerUserPersistenceHelper ( NSString * userAppId )
{
if ( findPersistenceHelperApp ( PERSISTENCE_HELPER _TYPE _ALL ) ) return ;
LSApplicationProxy * appProxy = [ LSApplicationProxy applicationProxyForIdentifier : userAppId ] ;
if ( ! appProxy || ! [ appProxy . bundleType isEqualToString : @ "User" ] ) return ;
NSString * markPath = [ appProxy . bundleURL . path stringByAppendingPathComponent : @ ".TrollStorePersistenceHelper" ] ;
[ [ NSFileManager defaultManager ] createFileAtPath : markPath contents : [ NSData data ] attributes : nil ] ;
}
2022-10-30 06:45:30 +08:00
// Apparently there is some odd behaviour where TrollStore installed apps sometimes get restricted
// This works around that issue at least and is triggered when rebuilding icon cache
void cleanRestrictions ( void )
{
NSString * clientTruthPath = @ "/private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles/Library/ConfigurationProfiles/ClientTruth.plist" ;
NSURL * clientTruthURL = [ NSURL fileURLWithPath : clientTruthPath ] ;
NSDictionary * clientTruthDictionary = [ NSDictionary dictionaryWithContentsOfURL : clientTruthURL ] ;
if ( ! clientTruthDictionary ) return ;
NSArray * valuesArr ;
NSDictionary * lsdAppRemoval = clientTruthDictionary [ @ "com.apple.lsd.appremoval" ] ;
if ( lsdAppRemoval && [ lsdAppRemoval isKindOfClass : NSDictionary . class ] )
{
NSDictionary * clientRestrictions = lsdAppRemoval [ @ "clientRestrictions" ] ;
if ( clientRestrictions && [ clientRestrictions isKindOfClass : NSDictionary . class ] )
{
NSDictionary * unionDict = clientRestrictions [ @ "union" ] ;
if ( unionDict && [ unionDict isKindOfClass : NSDictionary . class ] )
{
NSDictionary * removedSystemAppBundleIDs = unionDict [ @ "removedSystemAppBundleIDs" ] ;
if ( removedSystemAppBundleIDs && [ removedSystemAppBundleIDs isKindOfClass : NSDictionary . class ] )
{
valuesArr = removedSystemAppBundleIDs [ @ "values" ] ;
}
}
}
}
if ( ! valuesArr || ! valuesArr . count ) return ;
NSMutableArray * valuesArrM = valuesArr . mutableCopy ;
__block BOOL changed = NO ;
[ valuesArrM enumerateObjectsWithOptions : NSEnumerationReverse usingBlock : ^ ( NSString * value , NSUInteger idx , BOOL * stop )
{
2022-11-30 06:46:01 +08:00
if ( ! isRemovableSystemApp ( value ) )
2022-10-30 06:45:30 +08:00
{
[ valuesArrM removeObjectAtIndex : idx ] ;
changed = YES ;
}
} ] ;
if ( ! changed ) return ;
NSMutableDictionary * clientTruthDictionaryM = ( __bridge _transfer NSMutableDictionary * ) CFPropertyListCreateDeepCopy ( kCFAllocatorDefault , ( __bridge CFDictionaryRef ) clientTruthDictionary , kCFPropertyListMutableContainersAndLeaves ) ;
clientTruthDictionaryM [ @ "com.apple.lsd.appremoval" ] [ @ "clientRestrictions" ] [ @ "union" ] [ @ "removedSystemAppBundleIDs" ] [ @ "values" ] = valuesArrM ;
[ clientTruthDictionaryM writeToURL : clientTruthURL error : nil ] ;
2022-11-20 22:33:54 +08:00
killall ( @ "profiled" , NO ) ; // profiled needs to restart for the changes to apply
2022-10-30 06:45:30 +08:00
}
2022-10-07 07:25:20 +08:00
int MAIN_NAME ( int argc , char * argv [ ] , char * envp [ ] )
{
2022-09-02 23:19:48 +08:00
@ autoreleasepool {
if ( argc <= 1 ) return -1 ;
2023-01-21 20:52:39 +08:00
if ( getuid ( ) ! = 0 )
{
NSLog ( @ "ERROR: trollstorehelper has to be run as root." ) ;
return -1 ;
}
2022-09-02 23:19:48 +08:00
2023-01-21 20:52:39 +08:00
NSMutableArray * args = [ NSMutableArray new ] ;
for ( int i = 1 ; i < argc ; i + + )
{
[ args addObject : [ NSString stringWithUTF8String : argv [ i ] ] ] ;
}
NSLog ( @ "trollstorehelper invoked with arguments: %@" , args ) ;
2022-09-02 23:19:48 +08:00
2023-01-21 20:52:39 +08:00
int ret = 0 ;
NSString * cmd = args . firstObject ;
2022-09-02 23:19:48 +08:00
if ( [ cmd isEqualToString : @ "install" ] )
{
2023-01-21 20:52:39 +08:00
if ( args . count < 2 ) return -3 ;
// use system method when specified , otherwise use custom method
BOOL useInstalldMethod = [ args containsObject : @ "installd" ] ;
BOOL force = [ args containsObject : @ "force" ] ;
NSString * ipaPath = args . lastObject ;
ret = installIpa ( ipaPath , force , useInstalldMethod ) ;
}
else if ( [ cmd isEqualToString : @ "uninstall" ] )
2022-09-02 23:19:48 +08:00
{
2023-01-21 20:52:39 +08:00
if ( args . count < 2 ) return -3 ;
// use custom method when specified , otherwise use system method
BOOL useCustomMethod = [ args containsObject : @ "custom" ] ;
NSString * appId = args . lastObject ;
ret = uninstallAppById ( appId , useCustomMethod ) ;
}
else if ( [ cmd isEqualToString : @ "uninstall-path" ] )
2022-09-04 21:37:49 +08:00
{
2023-01-21 20:52:39 +08:00
if ( args . count < 2 ) return -3 ;
// use custom method when specified , otherwise use system method
BOOL useCustomMethod = [ args containsObject : @ "custom" ] ;
NSString * appPath = args . lastObject ;
ret = uninstallAppByPath ( appPath , useCustomMethod ) ;
}
else if ( [ cmd isEqualToString : @ "install-trollstore" ] )
2022-09-02 23:19:48 +08:00
{
2023-01-21 20:52:39 +08:00
if ( args . count < 2 ) return -3 ;
NSString * tsTar = args . lastObject ;
2022-09-03 09:08:59 +08:00
ret = installTrollStore ( tsTar ) ;
NSLog ( @ "installed troll store? %d" , ret = = 0 ) ;
2023-01-21 20:52:39 +08:00
}
else if ( [ cmd isEqualToString : @ "uninstall-trollstore" ] )
2022-11-20 06:22:20 +08:00
{
2023-01-21 20:52:39 +08:00
if ( ! [ args containsObject : @ "preserve-apps" ] )
{
uninstallAllApps ( [ args containsObject : @ "custom" ] ) ;
}
2022-11-20 06:22:20 +08:00
uninstallTrollStore ( YES ) ;
2023-01-21 20:52:39 +08:00
}
2023-11-28 08:04:40 +08:00
else if ( [ cmd isEqualToString : @ "install-ldid" ] )
{
2023-11-28 10:36:02 +08:00
// if ( @ available ( iOS 16 , * ) ) { } else {
2023-11-28 08:04:40 +08:00
if ( args . count < 3 ) return -3 ;
NSString * ldidPath = args [ 1 ] ;
NSString * ldidVersion = args [ 2 ] ;
installLdid ( ldidPath , ldidVersion ) ;
2023-11-28 10:36:02 +08:00
// }
2023-11-28 08:04:40 +08:00
}
2023-01-21 20:52:39 +08:00
else if ( [ cmd isEqualToString : @ "refresh" ] )
2022-09-02 23:19:48 +08:00
{
2022-11-30 06:46:01 +08:00
refreshAppRegistrations ( YES ) ;
2023-01-21 20:52:39 +08:00
}
else if ( [ cmd isEqualToString : @ "refresh-all" ] )
2022-09-02 23:19:48 +08:00
{
2022-10-30 06:45:30 +08:00
cleanRestrictions ( ) ;
2022-12-02 06:21:39 +08:00
// refreshAppRegistrations ( NO ) ; // < - fixes app permissions resetting , causes apps to move around on home screen , so I had to disable it
2023-01-21 20:52:39 +08:00
[ [ NSFileManager defaultManager ] removeItemAtPath : @ "/var/containers/Shared/SystemGroup/systemgroup.com.apple.lsd.iconscache/Library/Caches/com.apple.IconsCache" error : nil ] ;
2022-09-02 23:19:48 +08:00
[ [ LSApplicationWorkspace defaultWorkspace ] _LSPrivateRebuildApplicationDatabasesForSystemApps : YES internal : YES user : YES ] ;
2022-11-30 06:46:01 +08:00
refreshAppRegistrations ( YES ) ;
2022-11-20 22:33:54 +08:00
killall ( @ "backboardd" , YES ) ;
2023-01-21 20:52:39 +08:00
}
else if ( [ cmd isEqualToString : @ "install-persistence-helper" ] )
2022-09-02 23:19:48 +08:00
{
2023-01-21 20:52:39 +08:00
if ( args . count < 2 ) return -3 ;
NSString * systemAppId = args . lastObject ;
2022-09-02 23:19:48 +08:00
installPersistenceHelper ( systemAppId ) ;
2023-01-21 20:52:39 +08:00
}
else if ( [ cmd isEqualToString : @ "uninstall-persistence-helper" ] )
2022-09-02 23:19:48 +08:00
{
uninstallPersistenceHelper ( ) ;
2023-01-21 20:52:39 +08:00
}
else if ( [ cmd isEqualToString : @ "register-user-persistence-helper" ] )
2022-09-22 23:38:58 +08:00
{
2023-01-21 20:52:39 +08:00
if ( args . count < 2 ) return -3 ;
NSString * userAppId = args . lastObject ;
2022-10-12 04:57:08 +08:00
registerUserPersistenceHelper ( userAppId ) ;
2023-01-21 20:52:39 +08:00
}
else if ( [ cmd isEqualToString : @ "modify-registration" ] )
2022-10-30 06:45:30 +08:00
{
2023-01-21 20:52:39 +08:00
if ( args . count < 3 ) return -3 ;
NSString * appPath = args [ 1 ] ;
NSString * newRegistration = args [ 2 ] ;
2022-10-30 06:45:30 +08:00
NSString * trollStoreMark = [ [ appPath stringByDeletingLastPathComponent ] stringByAppendingPathComponent : @ "_TrollStore" ] ;
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : trollStoreMark ] )
{
2022-11-30 06:46:01 +08:00
registerPath ( appPath , NO , [ newRegistration isEqualToString : @ "System" ] ) ;
2022-11-20 06:22:20 +08:00
}
2023-01-21 20:52:39 +08:00
}
else if ( [ cmd isEqualToString : @ "url-scheme" ] )
2022-11-20 06:22:20 +08:00
{
2023-01-21 20:52:39 +08:00
if ( args . count < 2 ) return -3 ;
NSString * modifyArg = args . lastObject ;
2022-11-20 06:22:20 +08:00
BOOL newState = [ modifyArg isEqualToString : @ "enable" ] ;
if ( newState = = YES || [ modifyArg isEqualToString : @ "disable" ] )
{
setTSURLSchemeState ( newState , nil ) ;
2022-10-30 06:45:30 +08:00
}
2022-09-02 23:19:48 +08:00
}
2023-01-21 20:52:39 +08:00
NSLog ( @ "trollstorehelper returning %d" , ret ) ;
2022-09-03 09:08:59 +08:00
return ret ;
2022-09-02 23:19:48 +08:00
}
}