Skip to content

Commit

Permalink
Merge pull request #206 from hugeBlack/main
Browse files Browse the repository at this point in the history
Fix #195, bugs when installing / substituting apps and probably #161 #173
  • Loading branch information
hugeBlack authored Nov 9, 2024
2 parents 06ae3c2 + 8a3aaef commit 8b6e503
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 23 deletions.
2 changes: 1 addition & 1 deletion LCSharedUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ + (BOOL)launchToGuestApp {
if (!access(tsPath.UTF8String, F_OK)) {
urlScheme = @"apple-magnifier://enable-jit?bundle-id=%@";
} else if (self.certificatePassword) {
tries = 8;
tries = 2;
urlScheme = [NSString stringWithFormat:@"%@://livecontainer-relaunch", lcAppUrlScheme];
} else {
urlScheme = @"sidestore://sidejit-enable?bid=%@";
Expand Down
62 changes: 54 additions & 8 deletions LiveContainerSwiftUI/LCAppListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,29 @@ struct LCAppListView : View, LCAppBannerDelegate, LCAppModelDelegate {
var outputFolder = LCPath.bundlePath.appendingPathComponent(appRelativePath)
var appToReplace : LCAppModel? = nil
// Folder exist! show alert for user to choose which bundle to replace
let sameBundleIdApp = self.apps.filter { app in
var sameBundleIdApp = self.apps.filter { app in
return app.appInfo.bundleIdentifier()! == newAppInfo.bundleIdentifier()
}
if sameBundleIdApp.count == 0 {
sameBundleIdApp = self.hiddenApps.filter { app in
return app.appInfo.bundleIdentifier()! == newAppInfo.bundleIdentifier()
}

// we found a hidden app, we need to authenticate before proceeding
if sameBundleIdApp.count > 0 && !sharedModel.isHiddenAppUnlocked {
do {
if !(try await LCUtils.authenticateUser()) {
return
}
} catch {
errorInfo = error.localizedDescription
errorShow = true
return
}
}

}

if fm.fileExists(atPath: outputFolder.path) || sameBundleIdApp.count > 0 {
appRelativePath = "\(newAppInfo.bundleIdentifier()!)_\(Int(CFAbsoluteTimeGetCurrent())).app"

Expand All @@ -407,13 +427,15 @@ struct LCAppListView : View, LCAppBannerDelegate, LCAppModelDelegate {
return
}

outputFolder = LCPath.bundlePath.appendingPathComponent(installOptionChosen.nameOfFolderToInstall)
if let appToReplace = installOptionChosen.appToReplace, appToReplace.uiIsShared {
outputFolder = LCPath.lcGroupBundlePath.appendingPathComponent(installOptionChosen.nameOfFolderToInstall)
} else {
outputFolder = LCPath.bundlePath.appendingPathComponent(installOptionChosen.nameOfFolderToInstall)
}
appRelativePath = installOptionChosen.nameOfFolderToInstall
appToReplace = installOptionChosen.appToReplace
if installOptionChosen.isReplace {
try fm.removeItem(at: outputFolder)
self.apps.removeAll { appNow in
return appNow.appInfo.relativeBundlePath == installOptionChosen.nameOfFolderToInstall
}
}
}
// Move it!
Expand All @@ -440,12 +462,36 @@ struct LCAppListView : View, LCAppBannerDelegate, LCAppModelDelegate {
if let signError {
throw signError
}
// set data folder to the folder of the chosen app
if let appToReplace = appToReplace {

if let appToReplace {
// copy previous configration to new app
finalNewApp.isLocked = appToReplace.appInfo.isLocked
finalNewApp.isHidden = appToReplace.appInfo.isHidden
finalNewApp.isJITNeeded = appToReplace.appInfo.isJITNeeded
finalNewApp.isShared = appToReplace.appInfo.isShared
finalNewApp.bypassAssertBarrierOnQueue = appToReplace.appInfo.bypassAssertBarrierOnQueue
finalNewApp.doSymlinkInbox = appToReplace.appInfo.doSymlinkInbox
finalNewApp.setDataUUID(appToReplace.appInfo.getDataUUIDNoAssign())
finalNewApp.setTweakFolder(appToReplace.appInfo.tweakFolder())
}
DispatchQueue.main.async {
self.apps.append(LCAppModel(appInfo: finalNewApp))
if let appToReplace {
if appToReplace.uiIsHidden {
self.hiddenApps.removeAll { appNow in
return appNow == appToReplace
}
self.hiddenApps.append(LCAppModel(appInfo: finalNewApp, delegate: self))
} else {
self.apps.removeAll { appNow in
return appNow == appToReplace
}
self.apps.append(LCAppModel(appInfo: finalNewApp, delegate: self))
}

} else {
self.apps.append(LCAppModel(appInfo: finalNewApp, delegate: self))
}

self.installprogressVisible = false
}
}
Expand Down
2 changes: 1 addition & 1 deletion LiveContainerSwiftUI/LCSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ struct LCSettingsView: View {
}
} message: {
if folderRemoveCount > 0 {
Text("lc.settings.cleanDataFolderConfirm".localizeWithFormat(folderRemoveCount))
Text("lc.settings.cleanDataFolderConfirm %lld".localizeWithFormat(folderRemoveCount))
} else {
Text("lc.settings.noDataFolderToClean".loc)
}
Expand Down
4 changes: 2 additions & 2 deletions LiveContainerUI/LCAppInfo.m
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ - (void)preprocessBundleBeforeSiging:(NSURL *)bundleURL completion:(dispatch_blo
- (void)patchExecAndSignIfNeedWithCompletionHandler:(void(^)(NSString* errorInfo))completetionHandler progressHandler:(void(^)(NSProgress* errorInfo))progressHandler forceSign:(BOOL)forceSign {
NSString *appPath = self.bundlePath;
NSString *infoPath = [NSString stringWithFormat:@"%@/Info.plist", appPath];
NSMutableDictionary *info = [NSMutableDictionary dictionaryWithContentsOfFile:infoPath];
NSMutableDictionary *info = _info;
if (!info) {
completetionHandler(@"Info.plist not found");
return;
Expand Down Expand Up @@ -255,7 +255,7 @@ - (void)patchExecAndSignIfNeedWithCompletionHandler:(void(^)(NSString* errorInfo
[NSFileManager.defaultManager removeItemAtPath:tmpExecPath error:nil];

// Save sign ID and restore bundle ID
[info writeToFile:infoPath atomically:YES];
[self save];


if(error) {
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,4 @@ To install tweaks, you can use the built-in tweak manager in LiveContainer, whic
- @hugeBlack for SwiftUI contribution
- @Staubgeborener for automatic AltStore/SideStore source updater
- @fkunn1326 for improved app hiding
- @slds1 for dynamic color frature
- @slds1 for dynamic color feature
32 changes: 32 additions & 0 deletions TPRO.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// by khanhduytran0
#define _COMM_PAGE_START_ADDRESS (0x0000000FFFFFC000ULL)
//#define _COMM_PAGE_TPRO_SUPPORT (_COMM_PAGE_START_ADDRESS + ????)
#define _COMM_PAGE_TPRO_WRITE_ENABLE (_COMM_PAGE_START_ADDRESS + 0x0D0)
//#define _COMM_PAGE_TPRO_WRITE_DISABLE (_COMM_PAGE_START_ADDRESS + 0x0D8)

static inline bool os_thread_self_restrict_tpro_to_rw() {
if (!*(uint64_t*)_COMM_PAGE_TPRO_WRITE_ENABLE) {
// Doesn't have TPRO, skip this
return false;
}
__asm__ __volatile__ (
"mov x0, %0\n"
"ldr x0, [x0]\n"
"msr s3_6_c15_c1_5, x0\n"
"isb sy\n"
:: "r" (_COMM_PAGE_TPRO_WRITE_ENABLE)
: "memory", "x0"
);
return true;
}

/*
inline uint64_t sprr_read() {
uint64_t v;
__asm__ __volatile__(
"isb sy\n"
"mrs %0, s3_6_c15_c1_5\n"
: "=r"(v)::"memory");
return v;
}
*/
20 changes: 20 additions & 0 deletions TweakLoader/TweakLoader.m
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,23 @@ static void TweakLoaderConstructor() {
});
}
}

// fix dlsym(RTLD_DEFAULT, bd_requestURLParameters): symbol not found
// by declearing a dummy funtion that generates trash data since it's just a user tracking function
// see https://github.com/volcengine/datarangers-sdk-ios/blob/7ca475f90be36016d35281a02b4e44b6f99f4c72/BDAutoTracker/Classes/Core/Network/BDAutoTrackNetworkRequest.m#L22
NSMutableDictionary * bd_requestURLParameters(NSString *appID) {
NSMutableDictionary *result = [NSMutableDictionary new];
[result setValue:@"ios" forKey:@"platform"];
[result setValue:@"ios" forKey:@"sdk_lib"];
[result setValue:@"iPhone" forKey:@"device_platform"];
[result setValue:@(61002) forKey:@"sdk_version"];
[result setValue:@"iOS" forKey:@"os"];
[result setValue:@"18.0" forKey:@"os_version"];
[result setValue:@"6.9.69" forKey:@"app_version"];
[result setValue:@"iPhone14,2" forKey:@"device_model"];
[result setValue:@(NO) forKey:@"is_upgrade_user"];
[result setValue:@"00000000-0000-0000-0000-000000000000" forKey:@"idfa"];
[result setValue:@"00000000-0000-0000-0000-000000000000" forKey:@"idfv"];
[result setValue:@"6.9.69" forKey:@"version_code"];
return result;
}
2 changes: 1 addition & 1 deletion TweakLoader/UIKit+GuestHooks.m
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void LCOpenWebPage(NSString* webPageUrlString, NSString* originalUrl) {
NSString *message = @"lc.guestTweak.openWebPageTip".loc;
UIWindow *window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"LiveContainer" message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"lc.common.ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"lc.common.ok".loc style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
[NSClassFromString(@"LCSharedUtils") setWebPageUrlForNextLaunch:webPageUrlString];
[NSClassFromString(@"LCSharedUtils") launchToGuestApp];
}];
Expand Down
2 changes: 1 addition & 1 deletion control
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: com.kdt.livecontainer
Name: livecontainer
Version: 2.1.2
Version: 3.0.0
Architecture: iphoneos-arm
Description: Run iOS app without actually installing it!
Maintainer: khanhduytran0
Expand Down
22 changes: 14 additions & 8 deletions main.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <signal.h>
#include <sys/mman.h>
#include <stdlib.h>
#include "TPRO.h"

static int (*appMain)(int, char**);
static const char *dyldImageName;
Expand Down Expand Up @@ -124,13 +125,17 @@ static void overwriteExecPath_handler(int signum, siginfo_t* siginfo, void* cont
size_t newLen = strlen(newPath);
// Check if it's long enough...
assert(maxLen >= newLen);

// Make it RW and overwrite now
kern_return_t ret = builtin_vm_protect(mach_task_self(), (mach_vm_address_t)path, maxLen, false, PROT_READ | PROT_WRITE);
if (ret != KERN_SUCCESS) {
ret = builtin_vm_protect(mach_task_self(), (mach_vm_address_t)path, maxLen, false, PROT_READ | PROT_WRITE | VM_PROT_COPY);

// if we don't have TPRO, we will use the old way
if(!os_thread_self_restrict_tpro_to_rw()) {
// Make it RW and overwrite now
kern_return_t ret = builtin_vm_protect(mach_task_self(), (mach_vm_address_t)path, maxLen, false, PROT_READ | PROT_WRITE);
if (ret != KERN_SUCCESS) {
ret = builtin_vm_protect(mach_task_self(), (mach_vm_address_t)path, maxLen, false, PROT_READ | PROT_WRITE | VM_PROT_COPY);
}
assert(ret == KERN_SUCCESS);
}
assert(ret == KERN_SUCCESS);

bzero(path, maxLen);
strncpy(path, newPath, newLen);
}
Expand All @@ -157,6 +162,7 @@ static void overwriteExecPath(NSString *bundlePath) {
char currPath[PATH_MAX];
uint32_t len = PATH_MAX;
_NSGetExecutablePath(currPath, &len);

if (strncmp(currPath, newPath, newLen)) {
struct sigaction sa, saOld;
sa.sa_sigaction = overwriteExecPath_handler;
Expand Down Expand Up @@ -395,9 +401,9 @@ static void overwriteExecPath(NSString *bundlePath) {
// Go!
NSLog(@"[LCBootstrap] jumping to main %p", appMain);
argv[0] = (char *)appExecPath;
appMain(argc, argv);
int ret = appMain(argc, argv);

return nil;
return [NSString stringWithFormat:@"App returned from its main function with code %d.", ret];
}

static void exceptionHandler(NSException *exception) {
Expand Down

0 comments on commit 8b6e503

Please sign in to comment.