Skip to content

Commit

Permalink
Readd ldid for use on iOS 14
Browse files Browse the repository at this point in the history
  • Loading branch information
opa334 committed Nov 28, 2023
1 parent b79c9c1 commit c6ea42c
Show file tree
Hide file tree
Showing 14 changed files with 418 additions and 14 deletions.
39 changes: 31 additions & 8 deletions Exploits/fastPathSign/src/codesign.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <Foundation/Foundation.h>
#include <Security/Security.h>
#include <TargetConditionals.h>
#include <dlfcn.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -64,12 +65,27 @@ typedef CF_OPTIONS(uint32_t, SecPreserveFlags) {
typedef struct __SecCodeSigner* SecCodeSignerRef SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0));
#endif

extern const CFStringRef kSecCodeSignerEntitlements SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0));
extern const CFStringRef kSecCodeSignerIdentifier SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0));
extern const CFStringRef kSecCodeSignerIdentity SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0));
extern const CFStringRef kSecCodeSignerPreserveMetadata SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0));
extern const CFStringRef kSecCodeSignerRequirements SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0));
extern const CFStringRef kSecCodeSignerResourceRules SPI_AVAILABLE(macos(10.5), ios(15.0), macCatalyst(13.0));
const CFStringRef kSecCodeSignerApplicationData = CFSTR("application-specific");
const CFStringRef kSecCodeSignerDetached = CFSTR("detached");
const CFStringRef kSecCodeSignerDigestAlgorithm = CFSTR("digest-algorithm");
const CFStringRef kSecCodeSignerDryRun = CFSTR("dryrun");
const CFStringRef kSecCodeSignerEntitlements = CFSTR("entitlements");
const CFStringRef kSecCodeSignerFlags = CFSTR("flags");
const CFStringRef kSecCodeSignerIdentifier = CFSTR("identifier");
const CFStringRef kSecCodeSignerIdentifierPrefix = CFSTR("identifier-prefix");
const CFStringRef kSecCodeSignerIdentity = CFSTR("signer");
const CFStringRef kSecCodeSignerPageSize = CFSTR("pagesize");
const CFStringRef kSecCodeSignerRequirements = CFSTR("requirements");
const CFStringRef kSecCodeSignerResourceRules = CFSTR("resource-rules");
const CFStringRef kSecCodeSignerSDKRoot = CFSTR("sdkroot");
const CFStringRef kSecCodeSignerSigningTime = CFSTR("signing-time");
const CFStringRef kSecCodeSignerRequireTimestamp = CFSTR("timestamp-required");
const CFStringRef kSecCodeSignerTimestampServer = CFSTR("timestamp-url");
const CFStringRef kSecCodeSignerTimestampAuthentication = CFSTR("timestamp-authentication");
const CFStringRef kSecCodeSignerTimestampOmitCertificates = CFSTR("timestamp-omit-certificates");
const CFStringRef kSecCodeSignerPreserveMetadata = CFSTR("preserve-metadata");
const CFStringRef kSecCodeSignerTeamIdentifier = CFSTR("teamidentifier");
const CFStringRef kSecCodeSignerPlatformIdentifier = CFSTR("platform-identifier");

