diff --git a/futurerestore/futurerestore.cpp b/futurerestore/futurerestore.cpp index bd79efc2..5aed6080 100644 --- a/futurerestore/futurerestore.cpp +++ b/futurerestore/futurerestore.cpp @@ -21,10 +21,20 @@ #include "ipsw.h" #include "locking.h" #include "restore.h" +#include "tsschecker.h" #define NONCESIZE 20 #define USEC_PER_SEC 1000000 +#define TMP_PATH "/tmp" +#define FUTURERESTORE_TMP_PATH TMP_PATH"/futurerestore" + +#define BASEBAND_TMP_PATH FUTURERESTORE_TMP_PATH"/baseband.bbfw" +#define BASEBAND_MANIFEST_TMP_PATH FUTURERESTORE_TMP_PATH"/basebandManifest.plist" +#define SEP_TMP_PATH FUTURERESTORE_TMP_PATH"/sep.im4p" +#define SEP_MANIFEST_TMP_PATH FUTURERESTORE_TMP_PATH"/sepManifest.plist" + + #define reterror(code,msg ...) error(msg),throw int(code) #define safeFree(buf) if (buf) free(buf), buf = NULL #define safePlistFree(buf) if (buf) plist_free(buf), buf = NULL @@ -32,9 +42,12 @@ futurerestore::futurerestore(){ _client = idevicerestore_client_new(); if (_client == NULL) throw std::string("could not create idevicerestore client\n"); - _didInit = false; - _apticket = NULL; - _im4m = NULL; + + struct stat st{0}; + if (stat(FUTURERESTORE_TMP_PATH, &st) == -1) mkdir(FUTURERESTORE_TMP_PATH, 0755); + + //tsschecker nocache + nocache = 1; } bool futurerestore::init(){ @@ -441,11 +454,102 @@ error: futurerestore::~futurerestore(){ idevicerestore_client_free(_client); safeFree(_im4m); + safeFree(_firmwareJson); + safeFree(_firmwareTokens); + safeFree(__latestManifest); + safeFree(__latestFirmwareUrl); safePlistFree(_apticket); } +void futurerestore::loadFirmwareTokens(){ + if (_firmwareTokens){ + if (!_firmwareJson) _firmwareJson = getFirmwareJson(); + if (!_firmwareJson) reterror(-6,"[TSSC] could not get firmware.json\n"); + int cnt = parseTokens(_firmwareJson, &_firmwareTokens); + if (cnt < 1) reterror(-2,"[TSSC] parsing %s.json failed\n",(0) ? "ota" : "firmware"); + } +} + +const char *futurerestore::getConnectedDeviceModel(){ + if (!_client->device->hardware_model){ + + int mode = getDeviceMode(true); + if (mode != MODE_NORMAL && mode != MODE_RECOVERY) + reterror(-20, "unexpected device mode=%d\n",mode); + + if (check_hardware_model(_client) == NULL || _client->device == NULL) + reterror(-2,"ERROR: Unable to discover device model\n"); + } + + return _client->device->hardware_model; +} + +char *futurerestore::getLatestManifest(){ + if (!__latestManifest){ + loadFirmwareTokens(); + + const char *device = getConnectedDeviceModel(); + t_iosVersion versVals; + memset(&versVals, 0, sizeof(versVals)); + + int versionCnt = 0; + int i = 0; + char **versions = getListOfiOSForDevice(_firmwareJson, _firmwareTokens, device, 0, &versionCnt); + if (!versionCnt) reterror(-8, "[TSSC] failed finding latest iOS\n"); + char *bpos = NULL; + while((bpos = strstr(versVals.version = strdup(versions[i++]),"[B]")) != 0){ + free((char*)versVals.version); + if (--versionCnt == 0) reterror(-9, "[TSSC] automatic iOS selection couldn't find non-beta iOS\n"); + } + info("[TSSC] selecting latest iOS: %s\n",versVals.version); + if (bpos) *bpos= '\0'; + if (versions) free(versions[versionCnt-1]),free(versions); + + __latestFirmwareUrl = getFirmwareUrl(device, versVals, _firmwareJson, _firmwareTokens); + if (!__latestFirmwareUrl) reterror(-21, "could not find url of latest firmware\n"); + __latestManifest = getBuildManifest(__latestFirmwareUrl, device, versVals.version, 0); + if (!__latestManifest) reterror(-22, "could not get buildmanifest of latest firmware\n"); + free((char*)versVals.version); + } + + return __latestManifest; +} + +char *futurerestore::getLatestFirmwareUrl(){ + return getLatestManifest(),__latestFirmwareUrl; +} + + +void futurerestore::loadLatestBaseband(){ + char * manifeststr = getLatestManifest(); + char *pathStr = getPathOfElementInManifest("BasebandFirmware", manifeststr); + if (!downloadPartialzip(getLatestFirmwareUrl(), pathStr, _basebandPath = BASEBAND_TMP_PATH)) + reterror(-32, "could not download baseband\n"); + saveStringToFile(manifeststr, _basebandManifestPath = BASEBAND_MANIFEST_TMP_PATH); +} + +void futurerestore::loadLatestSep(){ + char * manifeststr = getLatestManifest(); + char *pathStr = getPathOfElementInManifest("SEP", manifeststr); + if (!downloadPartialzip(getLatestFirmwareUrl(), pathStr, _sepPath = SEP_TMP_PATH)) + reterror(-33, "could not download SEP\n"); + saveStringToFile(manifeststr, _sepManifestPath = SEP_MANIFEST_TMP_PATH); +} + + #pragma mark static methods +inline void futurerestore::saveStringToFile(const char *str, const char *path){ + FILE *f = fopen(path, "w"); + if (!f) reterror(-41,"can't save file at %s\n",path); + else{ + size_t len = strlen(str); + size_t wlen = fwrite(str, len, 1, f); + fclose(f); + if (len != wlen) reterror(-42, "saving file failed, wrote=%zu actual=%zu\n",wlen,len); + } +} + char *futurerestore::getNonceFromIM4M(const char* im4m){ char *ret = NULL; t_asn1Tag *mainSet = NULL; @@ -536,3 +640,22 @@ plist_t futurerestore::loadPlistFromFile(const char *path){ return ret; } +char *futurerestore::getPathOfElementInManifest(const char *element, const char *manifeststr){ + char *pathStr = NULL; + + plist_t buildmanifest; + plist_from_xml(manifeststr, (uint)strlen(manifeststr), &buildmanifest); + + if (plist_t buildidentities = plist_dict_get_item(buildmanifest, "BuildIdentities")) + if (plist_t firstIdentitie = plist_array_get_item(buildidentities, 0)) + if (plist_t manifest = plist_dict_get_item(firstIdentitie, element)) + if (plist_t info = plist_dict_get_item(manifest, "Info")) + if (plist_t path = plist_dict_get_item(info, "Path")) + if (plist_get_string_val(path, &pathStr), pathStr) + goto noerror; + reterror(-31, "could not get %s path\n",element); +noerror: + plist_free(buildmanifest); + return pathStr; +} + diff --git a/futurerestore/futurerestore.hpp b/futurerestore/futurerestore.hpp index d89a678b..237528a2 100644 --- a/futurerestore/futurerestore.hpp +++ b/futurerestore/futurerestore.hpp @@ -12,19 +12,26 @@ #include "config.h" #include #include "idevicerestore.h" +#include "jsmn.h" using namespace std; class futurerestore { struct idevicerestore_client_t* _client; - bool _didInit; - plist_t _apticket; - char *_im4m; + bool _didInit = false; + plist_t _apticket = NULL; + char *_im4m = NULL; + + char *_firmwareJson = NULL; + jsmntok_t *_firmwareTokens = NULL;; + char *__latestManifest = NULL; + char *__latestFirmwareUrl = NULL; + + const char *_sepManifestPath = NULL; + const char *_basebandManifestPath = NULL; + const char *_sepPath = NULL; + const char *_basebandPath = NULL; - const char *_sepManifestPath; - const char *_basebandManifestPath; - const char *_sepPath; - const char *_basebandPath; public: futurerestore(); @@ -40,12 +47,25 @@ public: bool nonceMatchesApTicket(); + void loadFirmwareTokens(); + const char *getConnectedDeviceModel(); + char *getLatestManifest(); + char *getLatestFirmwareUrl(); + void loadLatestBaseband(); + void loadLatestSep(); void setSepManifestPath(const char *sepManifestPath){_sepManifestPath = sepManifestPath;}; void setBasebandManifestPath(const char *basebandManifestPath){_basebandManifestPath = basebandManifestPath;}; void setSepPath(const char *sepPath){_sepPath = sepPath;}; void setBasebandPath(const char *basebandPath){_basebandPath = basebandPath;}; + + const char *sepManifestPath(){return _sepManifestPath;}; + const char *basebandManifestPath(){return _basebandManifestPath;}; + const char *sepPath(){return _sepPath;}; + const char *basebandPath(){return _basebandPath;}; + + int doRestore(const char *ipsw, bool noerase); ~futurerestore(); @@ -53,6 +73,8 @@ public: static char *getNonceFromIM4M(const char* im4m); static char *getNonceFromAPTicket(const char* apticketPath); static plist_t loadPlistFromFile(const char *path); + static void saveStringToFile(const char *str, const char *path); + static char *getPathOfElementInManifest(const char *element, const char *manifeststr); }; diff --git a/futurerestore/main.cpp b/futurerestore/main.cpp index d41a2c34..10305c19 100644 --- a/futurerestore/main.cpp +++ b/futurerestore/main.cpp @@ -16,19 +16,23 @@ #define safePlistFree(buf) if (buf) plist_free(buf), buf = NULL static struct option longopts[] = { - { "apticket", required_argument, NULL, 't' }, - { "baseband", required_argument, NULL, 'b' }, - { "baseband-plist", required_argument, NULL, 'p' }, - { "sep", required_argument, NULL, 's' }, - { "sep-manifest", required_argument, NULL, 'm' }, - { "wait", no_argument, NULL, 'w' }, - { "update", no_argument, NULL, 'u' }, - { "debug", no_argument, NULL, 'd' }, + { "apticket", required_argument, NULL, 't' }, + { "baseband", required_argument, NULL, 'b' }, + { "baseband-plist", required_argument, NULL, 'p' }, + { "sep", required_argument, NULL, 's' }, + { "sep-manifest", required_argument, NULL, 'm' }, + { "wait", no_argument, NULL, 'w' }, + { "update", no_argument, NULL, 'u' }, + { "debug", no_argument, NULL, 'd' }, + { "latest-sep", no_argument, NULL, '0' }, + { "latest-baseband", no_argument, NULL, '1' }, { NULL, 0, NULL, 0 } }; -#define FLAG_WAIT 1 << 0 -#define FLAG_UPDATE 1 << 1 +#define FLAG_WAIT 1 << 0 +#define FLAG_UPDATE 1 << 1 +#define FLAG_LATEST_SEP 1 << 2 +#define FLAG_LATEST_BASEBAND 1 << 3 void cmd_help(){ printf("Usage: futurerestore [OPTIONS] IPSW\n"); @@ -75,7 +79,7 @@ int main(int argc, const char * argv[]) { return -1; } - while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:wud", longopts, &optindex)) > 0) { + while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:wud01", longopts, &optindex)) > 0) { switch (opt) { case 't': // long option: "apticket"; can be called as short option apticketPath = optarg; @@ -98,6 +102,12 @@ int main(int argc, const char * argv[]) { case 'u': // long option: "update"; can be called as short option flags |= FLAG_UPDATE; break; + case '0': // long option: "latest-sep"; + flags |= FLAG_LATEST_SEP; + break; + case '1': // long option: "latest-baseband"; + flags |= FLAG_LATEST_BASEBAND; + break; case 'd': // long option: "debug"; can be called as short option idevicerestore_debug = 1; break; @@ -122,7 +132,9 @@ int main(int argc, const char * argv[]) { client.putDeviceIntoRecovery(); client.waitForNonce(); } - if (!(apticketPath && basebandPath && basebandManifestPath && sepPath && sepManifestPath && ipsw)) { + if (!(apticketPath && ipsw) + && ((basebandPath && basebandManifestPath) || (flags & FLAG_LATEST_BASEBAND)) + && ((sepPath && sepManifestPath) || (flags & FLAG_LATEST_SEP)) ) { if (!(flags & FLAG_WAIT) || ipsw){ error("missing argument\n"); cmd_help(); @@ -134,22 +146,28 @@ int main(int argc, const char * argv[]) { } + if (flags & FLAG_LATEST_SEP) client.loadLatestSep(); + else{ + client.setSepPath(sepPath); + client.setSepManifestPath(sepManifestPath); + } + if (flags & FLAG_LATEST_BASEBAND) client.loadLatestBaseband(); + else{ + client.setBasebandPath(basebandPath); + client.setBasebandManifestPath(basebandManifestPath); + } + + versVals.basebandMode = kBasebandModeWithoutBaseband; - if (!(isSepManifestSigned = isManifestSignedForDevice(sepManifestPath, NULL, devVals, versVals))){ + if (!(isSepManifestSigned = isManifestSignedForDevice(client.sepManifestPath(), NULL, devVals, versVals))){ reterror(-3,"sep firmware isn't signed\n"); } versVals.basebandMode = kBasebandModeOnlyBaseband; - if (!(isBasebandSigned = isManifestSignedForDevice(basebandManifestPath, NULL, devVals, versVals))){ + if (!(isBasebandSigned = isManifestSignedForDevice(client.basebandManifestPath(), NULL, devVals, versVals))){ reterror(-3,"baseband firmware isn't signed\n"); } - client.setSepPath(sepPath); - client.setSepManifestPath(sepManifestPath); - client.setBasebandPath(basebandPath); - client.setBasebandManifestPath(basebandManifestPath); - - client.putDeviceIntoRecovery(); try {