Skip to content

Commit

Permalink
Implement cert obtaining safely
Browse files Browse the repository at this point in the history
  • Loading branch information
khanhduytran0 committed Apr 18, 2024
1 parent df808e8 commit ee06075
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 23 deletions.
8 changes: 7 additions & 1 deletion LCAppDelegate.m
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#import "LCAppDelegate.h"
#import "LCJITLessSetupViewController.h"
#import "LCRootViewController.h"

@implementation LCAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
LCRootViewController *viewController = [[LCRootViewController alloc] init];
UIViewController *viewController;
if ([NSBundle.mainBundle.executablePath.lastPathComponent isEqualToString:@"JITLessSetup"]) {
viewController = [[LCJITLessSetupViewController alloc] init];
} else {
viewController = [[LCRootViewController alloc] init];
}
_window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
_rootViewController = [[UINavigationController alloc] initWithRootViewController:viewController];
_window.rootViewController = _rootViewController;
Expand Down
5 changes: 5 additions & 0 deletions LCJITLessSetupViewController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#import <UIKit/UIKit.h>

@interface LCJITLessSetupViewController : UIViewController

@end
42 changes: 42 additions & 0 deletions LCJITLessSetupViewController.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#import "LCJITLessSetupViewController.h"
#import "LCUtils.h"
#import "UIKitPrivate.h"

@implementation LCJITLessSetupViewController

- (void)showDialogTitle:(NSString *)title message:(NSString *)message handler:(void(^)(UIAlertAction *))handler {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:handler];
[alert addAction:okAction];
[self presentViewController:alert animated:YES completion:nil];
}

- (void)loadView {
[super loadView];
self.view.backgroundColor = UIColor.systemBackgroundColor;
self.title = @"LiveContainer JIT-less setup";

if (!LCUtils.storeCertPassword) {
[self showDialogTitle:@"Error" message:@"Failed to find certificate password" handler:nil];
return;
}

[LCUtils updateCertPassword];
[LCUtils changeMainExecutableTo:@"LiveContainer_PleaseDoNotShortenTheExecutableNameBecauseItIsUsedToReserveSpaceForOverwritingThankYou"];

NSError *error;
NSURL *url = [LCUtils archiveIPAWithError:&error];
if (!url) {
[self showDialogTitle:@"Error" message:error.localizedDescription handler:nil];
return;
}

[self showDialogTitle:@"Instruction" message:@"Done. Press OK to finish setting up."
handler:^(UIAlertAction * action) {
[UIApplication.sharedApplication openURL:[NSURL URLWithString:[NSString stringWithFormat:@"sidestore://install?url=%@", url]] options:@{} completionHandler:nil];
}];
}

@end
26 changes: 25 additions & 1 deletion LCRootViewController.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import "LCRootViewController.h"
#import "LCUtils.h"
#import "MBRoundProgressView.h"
#import "UIKitPrivate.h"
#import "unarchive.h"
Expand Down Expand Up @@ -139,7 +140,10 @@ - (void)loadView {
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay target:self action:@selector(launchButtonTapped)],
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addButtonTapped)]
];
self.navigationItem.leftBarButtonItems[0].enabled = NO;

if (!LCUtils.certPassword) {
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Setup JIT-less" style:UIBarButtonItemStylePlain target:self action:@selector(setupJITLessTapped)];
}
}

- (void)viewWillAppear:(BOOL)animated {
Expand Down Expand Up @@ -189,6 +193,26 @@ - (void)showInputDialogTitle:(NSString *)title message:(NSString *)message place
[self presentViewController:alert animated:YES completion:nil];
}

- (void)setupJITLessTapped {
if (!LCUtils.isAppGroupSideStore) {
[self showDialogTitle:@"Error" message:@"Unsupported installation method. Please use SideStore to setup this feature."];
return;
}

[LCUtils changeMainExecutableTo:@"JITLessSetup"];
NSError *error;
NSURL *url = [LCUtils archiveIPAWithError:&error];
if (!url) {
[self showDialogTitle:@"Error" message:error.localizedDescription];
return;
}

[self showDialogTitle:@"Instruction" message:@"Setting up JIT-less allows you to use LiveContainer without having to enable JIT. LiveContainer needs to safely obtain the certificate password from SideStore. Press OK to continue."
handler:^(UIAlertAction * action) {
[UIApplication.sharedApplication openURL:[NSURL URLWithString:[NSString stringWithFormat:@"sidestore://install?url=%@", url]] options:@{} completionHandler:nil];
}];
}

