diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7bd06a80..fe77546b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,14 @@ jobs: /Users/runner/work/futurerestore/futurerestore/.github/workflows/mac-bootstrap.sh /Users/runner/work/futurerestore/futurerestore/.github/workflows/mac-build.sh /Users/runner/work/futurerestore/futurerestore/.github/workflows/mac-post.sh + - name: Versioning + id: Versioning + uses: actions/upload-artifact@v2 + with: + name: Versioning + path: | + /Users/runner/work/futurerestore/futurerestore/latest_build_sha.txt + /Users/runner/work/futurerestore/futurerestore/latest_build_num.txt - name: macOS RELEASE Archive id: macOS-RELEASE-Archive uses: actions/upload-artifact@v2 diff --git a/.github/workflows/mac-build.sh b/.github/workflows/mac-build.sh index 6bf6fa75..1eed94b9 100755 --- a/.github/workflows/mac-build.sh +++ b/.github/workflows/mac-build.sh @@ -32,4 +32,6 @@ make -j4 -l4 -C cmake-build-asan-arm64 llvm-strip -s cmake-build-release-x86_64/src/futurerestore +codesign --deep --force --sign - cmake-build-release-x86_64/src/futurerestore llvm-strip -s cmake-build-release-arm64/src/futurerestore +codesign --deep --force --sign - cmake-build-release-arm64/src/futurerestore diff --git a/.github/workflows/mac-post.sh b/.github/workflows/mac-post.sh index 16a8e908..89884ab0 100755 --- a/.github/workflows/mac-post.sh +++ b/.github/workflows/mac-post.sh @@ -7,12 +7,18 @@ export BASE=/Users/runner/work/futurerestore/futurerestore/ cd ${BASE} export FUTURERESTORE_VERSION=$(git rev-list --count HEAD | tr -d '\n') +export FUTURERESTORE_VERSION_SHA=$(git rev-parse HEAD | tr -d '\n') export FUTURERESTORE_VERSION_RELEASE=$(cat version.txt | tr -d '\n') +echo -n $FUTURERESTORE_VERSION_SHA > latest_build_sha.txt +echo -n $FUTURERESTORE_VERSION > latest_build_num.txt lipo -create -arch x86_64 cmake-build-release-x86_64/src/futurerestore -arch arm64 cmake-build-release-arm64/src/futurerestore -output futurerestore +codesign --deep --force --sign - futurerestore tar cpPJf "futurerestore-macOS-${FUTURERESTORE_VERSION_RELEASE}-Build_${FUTURERESTORE_VERSION}-RELEASE.tar.xz" futurerestore rm -rf futurerestore lipo -create -arch x86_64 cmake-build-debug-x86_64/src/futurerestore -arch arm64 cmake-build-debug-arm64/src/futurerestore -output futurerestore +codesign --deep --force --sign - futurerestore tar cpPJf "futurerestore-macOS-${FUTURERESTORE_VERSION_RELEASE}-Build_${FUTURERESTORE_VERSION}-DEBUG.tar.xz" futurerestore rm -rf futurerestore lipo -create -arch x86_64 cmake-build-asan-x86_64/src/futurerestore -arch arm64 cmake-build-asan-arm64/src/futurerestore -output futurerestore +codesign --deep --force --sign - futurerestore tar cpPJf "futurerestore-macOS-${FUTURERESTORE_VERSION_RELEASE}-Build_${FUTURERESTORE_VERSION}-ASAN.tar.xz" futurerestore diff --git a/.gitignore b/.gitignore index d47f54ea..dc3d603d 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,6 @@ xcuserdata *.zst *.shsh2 *.shsh +.cmake +Testing +*.cbp diff --git a/CMakeLists.txt b/CMakeLists.txt index b70817ac..e78d1fd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ if("${CMAKE_HOST_SYSTEM_NAME}" MATCHES "Darwin") set(ARCH "${CMAKE_SYSTEM_PROCESSOR}") endif() endif() - if(NOT DEFINED MINVER OR NOT DEFINED "$ENV{MINVER}" AND DEFINED NO_PKGCFG AND "$ENV{NO_PKGCFG}" MATCHES "1") + if((NOT DEFINED MINVER OR NOT DEFINED "$ENV{MINVER}") AND (DEFINED NO_PKGCFG OR "$ENV{NO_PKGCFG}" MATCHES "1")) if("${ARCH}" STREQUAL "x86_64" OR "$ENV{ARCH}" STREQUAL "x86_64") set(MINVER -mmacosx-version-min=10.12) set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) diff --git a/README.md b/README.md index 9f930fe8..9f71c442 100644 --- a/README.md +++ b/README.md @@ -44,26 +44,29 @@ Usage: `futurerestore [OPTIONS] iPSW` | ` -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 | +| ` -3 ` | ` --use-pwndfu ` | Restoring devices with Odysseus method. Device needs to be in pwned DFU mode already | +| ` -4 ` | ` --no-ibss ` | Restoring devices with Odysseus method. For checkm8/iPwnder32 specifically, bootrom needs to be patched already with unless iPwnder. | +| ` -5 ` | ` --rdsk PATH ` | Set custom restore ramdisk for entering restoremode(requires use-pwndfu) | +| ` -6 ` | ` --rkrn PATH ` | Set custom restore kernelcache for entering restoremode(requires use-pwndfu) | +| ` -7 ` | ` --set-nonce ` | Set custom nonce from your blob then exit recovery(requires use-pwndfu) | +| ` -7 ` | ` --set-nonce=0xNONCE ` | Set custom nonce then exit recovery(requires use-pwndfu) | +| ` -8 ` | ` --serial ` | Enable serial during boot(requires serial cable and use-pwndfu) | +| ` -9 ` | ` --boot-args "BOOTARGS" ` | Set custom restore boot-args(PROCEED WITH CAUTION)(requires use-pwndfu) | +| ` -a ` | ` --no-cache ` | Disable cached patched iBSS/iBEC(requires use-pwndfu) | +| ` -f ` | ` --skip-blob ` | Skip SHSH blob validation(PROCEED WITH CAUTION)(requires use-pwndfu) | +| ` -0 ` | ` --latest-sep ` | Use latest signed SEP instead of manually specifying one | +| ` -j ` | ` --no-rsep ` | Choose not to send Restore Mode SEP firmware command | +| ` -1 ` | ` --latest-baseband ` | Use latest signed baseband instead of manually specifying one | +| ` -2 ` | ` --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) | +Deprecated/Legacy Options: + +| option (short) | option (long) | description | +|----------------|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | ` -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) Prometheus (64-bit device) - APNonce recreation with generator method diff --git a/external/idevicerestore b/external/idevicerestore index 97ab482c..46039a32 160000 --- a/external/idevicerestore +++ b/external/idevicerestore @@ -1 +1 @@ -Subproject commit 97ab482cf251b83e71887f9cd7a8f1d9e066e671 +Subproject commit 46039a322f595e60a9c089a25f302fc80238e8c8 diff --git a/external/tsschecker b/external/tsschecker index 6e55c67e..ad4c0d92 160000 --- a/external/tsschecker +++ b/external/tsschecker @@ -1 +1 @@ -Subproject commit 6e55c67ec78df55b8185c17ea2f79f838d0c034b +Subproject commit ad4c0d92f42e2cd2e90efdb38ed7fc11dd356656 diff --git a/src/futurerestore.cpp b/src/futurerestore.cpp index a2f69575..5fd70867 100644 --- a/src/futurerestore.cpp +++ b/src/futurerestore.cpp @@ -77,7 +77,7 @@ void safe_mkdir(const char *path, int mode) { seteuid(newID); setegid(newID); } - mkdir(path, mode); + __mkdir(path, mode); if(newID > -1) { setuid(id); setgid(id1); @@ -140,10 +140,29 @@ futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu, bool noIBSS, b _setNonce(setNonce), _serial(serial), _noRestore(noRestore), _noRSEP(noRSEP) { _client = idevicerestore_client_new(); retassure(_client != nullptr, "Could not create idevicerestore client\n"); - struct stat st{0}; + char *tmpdir = std::getenv("TMPDIR"); + if(tmpdir != nullptr ) { + std::string TMPDIR(tmpdir); + if(!TMPDIR.empty() && stat(tmpdir, &st) > -1) { + futurerestoreTempPath = TMPDIR +"/futurerestore"; + roseTempPath = futurerestoreTempPath + "/rose.bin"; + seTempPath = futurerestoreTempPath + "/se.sefw"; + veridianDGMTempPath = futurerestoreTempPath + "/veridianDGM.der"; + veridianFWMTempPath = futurerestoreTempPath + "/veridianFWM.plist"; + basebandTempPath = futurerestoreTempPath + "/baseband.bbfw"; + basebandManifestTempPath = futurerestoreTempPath + "/basebandManifest.plist"; + sepTempPath = futurerestoreTempPath + "/sep.im4p"; + sepManifestTempPath = futurerestoreTempPath + "/sepManifest.plist"; + } + } if (stat(futurerestoreTempPath.c_str(), &st) == -1) safe_mkdir(futurerestoreTempPath.c_str(), 0755); +// TODO: implement windows CI and enable update check +#ifndef WIN32 + this->checkForUpdates(); +#endif + nocache = 1; //tsschecker nocache _foundnonce = -1; _useCustomLatest = false; @@ -2363,3 +2382,76 @@ std::string futurerestore::getGeneratorFromSHSH2(plist_t shsh2) { return {genstr}; } + +// TODO: implement windows CI and enable update check +#ifndef WIN32 + +void futurerestore::checkForUpdates() { + info("Checking for updates...\n\n"); + std::string num = futurerestoreTempPath + "/latest_build_num.txt"; + std::string sha = futurerestoreTempPath + "/latest_build_sha.txt"; + std::string url = "https://nightly.link/futurerestore/futurerestore/workflows/ci/main/Versioning.zip"; + bool fail = false; + if(downloadPartialzip(url.c_str(), "latest_build_num.txt", num.c_str())) { + fail = true; + } + if(downloadPartialzip(url.c_str(), "latest_build_sha.txt", sha.c_str())) { + fail = true; + } + struct stat st{0}; + if(fail || stat(num.c_str(), &st) == -1 || stat(sha.c_str(), &st) == -1) { + info("ERROR: failed to check for futurerestore updates! continuing...\n"); + return; + } + char *num_data = nullptr; + size_t num_size = 0; + std::ifstream numFileStream(num, std::ios::binary | std::ios::in | std::ios::ate); + retassure(numFileStream.good(), "%s: failed init file stream for %s!\n", __func__, num.c_str()); + num_size = numFileStream.tellg(); + numFileStream.seekg(0, std::ios_base::beg); + std::allocator alloc; + retassure(num_data = (char *)alloc.allocate(num_size), + "%s: failed to allocate memory for %s\n", __func__, num.c_str()); + numFileStream.read(reinterpret_cast(num_data), + num_size); + retassure(numFileStream.good(), "%s: failed to read file stream for %s!\n", __func__, num.c_str()); + retassure(*(uint64_t *) (num_data) != 0, + "%s: failed to load num versioning file for %s with the size %zu!\n", + __func__, num.c_str(), num_size); + this->latest_num = std::string(num_data); + char *sha_data = nullptr; + size_t sha_size = 0; + std::ifstream shaFileStream(sha, std::ios::binary | std::ios::in | std::ios::ate); + retassure(shaFileStream.good(), "%s: failed init file stream for %s!\n", __func__, sha.c_str()); + sha_size = shaFileStream.tellg(); + shaFileStream.seekg(0, std::ios_base::beg); + retassure(sha_data = (char *)alloc.allocate(sha_size), + "%s: failed to allocate memory for %s\n", __func__, sha.c_str()); + shaFileStream.read(reinterpret_cast(sha_data), + sha_size); + retassure(shaFileStream.good(), "%s: failed to read file stream for %s!\n", __func__, sha.c_str()); + retassure(*(uint64_t *) (sha_data) != 0, + "%s: failed to load sha versioning file for %s with the size %zu!\n", + __func__, sha.c_str(), sha_size); + this->latest_sha = std::string(sha_data); + if(this->latest_num.empty() || this->latest_sha.empty()) { + info("ERROR: failed to check for futurerestore updates! continuing...\n"); + return; + } + bool updated = false; + if(std::equal(this->current_sha.begin(), this->current_sha.end(), this->latest_sha.begin())) { + updated = true; + } else { + if(std::stoi(this->current_num) < std::stoi(this->latest_num)) { + info("Error: Futurerestore is outdated! Please download the latest futurerestore! exitting...\n"); + exit(-1); + } else { + updated = true; + } + } + if(updated) { + info("Futurerestore is up to date!\n"); + } +} + +#endif diff --git a/src/futurerestore.hpp b/src/futurerestore.hpp index e2e8c14c..bd93f45f 100644 --- a/src/futurerestore.hpp +++ b/src/futurerestore.hpp @@ -88,6 +88,15 @@ class futurerestore { std::string _basebandPath; std::string _basebandManifestPath; + +// TODO: implement windows CI and enable update check +#ifndef WIN32 + std::string latest_num; + std::string latest_sha; + std::string current_num = VERSION_COMMIT_COUNT; + std::string current_sha = VERSION_COMMIT_SHA; +#endif + const char *_custom_nonce = nullptr; const char *_boot_args = nullptr; @@ -122,6 +131,11 @@ public: char *getLatestFirmwareUrl(); std::string getSepManifestPath(){return _sepManifestPath;} std::string getBasebandManifestPath(){return _basebandManifestPath;} + +// TODO: implement windows CI and enable update check +#ifndef WIN32 + void checkForUpdates(); +#endif void downloadLatestRose(); void downloadLatestSE(); void downloadLatestSavage(); diff --git a/src/main.cpp b/src/main.cpp index 09881090..17c6570f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,6 +79,8 @@ static struct option longopts[] = { #define FLAG_CUSTOM_LATEST_BETA 1 << 17 #define FLAG_NO_RSEP_FR 1 << 18 +bool manual = false; + void cmd_help(){ printf("Usage: futurerestore [OPTIONS] iPSW\n"); printf("Allows restoring to non-matching firmware with custom SEP+baseband\n"); @@ -97,29 +99,33 @@ void cmd_help(){ #ifdef HAVE_LIBIPATCHER printf("\nOptions for downgrading with Odysseus:\n"); - printf(" --use-pwndfu\t\t\tRestoring devices with Odysseus method. Device needs to be in pwned DFU mode already\n"); - printf(" --no-ibss\t\t\t\tRestoring devices with Odysseus method. For checkm8/iPwnder32 specifically, bootrom needs to be patched already with unless iPwnder.\n"); - printf(" --rdsk PATH\t\t\tSet custom restore ramdisk for entering restoremode(requires use-pwndfu)\n"); - printf(" --rkrn PATH\t\t\tSet custom restore kernelcache for entering restoremode(requires use-pwndfu)\n"); - printf(" --set-nonce\t\t\tSet custom nonce from your blob then exit recovery(requires use-pwndfu)\n"); - printf(" --set-nonce=0xNONCE\t\tSet custom nonce then exit recovery(requires use-pwndfu)\n"); - printf(" --serial\t\t\t\tEnable serial during boot(requires serial cable and use-pwndfu)\n"); - printf(" --boot-args\t\t\tSet custom restore boot-args(PROCEED WITH CAUTION)(requires use-pwndfu)\n"); - printf(" --no-cache\t\t\tDisable cached patched iBSS/iBEC(requires use-pwndfu)\n"); - printf(" --skip-blob\t\t\tSkip SHSH blob validation(PROCEED WITH CAUTION)(requires use-pwndfu)\n"); + printf(" -3, --use-pwndfu\t\t\tRestoring devices with Odysseus method. Device needs to be in pwned DFU mode already\n"); + printf(" -4, --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(" -5, --rdsk PATH\t\t\tSet custom restore ramdisk for entering restoremode(requires use-pwndfu)\n"); + printf(" -6, --rkrn PATH\t\t\tSet custom restore kernelcache for entering restoremode(requires use-pwndfu)\n"); + printf(" -7, --set-nonce\t\t\tSet custom nonce from your blob then exit recovery(requires use-pwndfu)\n"); + printf(" -7, --set-nonce=0xNONCE\t\tSet custom nonce then exit recovery(requires use-pwndfu)\n"); + printf(" -8, --serial\t\t\t\tEnable serial during boot(requires serial cable and use-pwndfu)\n"); + printf(" -9, --boot-args\t\t\tSet custom restore boot-args(PROCEED WITH CAUTION)(requires use-pwndfu)\n"); + printf(" -a, --no-cache\t\t\tDisable cached patched iBSS/iBEC(requires use-pwndfu)\n"); + printf(" -f, --skip-blob\t\t\tSkip SHSH blob validation(PROCEED WITH CAUTION)(requires use-pwndfu)\n"); #endif printf("\nOptions for SEP:\n"); - printf(" --latest-sep\t\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(" -0, --latest-sep\t\t\tUse latest signed SEP instead of manually specifying one\n"); + if(manual) { + 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\t\t\tChoose not to send Restore Mode SEP firmware command\n"); printf("\nOptions for baseband:\n"); - printf(" --latest-baseband\t\t\tUse latest signed baseband instead of manually specifying one\n"); - printf(" -b, --baseband PATH\t\t\tBaseband to be flashed\n"); - printf(" -p, --baseband-manifest PATH\t\tBuildManifest for requesting baseband ticket\n"); - printf(" --no-baseband\t\t\tSkip checks and don't flash baseband\n"); + printf(" -1, --latest-baseband\t\t\tUse latest signed baseband instead of manually specifying one\n"); + if(manual) { + printf(" -b, --baseband PATH\t\t\tBaseband to be flashed\n"); + printf(" -p, --baseband-manifest PATH\t\tBuildManifest for requesting baseband ticket\n"); + } + printf(" -2, --no-baseband\t\t\tSkip checks and don't flash baseband\n"); printf(" \t\t\tOnly use this for device without a baseband (eg. iPod touch or some Wi-Fi only iPads)\n\n"); } @@ -165,6 +171,12 @@ int main_r(int argc, const char * argv[]) { t_devicevals devVals = {nullptr}; t_iosVersion versVals = {nullptr}; + char *legacy = std::getenv("FUTURERESTORE_I_SOLEMNLY_SWEAR_THAT_I_AM_UP_TO_NO_GOOD"); + manual = legacy != nullptr; + if(manual) { + info("WARNING: User specified to enable Deprecated/Legacy options, at risk of boot loop!\n"); + } + if (argc == 1){ cmd_help(); return -1; @@ -180,15 +192,19 @@ int main_r(int argc, const char * argv[]) { apticketPaths.push_back(optarg); break; case 'b': // long option: "baseband"; can be called as short option + retassure(manual, "--baseband is Deprecated!"); basebandPath = optarg; break; case 'p': // long option: "baseband-manifest"; can be called as short option + retassure(manual, "--baseband-manifest is Deprecated!"); basebandManifestPath = optarg; break; case 's': // long option: "sep"; can be called as short option + retassure(manual, "--sep is Deprecated!"); sepPath = optarg; break; case 'm': // long option: "sep-manifest"; can be called as short option + retassure(manual, "--sep-manifest is Deprecated!"); sepManifestPath = optarg; break; case 'w': // long option: "wait"; can be called as short option