Skip to content

Commit 8e4a8ad

Browse files
committed
2.0 beta
1. faster app injection 2. fixed the issue where injected apps could not be updated in the App Store 3. fixed the issue where injected apps could not sync to Apple Watch 4. fixed the issue where battery usage in the Settings app could not be loaded 5. fixed the issue of slow userspace rebooting
1 parent 81f5aa7 commit 8e4a8ad

File tree

11 files changed

+193
-165
lines changed

11 files changed

+193
-165
lines changed

Bootstrap.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@
593593
"$(PROJECT_DIR)",
594594
"$(PROJECT_DIR)/basebin/common/lib",
595595
);
596-
MARKETING_VERSION = 1.4;
596+
MARKETING_VERSION = 2.0beta;
597597
OTHER_LDFLAGS = "";
598598
PRODUCT_BUNDLE_IDENTIFIER = com.roothide.Bootstrap;
599599
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -639,7 +639,7 @@
639639
"$(PROJECT_DIR)",
640640
"$(PROJECT_DIR)/basebin/common/lib",
641641
);
642-
MARKETING_VERSION = 1.4;
642+
MARKETING_VERSION = 2.0beta;
643643
OTHER_LDFLAGS = "";
644644
PRODUCT_BUNDLE_IDENTIFIER = com.roothide.Bootstrap;
645645
PRODUCT_NAME = "$(TARGET_NAME)";

Bootstrap/AppEnabler.m

Lines changed: 41 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#import <Foundation/Foundation.h>
2+
#include <sys/clonefile.h>
23
#include <sys/stat.h>
34
#include "AppInfo.h"
45
#include "common.h"
@@ -73,93 +74,34 @@
7374
return relPath;
7475
}
7576

