diff --git a/.gitmodules b/.gitmodules index 0c4618dd..1ced6f4b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,8 @@ [submodule "external/idevicerestore"] path = external/idevicerestore url = https://github.com/futurerestore/idevicerestore.git - branch = test + branch = main [submodule "external/tsschecker"] path = external/tsschecker url = https://github.com/1Conan/tsschecker.git + branch = master diff --git a/README.md b/README.md index 0261347e..f1efcc4f 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,8 @@ Usage: `futurerestore [OPTIONS] iPSW` | ` -d ` | ` --debug ` | Show all code, use to save a log for debug testing | | ` -e ` | ` --exit-recovery ` | Exit recovery mode and quit | | ` -c ` | ` --custom-latest VERSION ` | Specify custom latest version to use for SEP, Baseband and other FirmwareUpdater components | +| ` -g ` | ` --custom-latest-buildid BUILDID ` | Specify custom latest buildid to use for SEP, Baseband and other FirmwareUpdater components | +| ` -i ` | ` --custom-latest-beta ` | Get custom url from list of beta firmwares | | | ` --use-pwndfu ` | Restoring devices with Odysseus method. Device needs to be in pwned DFU mode already | | | ` --no-ibss ` | Restoring devices with Odysseus method. For checkm8/iPwnder32 specifically, bootrom needs to be patched already with unless iPwnder. | | | ` --rdsk PATH ` | Set custom restore ramdisk for entering restoremode(requires use-pwndfu) | diff --git a/external/idevicerestore b/external/idevicerestore index 6910da2f..44c13e41 160000 --- a/external/idevicerestore +++ b/external/idevicerestore @@ -1 +1 @@ -Subproject commit 6910da2f8d7c4667e89afdacc700006e89c589bd +Subproject commit 44c13e418806e8cb5b666486bb0de6052e5cfb3d diff --git a/external/tsschecker b/external/tsschecker index 7446832d..13745170 160000 --- a/external/tsschecker +++ b/external/tsschecker @@ -1 +1 @@ -Subproject commit 7446832da266b3dbd04e7850bf336cf2d4b1c641 +Subproject commit 13745170f46651b87a2215dbc4d70a2676d4c8af diff --git a/futurerestore/futurerestore.cpp b/futurerestore/futurerestore.cpp index 756318b5..2ba9b4f5 100644 --- a/futurerestore/futurerestore.cpp +++ b/futurerestore/futurerestore.cpp @@ -38,33 +38,57 @@ extern "C" { #include #define safe_mkdir(path, mode) mkdir(path) #else - -#include - +void safe_mkdir(const char *path, int mode) { + int newID = 1000; #ifdef __APPLE__ -#define NEW_ID 501 + newID = 501; #else -#define NEW_ID 1000 + std::ifstream osReleaseStream(std::string("/etc/os-release")); + std::string osRelease; + if(osReleaseStream.good()) { + osReleaseStream.seekg(std::ifstream::end); + osRelease.reserve(osReleaseStream.tellg()); + osReleaseStream.seekg(std::ifstream::beg); + osRelease.assign((std::istreambuf_iterator(osReleaseStream)), std::istreambuf_iterator()); + if ((osReleaseStream.rdstate() & std::ifstream::goodbit) == 0) { + int pos = osRelease.find(std::string("\nID=")); + if(pos != std::string::npos) { + osRelease.erase(0, pos + 4); + pos = osRelease.find('\n'); + osRelease.erase(pos, osRelease.length()); + if(std::equal(osRelease.begin(), osRelease.end(), std::string("ubuntu").end())) { + if (getuid() == 999) { + newID = 999; + } + } + } + } + } #endif -#define safe_mkdir(path, mode) \ -do { \ - int id = getuid(); \ - setuid(NEW_ID); \ - setgid(NEW_ID); \ - seteuid(NEW_ID); \ - setegid(NEW_ID); \ - mkdir(path, mode); \ - setuid(id); \ - setgid(id); \ - seteuid(id); \ - setegid(id); \ -} while(false) + int id = (int)getuid(); + int id1 = (int)getgid(); + int id2 = (int)geteuid(); + int id3 = (int)getegid(); + if(newID > -1) { + setuid(newID); + setgid(newID); + seteuid(newID); + setegid(newID); + } + mkdir(path, mode); + if(newID > -1) { + setuid(id); + setgid(id1); + seteuid(id2); + setegid(id3); + } +} #endif #define USEC_PER_SEC 1000000 #ifdef WIN32 -std::string futurerestoreTempPath(download"); +std::string futurerestoreTempPath("download"); #else std::string tempPath("/tmp"); std::string futurerestoreTempPath(tempPath + "/futurerestore"); @@ -115,7 +139,10 @@ futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu, bool noIBSS, b nocache = 1; //tsschecker nocache _foundnonce = -1; _useCustomLatest = false; + _useCustomLatestBuildID = false; + _useCustomLatestBeta = false; _customLatest = std::string(""); + _customLatestBuildID = std::string(""); } bool futurerestore::init() { @@ -376,7 +403,8 @@ void futurerestore::loadAPTickets(const vector &apticketPaths) { int blen = 0; int readsize = 16384; //0x4000 int bufsize = readsize; - char *bin = (char *) malloc(bufsize); + std::allocator alloc; + char *bin = (char *)alloc.allocate(bufsize); char *p = bin; do { int bytes_read = gzread(zf, p, readsize); @@ -521,13 +549,14 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, std::string bootarg ibss_name.append(img3_end); ibec_name.append(img3_end); } + std::allocator alloc; if (!_noCache) { ibss = fopen(ibss_name.c_str(), "rb"); if (ibss) { fseek(ibss, 0, SEEK_END); iBSS.second = ftell(ibss); fseek(ibss, 0, SEEK_SET); - retassure(iBSS.first = (char *) malloc(iBSS.second), "failed to calloc memory for Rose\n"); + retassure(iBSS.first = (char *)alloc.allocate(iBSS.second), "failed to allocate memory for Rose\n"); size_t freadRet = 0; retassure((freadRet = fread((char *) iBSS.first, 1, iBSS.second, ibss)) == iBSS.second, "failed to load iBSS. size=%zu but fread returned %zu\n", iBSS.second, freadRet); @@ -539,7 +568,7 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, std::string bootarg fseek(ibec, 0, SEEK_END); iBEC.second = ftell(ibec); fseek(ibec, 0, SEEK_SET); - retassure(iBEC.first = (char *) malloc(iBEC.second), "failed to calloc memory for Rose\n"); + retassure(iBEC.first = (char *)alloc.allocate(iBEC.second), "failed to allocate memory for Rose\n"); size_t freadRet = 0; retassure((freadRet = fread((char *) iBEC.first, 1, iBEC.second, ibec)) == iBEC.second, "failed to load iBEC. size=%zu but fread returned %zu\n", iBEC.second, freadRet); @@ -795,7 +824,7 @@ void futurerestore::enterPwnRecovery(plist_t build_identity, std::string bootarg "failed to write generator to nvram"); retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram"); uint64_t gen = std::stoul(generator, nullptr, 16); - auto *nonce = (uint8_t *) calloc(_client->nonce_size, sizeof(uint8_t)); + auto *nonce = (uint8_t *)alloc.allocate(_client->nonce_size); if (_client->nonce_size == 20) { SHA1((unsigned char *) &gen, 8, nonce); } else if (_client->nonce_size == 32) { @@ -1378,6 +1407,12 @@ void futurerestore::loadFirmwareTokens() { long cnt = parseTokens(_firmwareJson, &_firmwareTokens); retassure(cnt > 0, "[TSSC] parsing %s.json failed\n", (0) ? "ota" : "firmware"); } + if(!_betaFirmwareTokens) { + if (!_betaFirmwareJson) _betaFirmwareJson = getBetaFirmwareJson(getDeviceModelNoCopy()); + retassure(_betaFirmwareJson, "[TSSC] could not get betas json\n"); + long cnt = parseTokens(_betaFirmwareJson, &_betaFirmwareTokens); + retassure(cnt > 0, "[TSSC] parsing %s.json failed\n", (0) ? "ota" : "firmware"); + } } const char *futurerestore::getDeviceModelNoCopy() { @@ -1441,7 +1476,12 @@ char *futurerestore::getLatestManifest() { int versionCnt = 0; int i = 0; - char **versions = getListOfiOSForDevice(_firmwareTokens, device, 0, &versionCnt); + char **versions = nullptr; + if(_useCustomLatestBuildID) { + versions = getListOfiOSForDevice2(_firmwareTokens, device, 0, &versionCnt, 1); + } else { + versions = getListOfiOSForDevice(_firmwareTokens, device, 0, &versionCnt); + } retassure(versionCnt, "[TSSC] failed finding latest firmware version\n"); char *bpos = nullptr; while ((bpos = strstr((char *) (versVals.version = strdup(versions[i++])), "[B]")) != nullptr) { @@ -1464,18 +1504,50 @@ char *futurerestore::getLatestManifest() { if(i != -1) { reterror("[TSSC] failed to find custom version for device!\n"); } + } else if(!_useCustomLatestBeta && _useCustomLatestBuildID) { + i = 0; + while (i < versionCnt) { + versVals.buildID = strdup(versions[i++]); + std::string version(versVals.buildID); + if (!std::equal(_customLatestBuildID.begin(), _customLatestBuildID.end(), version.begin())) { + free((char *) versVals.buildID); + } else { + i = -1; + break; + } + } + if(i != -1) { + reterror("[TSSC] failed to find custom buildid for device!\n"); + } + } + if(!_useCustomLatestBeta) { + if(_useCustomLatestBuildID) { + info("[TSSC] selecting latest firmware version: %s\n", versVals.buildID); + } else { + info("[TSSC] selecting latest firmware version: %s\n", versVals.version); + } } - info("[TSSC] selecting latest firmware version: %s\n", versVals.version); if (bpos) *bpos = '\0'; if (versions) free(versions[versionCnt - 1]), free(versions); ptr_smart autofree( versVals.version); //make sure it gets freed after function finishes execution by either reaching end or throwing exception + ptr_smart autofree2( + versVals.buildID); //make sure it gets freed after function finishes execution by either reaching end or throwing exception - _latestFirmwareUrl = getFirmwareUrl(device, &versVals, _firmwareTokens); + if(_useCustomLatestBeta) { + info("[TSSC] selecting latest firmware version: %s\n", _customLatestBuildID.c_str()); + _latestFirmwareUrl = getBetaURLForDevice(_betaFirmwareTokens, _customLatestBuildID.c_str()); + _latestManifest = getBuildManifest(_latestFirmwareUrl, device, nullptr, _customLatestBuildID.c_str(), 0); + } else { + _latestFirmwareUrl = getFirmwareUrl(device, &versVals, _firmwareTokens); + if(_useCustomLatestBuildID) { + _latestManifest = getBuildManifest(_latestFirmwareUrl, device, nullptr, versVals.buildID, 0); + } else { + _latestManifest = getBuildManifest(_latestFirmwareUrl, device, versVals.version, versVals.buildID, 0); + } + } retassure(_latestFirmwareUrl, "could not find url of latest firmware version\n"); - - _latestManifest = getBuildManifest(_latestFirmwareUrl, device, versVals.version, versVals.buildID, 0); retassure(_latestManifest, "could not get buildmanifest of latest firmware version\n"); } @@ -1626,7 +1698,7 @@ void futurerestore::downloadLatestBaseband() { info("downloading Baseband\n\n"); retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, basebandTempPath.c_str()), "could not download baseband\n"); - saveStringToFile(manifeststr, basebandManifestTempPath.c_str()); + saveStringToFile(manifeststr, basebandManifestTempPath); setBasebandPath(basebandTempPath); setBasebandManifestPath(basebandManifestTempPath); loadBaseband(this->_basebandPath); @@ -1634,11 +1706,11 @@ void futurerestore::downloadLatestBaseband() { } void futurerestore::downloadLatestSep() { - char *manifeststr = getLatestManifest(); - char *pathStr = getPathOfElementInManifest("SEP", manifeststr, getDeviceBoardNoCopy(), 0); + std::string manifestString = getLatestManifest(); + std::string pathString = getPathOfElementInManifest("SEP", manifestString.c_str(), getDeviceBoardNoCopy(), 0); info("downloading SEP\n\n"); - retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, sepTempPath.c_str()), "could not download SEP\n"); - saveStringToFile(manifeststr, sepManifestTempPath.c_str()); + retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathString.c_str(), sepTempPath.c_str()), "could not download SEP\n"); + saveStringToFile(manifestString, sepManifestTempPath); setSepPath(sepTempPath); setSepManifestPath(sepManifestTempPath); loadSep(this->_sepPath); @@ -1663,8 +1735,9 @@ void futurerestore::loadRose(std::string rosePath) { roseFileStream.seekg(0, std::ios_base::end); _client->rosefwdatasize = roseFileStream.tellg(); roseFileStream.seekg(0, std::ios_base::beg); - retassure(_client->rosefwdata = (char *) calloc(_client->rosefwdatasize, 1), - "%s: failed to calloc memory for %s\n", __func__, rosePath.c_str()); + std::allocator alloc; + retassure(_client->rosefwdata = (char *)alloc.allocate(_client->rosefwdatasize), + "%s: failed to allocate memory for %s\n", __func__, rosePath.c_str()); roseFileStream.read((char *) _client->rosefwdata, (std::streamsize) _client->rosefwdatasize); retassure(*(uint64_t *) (_client->rosefwdata) != 0, @@ -1678,8 +1751,9 @@ void futurerestore::loadSE(std::string sePath) { seFileStream.seekg(0, std::ios_base::end); _client->sefwdatasize = seFileStream.tellg(); seFileStream.seekg(0, std::ios_base::beg); - retassure(_client->sefwdata = (char *) calloc(_client->sefwdatasize, 1), - "%s: failed to calloc memory for %s\n", __func__, sePath.c_str()); + std::allocator alloc; + retassure(_client->sefwdata = (char *)alloc.allocate(_client->sefwdatasize), + "%s: failed to allocate memory for %s\n", __func__, sePath.c_str()); seFileStream.read((char *) _client->sefwdata, (std::streamsize) _client->sefwdatasize); retassure(*(uint64_t *) (_client->sefwdata) != 0, @@ -1695,8 +1769,9 @@ void futurerestore::loadSavage(std::array savagePaths) { savageFileStream.seekg(0, std::ios_base::end); _client->savagefwdatasize[index] = savageFileStream.tellg(); savageFileStream.seekg(0, std::ios_base::beg); - retassure(_client->savagefwdata[index] = (char *) calloc(_client->savagefwdatasize[index], 1), - "%s: failed to calloc memory for %s\n", __func__, savagePath.c_str()); + std::allocator alloc; + retassure(_client->savagefwdata[index] = (char *)alloc.allocate(_client->savagefwdatasize[index]), + "%s: failed to allocate memory for %s\n", __func__, savagePath.c_str()); savageFileStream.read((char *) _client->savagefwdata[index], (std::streamsize) _client->savagefwdatasize[index]); retassure(*(uint64_t *) (_client->savagefwdata[index]) != 0, @@ -1715,8 +1790,9 @@ void futurerestore::loadVeridian(std::string veridianDGMPath, std::string veridi veridianDGMFileStream.seekg(0, std::ios_base::end); _client->veridiandgmfwdatasize = veridianDGMFileStream.tellg(); veridianDGMFileStream.seekg(0, std::ios_base::beg); - retassure(_client->veridiandgmfwdata = (char *) calloc(_client->veridiandgmfwdatasize, 1), - "%s: failed to calloc memory for %s\n", __func__, veridianDGMPath.c_str()); + std::allocator alloc; + retassure(_client->veridiandgmfwdata = (char *)alloc.allocate(_client->veridiandgmfwdatasize), + "%s: failed to allocate memory for %s\n", __func__, veridianDGMPath.c_str()); veridianDGMFileStream.read((char *) _client->veridiandgmfwdata, (std::streamsize) _client->veridiandgmfwdatasize); retassure(*(uint64_t *) (_client->veridiandgmfwdata) != 0, @@ -1725,8 +1801,8 @@ void futurerestore::loadVeridian(std::string veridianDGMPath, std::string veridi veridianFWMFileStream.seekg(0, std::ios_base::end); _client->veridianfwmfwdatasize = veridianFWMFileStream.tellg(); veridianFWMFileStream.seekg(0, std::ios_base::beg); - retassure(_client->veridianfwmfwdata = (char *) calloc(_client->veridianfwmfwdatasize, 1), - "%s: failed to calloc memory for %s\n", __func__, veridianFWMPath.c_str()); + retassure(_client->veridianfwmfwdata = (char *)alloc.allocate(_client->veridianfwmfwdatasize), + "%s: failed to allocate memory for %s\n", __func__, veridianFWMPath.c_str()); veridianFWMFileStream.read((char *) _client->veridianfwmfwdata, (std::streamsize) _client->veridianfwmfwdatasize); retassure(*(uint64_t *) (_client->veridianfwmfwdata) != 0, @@ -1740,8 +1816,9 @@ void futurerestore::loadRamdisk(std::string ramdiskPath) { ramdiskFileStream.seekg(0, std::ios_base::end); _client->ramdiskdatasize = ramdiskFileStream.tellg(); ramdiskFileStream.seekg(0, std::ios_base::beg); - retassure(_client->ramdiskdata = (char *) calloc(_client->ramdiskdatasize, 1), - "%s: failed to calloc memory for %s\n", __func__, ramdiskPath.c_str()); + std::allocator alloc; + retassure(_client->ramdiskdata = (char *)alloc.allocate(_client->ramdiskdatasize), + "%s: failed to allocate memory for %s\n", __func__, ramdiskPath.c_str()); ramdiskFileStream.read((char *) _client->ramdiskdata, (std::streamsize) _client->ramdiskdatasize); retassure(*(uint64_t *) (_client->ramdiskdata) != 0, @@ -1755,8 +1832,9 @@ void futurerestore::loadKernel(std::string kernelPath) { kernelFileStream.seekg(0, std::ios_base::end); _client->kerneldatasize = kernelFileStream.tellg(); kernelFileStream.seekg(0, std::ios_base::beg); - retassure(_client->kerneldata = (char *) calloc(_client->kerneldatasize, 1), - "%s: failed to calloc memory for %s\n", __func__, kernelPath.c_str()); + std::allocator alloc; + retassure(_client->kerneldata = (char *)alloc.allocate(_client->kerneldatasize), + "%s: failed to allocate memory for %s\n", __func__, kernelPath.c_str()); kernelFileStream.read((char *) _client->kerneldata, (std::streamsize) _client->kerneldatasize); retassure(*(uint64_t *) (_client->kerneldata) != 0, @@ -1770,8 +1848,9 @@ void futurerestore::loadSep(std::string sepPath) { sepFileStream.seekg(0, std::ios_base::end); _client->sepfwdatasize = sepFileStream.tellg(); sepFileStream.seekg(0, std::ios_base::beg); - retassure(_client->sepfwdata = (char *) calloc(_client->sepfwdatasize, 1), - "%s: failed to calloc memory for %s\n", __func__, sepPath.c_str()); + std::allocator alloc; + retassure(_client->sepfwdata = (char *)alloc.allocate(_client->sepfwdatasize), + "%s: failed to allocate memory for %s\n", __func__, sepPath.c_str()); sepFileStream.read((char *) _client->sepfwdata, (std::streamsize) _client->sepfwdatasize); retassure(*(uint64_t *) (_client->sepfwdata) != 0, @@ -1784,8 +1863,9 @@ void futurerestore::loadBaseband(std::string basebandPath) { retassure(basebandFileStream.good(), "%s: failed init file stream for %s!\n", __func__, basebandPath.c_str()); basebandFileStream.seekg(0, std::ios_base::beg); uint64_t *basebandFront = nullptr; - retassure(basebandFront = (uint64_t *) calloc(1, sizeof(uint64_t)), - "%s: failed to calloc memory for %s\n", __func__, basebandPath.c_str()); + std::allocator alloc; + retassure(basebandFront = (uint64_t *)alloc.allocate(sizeof(uint64_t)), + "%s: failed to allocate memory for %s\n", __func__, basebandPath.c_str()); basebandFileStream.read((char *)basebandFront, (std::streamsize)sizeof(uint64_t)); retassure(*(uint64_t *) (basebandFront) != 0, "%s: failed to load Baseband for %s!\n", __func__, basebandPath.c_str()); @@ -1793,13 +1873,15 @@ void futurerestore::loadBaseband(std::string basebandPath) { #pragma mark static methods -inline void futurerestore::saveStringToFile(const char *str, const char *path) { - FILE *f = nullptr; - retassure(f = fopen(path, "w"), "can't save file at %s\n", path); - size_t len = strlen(str); - size_t wlen = fwrite(str, 1, len, f); - fclose(f); - retassure(len == wlen, "saving file failed, wrote=%zu actual=%zu\n", wlen, len); +inline void futurerestore::saveStringToFile(std::string str, std::string path) { + if(str.empty() || path.empty()) { + info("%s: No data to save!", __func__); + return; + } + std::ofstream fileStream(path); + retassure(fileStream.good(), "%s: failed init file stream for %s!\n", __func__, path.c_str()); + fileStream.write(str.data(), str.length()); + retassure((fileStream.rdstate() & std::ofstream::goodbit) == 0, "Can't save file at %s\n", path.c_str()); } std::pair futurerestore::getNonceFromSCAB(const char *scab, size_t scabSize) { diff --git a/futurerestore/futurerestore.hpp b/futurerestore/futurerestore.hpp index 9e7cd515..c577ef9e 100644 --- a/futurerestore/futurerestore.hpp +++ b/futurerestore/futurerestore.hpp @@ -65,11 +65,16 @@ class futurerestore { bool _noRestore = false; char *_firmwareJson = nullptr; + char *_betaFirmwareJson = nullptr; jssytok_t *_firmwareTokens = nullptr;; + jssytok_t *_betaFirmwareTokens = nullptr; char *_latestManifest = nullptr; char *_latestFirmwareUrl = nullptr; bool _useCustomLatest = false; + bool _useCustomLatestBuildID = false; + bool _useCustomLatestBeta = false; std::string _customLatest; + std::string _customLatestBuildID; plist_t _sepbuildmanifest = nullptr; plist_t _basebandbuildmanifest = nullptr; @@ -135,6 +140,7 @@ public: void loadBaseband(std::string basebandPath); void setCustomLatest(std::string version){_customLatest = version; _useCustomLatest = true;} + void setCustomLatestBuildID(std::string version, bool beta){_customLatestBuildID = version; _useCustomLatest = false; _useCustomLatestBuildID = true; _useCustomLatestBeta = beta;} void setSepPath(std::string sepPath) {_sepPath = sepPath;} void setSepManifestPath(std::string sepManifestPath) {_sepManifestPath = sepManifestPath;} void setRamdiskPath(std::string ramdiskPath) {_ramdiskPath = ramdiskPath;} @@ -158,7 +164,7 @@ public: static std::pair getNonceFromSCAB(const char* scab, size_t scabSize); static uint64_t getEcidFromSCAB(const char* scab, size_t scabSize); static plist_t loadPlistFromFile(const char *path); - static void saveStringToFile(const char *str, const char *path); + static void saveStringToFile(std::string str, std::string path); static char *getPathOfElementInManifest(const char *element, const char *manifeststr, const char *boardConfig, int isUpdateInstall); static bool elemExists(const char *element, const char *manifeststr, const char *boardConfig, int isUpdateInstall); static std::string getGeneratorFromSHSH2(plist_t shsh2); diff --git a/futurerestore/main.cpp b/futurerestore/main.cpp index d4cb8645..dae4aab7 100644 --- a/futurerestore/main.cpp +++ b/futurerestore/main.cpp @@ -30,87 +30,97 @@ extern "C"{ #endif static struct option longopts[] = { - { "apticket", required_argument, nullptr, 't' }, - { "baseband", required_argument, nullptr, 'b' }, - { "baseband-manifest", required_argument, nullptr, 'p' }, - { "sep", required_argument, nullptr, 's' }, - { "sep-manifest", required_argument, nullptr, 'm' }, - { "wait", no_argument, nullptr, 'w' }, - { "update", no_argument, nullptr, 'u' }, - { "debug", no_argument, nullptr, 'd' }, - { "exit-recovery", no_argument, nullptr, 'e' }, - { "custom-latest", required_argument, nullptr, 'c' }, - { "latest-sep", no_argument, nullptr, '0' }, - { "no-restore", no_argument, nullptr, 'z' }, - { "latest-baseband", no_argument, nullptr, '1' }, - { "no-baseband", no_argument, nullptr, '2' }, + { "apticket", required_argument, nullptr, 't' }, + { "baseband", required_argument, nullptr, 'b' }, + { "baseband-manifest", required_argument, nullptr, 'p' }, + { "sep", required_argument, nullptr, 's' }, + { "sep-manifest", required_argument, nullptr, 'm' }, + { "wait", no_argument, nullptr, 'w' }, + { "update", no_argument, nullptr, 'u' }, + { "debug", no_argument, nullptr, 'd' }, + { "exit-recovery", no_argument, nullptr, 'e' }, + { "custom-latest", required_argument, nullptr, 'c' }, + { "custom-latest-buildid", required_argument, nullptr, 'g' }, + { "help", no_argument, nullptr, 'h' }, + { "custom-latest-beta", no_argument, nullptr, 'i' }, + { "latest-sep", no_argument, nullptr, '0' }, + { "no-restore", no_argument, nullptr, 'z' }, + { "latest-baseband", no_argument, nullptr, '1' }, + { "no-baseband", no_argument, nullptr, '2' }, #ifdef HAVE_LIBIPATCHER - { "use-pwndfu", no_argument, nullptr, '3' }, - { "no-ibss", no_argument, nullptr, '4' }, - { "rdsk", required_argument, nullptr, '5' }, - { "rkrn", required_argument, nullptr, '6' }, - { "set-nonce", optional_argument, nullptr, '7' }, - { "serial", no_argument, nullptr, '8' }, - { "boot-args", required_argument, nullptr, '9' }, - { "no-cache", no_argument, nullptr, 'a' }, - { "skip-blob", no_argument, nullptr, 'f' }, + { "use-pwndfu", no_argument, nullptr, '3' }, + { "no-ibss", no_argument, nullptr, '4' }, + { "rdsk", required_argument, nullptr, '5' }, + { "rkrn", required_argument, nullptr, '6' }, + { "set-nonce", optional_argument, nullptr, '7' }, + { "serial", no_argument, nullptr, '8' }, + { "boot-args", required_argument, nullptr, '9' }, + { "no-cache", no_argument, nullptr, 'a' }, + { "skip-blob", no_argument, nullptr, 'f' }, #endif { nullptr, 0, nullptr, 0 } }; -#define FLAG_WAIT 1 << 0 -#define FLAG_UPDATE 1 << 1 -#define FLAG_LATEST_SEP 1 << 2 -#define FLAG_LATEST_BASEBAND 1 << 3 -#define FLAG_NO_BASEBAND 1 << 4 -#define FLAG_IS_PWN_DFU 1 << 5 -#define FLAG_NO_IBSS 1 << 6 -#define FLAG_RESTORE_RAMDISK 1 << 7 -#define FLAG_RESTORE_KERNEL 1 << 8 -#define FLAG_SET_NONCE 1 << 9 -#define FLAG_SERIAL 1 << 10 -#define FLAG_BOOT_ARGS 1 << 11 -#define FLAG_NO_CACHE 1 << 12 -#define FLAG_SKIP_BLOB 1 << 13 -#define FLAG_NO_RESTORE_FR 1 << 14 +#define FLAG_WAIT 1 << 0 +#define FLAG_UPDATE 1 << 1 +#define FLAG_LATEST_SEP 1 << 2 +#define FLAG_LATEST_BASEBAND 1 << 3 +#define FLAG_NO_BASEBAND 1 << 4 +#define FLAG_IS_PWN_DFU 1 << 5 +#define FLAG_NO_IBSS 1 << 6 +#define FLAG_RESTORE_RAMDISK 1 << 7 +#define FLAG_RESTORE_KERNEL 1 << 8 +#define FLAG_SET_NONCE 1 << 9 +#define FLAG_SERIAL 1 << 10 +#define FLAG_BOOT_ARGS 1 << 11 +#define FLAG_NO_CACHE 1 << 12 +#define FLAG_SKIP_BLOB 1 << 13 +#define FLAG_NO_RESTORE_FR 1 << 14 +#define FLAG_CUSTOM_LATEST 1 << 15 +#define FLAG_CUSTOM_LATEST_BUILDID 1 << 16 +#define FLAG_CUSTOM_LATEST_BETA 1 << 17 + void cmd_help(){ printf("Usage: futurerestore [OPTIONS] iPSW\n"); printf("Allows restoring to non-matching firmware with custom SEP+baseband\n"); printf("\nGeneral options:\n"); - printf(" -t, --apticket PATH\t\tSigning tickets used for restoring\n"); - printf(" -u, --update\t\t\tUpdate instead of erase install (requires appropriate APTicket)\n"); - printf(" \t\t\tDO NOT use this parameter, if you update from jailbroken firmware!\n"); - printf(" -w, --wait\t\t\tKeep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable)\n"); - printf(" -d, --debug\t\t\tShow all code, use to save a log for debug testing\n"); - printf(" -e, --exit-recovery\t\tExit recovery mode and quit\n"); - printf(" -z, --no-restore\t\tDo not restore and end right before NOR data is sent\n"); - printf(" -c, --custom-latest VERSION\tSpecify custom latest version to use for SEP, Baseband and other FirmwareUpdater components\n"); + printf(" -h, --help\t\t\t\tShows this usage message\n"); + printf(" -t, --apticket PATH\t\t\tSigning tickets used for restoring\n"); + printf(" -u, --update\t\t\t\tUpdate instead of erase install (requires appropriate APTicket)\n"); + printf(" \t\t\t\tDO NOT use this parameter, if you update from jailbroken firmware!\n"); + printf(" -w, --wait\t\t\t\tKeep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable)\n"); + printf(" -d, --debug\t\t\t\tShow all code, use to save a log for debug testing\n"); + printf(" -e, --exit-recovery\t\t\tExit recovery mode and quit\n"); + printf(" -z, --no-restore\t\t\tDo not restore and end right before NOR data is sent\n"); + printf(" -c, --custom-latest VERSION\t\tSpecify custom latest version to use for SEP, Baseband and other FirmwareUpdater components\n"); + printf(" -g, --custom-latest-buildid BUILDID\tSpecify custom latest buildid to use for SEP, Baseband and other FirmwareUpdater components\n"); + printf(" -i, --custom-latest-beta\t\tGet custom url from list of beta firmwares"); #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(" --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\t\tSet custom nonce from your blob then exit recovery(requires use-pwndfu)\n"); - printf(" --set-nonce=0xNONCE\tSet custom nonce then exit recovery(requires use-pwndfu)\n"); - printf(" --serial\t\t\tEnable serial during boot(requires serial cable and use-pwndfu)\n"); - printf(" --boot-args\t\tSet custom restore boot-args(PROCEED WITH CAUTION)(requires use-pwndfu)\n"); - printf(" --no-cache\t\tDisable cached patched iBSS/iBEC(requires use-pwndfu)\n"); - printf(" --skip-blob\t\tSkip SHSH blob validation(PROCEED WITH CAUTION)(requires use-pwndfu)\n"); + printf(" --use-pwndfu\t\t\tRestoring devices with Odysseus method. Device needs to be in pwned DFU mode already\n"); + printf(" --no-ibss\t\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\t\tSet custom restore ramdisk for entering restoremode(requires use-pwndfu)\n"); + printf(" --rkrn PATH\t\t\tSet custom restore kernelcache for entering restoremode(requires use-pwndfu)\n"); + printf(" --set-nonce\t\t\tSet custom nonce from your blob then exit recovery(requires use-pwndfu)\n"); + printf(" --set-nonce=0xNONCE\t\tSet custom nonce then exit recovery(requires use-pwndfu)\n"); + printf(" --serial\t\t\t\tEnable serial during boot(requires serial cable and use-pwndfu)\n"); + printf(" --boot-args\t\t\tSet custom restore boot-args(PROCEED WITH CAUTION)(requires use-pwndfu)\n"); + printf(" --no-cache\t\t\tDisable cached patched iBSS/iBEC(requires use-pwndfu)\n"); + printf(" --skip-blob\t\t\tSkip SHSH blob validation(PROCEED WITH CAUTION)(requires use-pwndfu)\n"); #endif printf("\nOptions for SEP:\n"); - printf(" --latest-sep\t\tUse latest signed SEP instead of manually specifying one\n"); - printf(" -s, --sep PATH\t\tSEP to be flashed\n"); - printf(" -m, --sep-manifest PATH\tBuildManifest for requesting SEP ticket\n"); + printf(" --latest-sep\t\t\tUse latest signed SEP instead of manually specifying one\n"); + printf(" -s, --sep PATH\t\t\tSEP to be flashed\n"); + printf(" -m, --sep-manifest PATH\t\tBuildManifest for requesting SEP ticket\n"); printf("\nOptions for baseband:\n"); - printf(" --latest-baseband\t\tUse latest signed baseband instead of manually specifying one\n"); - printf(" -b, --baseband PATH\t\tBaseband to be flashed\n"); - printf(" -p, --baseband-manifest PATH\tBuildManifest for requesting baseband ticket\n"); - printf(" --no-baseband\t\tSkip checks and don't flash baseband\n"); - printf(" \t\tOnly use this for device without a baseband (eg. iPod touch or some Wi-Fi only iPads)\n\n"); + printf(" --latest-baseband\t\t\tUse latest signed baseband instead of manually specifying one\n"); + printf(" -b, --baseband PATH\t\t\tBaseband to be flashed\n"); + printf(" -p, --baseband-manifest PATH\t\tBuildManifest for requesting baseband ticket\n"); + printf(" --no-baseband\t\t\tSkip checks and don't flash baseband\n"); + printf(" \t\t\tOnly use this for device without a baseband (eg. iPod touch or some Wi-Fi only iPads)\n\n"); } using namespace std; @@ -145,6 +155,7 @@ int main_r(int argc, const char * argv[]) { const char *sepManifestPath = nullptr; const char *bootargs = nullptr; std::string customLatest; + std::string customLatestBuildID; const char *ramdiskPath = nullptr; const char *kernelPath = nullptr; const char *custom_nonce = nullptr; @@ -159,8 +170,12 @@ int main_r(int argc, const char * argv[]) { return -1; } - while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:c:wude0z123456789af", longopts, &optindex)) > 0) { + while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:c:g:hiwude0z123456789af", longopts, &optindex)) > 0) { switch (opt) { + case 'h': // long option: "help"; can be called as short option + cmd_help(); + return 0; + break; case 't': // long option: "apticket"; can be called as short option apticketPaths.push_back(optarg); break; @@ -182,8 +197,16 @@ int main_r(int argc, const char * argv[]) { case 'u': // long option: "update"; can be called as short option flags |= FLAG_UPDATE; break; - case 'c': // long option: "custom-latest"; + case 'c': // long option: "custom-latest"; can be called as short option customLatest = (optarg) ? std::string(optarg) : std::string(""); + flags |= FLAG_CUSTOM_LATEST; + break; + case 'g': // long option: "custom-latest-buildid"; can be called as short option + customLatestBuildID = (optarg) ? std::string(optarg) : std::string(""); + flags |= FLAG_CUSTOM_LATEST_BUILDID; + break; + case 'i': // long option: "custom-latest-beta"; can be called as short option + flags |= FLAG_CUSTOM_LATEST_BETA; break; case '0': // long option: "latest-sep"; flags |= FLAG_LATEST_SEP; @@ -292,6 +315,10 @@ int main_r(int argc, const char * argv[]) { retassure((flags & FLAG_IS_PWN_DFU),"--no-cache requires --use-pwndfu\n"); if(flags & FLAG_SKIP_BLOB) retassure((flags & FLAG_IS_PWN_DFU),"--skip-blob requires --use-pwndfu\n"); + if(flags & FLAG_CUSTOM_LATEST_BETA) + retassure((flags & FLAG_CUSTOM_LATEST_BUILDID),"-i, --custom-latest-beta requires -g, --custom-latest-buildid\n"); + if(flags & FLAG_CUSTOM_LATEST_BUILDID) + retassure((flags & FLAG_CUSTOM_LATEST) == 0,"-g, --custom-latest-buildid is not compatible with -c, --custom-latest\n"); if (exitRecovery) { client.exitRecovery(); @@ -307,6 +334,9 @@ int main_r(int argc, const char * argv[]) { if(!customLatest.empty()) { client.setCustomLatest(customLatest); } + if(!customLatestBuildID.empty()) { + client.setCustomLatestBuildID(customLatestBuildID, (flags & FLAG_CUSTOM_LATEST_BETA) != 0); + } if (!( ((!apticketPaths.empty() && ipsw)