From d1844f4a3c7a6a4d1f9da43e0468ea89d8bbf0a2 Mon Sep 17 00:00:00 2001 From: Linus Henze Date: Fri, 20 Mar 2020 18:38:43 +0100 Subject: [PATCH] Add autoinstall and iOS 13.4 support --- Fugu/main.swift | 2 +- README.md | 32 +- USB/IOKitUSB.swift | 1 + iDownload/iDownload.xcodeproj/project.pbxproj | 14 + iDownload/iDownload/Makefile | 9 +- iDownload/iDownload/common.h | 17 + iDownload/iDownload/iDownload.entitlements | 4 + iDownload/iDownload/install.h | 17 + iDownload/iDownload/install.m | 447 ++++++++++ iDownload/iDownload/main.m | 773 ++---------------- iDownload/iDownload/server.c | 646 +++++++++++++++ iDownload/iDownload/server.h | 16 + iStrap/iStrap/patch.c | 36 +- iStrap/iStrap/shellcode.S | 4 +- install_sileo.py | 7 + 15 files changed, 1295 insertions(+), 730 deletions(-) create mode 100644 iDownload/iDownload/common.h create mode 100644 iDownload/iDownload/install.h create mode 100644 iDownload/iDownload/install.m create mode 100644 iDownload/iDownload/server.c create mode 100644 iDownload/iDownload/server.h diff --git a/Fugu/main.swift b/Fugu/main.swift index 0261a16..d93e1e6 100644 --- a/Fugu/main.swift +++ b/Fugu/main.swift @@ -28,4 +28,4 @@ DispatchQueue.global().async { ]) } -dispatchMain() +CFRunLoopRun() diff --git a/README.md b/README.md index 6de8a9d..d77df73 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Fugu Fugu is the first open source jailbreak tool based on the checkm8 exploit. - -__UPDATE:__ NewTerm and other Apps that do not rely on tweak injection should work now. -__UPDATE2:__ Experimental MobileSubstrate support has been added. Tested with Bloard and PreferenceLoader. -__IMPORTANT:__ This jailbreak is currently in development and only meant to be used by developers. While it is possible to install Sileo (or Cydia), most tweaks (and probably other stuff) won't work. Additionally, although the root filesystem is mounted read/write, __rebooting into non-jailbroken mode will reset the root filesystem back to stock!__ + +__UPDATE:__ Fugu will now install Sileo, SSH and Substitute automatically! Put your iDevice into DFU mode, run `Fugu iStrap`, unlock your iDevice and follow the on-screen prompts. +__IMPORTANT:__ This jailbreak is currently in development and only meant to be used by developers. Although the root filesystem is mounted read/write, __rebooting into non-jailbroken mode will reset the root filesystem back to stock!__ (i.e. Remove Sileo and your Tweaks) + +# WARNING +**!!! ONLY DOWNLOAD FUGU FROM [https://github.com/LinusHenze/Fugu](https://github.com/LinusHenze/Fugu) AS IT IS VERY EASY TO CREATE A VERSION OF FUGU THAT CONTAINS MALWARE !!!** # Supported Devices -Currently, the iPad Pro (2017) and iPhone 7 are the only officially supported devices (on iOS 13 - 13.3.1). +Currently, the iPad Pro (2017) and iPhone 7 are the only officially supported devices (on iOS 13 - 13.4). # Building _Note that you can also download a precompiled version from the releases tab._ @@ -28,24 +30,8 @@ _You may need to run this command multiple times. If it won't work after the 4th This will send iStrap (the kernel bootstrapper) to your iDevice together with iDownload (small application that can be used to upload files to the iDevice or execute commands). See _Components_ for more information. -# Installing Sileo, SSH and MobileSubstrate -__IMPORTANT:__ All of this is highly experimental. Expect things to be broken. - -Make sure you have `libusbmuxd` installed. -You can install it through Homebrew: -```bash -brew install libusbmuxd -``` -After installing usbmuxd, boot your iDevice into jailbroken mode (e.g. `Fugu iStrap`) and unlock it afterwards. -Make sure it's still connected to your Mac via USB. -You can now install Sileo using: -```bash -python install_sileo.py -``` -This will download all the necessary files to install Sileo and install it. -After the installation is done, you should see the Sileo Icon on your Homescreen. -Aditionally, SSH will be running now. __Make sure to change the root/mobile passwords!__ -MobileSubstrate will be installed as well. +# Installing Sileo, SSH and Substitute +**Fugu will now install Sileo, SSH and Substitute automatically!** Unlock your iDevice and follow the on-screen prompts. Make sure your iDevice is connected to the internet! # Components Fugu consists of the following components: diff --git a/USB/IOKitUSB.swift b/USB/IOKitUSB.swift index 548371b..134fe16 100644 --- a/USB/IOKitUSB.swift +++ b/USB/IOKitUSB.swift @@ -217,6 +217,7 @@ final class IOKitUSB: USBDeviceImplementation { let nPort = IONotificationPortCreate(kIOMasterPortDefault) var source = IONotificationPortGetRunLoopSource(nPort) _ = deviceInterface.CreateDeviceAsyncEventSource(deviceInterfacePtrPtr, &source) + CFRunLoopAddSource(CFRunLoopGetMain(), source?.takeUnretainedValue(), CFRunLoopMode.commonModes) } deinit { diff --git a/iDownload/iDownload.xcodeproj/project.pbxproj b/iDownload/iDownload.xcodeproj/project.pbxproj index 9127e6c..aa5d12c 100644 --- a/iDownload/iDownload.xcodeproj/project.pbxproj +++ b/iDownload/iDownload.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 1557A3BD236624D60072A036 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1557A3AD236623F60072A036 /* main.m */; }; + 1591CDF023F0703700FAC98C /* install.m in Sources */ = {isa = PBXBuildFile; fileRef = 1591CDEF23F0703700FAC98C /* install.m */; }; + 1591CDF323F070A100FAC98C /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = 1591CDF223F070A100FAC98C /* server.c */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -34,6 +36,11 @@ 1557A3AF236624580072A036 /* iDownload */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = iDownload; sourceTree = ""; }; 1557A3B0236624750072A036 /* iDownload.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iDownload.entitlements; sourceTree = ""; }; 1557A3B5236624CF0072A036 /* iDownload_macOS_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = iDownload_macOS_test; sourceTree = BUILT_PRODUCTS_DIR; }; + 1591CDEE23F0703700FAC98C /* install.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = install.h; sourceTree = ""; }; + 1591CDEF23F0703700FAC98C /* install.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = install.m; sourceTree = ""; }; + 1591CDF123F070A100FAC98C /* server.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = server.h; sourceTree = ""; }; + 1591CDF223F070A100FAC98C /* server.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = ""; }; + 1591CDF423F0719100FAC98C /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; 15D3CBE6236640AC00D71E2D /* iDownload.z */ = {isa = PBXFileReference; lastKnownFileType = file; path = iDownload.z; sourceTree = ""; }; /* End PBXFileReference section */ @@ -75,6 +82,11 @@ children = ( 1557A3AC236623D90072A036 /* Makefile */, 1557A3AD236623F60072A036 /* main.m */, + 1591CDEF23F0703700FAC98C /* install.m */, + 1591CDEE23F0703700FAC98C /* install.h */, + 1591CDF223F070A100FAC98C /* server.c */, + 1591CDF123F070A100FAC98C /* server.h */, + 1591CDF423F0719100FAC98C /* common.h */, 1557A3B0236624750072A036 /* iDownload.entitlements */, 150E2BF82367055F00611E9F /* xpc */, ); @@ -177,6 +189,8 @@ buildActionMask = 2147483647; files = ( 1557A3BD236624D60072A036 /* main.m in Sources */, + 1591CDF323F070A100FAC98C /* server.c in Sources */, + 1591CDF023F0703700FAC98C /* install.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/iDownload/iDownload/Makefile b/iDownload/iDownload/Makefile index 1efc559..bc83ba2 100644 --- a/iDownload/iDownload/Makefile +++ b/iDownload/iDownload/Makefile @@ -1,17 +1,20 @@ CC=xcrun -sdk iphoneos clang CFLAGS=-target arm64-apple-darwin -arch arm64 -Wall -nostdlib -fno-stack-protector -DiOS -LDFLAGS=-target arm64-apple-darwin -arch arm64 -dead-strip -framework Foundation +LDFLAGS=-target arm64-apple-darwin -arch arm64 -dead-strip -framework Foundation -framework UIKit -OBJS=main.o +OBJS=main.o server.o install.o DEPS=iDownload.entitlements %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) + +%.o: %.m $(DEPS) + $(CC) -c -o $@ $< $(CFLAGS) %.o: %.S $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) -iDiskMounter: $(OBJS) +iDownload: $(OBJS) $(CC) -o ../build/iDownload $(OBJS) $(LDFLAGS) codesign -s - --entitlements iDownload.entitlements ../build/iDownload cat ../build/iDownload | python -c "import sys, zlib; print zlib.compress(sys.stdin.read(), 9)" > ../build/iDownload.z diff --git a/iDownload/iDownload/common.h b/iDownload/iDownload/common.h new file mode 100644 index 0000000..eb19ad9 --- /dev/null +++ b/iDownload/iDownload/common.h @@ -0,0 +1,17 @@ +// +// common.h +// iDownload +// +// Created by Linus Henze on 09.02.20. +// Copyright © 2020 Linus Henze. All rights reserved. +// + +#ifndef common_h +#define common_h + +#define VERSION "1.1" +#define PLIST_VERSION 1 + +#define FILE_EXISTS(file) (access(file, F_OK ) != -1) + +#endif /* common_h */ diff --git a/iDownload/iDownload/iDownload.entitlements b/iDownload/iDownload/iDownload.entitlements index 49c2c1e..a8ad393 100644 --- a/iDownload/iDownload/iDownload.entitlements +++ b/iDownload/iDownload/iDownload.entitlements @@ -54,6 +54,10 @@ com.apple.private.ProvInfoIOKitUserClient.access + com.apple.springboard.CFUserNotification + + com.apple.springboard.launchapplications + com.apple.private.PurpleReverseProxy.allowed com.apple.private.apfs.trim-active-file diff --git a/iDownload/iDownload/install.h b/iDownload/iDownload/install.h new file mode 100644 index 0000000..01b5405 --- /dev/null +++ b/iDownload/iDownload/install.h @@ -0,0 +1,17 @@ +// +// install.h +// iDownload +// +// Created by Linus Henze on 09.02.20. +// Copyright © 2020 Linus Henze. All rights reserved. +// + +#ifndef install_h +#define install_h + +#include "common.h" + +void update_springboard_plist(void); +void requestInstall(void); + +#endif /* install_h */ diff --git a/iDownload/iDownload/install.m b/iDownload/iDownload/install.m new file mode 100644 index 0000000..46b6bc8 --- /dev/null +++ b/iDownload/iDownload/install.m @@ -0,0 +1,447 @@ +// +// install.m +// iDownload +// +// Created by Linus Henze on 09.02.20. +// Copyright © 2020 Linus Henze. All rights reserved. +// + +#import +#import +#import +#import +#import + +#import "install.h" + +bool deviceLocked = true; +bool installStarted = false; + +void (^deviceUnlockHandler)(void) = NULL; + +@interface FBSSystemService ++ (instancetype) sharedService; +- (void)openApplication: (NSString *) id options: (NSDictionary*) suspended withResult: (id) res; +@end + +void update_springboard_plist() { + NSDictionary *springBoardPlist = [NSMutableDictionary dictionaryWithContentsOfFile: @"/var/mobile/Library/Preferences/com.apple.springboard.plist"]; + [springBoardPlist setValue: @YES forKey: @"SBShowNonDefaultSystemApps"]; + [springBoardPlist writeToFile: @"/var/mobile/Library/Preferences/com.apple.springboard.plist" atomically: YES]; + + NSDictionary* attr = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithShort:0755], NSFilePosixPermissions, @"mobile", NSFileOwnerAccountName, NULL]; + + NSError *error = nil; + [[NSFileManager defaultManager] setAttributes: attr ofItemAtPath: @"/var/mobile/Library/Preferences/com.apple.springboard.plist" error: &error]; +} + +CFOptionFlags showMessage(CFDictionaryRef dict) { + while (true) { + while (deviceLocked) { + sleep(1); + } + + SInt32 err = 0; + CFUserNotificationRef notif = CFUserNotificationCreate(NULL, 0, kCFUserNotificationPlainAlertLevel, &err, dict); + if (notif == NULL || err != 0) { + sleep(1); + continue; + } + + CFOptionFlags response = 0; + CFUserNotificationReceiveResponse(notif, 0, &response); + + sleep(1); + + if ((response & 0x3) != kCFUserNotificationCancelResponse) { + return response & 0x3; + } + } +} + +void showSimpleMessage(NSString *title, NSString *message) { + CFDictionaryRef dict = (__bridge CFDictionaryRef) @{ + (__bridge NSString*) kCFUserNotificationAlertTopMostKey: @1, + (__bridge NSString*) kCFUserNotificationAlertHeaderKey: title, + (__bridge NSString*) kCFUserNotificationAlertMessageKey: message + }; + + showMessage(dict); +} + +__strong NSData *downloadData(NSString *url, NSError **error) { + NSLog(@"Downloading file at %@", url); + + NSURL *nsurl = [NSURL URLWithString: url]; + if (!nsurl) { + *error = [NSError errorWithDomain: @"URLError" code: 1 userInfo: nil]; + return nil; + } + + __block __strong NSData *download = nil; + while (!download) { + *error = nil; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + NSURLSession *session = [NSURLSession sharedSession]; + NSInteger __block status = 0; + + [[session dataTaskWithURL: nsurl completionHandler: ^(NSData *data, NSURLResponse *response, NSError *e) { + if ([response isKindOfClass: [NSHTTPURLResponse class]] && [(NSHTTPURLResponse*) response statusCode] == 200 && !e) { + download = [[NSData alloc] initWithBytes: [data bytes] length: [data length]]; + } else { + download = NULL; + *error = e; + } + + status = [response isKindOfClass: [NSHTTPURLResponse class]] ? [(NSHTTPURLResponse*) response statusCode] : 0; + + dispatch_semaphore_signal(semaphore); + }] resume]; + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + if (!download && !*error) { + // Connected to the internet but no file + // Fatal + *error = [NSError errorWithDomain: @"HTTP Error" code: status userInfo: nil]; + return nil; + } + } + + return [[NSData alloc] initWithBytes: [download bytes] length: [download length]]; +} + +NSString *download(NSString *url, NSString *dir, NSError **error) { + *error = nil; + + NSURL *nsurl = [NSURL URLWithString: url]; + if (!nsurl) { + *error = [NSError errorWithDomain: @"URLError" code: 1 userInfo: nil]; + return nil; + } + + if ([dir characterAtIndex: ([dir length] - 1)] != '/') { + dir = [dir stringByAppendingString: @"/"]; + } + + NSString *filename = [dir stringByAppendingString: [nsurl lastPathComponent]]; + + NSData *download = downloadData(url, error); + if (*error) { + return nil; + } + + NSLog(@"Will write to file %@", filename); + + FILE *f = fopen([filename UTF8String], "w+"); + if (!f) { + NSLog(@"Failed to open %@", filename); + *error = [NSError errorWithDomain: @"FileWriteError" code: 1 userInfo: nil]; + return nil; + } + + size_t written = fwrite([download bytes], 1, [download length], f); + fclose(f); + + if (written != [download length]) { + NSLog(@"Failed to write to %@", filename); + unlink([filename UTF8String]); + *error = [NSError errorWithDomain: @"FileWriteError" code: 1 userInfo: nil]; + return nil; + } + + NSLog(@"Wrote to %@", filename); + + return filename; +} + +int runCmd(NSString *file, NSArray *args) { + const char **cargs = malloc(([args count] + 2) * sizeof(char*)); + + cargs[0] = [file UTF8String]; + cargs[[args count] + 1] = NULL; + + for (NSUInteger i = 0; i < [args count]; i++) { + cargs[i+1] = [(NSString*)[args objectAtIndex: i] UTF8String]; + } + + NSLog(@"About to run %@", file); + for (NSUInteger i = 0; i < ([args count] + 2); i++) { + NSLog(@"Arg[%lu]: %s", i, cargs[i]); + } + + pid_t pid = fork(); + if (!pid) { + // Child + int fd_r = open("/dev/null", O_RDONLY); + dup2(fd_r, STDIN_FILENO); + + int fd_w = open("/fugu_install.log", O_WRONLY | O_CREAT | O_APPEND, 0644); + dup2(fd_w, STDOUT_FILENO); + dup2(fd_w, STDERR_FILENO); + + execv(cargs[0], (char * const *) cargs); + exit(-1); + } + + free(cargs); + + // Parent + int status; + waitpid(pid, &status, 0); + + status = WEXITSTATUS(status); + + NSLog(@"Exit status: %d", status); + + return status; +} + +void startInstall(NSDictionary *installData) { + // installData looks like bootstrap.plist + // but it doesn't have a version and it has local + // paths instead of URLs + + // Step 1: Decompress bootstrap.tar.gz + NSString *bootstrap = [installData valueForKey: @"bootstrap"]; + NSString *decomp = [bootstrap stringByReplacingOccurrencesOfString: @".tar.gz" withString: @".tar"]; + NSString *gzip = [installData valueForKey: @"gzip"]; + + unlink([decomp UTF8String]); // In case it exists from a previous attempt + + int status = runCmd(gzip, @[@"-d", bootstrap]); + if (status != 0) { + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the bootstrap.tar.gz couldn't be decompressed (Error code %d). To retry, reboot and launch Fugu again.", status]); + return; + } + + sync(); + + // Step 2: Extract bootstrap.tar + NSString *tar = [installData valueForKey: @"tar"]; + chdir("/"); + status = runCmd(tar, @[@"--preserve-permissions", @"--no-overwrite-dir", @"-xf", decomp]); + if (status != 0) { + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the bootstrap.tar couldn't be extracted (Error code %d). To retry, reboot and launch Fugu again.", status]); + return; + } + + // Step 3: Enable SBShowNonDefaultSystemApps + update_springboard_plist(); + + // Step 4: Launch install script + NSString *installScript = [installData valueForKey: @"installScript"]; + status = runCmd(@"/bin/bash", @[installScript, @"noRespring"]); + if (status != 0) { + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the install script exited with error code %d. To retry, reboot and launch Fugu again.", status]); + return; + } + + // Step 5: Tell the user that we're about to respring + bool respringNow = false; + while (!respringNow) { + CFDictionaryRef respringNotif = (__bridge CFDictionaryRef) @{ + (__bridge NSString*) kCFUserNotificationAlertTopMostKey: @1, + (__bridge NSString*) kCFUserNotificationAlertHeaderKey: @"Fugu\nRespring required!", + (__bridge NSString*) kCFUserNotificationAlertMessageKey: @"To finish the installation, a respring is required. Continue?", + (__bridge NSString*) kCFUserNotificationDefaultButtonTitleKey: @"Respring now!", + (__bridge NSString*) kCFUserNotificationAlternateButtonTitleKey: @"Remind me in a minute" + }; + + CFOptionFlags flags = showMessage(respringNotif); + if (flags == kCFUserNotificationDefaultResponse) { + respringNow = true; + } else { + sleep(60); + } + } + + // Step 6: Tell the install script to finish and respring + status = runCmd(@"/bin/bash", @[installScript, @"respringNow"]); + if (status != 0) { + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the install script exited with error code %d. To retry, reboot and launch Fugu again.", status]); + return; + } + + deviceLocked = true; // We are respringing + + // Step 7: Tell user we succeeded + CFDictionaryRef respringNotif = (__bridge CFDictionaryRef) @{ + (__bridge NSString*) kCFUserNotificationAlertTopMostKey: @1, + (__bridge NSString*) kCFUserNotificationAlertHeaderKey: @"Fugu\nInstallation succeded!", + (__bridge NSString*) kCFUserNotificationAlertMessageKey: @"The installation has been completed successfully! Enjoy your jailbroken device ;)", + (__bridge NSString*) kCFUserNotificationDefaultButtonTitleKey: @"OK", + (__bridge NSString*) kCFUserNotificationAlternateButtonTitleKey: @"Open Sileo" + }; + + // Step 8: Launch Sileo if requested + CFOptionFlags flags = showMessage(respringNotif); + if (flags == kCFUserNotificationAlternateResponse) { + Class FBSSystemService = NSClassFromString(@"FBSSystemService"); + [[FBSSystemService sharedService] openApplication: @"org.coolstar.SileoStore" options: @{@"__ActivateSuspended": @0} withResult: nil]; + } + + // We're done! +} + +#define PLIST_GET_VALUE(valueName, value, className, classDesc) className *value = [plist valueForKey: valueName]; if (!value || ![value isKindOfClass: [className class]]) { \ + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the bootstrap.plist is invalid (%@ %@). To retry, reboot and launch Fugu again.", valueName, value ? [@"is not " stringByAppendingString: classDesc] : @"is missing"]); \ + return; \ +} + +#define CHECK_DOWNLOADED(var, url) if (!var) { \ + if ([[error domain] isEqualToString: @"URLError"]) { \ + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the bootstrap.plist is invalid (URL %@ is invalid). To retry, reboot and launch Fugu again.", url]); \ + return; \ + } else if ([[error domain] isEqualToString: @"FileWriteError"]) { \ + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because a required file couldn't be written (URL: %@). To retry, reboot and launch Fugu again.", url]); \ + return; \ + } else { \ + NSString *loc = [error localizedDescription]; \ + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because of the following error: %@. To retry, reboot and launch Fugu again.", loc ? loc : [error description]]); \ + return; \ + } \ +} + +#define SET_FILE_PERM(file, perm) \ +[[NSFileManager defaultManager] setAttributes: @{ NSFilePosixPermissions: @perm } ofItemAtPath: file error:&error];\ +if (error) { \ + NSString *loc = [error localizedDescription]; \ +showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the file permissions couldn't be set (File: %@ -- Error: %@). To retry, reboot and launch Fugu again.", file, loc ? loc : [error description]]); \ + return; \ +} + +void startDownload() { + // Download bootstrap.plist + NSError *error; + NSData *bstrapData = downloadData(@"https://repo.fugujb.dev/bootstrap/bootstrap.plist", &error); + if (error) { + // Cannot be an URL error + // Connected to the internet but no file + // Fatal + showSimpleMessage(@"Fugu\nInstallation failed!", @"The installation failed because the bootstrap.plist couldn't be downloaded. To retry, reboot and launch Fugu again."); + return; + } + + NSPropertyListFormat format; + NSDictionary* plist = [NSPropertyListSerialization propertyListWithData: bstrapData options: NSPropertyListImmutable format: &format error: &error]; + if (!plist) { + // Invalid format? + showSimpleMessage(@"Fugu\nInstallation failed!", @"The installation failed because the bootstrap.plist is invalid. To retry, reboot and launch Fugu again."); + return; + } + + // Now check format + PLIST_GET_VALUE(@"version", version, NSNumber, @"a number") + + if ([version unsignedIntValue] != PLIST_VERSION) { + showSimpleMessage(@"Fugu\nUpdate required!", @"The installation failed because your version of Fugu is too old. Please update Fugu and try again."); + return; + } + + // Get tar, gzip, bootstrap, installScript, debs + PLIST_GET_VALUE(@"tar", tar, NSString, @"a string") + PLIST_GET_VALUE(@"gzip", gzip, NSString, @"a string") + PLIST_GET_VALUE(@"bootstrap", bootstrap, NSString, @"a string") + PLIST_GET_VALUE(@"installScript", installScript, NSString, @"a string") + PLIST_GET_VALUE(@"debs", debs, NSArray, @"an array") + + for (NSUInteger i = 0; i < [debs count]; i++) { + NSString *value = [debs objectAtIndex: i]; + if (![value isKindOfClass: [NSString class]]) { + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the bootstrap.plist is invalid (debs[%lu] is not a string). To retry, reboot and launch Fugu again.", i]); + return; + } + } + + // Download files + NSMutableDictionary *installDict = [[NSMutableDictionary alloc] init]; + + NSString *tarFile = download(tar, @"/bin", &error); + CHECK_DOWNLOADED(tarFile, tar) + SET_FILE_PERM(tarFile, 0755) + [installDict setValue: tarFile forKey: @"tar"]; + + NSString *gzipFile = download(gzip, @"/usr/bin", &error); + CHECK_DOWNLOADED(gzipFile, gzip) + SET_FILE_PERM(gzipFile, 0755) + [installDict setValue: gzipFile forKey: @"gzip"]; + + NSString *bootstrapFile = download(bootstrap, @"/", &error); + CHECK_DOWNLOADED(bootstrapFile, bootstrap) + [installDict setValue: bootstrapFile forKey: @"bootstrap"]; + + NSString *installScriptFile = download(installScript, @"/", &error); + CHECK_DOWNLOADED(installScriptFile, installScript) + SET_FILE_PERM(installScriptFile, 0755) + [installDict setValue: installScriptFile forKey: @"installScript"]; + + if (![[NSFileManager defaultManager] fileExistsAtPath: @"/debs" isDirectory: nil]) { + BOOL debsCreated = [[NSFileManager defaultManager] createDirectoryAtPath: @"/debs" withIntermediateDirectories: NO attributes: @{} error: &error]; + if (!debsCreated) { + NSString *loc = [error localizedDescription]; + showSimpleMessage(@"Fugu\nInstallation failed!", [NSString stringWithFormat: @"The installation failed because the /debs directory couldn't be created (error: %@). To retry, reboot and launch Fugu again.", loc ? loc : [error description]]); + return; + } + } + + NSMutableArray *debFiles = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < [debs count]; i++) { + // Guaranteed to be a string + NSString *url = [debs objectAtIndex: i]; + NSString *dwnldLoc = download(url, @"/debs", &error); + CHECK_DOWNLOADED(dwnldLoc, url) + + [debFiles addObject: dwnldLoc]; + } + + [installDict setValue: debFiles forKey: @"debs"]; + + // Downloaded everything, install now! + CFDictionaryRef installNotif = (__bridge CFDictionaryRef) @{ + (__bridge NSString*) kCFUserNotificationAlertTopMostKey: @1, + (__bridge NSString*) kCFUserNotificationAlertHeaderKey: @"Fugu\nDownload completed!", + (__bridge NSString*) kCFUserNotificationAlertMessageKey: @"All required files have been downloaded and are ready to be installed.", + (__bridge NSString*) kCFUserNotificationDefaultButtonTitleKey: @"Install now!" + }; + + showMessage(installNotif); + + startInstall(installDict); +} + +void handleLockNotification(int stateToken, int token) { + // Is this an unlock notification? + uint64_t state; + notify_get_state(stateToken, &state); + if (state == 0) { + deviceLocked = false; + + if (!installStarted) { + // Start install now! + dispatch_async(dispatch_queue_create("Download", NULL), ^{ + installStarted = true; + + showSimpleMessage(@"Welcome to Fugu!", @"We will now download and install Sileo, Substitute and other components. Depending on your internet connection, this may take a few minutes. You will get another message once the download has been completed."); + + startDownload(); + }); + } else { + if (deviceUnlockHandler) { + deviceUnlockHandler(); + deviceUnlockHandler = NULL; + } + } + } else { + deviceLocked = true; + } +} + +void requestInstall() { + int notify_token; + notify_register_dispatch("com.apple.springboard.lockstate", ¬ify_token, dispatch_queue_create("LockstateNotify", NULL), ^(int stateToken) { + handleLockNotification(stateToken, notify_token); + }); +} diff --git a/iDownload/iDownload/main.m b/iDownload/iDownload/main.m index 5df7de4..2a1a3d6 100644 --- a/iDownload/iDownload/main.m +++ b/iDownload/iDownload/main.m @@ -9,26 +9,22 @@ #include #include #include -#include -#include #include #include #include #include #include #include -#include -#include -#include -#include #include +#include "common.h" +#include "server.h" +#include "install.h" + extern char **environ; mach_port_t bPort = MACH_PORT_NULL; -#define VERSION "1.0" - mach_port_t task_for_pid_backdoor(int pid) { mach_port_t psDefault; mach_port_t psDefault_control; @@ -70,722 +66,101 @@ void removeBP() { task_set_bootstrap_port(mach_task_self(), MACH_PORT_NULL); } -int runCommand(FILE *f, char *argv[]) { - dup2(fileno(f), STDIN_FILENO); - dup2(fileno(f), STDOUT_FILENO); - dup2(fileno(f), STDERR_FILENO); - - pid_t pid = fork(); - if (pid == 0) { - execve(argv[0], argv, environ); - fprintf(stderr, "child: Failed to launch! Error: %s\r\n", strerror(errno)); - exit(-1); - } - - // Now wait for child - int status; - waitpid(pid, &status, 0); - - return status; -} - -bool readToNewline(FILE *f, char *buf, size_t size) { - size_t cmdOffset = 0; - memset(buf, 0, size); - - while (1) { - // Read incoming data - size_t status = fread(buf + cmdOffset, 1, 1, f); - if (status < 1) { - return false; - } - - cmdOffset++; - if (cmdOffset >= (size-1)) { - fprintf(f, "\r\nERROR: Command to long!\r\n"); - cmdOffset = 0; - memset(buf, 0, size); - continue; - } - - // Check if there is a newline somewhere - char *loc = strstr(buf, "\n"); - if (!loc) { - continue; - } - - // There is - if ((loc - 1) >= buf) { - if (*(loc - 1) == '\r') { - loc--; - } - } - - *loc = 0; - return true; - } -} - -char *getParameter(char *buf, int param) { - char *loc = buf; - - for (int i = 0; i < param; i++) { - loc = strstr(loc, " "); - if (!loc) { - return NULL; - } - - loc++; // Skip over the space - } - - char *next = strstr(loc, " "); - if (!next) { - return strdup(loc); - } - - *next = 0; - char *data = strdup(loc); - *next = ' '; - - return data; -} - -/* - * https://stackoverflow.com/questions/10323060/printing-file-permissions-like-ls-l-using-stat2-in-c - */ -void printInfo(FILE *f, char *file) { - struct stat fileStat; - if(lstat(file, &fileStat) < 0) { - fprintf(f, "info: %s\r\n", strerror(errno)); - return; - } - - fprintf(f, "---------------------------\r\n"); - fprintf(f, "Information for %s\r\n", file); - fprintf(f, "---------------------------\r\n"); - if (fileStat.st_size != 1) { - fprintf(f, "File Size: \t\t%lld bytes\r\n", fileStat.st_size); - } else { - fprintf(f, "File Size: \t\t1 byte\r\n"); - } - - //fprintf(f, "Number of Links: \t%d\r\n", fileStat.st_nlink); - //fprintf(f, "File inode: \t\t%llu\r\n", fileStat.st_ino); - - fprintf(f, "File Permissions: \t"); - fprintf(f, (S_ISDIR(fileStat.st_mode)) ? "d" : "-"); - fprintf(f, (fileStat.st_mode & S_IRUSR) ? "r" : "-"); - fprintf(f, (fileStat.st_mode & S_IWUSR) ? "w" : "-"); - if (fileStat.st_mode & S_ISUID) { - fprintf(f, (fileStat.st_mode & S_IXUSR) ? "s" : "S"); - } else { - fprintf(f, (fileStat.st_mode & S_IXUSR) ? "x" : "-"); - } - fprintf(f, (fileStat.st_mode & S_IRGRP) ? "r" : "-"); - fprintf(f, (fileStat.st_mode & S_IWGRP) ? "w" : "-"); - if (fileStat.st_mode & S_ISGID) { - fprintf(f, (fileStat.st_mode & S_IXGRP) ? "s" : "S"); - } else { - fprintf(f, (fileStat.st_mode & S_IXGRP) ? "x" : "-"); - } - fprintf(f, (fileStat.st_mode & S_IROTH) ? "r" : "-"); - fprintf(f, (fileStat.st_mode & S_IWOTH) ? "w" : "-"); - fprintf(f, (fileStat.st_mode & S_IXOTH) ? "x" : "-"); - fprintf(f, "\r\n"); - fprintf(f, "File Owner UID: \t%d\r\n", fileStat.st_uid); - fprintf(f, "File Owner GID: \t%d\r\n", fileStat.st_gid); - - if (S_ISLNK(fileStat.st_mode)) { - fprintf(f, "\r\n"); - fprintf(f, "The file is a symbolic link.\r\n"); - } -} - -void printHelp(FILE *f) { - fprintf(f, "iDownload has a bash-like interface\r\n"); - fprintf(f, "The following commands are supported:\r\n"); - fprintf(f, "exit: Close connection\r\n"); - fprintf(f, "exit_full: Close connection and terminate iDownload\r\n"); - fprintf(f, "pwd: Print current working directory\r\n"); - fprintf(f, "cd : Change directory\r\n"); - fprintf(f, "ls : List directory\r\n"); - fprintf(f, "clear: Clear screen\r\n"); - fprintf(f, "write : Create file with name and size\r\n"); - fprintf(f, " Send file data afterwards\r\n"); - fprintf(f, "cat : Print contents of file\r\n"); - fprintf(f, "rm : Delete file\r\n"); - fprintf(f, "rmdir : Delete an empty folder\r\n"); - fprintf(f, "chmod : Chmod a file. Mode must be octal\r\n"); - fprintf(f, "chown : Chown a file\r\n"); - fprintf(f, "info : Print file infos\r\n"); - fprintf(f, "mkdir : Create a directory\r\n"); - fprintf(f, "exec : Launch a program\r\n"); - fprintf(f, "help: Print this help\r\n"); - fprintf(f, "\r\n"); -} - -void update_springboard_plist(){ - NSDictionary *springBoardPlist = [NSMutableDictionary dictionaryWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.springboard.plist"]; - [springBoardPlist setValue:@YES forKey:@"SBShowNonDefaultSystemApps"]; - [springBoardPlist writeToFile:@"/var/mobile/Library/Preferences/com.apple.springboard.plist" atomically:YES]; - - NSDictionary* attr = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithShort:0755], NSFilePosixPermissions,@"mobile",NSFileOwnerAccountName,NULL]; - - NSError *error = nil; - [[NSFileManager defaultManager] setAttributes:attr ofItemAtPath:@"/var/mobile/Library/Preferences/com.apple.springboard.plist" error:&error]; -} - -void handleConnection(int socket) { - FILE *f = fdopen(socket, "r+b"); - if (f == NULL) { - return; - } - - fprintf(f, "===================================================================\r\n"); - fprintf(f, " iDownload Copyright (C) 2019/2020 Linus Henze \r\n"); - fprintf(f, " Part of the Fugu Jailbreak \r\n"); - fprintf(f, " https://github.com/LinusHenze/Fugu \r\n\r\n"); - fprintf(f, " This is free software, and you are welcome to redistribute it \r\n"); - fprintf(f, "under certain conditions; See the LICENSE file for more information\r\n\r\n"); - fprintf(f, " If you paid for this software, you got scammed \r\n"); - fprintf(f, "===================================================================\r\n\r\n"); - fprintf(f, "iDownload version " VERSION " ready.\r\n"); - - char *cmdBuffer = malloc(2048); - - while (1) { - fprintf(f, "iDownload> "); - - // Read a command - if (!readToNewline(f, cmdBuffer, 2048)) { - break; +int main(int argc, char **argv) { +#ifdef iOS + if (getpid() == 1) { + // We're the first process + // Spawn launchd + pid_t pid = fork(); + if (pid != 0) { + // Parent + char *args[] = { "/sbin/launchd", NULL }; + execve("/sbin/launchd", args, environ); + return -1; } - // Guaranteed to always exist - char *cmd = getParameter(cmdBuffer, 0); + // Sleep a bit for launchd to do some work + sleep(3); - // Execute it - if (strcmp(cmd, "help") == 0) { - printHelp(f); - } else if (strcmp(cmd, "exit") == 0) { - fprintf(f, "Bye!\r\n"); - break; - } else if (strcmp(cmd, "exit_full") == 0) { - fprintf(f, "Completely exiting.\r\nBye!\r\n"); - exit(0); - } else if (strcmp(cmd, "pwd") == 0) { - char cwd[PATH_MAX]; - memset(cwd, 0, PATH_MAX); - getcwd(cwd, PATH_MAX); - - fprintf(f, "%s\r\n", cwd); - } else if (strcmp(cmd, "cd") == 0) { - char *param = getParameter(cmdBuffer, 1); - if (param) { - if (chdir(param) < 0) { - fprintf(f, "cd: %s\r\n", strerror(errno)); - } - - free(param); - } else { - fprintf(f, "Usage: cd \r\n"); - } - } else if (strcmp(cmd, "ls") == 0) { - char *param = getParameter(cmdBuffer, 1); - if (!param) { - param = strdup("."); + // Now get task port for something that has a valid bootstrap port + int ctr = getpid() + 1; + mach_port_t port = 0; + while (!port) { + port = task_for_pid_backdoor(ctr++); + if (!port) { + continue; } - DIR *d; - struct dirent *dir; - d = opendir(param); - if (d) { - readdir(d); // Skip . - readdir(d); // Skip .. - - while ((dir = readdir(d)) != NULL) { - fprintf(f, "%s\r\n", dir->d_name); - } - - closedir(d); - } else { - fprintf(f, "ls: %s\r\n", strerror(errno)); + mach_port_t bp = 0; + task_get_bootstrap_port(port, &bp); + if (!bp) { + port = 0; + continue; } - free(param); - } else if (strcmp(cmd, "clear") == 0) { - fprintf(f, "\E[H\E[J"); - } else if (strcmp(cmd, "write") == 0) { - char *name = getParameter(cmdBuffer, 1); - if (name) { - char *length = getParameter(cmdBuffer, 2); - if (length) { - FILE *file = fopen(name, "wb+"); - if (file) { - size_t size = strtoul(length, NULL, 0); - if (size) { - char *buffer = malloc(size); - if (buffer) { - size_t offset = 0; - while (offset < size) { - size_t read = fread(buffer + offset, 1, 1, f); - if (read < 1) { - // OOPS - offset = 0; - break; - } - - offset++; - } - - if (offset == size) { - fwrite(buffer, size, 1, file); - fprintf(f, "\r\nFile written.\r\n"); - } else { - fprintf(f, "\r\nFailed to write file!\r\n"); - } - - fclose(file); - - free(buffer); - } else { - fprintf(f, "write: %s\r\n", strerror(errno)); - } - } else { - fprintf(f, "Usage: write \r\n"); - } - } else { - fprintf(f, "write: %s\r\n", strerror(errno)); - } - - free(length); - } else { - fprintf(f, "Usage: write \r\n"); - } - - free(name); - } else { - fprintf(f, "Usage: write \r\n"); - } - } else if (strcmp(cmd, "cat") == 0) { - char *param = getParameter(cmdBuffer, 1); - if (param) { - FILE *file = fopen(param, "rb"); - if (file) { - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - fseek(file, 0, SEEK_SET); - - char *buffer = malloc(size + 1); - memset(buffer, 0, size + 1); - if (buffer) { - fread(buffer, size, 1, file); - fprintf(f, "%s\r\n", buffer); - } else { - fprintf(f, "cat: %s\r\n", strerror(errno)); - } - - fclose(file); - } else { - fprintf(f, "cat: %s\r\n", strerror(errno)); - } - - free(param); - } else { - fprintf(f, "Usage: cat \r\n"); - } - } else if (strcmp(cmd, "rm") == 0) { - char *param = getParameter(cmdBuffer, 1); - if (param) { - if (unlink(param) < 0) { - fprintf(f, "rm: %s\r\n", strerror(errno)); - } - - free(param); - } else { - fprintf(f, "Usage: rm \r\n"); - } - } else if (strcmp(cmd, "chmod") == 0) { - char *modeStr = getParameter(cmdBuffer, 1); - if (modeStr) { - char *param = getParameter(cmdBuffer, 2); - if (param) { - size_t mode = strtoul(modeStr, NULL, 8); - if (mode) { - if (chmod(param, mode) < 0) { - fprintf(f, "chmod: %s\r\n", strerror(errno)); - } - } else { - fprintf(f, "Usage: chmod \r\n"); - } - - free(param); - } else { - fprintf(f, "Usage: chmod \r\n"); - } - - free(modeStr); - } else { - fprintf(f, "Usage: chmod \r\n"); - } - } else if (strcmp(cmd, "chown") == 0) { - char *uid_str = getParameter(cmdBuffer, 1); - if (uid_str) { - char *gid_str = getParameter(cmdBuffer, 2); - if (gid_str) { - char *param = getParameter(cmdBuffer, 3); - if (param) { - size_t uid = strtoul(uid_str, NULL, 0); - size_t gid = strtoul(gid_str, NULL, 0); - if (chown(param, (uid_t) uid, (gid_t) gid) < 0) { - fprintf(f, "chown: %s\r\n", strerror(errno)); - } - - free(param); - } else { - fprintf(f, "Usage: chown \r\n"); - } - - free(gid_str); - } else { - fprintf(f, "Usage: chown \r\n"); - } - - free(uid_str); - } else { - fprintf(f, "Usage: chown \r\n"); - } - } else if (strcmp(cmd, "rmdir") == 0) { - char *param = getParameter(cmdBuffer, 1); - if (param) { - if (rmdir(param) < 0) { - fprintf(f, "rmdir: %s\r\n", strerror(errno)); - } - - free(param); - } else { - fprintf(f, "Usage: rmdir \r\n"); - } - } else if (strcmp(cmd, "info") == 0) { - char *param = getParameter(cmdBuffer, 1); - if (param) { - printInfo(f, param); - free(param); - } else { - fprintf(f, "Usage: info \r\n"); - } - } else if (strcmp(cmd, "mkdir") == 0) { - char *param = getParameter(cmdBuffer, 1); - if (param) { - if (mkdir(param, 0777) < 0) { - fprintf(f, "mkdir: %s\r\n", strerror(errno)); - } - - free(param); - } else { - fprintf(f, "Usage: mkdir \r\n"); - } - } else if (strcmp(cmd, "exec") == 0) { - char *param = getParameter(cmdBuffer, 1); - if (param) { - int ctr = 2; - while (1) { - char *param = getParameter(cmdBuffer, ctr++); - if (!param) { - break; - } - - free(param); - } - - char **buf = malloc(ctr * sizeof(char*)); - buf[0] = param; - - ctr = 2; - while (1) { - char *param = getParameter(cmdBuffer, ctr); - if (!param) { - break; - } - - buf[(ctr++) - 1] = param; - } - - buf[ctr - 1] = NULL; - - int status = runCommand(f, buf); - while (*buf) { - free(*buf); - buf++; - } - - fprintf(f, "exec: Child status: %d\r\n", status); - } else { - fprintf(f, "Usage: exec \r\n"); - } - } else if (strcmp(cmd, "bootstrap") == 0) { - // Bootstrap the device from /bootstrap.tar using /bin/tar - int fd = open("/bootstrap.tar", O_RDONLY); - if (fd != -1) { - close(fd); - - fd = open("/bin/tar", O_RDONLY); - if (fd != -1) { - close(fd); - - fprintf(f, "Extracting bootstrap.tar\r\n"); - fflush(f); - - chdir("/"); - - // All the stuff exists, let's go! - char *argv[] = { "/bin/tar", "--preserve-permissions", "--no-overwrite-dir", "-xvf", "/bootstrap.tar", NULL }; - int res = runCommand(f, argv); - if (res == 0) { - fd = open("/usr/bin/ssh-keygen", O_RDONLY); - if (fd != -1) { - close(fd); - fprintf(f, "Generating SSH Host Keys...\r\n"); - fflush(f); - char *args[] = { "/usr/bin/ssh-keygen", "-A", NULL }; - runCommand(f, args); - } - - fd = open("/usr/bin/launchctl", O_RDONLY); - if (fd != -1) { - close(fd); - - fprintf(f, "Launching services...\r\n"); - fflush(f); - char *launchctlArgs[] = { "/bin/bash", "-c", "/usr/bin/launchctl load /Library/LaunchDaemons/*", NULL }; - res = runCommand(f, launchctlArgs); - if (res == 0) { - fprintf(f, "Successfully started services!\r\n"); - fflush(f); - } else { - fprintf(f, "Failed to start services!\r\n"); - fflush(f); - } - } else { - fprintf(f, "bootstrap: Couldn't find launchctl, cannot start services!\r\n"); - fflush(f); - } - - fd = open("/usr/libexec/cydia/firmware.sh", O_RDONLY); - if (fd != -1) { - close(fd); - - fprintf(f, "Installing firmware package...\r\n"); - fflush(f); - - char *args[] = { "/bin/bash", "-c", "/usr/libexec/cydia/firmware.sh", NULL }; - runCommand(f, args); - - fd = open("/sileo.deb", O_RDONLY); - if (fd != -1) { - close(fd); - - fd = open("/cydia.deb", O_RDONLY); - if (fd != -1) { - close(fd); - - fd = open("/swift.deb", O_RDONLY); - if (fd != -1) { - close(fd); - - fprintf(f, "Installing Sileo...\r\n"); - fflush(f); - - setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin", 1); - char *args[] = { "/usr/bin/dpkg", "-i", "/sileo.deb", "/cydia.deb", "/swift.deb", NULL }; - runCommand(f, args); - - // Create /var/lib/dpkg/available - char *args_touch[] = { "/usr/bin/touch", "/var/lib/dpkg/available", NULL }; - runCommand(f, args_touch); - - fd = open("/MobileSubstrate.deb", O_RDONLY); - if (fd != -1) { - close(fd); - - fd = open("/SafeMode.deb", O_RDONLY); - if (fd != -1) { - close(fd); - - fprintf(f, "Removing Substrate Compatibility Layer...\r\n"); - fflush(f); - - char *args[] = { "/usr/bin/apt-get", "remove", "-y", "mobilesubstrate", "com.saurik.substrate.safemode", NULL }; - runCommand(f, args); - - fprintf(f, "Installing MobileSubstrate...\r\n"); - fflush(f); - - char *args2[] = { "/usr/bin/dpkg", "-i", "/MobileSubstrate.deb", "/SafeMode.deb", NULL }; - runCommand(f, args2); - } - } - - fprintf(f, "Adding chimera repo...\r\n"); - fflush(f); - - FILE *fp = fopen("/etc/apt/sources.list.d/chimera.list", "w+"); - if (fp) { - fwrite("deb https://repo.chimera.sh/ ./", 31, 1, fp); - fclose(fp); - } else { - fprintf(f, "bootstrap: Failed to add chimera repo!\r\n"); - fflush(f); - } - - fprintf(f, "Updating Springboard Plist...\r\n"); - fflush(f); - update_springboard_plist(); - - fprintf(f, "Running uicache...\r\n"); - fflush(f); - char *argsUicache[] = { "/bin/bash", "-c", "uicache --path /Applications/Sileo.app --respring", NULL }; - runCommand(f, argsUicache); - } - } - } - } - } else { - fprintf(f, "bootstrap: tar failed!\r\n"); - } - - // We're done - break; - } else { - fprintf(f, "bootstrap: /bin/tar is missing!\r\n"); - } - } else { - fprintf(f, "bootstrap: /bootstrap.tar is missing!\r\n"); - } - } else { - fprintf(f, "Unknown command %s!\r\n", cmdBuffer); + bPort = bp; + insertBP(); } - free(cmd); - } - - fclose(f); -} - -int main(int argc, char **argv) { -#ifdef iOS - pid_t pid = fork(); - if (pid != 0) { - execve("/sbin/launchd", argv, environ); + // Now we've got a valid bootstrap port! + // Re-Exec with the bp + execv(argv[0], argv); return -1; - } - - // Sleep a bit for launchd to do some work - sleep(3); - - // Now get task port for something that has a valid bootstrap port - int ctr = getpid() + 1; - mach_port_t port = 0; - while (!port) { - port = task_for_pid_backdoor(ctr++); - if (!port) { - continue; - } + } else if (getpid() == 2) { + // After exec + // Set PATH + setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin", 1); - mach_port_t bp = 0; - task_get_bootstrap_port(port, &bp); - if (!bp) { - port = 0; - continue; - } - - bPort = bp; - insertBP(); - } - - // Now we've got a valid bootstrap port! - // Check if launchctl and bash exist - // If they do, load all daemons - int fd = open("/bin/bash", O_RDONLY); - if (fd != -1) { - close(fd); - fd = open("/usr/bin/launchctl", O_RDONLY); - if (fd != -1) { - close(fd); - + // Check if launchctl and bash exist + // If they do, load all daemons + if (FILE_EXISTS("/.Fugu_installed") && FILE_EXISTS("/bin/bash") && FILE_EXISTS("/sbin/launchctl")) { pid_t pid = fork(); if (pid == 0) { // Child - char *args[] = { "/bin/bash", "-c", "/usr/bin/launchctl load /Library/LaunchDaemons/*", NULL }; + char *args[] = { "/bin/bash", "-c", "/sbin/launchctl load /Library/LaunchDaemons/*", NULL }; execve("/bin/bash", args, environ); exit(-1); } // Parent waitpid(pid, NULL, 0); - } - - // If MobileSubstrate is installed, run it! - fd = open("/usr/libexec/substrate", O_RDONLY); - if (fd != -1) { - close(fd); - pid_t pid = fork(); - if (pid == 0) { - // Child - char *args[] = { "/usr/libexec/substrate", NULL }; - execve("/usr/libexec/substrate", args, environ); - exit(-1); + // Inject substitute + if (FILE_EXISTS("/etc/rc.d/substitute")) { + pid_t pid = fork(); + if (pid == 0) { + // Child + char *args[] = { "/etc/rc.d/substitute", NULL }; + execve("/etc/rc.d/substitute", args, environ); + exit(-1); + } + + // Sleep a bit + sleep(5); + + // Parent + waitpid(pid, NULL, 0); + + // Kill cfprefsd in case it was running already + pid = fork(); + if (pid == 0) { + // Child + char *args[] = { "/bin/bash", "-c", "/sbin/launchctl stop com.apple.cfprefsd.xpc.daemon", NULL }; + execve("/bin/bash", args, environ); + exit(-1); + } + + // Parent + waitpid(pid, NULL, 0); } - - // Parent - waitpid(pid, NULL, 0); + } else { + // Install didn't succeed yet + requestInstall(); } } #endif - int server_fd = socket(AF_INET, SOCK_STREAM, 0); - if (server_fd < 0) { - return -1; - } - - dup2(server_fd, 10); - close(server_fd); - server_fd = 10; + launchServer(); - int option = 1; - - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option)) < 0) { - return -1; - } - - struct sockaddr_in server; - - memset(&server, 0, sizeof (server)); - server.sin_family = AF_INET; - server.sin_addr.s_addr = inet_addr("127.0.0.1"); - server.sin_port = htons(1337); - - if (bind(server_fd, (struct sockaddr*) &server, sizeof(server)) < 0) { - return -1; - } - - if (listen(server_fd, SOMAXCONN) < 0) { - return -1; - } - - while (1) { - int new_socket = accept(server_fd, NULL, NULL); - if (new_socket == -1) { - if (errno == EINTR) { - continue; - } - - return -1; - } - - dispatch_async(dispatch_queue_create(NULL, NULL), ^{ - handleConnection(new_socket); - }); - } + CFRunLoopRun(); } diff --git a/iDownload/iDownload/server.c b/iDownload/iDownload/server.c new file mode 100644 index 0000000..b75ddb0 --- /dev/null +++ b/iDownload/iDownload/server.c @@ -0,0 +1,646 @@ +// +// server.c +// iDownload +// +// Created by Linus Henze on 09.02.20. +// Copyright © 2020 Linus Henze. All rights reserved. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "server.h" +#include "install.h" + +extern char **environ; + +int runCommand(FILE *f, char *argv[]) { + pid_t pid = fork(); + if (pid == 0) { + dup2(fileno(f), STDIN_FILENO); + dup2(fileno(f), STDOUT_FILENO); + dup2(fileno(f), STDERR_FILENO); + + execve(argv[0], argv, environ); + fprintf(stderr, "child: Failed to launch! Error: %s\r\n", strerror(errno)); + exit(-1); + } + + // Now wait for child + int status; + waitpid(pid, &status, 0); + + return WEXITSTATUS(status); +} + +bool readToNewline(FILE *f, char *buf, size_t size) { + size_t cmdOffset = 0; + memset(buf, 0, size); + + while (1) { + // Read incoming data + size_t status = fread(buf + cmdOffset, 1, 1, f); + if (status < 1) { + return false; + } + + cmdOffset++; + if (cmdOffset >= (size-1)) { + fprintf(f, "\r\nERROR: Command to long!\r\n"); + cmdOffset = 0; + memset(buf, 0, size); + continue; + } + + // Check if there is a newline somewhere + char *loc = strstr(buf, "\n"); + if (!loc) { + continue; + } + + // There is + if ((loc - 1) >= buf) { + if (*(loc - 1) == '\r') { + loc--; + } + } + + *loc = 0; + return true; + } +} + +char *getParameter(char *buf, int param) { + char *loc = buf; + + for (int i = 0; i < param; i++) { + loc = strstr(loc, " "); + if (!loc) { + return NULL; + } + + loc++; // Skip over the space + } + + char *next = strstr(loc, " "); + if (!next) { + return strdup(loc); + } + + *next = 0; + char *data = strdup(loc); + *next = ' '; + + return data; +} + +/* + * https://stackoverflow.com/questions/10323060/printing-file-permissions-like-ls-l-using-stat2-in-c + */ +void printInfo(FILE *f, char *file) { + struct stat fileStat; + if(lstat(file, &fileStat) < 0) { + fprintf(f, "info: %s\r\n", strerror(errno)); + return; + } + + fprintf(f, "---------------------------\r\n"); + fprintf(f, "Information for %s\r\n", file); + fprintf(f, "---------------------------\r\n"); + if (fileStat.st_size != 1) { + fprintf(f, "File Size: \t\t%lld bytes\r\n", fileStat.st_size); + } else { + fprintf(f, "File Size: \t\t1 byte\r\n"); + } + + //fprintf(f, "Number of Links: \t%d\r\n", fileStat.st_nlink); + //fprintf(f, "File inode: \t\t%llu\r\n", fileStat.st_ino); + + fprintf(f, "File Permissions: \t"); + fprintf(f, (S_ISDIR(fileStat.st_mode)) ? "d" : "-"); + fprintf(f, (fileStat.st_mode & S_IRUSR) ? "r" : "-"); + fprintf(f, (fileStat.st_mode & S_IWUSR) ? "w" : "-"); + if (fileStat.st_mode & S_ISUID) { + fprintf(f, (fileStat.st_mode & S_IXUSR) ? "s" : "S"); + } else { + fprintf(f, (fileStat.st_mode & S_IXUSR) ? "x" : "-"); + } + fprintf(f, (fileStat.st_mode & S_IRGRP) ? "r" : "-"); + fprintf(f, (fileStat.st_mode & S_IWGRP) ? "w" : "-"); + if (fileStat.st_mode & S_ISGID) { + fprintf(f, (fileStat.st_mode & S_IXGRP) ? "s" : "S"); + } else { + fprintf(f, (fileStat.st_mode & S_IXGRP) ? "x" : "-"); + } + fprintf(f, (fileStat.st_mode & S_IROTH) ? "r" : "-"); + fprintf(f, (fileStat.st_mode & S_IWOTH) ? "w" : "-"); + fprintf(f, (fileStat.st_mode & S_IXOTH) ? "x" : "-"); + fprintf(f, "\r\n"); + fprintf(f, "File Owner UID: \t%d\r\n", fileStat.st_uid); + fprintf(f, "File Owner GID: \t%d\r\n", fileStat.st_gid); + + if (S_ISLNK(fileStat.st_mode)) { + fprintf(f, "\r\n"); + fprintf(f, "The file is a symbolic link.\r\n"); + } +} + +void printHelp(FILE *f) { + fprintf(f, "iDownload has a bash-like interface\r\n"); + fprintf(f, "The following commands are supported:\r\n"); + fprintf(f, "exit: Close connection\r\n"); + fprintf(f, "exit_full: Close connection and terminate iDownload\r\n"); + fprintf(f, "pwd: Print current working directory\r\n"); + fprintf(f, "cd : Change directory\r\n"); + fprintf(f, "ls : List directory\r\n"); + fprintf(f, "clear: Clear screen\r\n"); + fprintf(f, "write : Create file with name and size\r\n"); + fprintf(f, " Send file data afterwards\r\n"); + fprintf(f, "cat : Print contents of file\r\n"); + fprintf(f, "rm : Delete file\r\n"); + fprintf(f, "rmdir : Delete an empty folder\r\n"); + fprintf(f, "chmod : Chmod a file. Mode must be octal\r\n"); + fprintf(f, "chown : Chown a file\r\n"); + fprintf(f, "info : Print file infos\r\n"); + fprintf(f, "mkdir : Create a directory\r\n"); + fprintf(f, "exec : Launch a program\r\n"); + fprintf(f, "help: Print this help\r\n"); + fprintf(f, "\r\n"); +} + +void handleConnection(int socket) { + FILE *f = fdopen(socket, "r+b"); + if (f == NULL) { + return; + } + + fprintf(f, "===================================================================\r\n"); + fprintf(f, " iDownload Copyright (C) 2019/2020 Linus Henze \r\n"); + fprintf(f, " Part of the Fugu Jailbreak \r\n"); + fprintf(f, " https://github.com/LinusHenze/Fugu \r\n\r\n"); + fprintf(f, " This is free software, and you are welcome to redistribute it \r\n"); + fprintf(f, "under certain conditions; See the LICENSE file for more information\r\n\r\n"); + fprintf(f, " If you paid for this software, you got scammed \r\n"); + fprintf(f, "===================================================================\r\n\r\n"); + fprintf(f, "iDownload version " VERSION " ready.\r\n"); + + char *cmdBuffer = malloc(2048); + + while (1) { + fprintf(f, "iDownload> "); + + // Read a command + if (!readToNewline(f, cmdBuffer, 2048)) { + break; + } + + // Guaranteed to always exist + char *cmd = getParameter(cmdBuffer, 0); + + // Execute it + if (strcmp(cmd, "help") == 0) { + printHelp(f); + } else if (strcmp(cmd, "exit") == 0) { + fprintf(f, "Bye!\r\n"); + break; + } else if (strcmp(cmd, "exit_full") == 0) { + fprintf(f, "Completely exiting.\r\nBye!\r\n"); + exit(0); + } else if (strcmp(cmd, "pwd") == 0) { + char cwd[PATH_MAX]; + memset(cwd, 0, PATH_MAX); + getcwd(cwd, PATH_MAX); + + fprintf(f, "%s\r\n", cwd); + } else if (strcmp(cmd, "cd") == 0) { + char *param = getParameter(cmdBuffer, 1); + if (param) { + if (chdir(param) < 0) { + fprintf(f, "cd: %s\r\n", strerror(errno)); + } + + free(param); + } else { + fprintf(f, "Usage: cd \r\n"); + } + } else if (strcmp(cmd, "ls") == 0) { + char *param = getParameter(cmdBuffer, 1); + if (!param) { + param = strdup("."); + } + + DIR *d; + struct dirent *dir; + d = opendir(param); + if (d) { + readdir(d); // Skip . + readdir(d); // Skip .. + + while ((dir = readdir(d)) != NULL) { + fprintf(f, "%s\r\n", dir->d_name); + } + + closedir(d); + } else { + fprintf(f, "ls: %s\r\n", strerror(errno)); + } + + free(param); + } else if (strcmp(cmd, "clear") == 0) { + fprintf(f, "\E[H\E[J"); + } else if (strcmp(cmd, "write") == 0) { + char *name = getParameter(cmdBuffer, 1); + if (name) { + char *length = getParameter(cmdBuffer, 2); + if (length) { + FILE *file = fopen(name, "wb+"); + if (file) { + size_t size = strtoul(length, NULL, 0); + if (size) { + char *buffer = malloc(size); + if (buffer) { + size_t offset = 0; + while (offset < size) { + size_t read = fread(buffer + offset, 1, 1, f); + if (read < 1) { + // OOPS + offset = 0; + break; + } + + offset++; + } + + if (offset == size) { + fwrite(buffer, size, 1, file); + fprintf(f, "\r\nFile written.\r\n"); + } else { + fprintf(f, "\r\nFailed to write file!\r\n"); + } + + fclose(file); + + free(buffer); + } else { + fprintf(f, "write: %s\r\n", strerror(errno)); + } + } else { + fprintf(f, "Usage: write \r\n"); + } + } else { + fprintf(f, "write: %s\r\n", strerror(errno)); + } + + free(length); + } else { + fprintf(f, "Usage: write \r\n"); + } + + free(name); + } else { + fprintf(f, "Usage: write \r\n"); + } + } else if (strcmp(cmd, "cat") == 0) { + char *param = getParameter(cmdBuffer, 1); + if (param) { + FILE *file = fopen(param, "rb"); + if (file) { + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + fseek(file, 0, SEEK_SET); + + char *buffer = malloc(size + 1); + memset(buffer, 0, size + 1); + if (buffer) { + fread(buffer, size, 1, file); + fprintf(f, "%s\r\n", buffer); + } else { + fprintf(f, "cat: %s\r\n", strerror(errno)); + } + + fclose(file); + } else { + fprintf(f, "cat: %s\r\n", strerror(errno)); + } + + free(param); + } else { + fprintf(f, "Usage: cat \r\n"); + } + } else if (strcmp(cmd, "rm") == 0) { + char *param = getParameter(cmdBuffer, 1); + if (param) { + if (unlink(param) < 0) { + fprintf(f, "rm: %s\r\n", strerror(errno)); + } + + free(param); + } else { + fprintf(f, "Usage: rm \r\n"); + } + } else if (strcmp(cmd, "chmod") == 0) { + char *modeStr = getParameter(cmdBuffer, 1); + if (modeStr) { + char *param = getParameter(cmdBuffer, 2); + if (param) { + size_t mode = strtoul(modeStr, NULL, 8); + if (mode) { + if (chmod(param, mode) < 0) { + fprintf(f, "chmod: %s\r\n", strerror(errno)); + } + } else { + fprintf(f, "Usage: chmod \r\n"); + } + + free(param); + } else { + fprintf(f, "Usage: chmod \r\n"); + } + + free(modeStr); + } else { + fprintf(f, "Usage: chmod \r\n"); + } + } else if (strcmp(cmd, "chown") == 0) { + char *uid_str = getParameter(cmdBuffer, 1); + if (uid_str) { + char *gid_str = getParameter(cmdBuffer, 2); + if (gid_str) { + char *param = getParameter(cmdBuffer, 3); + if (param) { + size_t uid = strtoul(uid_str, NULL, 0); + size_t gid = strtoul(gid_str, NULL, 0); + if (chown(param, (uid_t) uid, (gid_t) gid) < 0) { + fprintf(f, "chown: %s\r\n", strerror(errno)); + } + + free(param); + } else { + fprintf(f, "Usage: chown \r\n"); + } + + free(gid_str); + } else { + fprintf(f, "Usage: chown \r\n"); + } + + free(uid_str); + } else { + fprintf(f, "Usage: chown \r\n"); + } + } else if (strcmp(cmd, "rmdir") == 0) { + char *param = getParameter(cmdBuffer, 1); + if (param) { + if (rmdir(param) < 0) { + fprintf(f, "rmdir: %s\r\n", strerror(errno)); + } + + free(param); + } else { + fprintf(f, "Usage: rmdir \r\n"); + } + } else if (strcmp(cmd, "info") == 0) { + char *param = getParameter(cmdBuffer, 1); + if (param) { + printInfo(f, param); + free(param); + } else { + fprintf(f, "Usage: info \r\n"); + } + } else if (strcmp(cmd, "mkdir") == 0) { + char *param = getParameter(cmdBuffer, 1); + if (param) { + if (mkdir(param, 0777) < 0) { + fprintf(f, "mkdir: %s\r\n", strerror(errno)); + } + + free(param); + } else { + fprintf(f, "Usage: mkdir \r\n"); + } + } else if (strcmp(cmd, "exec") == 0) { + char *param = getParameter(cmdBuffer, 1); + if (param) { + int ctr = 2; + while (1) { + char *param = getParameter(cmdBuffer, ctr++); + if (!param) { + break; + } + + free(param); + } + + char **buf = malloc(ctr * sizeof(char*)); + buf[0] = param; + + ctr = 2; + while (1) { + char *param = getParameter(cmdBuffer, ctr); + if (!param) { + break; + } + + buf[(ctr++) - 1] = param; + } + + buf[ctr - 1] = NULL; + + int status = runCommand(f, buf); + while (*buf) { + free(*buf); + buf++; + } + + fprintf(f, "exec: Child status: %d\r\n", status); + } else { + fprintf(f, "Usage: exec \r\n"); + } + } else if (strcmp(cmd, "bootstrap") == 0) { + // Bootstrap the device from /bootstrap.tar using /bin/tar + if (FILE_EXISTS("/bootstrap.tar")) { + if (FILE_EXISTS("/bin/tar")) { + fprintf(f, "Extracting bootstrap.tar\r\n"); + fflush(f); + + chdir("/"); + + // All the stuff exists, let's go! + char *argv[] = { "/bin/tar", "--preserve-permissions", "--no-overwrite-dir", "-xvf", "/bootstrap.tar", NULL }; + int res = runCommand(f, argv); + if (res == 0) { + if (FILE_EXISTS("/usr/bin/ssh-keygen")) { + fprintf(f, "Generating SSH Host Keys...\r\n"); + fflush(f); + char *args[] = { "/usr/bin/ssh-keygen", "-A", NULL }; + runCommand(f, args); + } + + if (FILE_EXISTS("/usr/libexec/cydia/firmware.sh")) { + fprintf(f, "Installing firmware package...\r\n"); + fflush(f); + + char *args[] = { "/bin/bash", "-c", "/usr/libexec/cydia/firmware.sh", NULL }; + runCommand(f, args); + + if (FILE_EXISTS("/sileo.deb") && FILE_EXISTS("/cydia.deb") && FILE_EXISTS("/swift.deb")) { + fprintf(f, "Installing Sileo...\r\n"); + fflush(f); + + setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin", 1); + char *args[] = { "/usr/bin/dpkg", "-i", "/sileo.deb", "/cydia.deb", "/swift.deb", NULL }; + runCommand(f, args); + + // Create /var/lib/dpkg/available + char *args_touch[] = { "/usr/bin/touch", "/var/lib/dpkg/available", NULL }; + runCommand(f, args_touch); + + bool hasSubstitute = false; + + if (FILE_EXISTS("/Substitute.deb") && FILE_EXISTS("/Unsandbox.deb")) { + fprintf(f, "Installing Substitute...\r\n"); + fflush(f); + + char *args2[] = { "/usr/bin/dpkg", "-i", "/Substitute.deb", "/Unsandbox.deb", NULL }; + runCommand(f, args2); + + hasSubstitute = true; + } + + fprintf(f, "Adding chimera repo...\r\n"); + fflush(f); + + FILE *fp = fopen("/etc/apt/sources.list.d/chimera.list", "w+"); + if (fp) { + fwrite("deb https://repo.chimera.sh/ ./", 31, 1, fp); + fclose(fp); + } else { + fprintf(f, "bootstrap: Failed to add chimera repo!\r\n"); + fflush(f); + } + + fprintf(f, "Updating Springboard Plist...\r\n"); + fflush(f); + update_springboard_plist(); + + if (FILE_EXISTS("/sbin/launchctl")) { + fprintf(f, "Launching services...\r\n"); + fflush(f); + char *launchctlArgs[] = { "/bin/bash", "-c", "/sbin/launchctl load /Library/LaunchDaemons/*", NULL }; + res = runCommand(f, launchctlArgs); + if (res == 0) { + fprintf(f, "Successfully started services!\r\n"); + fflush(f); + } else { + fprintf(f, "Failed to start services!\r\n"); + fflush(f); + } + } else { + fprintf(f, "bootstrap: Couldn't find launchctl, cannot start services!\r\n"); + fflush(f); + } + + fprintf(f, "Running uicache...\r\n"); + fflush(f); + char *argsUicache[] = { "/bin/bash", "-c", "uicache --path /Applications/Sileo.app", NULL }; + runCommand(f, argsUicache); + + if (hasSubstitute) { + // Launch it! + char *args_substitute[] = { "/etc/rc.d/substitute", NULL }; + runCommand(f, args_substitute); + + // Kill cfprefsd + char *args_kill[] = { "/bin/bash", "-c", "killall -9 cfprefsd", NULL }; + runCommand(f, args_kill); + } + + fprintf(f, "Respringing...\r\n"); + fflush(f); + + char *args_respring[] = { "/bin/bash", "-c", "killall -SIGTERM SpringBoard", NULL }; + runCommand(f, args_respring); + } + } + } else { + fprintf(f, "bootstrap: tar failed!\r\n"); + } + + // We're done + break; + } else { + fprintf(f, "bootstrap: /bin/tar is missing!\r\n"); + } + } else { + fprintf(f, "bootstrap: /bootstrap.tar is missing!\r\n"); + } + } else { + fprintf(f, "Unknown command %s!\r\n", cmdBuffer); + } + + free(cmd); + } + + fclose(f); +} + +void launchServer() { + dispatch_async(dispatch_queue_create("Server", NULL), ^{ + int server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd < 0) { + exit(-1); + } + + dup2(server_fd, 10); + close(server_fd); + server_fd = 10; + + int option = 1; + + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option)) < 0) { + exit(-1); + } + + struct sockaddr_in server; + + memset(&server, 0, sizeof (server)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = inet_addr("127.0.0.1"); + server.sin_port = htons(1337); + + if (bind(server_fd, (struct sockaddr*) &server, sizeof(server)) < 0) { + exit(-1); + } + + if (listen(server_fd, SOMAXCONN) < 0) { + exit(-1); + } + + while (1) { + int new_socket = accept(server_fd, NULL, NULL); + if (new_socket == -1) { + if (errno == EINTR) { + continue; + } + + exit(-1); + } + + dispatch_async(dispatch_queue_create(NULL, NULL), ^{ + handleConnection(new_socket); + }); + } + }); +} diff --git a/iDownload/iDownload/server.h b/iDownload/iDownload/server.h new file mode 100644 index 0000000..eb977db --- /dev/null +++ b/iDownload/iDownload/server.h @@ -0,0 +1,16 @@ +// +// server.h +// iDownload +// +// Created by Linus Henze on 09.02.20. +// Copyright © 2020 Linus Henze. All rights reserved. +// + +#ifndef server_h +#define server_h + +#include "common.h" + +void launchServer(void); + +#endif /* server_h */ diff --git a/iStrap/iStrap/patch.c b/iStrap/iStrap/patch.c index 60847f3..8098ff0 100644 --- a/iStrap/iStrap/patch.c +++ b/iStrap/iStrap/patch.c @@ -29,10 +29,11 @@ extern void setuid_patch_end(void); #define OFFSET_64(a, b) ((uint64_t) a - (uint64_t) b) -// FIXME: These shouldn't be static -#define TEXT_EXEC_BASE 0xFFFFFFF0070F0000ULL +// FIXME: This shouldn't be static #define KERNEL_FULL_BASE (void*) 0x820000000ULL +uintptr_t TEXT_EXEC_BASE = 0x0; + void *findTCFunc(void *stringLoc, DTMemoryEntry *kText_kxt, DTMemoryEntry *kText_krnl) { void *kTextKEXTEnd = (void*) ((uintptr_t) kText_kxt->start + kText_kxt->size); @@ -94,7 +95,19 @@ void *findRootmountallocCall(void *start, void *end, void *strLoc) { return NULL; } + bool isNewVersion = false; + while (vfs_mountroot < (uint32_t*) end) { + if (!isNewVersion) { + // Detect newer versions + uint32_t *branch = (uint32_t*) aarch64_emulate_b(*vfs_mountroot, (uint64_t) vfs_mountroot); + if (branch) { + // New version + vfs_mountroot = branch; + isNewVersion = true; + } + } + if (aarch64_emulate_bl(*vfs_mountroot, (uint64_t) vfs_mountroot)) { return vfs_mountroot; } @@ -275,9 +288,28 @@ void *resolveSymbol(char *name) { return NULL; } +void setTextExecBase() { + void *kernel_start = KERNEL_FULL_BASE; + while (*(uint32_t*) kernel_start != MH_MAGIC_64) { + kernel_start++; + } + + struct segment_command_64 *text_exec_seg = findSegmentLoadCommand(kernel_start, "__TEXT_EXEC"); + if (!text_exec_seg) { + puts("!!! FAILED TO FIND TEXT_EXEC SECTION (KERNEL_FULL_BASE) !!!"); + puts("!!! HANGING NOW !!!"); + while (1) {} + } + + TEXT_EXEC_BASE = text_exec_seg->vmaddr; +} + #define RESOLVE_TEXT_SYMBOL(name) ((void*) ((uintptr_t) resolveSymbol(name) - (uintptr_t) TEXT_EXEC_BASE + (uintptr_t) kText->start)) void applyKernelPatches(boot_args *args, bool iDownloadPresent, void *iDownloadLoc, size_t iDownloadSize) { + // Set TEXT_EXEC_BASE first + setTextExecBase(); + DTMemoryEntry *kStrings = dt_lookup_memory_map(args, "Kernel-__TEXT"); if (!kStrings) { puts("!!! FAILED TO FIND TEXT SECTION !!!"); diff --git a/iStrap/iStrap/shellcode.S b/iStrap/iStrap/shellcode.S index 070706e..1c8c93b 100644 --- a/iStrap/iStrap/shellcode.S +++ b/iStrap/iStrap/shellcode.S @@ -8,8 +8,8 @@ #define O_WRONLY 0x0001 #define O_CREAT 0x0200 -#define FWASWRITTEN 0x10000 -#define IO_NOAUTH 0x8000 +#define FWASWRITTEN 0x10000 +#define IO_NOAUTH 0x8000 .align 4 .text diff --git a/install_sileo.py b/install_sileo.py index 082ea29..4103fea 100644 --- a/install_sileo.py +++ b/install_sileo.py @@ -17,6 +17,13 @@ print(" If you paid for this software, you got scammed ") print("===================================================================\n") +print("NOT REQUIRED ANYMORE") +print("Fugu automatically installs all required files") +print("This script might be updated for offline install") +print("For now, use Fugu's online install") + +exit(-1) + def upload(r, name, data): socket = r.get_socket() socket.sendall(b"write %s %d\n"%(name.encode(), len(data)))