Add -h, -g, and -i, fix some linux issues

This commit is contained in:
Cryptiiiic 2022-03-21 15:04:13 -07:00
parent 7d93f437ba
commit 6b18838674
No known key found for this signature in database
GPG key ID: 6027B509EFE3A76B
7 changed files with 249 additions and 128 deletions

3
.gitmodules vendored
View file

@ -1,7 +1,8 @@
[submodule "external/idevicerestore"] [submodule "external/idevicerestore"]
path = external/idevicerestore path = external/idevicerestore
url = https://github.com/futurerestore/idevicerestore.git url = https://github.com/futurerestore/idevicerestore.git
branch = test branch = main
[submodule "external/tsschecker"] [submodule "external/tsschecker"]
path = external/tsschecker path = external/tsschecker
url = https://github.com/1Conan/tsschecker.git url = https://github.com/1Conan/tsschecker.git
branch = master

View file

@ -69,6 +69,8 @@ Usage: `futurerestore [OPTIONS] iPSW`
| ` -d ` | ` --debug ` | Show all code, use to save a log for debug testing | | ` -d ` | ` --debug ` | Show all code, use to save a log for debug testing |
| ` -e ` | ` --exit-recovery ` | Exit recovery mode and quit | | ` -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 | | ` -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 | | | ` --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. | | | ` --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) | | | ` --rdsk PATH ` | Set custom restore ramdisk for entering restoremode(requires use-pwndfu) |

@ -1 +1 @@
Subproject commit 6910da2f8d7c4667e89afdacc700006e89c589bd Subproject commit 44c13e418806e8cb5b666486bb0de6052e5cfb3d

2
external/tsschecker vendored

@ -1 +1 @@
Subproject commit 7446832da266b3dbd04e7850bf336cf2d4b1c641 Subproject commit 13745170f46651b87a2215dbc4d70a2676d4c8af

View file