76-
NSArray* appBackupFileNames = @[
77-
@"Info.plist",
78-
@"_CodeSignature",
79-
@"SC_Info",
80-
];
81-
82-
//will skip empty dir
83-
int backupApp(NSString* bundlePath)
84-
{
85-
NSFileManager* fm = NSFileManager.defaultManager;
86-
87-
NSString* backup = [bundlePath stringByAppendingPathExtension:@"appbackup"];
88-
89-
if([fm fileExistsAtPath:backup]) {
90-
ASSERT(![fm fileExistsAtPath:[backup.stringByDeletingLastPathComponent stringByAppendingPathComponent:@".appbackup"]]);
91-
ASSERT([fm removeItemAtPath:backup error:nil]);
92-
}
93-
94-
NSDictionary* appInfo = [NSDictionary dictionaryWithContentsOfFile:[bundlePath stringByAppendingPathComponent:@"Info.plist"]];
95-
BOOL encryptedApp = [[NSFileManager defaultManager] fileExistsAtPath:[bundlePath stringByAppendingPathComponent:@"SC_Info"]];
96-
97-
NSString *resolvedPath = [[bundlePath stringByResolvingSymlinksInPath] stringByStandardizingPath];
98-
NSDirectoryEnumerator<NSURL *> *directoryEnumerator = [fm enumeratorAtURL:[NSURL fileURLWithPath:resolvedPath isDirectory:YES] includingPropertiesForKeys:@[NSURLIsRegularFileKey] options:0 errorHandler:nil];
99-
100-
int backupFileCount=0;
101-
for (NSURL *enumURL in directoryEnumerator) { @autoreleasepool {
102-
NSNumber *isFile=nil;
103-
ASSERT([enumURL getResourceValue:&isFile forKey:NSURLIsRegularFileKey error:nil] && isFile!=nil);
104-
if (![isFile boolValue]) continue;
105-
106-
BOOL copy = NO;
107-
108-
if([appBackupFileNames containsObject:enumURL.path.lastPathComponent]) {
109-
copy = YES;
110-
}
111-
else if(encryptedApp) {
112-
if([appInfo[@"CFBundleExecutable"] isEqualToString:enumURL.path.lastPathComponent]) {
113-
copy = YES;
114-
}
115-
}
116-
else {
117-
bool ismacho=false, islib=false;
118-
ASSERT(machoGetInfo(enumURL.fileSystemRepresentation, &ismacho, &islib));
119-
if(ismacho) {
120-
copy = YES;
121-
}
122-
}
123-
124-
125-
//bundlePath should be a real-path
126-
NSString* subPath = relativize(enumURL, [NSURL fileURLWithPath:bundlePath], YES);
127-
NSString* backupPath = [backup stringByAppendingPathComponent:subPath];
128-
129-
if(![fm fileExistsAtPath:backupPath.stringByDeletingLastPathComponent])
130-
ASSERT([fm createDirectoryAtPath:backupPath.stringByDeletingLastPathComponent withIntermediateDirectories:YES attributes:nil error:nil]);
131-
132-
if(copy)
133-
{
134-
NSError* err=nil;
135-
ASSERT([fm copyItemAtPath:enumURL.path toPath:backupPath error:&err]);
136-
SYSLOG("copied %@ => %@", enumURL.path, backupPath);
137-
138-
backupFileCount++;
139-
}
140-
else {
141-
ASSERT(link(enumURL.path.UTF8String, backupPath.UTF8String)==0);
142-
}
143-
144-
} }
145-
146-
ASSERT(backupFileCount > 0);
147-
148-
ASSERT([[NSString new] writeToFile:[backup.stringByDeletingLastPathComponent stringByAppendingPathComponent:@".appbackup"] atomically:YES encoding:NSUTF8StringEncoding error:nil]);
149-
150-
return 0;
151-
}
152-
15377
//if the app package is changed/upgraded, the directory structure may change and some paths may become invalid.
15478
int restoreApp(NSString* bundlePath)
15579
{
15680
SYSLOG("restoreApp=%@", bundlePath);
15781
NSFileManager* fm = NSFileManager.defaultManager;
15882

15983
NSString* backup = [bundlePath stringByAppendingPathExtension:@"appbackup"];
84+
NSString* backupFlag = [bundlePath.stringByDeletingLastPathComponent stringByAppendingPathComponent:@".appbackup"];
16085

16186
ASSERT([fm fileExistsAtPath:backup]);
162-
ASSERT([fm fileExistsAtPath:[backup.stringByDeletingLastPathComponent stringByAppendingPathComponent:@".appbackup"]]);
87+
ASSERT([fm fileExistsAtPath:backupFlag]);
88+
NSString* backupver = [NSString stringWithContentsOfFile:backupFlag encoding:NSASCIIStringEncoding error:nil];
89+
if(backupver.intValue >= 1) {
90+
ASSERT([fm removeItemAtPath:bundlePath error:nil]);
91+
ASSERT([fm moveItemAtPath:backup toPath:bundlePath error:nil]);
92+
ASSERT([fm removeItemAtPath:[backup.stringByDeletingLastPathComponent stringByAppendingPathComponent:@".appbackup"] error:nil]);
93+
return 0;
94+
}
95+
96+
struct stat st;
97+
if(lstat([bundlePath stringByAppendingString:@"/.jbroot"].fileSystemRepresentation, &st)==0)
98+
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.jbroot"] error:nil]);
99+
if(lstat([bundlePath stringByAppendingString:@"/.prelib"].fileSystemRepresentation, &st)==0)
100+
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.prelib"] error:nil]);
101+
if(lstat([bundlePath stringByAppendingString:@"/.preload"].fileSystemRepresentation, &st)==0)
102+
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.preload"] error:nil]);
103+
if(lstat([bundlePath stringByAppendingString:@"/.rebuild"].fileSystemRepresentation, &st)==0)
104+
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.rebuild"] error:nil]);
163105

164106
NSString *resolvedPath = [[backup stringByResolvingSymlinksInPath] stringByStandardizingPath];
165107
NSDirectoryEnumerator<NSURL *> *directoryEnumerator = [fm enumeratorAtURL:[NSURL fileURLWithPath:resolvedPath isDirectory:YES] includingPropertiesForKeys:@[NSURLIsRegularFileKey] options:0 errorHandler:nil];
@@ -197,6 +139,23 @@ int restoreApp(NSString* bundlePath)
197139
return 0;
198140
}
199141