#ifdef BRIDGED_SECCODESIGNER
OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags, SecCodeSignerRef* __nonnull CF_RETURNS_RETAINED signer)
Expand All @@ -91,6 +107,13 @@ OSStatus SecCodeSignerAddSignatureWithErrors(SecCodeSignerRef signer, SecStaticC

int codesign_sign_adhoc(const char *path, bool preserveMetadata, NSDictionary *customEntitlements)
{
// We need to do this shit because iOS 14 does not have the symbol
OSStatus (*__SecCodeSignerCreate)(CFDictionaryRef parameters, SecCSFlags flags, SecCodeSignerRef *signerRef) = dlsym(RTLD_DEFAULT, "SecCodeSignerCreate");
OSStatus (*__SecCodeSignerAddSignatureWithErrors)(SecCodeSignerRef signerRef, SecStaticCodeRef codeRef, SecCSFlags flags, CFErrorRef *errors) = dlsym(RTLD_DEFAULT, "SecCodeSignerAddSignatureWithErrors");
// if this is not found, all bets are off
if (!__SecCodeSignerCreate) return 404;
if (!__SecCodeSignerAddSignatureWithErrors) return 404;

NSString *filePath = [NSString stringWithUTF8String:path];
OSStatus status = 0;
int retval = 200;
Expand Down Expand Up @@ -127,13 +150,13 @@ int codesign_sign_adhoc(const char *path, bool preserveMetadata, NSDictionary *c
}

SecCodeSignerRef signerRef;
status = SecCodeSignerCreate((__bridge CFDictionaryRef)parameters, kSecCSDefaultFlags, &signerRef);
status = __SecCodeSignerCreate((__bridge CFDictionaryRef)parameters, kSecCSDefaultFlags, &signerRef);
if (status == 0) {
SecStaticCodeRef code;
status = SecStaticCodeCreateWithPathAndAttributes((__bridge CFURLRef)[NSURL fileURLWithPath:filePath], kSecCSDefaultFlags, (__bridge CFDictionaryRef)@{}, &code);
if (status == 0) {
CFErrorRef errors;
status = SecCodeSignerAddSignatureWithErrors(signerRef, code, kSecCSDefaultFlags, &errors);
status = __SecCodeSignerAddSignatureWithErrors(signerRef, code, kSecCSDefaultFlags, &errors);
if (status == 0) {
CFDictionaryRef newSigningInformation;
// Difference from codesign: added kSecCSSigningInformation, kSecCSRequirementInformation, kSecCSInternalInformation
Expand Down
192 changes: 191 additions & 1 deletion RootHelper/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,105 @@ void setTSURLSchemeState(BOOL newState, NSString* customAppPath)
}
}

void installLdid(NSString* ldidToCopyPath, NSString* ldidVersion)
{
if(![[NSFileManager defaultManager] fileExistsAtPath:ldidToCopyPath]) return;

NSString* ldidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
NSString* ldidVersionPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid.version"];

if([[NSFileManager defaultManager] fileExistsAtPath:ldidPath])
{
[[NSFileManager defaultManager] removeItemAtPath:ldidPath error:nil];
}

[[NSFileManager defaultManager] copyItemAtPath:ldidToCopyPath toPath:ldidPath error:nil];

NSData* ldidVersionData = [ldidVersion dataUsingEncoding:NSUTF8StringEncoding];
[ldidVersionData writeToFile:ldidVersionPath atomically:YES];

chmod(ldidPath.fileSystemRepresentation, 0755);
chmod(ldidVersionPath.fileSystemRepresentation, 0644);
}

BOOL isLdidInstalled(void)
{
NSString* ldidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
return [[NSFileManager defaultManager] fileExistsAtPath:ldidPath];
}

int runLdid(NSArray* args, NSString** output, NSString** errorOutput)
{
NSString* ldidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
NSMutableArray* argsM = args.mutableCopy ?: [NSMutableArray new];
[argsM insertObject:ldidPath.lastPathComponent atIndex:0];

NSUInteger argCount = [argsM count];
char **argsC = (char **)malloc((argCount + 1) * sizeof(char*));

for (NSUInteger i = 0; i < argCount; i++)
{
argsC[i] = strdup([[argsM objectAtIndex:i] UTF8String]);
}
argsC[argCount] = NULL;

posix_spawn_file_actions_t action;
posix_spawn_file_actions_init(&action);

int outErr[2];
pipe(outErr);
posix_spawn_file_actions_adddup2(&action, outErr[1], STDERR_FILENO);
posix_spawn_file_actions_addclose(&action, outErr[0]);

int out[2];
pipe(out);
posix_spawn_file_actions_adddup2(&action, out[1], STDOUT_FILENO);
posix_spawn_file_actions_addclose(&action, out[0]);

pid_t task_pid;
int status = -200;
int spawnError = posix_spawn(&task_pid, [ldidPath fileSystemRepresentation], &action, NULL, (char* const*)argsC, NULL);
for (NSUInteger i = 0; i < argCount; i++)
{
free(argsC[i]);
}
free(argsC);

if(spawnError != 0)
{
NSLog(@"posix_spawn error %d\n", spawnError);
return spawnError;
}

do
{
if (waitpid(task_pid, &status, 0) != -1) {
//printf("Child status %dn", WEXITSTATUS(status));
} else
{
perror("waitpid");
return -222;
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));

close(outErr[1]);
close(out[1]);

NSString* ldidOutput = getNSStringFromFile(out[0]);
if(output)
{
*output = ldidOutput;
}

NSString* ldidErrorOutput = getNSStringFromFile(outErr[0]);
if(errorOutput)
{
*errorOutput = ldidErrorOutput;
}

return WEXITSTATUS(status);
}

BOOL certificateHasDataForExtensionOID(SecCertificateRef certificate, CFStringRef oidString)
{
if(certificate == NULL || oidString == NULL)
Expand Down Expand Up @@ -377,6 +476,52 @@ int signApp(NSString* appPath)
return -1;
}
#else
int signAdhoc(NSString *filePath, NSDictionary *entitlements)
{
if (@available(iOS 15, *)) {
return codesign_sign_adhoc(filePath.fileSystemRepresentation, true, entitlements);
}
// If iOS 14 is so great, how come there is no iOS 14 2?????
else {
if(!isLdidInstalled()) return 173;

NSString *entitlementsPath = nil;
NSString *signArg = @"-s";
NSString* errorOutput;
if(entitlements)
{
NSData *entitlementsXML = [NSPropertyListSerialization dataWithPropertyList:entitlements format:NSPropertyListXMLFormat_v1_0 options:0 error:nil];
if (entitlementsXML) {
entitlementsPath = [[NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString] stringByAppendingPathExtension:@"plist"];
[entitlementsXML writeToFile:entitlementsPath atomically:NO];
signArg = [@"-S" stringByAppendingString:entitlementsPath];
}

}
int ldidRet = runLdid(@[signArg, filePath], nil, &errorOutput);
if (entitlementsPath) {
[[NSFileManager defaultManager] removeItemAtPath:entitlementsPath error:nil];
}

NSLog(@"ldid exited with status %d", ldidRet);

NSLog(@"- ldid error output start -");

printMultilineNSString(errorOutput);

NSLog(@"- ldid error output end -");

if(ldidRet == 0)
{
return 0;
}
else
{
return 175;
}
}
}

int signApp(NSString* appPath)
{
NSDictionary* appInfoDict = infoDictionaryForAppPath(appPath);
Expand Down Expand Up @@ -460,7 +605,7 @@ int signApp(NSString* appPath)
}

// First attempt ad hoc signing
int r = codesign_sign_adhoc(tmpPath.fileSystemRepresentation, true, entitlementsToUse);
int r = signAdhoc(tmpPath, entitlementsToUse);
if (r != 0) {
NSLog(@"[%@] Adhoc signing failed with error code %d, continuing anyways...\n", filePath, r);
}
Expand Down Expand Up @@ -545,6 +690,7 @@ void applyPatchesToInfoDictionary(NSString* appPath)
// 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
// 173: app is not signed and cannot be signed because ldid not installed or didn't work
// 174:
int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, BOOL useInstalldMethod)
{
Expand Down Expand Up @@ -892,6 +1038,41 @@ int installTrollStore(NSString* pathToTar)
NSString* tmpTrollStorePath = [tmpPayloadPath stringByAppendingPathComponent:@"TrollStore.app"];
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStorePath]) return 1;

if (@available(iOS 15, *)) {} else {
// Transfer existing ldid installation if it exists
// But only if the to-be-installed version of TrollStore is 1.5.0 or above
// This is to make it possible to downgrade to older versions still

NSString* toInstallInfoPlistPath = [tmpTrollStorePath stringByAppendingPathComponent:@"Info.plist"];
if(![[NSFileManager defaultManager] fileExistsAtPath:toInstallInfoPlistPath]) return 1;

NSDictionary* toInstallInfoDict = [NSDictionary dictionaryWithContentsOfFile:toInstallInfoPlistPath];
NSString* toInstallVersion = toInstallInfoDict[@"CFBundleVersion"];

NSComparisonResult result = [@"1.5.0" compare:toInstallVersion options:NSNumericSearch];
if(result != NSOrderedDescending)
{
NSString* existingLdidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
NSString* existingLdidVersionPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid.version"];
if([[NSFileManager defaultManager] fileExistsAtPath:existingLdidPath])
{
NSString* tmpLdidPath = [tmpTrollStorePath stringByAppendingPathComponent:@"ldid"];
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpLdidPath])
{
[[NSFileManager defaultManager] copyItemAtPath:existingLdidPath toPath:tmpLdidPath error:nil];
}
}
if([[NSFileManager defaultManager] fileExistsAtPath:existingLdidVersionPath])
{
NSString* tmpLdidVersionPath = [tmpTrollStorePath stringByAppendingPathComponent:@"ldid.version"];
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpLdidVersionPath])
{
[[NSFileManager defaultManager] copyItemAtPath:existingLdidVersionPath toPath:tmpLdidVersionPath error:nil];
}
}
}
}