- (void)addButtonTapped {
UIDocumentPickerViewController* documentPickerVC = [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:@[[UTType typeWithFilenameExtension:@"ipa" conformingToType:UTTypeData]]];
documentPickerVC.allowsMultipleSelection = YES;
Expand Down
20 changes: 20 additions & 0 deletions LCUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#import <Foundation/Foundation.h>

@interface PKZipArchiver : NSObject

- (NSData *)zippedDataForURL:(NSURL *)url;

@end

@interface LCUtils : NSObject

+ (NSString *)certPassword;
+ (void)updateCertPassword;
+ (NSData *)storeCertPassword;

+ (BOOL)isAppGroupSideStore;
+ (NSError *)changeMainExecutableTo:(NSString *)exec;

+ (NSURL *)archiveIPAWithError:(NSError **)error;

@end
86 changes: 86 additions & 0 deletions LCUtils.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#import "LCUtils.h"
#include <dlfcn.h>

@implementation LCUtils

#pragma mark Certificate password

+ (NSString *)storeCertPassword {
NSDictionary *dict = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrService: @"com.SideStore.SideStore",
(id)kSecAttrAccount: @"signingCertificatePassword",
(id)kSecAttrSynchronizable: (id)kSecAttrSynchronizableAny,
(id)kSecMatchLimit: (id)kSecMatchLimitOne,
(id)kSecReturnData: (id)kCFBooleanTrue
};
CFTypeRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict, &result);
if (status == errSecSuccess) {
return [[NSString alloc] initWithData:(__bridge NSData *)result encoding:NSUTF8StringEncoding];
} else {
return nil;
}
}

+ (void)updateCertPassword {
[NSUserDefaults.standardUserDefaults setObject:self.storeCertPassword forKey:@"LCCertificateID"];
}

+ (NSString *)certPassword {
return [NSUserDefaults.standardUserDefaults objectForKey:@"LCCertificateID"];
}

#pragma mark Setup

+ (NSString *)appGroupID {
return [NSBundle.mainBundle.infoDictionary[@"ALTAppGroups"] firstObject];
}

+ (BOOL)isAppGroupSideStore {
return [self.appGroupID containsString:@"com.SideStore.SideStore"];
}

+ (NSError *)changeMainExecutableTo:(NSString *)exec {
NSError *error;
NSURL *appGroupPath = [NSFileManager.defaultManager containerURLForSecurityApplicationGroupIdentifier:self.appGroupID];
NSURL *infoPath = [appGroupPath URLByAppendingPathComponent:@"Apps/com.kdt.livecontainer/App.app/Info.plist"];
NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfURL:infoPath];
if (!infoDict) return nil;

infoDict[@"CFBundleExecutable"] = exec;
[infoDict writeToURL:infoPath error:&error];
return error;
}

+ (NSURL *)archiveIPAWithError:(NSError **)error {
NSFileManager *manager = NSFileManager.defaultManager;
NSURL *appGroupPath = [NSFileManager.defaultManager containerURLForSecurityApplicationGroupIdentifier:self.appGroupID];
NSURL *bundlePath = [appGroupPath URLByAppendingPathComponent:@"Apps/com.kdt.livecontainer"];

NSURL *tmpPath = [appGroupPath URLByAppendingPathComponent:@"tmp"];
[manager removeItemAtURL:tmpPath error:nil];

NSURL *tmpPayloadPath = [tmpPath URLByAppendingPathComponent:@"Payload"];
NSURL *tmpIPAPath = [appGroupPath URLByAppendingPathComponent:@"tmp.ipa"];

[manager createDirectoryAtURL:tmpPath withIntermediateDirectories:YES attributes:nil error:error];
if (*error) return nil;

[manager copyItemAtURL:bundlePath toURL:tmpPayloadPath error:error];
if (*error) return nil;

dlopen("/System/Library/PrivateFrameworks/PassKitCore.framework/PassKitCore", RTLD_GLOBAL);
NSData *zipData = [[NSClassFromString(@"PKZipArchiver") new] zippedDataForURL:tmpPayloadPath.URLByDeletingLastPathComponent];
if (!zipData) return nil;

[manager removeItemAtURL:tmpPath error:error];
if (*error) return nil;

[zipData writeToURL:tmpIPAPath options:0 error:error];
if (*error) return nil;

return tmpIPAPath;
}

