Improve logging, add no rsep, add component cache

This commit is contained in:
Cryptiiiic 2022-09-15 12:30:04 -07:00
parent 7f73214018
commit 19e30c014b
No known key found for this signature in database
GPG key ID: 6027B509EFE3A76B
8 changed files with 325 additions and 117 deletions

View file

@ -4,6 +4,12 @@ execute_process(COMMAND git submodule update --init --recursive WORKING_DIRECTOR
set(ignoreMe "${NO_PKGCFG} ${ASAN} ${NO_XCODE} ${ARCH}")
set(SUBPROJECT_BUILD 1)
set(ASAN_FLAG "")
set(CMAKE_C_FLAGS_RELEASE "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-Os -DNDEBUG")
set(CMAKE_C_FLAGS_DEBUG "-g -O0 -DDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -DDEBUG")
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
if(DEFINED ASAN OR "$ENV{ASAN}" MATCHES "1")
set(ASAN 1)
set(ASAN_FLAG "-fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
@ -40,12 +46,6 @@ elseif("${CMAKE_HOST_SYSTEM_NAME}" MATCHES "Linux")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-multiple-definition -pthread -mrelax-all -std=gnu++20 ${ASAN_FLAG}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--allow-multiple-definition -pthread -mrelax-all -std=gnu17 ${ASAN_FLAG}")
endif()
set(CMAKE_C_FLAGS_RELEASE "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-Os -DNDEBUG")
set(CMAKE_C_FLAGS_DEBUG "-g -O0 -DDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -DDEBUG")
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
project(futurerestore)
add_subdirectory(external/tsschecker)
add_subdirectory(external/idevicerestore)

View file

@ -33,35 +33,36 @@ See [COMPILING](COMPILING.md)
# Futurerestore Usage
Usage: `futurerestore [OPTIONS] iPSW`
| option (short) | option (long) | description |
|----------------|------------------------------------------|-----------------------------------------------------------------------------------|
| ` -t ` | ` --apticket PATH ` | Signing tickets used for restoring, commonly known as blobs |
| ` -u ` | ` --update ` | Update instead of erase install (requires appropriate APTicket) |
| | | This parameter is recommended to not be used for downgrading. If you are jailbroken, make sure to have your orig-fs snapshot restored (Restore RootFS). |
| ` -w ` | ` --wait ` | Keep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable) |
| ` -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) |
| | ` --rkrn PATH ` | Set custom restore kernelcache for entering restoremode(requires use-pwndfu) |
| | ` --set-nonce ` | Set custom nonce from your blob then exit recovery(requires use-pwndfu) |
| | ` --set-nonce=0xNONCE ` | Set custom nonce then exit recovery(requires use-pwndfu) |
| | ` --serial ` | Enable serial during boot(requires serial cable and use-pwndfu) |
| | ` --boot-args "BOOTARGS" ` | Set custom restore boot-args(PROCEED WITH CAUTION)(requires use-pwndfu) |
| | ` --no-cache ` | Disable cached patched iBSS/iBEC(requires use-pwndfu) |
| | ` --skip-blob ` | Skip SHSH blob validation(PROCEED WITH CAUTION)(requires use-pwndfu) |
| | ` --latest-sep ` | Use latest signed SEP instead of manually specifying one |
| ` -s ` | ` --sep PATH ` | Manually specify SEP to be flashed |
| ` -m ` | ` --sep-manifest PATH ` | BuildManifest for requesting SEP ticket |
| | ` --latest-baseband ` | Use latest signed baseband instead of manually specifying one |
| ` -b ` | ` --baseband PATH ` | Manually specify baseband to be flashed |
| ` -p ` | ` --baseband-manifest PATH ` | BuildManifest for requesting baseband ticket |
| | ` --no-baseband ` | Skip checks and don't flash baseband |
| | | Only use this for device without a baseband (eg. iPod touch or Wi-Fi only iPads) |
| option (short) | option (long) | description |
|----------------|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
| ` -t ` | ` --apticket PATH ` | Signing tickets used for restoring, commonly known as blobs |
| ` -u ` | ` --update ` | Update instead of erase install (requires appropriate APTicket) |
| | | This parameter is recommended to not be used for downgrading. If you are jailbroken, make sure to have your orig-fs snapshot restored (Restore RootFS). |
| ` -w ` | ` --wait ` | Keep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable) |
| ` -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) |
| | ` --rkrn PATH ` | Set custom restore kernelcache for entering restoremode(requires use-pwndfu) |
| | ` --set-nonce ` | Set custom nonce from your blob then exit recovery(requires use-pwndfu) |
| | ` --set-nonce=0xNONCE ` | Set custom nonce then exit recovery(requires use-pwndfu) |
| | ` --serial ` | Enable serial during boot(requires serial cable and use-pwndfu) |
| | ` --boot-args "BOOTARGS" ` | Set custom restore boot-args(PROCEED WITH CAUTION)(requires use-pwndfu) |
| | ` --no-cache ` | Disable cached patched iBSS/iBEC(requires use-pwndfu) |
| | ` --skip-blob ` | Skip SHSH blob validation(PROCEED WITH CAUTION)(requires use-pwndfu) |
| | ` --latest-sep ` | Use latest signed SEP instead of manually specifying one |
| ` -s ` | ` --sep PATH ` | Manually specify SEP to be flashed |
| ` -m ` | ` --sep-manifest PATH ` | BuildManifest for requesting SEP ticket |
| ` -j ` | ` --no-rsep ` | Choose not to send Restore Mode SEP |
| | ` --latest-baseband ` | Use latest signed baseband instead of manually specifying one |
| ` -b ` | ` --baseband PATH ` | Manually specify baseband to be flashed |
| ` -p ` | ` --baseband-manifest PATH ` | BuildManifest for requesting baseband ticket |
| | ` --no-baseband ` | Skip checks and don't flash baseband |
| | | Only use this for device without a baseband (eg. iPod touch or Wi-Fi only iPads) |
---