@ -38,33 +38,57 @@ extern "C" {
#include <windows.h> #include <windows.h>
#define safe_mkdir(path, mode) mkdir(path) #define safe_mkdir(path, mode) mkdir(path)
#else #else
void safe_mkdir(const char *path, int mode) {
#include <sys/stat.h> int newID = 1000;
#ifdef __APPLE__ #ifdef __APPLE__
#define NEW_ID 501 newID = 501;
#else #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<char>(osReleaseStream)), std::istreambuf_iterator<char>());
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 #endif
#define safe_mkdir(path, mode) \ int id = (int)getuid();
do { \ int id1 = (int)getgid();
int id = getuid(); \ int id2 = (int)geteuid();
setuid(NEW_ID); \ int id3 = (int)getegid();
setgid(NEW_ID); \ if(newID > -1) {
seteuid(NEW_ID); \ setuid(newID);
setegid(NEW_ID); \ setgid(newID);
mkdir(path, mode); \ seteuid(newID);
setuid(id); \ setegid(newID);
setgid(id); \ }
seteuid(id); \ mkdir(path, mode);
setegid(id); \ if(newID > -1) {
} while(false) setuid(id);
setgid(id1);
seteuid(id2);
setegid(id3);
}
}
#endif #endif
#define USEC_PER_SEC 1000000 #define USEC_PER_SEC 1000000
#ifdef WIN32 #ifdef WIN32
std::string futurerestoreTempPath(download"); std::string futurerestoreTempPath("download");
#else #else
std::string tempPath("/tmp"); std::string tempPath("/tmp");
std::string futurerestoreTempPath(tempPath + "/futurerestore"); std::string futurerestoreTempPath(tempPath + "/futurerestore");
@ -115,7 +139,10 @@ futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu, bool noIBSS, b
nocache = 1; //tsschecker nocache nocache = 1; //tsschecker nocache
_foundnonce = -1; _foundnonce = -1;
_useCustomLatest = false; _useCustomLatest = false;
_useCustomLatestBuildID = false;
_useCustomLatestBeta = false;
_customLatest = std::string(""); _customLatest = std::string("");
_customLatestBuildID = std::string("");
} }
bool futurerestore::init() { bool futurerestore::init() {
@ -376,7 +403,8 @@ void futurerestore::loadAPTickets(const vector<const char *> &apticketPaths) {
int blen = 0; int blen = 0;
int readsize = 16384; //0x4000 int readsize = 16384; //0x4000
int bufsize = readsize; int bufsize = readsize;
char *bin = (char *) malloc(bufsize); std::allocator<uint8_t> alloc;
char *bin = (char *)alloc.allocate(bufsize);
char *p = bin; char *p = bin;
do { do {
int bytes_read = gzread(zf, p, readsize); 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); ibss_name.append(img3_end);
ibec_name.append(img3_end); ibec_name.append(img3_end);
} }
std::allocator<uint8_t> alloc;
if (!_noCache) { if (!_noCache) {
ibss = fopen(ibss_name.c_str(), "rb"); ibss = fopen(ibss_name.c_str(), "rb");
if (ibss) { if (ibss) {
fseek(ibss, 0, SEEK_END); fseek(ibss, 0, SEEK_END);
iBSS.second = ftell(ibss); iBSS.second = ftell(ibss);
fseek(ibss, 0, SEEK_SET); 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; size_t freadRet = 0;
retassure((freadRet = fread((char *) iBSS.first, 1, iBSS.second, ibss)) == iBSS.second, 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); "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); fseek(ibec, 0, SEEK_END);
iBEC.second = ftell(ibec); iBEC.second = ftell(ibec);
fseek(ibec, 0, SEEK_SET); 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; size_t freadRet = 0;
retassure((freadRet = fread((char *) iBEC.first, 1, iBEC.second, ibec)) == iBEC.second, 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); "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"); "failed to write generator to nvram");
retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram"); retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram");
uint64_t gen = std::stoul(generator, nullptr, 16); 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) { if (_client->nonce_size == 20) {
SHA1((unsigned char *) &gen, 8, nonce); SHA1((unsigned char *) &gen, 8, nonce);
} else if (_client->nonce_size == 32) { } else if (_client->nonce_size == 32) {
@ -1378,6 +1407,12 @@ void futurerestore::loadFirmwareTokens() {
long cnt = parseTokens(_firmwareJson, &_firmwareTokens); long cnt = parseTokens(_firmwareJson, &_firmwareTokens);
retassure(cnt > 0, "[TSSC] parsing %s.json failed\n", (0) ? "ota" : "firmware"); 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() { const char *futurerestore::getDeviceModelNoCopy() {
@ -1441,7 +1476,12 @@ char *futurerestore::getLatestManifest() {
int versionCnt = 0; int versionCnt = 0;
int i = 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"); retassure(versionCnt, "[TSSC] failed finding latest firmware version\n");
char *bpos = nullptr; char *bpos = nullptr;
while ((bpos = strstr((char *) (versVals.version = strdup(versions[i++])), "[B]")) != nullptr) { while ((bpos = strstr((char *) (versVals.version = strdup(versions[i++])), "[B]")) != nullptr) {
@ -1464,18 +1504,50 @@ char *futurerestore::getLatestManifest() {
if(i != -1) { if(i != -1) {
reterror("[TSSC] failed to find custom version for device!\n"); 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 (bpos) *bpos = '\0';
if (versions) free(versions[versionCnt - 1]), free(versions); if (versions) free(versions[versionCnt - 1]), free(versions);
ptr_smart<const char *> autofree( ptr_smart<const char *> autofree(
versVals.version); //make sure it gets freed after function finishes execution by either reaching end or throwing exception versVals.version); //make sure it gets freed after function finishes execution by either reaching end or throwing exception
ptr_smart<const char *> 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"); 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"); retassure(_latestManifest, "could not get buildmanifest of latest firmware version\n");
} }
@ -1626,7 +1698,7 @@ void futurerestore::downloadLatestBaseband() {
info("downloading Baseband\n\n"); info("downloading Baseband\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, basebandTempPath.c_str()), retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, basebandTempPath.c_str()),
"could not download baseband\n"); "could not download baseband\n");
saveStringToFile(manifeststr, basebandManifestTempPath.c_str()); saveStringToFile(manifeststr, basebandManifestTempPath);
setBasebandPath(basebandTempPath); setBasebandPath(basebandTempPath);
setBasebandManifestPath(basebandManifestTempPath); setBasebandManifestPath(basebandManifestTempPath);
loadBaseband(this->_basebandPath); loadBaseband(this->_basebandPath);
@ -1634,11 +1706,11 @@ void futurerestore::downloadLatestBaseband() {
} }
void futurerestore::downloadLatestSep() { void futurerestore::downloadLatestSep() {
char *manifeststr = getLatestManifest(); std::string manifestString = getLatestManifest();
char *pathStr = getPathOfElementInManifest("SEP", manifeststr, getDeviceBoardNoCopy(), 0); std::string pathString = getPathOfElementInManifest("SEP", manifestString.c_str(), getDeviceBoardNoCopy(), 0);
info("downloading SEP\n\n"); info("downloading SEP\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, sepTempPath.c_str()), "could not download SEP\n"); retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathString.c_str(), sepTempPath.c_str()), "could not download SEP\n");
saveStringToFile(manifeststr, sepManifestTempPath.c_str()); saveStringToFile(manifestString, sepManifestTempPath);
setSepPath(sepTempPath); setSepPath(sepTempPath);
setSepManifestPath(sepManifestTempPath); setSepManifestPath(sepManifestTempPath);
loadSep(this->_sepPath); loadSep(this->_sepPath);
@ -1663,8 +1735,9 @@ void futurerestore::loadRose(std::string rosePath) {
roseFileStream.seekg(0, std::ios_base::end); roseFileStream.seekg(0, std::ios_base::end);
_client->rosefwdatasize = roseFileStream.tellg(); _client->rosefwdatasize = roseFileStream.tellg();
roseFileStream.seekg(0, std::ios_base::beg); roseFileStream.seekg(0, std::ios_base::beg);
retassure(_client->rosefwdata = (char *) calloc(_client->rosefwdatasize, 1), std::allocator<uint8_t> alloc;
"%s: failed to calloc memory for %s\n", __func__, rosePath.c_str()); 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, roseFileStream.read((char *) _client->rosefwdata,
(std::streamsize) _client->rosefwdatasize); (std::streamsize) _client->rosefwdatasize);
retassure(*(uint64_t *) (_client->rosefwdata) != 0, retassure(*(uint64_t *) (_client->rosefwdata) != 0,
@ -1678,8 +1751,9 @@ void futurerestore::loadSE(std::string sePath) {
seFileStream.seekg(0, std::ios_base::end); seFileStream.seekg(0, std::ios_base::end);
_client->sefwdatasize = seFileStream.tellg(); _client->sefwdatasize = seFileStream.tellg();
seFileStream.seekg(0, std::ios_base::beg); seFileStream.seekg(0, std::ios_base::beg);
retassure(_client->sefwdata = (char *) calloc(_client->sefwdatasize, 1), std::allocator<uint8_t> alloc;
"%s: failed to calloc memory for %s\n", __func__, sePath.c_str()); 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, seFileStream.read((char *) _client->sefwdata,
(std::streamsize) _client->sefwdatasize); (std::streamsize) _client->sefwdatasize);
retassure(*(uint64_t *) (_client->sefwdata) != 0, retassure(*(uint64_t *) (_client->sefwdata) != 0,
@ -1695,8 +1769,9 @@ void futurerestore::loadSavage(std::array<std::string, 6> savagePaths) {
savageFileStream.seekg(0, std::ios_base::end); savageFileStream.seekg(0, std::ios_base::end);
_client->savagefwdatasize[index] = savageFileStream.tellg(); _client->savagefwdatasize[index] = savageFileStream.tellg();
savageFileStream.seekg(0, std::ios_base::beg); savageFileStream.seekg(0, std::ios_base::beg);
retassure(_client->savagefwdata[index] = (char *) calloc(_client->savagefwdatasize[index], 1), std::allocator<uint8_t> alloc;
"%s: failed to calloc memory for %s\n", __func__, savagePath.c_str()); 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], savageFileStream.read((char *) _client->savagefwdata[index],
(std::streamsize) _client->savagefwdatasize[index]); (std::streamsize) _client->savagefwdatasize[index]);
retassure(*(uint64_t *) (_client->savagefwdata[index]) != 0, 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); veridianDGMFileStream.seekg(0, std::ios_base::end);
_client->veridiandgmfwdatasize = veridianDGMFileStream.tellg(); _client->veridiandgmfwdatasize = veridianDGMFileStream.tellg();
veridianDGMFileStream.seekg(0, std::ios_base::beg); veridianDGMFileStream.seekg(0, std::ios_base::beg);
retassure(_client->veridiandgmfwdata = (char *) calloc(_client->veridiandgmfwdatasize, 1), std::allocator<uint8_t> alloc;
"%s: failed to calloc memory for %s\n", __func__, veridianDGMPath.c_str()); 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, veridianDGMFileStream.read((char *) _client->veridiandgmfwdata,
(std::streamsize) _client->veridiandgmfwdatasize); (std::streamsize) _client->veridiandgmfwdatasize);
retassure(*(uint64_t *) (_client->veridiandgmfwdata) != 0, 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); veridianFWMFileStream.seekg(0, std::ios_base::end);
_client->veridianfwmfwdatasize = veridianFWMFileStream.tellg(); _client->veridianfwmfwdatasize = veridianFWMFileStream.tellg();
veridianFWMFileStream.seekg(0, std::ios_base::beg); veridianFWMFileStream.seekg(0, std::ios_base::beg);
retassure(_client->veridianfwmfwdata = (char *) calloc(_client->veridianfwmfwdatasize, 1), retassure(_client->veridianfwmfwdata = (char *)alloc.allocate(_client->veridianfwmfwdatasize),
"%s: failed to calloc memory for %s\n", __func__, veridianFWMPath.c_str()); "%s: failed to allocate memory for %s\n", __func__, veridianFWMPath.c_str());
veridianFWMFileStream.read((char *) _client->veridianfwmfwdata, veridianFWMFileStream.read((char *) _client->veridianfwmfwdata,
(std::streamsize) _client->veridianfwmfwdatasize); (std::streamsize) _client->veridianfwmfwdatasize);
retassure(*(uint64_t *) (_client->veridianfwmfwdata) != 0, retassure(*(uint64_t *) (_client->veridianfwmfwdata) != 0,
@ -1740,8 +1816,9 @@ void futurerestore::loadRamdisk(std::string ramdiskPath) {
ramdiskFileStream.seekg(0, std::ios_base::end); ramdiskFileStream.seekg(0, std::ios_base::end);
_client->ramdiskdatasize = ramdiskFileStream.tellg(); _client->ramdiskdatasize = ramdiskFileStream.tellg();
ramdiskFileStream.seekg(0, std::ios_base::beg); ramdiskFileStream.seekg(0, std::ios_base::beg);
retassure(_client->ramdiskdata = (char *) calloc(_client->ramdiskdatasize, 1), std::allocator<uint8_t> alloc;
"%s: failed to calloc memory for %s\n", __func__, ramdiskPath.c_str()); 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, ramdiskFileStream.read((char *) _client->ramdiskdata,
(std::streamsize) _client->ramdiskdatasize); (std::streamsize) _client->ramdiskdatasize);
retassure(*(uint64_t *) (_client->ramdiskdata) != 0, retassure(*(uint64_t *) (_client->ramdiskdata) != 0,
@ -1755,8 +1832,9 @@ void futurerestore::loadKernel(std::string kernelPath) {
kernelFileStream.seekg(0, std::ios_base::end); kernelFileStream.seekg(0, std::ios_base::end);
_client->kerneldatasize = kernelFileStream.tellg(); _client->kerneldatasize = kernelFileStream.tellg();
kernelFileStream.seekg(0, std::ios_base::beg); kernelFileStream.seekg(0, std::ios_base::beg);
retassure(_client->kerneldata = (char *) calloc(_client->kerneldatasize, 1), std::allocator<uint8_t> alloc;
"%s: failed to calloc memory for %s\n", __func__, kernelPath.c_str()); 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, kernelFileStream.read((char *) _client->kerneldata,
(std::streamsize) _client->kerneldatasize); (std::streamsize) _client->kerneldatasize);
retassure(*(uint64_t *) (_client->kerneldata) != 0, retassure(*(uint64_t *) (_client->kerneldata) != 0,
@ -1770,8 +1848,9 @@ void futurerestore::loadSep(std::string sepPath) {
sepFileStream.seekg(0, std::ios_base::end); sepFileStream.seekg(0, std::ios_base::end);
_client->sepfwdatasize = sepFileStream.tellg(); _client->sepfwdatasize = sepFileStream.tellg();
sepFileStream.seekg(0, std::ios_base::beg); sepFileStream.seekg(0, std::ios_base::beg);
retassure(_client->sepfwdata = (char *) calloc(_client->sepfwdatasize, 1), std::allocator<uint8_t> alloc;
"%s: failed to calloc memory for %s\n", __func__, sepPath.c_str()); 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, sepFileStream.read((char *) _client->sepfwdata,
(std::streamsize) _client->sepfwdatasize); (std::streamsize) _client->sepfwdatasize);
retassure(*(uint64_t *) (_client->sepfwdata) != 0, 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()); retassure(basebandFileStream.good(), "%s: failed init file stream for %s!\n", __func__, basebandPath.c_str());
basebandFileStream.seekg(0, std::ios_base::beg); basebandFileStream.seekg(0, std::ios_base::beg);
uint64_t *basebandFront = nullptr; uint64_t *basebandFront = nullptr;
retassure(basebandFront = (uint64_t *) calloc(1, sizeof(uint64_t)), std::allocator<uint8_t> alloc;
"%s: failed to calloc memory for %s\n", __func__, basebandPath.c_str()); 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)); basebandFileStream.read((char *)basebandFront, (std::streamsize)sizeof(uint64_t));
retassure(*(uint64_t *) (basebandFront) != 0, "%s: failed to load Baseband for %s!\n", retassure(*(uint64_t *) (basebandFront) != 0, "%s: failed to load Baseband for %s!\n",
__func__, basebandPath.c_str()); __func__, basebandPath.c_str());
@ -1793,13 +1873,15 @@ void futurerestore::loadBaseband(std::string basebandPath) {
#pragma mark static methods #pragma mark static methods
inline void futurerestore::saveStringToFile(const char *str, const char *path) { inline void futurerestore::saveStringToFile(std::string str, std::string path) {
FILE *f = nullptr; if(str.empty() || path.empty()) {
retassure(f = fopen(path, "w"), "can't save file at %s\n", path); info("%s: No data to save!", __func__);
size_t len = strlen(str); return;
size_t wlen = fwrite(str, 1, len, f); }
fclose(f); std::ofstream fileStream(path);
retassure(len == wlen, "saving file failed, wrote=%zu actual=%zu\n", wlen, len); 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<const char *, size_t> futurerestore::getNonceFromSCAB(const char *scab, size_t scabSize) { std::pair<const char *, size_t> futurerestore::getNonceFromSCAB(const char *scab, size_t scabSize) {

View file

@ -65,11 +65,16 @@ class futurerestore {
bool _noRestore = false; bool _noRestore = false;
char *_firmwareJson = nullptr; char *_firmwareJson = nullptr;
char *_betaFirmwareJson = nullptr;
jssytok_t *_firmwareTokens = nullptr;; jssytok_t *_firmwareTokens = nullptr;;
jssytok_t *_betaFirmwareTokens = nullptr;
char *_latestManifest = nullptr; char *_latestManifest = nullptr;
char *_latestFirmwareUrl = nullptr; char *_latestFirmwareUrl = nullptr;
bool _useCustomLatest = false; bool _useCustomLatest = false;
bool _useCustomLatestBuildID = false;
bool _useCustomLatestBeta = false;
std::string _customLatest; std::string _customLatest;
std::string _customLatestBuildID;
plist_t _sepbuildmanifest = nullptr; plist_t _sepbuildmanifest = nullptr;
plist_t _basebandbuildmanifest = nullptr; plist_t _basebandbuildmanifest = nullptr;
@ -135,6 +140,7 @@ public:
void loadBaseband(std::string basebandPath); void loadBaseband(std::string basebandPath);
void setCustomLatest(std::string version){_customLatest = version; _useCustomLatest = true;} 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 setSepPath(std::string sepPath) {_sepPath = sepPath;}
void setSepManifestPath(std::string sepManifestPath) {_sepManifestPath = sepManifestPath;} void setSepManifestPath(std::string sepManifestPath) {_sepManifestPath = sepManifestPath;}
void setRamdiskPath(std::string ramdiskPath) {_ramdiskPath = ramdiskPath;} void setRamdiskPath(std::string ramdiskPath) {_ramdiskPath = ramdiskPath;}
@ -158,7 +164,7 @@ public:
static std::pair<const char *,size_t> getNonceFromSCAB(const char* scab, size_t scabSize); static std::pair<const char *,size_t> getNonceFromSCAB(const char* scab, size_t scabSize);
static uint64_t getEcidFromSCAB(const char* scab, size_t scabSize); static uint64_t getEcidFromSCAB(const char* scab, size_t scabSize);
static plist_t loadPlistFromFile(const char *path); 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 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 bool elemExists(const char *element, const char *manifeststr, const char *boardConfig, int isUpdateInstall);
static std::string getGeneratorFromSHSH2(plist_t shsh2); static std::string getGeneratorFromSHSH2(plist_t shsh2);

View file

@ -30,87 +30,97 @@ extern "C"{
#endif #endif
static struct option longopts[] = { static struct option longopts[] = {
{ "apticket", required_argument, nullptr, 't' }, { "apticket", required_argument, nullptr, 't' },
{ "baseband", required_argument, nullptr, 'b' }, { "baseband", required_argument, nullptr, 'b' },
{ "baseband-manifest", required_argument, nullptr, 'p' }, { "baseband-manifest", required_argument, nullptr, 'p' },
{ "sep", required_argument, nullptr, 's' }, { "sep", required_argument, nullptr, 's' },
{ "sep-manifest", required_argument, nullptr, 'm' }, { "sep-manifest", required_argument, nullptr, 'm' },
{ "wait", no_argument, nullptr, 'w' }, { "wait", no_argument, nullptr, 'w' },
{ "update", no_argument, nullptr, 'u' }, { "update", no_argument, nullptr, 'u' },
{ "debug", no_argument, nullptr, 'd' }, { "debug", no_argument, nullptr, 'd' },
{ "exit-recovery", no_argument, nullptr, 'e' }, { "exit-recovery", no_argument, nullptr, 'e' },
{ "custom-latest", required_argument, nullptr, 'c' }, { "custom-latest", required_argument, nullptr, 'c' },
{ "latest-sep", no_argument, nullptr, '0' }, { "custom-latest-buildid", required_argument, nullptr, 'g' },
{ "no-restore", no_argument, nullptr, 'z' }, { "help", no_argument, nullptr, 'h' },
{ "latest-baseband", no_argument, nullptr, '1' }, { "custom-latest-beta", no_argument, nullptr, 'i' },
{ "no-baseband", no_argument, nullptr, '2' }, { "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 #ifdef HAVE_LIBIPATCHER
{ "use-pwndfu", no_argument, nullptr, '3' }, { "use-pwndfu", no_argument, nullptr, '3' },
{ "no-ibss", no_argument, nullptr, '4' }, { "no-ibss", no_argument, nullptr, '4' },
{ "rdsk", required_argument, nullptr, '5' }, { "rdsk", required_argument, nullptr, '5' },
{ "rkrn", required_argument, nullptr, '6' }, { "rkrn", required_argument, nullptr, '6' },
{ "set-nonce", optional_argument, nullptr, '7' }, { "set-nonce", optional_argument, nullptr, '7' },
{ "serial", no_argument, nullptr, '8' }, { "serial", no_argument, nullptr, '8' },
{ "boot-args", required_argument, nullptr, '9' }, { "boot-args", required_argument, nullptr, '9' },
{ "no-cache", no_argument, nullptr, 'a' }, { "no-cache", no_argument, nullptr, 'a' },
{ "skip-blob", no_argument, nullptr, 'f' }, { "skip-blob", no_argument, nullptr, 'f' },
#endif #endif
{ nullptr, 0, nullptr, 0 } { nullptr, 0, nullptr, 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_SEP 1 << 2
#define FLAG_LATEST_BASEBAND 1 << 3 #define FLAG_LATEST_BASEBAND 1 << 3
#define FLAG_NO_BASEBAND 1 << 4 #define FLAG_NO_BASEBAND 1 << 4
#define FLAG_IS_PWN_DFU 1 << 5 #define FLAG_IS_PWN_DFU 1 << 5
#define FLAG_NO_IBSS 1 << 6 #define FLAG_NO_IBSS 1 << 6
#define FLAG_RESTORE_RAMDISK 1 << 7 #define FLAG_RESTORE_RAMDISK 1 << 7
#define FLAG_RESTORE_KERNEL 1 << 8 #define FLAG_RESTORE_KERNEL 1 << 8
#define FLAG_SET_NONCE 1 << 9 #define FLAG_SET_NONCE 1 << 9
#define FLAG_SERIAL 1 << 10 #define FLAG_SERIAL 1 << 10
#define FLAG_BOOT_ARGS 1 << 11 #define FLAG_BOOT_ARGS 1 << 11
#define FLAG_NO_CACHE 1 << 12 #define FLAG_NO_CACHE 1 << 12
#define FLAG_SKIP_BLOB 1 << 13 #define FLAG_SKIP_BLOB 1 << 13
#define FLAG_NO_RESTORE_FR 1 << 14 #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(){ void cmd_help(){
printf("Usage: futurerestore [OPTIONS] iPSW\n"); printf("Usage: futurerestore [OPTIONS] iPSW\n");
printf("Allows restoring to non-matching firmware with custom SEP+baseband\n"); printf("Allows restoring to non-matching firmware with custom SEP+baseband\n");
printf("\nGeneral options:\n"); printf("\nGeneral options:\n");
printf(" -t, --apticket PATH\t\tSigning tickets used for restoring\n"); printf(" -h, --help\t\t\t\tShows this usage message\n");
printf(" -u, --update\t\t\tUpdate instead of erase install (requires appropriate APTicket)\n"); printf(" -t, --apticket PATH\t\t\tSigning tickets used for restoring\n");
printf(" \t\t\tDO NOT use this parameter, if you update from jailbroken firmware!\n"); printf(" -u, --update\t\t\t\tUpdate instead of erase install (requires appropriate APTicket)\n");
printf(" -w, --wait\t\t\tKeep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable)\n"); printf(" \t\t\t\tDO NOT use this parameter, if you update from jailbroken firmware!\n");
printf(" -d, --debug\t\t\tShow all code, use to save a log for debug testing\n"); printf(" -w, --wait\t\t\t\tKeep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable)\n");
printf(" -e, --exit-recovery\t\tExit recovery mode and quit\n"); printf(" -d, --debug\t\t\t\tShow all code, use to save a log for debug testing\n");
printf(" -z, --no-restore\t\tDo not restore and end right before NOR data is sent\n"); printf(" -e, --exit-recovery\t\t\tExit recovery mode and quit\n");
printf(" -c, --custom-latest VERSION\tSpecify custom latest version to use for SEP, Baseband and other FirmwareUpdater components\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 #ifdef HAVE_LIBIPATCHER
printf("\nOptions for downgrading with Odysseus:\n"); 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(" --use-pwndfu\t\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(" --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\tSet custom restore ramdisk for entering restoremode(requires use-pwndfu)\n"); printf(" --rdsk PATH\t\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(" --rkrn PATH\t\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\t\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(" --set-nonce=0xNONCE\t\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(" --serial\t\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(" --boot-args\t\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(" --no-cache\t\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(" --skip-blob\t\t\tSkip SHSH blob validation(PROCEED WITH CAUTION)(requires use-pwndfu)\n");
#endif #endif
printf("\nOptions for SEP:\n"); printf("\nOptions for SEP:\n");
printf(" --latest-sep\t\tUse latest signed SEP instead of manually specifying one\n"); printf(" --latest-sep\t\t\tUse latest signed SEP instead of manually specifying one\n");
printf(" -s, --sep PATH\t\tSEP to be flashed\n"); printf(" -s, --sep PATH\t\t\tSEP to be flashed\n");
printf(" -m, --sep-manifest PATH\tBuildManifest for requesting SEP ticket\n"); printf(" -m, --sep-manifest PATH\t\tBuildManifest for requesting SEP ticket\n");
printf("\nOptions for baseband:\n"); printf("\nOptions for baseband:\n");
printf(" --latest-baseband\t\tUse latest signed baseband instead of manually specifying one\n"); printf(" --latest-baseband\t\t\tUse latest signed baseband instead of manually specifying one\n");
printf(" -b, --baseband PATH\t\tBaseband to be flashed\n"); printf(" -b, --baseband PATH\t\t\tBaseband to be flashed\n");
printf(" -p, --baseband-manifest PATH\tBuildManifest for requesting baseband ticket\n"); printf(" -p, --baseband-manifest PATH\t\tBuildManifest for requesting baseband ticket\n");
printf(" --no-baseband\t\tSkip checks and don't flash baseband\n"); printf(" --no-baseband\t\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(" \t\t\tOnly use this for device without a baseband (eg. iPod touch or some Wi-Fi only iPads)\n\n");
} }
using namespace std; using namespace std;
@ -145,6 +155,7 @@ int main_r(int argc, const char * argv[]) {
const char *sepManifestPath = nullptr; const char *sepManifestPath = nullptr;
const char *bootargs = nullptr; const char *bootargs = nullptr;
std::string customLatest; std::string customLatest;
std::string customLatestBuildID;
const char *ramdiskPath = nullptr; const char *ramdiskPath = nullptr;
const char *kernelPath = nullptr; const char *kernelPath = nullptr;
const char *custom_nonce = nullptr; const char *custom_nonce = nullptr;
@ -159,8 +170,12 @@ int main_r(int argc, const char * argv[]) {
return -1; 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) { 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 case 't': // long option: "apticket"; can be called as short option
apticketPaths.push_back(optarg); apticketPaths.push_back(optarg);
break; break;
@ -182,8 +197,16 @@ int main_r(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 'c': // long option: "custom-latest"; case 'c': // long option: "custom-latest"; can be called as short option
customLatest = (optarg) ? std::string(optarg) : std::string(""); 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; break;
case '0': // long option: "latest-sep"; case '0': // long option: "latest-sep";
flags |= FLAG_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"); retassure((flags & FLAG_IS_PWN_DFU),"--no-cache requires --use-pwndfu\n");
if(flags & FLAG_SKIP_BLOB) if(flags & FLAG_SKIP_BLOB)
retassure((flags & FLAG_IS_PWN_DFU),"--skip-blob requires --use-pwndfu\n"); 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) { if (exitRecovery) {
client.exitRecovery(); client.exitRecovery();
@ -307,6 +334,9 @@ int main_r(int argc, const char * argv[]) {
if(!customLatest.empty()) { if(!customLatest.empty()) {
client.setCustomLatest(customLatest); client.setCustomLatest(customLatest);
} }
if(!customLatestBuildID.empty()) {
client.setCustomLatestBuildID(customLatestBuildID, (flags & FLAG_CUSTOM_LATEST_BETA) != 0);
}
if (!( if (!(
((!apticketPaths.empty() && ipsw) ((!apticketPaths.empty() && ipsw)