// Merge existing URL scheme settings value
if(!getTSURLSchemeState(nil))
{
Expand Down Expand Up @@ -1171,6 +1352,15 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
}
uninstallTrollStore(YES);
}
else if([cmd isEqualToString:@"install-ldid"])
{
if (@available(iOS 15, *)) {} else {
if(args.count < 3) return -3;
NSString* ldidPath = args[1];
NSString* ldidVersion = args[2];
installLdid(ldidPath, ldidVersion);
}
}
else if([cmd isEqualToString:@"refresh"])
{
refreshAppRegistrations(YES);
Expand Down
1 change: 1 addition & 0 deletions Shared/TSUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString*
extern void killall(NSString* processName, BOOL softly);
extern void respring(void);
extern void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion));
extern void fetchLatestLdidVersion(void (^completionHandler)(NSString* latestVersion));

extern NSArray* trollStoreInstalledAppBundlePaths();
extern NSArray* trollStoreInstalledAppContainerPaths();
Expand Down
5 changes: 5 additions & 0 deletions Shared/TSUtil.m
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,11 @@ void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVers
github_fetchLatestVersion(@"opa334/TrollStore", completionHandler);
}

void fetchLatestLdidVersion(void (^completionHandler)(NSString* latestVersion))
{
github_fetchLatestVersion(@"opa334/ldid", completionHandler);
}

