mirror of
https://github.com/tihmstar/futurerestore.git
synced 2024-12-22 17:35:29 +00:00
added option to automatically load latest sep/baseband (untested)
This commit is contained in:
parent
8c08fb0a29
commit
20851cc697
|
@ -21,10 +21,20 @@
|
||||||
#include "ipsw.h"
|
#include "ipsw.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "restore.h"
|
#include "restore.h"
|
||||||
|
#include "tsschecker.h"
|
||||||
|
|
||||||
#define NONCESIZE 20
|
#define NONCESIZE 20
|
||||||
#define USEC_PER_SEC 1000000
|
#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 reterror(code,msg ...) error(msg),throw int(code)
|
||||||
#define safeFree(buf) if (buf) free(buf), buf = NULL
|
#define safeFree(buf) if (buf) free(buf), buf = NULL
|
||||||
#define safePlistFree(buf) if (buf) plist_free(buf), buf = NULL
|
#define safePlistFree(buf) if (buf) plist_free(buf), buf = NULL
|
||||||
|
@ -32,9 +42,12 @@
|
||||||
futurerestore::futurerestore(){
|
futurerestore::futurerestore(){
|
||||||
_client = idevicerestore_client_new();
|
_client = idevicerestore_client_new();
|
||||||
if (_client == NULL) throw std::string("could not create idevicerestore client\n");
|
if (_client == NULL) throw std::string("could not create idevicerestore client\n");
|
||||||
_didInit = false;
|
|
||||||
_apticket = NULL;
|
struct stat st{0};
|
||||||
_im4m = NULL;
|
if (stat(FUTURERESTORE_TMP_PATH, &st) == -1) mkdir(FUTURERESTORE_TMP_PATH, 0755);
|
||||||
|
|
||||||
|
//tsschecker nocache
|
||||||
|
nocache = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool futurerestore::init(){
|
bool futurerestore::init(){
|
||||||
|
@ -441,11 +454,102 @@ error:
|
||||||
futurerestore::~futurerestore(){
|
futurerestore::~futurerestore(){
|
||||||
idevicerestore_client_free(_client);
|
idevicerestore_client_free(_client);
|
||||||
safeFree(_im4m);
|
safeFree(_im4m);
|
||||||
|
safeFree(_firmwareJson);
|
||||||
|
safeFree(_firmwareTokens);
|
||||||
|
safeFree(__latestManifest);
|
||||||
|
safeFree(__latestFirmwareUrl);
|
||||||
safePlistFree(_apticket);
|
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
|
#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 *futurerestore::getNonceFromIM4M(const char* im4m){
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
t_asn1Tag *mainSet = NULL;
|
t_asn1Tag *mainSet = NULL;
|
||||||
|
@ -536,3 +640,22 @@ plist_t futurerestore::loadPlistFromFile(const char *path){
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,26 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "idevicerestore.h"
|
#include "idevicerestore.h"
|
||||||
|
#include "jsmn.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class futurerestore {
|
class futurerestore {
|
||||||
struct idevicerestore_client_t* _client;
|
struct idevicerestore_client_t* _client;
|
||||||
bool _didInit;
|
bool _didInit = false;
|
||||||
plist_t _apticket;
|
plist_t _apticket = NULL;
|
||||||
char *_im4m;
|
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:
|
public:
|
||||||
futurerestore();
|
futurerestore();
|
||||||
|
@ -40,12 +47,25 @@ public:
|
||||||
|
|
||||||
bool nonceMatchesApTicket();
|
bool nonceMatchesApTicket();
|
||||||
|
|
||||||
|
void loadFirmwareTokens();
|
||||||
|
const char *getConnectedDeviceModel();
|
||||||
|
char *getLatestManifest();
|
||||||
|
char *getLatestFirmwareUrl();
|
||||||
|
void loadLatestBaseband();
|
||||||
|
void loadLatestSep();
|
||||||
|
|
||||||
void setSepManifestPath(const char *sepManifestPath){_sepManifestPath = sepManifestPath;};
|
void setSepManifestPath(const char *sepManifestPath){_sepManifestPath = sepManifestPath;};
|
||||||
void setBasebandManifestPath(const char *basebandManifestPath){_basebandManifestPath = basebandManifestPath;};
|
void setBasebandManifestPath(const char *basebandManifestPath){_basebandManifestPath = basebandManifestPath;};
|
||||||
void setSepPath(const char *sepPath){_sepPath = sepPath;};
|
void setSepPath(const char *sepPath){_sepPath = sepPath;};
|
||||||
void setBasebandPath(const char *basebandPath){_basebandPath = basebandPath;};
|
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);
|
int doRestore(const char *ipsw, bool noerase);
|
||||||
|
|
||||||
~futurerestore();
|
~futurerestore();
|
||||||
|
@ -53,6 +73,8 @@ public:
|
||||||
static char *getNonceFromIM4M(const char* im4m);
|
static char *getNonceFromIM4M(const char* im4m);
|
||||||
static char *getNonceFromAPTicket(const char* apticketPath);
|
static char *getNonceFromAPTicket(const char* apticketPath);
|
||||||
static plist_t loadPlistFromFile(const char *path);
|
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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,19 +16,23 @@
|
||||||
#define safePlistFree(buf) if (buf) plist_free(buf), buf = NULL
|
#define safePlistFree(buf) if (buf) plist_free(buf), buf = NULL
|
||||||
|
|
||||||
static struct option longopts[] = {
|
static struct option longopts[] = {
|
||||||
{ "apticket", required_argument, NULL, 't' },
|
{ "apticket", required_argument, NULL, 't' },
|
||||||
{ "baseband", required_argument, NULL, 'b' },
|
{ "baseband", required_argument, NULL, 'b' },
|
||||||
{ "baseband-plist", required_argument, NULL, 'p' },
|
{ "baseband-plist", required_argument, NULL, 'p' },
|
||||||
{ "sep", required_argument, NULL, 's' },
|
{ "sep", required_argument, NULL, 's' },
|
||||||
{ "sep-manifest", required_argument, NULL, 'm' },
|
{ "sep-manifest", required_argument, NULL, 'm' },
|
||||||
{ "wait", no_argument, NULL, 'w' },
|
{ "wait", no_argument, NULL, 'w' },
|
||||||
{ "update", no_argument, NULL, 'u' },
|
{ "update", no_argument, NULL, 'u' },
|
||||||
{ "debug", no_argument, NULL, 'd' },
|
{ "debug", no_argument, NULL, 'd' },
|
||||||
|
{ "latest-sep", no_argument, NULL, '0' },
|
||||||
|
{ "latest-baseband", no_argument, NULL, '1' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FLAG_WAIT 1 << 0
|
#define FLAG_WAIT 1 << 0
|
||||||
#define FLAG_UPDATE 1 << 1
|
#define FLAG_UPDATE 1 << 1
|
||||||
|
#define FLAG_LATEST_SEP 1 << 2
|
||||||
|
#define FLAG_LATEST_BASEBAND 1 << 3
|
||||||
|
|
||||||
void cmd_help(){
|
void cmd_help(){
|
||||||
printf("Usage: futurerestore [OPTIONS] IPSW\n");
|
printf("Usage: futurerestore [OPTIONS] IPSW\n");
|
||||||
|
@ -75,7 +79,7 @@ int main(int argc, const char * argv[]) {
|
||||||
return -1;
|
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) {
|
switch (opt) {
|
||||||
case 't': // long option: "apticket"; can be called as short option
|
case 't': // long option: "apticket"; can be called as short option
|
||||||
apticketPath = optarg;
|
apticketPath = optarg;
|
||||||
|
@ -98,6 +102,12 @@ int main(int argc, const char * argv[]) {
|
||||||
case 'u': // long option: "update"; can be called as short option
|
case 'u': // long option: "update"; can be called as short option
|
||||||
flags |= FLAG_UPDATE;
|
flags |= FLAG_UPDATE;
|
||||||
break;
|
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
|
case 'd': // long option: "debug"; can be called as short option
|
||||||
idevicerestore_debug = 1;
|
idevicerestore_debug = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -122,7 +132,9 @@ int main(int argc, const char * argv[]) {
|
||||||
client.putDeviceIntoRecovery();
|
client.putDeviceIntoRecovery();
|
||||||
client.waitForNonce();
|
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){
|
if (!(flags & FLAG_WAIT) || ipsw){
|
||||||
error("missing argument\n");
|
error("missing argument\n");
|
||||||
cmd_help();
|
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;
|
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");
|
reterror(-3,"sep firmware isn't signed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
versVals.basebandMode = kBasebandModeOnlyBaseband;
|
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");
|
reterror(-3,"baseband firmware isn't signed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
client.setSepPath(sepPath);
|
|
||||||
client.setSepManifestPath(sepManifestPath);
|
|
||||||
client.setBasebandPath(basebandPath);
|
|
||||||
client.setBasebandManifestPath(basebandManifestPath);
|
|
||||||
|
|
||||||
|
|
||||||
client.putDeviceIntoRecovery();
|
client.putDeviceIntoRecovery();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in a new issue