142+
int backupApp(NSString* bundlePath)
143+
{
144+
NSFileManager* fm = NSFileManager.defaultManager;
145+
146+
NSString* backup = [bundlePath stringByAppendingPathExtension:@"appbackup"];
147+
148+
if([fm fileExistsAtPath:backup]) {
149+
ASSERT(![fm fileExistsAtPath:[backup.stringByDeletingLastPathComponent stringByAppendingPathComponent:@".appbackup"]]);
150+
ASSERT([fm removeItemAtPath:backup error:nil]);
151+
}
152+
153+
ASSERT(clonefile(bundlePath.fileSystemRepresentation, backup.fileSystemRepresentation, CLONE_ACL) == 0);
154+
155+
ASSERT([@"1" writeToFile:[backup.stringByDeletingLastPathComponent stringByAppendingPathComponent:@".appbackup"] atomically:YES encoding:NSUTF8StringEncoding error:nil]);
156+
157+
return 0;
158+
}
200159

201160
int enableForApp(NSString* bundlePath)
202161
{
@@ -276,16 +235,6 @@ int disableForApp(NSString* bundlePath)
276235
else if([appInfo[@"CFBundleIdentifier"] hasPrefix:@"com.apple."] || hasTrollstoreMarker(bundlePath.fileSystemRepresentation))
277236
{
278237

279-
struct stat st;
280-
if(lstat([bundlePath stringByAppendingString:@"/.jbroot"].fileSystemRepresentation, &st)==0)
281-
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.jbroot"] error:nil]);
282-
if(lstat([bundlePath stringByAppendingString:@"/.prelib"].fileSystemRepresentation, &st)==0)
283-
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.prelib"] error:nil]);
284-
if(lstat([bundlePath stringByAppendingString:@"/.preload"].fileSystemRepresentation, &st)==0)
285-
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.preload"] error:nil]);
286-
if(lstat([bundlePath stringByAppendingString:@"/.rebuild"].fileSystemRepresentation, &st)==0)
287-
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.rebuild"] error:nil]);
288-
289238
ASSERT(restoreApp(bundlePath) == 0);
290239

291240
ASSERT(spawnBootstrap((char*[]){"/usr/bin/uicache","-s","-p", rootfsPrefix(bundlePath).UTF8String, NULL}, nil, nil) == 0);
@@ -294,18 +243,13 @@ int disableForApp(NSString* bundlePath)
294243
{
295244
//should be an appstored app
296245

297-
struct stat st;
298-
if(lstat([bundlePath stringByAppendingString:@"/.jbroot"].fileSystemRepresentation, &st)==0)
299-
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.jbroot"] error:nil]);
300-
if(lstat([bundlePath stringByAppendingString:@"/.prelib"].fileSystemRepresentation, &st)==0)
301-
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.prelib"] error:nil]);
302-
if(lstat([bundlePath stringByAppendingString:@"/.preload"].fileSystemRepresentation, &st)==0)
303-
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.preload"] error:nil]);
304-
if(lstat([bundlePath stringByAppendingString:@"/.rebuild"].fileSystemRepresentation, &st)==0)
305-
ASSERT([fm removeItemAtPath:[bundlePath stringByAppendingString:@"/.rebuild"] error:nil]);
246+
BOOL encryptedApp = [NSFileManager.defaultManager fileExistsAtPath:[bundlePath stringByAppendingPathComponent:@"SC_Info"]];
247+
NSString* backupVersion = [NSString stringWithContentsOfFile:[bundlePath stringByAppendingString:@"/../.appbackup"] encoding:NSASCIIStringEncoding error:nil];
306248

307249
ASSERT(restoreApp(bundlePath) == 0);
308250

251+
if(encryptedApp && backupVersion.intValue>=1) return 0;
252+
309253
//unregister or respring to keep app's icon on home screen
310254
ASSERT(spawnBootstrap((char*[]){"/usr/bin/uicache","-u", rootfsPrefix(bundlePath).UTF8String, NULL}, nil, nil) == 0);
311255
//come back

Bootstrap/AppViewController.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ -(BOOL)tweakEnabled:(AppInfo*)app {
121121
return YES;
122122
}
123123

124-
if(!isDefaultInstallationPath(app.bundleURL.path.fileSystemRepresentation)) {
124+
if(!isRemovableBundlePath(app.bundleURL.path.fileSystemRepresentation)) {
125125
return NO;
126126
}
127127

@@ -147,7 +147,7 @@ - (void)updateData:(BOOL)sort {
147147

148148
// if(app.isHiddenApp) continue;
149149

150-
if(![app.bundleURL.path hasPrefix:@"/Applications/"] && !isDefaultInstallationPath(app.bundleURL.path.fileSystemRepresentation)) {
150+
if(![app.bundleURL.path hasPrefix:@"/Applications/"] && !isRemovableBundlePath(app.bundleURL.path.fileSystemRepresentation)) {
151151
//sysapp installed as jailbreak apps
152152
NSString* sysPath = [@"/Applications/" stringByAppendingPathComponent:app.bundleURL.path.lastPathComponent];
153153
if(![NSFileManager.defaultManager fileExistsAtPath:sysPath])

Bootstrap/ViewController.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ void URLSchemesAction(BOOL enable);
1818
void hideAllCTBugApps();
1919
void unhideAllCTBugApps();
2020
BOOL isAllCTBugAppsHidden();
21+
void rebootUserspaceAction();

Bootstrap/ViewController.m

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@
1212
#include <sys/sysctl.h>
1313
#include <sys/utsname.h>
1414

15-
#include <Security/SecKey.h>
16-
#include <Security/Security.h>
17-
typedef struct CF_BRIDGED_TYPE(id) __SecCode const* SecStaticCodeRef; /* code on disk */
18-
typedef enum { kSecCSDefaultFlags=0, kSecCSSigningInformation = 1 << 1 } SecCSFlags;
19-
OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, SecStaticCodeRef* CF_RETURNS_RETAINED staticCode);
20-
OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags, CFDictionaryRef* __nonnull CF_RETURNS_RETAINED information);
21-
22-
2315
@interface ViewController ()
2416
@end
2517

@@ -78,10 +70,6 @@ void checkAppsHidden()
7870

7971
void tryLoadOpenSSH()
8072
{
81-
// if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/basebin/.launchctl_support")]) {
82-
// return;
83-
// }
84-
8573
if([NSUserDefaults.appDefaults boolForKey:@"openssh"] && [NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/usr/libexec/sshd-keygen-wrapper")])
8674
{
8775
NSString* log=nil;
@@ -108,6 +96,10 @@ BOOL checkServer()
10896

10997
UIAlertController *alert = [UIAlertController alertControllerWithTitle:Localized(@"Server Not Running") message:Localized(@"for unknown reasons the bootstrap server is not running, the only thing we can do is to restart it now.") preferredStyle:UIAlertControllerStyleAlert];
11098
[alert addAction:[UIAlertAction actionWithTitle:Localized(@"Restart Server") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
99+
100+
if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/basebin/.launchctl_support")]) {
101+
return;
102+
}
111103

112104
alerted = false;
113105

@@ -178,6 +170,10 @@ void initFromSwiftUI()
178170

179171
if(isSystemBootstrapped())
180172
{
173+
if(!checkBootstrapVersion()) {
174+
return;
175+
}
176+
181177
if(checkServer()) {
182178
[AppDelegate addLogText:Localized(@"bootstrap server check successful")];
183179
checkAppsHidden();
@@ -206,19 +202,8 @@ void setIdleTimerDisabled(BOOL disabled) {
206202
}
207203

208204
BOOL checkTSVersion()
209-
{
210-
CFURLRef binaryURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)NSBundle.mainBundle.executablePath, kCFURLPOSIXPathStyle, false);
211-
if(binaryURL == NULL) return NO;
212-
213-
SecStaticCodeRef codeRef = NULL;
214-
OSStatus result = SecStaticCodeCreateWithPathAndAttributes(binaryURL, kSecCSDefaultFlags, NULL, &codeRef);
215-
if(result != errSecSuccess) return NO;
216-
217-
CFDictionaryRef signingInfo = NULL;
218-
result = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingInfo);
219-
if(result != errSecSuccess) return NO;
220-
221-
NSString* teamID = (NSString*)CFDictionaryGetValue(signingInfo, CFSTR("teamid"));
205+
{
206+
NSString* teamID = getTeamIDFromBinaryAtPath(NSBundle.mainBundle.executablePath);
222207
SYSLOG("teamID in trollstore: %@", teamID);
223208

224209
return [teamID isEqualToString:@"T8ALTGMVXN"];
@@ -361,6 +346,15 @@ void tweaEnableAction(BOOL enable)
361346
} else if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/var/mobile/.tweakenabled")]) {
362347
ASSERT([NSFileManager.defaultManager removeItemAtPath:jbroot(@"/var/mobile/.tweakenabled") error:nil]);
363348
}
349+
350+
if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/basebin/.launchctl_support")]) {
351+
UIAlertController *alert = [UIAlertController alertControllerWithTitle:Localized(@"Userspace Reboot Required") message:Localized(@"A userspace reboot is neccessary to apply the changes. Do you want to do it now?") preferredStyle:UIAlertControllerStyleAlert];
352+
[alert addAction:[UIAlertAction actionWithTitle:Localized(@"Reboot Later") style:UIAlertActionStyleCancel handler:nil]];
353+
[alert addAction:[UIAlertAction actionWithTitle:Localized(@"Reboot Now") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
354+
spawnBootstrap((char*[]){"/usr/bin/launchctl","reboot","userspace",NULL}, nil, nil);
355+
}]];
356+
[AppDelegate showAlert:alert];
357+
}
364358
}
365359

366360
void URLSchemesToggle(BOOL enable)
@@ -400,15 +394,16 @@ BOOL opensshAction(BOOL enable)
400394
[NSUserDefaults.appDefaults synchronize];
401395
return enable;
402396
}
403-
404-
// if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/basebin/.launchctl_support")]) {
405-
// return NO;
406-
// }
407397

408398
if(![NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/usr/libexec/sshd-keygen-wrapper")]) {
409399
[AppDelegate showMesage:Localized(@"openssh package is not installed") title:Localized(@"Developer")];
410400
return NO;
411401
}
402+
403+
if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/basebin/.launchctl_support")]) {
404+
[AppDelegate showMesage:Localized(@"The SSH Service on your device is hosted by launchd.") title:@""];
405+
return NO;
406+
}
412407

413408
NSString* log=nil;
414409
NSString* err=nil;
@@ -431,10 +426,17 @@ BOOL opensshAction(BOOL enable)
431426
return enable;
432427
}
433428

429+
void rebootUserspaceAction()
430+
{
431+
spawnBootstrap((char*[]){"/usr/bin/launchctl","reboot","userspace",NULL}, nil, nil);
432+
}
433+
434434
NSArray* ResignExecutables = @[
435435
@"/sbin/launchd",
436436
@"/usr/libexec/xpcproxy",
437437
@"/System/Library/CoreServices/SpringBoard.app/SpringBoard",
438+
@"/usr/bin/powerlogHelperd",
439+
@"/usr/sbin/spindump",
438440
];
439441

440442
#define RESIGNED_SYSROOT_PATH jbroot(@"/.sysroot")
@@ -802,7 +804,7 @@ void hideAllCTBugAppsAction(BOOL usreboot)
802804
continue;
803805
}
804806

805-
if(isDefaultInstallationPath(appPath.fileSystemRepresentation) && !hasTrollstoreMarker(appPath.fileSystemRepresentation)) {
807+
if(isRemovableBundlePath(appPath.fileSystemRepresentation) && !hasTrollstoreMarker(appPath.fileSystemRepresentation)) {
806808
continue;
807809
}
808810

Bootstrap/Views/ContentView.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct MainView: View {
3737
@State private var newVersionReleaseURL:String = ""
3838
@State private var tweakEnable: Bool = !isSystemBootstrapped() || FileManager.default.fileExists(atPath: jbroot("/var/mobile/.tweakenabled"))
3939

40-
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
40+
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String
4141

4242
var body: some View {
4343
ZStack {
@@ -69,7 +69,7 @@ struct MainView: View {
6969
Text("Bootstrap")
7070
.bold()
7171
.font(Font.system(size: 35))
72-
Text("Version \(appVersion!)")
72+
Text("Version \(appVersion)")
7373
.font(Font.system(size: 20))
7474
.opacity(0.5)
7575
})
@@ -184,6 +184,7 @@ struct MainView: View {
184184
.cornerRadius(18)
185185
.opacity(0.5)
186186
}
187+
.disabled(isSystemBootstrapped() && !checkBootstrapVersion())
187188

188189
}
189190

0 commit comments

Comments
 (0)