@ -1 +1 @@
Subproject commit b46637056fce7cb771f53916b1a8c527d256c5f2
Subproject commit 97ab482cf251b83e71887f9cd7a8f1d9e066e671

2
external/tsschecker vendored

@ -1 +1 @@
Subproject commit 9a046508ffb7cbd62d3ff50042944237389c51b4
Subproject commit 6e55c67ec78df55b8185c17ea2f79f838d0c034b

View file

@ -88,6 +88,7 @@ endif()
execute_process(COMMAND cat version.txt WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE VERSION_RELEASE ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
add_definitions(
-DHAVE_LIBIPATCHER=1
-DCUSTOM_LOGGING=<stdlib.h>
-DVERSION_COMMIT_COUNT="${VERSION_COMMIT_COUNT}"
-DVERSION_COMMIT_SHA="${VERSION_COMMIT_SHA}"
-DVERSION_RELEASE="${VERSION_RELEASE}"

View file

@ -108,9 +108,15 @@ std::string sepManifestTempPath = futurerestoreTempPath + "/sepManifest.plist";
# include <CommonCrypto/CommonDigest.h>
# define SHA1(d, n, md) CC_SHA1(d, n, md)
# define SHA256(d, n, md) CC_SHA256(d, n, md)
# define SHA384(d, n, md) CC_SHA384(d, n, md)
# define SHA512(d, n, md) CC_SHA512(d, n, md)
#else
# include <openssl/sha.h>
extern "C" {
unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md);
unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md);
}
#endif // __APPLE__
#ifndef HAVE_LIBIPATCHER
@ -128,10 +134,10 @@ void idevice_event_cb(const idevice_event_t *event, void *userdata);
#pragma mark futurerestore
futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu, bool noIBSS, bool setNonce, bool serial,
bool noRestore) : _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu), _noIBSS(noIBSS),
_setNonce(setNonce), _serial(serial), _noRestore(noRestore) {
bool noRestore, bool noRSEP) : _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu), _noIBSS(noIBSS),
_setNonce(setNonce), _serial(serial), _noRestore(noRestore), _noRSEP(noRSEP) {
_client = idevicerestore_client_new();
retassure(_client != nullptr, "could not create idevicerestore client\n");
retassure(_client != nullptr, "Could not create idevicerestore client\n");
struct stat st{0};
if (stat(futurerestoreTempPath.c_str(), &st) == -1) safe_mkdir(futurerestoreTempPath.c_str(), 0755);
@ -468,7 +474,7 @@ uint64_t futurerestore::getBasebandGoldCertIDFromDevice() {
plist_t node;
node = plist_dict_get_item(_client->preflight_info, "CertID");
if (!node || plist_get_node_type(node) != PLIST_UINT) {
error("Unable to find required BbGoldCertId in parameters\n");
debug("Unable to find required BbGoldCertId in parameters\n");
return 0;
}
uint64_t val = 0;
@ -893,6 +899,7 @@ void futurerestore::doRestore(const char *ipsw) {
client->ipsw = strdup(ipsw);
if (_noRestore) client->flags |= FLAG_NO_RESTORE;
if (_noRSEP) client->flags |= FLAG_NO_RSEP;
if (!_isUpdateInstall) client->flags |= FLAG_ERASE;
irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client);
@ -1119,13 +1126,13 @@ void futurerestore::doRestore(const char *ipsw) {
if (sephashlen == 20)
SHA1((unsigned char *) _client->sepfwdata, (unsigned int) _client->sepfwdatasize, genHash);
else
SHA384((unsigned char *) _client->sepfwdata, (unsigned int) _client->sepfwdatasize, genHash);
SHA384((const unsigned char *) _client->sepfwdata, (unsigned long) _client->sepfwdatasize, genHash);
retassure(!memcmp(genHash, sephash, sephashlen), "ERROR: SEP does not match sepmanifest\n");
}
build_identity_print_information(build_identity); // print information about current build identity
//check for enterpwnrecovery, because we could be in DFU mode
//check for enterpwnrecovery, because we Could be in DFU mode
if (_enterPwnRecoveryRequested) {
retassure((getDeviceMode(true) == _MODE_DFU) || (getDeviceMode(false) == _MODE_RECOVERY && _noIBSS),
"unexpected device mode\n");
@ -1352,7 +1359,7 @@ void futurerestore::doRestore(const char *ipsw) {
get_ap_nonce(client, &client->nonce, &client->nonce_size);
if (client->mode == MODE_RECOVERY) {
retassure(client->srnm, "ERROR: could not retrieve device serial number. Can't continue.\n");
retassure(client->srnm, "ERROR: Could not retrieve device serial number. Can't continue.\n");
if (client->device->chip_id < 0x8015) {
retassure(!irecv_send_command(client->recovery->client, "bgcolor 0 255 0"),
@ -1401,17 +1408,17 @@ int futurerestore::findProc(const char *procName, bool load) {
do {
ctlRet = sysctl(mib, mibLen, nullptr, &size, nullptr, 0);
if (ctlRet < 0) {
info("daemonManager: findProc: failed sysctl(KERN_PROC)!\n");
debug("daemonManager: findProc: failed sysctl(KERN_PROC)!\n");
return -1;
}
if (!size) {
info("daemonManager: findProc: failed sysctl(KERN_PROC) size!\n");
debug("daemonManager: findProc: failed sysctl(KERN_PROC) size!\n");
return -1;
}
size += size / 10;
procs2 = static_cast<kinfo_proc *>(realloc(procs, size));
if (!procs2) {
info("daemonManager: findProc: realloc failed!\n");
debug("daemonManager: findProc: realloc failed!\n");
safeFree(procs);
safeFree(procs2);
return -1;
@ -1478,7 +1485,7 @@ int futurerestore::findProc(const char *procName, bool load) {
}
if (strcmp(cmd, procName) == 0) {
if(!load) {
info("daemonManager: findProc: found %s!\n", procName);
debug("daemonManager: findProc: found %s!\n", procName);
}
return pid;
}
@ -1488,7 +1495,7 @@ int futurerestore::findProc(const char *procName, bool load) {
void futurerestore::daemonManager(bool load) {
if(!load) {
info("daemonManager: suspending invasive macOS daemons...\n");
debug("daemonManager: suspending invasive macOS daemons...\n");
}
int pid = 0;
const char *procList[] = { "MobileDeviceUpdater", "AMPDevicesAgent", "AMPDeviceDiscoveryAgent", 0};
@ -1498,14 +1505,14 @@ void futurerestore::daemonManager(bool load) {
if (load) {
int ret = kill(pid, SIGCONT);
} else {
info("daemonManager: killing %s.\n", procList[i]);
debug("daemonManager: killing %s.\n", procList[i]);
int ret = kill(pid, SIGSTOP);
}
}
}
if(!load) {
info("daemonManager: done!\n");
debug("daemonManager: done!\n");
}
}
#endif
@ -1536,19 +1543,22 @@ futurerestore::~futurerestore() {
void futurerestore::loadFirmwareTokens() {
if (!_firmwareTokens) {
if (!_firmwareJson) _firmwareJson = getFirmwareJson();
retassure(_firmwareJson, "[TSSC] could not get firmware.json\n");
retassure(_firmwareJson, "[TSSC] Could not get firmware.json\n");
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");
retassure(_betaFirmwareJson, "[TSSC] Could not get betas json\n");
long cnt = parseTokens(_betaFirmwareJson, &_betaFirmwareTokens);
retassure(cnt > 0, "[TSSC] parsing %s.json failed\n", (0) ? "beta ota" : "beta firmware");
}
}
const char *futurerestore::getDeviceModelNoCopy() {
if(_model) {
return _model;
}
if (!_client->device || !_client->device->product_type) {
int mode = getDeviceMode(true);
@ -1571,10 +1581,13 @@ const char *futurerestore::getDeviceModelNoCopy() {
}
}
return _client->device->product_type;
return _model = _client->device->product_type;
}
const char *futurerestore::getDeviceBoardNoCopy() {
if(_board) {
return _board;
}
if (!_client->device || !_client->device->product_type) {
int mode = getDeviceMode(true);
@ -1596,7 +1609,7 @@ const char *futurerestore::getDeviceBoardNoCopy() {
break;
}
}
return _client->device->hardware_model;
return _board = _client->device->hardware_model;
}
char *futurerestore::getLatestManifest() {
@ -1620,7 +1633,7 @@ char *futurerestore::getLatestManifest() {
while ((bpos = strstr((char *) (versVals.version = strdup(versions[i++])), "[B]")) != nullptr) {
free((char *) versVals.version);
if (--versionCnt == 0)
reterror("[TSSC] automatic selection of firmware couldn't find for non-beta versions\n");
reterror("[TSSC] automatic selection of firmware Couldn't find for non-beta versions\n");
}
if(_useCustomLatest) {
i = 0;
@ -1655,9 +1668,9 @@ char *futurerestore::getLatestManifest() {
}
if(!_useCustomLatestBeta) {
if(_useCustomLatestBuildID) {
info("[TSSC] selecting latest firmware version: %s\n", versVals.buildID);
debug("[TSSC] selecting latest firmware version: %s\n", versVals.buildID);
} else {
info("[TSSC] selecting latest firmware version: %s\n", versVals.version);
debug("[TSSC] selecting latest firmware version: %s\n", versVals.version);
}
}
if (bpos) *bpos = '\0';
@ -1669,7 +1682,7 @@ char *futurerestore::getLatestManifest() {
versVals.buildID); //make sure it gets freed after function finishes execution by either reaching end or throwing exception
if(_useCustomLatestBeta) {
info("[TSSC] selecting latest firmware version: %s\n", _customLatestBuildID.c_str());
debug("[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 {
@ -1680,8 +1693,8 @@ char *futurerestore::getLatestManifest() {
_latestManifest = getBuildManifest(_latestFirmwareUrl, device, versVals.version, versVals.buildID, 0);
}
}
retassure(_latestFirmwareUrl, "could not find url of latest firmware version\n");
retassure(_latestManifest, "could not get buildmanifest of latest firmware version\n");
retassure(_latestFirmwareUrl, "Could not find url of latest firmware version\n");
retassure(_latestManifest, "Could not get buildmanifest of latest firmware version\n");
}
return _latestManifest;
@ -1696,9 +1709,20 @@ void futurerestore::downloadLatestRose() {
char *roseStr = (elemExists("Rap,RTKitOS", manifeststr, getDeviceBoardNoCopy(), 0) ? getPathOfElementInManifest(
"Rap,RTKitOS", manifeststr, getDeviceBoardNoCopy(), 0) : nullptr);
if (roseStr) {
info("downloading Rose firmware\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), roseStr, roseTempPath.c_str()),
"could not download Rose\n");
auto *digestString = getDigestOfElementInManifest("Rap,RTKitOS", manifeststr, getDeviceBoardNoCopy(), 0);
unsigned char *hash = getSHA(roseTempPath);
if(hash && digestString) {
if(!memcmp(digestString, hash, 48)) {
info("Using cached Rose\n");
safeFree(digestString);
safeFree(hash);
return;
}
} else {
info("Downloading Rose firmware\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), roseStr, roseTempPath.c_str()),
"Could not download Rose\n");
}
loadRose(roseTempPath);
}
}
@ -1708,8 +1732,10 @@ void futurerestore::downloadLatestSE() {
char *seStr = (elemExists("SE,UpdatePayload", manifeststr, getDeviceBoardNoCopy(), 0) ? getPathOfElementInManifest(
"SE,UpdatePayload", manifeststr, getDeviceBoardNoCopy(), 0) : nullptr);
if (seStr) {
info("downloading SE firmware\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), seStr, seTempPath.c_str()), "could not download SE\n");
// TODO: SE caching how does ProductionUpdatePayloadHash work?
info("Downloading SE firmware\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), seStr, seTempPath.c_str()),
"Could not download SE\n");
loadSE(seTempPath);
}
}
@ -1736,41 +1762,102 @@ void futurerestore::downloadLatestSavage() {
: nullptr);
std::array<std::string, 6> savagePaths{};
if (savageB0ProdStr) {
info("downloading Savage,B0-Prod-Patch\n\n");
savagePaths[0] = futurerestoreTempPath + "/savageB0PP.fw";
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageB0ProdStr, savagePaths[0].c_str()),
"could not download Savage,B0-Prod-Patch\n");
auto *digestString = getDigestOfElementInManifest("Savage,B0-Prod-Patch", manifeststr, getDeviceBoardNoCopy(), 0);
unsigned char *hash = getSHA(savagePaths[0], 1);
if(hash && digestString) {
if(!memcmp(digestString, hash, 32)) {
info("Using cached Savage,B0-Prod-Patch.\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading Savage,B0-Prod-Patch\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageB0ProdStr, savagePaths[0].c_str()),
"Could not download Savage,B0-Prod-Patch\n");
}
}
if (savageB0DevStr) {
info("downloading Savage,B0-Dev-Patch\n\n");
savagePaths[1] = futurerestoreTempPath + "//savageB0DP.fw";
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageB0DevStr, savagePaths[1].c_str()),
"could not download Savage,B0-Dev-Patch\n");
auto *digestString = getDigestOfElementInManifest("Savage,B0-Dev-Patch", manifeststr, getDeviceBoardNoCopy(), 0);
unsigned char *hash = getSHA(savagePaths[1], 1);
if(hash && digestString) {
if(!memcmp(digestString, hash, 32)) {
info("Using cached Savage,B0-Dev-Patch.\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading Savage,B0-Dev-Patch\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageB0DevStr, savagePaths[1].c_str()),
"Could not download Savage,B0-Dev-Patch\n");
}
}
if (savageB2ProdStr) {
info("downloading Savage,B2-Prod-Patch\n\n");
savagePaths[2] = futurerestoreTempPath + "//savageB2PP.fw";
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageB2ProdStr, savagePaths[2].c_str()),
"could not download Savage,B2-Prod-Patch\n");
auto *digestString = getDigestOfElementInManifest("Savage,B2-Prod-Patch", manifeststr, getDeviceBoardNoCopy(), 0);
unsigned char *hash = getSHA(savagePaths[2], 1);
if(hash && digestString) {
if(!memcmp(digestString, hash, 32)) {
info("Using cached Savage,B2-Prod-Patch.\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading Savage,B2-Prod-Patch\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageB2ProdStr, savagePaths[2].c_str()),
"Could not download Savage,B2-Prod-Patch\n");
}
}
if (savageB2DevStr) {
info("downloading Savage,B2-Dev-Patch\n\n");
savagePaths[3] = futurerestoreTempPath + "//savageB2DP.fw";
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageB2DevStr, savagePaths[3].c_str()),
"could not download Savage,B2-Dev-Patch\n");
auto *digestString = getDigestOfElementInManifest("Savage,B2-Dev-Patch", manifeststr, getDeviceBoardNoCopy(), 0);
unsigned char *hash = getSHA(savagePaths[3], 1);
if(hash && digestString) {
if(!memcmp(digestString, hash, 32)) {
info("Using cached Savage,B2-Dev-Patch.\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading Savage,B2-Dev-Patch\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageB2DevStr, savagePaths[3].c_str()),
"Could not download Savage,B2-Dev-Patch\n");
}
}
if (savageBAProdStr) {
info("downloading Savage,BA-Prod-Patch\n\n");
savagePaths[4] = futurerestoreTempPath + "//savageBAPP.fw";
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageBAProdStr, savagePaths[4].c_str()),
"could not download Savage,BA-Prod-Patch\n");
auto *digestString = getDigestOfElementInManifest("Savage,BA-Prod-Patch", manifeststr, getDeviceBoardNoCopy(), 0);
unsigned char *hash = getSHA(savagePaths[4], 1);
if(hash && digestString) {
if(!memcmp(digestString, hash, 32)) {
info("Using cached Savage,BA-Prod-Patch.\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading Savage,BA-Prod-Patch\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageBAProdStr, savagePaths[4].c_str()),
"Could not download Savage,BA-Prod-Patch\n");
}
}
if (savageBADevStr) {
info("downloading Savage,BA-Dev-Patch\n\n");
savagePaths[5] = futurerestoreTempPath + "//savageBADP.fw";
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageBADevStr, savagePaths[5].c_str()),
"could not download Savage,BA-Dev-Patch\n");
auto *digestString = getDigestOfElementInManifest("Savage,BA-Dev-Patch", manifeststr, getDeviceBoardNoCopy(), 0);
unsigned char *hash = getSHA(savagePaths[5], 1);
if(hash && digestString) {
if(!memcmp(digestString, hash, 32)) {
info("Using cached Savage,BA-Dev-Patch.\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading Savage,BA-Dev-Patch\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), savageBADevStr, savagePaths[5].c_str()),
"Could not download Savage,BA-Dev-Patch\n");
}
}
if (savageB0ProdStr &&
savageB0DevStr &&
@ -1790,15 +1877,36 @@ void futurerestore::downloadLatestVeridian() {
char *veridianFWMStr = (elemExists("BMU,FirmwareMap", manifeststr, getDeviceBoardNoCopy(), 0)
? getPathOfElementInManifest("BMU,FirmwareMap", manifeststr, getDeviceBoardNoCopy(), 0)
: nullptr);
if (veridianDGMStr) {
info("downloading Veridian DigestMap\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), veridianDGMStr, veridianDGMTempPath.c_str()),
"could not download Veridian DigestMap\n");
auto *digestString = getDigestOfElementInManifest("BMU,DigestMap", manifeststr, getDeviceBoardNoCopy(), 0);
unsigned char *hash = getSHA(veridianDGMTempPath);
if(hash && digestString) {
if(!memcmp(digestString, hash, 48)) {
info("Using cached BMU,DigestMap(Veridian).\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading Veridian DigestMap\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), veridianDGMStr, veridianDGMTempPath.c_str()),
"Could not download Veridian DigestMap\n");
}
}
if (veridianFWMStr) {
info("downloading Veridian FirmwareMap\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), veridianFWMStr, veridianFWMTempPath.c_str()),
"could not download Veridian FirmwareMap\n");
auto digestString = getDigestOfElementInManifest("BMU,FirmwareMap", manifeststr, getDeviceBoardNoCopy(), 0);
auto hash = getSHA(veridianFWMTempPath);
if(hash && digestString) {
if(!memcmp(digestString, hash, 48)) {
info("Using cached BMU,FirmwareMap(Veridian).\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading Veridian FirmwareMap\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), veridianFWMStr, veridianFWMTempPath.c_str()),
"Could not download Veridian FirmwareMap\n");
}
}
if (veridianDGMStr && veridianFWMStr)
loadVeridian(veridianDGMTempPath, veridianFWMTempPath);
@ -1826,11 +1934,12 @@ void futurerestore::downloadLatestFirmwareComponents() {
}
void futurerestore::downloadLatestBaseband() {
char *manifeststr = getLatestManifest();
char *pathStr = getPathOfElementInManifest("BasebandFirmware", manifeststr, getDeviceBoardNoCopy(), 0);
info("downloading Baseband\n\n");
auto manifeststr = getLatestManifest();
auto pathStr = getPathOfElementInManifest("BasebandFirmware", manifeststr, getDeviceBoardNoCopy(), 0);
// TODO: Baseband caching. How on earth does basebandfirmware digest work?
info("Downloading Baseband\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, basebandTempPath.c_str()),
"could not download baseband\n");
"Could not download baseband\n");
saveStringToFile(manifeststr, basebandManifestTempPath);
setBasebandPath(basebandTempPath);
setBasebandManifestPath(basebandManifestTempPath);
@ -1839,10 +1948,20 @@ void futurerestore::downloadLatestBaseband() {
}
void futurerestore::downloadLatestSep() {
std::string manifestString = getLatestManifest();
std::string pathString = getPathOfElementInManifest("SEP", manifestString.c_str(), getDeviceBoardNoCopy(), 0);
info("downloading SEP\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathString.c_str(), sepTempPath.c_str()), "could not download SEP\n");
auto manifestString = getLatestManifest();
auto pathString = getPathOfElementInManifest("SEP", manifestString, getDeviceBoardNoCopy(), 0);
auto *digestString = getDigestOfElementInManifest("SEP",manifestString,getDeviceBoardNoCopy(),0);
auto *hash = getSHA(sepTempPath);
if(hash && digestString) {
if(!memcmp(digestString, hash, 48)) {
info("Using cached SEP.\n");
safeFree(digestString);
safeFree(hash);
}
} else {
info("Downloading SEP\n\n");
retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathString, sepTempPath.c_str()), "Could not download SEP\n");
}
saveStringToFile(manifestString, sepManifestTempPath);
setSepPath(sepTempPath);
setSepManifestPath(sepManifestTempPath);
@ -1853,13 +1972,13 @@ void futurerestore::downloadLatestSep() {
void futurerestore::loadSepManifest(std::string sepManifestPath) {
this->_sepManifestPath = sepManifestPath;
retassure(_sepbuildmanifest = loadPlistFromFile(sepManifestPath.c_str()),
"failed to load SEP Manifest");
"Failed to load SEP Manifest");
}
void futurerestore::loadBasebandManifest(std::string basebandManifestPath) {
this->_basebandManifestPath = basebandManifestPath;
retassure(_basebandbuildmanifest = loadPlistFromFile(basebandManifestPath.c_str()),
"failed to load Baseband Manifest");
"Failed to load Baseband Manifest");
};
void futurerestore::loadRose(std::string rosePath) {
@ -2004,6 +2123,54 @@ void futurerestore::loadBaseband(std::string basebandPath) {
__func__, basebandPath.c_str());
}
unsigned char *futurerestore::getSHA(const std::string& filePath, int type) {
std::ifstream fileStream(filePath);
if(!fileStream.good()) {
info("Cached %s not found, downloading a new one.\n", filePath.c_str());
return nullptr;
}
fileStream.seekg(0, std::ios_base::end);
size_t dataSize = fileStream.tellg();
fileStream.seekg(0, std::ios_base::beg);
std::allocator<uint8_t> alloc;
char *data = nullptr;
if(!(data = (char *)alloc.allocate(dataSize))) {
error("%s: failed to allocate memory for %s\n", __func__, filePath.c_str());
return nullptr;
}
fileStream.read((char *) data,
(std::streamsize) dataSize);
if(*(uint64_t *)(data) == 0) {
error("%s: failed to load File for %s with the size %zu!\n",
__func__, filePath.c_str(), dataSize);
return nullptr;
}
auto *fileHash = (unsigned char *)nullptr;
switch(type) {
case 0:
fileHash = (unsigned char *) alloc.allocate(48);
SHA384((const unsigned char*)data, (unsigned int)dataSize, fileHash);
break;
case 1:
fileHash = (unsigned char *) alloc.allocate(32);
SHA256((const unsigned char*)data, (unsigned int)dataSize, fileHash);
break;
case 2:
fileHash = (unsigned char *) alloc.allocate(64);
SHA512((const unsigned char*)data, (unsigned int)dataSize, fileHash);
break;
case 3:
fileHash = (unsigned char *) alloc.allocate(20);
SHA1((const unsigned char*)data, (unsigned int)dataSize, fileHash);
break;
default:
fileHash = (unsigned char *) alloc.allocate(48);
SHA384((const unsigned char*)data, (unsigned int)dataSize, fileHash);
break;
}
return fileHash;
}
#pragma mark static methods
inline void futurerestore::saveStringToFile(std::string str, std::string path) {
@ -2094,7 +2261,7 @@ plist_t futurerestore::loadPlistFromFile(const char *path) {
FILE *f = fopen(path, "rb");
if (!f) {
error("could not open file %s\n", path);
error("Could not open file %s\n", path);
return nullptr;
}
fseek(f, 0, SEEK_END);
@ -2138,11 +2305,31 @@ char *futurerestore::getPathOfElementInManifest(const char *element, const char
if (plist_get_string_val(path, &pathStr), pathStr)
goto noerror;
reterror("could not get %s path\n", element);
reterror("Could not get %s path\n", element);
noerror:
return pathStr;
}
unsigned char *futurerestore::getDigestOfElementInManifest(const char *element, const char *manifeststr, const char *boardConfig,
int isUpdateInstall) {
char *digestStr = nullptr;
ptr_smart<plist_t> buildmanifest(NULL, plist_free);
uint64_t size;
plist_from_xml(manifeststr, (uint32_t) strlen(manifeststr), &buildmanifest);
if (plist_t identity = getBuildidentityWithBoardconfig(buildmanifest._p, boardConfig, isUpdateInstall))
if (plist_t manifest = plist_dict_get_item(identity, "Manifest"))
if (plist_t elem = plist_dict_get_item(manifest, element))
if (plist_t path = plist_dict_get_item(elem, "Digest"))
if (plist_get_data_val(path, &digestStr, &size), digestStr)
goto noerror;
return nullptr;
noerror:
return (unsigned char *)digestStr;
}
bool
futurerestore::elemExists(const char *element, const char *manifeststr, const char *boardConfig, int isUpdateInstall) {
char *pathStr = nullptr;

View file

@ -63,7 +63,8 @@ class futurerestore {
bool _setNonce = false;
bool _serial = false;
bool _noRestore = false;
bool _noRSEP = false;
char *_firmwareJson = nullptr;
char *_betaFirmwareJson = nullptr;
jssytok_t *_firmwareTokens = nullptr;;
@ -75,9 +76,12 @@ class futurerestore {
bool _useCustomLatestBeta = false;
std::string _customLatest;
std::string _customLatestBuildID;
const char *_model = nullptr;
const char *_board = nullptr;
plist_t _sepbuildmanifest = nullptr;
plist_t _basebandbuildmanifest = nullptr;
plist_t _buildidentity = nullptr;
std::string _ramdiskPath;
std::string _kernelPath;
@ -98,7 +102,7 @@ class futurerestore {
void enterPwnRecovery(plist_t build_identity, std::string bootargs);
public:
futurerestore(bool isUpdateInstall = false, bool isPwnDfu = false, bool noIBSS = false, bool setNonce = false, bool serial = false, bool noRestore = false);
futurerestore(bool isUpdateInstall = false, bool isPwnDfu = false, bool noIBSS = false, bool setNonce = false, bool serial = false, bool noRestore = false, bool noRSEP = false);
bool init();
int getDeviceMode(bool reRequest);
uint64_t getDeviceEcid();
@ -138,6 +142,7 @@ public:
void loadKernel(std::string kernelPath);
void loadSep(std::string sepPath);
void loadBaseband(std::string basebandPath);
unsigned char *getSHA(const std::string& filePath, int type = 0);
void setCustomLatest(std::string version){_customLatest = version; _useCustomLatest = true;}
void setCustomLatestBuildID(std::string version, bool beta){_customLatestBuildID = version; _useCustomLatest = false; _useCustomLatestBuildID = true; _useCustomLatestBeta = beta;}
@ -171,8 +176,10 @@ public:
static plist_t loadPlistFromFile(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 unsigned char *getDigestOfElementInManifest(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);
};
#endif /* futurerestore_hpp */

View file

@ -44,6 +44,7 @@ static struct option longopts[] = {
{ "no-restore", no_argument, nullptr, 'z' },
{ "latest-baseband", no_argument, nullptr, '1' },
{ "no-baseband", no_argument, nullptr, '2' },
{ "no-rsep", no_argument, nullptr, 'j' },
#ifdef HAVE_LIBIPATCHER
{ "use-pwndfu", no_argument, nullptr, '3' },
{ "no-ibss", no_argument, nullptr, '4' },
@ -76,6 +77,7 @@ static struct option longopts[] = {
#define FLAG_CUSTOM_LATEST 1 << 15
#define FLAG_CUSTOM_LATEST_BUILDID 1 << 16
#define FLAG_CUSTOM_LATEST_BETA 1 << 17
#define FLAG_NO_RSEP_FR 1 << 18
void cmd_help(){
printf("Usage: futurerestore [OPTIONS] iPSW\n");
@ -111,6 +113,7 @@ void cmd_help(){
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(" -j, --no-rsep\t\tChoose not to send Restore Mode SEP\n");
printf("\nOptions for baseband:\n");
printf(" --latest-baseband\t\t\tUse latest signed baseband instead of manually specifying one\n");
@ -167,7 +170,7 @@ int main_r(int argc, const char * argv[]) {
return -1;
}
while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:c:g:hiwude0z123456789af", longopts, &optindex)) > 0) {
while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:c:g:hiwude0z123456789afj", longopts, &optindex)) > 0) {
switch (opt) {
case 'h': // long option: "help"; can be called as short option
cmd_help();
@ -214,6 +217,9 @@ int main_r(int argc, const char * argv[]) {
case '2': // long option: "no-baseband";
flags |= FLAG_NO_BASEBAND;
break;
case 'j': // long option: "no-rsep";
flags |= FLAG_NO_RSEP_FR;
break;
#ifdef HAVE_LIBIPATCHER
case '3': // long option: "use-pwndfu";
flags |= FLAG_IS_PWN_DFU;
@ -286,7 +292,7 @@ int main_r(int argc, const char * argv[]) {
return -5;
}
futurerestore client(flags & FLAG_UPDATE, flags & FLAG_IS_PWN_DFU, flags & FLAG_NO_IBSS, flags & FLAG_SET_NONCE, flags & FLAG_SERIAL, flags & FLAG_NO_RESTORE_FR);
futurerestore client(flags & FLAG_UPDATE, flags & FLAG_IS_PWN_DFU, flags & FLAG_NO_IBSS, flags & FLAG_SET_NONCE, flags & FLAG_SERIAL, flags & FLAG_NO_RESTORE_FR, flags & FLAG_NO_RSEP_FR);
retassure(client.init(),"can't init, no device found\n");
printf("futurerestore init done\n");
@ -384,7 +390,7 @@ int main_r(int argc, const char * argv[]) {
}
if (flags & FLAG_LATEST_SEP){
info("user specified to use latest signed SEP\n");
info("User specified to use latest signed SEP\n");
client.downloadLatestSep();
}else if (!client.is32bit()){
client.setSepPath(sepPath);
@ -394,38 +400,44 @@ int main_r(int argc, const char * argv[]) {
}
versVals.basebandMode = kBasebandModeWithoutBaseband;
if (!client.is32bit() && !(isManifestSignedForDevice(client.getSepManifestPath().c_str(), &devVals, &versVals, nullptr))){
info("Checking if SEP is being signed...\n");
if (!client.is32bit() && !(isManifestSignedForDevice(client.getSepManifestPath().c_str(), &devVals, &versVals, nullptr))) {
reterror("SEP firmware is NOT being signed!\n");
} else {
info("SEP is being signed!\n");
}
if (flags & FLAG_NO_BASEBAND){
printf("\nWARNING: user specified is not to flash a baseband. This can make the restore fail if the device needs a baseband!\n");
printf("if you added this flag by mistake, you can press CTRL-C now to cancel\n");
info("\nWARNING: user specified is not to flash a baseband. This can make the restore fail if the device needs a baseband!\n");
info("\nIf you added this flag by mistake, you can press CTRL-C now to cancel\n");
int c = 10;
printf("continuing restore in ");
info("Continuing restore in ");
while (c) {
printf("%d ",c--);
info("%d ",c--);
fflush(stdout);
sleep(1);
}
printf("\n");
info("");
}else{
if (flags & FLAG_LATEST_BASEBAND){
info("user specified to use latest signed baseband\n");
info("User specified to use latest signed baseband\n");
client.downloadLatestBaseband();
}else{
client.setBasebandPath(basebandPath);
client.setBasebandManifestPath(basebandManifestPath);
client.loadBaseband(basebandPath);
client.loadBasebandManifest(basebandManifestPath);
printf("Did set SEP+baseband path and firmware\n");
info("Did set SEP and baseband path and firmware\n");
}
versVals.basebandMode = kBasebandModeOnlyBaseband;
if (!(devVals.bbgcid = client.getBasebandGoldCertIDFromDevice())){
printf("[WARNING] using tsschecker's fallback to get BasebandGoldCertID. This might result in invalid baseband signing status information\n");
debug("[WARNING] using tsschecker's fallback to get BasebandGoldCertID. This might result in invalid baseband signing status information\n");
}
info("Checking if Baseband is being signed...\n");
if (!(isManifestSignedForDevice(client.getBasebandManifestPath().c_str(), &devVals, &versVals, nullptr))) {
reterror("baseband firmware is NOT being signed!\n");
reterror("Baseband firmware is NOT being signed!\n");
} else {
info("Baseband is being signed!\n");
}
}