NSArray* trollStoreInstalledAppContainerPaths()
{
NSMutableArray* appContainerPaths = [NSMutableArray new];
Expand Down
1 change: 1 addition & 0 deletions TrollStore/Resources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@
<key>TSRootBinaries</key>
<array>
<string>trollstorehelper</string>
<string>ldid</string>
</array>
</dict>
</plist>
13 changes: 11 additions & 2 deletions TrollStore/TSApplicationsManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,20 @@ - (NSError*)errorForCode:(int)code
case 172:
errorDescription = @"The app does not contain an Info.plist file.";
break;
case 173:
errorDescription = @"The app is not signed with a fake CoreTrust certificate and ldid is not installed. Install ldid in the settings tab and try again.";
break;
case 174:
errorDescription = @"The app's main executable does not exist.";
break;
case 175:
errorDescription = @"Failed to sign the app.";
case 175: {
if (@available(iOS 15, *)) {
errorDescription = @"Failed to sign the app.";
}
else {
errorDescription = @"Failed to sign the app. ldid returned a non zero status code.";
}
}
break;
case 176:
errorDescription = @"The app's Info.plist is missing required values.";
Expand Down
2 changes: 2 additions & 0 deletions TrollStore/TSInstallationController.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@

+ (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completion;

+ (void)installLdid;

@end
Loading

0 comments on commit c6ea42c

Please sign in to comment.