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 >
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 ;
}
NSSet < NSString * > * appleURLSchemes ( void )
{
LSEnumerator * enumerator = [ LSEnumerator enumeratorForApplicationProxiesWithOptions : 0 ] ;
enumerator . predicate = [ NSPredicate predicateWithFormat : @ "bundleIdentifier BEGINSWITH 'com.apple'" ] ;
NSMutableSet * systemURLSchemes = [ NSMutableSet new ] ;
LSApplicationProxy * proxy ;
while ( proxy = [ enumerator nextObject ] )
{
2022-11-20 06:22:20 +08:00
for ( NSString * claimedURLScheme in proxy . claimedURLSchemes )
{
if ( [ claimedURLScheme isKindOfClass : NSString . class ] )
{
[ systemURLSchemes addObject : claimedURLScheme . lowercaseString ] ;
}
}
2022-09-10 02:22:34 +08:00
}
return systemURLSchemes . copy ;
}
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 ;
}
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 ] ;
}
}
2022-09-02 23:19:48 +08:00
void installLdid ( NSString * ldidToCopyPath )
{
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : ldidToCopyPath ] ) return ;
NSString * ldidPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "ldid" ] ;
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : ldidPath ] )
{
[ [ NSFileManager defaultManager ] removeItemAtPath : ldidPath error : nil ] ;
}
[ [ NSFileManager defaultManager ] copyItemAtPath : ldidToCopyPath toPath : ldidPath error : nil ] ;
2022-11-20 06:22:20 +08:00
chmod ( ldidPath . fileSystemRepresentation , 0755 ) ;
chown ( ldidPath . fileSystemRepresentation , 0 , 0 ) ;
2022-09-02 23:19:48 +08:00
}
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 ;
2022-11-20 06:22:20 +08:00
int spawnError = posix_spawn ( & task_pid , [ ldidPath fileSystemRepresentation ] , & action , NULL , ( char * const * ) argsC , NULL ) ;
2022-09-02 23:19:48 +08:00
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
}
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
2022-09-10 02:22:34 +08:00
NSString * executablePath = appMainExecutablePathForAppPath ( appPath ) ;
if ( ! executablePath ) return 176 ;
2022-09-02 23:19:48 +08:00
2022-09-10 02:22:34 +08:00
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : executablePath ] ) return 174 ;
2022-09-06 07:04:45 +08:00
NSObject * tsBundleIsPreSigned = appInfoDict [ @ "TSBundlePreSigned" ] ;
if ( [ tsBundleIsPreSigned isKindOfClass : [ NSNumber class ] ] )
{
// if TSBundlePreSigned = YES , this bundle has been externally signed so we can skip over signing it now
NSNumber * tsBundleIsPreSignedNum = ( NSNumber * ) tsBundleIsPreSigned ;
if ( [ tsBundleIsPreSignedNum boolValue ] = = YES )
{
NSLog ( @ "[signApp] taking fast path for app which declares it has already been signed (%@)" , executablePath ) ;
2022-09-10 02:22:34 +08:00
return 0 ;
2022-09-06 07:04:45 +08:00
}
}
SecStaticCodeRef codeRef = getStaticCodeRef ( executablePath ) ;
if ( codeRef ! = NULL )
{
2022-09-06 07:04:10 +08:00
if ( codeCertChainContainsFakeAppStoreExtensions ( codeRef ) )
{
NSLog ( @ "[signApp] taking fast path for app signed using a custom root certificate (%@)" , executablePath ) ;
CFRelease ( codeRef ) ;
2022-09-10 02:22:34 +08:00
return 0 ;
2022-09-06 07:04:10 +08:00
}
2022-09-06 07:04:45 +08:00
}
2022-09-06 07:04:10 +08:00
else
{
2022-09-06 07:04:45 +08:00
NSLog ( @ "[signApp] failed to get static code, can't derive entitlements from %@, continuing anways..." , executablePath ) ;
2022-09-06 07:04:10 +08:00
}
2022-09-10 02:22:34 +08:00
if ( ! isLdidInstalled ( ) ) return 173 ;
2022-09-02 23:19:48 +08:00
NSString * certPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "cert.p12" ] ;
NSString * certArg = [ @ "-K" stringByAppendingPathComponent : certPath ] ;
NSString * errorOutput ;
int ldidRet ;
2022-09-06 07:04:45 +08:00
NSDictionary * entitlements = dumpEntitlements ( codeRef ) ;
CFRelease ( codeRef ) ;
2022-09-04 06:48:40 +08:00
if ( ! entitlements )
2022-09-02 23:19:48 +08:00
{
NSLog ( @ "app main binary has no entitlements, signing app with fallback entitlements..." ) ;
// app has no entitlements , sign with fallback entitlements
NSString * entitlementPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "fallback.entitlements" ] ;
NSString * entitlementArg = [ @ "-S" stringByAppendingString : entitlementPath ] ;
ldidRet = runLdid ( @ [ entitlementArg , certArg , appPath ] , nil , & errorOutput ) ;
}
else
{
2022-09-13 00:20:39 +08:00
// Work around an ldid bug where it doesn ' t keep entitlements on stray binaries
NSMutableDictionary * storedEntitlements = [ NSMutableDictionary new ] ;
NSDirectoryEnumerator * enumerator = [ [ NSFileManager defaultManager ] enumeratorAtURL : [ NSURL fileURLWithPath : appPath ] includingPropertiesForKeys : nil options : 0 errorHandler : nil ] ;
NSURL * fileURL ;
while ( fileURL = [ enumerator nextObject ] )
{
NSString * filePath = fileURL . path ;
2022-11-01 06:39:28 +08:00
if ( isMachoFile ( filePath ) )
2022-09-13 00:20:39 +08:00
{
2022-11-01 06:39:28 +08:00
storedEntitlements [ filePath ] = dumpEntitlementsFromBinaryAtPath ( filePath ) ;
2022-09-13 00:20:39 +08:00
}
}
2022-09-02 23:19:48 +08:00
// app has entitlements , keep them
2022-09-03 22:49:53 +08:00
ldidRet = runLdid ( @ [ @ "-s" , certArg , appPath ] , nil , & errorOutput ) ;
2022-09-13 00:20:39 +08:00
[ storedEntitlements enumerateKeysAndObjectsUsingBlock : ^ ( NSString * binaryPath , NSDictionary * entitlements , BOOL * stop )
{
2022-11-01 06:39:28 +08:00
NSDictionary * newEntitlements = dumpEntitlementsFromBinaryAtPath ( binaryPath ) ;
if ( ! newEntitlements || ! [ newEntitlements isEqualToDictionary : entitlements ] )
{
NSString * tmpEntitlementPlistPath = [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : @ "ent.xml" ] ;
[ entitlements writeToURL : [ NSURL fileURLWithPath : tmpEntitlementPlistPath ] error : nil ] ;
NSString * tmpEntitlementArg = [ @ "-S" stringByAppendingString : tmpEntitlementPlistPath ] ;
runLdid ( @ [ tmpEntitlementArg , certArg , binaryPath ] , nil , nil ) ;
[ [ NSFileManager defaultManager ] removeItemAtPath : tmpEntitlementPlistPath error : nil ] ;
}
2022-09-13 00:20:39 +08:00
} ] ;
2022-09-02 23:19:48 +08:00
}
NSLog ( @ "ldid exited with status %d" , ldidRet ) ;
NSLog ( @ "- ldid error output start -" ) ;
printMultilineNSString ( errorOutput ) ;
NSLog ( @ "- ldid error output end -" ) ;
2022-09-10 02:22:34 +08:00
if ( ldidRet = = 0 )
{
return 0 ;
}
else
{
return 175 ;
}
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
NSSet * appleSchemes = appleURLSchemes ( ) ;
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
2022-09-06 07:04:10 +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 :
2022-11-20 06:22:20 +08:00
int installApp ( NSString * appPackagePath , BOOL sign , BOOL force , BOOL isTSUpdate )
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" ] ;
NSArray * items = [ [ NSFileManager defaultManager ] contentsOfDirectoryAtPath : appPayloadPath error : nil ] ;
if ( ! items ) return 167 ;
NSString * appBundlePath ;
for ( NSString * item in items )
{
if ( [ item . pathExtension isEqualToString : @ "app" ] )
{
appBundlePath = [ appPayloadPath stringByAppendingPathComponent : item ] ;
break ;
}
}
if ( ! appBundlePath ) return 167 ;
2022-09-10 02:22:34 +08:00
2022-11-20 06:22:20 +08:00
NSString * appId = appIdForAppPath ( appBundlePath ) ;
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
2022-11-20 06:22:20 +08:00
if ( ! infoDictionaryForAppPath ( appBundlePath ) ) return 172 ;
if ( ! isTSUpdate )
2022-10-18 02:30:49 +08:00
{
2022-11-20 06:22:20 +08:00
applyPatchesToInfoDictionary ( appBundlePath ) ;
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 )
{
2022-11-20 06:22:20 +08:00
int signRet = signApp ( appBundlePath ) ;
2022-09-10 02:22:34 +08:00
if ( signRet ! = 0 ) return signRet ;
2022-09-02 23:19:48 +08:00
}
2022-11-23 03:46:01 +08:00
loadMCMFramework ( ) ;
2022-09-10 02:22:34 +08:00
2022-11-23 03:46:01 +08:00
BOOL existed ;
NSError * mcmError ;
MCMAppContainer * appContainer = [ objc_getClass ( "MCMAppContainer" ) containerWithIdentifier : appId createIfNecessary : YES existed : & existed error : & mcmError ] ;
if ( ! appContainer || mcmError )
{
NSLog ( @ "[installApp] failed to create app container for %@: %@" , appId , mcmError ) ;
return 170 ;
}
2022-11-20 06:22:20 +08:00
2022-11-23 03:46:01 +08:00
if ( existed )
{
NSLog ( @ "[installApp] got existing app container: %@" , appContainer ) ;
}
else
{
NSLog ( @ "[installApp] created app container: %@" , appContainer ) ;
}
2022-09-02 23:19:48 +08:00
2022-11-23 03:46:01 +08:00
// check if the bundle is empty
BOOL isEmpty = YES ;
NSArray * bundleItems = [ [ NSFileManager defaultManager ] contentsOfDirectoryAtPath : appContainer . url . path error : nil ] ;
for ( NSString * bundleItem in bundleItems )
{
if ( [ bundleItem . pathExtension isEqualToString : @ "app" ] )
2022-09-22 23:38:58 +08:00
{
2022-11-23 03:46:01 +08:00
isEmpty = NO ;
break ;
2022-09-22 23:38:58 +08:00
}
2022-11-23 03:46:01 +08:00
}
2022-09-22 23:38:58 +08:00
2022-11-23 03:46:01 +08:00
NSLog ( @ "[installApp] container is empty? %d" , isEmpty ) ;
2022-09-02 23:19:48 +08:00
2022-11-23 03:46:01 +08:00
// Make sure there isn ' t already an app store app installed with the same identifier
NSURL * trollStoreMarkURL = [ appContainer . url URLByAppendingPathComponent : @ "_TrollStore" ] ;
if ( existed && ! isEmpty && ! [ trollStoreMarkURL checkResourceIsReachableAndReturnError : nil ] && ! force )
{
NSLog ( @ "[installApp] already installed and not a TrollStore app... bailing out" ) ;
return 171 ;
2022-09-02 23:19:48 +08:00
}
2022-11-23 03:46:01 +08:00
// Mark app as TrollStore app
BOOL marked = [ [ NSFileManager defaultManager ] createFileAtPath : trollStoreMarkURL . path contents : [ NSData data ] attributes : nil ] ;
if ( ! marked )
2022-09-02 23:19:48 +08:00
{
2022-11-23 03:46:01 +08:00
NSLog ( @ "[installApp] failed to mark %@ as TrollStore app" , appId ) ;
return 177 ;
}
2022-09-02 23:19:48 +08:00
2022-11-23 03:46:01 +08:00
fixPermissionsOfAppBundle ( appBundlePath ) ;
// Wipe old version if needed
if ( existed )
{
if ( ! [ appId isEqualToString : @ "com.opa334.TrollStore" ] )
2022-09-30 03:00:11 +08:00
{
2022-11-23 03:46:01 +08:00
BKSTerminateApplicationForReasonAndReportWithDescription ( appId , 5 , false , @ "TrollStore - App updated" ) ;
2022-11-20 06:22:20 +08:00
}
2022-11-23 03:46:01 +08:00
NSLog ( @ "[installApp] found existing TrollStore app, cleaning directory" ) ;
NSDirectoryEnumerator * enumerator = [ [ NSFileManager defaultManager ] enumeratorAtURL : appContainer . url includingPropertiesForKeys : nil options : 0 errorHandler : nil ] ;
NSURL * fileURL ;
while ( fileURL = [ enumerator nextObject ] )
2022-11-20 06:22:20 +08:00
{
2022-11-23 03:46:01 +08:00
// do not under any circumstance delete this file as it makes iOS loose the app registration
if ( [ fileURL . lastPathComponent isEqualToString : @ ".com.apple.mobile_container_manager.metadata.plist" ] || [ fileURL . lastPathComponent isEqualToString : @ "_TrollStore" ] )
{
NSLog ( @ "[installApp] skipping removal of %@" , fileURL ) ;
continue ;
}
2022-09-30 03:00:11 +08:00
2022-11-23 03:46:01 +08:00
[ [ NSFileManager defaultManager ] removeItemAtURL : fileURL error : nil ] ;
}
2022-11-21 01:27:14 +08:00
}
2022-09-02 23:19:48 +08:00
2022-11-23 03:46:01 +08:00
// Install app
NSString * newAppBundlePath = [ appContainer . url . path stringByAppendingPathComponent : appBundlePath . lastPathComponent ] ;
NSLog ( @ "[installApp] new app path: %@" , newAppBundlePath ) ;
NSError * copyError ;
BOOL suc = [ [ NSFileManager defaultManager ] copyItemAtPath : appBundlePath toPath : newAppBundlePath error : & copyError ] ;
if ( suc )
2022-11-21 01:27:14 +08:00
{
2022-11-23 03:46:01 +08:00
NSLog ( @ "[installApp] App %@ installed, adding to icon cache now..." , appId ) ;
registerPath ( ( char * ) newAppBundlePath . fileSystemRepresentation , 0 , YES ) ;
return 0 ;
}
else
{
NSLog ( @ "[installApp] Failed to copy app bundle for app %@, error: %@" , appId , copyError ) ;
return 178 ;
2022-09-02 23:19:48 +08:00
}
2022-11-20 06:22:20 +08:00
}
int uninstallApp ( NSString * appPath , NSString * appId )
{
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 ] ;
registerPath ( ( char * ) appPath . fileSystemRepresentation , 1 , 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 ] ;
// 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 ] ;
}
}
2022-11-20 06:22:20 +08:00
deleteSuc = [ [ LSApplicationWorkspace defaultWorkspace ] uninstallApplication : appId withOptions : nil ] ;
}
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
}
2022-11-20 06:22:20 +08:00
int uninstallAppByPath ( NSString * appPath )
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 ) ;
2022-09-10 02:22:34 +08:00
return uninstallApp ( appPath , appId ) ;
2022-09-04 21:37:49 +08:00
}
2022-09-10 02:22:34 +08:00
int uninstallAppById ( NSString * appId )
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 ;
2022-09-10 02:22:34 +08:00
return uninstallApp ( appPath , appId ) ;
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
2022-09-10 02:22:34 +08:00
int installIpa ( NSString * ipaPath , BOOL force )
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
2022-11-20 06:22:20 +08:00
int ret = installApp ( tmpPackagePath , YES , force , NO ) ;
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
}
void uninstallAllApps ( void )
{
for ( NSString * appPath in trollStoreInstalledAppBundlePaths ( ) )
{
2022-09-10 02:22:34 +08:00
uninstallAppById ( appIdForAppPath ( appPath ) ) ;
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-20 06:22:20 +08:00
registerPath ( ( char * ) trollStoreAppPath ( ) . fileSystemRepresentation , 1 , 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
// Save existing ldid installation if it exists
NSString * existingLdidPath = [ trollStoreAppPath ( ) stringByAppendingPathComponent : @ "ldid" ] ;
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : existingLdidPath ] )
{
2022-11-20 06:22:20 +08:00
NSString * tmpLdidPath = [ tmpTrollStorePath stringByAppendingPathComponent : @ "ldid" ] ;
2022-09-02 23:19:48 +08:00
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : tmpLdidPath ] )
{
[ [ NSFileManager defaultManager ] copyItemAtPath : existingLdidPath toPath : tmpLdidPath error : nil ] ;
}
}
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 ) ;
}
2022-11-20 06:22:20 +08:00
int ret = installApp ( tmpPackagePath , NO , YES , YES ) ;
NSLog ( @ "[installTrollStore] installApp => %d" , ret ) ;
[ [ NSFileManager defaultManager ] removeItemAtPath : tmpPackagePath error : nil ] ;
return ret ;
2022-09-02 23:19:48 +08:00
}
void refreshAppRegistrations ( )
{
2022-11-20 06:22:20 +08:00
// registerPath ( ( char * ) trollStoreAppPath ( ) . fileSystemRepresentation , 1 , YES ) ;
registerPath ( ( char * ) trollStoreAppPath ( ) . fileSystemRepresentation , 0 , YES ) ;
2022-09-02 23:19:48 +08:00
for ( NSString * appPath in trollStoreInstalledAppBundlePaths ( ) )
{
2022-11-20 06:22:20 +08:00
// registerPath ( ( char * ) appPath . fileSystemRepresentation , 1 , YES ) ;
registerPath ( ( char * ) appPath . fileSystemRepresentation , 0 , YES ) ;
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 )
{
if ( ! [ value hasPrefix : @ "com.apple." ] )
{
[ 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 ;
NSLog ( @ "trollstore helper go, uid: %d, gid: %d" , getuid ( ) , getgid ( ) ) ;
2022-09-03 09:08:59 +08:00
int ret = 0 ;
2022-09-02 23:19:48 +08:00
NSString * cmd = [ NSString stringWithUTF8String : argv [ 1 ] ] ;
if ( [ cmd isEqualToString : @ "install" ] )
{
2022-09-04 00:49:53 +08:00
BOOL force = NO ;
2022-09-03 09:08:59 +08:00
if ( argc <= 2 ) return -3 ;
2022-09-04 00:49:53 +08:00
if ( argc > 3 )
{
if ( ! strcmp ( argv [ 3 ] , "force" ) )
{
force = YES ;
}
}
2022-09-02 23:19:48 +08:00
NSString * ipaPath = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
2022-09-10 02:22:34 +08:00
ret = installIpa ( ipaPath , force ) ;
2022-09-02 23:19:48 +08:00
} else if ( [ cmd isEqualToString : @ "uninstall" ] )
{
2022-09-03 09:08:59 +08:00
if ( argc <= 2 ) return -3 ;
2022-09-02 23:19:48 +08:00
NSString * appId = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
2022-09-10 02:22:34 +08:00
ret = uninstallAppById ( appId ) ;
2022-11-20 06:22:20 +08:00
} else if ( [ cmd isEqualToString : @ "uninstall-path" ] )
2022-09-04 21:37:49 +08:00
{
if ( argc <= 2 ) return -3 ;
NSString * appPath = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
2022-09-10 02:22:34 +08:00
ret = uninstallAppByPath ( appPath ) ;
2022-09-04 21:37:49 +08:00
} else if ( [ cmd isEqualToString : @ "install-trollstore" ] )
2022-09-02 23:19:48 +08:00
{
2022-09-03 09:08:59 +08:00
if ( argc <= 2 ) return -3 ;
2022-09-02 23:19:48 +08:00
NSString * tsTar = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
2022-09-03 09:08:59 +08:00
ret = installTrollStore ( tsTar ) ;
NSLog ( @ "installed troll store? %d" , ret = = 0 ) ;
2022-09-02 23:19:48 +08:00
} else if ( [ cmd isEqualToString : @ "uninstall-trollstore" ] )
{
uninstallAllApps ( ) ;
uninstallTrollStore ( YES ) ;
2022-11-20 06:22:20 +08:00
} else if ( [ cmd isEqualToString : @ "uninstall-trollstore-preserve-apps" ] )
{
uninstallTrollStore ( YES ) ;
} else if ( [ cmd isEqualToString : @ "install-ldid" ] )
2022-09-02 23:19:48 +08:00
{
2022-09-03 09:08:59 +08:00
if ( argc <= 2 ) return -3 ;
2022-09-02 23:19:48 +08:00
NSString * ldidPath = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
installLdid ( ldidPath ) ;
} else if ( [ cmd isEqualToString : @ "refresh" ] )
{
refreshAppRegistrations ( ) ;
} else if ( [ cmd isEqualToString : @ "refresh-all" ] )
{
2022-10-30 06:45:30 +08:00
cleanRestrictions ( ) ;
2022-09-02 23:19:48 +08:00
[ [ LSApplicationWorkspace defaultWorkspace ] _LSPrivateRebuildApplicationDatabasesForSystemApps : YES internal : YES user : YES ] ;
refreshAppRegistrations ( ) ;
2022-11-20 22:33:54 +08:00
killall ( @ "backboardd" , YES ) ;
2022-09-02 23:19:48 +08:00
} else if ( [ cmd isEqualToString : @ "install-persistence-helper" ] )
{
2022-09-03 09:08:59 +08:00
if ( argc <= 2 ) return -3 ;
2022-09-02 23:19:48 +08:00
NSString * systemAppId = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
installPersistenceHelper ( systemAppId ) ;
} else if ( [ cmd isEqualToString : @ "uninstall-persistence-helper" ] )
{
uninstallPersistenceHelper ( ) ;
2022-10-12 04:57:08 +08:00
} else if ( [ cmd isEqualToString : @ "register-user-persistence-helper" ] )
2022-09-22 23:38:58 +08:00
{
2022-10-12 04:57:08 +08:00
if ( argc <= 2 ) return -3 ;
NSString * userAppId = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
registerUserPersistenceHelper ( userAppId ) ;
2022-10-30 06:45:30 +08:00
} else if ( [ cmd isEqualToString : @ "modify-registration" ] )
{
if ( argc <= 3 ) return -3 ;
NSString * appPath = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
NSString * newRegistration = [ NSString stringWithUTF8String : argv [ 3 ] ] ;
NSString * trollStoreMark = [ [ appPath stringByDeletingLastPathComponent ] stringByAppendingPathComponent : @ "_TrollStore" ] ;
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : trollStoreMark ] )
{
2022-11-20 06:22:20 +08:00
registerPath ( ( char * ) appPath . fileSystemRepresentation , 0 , [ newRegistration isEqualToString : @ "System" ] ) ;
}
} else if ( [ cmd isEqualToString : @ "url-scheme" ] )
{
if ( argc <= 2 ) return -3 ;
NSString * modifyArg = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
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
}
2022-09-03 09:08:59 +08:00
NSLog ( @ "returning %d" , ret ) ;
return ret ;
2022-09-02 23:19:48 +08:00
}
}