@end
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ CONFIG_BRANCH = $(shell git branch --show-current)
CONFIG_COMMIT = $(shell git log --oneline | sed '2,10000000d' | cut -b 1-7)

# Build the UI library
LiveContainerUI_FILES = LCAppDelegate.m LCRootViewController.m MBRoundProgressView.m unarchive.m AppInfo.m
LiveContainerUI_FILES = LCAppDelegate.m LCJITLessSetupViewController.m LCRootViewController.m LCUtils.m MBRoundProgressView.m unarchive.m AppInfo.m
LiveContainerUI_CFLAGS = \
-fobjc-arc \
-DCONFIG_TYPE=\"$(CONFIG_TYPE)\" \
Expand All @@ -31,14 +31,17 @@ include $(THEOS_MAKE_PATH)/library.mk

# Build the app
APPLICATION_NAME = LiveContainer

$(APPLICATION_NAME)_FILES = dyld_bypass_validation.m main.m utils.m FixCydiaSubstrate.c fishhook/fishhook.c
$(APPLICATION_NAME)_CODESIGN_FLAGS = -Sentitlements.xml
$(APPLICATION_NAME)_CFLAGS = -fobjc-arc
$(APPLICATION_NAME)_LDFLAGS = -e_LiveContainerMain -rpath @loader_path/Frameworks
$(APPLICATION_NAME)_FRAMEWORKS = UIKit
#$(APPLICATION_NAME)_INSTALL_PATH = /Applications/LiveContainer.app

include $(THEOS_MAKE_PATH)/application.mk

# Make the executable name longer so we have space to overwrite it with the guest app's name
before-package::
@cp .theos/_/Applications/LiveContainer.app/LiveContainer .theos/_/Applications/LiveContainer.app/JITLessSetup
@ldid -Sentitlements_setup.xml .theos/_/Applications/LiveContainer.app/JITLessSetup
@mv .theos/_/Applications/LiveContainer.app/LiveContainer .theos/_/Applications/LiveContainer.app/LiveContainer_PleaseDoNotShortenTheExecutableNameBecauseItIsUsedToReserveSpaceForOverwritingThankYou
22 changes: 13 additions & 9 deletions entitlements.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>com.kdt.livecontainer</string>
<key>get-task-allow</key>
<true/>
<!-- Optional entitlements -->
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
<true/>
<key>com.apple.developer.kernel.increased-memory-limit</key>
<true/>
<key>application-identifier</key>
<string>com.kdt.livecontainer</string>
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
<true/>
<key>com.apple.developer.kernel.increased-memory-limit</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.SideStore.SideStore</string>
</array>
<key>get-task-allow</key>
<true/>
</dict>
</plist>
18 changes: 18 additions & 0 deletions entitlements_setup.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>com.kdt.livecontainer</string>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.SideStore.SideStore</string>
</array>
<key>get-task-allow</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>group.*</string>
</array>
</dict>
</plist>
14 changes: 4 additions & 10 deletions main.m
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,6 @@ static void overwriteExecPath(NSString *bundlePath) {

static NSString* invokeAppMain(NSString *selectedApp, int argc, char *argv[]) {
NSString *appError = nil;
// First of all, let's check if we have JIT
for (int i = 0; i < 10 && !checkJITEnabled(); i++) {
usleep(1000*100);
}
if (!checkJITEnabled()) {
appError = @"JIT was not enabled";
return appError;
}

NSFileManager *fm = NSFileManager.defaultManager;
NSString *docPath = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
Expand All @@ -197,8 +189,10 @@ static void overwriteExecPath(NSString *bundlePath) {
symlink(target.UTF8String, tweakLoaderPath.UTF8String);
}

// Bypass library validation so we can load arbitrary binaries
init_bypassDyldLibValidation();
// If JIT is enabled, bypass library validation so we can load arbitrary binaries
if (checkJITEnabled()) {
init_bypassDyldLibValidation();
}

// Bind _dyld_get_all_image_infos
init_fixCydiaSubstrate();
Expand Down

0 comments on commit ee06075

Please sign in to comment.