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 >
# import "CoreServices.h"
# import "Shared.h"
2022-09-04 06:48:40 +08:00
# import < sys / utsname . 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-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-06 03:39:17 +08:00
typedef CF_OPTIONS ( uint32_t , SecCSFlags ) {
2022-09-06 07:04:45 +08:00
kSecCSDefaultFlags = 0
2022-09-06 03:39:17 +08:00
} ;
# define kSecCSRequirementInformation 1 < < 2
# define kSecCSSigningInformation 1 < < 1
typedef struct __SecCode const * SecStaticCodeRef ;
extern CFStringRef kSecCodeInfoEntitlementsDict ;
extern CFStringRef kSecCodeInfoCertificates ;
extern CFStringRef kSecPolicyAppleiPhoneApplicationSigning ;
extern CFStringRef kSecPolicyAppleiPhoneProfileApplicationSigning ;
extern CFStringRef kSecPolicyLeafMarkerOid ;
OSStatus SecStaticCodeCreateWithPathAndAttributes ( CFURLRef path , SecCSFlags flags , CFDictionaryRef attributes , SecStaticCodeRef * staticCode ) ;
OSStatus SecCodeCopySigningInformation ( SecStaticCodeRef code , SecCSFlags flags , CFDictionaryRef * information ) ;
CFDataRef SecCertificateCopyExtensionValue ( SecCertificateRef certificate , CFTypeRef extensionOID , bool * isCritical ) ;
void SecPolicySetOptionsValue ( SecPolicyRef policy , CFStringRef key , CFTypeRef value ) ;
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 ] )
{
[ systemURLSchemes unionSet : proxy . claimedURLSchemes ] ;
}
return systemURLSchemes . copy ;
}
2022-09-02 23:19:48 +08:00
extern char * * * _NSGetArgv ( ) ;
NSString * safe_getExecutablePath ( )
{
char * executablePathC = * * _NSGetArgv ( ) ;
return [ NSString stringWithUTF8String : executablePathC ] ;
}
NSDictionary * infoDictionaryForAppPath ( NSString * appPath )
{
NSString * infoPlistPath = [ appPath stringByAppendingPathComponent : @ "Info.plist" ] ;
return [ NSDictionary dictionaryWithContentsOfFile : infoPlistPath ] ;
}
NSString * appIdForAppPath ( NSString * appPath )
{
return infoDictionaryForAppPath ( appPath ) [ @ "CFBundleIdentifier" ] ;
}
2022-09-10 02:22:34 +08:00
NSString * appMainExecutablePathForAppPath ( NSString * appPath )
{
return [ appPath stringByAppendingPathComponent : infoDictionaryForAppPath ( appPath ) [ @ "CFBundleExecutable" ] ] ;
}
NSString * appPathForAppId ( NSString * appId )
2022-09-02 23:19:48 +08:00
{
for ( NSString * appPath in trollStoreInstalledAppBundlePaths ( ) )
{
if ( [ appIdForAppPath ( appPath ) isEqualToString : appId ] )
{
return appPath ;
}
}
return nil ;
}
static NSString * getNSStringFromFile ( int fd )
{
NSMutableString * ms = [ NSMutableString new ] ;
ssize_t num_read ;
char c ;
while ( ( num_read = read ( fd , & c , sizeof ( c ) ) ) )
{
[ ms appendString : [ NSString stringWithFormat : @ "%c" , c ] ] ;
}
return ms . copy ;
}
static void printMultilineNSString ( NSString * stringToPrint )
{
NSCharacterSet * separator = [ NSCharacterSet newlineCharacterSet ] ;
NSArray * lines = [ stringToPrint componentsSeparatedByCharactersInSet : separator ] ;
for ( NSString * line in lines )
{
NSLog ( @ "%@" , line ) ;
}
}
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 ] ;
chmod ( ldidPath . UTF8String , 0755 ) ;
chown ( ldidPath . UTF8String , 0 , 0 ) ;
}
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 UTF8String ] , & 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
SecStaticCodeRef getStaticCodeRef ( NSString * binaryPath )
2022-09-02 23:19:48 +08:00
{
2022-09-06 07:04:45 +08:00
if ( binaryPath = = nil )
{
return NULL ;
}
CFURLRef binaryURL = CFURLCreateWithFileSystemPath ( kCFAllocatorDefault , ( __bridge CFStringRef ) binaryPath , kCFURLPOSIXPathStyle , false ) ;
if ( binaryURL = = NULL )
{
NSLog ( @ "[getStaticCodeRef] failed to get URL to binary %@" , binaryPath ) ;
return NULL ;
}
SecStaticCodeRef codeRef = NULL ;
OSStatus result ;
result = SecStaticCodeCreateWithPathAndAttributes ( binaryURL , kSecCSDefaultFlags , NULL , & codeRef ) ;
CFRelease ( binaryURL ) ;
if ( result ! = errSecSuccess )
{
NSLog ( @ "[getStaticCodeRef] failed to create static code for binary %@" , binaryPath ) ;
return NULL ;
}
return codeRef ;
2022-09-06 03:39:17 +08:00
}
2022-09-05 21:09:31 +08:00
2022-09-06 03:39:17 +08:00
NSDictionary * dumpEntitlements ( SecStaticCodeRef codeRef )
{
2022-09-06 07:04:45 +08:00
if ( codeRef = = NULL )
{
NSLog ( @ "[dumpEntitlements] attempting to dump entitlements without a StaticCodeRef" ) ;
return nil ;
}
CFDictionaryRef signingInfo = NULL ;
OSStatus result ;
result = SecCodeCopySigningInformation ( codeRef , kSecCSRequirementInformation , & signingInfo ) ;
if ( result ! = errSecSuccess )
{
NSLog ( @ "[dumpEntitlements] failed to copy signing info from static code" ) ;
return nil ;
}
NSDictionary * entitlementsNSDict = nil ;
CFDictionaryRef entitlements = CFDictionaryGetValue ( signingInfo , kSecCodeInfoEntitlementsDict ) ;
if ( entitlements = = NULL )
{
NSLog ( @ "[dumpEntitlements] no entitlements specified" ) ;
}
else if ( CFGetTypeID ( entitlements ) ! = CFDictionaryGetTypeID ( ) )
{
NSLog ( @ "[dumpEntitlements] invalid entitlements" ) ;
}
else
{
entitlementsNSDict = ( __bridge NSDictionary * ) ( entitlements ) ;
NSLog ( @ "[dumpEntitlements] dumped %@" , entitlementsNSDict ) ;
}
CFRelease ( signingInfo ) ;
return entitlementsNSDict ;
2022-09-06 03:39:17 +08:00
}
2022-09-05 21:09:31 +08:00
2022-09-06 03:39:17 +08:00
NSDictionary * dumpEntitlementsFromBinaryAtPath ( NSString * binaryPath )
{
2022-09-06 07:04:45 +08:00
// This function is intended for one - shot checks . Main - event functions should retain / release their own SecStaticCodeRefs
if ( binaryPath = = nil )
{
return nil ;
}
SecStaticCodeRef codeRef = getStaticCodeRef ( binaryPath ) ;
if ( codeRef = = NULL )
{
return nil ;
}
NSDictionary * entitlements = dumpEntitlements ( codeRef ) ;
CFRelease ( codeRef ) ;
return entitlements ;
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 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 ;
BOOL isDir ;
[ [ NSFileManager defaultManager ] fileExistsAtPath : fileURL . path isDirectory : & isDir ] ;
if ( [ filePath . lastPathComponent isEqualToString : @ "Info.plist" ] )
{
NSDictionary * infoDictionary = [ NSDictionary dictionaryWithContentsOfFile : filePath ] ;
NSArray * tsRootBinaries = infoDictionary [ @ "TSRootBinaries" ] ;
if ( tsRootBinaries && [ tsRootBinaries isKindOfClass : [ NSArray class ] ] )
{
for ( NSString * rootBinary in tsRootBinaries )
{
if ( [ rootBinary isKindOfClass : [ NSString class ] ] )
{
NSString * rootBinaryPath = [ [ filePath stringByDeletingLastPathComponent ] stringByAppendingPathComponent : rootBinary ] ;
storedEntitlements [ rootBinaryPath ] = dumpEntitlementsFromBinaryAtPath ( rootBinaryPath ) ;
}
}
}
}
}
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 )
{
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-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 ] ;
[ URLSchemesSet minusSet : appleSchemes ] ;
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 :
int installApp ( NSString * appPath , BOOL sign , BOOL force )
2022-09-02 23:19:48 +08:00
{
2022-09-04 00:49:53 +08:00
NSLog ( @ "[installApp force = %d]" , force ) ;
2022-09-10 02:22:34 +08:00
if ( ! infoDictionaryForAppPath ( appPath ) ) return 172 ;
2022-09-02 23:19:48 +08:00
NSString * appId = appIdForAppPath ( appPath ) ;
2022-09-10 02:22:34 +08:00
if ( ! appId ) return 176 ;
2022-09-02 23:19:48 +08:00
2022-09-04 21:37:49 +08:00
applyPatchesToInfoDictionary ( appPath ) ;
2022-09-02 23:19:48 +08:00
if ( sign )
{
2022-09-10 02:22:34 +08:00
int signRet = signApp ( appPath ) ;
if ( signRet ! = 0 ) return signRet ;
2022-09-02 23:19:48 +08:00
}
BOOL existed ;
NSError * mcmError ;
MCMAppContainer * appContainer = [ objc_getClass ( "MCMAppContainer" ) containerWithIdentifier : appId createIfNecessary : YES existed : & existed error : & mcmError ] ;
if ( ! appContainer || mcmError )
{
2022-09-10 02:22:34 +08:00
NSLog ( @ "[installApp] failed to create app container for %@: %@" , appId , mcmError ) ;
2022-09-03 09:08:59 +08:00
return 170 ;
}
2022-09-10 02:22:34 +08:00
if ( existed )
{
NSLog ( @ "[installApp] got existing app container: %@" , appContainer ) ;
}
else
{
NSLog ( @ "[installApp] created app container: %@" , appContainer ) ;
}
2022-09-03 09:08:59 +08:00
// check if the bundle is empty
BOOL isEmpty = YES ;
2022-09-10 02:22:34 +08:00
NSArray * bundleItems = [ [ NSFileManager defaultManager ] contentsOfDirectoryAtPath : appContainer . url . path error : nil ] ;
2022-09-03 09:08:59 +08:00
for ( NSString * bundleItem in bundleItems )
{
if ( [ bundleItem . pathExtension isEqualToString : @ "app" ] )
{
isEmpty = NO ;
break ;
}
2022-09-02 23:19:48 +08:00
}
2022-09-10 02:22:34 +08:00
NSLog ( @ "[installApp] container is empty? %d" , isEmpty ) ;
2022-09-02 23:19:48 +08:00
// Make sure there isn ' t already an app store app installed with the same identifier
NSURL * trollStoreMarkURL = [ appContainer . url URLByAppendingPathComponent : @ "_TrollStore" ] ;
2022-09-04 00:49:53 +08:00
if ( existed && ! isEmpty && ! [ trollStoreMarkURL checkResourceIsReachableAndReturnError : nil ] && ! force )
2022-09-02 23:19:48 +08:00
{
NSLog ( @ "[installApp] already installed and not a TrollStore app... bailing out" ) ;
2022-09-03 09:08:59 +08:00
return 171 ;
2022-09-02 23:19:48 +08:00
}
2022-09-04 00:49:53 +08:00
// Mark app as TrollStore app
2022-09-10 02:22:34 +08:00
BOOL marked = [ [ NSFileManager defaultManager ] createFileAtPath : trollStoreMarkURL . path contents : [ NSData data ] attributes : nil ] ;
if ( ! marked )
{
NSLog ( @ "[installApp] failed to mark %@ as TrollStore app" , appId ) ;
return 177 ;
}
2022-09-04 00:49:53 +08:00
2022-09-04 21:37:49 +08:00
// Apply correct permissions ( First run , set everything to 644 , owner 33 )
2022-09-02 23:19:48 +08:00
NSURL * fileURL ;
2022-09-04 21:37:49 +08:00
NSDirectoryEnumerator * enumerator = [ [ NSFileManager defaultManager ] enumeratorAtURL : [ NSURL fileURLWithPath : appPath ] includingPropertiesForKeys : nil options : 0 errorHandler : nil ] ;
2022-09-02 23:19:48 +08:00
while ( fileURL = [ enumerator nextObject ] )
{
NSString * filePath = fileURL . path ;
chown ( filePath . UTF8String , 33 , 33 ) ;
2022-09-04 21:37:49 +08:00
chmod ( filePath . UTF8String , 0644 ) ;
2022-09-10 02:22:34 +08:00
NSLog ( @ "[installApp] setting %@ to chown(33,33) chmod(0644)" , filePath ) ;
2022-09-04 21:37:49 +08:00
}
// Apply correct permissions ( Second run , set executables and directories to 0755 )
enumerator = [ [ NSFileManager defaultManager ] enumeratorAtURL : [ NSURL fileURLWithPath : appPath ] includingPropertiesForKeys : nil options : 0 errorHandler : nil ] ;
while ( fileURL = [ enumerator nextObject ] )
{
NSString * filePath = fileURL . path ;
BOOL isDir ;
[ [ NSFileManager defaultManager ] fileExistsAtPath : fileURL . path isDirectory : & isDir ] ;
2022-09-02 23:19:48 +08:00
if ( [ filePath . lastPathComponent isEqualToString : @ "Info.plist" ] )
{
NSDictionary * infoDictionary = [ NSDictionary dictionaryWithContentsOfFile : filePath ] ;
NSString * executable = infoDictionary [ @ "CFBundleExecutable" ] ;
2022-09-10 02:22:34 +08:00
if ( executable && [ executable isKindOfClass : [ NSString class ] ] )
2022-09-02 23:19:48 +08:00
{
NSString * executablePath = [ [ filePath stringByDeletingLastPathComponent ] stringByAppendingPathComponent : executable ] ;
chmod ( executablePath . UTF8String , 0755 ) ;
2022-09-10 02:22:34 +08:00
NSLog ( @ "[installApp] applied permissions for bundle executable %@" , executablePath ) ;
}
NSArray * tsRootBinaries = infoDictionary [ @ "TSRootBinaries" ] ;
if ( tsRootBinaries && [ tsRootBinaries isKindOfClass : [ NSArray class ] ] )
{
for ( NSString * rootBinary in tsRootBinaries )
{
if ( [ rootBinary isKindOfClass : [ NSString class ] ] )
{
NSString * rootBinaryPath = [ [ filePath stringByDeletingLastPathComponent ] stringByAppendingPathComponent : rootBinary ] ;
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : rootBinaryPath ] )
{
chmod ( rootBinaryPath . UTF8String , 0755 ) ;
chown ( rootBinaryPath . UTF8String , 0 , 0 ) ;
NSLog ( @ "[installApp] applied permissions for root binary %@" , rootBinaryPath ) ;
}
}
}
2022-09-02 23:19:48 +08:00
}
}
2022-09-04 21:37:49 +08:00
else if ( ! isDir && [ filePath . pathExtension isEqualToString : @ "dylib" ] )
2022-09-02 23:19:48 +08:00
{
chmod ( filePath . UTF8String , 0755 ) ;
}
2022-09-04 21:37:49 +08:00
else if ( isDir )
{
// apparently all dirs are writable by default
chmod ( filePath . UTF8String , 0755 ) ;
}
2022-09-02 23:19:48 +08:00
}
2022-09-10 02:22:34 +08:00
// Set . app directory permissions too
chmod ( appPath . UTF8String , 0755 ) ;
chown ( appPath . UTF8String , 33 , 33 ) ;
2022-09-02 23:19:48 +08:00
// Wipe old version if needed
if ( existed )
{
2022-09-22 23:38:58 +08:00
if ( ! [ appId isEqualToString : @ "com.opa334.TrollStore" ] )
{
BKSTerminateApplicationForReasonAndReportWithDescription ( appId , 5 , false , @ "TrollStore - App updated" ) ;
}
2022-09-02 23:19:48 +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 ] )
{
// do not under any circumstance delete this file as it makes iOS loose the app registration
2022-09-04 00:49:53 +08:00
if ( [ fileURL . lastPathComponent isEqualToString : @ ".com.apple.mobile_container_manager.metadata.plist" ] || [ fileURL . lastPathComponent isEqualToString : @ "_TrollStore" ] )
2022-09-02 23:19:48 +08:00
{
2022-09-22 23:38:58 +08:00
NSLog ( @ "[installApp] skipping removal of %@" , fileURL ) ;
2022-09-02 23:19:48 +08:00
continue ;
}
[ [ NSFileManager defaultManager ] removeItemAtURL : fileURL error : nil ] ;
}
}
// Install app
NSString * newAppPath = [ appContainer . url . path stringByAppendingPathComponent : appPath . lastPathComponent ] ;
NSLog ( @ "[installApp] new app path: %@" , newAppPath ) ;
2022-09-10 02:22:34 +08:00
NSError * copyError ;
BOOL suc = [ [ NSFileManager defaultManager ] copyItemAtPath : appPath toPath : newAppPath error : & copyError ] ;
2022-09-02 23:19:48 +08:00
if ( suc )
{
2022-09-10 02:22:34 +08:00
NSLog ( @ "[installApp] App %@ installed, adding to icon cache now..." , appId ) ;
2022-09-02 23:19:48 +08:00
registerPath ( ( char * ) newAppPath . UTF8String , 0 ) ;
2022-09-03 09:08:59 +08:00
return 0 ;
2022-09-02 23:19:48 +08:00
}
else
{
2022-09-10 02:22:34 +08:00
NSLog ( @ "[installApp] Failed to copy app bundle for app %@, error: %@" , appId , copyError ) ;
return 178 ;
2022-09-02 23:19:48 +08:00
}
}
2022-09-10 02:22:34 +08:00
int uninstallApp ( NSString * appPath , NSString * appId )
2022-09-02 23:19:48 +08:00
{
2022-09-22 23:38:58 +08:00
BKSTerminateApplicationForReasonAndReportWithDescription ( appId , 5 , false , @ "TrollStore - App uninstalled" ) ;
2022-09-02 23:19:48 +08:00
LSApplicationProxy * appProxy = [ LSApplicationProxy applicationProxyForIdentifier : appId ] ;
MCMContainer * appContainer = [ objc_getClass ( "MCMAppDataContainer" ) containerWithIdentifier : appId createIfNecessary : NO existed : nil error : nil ] ;
NSString * containerPath = [ appContainer url ] . path ;
if ( containerPath )
{
2022-09-10 02:22:34 +08:00
NSLog ( @ "[uninstallApp] deleting %@" , containerPath ) ;
2022-09-02 23:19:48 +08:00
// delete app container path
2022-09-10 02:22:34 +08:00
[ [ NSFileManager defaultManager ] removeItemAtPath : containerPath error : nil ] ;
2022-09-02 23:19:48 +08:00
}
// delete group container paths
2022-09-10 02:22:34 +08:00
[ [ appProxy groupContainerURLs ] enumerateKeysAndObjectsUsingBlock : ^ ( NSString * groupId , NSURL * groupURL , BOOL * stop )
2022-09-02 23:19:48 +08:00
{
2022-09-10 02:22:34 +08:00
// 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 ) ;
2022-09-04 21:37:49 +08:00
[ [ NSFileManager defaultManager ] removeItemAtURL : groupURL error : nil ] ;
2022-09-04 00:49:53 +08:00
} ] ;
2022-09-02 23:19:48 +08:00
// delete app plugin paths
for ( LSPlugInKitProxy * pluginProxy in appProxy . plugInKitPlugins )
{
NSURL * pluginURL = pluginProxy . dataContainerURL ;
if ( pluginURL )
{
2022-09-10 02:22:34 +08:00
NSLog ( @ "[uninstallApp] deleting %@" , pluginURL ) ;
[ [ NSFileManager defaultManager ] removeItemAtURL : pluginURL error : nil ] ;
2022-09-02 23:19:48 +08:00
}
}
// unregister app
registerPath ( ( char * ) appPath . UTF8String , 1 ) ;
2022-09-10 02:22:34 +08:00
NSLog ( @ "[uninstallApp] deleting %@" , [ appPath stringByDeletingLastPathComponent ] ) ;
2022-09-02 23:19:48 +08:00
// delete app
2022-09-10 02:22:34 +08:00
BOOL deleteSuc = [ [ NSFileManager defaultManager ] removeItemAtPath : [ appPath stringByDeletingLastPathComponent ] error : nil ] ;
2022-09-03 09:08:59 +08:00
if ( deleteSuc )
{
return 0 ;
}
else
{
return 1 ;
}
2022-09-02 23:19:48 +08:00
}
2022-09-10 02:22:34 +08:00
/ * int detachApp ( NSString * appId )
{
NSString * appPath = appPathForAppId ( appId ) ;
NSString * executablePath = appMainExecutablePathForAppPath ( appPath ) ;
NSString * trollStoreMarkPath = [ [ appPath stringByDeletingLastPathComponent ] stringByAppendingPathComponent : @ "_TrollStore" ] ;
// Not attached to TrollStore
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : trollStoreMarkPath ] ) return 0 ;
// Refuse to detach app if it ' s still signed with fake root cert
SecStaticCodeRef codeRef = getStaticCodeRef ( executablePath ) ;
if ( codeRef ! = NULL )
{
if ( codeCertChainContainsFakeAppStoreExtensions ( codeRef ) )
{
CFRelease ( codeRef ) ;
return 184 ;
}
}
// Deleting TrollStore mark to detach app
BOOL suc = [ [ NSFileManager defaultManager ] removeItemAtPath : trollStoreMarkPath error : nil ] ;
return ! suc ;
} * /
int uninstallAppByPath ( NSString * appPath )
2022-09-04 21:37:49 +08:00
{
if ( ! appPath ) return 1 ;
NSString * appId = appIdForAppPath ( appPath ) ;
if ( ! appId ) return 1 ;
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-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 ;
NSString * tmpPath = [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : [ NSUUID UUID ] . UUIDString ] ;
2022-09-10 02:22:34 +08:00
suc = [ [ NSFileManager defaultManager ] createDirectoryAtPath : tmpPath 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
extract ( ipaPath , tmpPath ) ;
NSString * tmpPayloadPath = [ tmpPath stringByAppendingPathComponent : @ "Payload" ] ;
2022-09-10 02:22:34 +08:00
NSArray * items = [ [ NSFileManager defaultManager ] contentsOfDirectoryAtPath : tmpPayloadPath error : nil ] ;
2022-09-03 09:08:59 +08:00
if ( ! items ) return 167 ;
2022-09-02 23:19:48 +08:00
NSString * tmpAppPath ;
for ( NSString * item in items )
{
if ( [ item . pathExtension isEqualToString : @ "app" ] )
{
tmpAppPath = [ tmpPayloadPath stringByAppendingPathComponent : item ] ;
break ;
}
}
2022-09-03 09:08:59 +08:00
if ( ! tmpAppPath ) return 167 ;
2022-09-02 23:19:48 +08:00
2022-09-10 02:22:34 +08:00
int ret = installApp ( tmpAppPath , YES , force ) ;
2022-09-02 23:19:48 +08:00
[ [ NSFileManager defaultManager ] removeItemAtPath : tmpAppPath error : nil ] ;
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
}
}
BOOL uninstallTrollStore ( BOOL unregister )
{
NSString * trollStore = trollStorePath ( ) ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : trollStore ] ) return NO ;
if ( unregister )
{
registerPath ( ( char * ) trollStoreAppPath ( ) . UTF8String , 1 ) ;
}
return [ [ NSFileManager defaultManager ] removeItemAtPath : trollStore error : nil ] ;
}
BOOL installTrollStore ( NSString * pathToTar )
{
// _CFPreferencesCopyValueWithContainerType _CFPreferencesCopyValueWithContainer = ( _CFPreferencesCopyValueWithContainerType ) dlsym ( RTLD_DEFAULT , "_CFPreferencesCopyValueWithContainer" ) ;
_CFPreferencesSetValueWithContainerType _CFPreferencesSetValueWithContainer = ( _CFPreferencesSetValueWithContainerType ) dlsym ( RTLD_DEFAULT , "_CFPreferencesSetValueWithContainer" ) ;
_CFPreferencesSynchronizeWithContainerType _CFPreferencesSynchronizeWithContainer = ( _CFPreferencesSynchronizeWithContainerType ) dlsym ( RTLD_DEFAULT , "_CFPreferencesSynchronizeWithContainer" ) ;
/ * CFPropertyListRef SBShowNonDefaultSystemAppsValue = _CFPreferencesCopyValueWithContainer ( CFSTR ( "SBShowNonDefaultSystemApps" ) , CFSTR ( "com.apple.springboard" ) , CFSTR ( "mobile" ) , kCFPreferencesAnyHost , kCFPreferencesNoContainer ) ;
if ( SBShowNonDefaultSystemAppsValue ! = kCFBooleanTrue )
{ * /
_CFPreferencesSetValueWithContainer ( CFSTR ( "SBShowNonDefaultSystemApps" ) , kCFBooleanTrue , CFSTR ( "com.apple.springboard" ) , CFSTR ( "mobile" ) , kCFPreferencesAnyHost , kCFPreferencesNoContainer ) ;
_CFPreferencesSynchronizeWithContainer ( CFSTR ( "com.apple.springboard" ) , CFSTR ( "mobile" ) , kCFPreferencesAnyHost , kCFPreferencesNoContainer ) ;
// NSLog ( @ "unrestricted springboard apps" ) ;
/ * } * /
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
NSString * tmpPath = [ NSTemporaryDirectory ( ) stringByAppendingPathComponent : [ NSUUID UUID ] . UUIDString ] ;
BOOL suc = [ [ NSFileManager defaultManager ] createDirectoryAtPath : tmpPath 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
extract ( pathToTar , tmpPath ) ;
NSString * tmpTrollStore = [ tmpPath stringByAppendingPathComponent : @ "TrollStore.app" ] ;
2022-09-03 09:08:59 +08:00
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : tmpTrollStore ] ) 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 ] )
{
NSString * tmpLdidPath = [ tmpTrollStore stringByAppendingPathComponent : @ "ldid" ] ;
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : tmpLdidPath ] )
{
[ [ NSFileManager defaultManager ] copyItemAtPath : existingLdidPath toPath : tmpLdidPath error : nil ] ;
}
}
// Update persistence helper if installed
LSApplicationProxy * persistenceHelperApp = findPersistenceHelperApp ( ) ;
if ( persistenceHelperApp )
{
NSString * trollStorePersistenceHelper = [ tmpTrollStore stringByAppendingPathComponent : @ "PersistenceHelper" ] ;
NSString * trollStoreRootHelper = [ tmpTrollStore stringByAppendingPathComponent : @ "trollstorehelper" ] ;
_installPersistenceHelper ( persistenceHelperApp , trollStorePersistenceHelper , trollStoreRootHelper ) ;
}
2022-09-10 02:22:34 +08:00
return installApp ( tmpTrollStore , NO , YES ) ;;
2022-09-02 23:19:48 +08:00
}
void refreshAppRegistrations ( )
{
// registerPath ( ( char * ) trollStoreAppPath ( ) . UTF8String , 1 ) ;
registerPath ( ( char * ) trollStoreAppPath ( ) . UTF8String , 0 ) ;
for ( NSString * appPath in trollStoreInstalledAppBundlePaths ( ) )
{
// registerPath ( ( char * ) appPath . UTF8String , 1 ) ;
registerPath ( ( char * ) appPath . UTF8String , 0 ) ;
}
}
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" ] ;
NSString * helperPath = [ bundlePath stringByAppendingPathComponent : @ "trollstorehelper" ] ;
// 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
if ( [ [ NSFileManager defaultManager ] fileExistsAtPath : helperPath ] )
{
[ [ NSFileManager defaultManager ] removeItemAtPath : helperPath error : nil ] ;
}
// install new persistence helper binary
if ( ! [ [ NSFileManager defaultManager ] copyItemAtPath : sourcePersistenceHelper toPath : executablePath error : nil ] )
{
return NO ;
}
chmod ( executablePath . UTF8String , 0755 ) ;
chown ( executablePath . UTF8String , 33 , 33 ) ;
NSError * error ;
if ( ! [ [ NSFileManager defaultManager ] copyItemAtPath : sourceRootHelper toPath : helperPath error : & error ] )
{
NSLog ( @ "error copying root helper: %@" , error ) ;
}
chmod ( helperPath . UTF8String , 0755 ) ;
chown ( helperPath . UTF8String , 0 , 0 ) ;
// 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 )
{
if ( findPersistenceHelperApp ( ) ) return ;
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" ) ;
}
void uninstallPersistenceHelper ( void )
{
LSApplicationProxy * appProxy = findPersistenceHelperApp ( ) ;
if ( appProxy )
{
NSString * executablePath = appProxy . canonicalExecutablePath ;
NSString * bundlePath = appProxy . bundleURL . path ;
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 ] ;
BKSTerminateApplicationForReasonAndReportWithDescription ( appProxy . bundleIdentifier , 5 , false , @ "TrollStore - Reload persistence helper" ) ;
}
}
int main ( int argc , char * argv [ ] , char * envp [ ] ) {
@ autoreleasepool {
if ( argc <= 1 ) return -1 ;
NSLog ( @ "trollstore helper go, uid: %d, gid: %d" , getuid ( ) , getgid ( ) ) ;
NSBundle * mcmBundle = [ NSBundle bundleWithPath : @ "/System/Library/PrivateFrameworks/MobileContainerManager.framework" ] ;
[ mcmBundle load ] ;
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
NSLog ( @ "argc = %d" , argc ) ;
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 )
{
NSLog ( @ "argv3 = %s" , argv [ 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 ) ;
} / * else if ( [ cmd isEqualToString : @ "detach" ] )
{
if ( argc <= 2 ) return -3 ;
NSString * appId = [ NSString stringWithUTF8String : argv [ 2 ] ] ;
ret = detachApp ( appId ) ;
} * / 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 ) ;
} else if ( [ cmd isEqualToString : @ "install-ldid" ] )
{
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" ] )
{
[ [ LSApplicationWorkspace defaultWorkspace ] _LSPrivateRebuildApplicationDatabasesForSystemApps : YES internal : YES user : YES ] ;
refreshAppRegistrations ( ) ;
} 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-09-22 23:38:58 +08:00
} else if ( [ cmd isEqualToString : @ "dash" ] )
{
LSApplicationProxy * appProxy = findPersistenceHelperApp ( ) ;
if ( appProxy )
{
NSString * executablePath = appProxy . canonicalExecutablePath ;
registerPath ( ( char * ) executablePath . UTF8String , 1 ) ;
}
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
}
}