diff --git a/external/idevicerestore b/external/idevicerestore index 59ca01eb..988bd03b 160000 --- a/external/idevicerestore +++ b/external/idevicerestore @@ -1 +1 @@ -Subproject commit 59ca01ebf4a9ed2e019cf5b28cc01707adc283fb +Subproject commit 988bd03b5acd8692b23969a7e24b290abed75b5a diff --git a/futurerestore/futurerestore.cpp b/futurerestore/futurerestore.cpp index 02aa65f0..c89916b6 100644 --- a/futurerestore/futurerestore.cpp +++ b/futurerestore/futurerestore.cpp @@ -106,7 +106,7 @@ extern "C"{ } #pragma mark futurerestore -futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu, bool noIBSS, bool noRestore) : _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu), _noIBSS(noIBSS), _noRestore(noRestore){ +futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu, bool noIBSS, bool cfwRamdisk, bool cfwKernel, bool setNonce, bool noRestore) : _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu), _noIBSS(noIBSS), _cfwRamdisk(cfwRamdisk), _cfwKernel(cfwKernel), _setNonce(setNonce), _noRestore(noRestore){ _client = idevicerestore_client_new(); if (_client == NULL) throw std::string("could not create idevicerestore client\n"); @@ -582,7 +582,8 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){ info("ApNonce pre-hax:\n"); get_ap_nonce(_client, &_client->nonce, &_client->nonce_size); - std::string generator = getGeneratorFromSHSH2(_client->tss); + + std::string generator = (_setNonce && _custom_nonce != NULL) ? _custom_nonce : getGeneratorFromSHSH2(_client->tss); if(memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) != 0) { info("ApNonce from device doesn't match IM4M nonce, applying hax...\n"); @@ -616,7 +617,7 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){ printf("APnonce post-hax:\n"); get_ap_nonce(_client, &_client->nonce, &_client->nonce_size); assure(!irecv_send_command(_client->recovery->client, "bgcolor 255 255 0")); - retassure(memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) == 0, "ApNonce from device doesn't match IM4M nonce after applying ApNonce hax. Aborting!"); + retassure(_setNonce || memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) == 0, "ApNonce from device doesn't match IM4M nonce after applying ApNonce hax. Aborting!"); } else { getDeviceMode(true); retassure(((dfu_client_new(_client) == IRECV_E_SUCCESS) || (mutex_unlock(&_client->device_event_mutex),0)), "Failed to connect to device in Recovery Mode!"); @@ -643,6 +644,12 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){ retassure(!irecv_setenv(_client->recovery->client, "com.apple.System.boot-nonce", generator.c_str()), "failed to write generator to nvram"); retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram"); + if(_setNonce) { + info("Successfully set nonce generator: %s, exiting recovery mode...\n", generator.c_str()); + exitRecovery(); + exit(0); + } + sleep(2); } #endif //HAVE_LIBIPATCHER @@ -1947,6 +1954,40 @@ void futurerestore::loadVeridian(const char *veridianDGMPath, const char *veridi fclose(fveridianfwm); } +void futurerestore::loadRamdisk(const char *ramdiskPath){ + FILE *framdisk = NULL; + retassure(framdisk = fopen(ramdiskPath, "rb"), "failed to read Ramdisk\n"); + + fseek(framdisk, 0, SEEK_END); + _client->ramdiskdatasize = ftell(framdisk); + fseek(framdisk, 0, SEEK_SET); + + retassure(_client->ramdiskdata = (char*)malloc(_client->ramdiskdatasize), "failed to malloc memory for Ramdisk\n"); + + size_t freadRet=0; + retassure((freadRet = fread(_client->ramdiskdata, 1, _client->ramdiskdatasize, framdisk)) == _client->ramdiskdatasize, + "failed to load Ramdisk. size=%zu but fread returned %zu\n",_client->ramdiskdatasize,freadRet); + + fclose(framdisk); +} + +void futurerestore::loadKernel(const char *loadKernel){ + FILE *fkernel = NULL; + retassure(fkernel = fopen(loadKernel, "rb"), "failed to read Kernel\n"); + + fseek(fkernel, 0, SEEK_END); + _client->kerneldatasize = ftell(fkernel); + fseek(fkernel, 0, SEEK_SET); + + retassure(_client->kerneldata = (char*)malloc(_client->kerneldatasize), "failed to malloc memory for Kernel\n"); + + size_t freadRet=0; + retassure((freadRet = fread(_client->kerneldata, 1, _client->kerneldatasize, fkernel)) == _client->kerneldatasize, + "failed to load Kernel. size=%zu but fread returned %zu\n",_client->kerneldatasize,freadRet); + + fclose(fkernel); +} + void futurerestore::loadSep(const char *sepPath){ FILE *fsep = NULL; retassure(fsep = fopen(sepPath, "rb"), "failed to read SEP\n"); @@ -1972,6 +2013,21 @@ void futurerestore::setBasebandPath(const char *basebandPath){ fclose(fbb); } +void futurerestore::setRamdiskPath(const char *ramdiskPath) { + FILE *fbb = NULL; + + retassure(fbb = fopen(ramdiskPath, "rb"), "failed to read ramdisk"); + _ramdiskPath = ramdiskPath; + fclose(fbb); +} +void futurerestore::setKernelPath(const char *kernelPath) { + FILE *fbb = NULL; + + retassure(fbb = fopen(kernelPath, "rb"), "failed to read kernel"); + _kernelPath = kernelPath; + fclose(fbb); +} + #pragma mark static methods inline void futurerestore::saveStringToFile(const char *str, const char *path){ FILE *f = NULL; diff --git a/futurerestore/futurerestore.hpp b/futurerestore/futurerestore.hpp index 48bb62ac..d87322ff 100644 --- a/futurerestore/futurerestore.hpp +++ b/futurerestore/futurerestore.hpp @@ -58,6 +58,9 @@ class futurerestore { bool _isUpdateInstall = false; bool _isPwnDfu = false; bool _noIBSS = false; + bool _cfwRamdisk = false; + bool _cfwKernel = false; + bool _setNonce = false; bool _noRestore = false; char *_firmwareJson = NULL; @@ -77,6 +80,10 @@ class futurerestore { const char *_basebandPath = NULL; const char *_sepbuildmanifestPath = NULL; const char *_basebandbuildmanifestPath = NULL; + const char *_ramdiskPath = NULL; + const char *_kernelPath = NULL; + + const char *_custom_nonce = NULL; bool _enterPwnRecoveryRequested = false; bool _rerestoreiOS9 = false; @@ -85,7 +92,7 @@ class futurerestore { void enterPwnRecovery2(plist_t build_identity, std::string bootargs = ""); public: - futurerestore(bool isUpdateInstall = false, bool isPwnDfu = false, bool noIBSS = false, bool noRestore = false); + futurerestore(bool isUpdateInstall = false, bool isPwnDfu = false, bool noIBSS = false, bool cfwRamdisk = false, bool cfwKernel = false, bool setNonce = false, bool noRestore = false); bool init(); int getDeviceMode(bool reRequest); uint64_t getDeviceEcid(); @@ -119,8 +126,13 @@ public: void loadSE(const char *sePath); void loadSavage(const char *savagePath[6]); void loadVeridian(const char *veridianDGMPath, const char *veridianFWMPath); + void loadRamdisk(const char *ramdiskPath); + void loadKernel(const char *kernelPath); void loadSep(const char *sepPath); void setBasebandPath(const char *basebandPath); + void setRamdiskPath(const char *ramdiskPath); + void setKernelPath(const char *kernelPath); + void setNonce(const char *custom_nonce){_custom_nonce = custom_nonce;}; bool isUpdateInstall(){return _isUpdateInstall;}; plist_t sepManifest(){return _sepbuildmanifest;}; diff --git a/futurerestore/main.cpp b/futurerestore/main.cpp index 5f3de7d0..04164259 100644 --- a/futurerestore/main.cpp +++ b/futurerestore/main.cpp @@ -49,8 +49,10 @@ static struct option longopts[] = { { "no-baseband", no_argument, NULL, '2' }, #ifdef HAVE_LIBIPATCHER { "use-pwndfu", no_argument, NULL, '3' }, - { "just-boot", optional_argument, NULL, '4' }, - { "no-ibss", no_argument, NULL, '5' }, + { "no-ibss", no_argument, NULL, '4' }, + { "rdsk", required_argument, NULL, '5' }, + { "rkrn", required_argument, NULL, '6' }, + { "set-nonce", optional_argument, NULL, '7' }, #endif { NULL, 0, NULL, 0 } }; @@ -62,8 +64,10 @@ static struct option longopts[] = { #define FLAG_NO_BASEBAND 1 << 4 #define FLAG_IS_PWN_DFU 1 << 5 #define FLAG_NO_IBSS 1 << 6 -#define FLAG_NO_RESTORE_FR 1 << 7 - +#define FLAG_RESTORE_RAMDISK 1 << 7 +#define FLAG_RESTORE_KERNEL 1 << 8 +#define FLAG_SET_NONCE 1 << 9 +#define FLAG_NO_RESTORE_FR 1 << 10 void cmd_help(){ printf("Usage: futurerestore [OPTIONS] iPSW\n"); printf("Allows restoring to non-matching firmware with custom SEP+baseband\n"); @@ -79,8 +83,10 @@ void cmd_help(){ #ifdef HAVE_LIBIPATCHER printf("\nOptions for downgrading with Odysseus:\n"); printf(" --use-pwndfu\t\tRestoring devices with Odysseus method. Device needs to be in pwned DFU mode already\n"); - printf(" --just-boot=\"-v\"\t\tTethered booting the device from pwned DFU mode. You can optionally set boot-args\n"); printf(" --no-ibss\t\t\tRestoring devices with Odysseus method. For checkm8/iPwnder32 specifically, bootrom needs to be patched already with unless iPwnder.\n"); + printf(" --rdsk PATH\t\tSet custom restore ramdisk for entering restoremode(requires use-pwndfu)\n"); + printf(" --rkrn PATH\t\tSet custom restore kernelcache for entering restoremode(requires use-pwndfu)\n"); + printf(" --set-nonce NONCE\t\tSet custom nonce then exit recovery(requires use-pwndfu)\n"); #endif printf("\nOptions for SEP:\n"); @@ -131,7 +137,10 @@ int main_r(int argc, const char * argv[]) { const char *sepPath = NULL; const char *sepManifestPath = NULL; const char *bootargs = NULL; - + const char *ramdiskPath = NULL; + const char *kernelPath = NULL; + const char *custom_nonce = NULL; + vector apticketPaths; t_devicevals devVals = {0}; @@ -142,7 +151,7 @@ int main_r(int argc, const char * argv[]) { return -1; } - while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:wudez0123", longopts, &optindex)) > 0) { + while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:wudez01234567", longopts, &optindex)) > 0) { switch (opt) { case 't': // long option: "apticket"; can be called as short option apticketPaths.push_back(optarg); @@ -178,13 +187,27 @@ int main_r(int argc, const char * argv[]) { case '3': // long option: "use-pwndfu"; flags |= FLAG_IS_PWN_DFU; break; - case '4': // long option: "just-boot"; - bootargs = (optarg) ? optarg : ""; - break; - case '5': // long option: "no-ibss"; + case '4': // long option: "no-ibss"; flags |= FLAG_NO_IBSS; break; - break; + case '5': // long option: "rdsk"; + flags |= FLAG_RESTORE_RAMDISK; + ramdiskPath = optarg; + break; + case '6': // long option: "rkrn"; + flags |= FLAG_RESTORE_KERNEL; + kernelPath = optarg; + break; + case '7': // long option: "set-nonce"; + flags |= FLAG_SET_NONCE; + custom_nonce = (optarg) ? optarg : NULL; + if(custom_nonce != NULL) { + uint64_t gen; + retassure(strlen(custom_nonce) == 16 || strlen(custom_nonce) == 18,"Incorrect nonce length!\n"); + sscanf(custom_nonce, "0x%16llx",&gen); + retassure(gen, "failed to parse generator. Make sure it is in format 0x%16llx"); + } + break; #endif case 'e': // long option: "exit-recovery"; can be called as short option exitRecovery = true; @@ -220,14 +243,22 @@ int main_r(int argc, const char * argv[]) { return -5; } - futurerestore client(flags & FLAG_UPDATE, flags & FLAG_IS_PWN_DFU, flags & FLAG_NO_IBSS, flags & FLAG_NO_RESTORE_FR); + futurerestore client(flags & FLAG_UPDATE, flags & FLAG_IS_PWN_DFU, flags & FLAG_NO_IBSS, flags & FLAG_RESTORE_RAMDISK, flags & FLAG_RESTORE_KERNEL, flags & FLAG_SET_NONCE, flags & FLAG_NO_RESTORE_FR); retassure(client.init(),"can't init, no device found\n"); printf("futurerestore init done\n"); retassure(!bootargs || (flags & FLAG_IS_PWN_DFU),"--just-boot requires --use-pwndfu\n"); if(flags & FLAG_NO_IBSS) retassure((flags & FLAG_IS_PWN_DFU),"--no-ibss requires --use-pwndfu\n"); - + if(flags & FLAG_RESTORE_RAMDISK) + retassure((flags & FLAG_IS_PWN_DFU),"--rdsk requires --use-pwndfu\n"); + if(flags & FLAG_RESTORE_KERNEL) + retassure((flags & FLAG_IS_PWN_DFU),"--rkrn requires --use-pwndfu\n"); + if(flags & FLAG_SET_NONCE) + retassure((flags & FLAG_IS_PWN_DFU),"--set-nonce requires --use-pwndfu\n"); + if(flags & FLAG_RESTORE_RAMDISK) + retassure((flags & FLAG_RESTORE_KERNEL),"--rdsk requires --rkrn\n"); + if (exitRecovery) { client.exitRecovery(); info("Done\n"); @@ -260,7 +291,21 @@ int main_r(int argc, const char * argv[]) { }else{ devVals.deviceModel = (char*)client.getDeviceModelNoCopy(); devVals.deviceBoard = (char*)client.getDeviceBoardNoCopy(); - + + if(flags & FLAG_SET_NONCE) { + client.setNonce(custom_nonce); + } + + if(flags & FLAG_RESTORE_RAMDISK) { + client.setRamdiskPath(ramdiskPath); + client.loadRamdisk(ramdiskPath); + } + + if(flags & FLAG_RESTORE_KERNEL) { + client.setKernelPath(kernelPath); + client.loadKernel(kernelPath); + } + if (flags & FLAG_LATEST_SEP){ info("user specified to use latest signed SEP\n"); client.loadLatestSep(); @@ -316,10 +361,7 @@ int main_r(int argc, const char * argv[]) { } try { - if (bootargs) - client.doJustBoot(ipsw,bootargs); - else - client.doRestore(ipsw); + client.doRestore(ipsw); printf("Done: restoring succeeded!\n"); } catch (tihmstar::exception &e) { e.dump();