From 698ce147c1df46e7c1d653cfcb8560dc78c52586 Mon Sep 17 00:00:00 2001 From: Elcomsoft R&D Date: Wed, 4 Nov 2026 11:38:34 +0900 Subject: [PATCH] opensource_v2 --- .gitignore | 3 + .gitmodules | 6 - Makefile.am | 3 +- README.md | 2 - autogen.sh | 27 +- configure.ac | 41 +- external/idevicerestore | 1 - external/tsschecker | 1 - futurerestore.xcodeproj/project.pbxproj | 288 +-- futurerestore/Makefile.am | 13 +- futurerestore/futurerestore.cpp | 2461 ++++++++++++----------- futurerestore/futurerestore.hpp | 173 +- futurerestore/main.cpp | 585 +++--- 13 files changed, 1749 insertions(+), 1855 deletions(-) delete mode 100644 .gitmodules delete mode 160000 external/idevicerestore delete mode 160000 external/tsschecker diff --git a/.gitignore b/.gitignore index dbd882a0..72eee85f 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ missing */futurerestore* stamp-h1 xcuserdata +Build +configure~ +xcshareddata \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 43ff96da..00000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "external/tsschecker"] - path = external/tsschecker - url = https://github.com/tihmstar/tsschecker.git -[submodule "external/idevicerestore"] - path = external/idevicerestore - url = https://github.com/tihmstar/idevicerestore.git diff --git a/Makefile.am b/Makefile.am index be54f0f1..965e1fe0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,3 @@ AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = external/idevicerestore external/tsschecker futurerestore -install installdirs: SUBDIRS = futurerestore +SUBDIRS = futurerestore diff --git a/README.md b/README.md index ba4ad093..30137b54 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,6 @@ __Only use if you are sure what you're doing.__ * [libirecovery](https://github.com/libimobiledevice/libirecovery); * [libimobiledevice](https://github.com/libimobiledevice/libimobiledevice); * [img4tool](https://github.com/tihmstar/img4tool); - * [liboffsetfinder64](https://github.com/tihmstar/liboffsetfinder64); - * [libipatcher](https://github.com/tihmstar/libipatcher) * ## Submodules Make sure these projects compile on your system (install it's dependencies): diff --git a/autogen.sh b/autogen.sh index 843745f6..dd9f03c4 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,27 +1,12 @@ #!/bin/bash -gprefix=`which glibtoolize 2>&1 >/dev/null` -if [ $? -eq 0 ]; then - glibtoolize --force -else - libtoolize --force -fi + +#cleanup cache for correct versioning when run multiple times +rm -rf autom4te.cache + + aclocal -I m4 autoconf autoheader automake --add-missing autoreconf -i - -export NOCONFIGURE=1 - -SUBDIRS="external/idevicerestore external/tsschecker" -for SUB in $SUBDIRS; do - pushd $SUB - ./autogen.sh - popd -done - -unset NOCONFIGURE - -if [ -z "$NOCONFIGURE" ]; then - ./configure "$@" -fi +./configure "$@" diff --git a/configure.ac b/configure.ac index 1d4d48b9..b8b4cd8b 100644 --- a/configure.ac +++ b/configure.ac @@ -27,9 +27,8 @@ case $host_os in esac # Checks the flags. -CFLAGS+=" -DIDEVICERESTORE_NOMAIN=1 -DTSSCHECKER_NOMAIN=1" -CXXFLAGS+=" -std=c++11" -CFLAGS+=" -std=c11" +CXXFLAGS+=" -std=c++17" +CFLAGS+=" -std=c17" AC_DEFUN([AX_UNPRECIOUS], [ m4_define([_AC_PRECIOUS_VARS], m4_bpatsubst(_AC_PRECIOUS_VARS, [$1], [])) @@ -37,18 +36,19 @@ AC_DEFUN([AX_UNPRECIOUS], [ AX_UNPRECIOUS([CFLAGS]) export CFLAGS -AC_CONFIG_SUBDIRS(external/idevicerestore external/tsschecker) AC_CONFIG_SRCDIR([futurerestore]) # Checks the libraries. -LIBIPATCHER_REQUIRES_STR="libipatcher >= 61" -LIBPLIST_REQUIRES_STR="libplist-2.0 >= 2.2.0" +LIBPLIST_REQUIRES_STR="libplist-2.0 >= 2.3.0" LIBZIP_REQUIRES_STR="libzip >= 0.10" LIBIMOBILEDEVICE_REQUIRES_STR="libimobiledevice-1.0 >= 1.2.1" LIBFRAGMENTZIP_REQUIRES_STR="libfragmentzip >= 47" +LIBFWKEYFETCH_REQUIRES_STR="libfwkeyfetch >= 1" LIBIRECOVERY_REQUIRES_STR="libirecovery-1.0 >= 1.0.0" IMG4TOOL_REQUIRES_STR="libimg4tool >= 162" LIBGENERAL_REQUIRES_STR="libgeneral >= 26" +LIBIDEVICERESTORE_REQUIRES_STR="libidevicerestore >= 1.0.0" +LIBRA1NSN0W_REQUIRES_STR="libra1nsn0w >= 158" PKG_CHECK_MODULES(libplist, $LIBPLIST_REQUIRES_STR) PKG_CHECK_MODULES(libzip, $LIBZIP_REQUIRES_STR) @@ -57,31 +57,9 @@ PKG_CHECK_MODULES(libfragmentzip, $LIBFRAGMENTZIP_REQUIRES_STR) PKG_CHECK_MODULES(libirecovery, $LIBIRECOVERY_REQUIRES_STR) PKG_CHECK_MODULES(libimg4tool, $IMG4TOOL_REQUIRES_STR) PKG_CHECK_MODULES(libgeneral, $LIBGENERAL_REQUIRES_STR) - -# Optional module libipatcher -AC_ARG_WITH([libipatcher], - [AS_HELP_STRING([--without-libipatcher], - [build with bundle-less odysseus support (default is yes)])], - [build_libipatcher=false], - [build_libipatcher=true]) - -PKG_PROG_PKG_CONFIG -LIBIPATCHER_FLAGS=$($PKG_CONFIG --cflags libipatcher) -if [test -z "$LIBIPATCHER_FLAGS"]; then - do_libipatcher=no -else - AC_MSG_CHECKING([for futurerestore libipatcher]) - if test "$build_libipatcher" = "true"; then - PKG_CHECK_MODULES(libipatcher, $LIBIPATCHER_REQUIRES_STR) - AC_DEFINE(HAVE_LIBIPATCHER, 1, [Define if you have libipatcher]) - do_libipatcher=yes - else - do_libipatcher=no - fi -fi -AM_CONDITIONAL([HAVE_LIBIPATCHER],[test "x$do_libipatcher" = "xyes"]) - -AC_DEFINE(CUSTOM_LOGGING, 1, [required for futurerestore]) +PKG_CHECK_MODULES(libidevicerestore, $LIBIDEVICERESTORE_REQUIRES_STR) +PKG_CHECK_MODULES(libra1nsn0w, $LIBRA1NSN0W_REQUIRES_STR) +PKG_CHECK_MODULES(libfwkeyfetch, $LIBFWKEYFETCH_REQUIRES_STR) LT_INIT @@ -95,7 +73,6 @@ Configuration for $PACKAGE $VERSION: ------------------------------------------- Install prefix ..........: $prefix - With libipatcher ........: $do_libipatcher Now type 'make' to build $PACKAGE $VERSION, and then 'make install' for installation. " diff --git a/external/idevicerestore b/external/idevicerestore deleted file mode 160000 index c97e02e2..00000000 --- a/external/idevicerestore +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c97e02e22b9971471db5dcb3b9e02eb30222d6c0 diff --git a/external/tsschecker b/external/tsschecker deleted file mode 160000 index b9d193aa..00000000 --- a/external/tsschecker +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b9d193aa6e6d24421094873c830692d02d8b32f5 diff --git a/futurerestore.xcodeproj/project.pbxproj b/futurerestore.xcodeproj/project.pbxproj index f3360cdb..f8e680f9 100644 --- a/futurerestore.xcodeproj/project.pbxproj +++ b/futurerestore.xcodeproj/project.pbxproj @@ -7,45 +7,32 @@ objects = { /* Begin PBXBuildFile section */ - 5669111D23B3D86E00C93279 /* libbz2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669111C23B3D86E00C93279 /* libbz2.a */; }; - 5669111F23B3D88200C93279 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669111E23B3D88200C93279 /* libcrypto.a */; }; - 5669112123B3D89B00C93279 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112023B3D89B00C93279 /* libcurl.tbd */; }; - 5669112323B3D89E00C93279 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112223B3D89E00C93279 /* libz.tbd */; }; - 5669112523B3D8B200C93279 /* libfragmentzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112423B3D8B200C93279 /* libfragmentzip.a */; }; - 5669112723B3D8BE00C93279 /* libgeneral.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112623B3D8BE00C93279 /* libgeneral.a */; }; - 5669112923B3D8CF00C93279 /* libimg4tool.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112823B3D8CE00C93279 /* libimg4tool.a */; }; - 5669112B23B3D8DA00C93279 /* libimobiledevice.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112A23B3D8DA00C93279 /* libimobiledevice.a */; }; - 5669112D23B3D8E200C93279 /* libipatcher.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112C23B3D8E200C93279 /* libipatcher.a */; }; - 5669112F23B3D8ED00C93279 /* libirecovery.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112E23B3D8ED00C93279 /* libirecovery.a */; }; - 5669113123B3D91B00C93279 /* libpartialzip-1.0.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669113023B3D91B00C93279 /* libpartialzip-1.0.a */; }; - 5669113323B3D92B00C93279 /* libplist.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669113223B3D92B00C93279 /* libplist.a */; }; - 5669113523B3D94300C93279 /* libzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669113423B3D94300C93279 /* libzip.a */; }; + 2A3E771029ACA1590079E6B4 /* libimg3tool.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A3E770F29ACA1590079E6B4 /* libimg3tool.0.dylib */; }; + 2A3E771129ACA1590079E6B4 /* libimg3tool.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2A3E770F29ACA1590079E6B4 /* libimg3tool.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2A4C882A2DF810E10010BA7E /* libfwkeyfetch.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A4C88292DF810E10010BA7E /* libfwkeyfetch.0.dylib */; }; + 2A4C882B2DF810E10010BA7E /* libfwkeyfetch.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2A4C88292DF810E10010BA7E /* libfwkeyfetch.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2A76ED882A5BFBED0074B9E4 /* libtsschecker.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A76ED872A5BFBED0074B9E4 /* libtsschecker.0.dylib */; }; + 2A76ED892A5BFBED0074B9E4 /* libtsschecker.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2A76ED872A5BFBED0074B9E4 /* libtsschecker.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2A8D85DB296D7056004894E4 /* libra1nsn0w.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A8D85DA296D7056004894E4 /* libra1nsn0w.0.dylib */; }; + 2A8D85DC296D7056004894E4 /* libra1nsn0w.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2A8D85DA296D7056004894E4 /* libra1nsn0w.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2A8D85DE296D75B1004894E4 /* libpatchfinder.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A8D85DD296D75B1004894E4 /* libpatchfinder.0.dylib */; }; + 2A8D85DF296D75B1004894E4 /* libpatchfinder.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2A8D85DD296D75B1004894E4 /* libpatchfinder.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2AC7AB922A8279A0004F21C9 /* libplist-2.0.4.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AC7AB912A8279A0004F21C9 /* libplist-2.0.4.dylib */; }; + 2AC7AB932A8279A0004F21C9 /* libplist-2.0.4.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2AC7AB912A8279A0004F21C9 /* libplist-2.0.4.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2AE12620296C1F6B0051DB0F /* libgeneral.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AE1261F296C1F6B0051DB0F /* libgeneral.0.dylib */; }; + 2AE12621296C1F6B0051DB0F /* libgeneral.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2AE1261F296C1F6B0051DB0F /* libgeneral.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2AE12626296C1F830051DB0F /* libidevicerestore.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AE12625296C1F830051DB0F /* libidevicerestore.0.dylib */; }; + 2AE12627296C1F830051DB0F /* libidevicerestore.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2AE12625296C1F830051DB0F /* libidevicerestore.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2AE1262C296C24560051DB0F /* libimobiledevice-glue-1.0.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AE1262B296C24560051DB0F /* libimobiledevice-glue-1.0.0.dylib */; }; + 2AE1262D296C24560051DB0F /* libimobiledevice-glue-1.0.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2AE1262B296C24560051DB0F /* libimobiledevice-glue-1.0.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2AE12632296C278E0051DB0F /* libimobiledevice-1.0.6.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AE12631296C278E0051DB0F /* libimobiledevice-1.0.6.dylib */; }; + 2AE12633296C278E0051DB0F /* libimobiledevice-1.0.6.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2AE12631296C278E0051DB0F /* libimobiledevice-1.0.6.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2AE12635296C306A0051DB0F /* libimg4tool.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AE12634296C306A0051DB0F /* libimg4tool.0.dylib */; }; + 2AE12636296C306A0051DB0F /* libimg4tool.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2AE12634296C306A0051DB0F /* libimg4tool.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 2AF0D6332C63BFA000CDBC03 /* libirecovery-1.0.5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AF0D6322C63BFA000CDBC03 /* libirecovery-1.0.5.dylib */; }; + 2AF0D6342C63BFA000CDBC03 /* libirecovery-1.0.5.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 2AF0D6322C63BFA000CDBC03 /* libirecovery-1.0.5.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 878587471D89CFDC008689F0 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 878587461D89CFDC008689F0 /* main.cpp */; }; 8799B0B21D89D99D002F4D5F /* futurerestore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8799B0B01D89D99D002F4D5F /* futurerestore.cpp */; }; - 8799B0B31D89DAE7002F4D5F /* idevicerestore.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785875C1D89D1C1008689F0 /* idevicerestore.c */; }; - 8799B0B41D89DAF6002F4D5F /* tss.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587761D89D1C1008689F0 /* tss.c */; }; - 8799B0B51D89DAFF002F4D5F /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587511D89D1C1008689F0 /* common.c */; }; - 8799B0B61D89DAFF002F4D5F /* dfu.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587531D89D1C1008689F0 /* dfu.c */; }; - 8799B0B71D89DAFF002F4D5F /* normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785876C1D89D1C1008689F0 /* normal.c */; }; - 8799B0B81D89DAFF002F4D5F /* recovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785876E1D89D1C1008689F0 /* recovery.c */; }; - 8799B0B91D89DB0D002F4D5F /* img3.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785875E1D89D1C1008689F0 /* img3.c */; }; - 8799B0BB1D89DB12002F4D5F /* download.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587551D89D1C1008689F0 /* download.c */; settings = {COMPILER_FLAGS = "-DPACKAGE_VERSION=\"\""; }; }; - 8799B0BC1D89DB27002F4D5F /* ipsw.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587621D89D1C1008689F0 /* ipsw.c */; }; - 8799B0BD1D89DB27002F4D5F /* limera1n.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587641D89D1C1008689F0 /* limera1n.c */; }; - 8799B0BE1D89DB27002F4D5F /* restore.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587701D89D1C1008689F0 /* restore.c */; }; - 8799B0BF1D89DB38002F4D5F /* asr.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785874F1D89D1C1008689F0 /* asr.c */; }; - 8799B0C01D89DB38002F4D5F /* fdr.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587581D89D1C1008689F0 /* fdr.c */; }; - 8799B0C11D89DB38002F4D5F /* fls.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785875A1D89D1C1008689F0 /* fls.c */; }; - 8799B0C21D89DB46002F4D5F /* thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587741D89D1C1008689F0 /* thread.c */; }; - 8799B0C31D89DB4B002F4D5F /* socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587721D89D1C1008689F0 /* socket.c */; }; - 8799B0C41D89DB55002F4D5F /* mbn.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785876A1D89D1C1008689F0 /* mbn.c */; }; - 8799B0C51D89DB67002F4D5F /* locking.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587671D89D1C1008689F0 /* locking.c */; }; - 8799B0CA1D89E371002F4D5F /* img4.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587601D89D1C1008689F0 /* img4.c */; }; - 8799B0CB1D89F796002F4D5F /* tsschecker.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785879F1D89D2BA008689F0 /* tsschecker.c */; }; - 8799B0CC1D89F7B9002F4D5F /* download.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587981D89D2BA008689F0 /* download.c */; }; - 87B517C3236EF36B009EAB8F /* ftab.c in Sources */ = {isa = PBXBuildFile; fileRef = 87B517C1236EF36B009EAB8F /* ftab.c */; }; - 87B517C6236EF3B0009EAB8F /* json_plist.c in Sources */ = {isa = PBXBuildFile; fileRef = 87B517C5236EF3B0009EAB8F /* json_plist.c */; }; - 87B517C9236EF3CD009EAB8F /* jsmn.c in Sources */ = {isa = PBXBuildFile; fileRef = 87B517C7236EF3CD009EAB8F /* jsmn.c */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -55,6 +42,18 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 2AE12633296C278E0051DB0F /* libimobiledevice-1.0.6.dylib in Embed Libraries */, + 2AE12636296C306A0051DB0F /* libimg4tool.0.dylib in Embed Libraries */, + 2AC7AB932A8279A0004F21C9 /* libplist-2.0.4.dylib in Embed Libraries */, + 2A8D85DF296D75B1004894E4 /* libpatchfinder.0.dylib in Embed Libraries */, + 2A4C882B2DF810E10010BA7E /* libfwkeyfetch.0.dylib in Embed Libraries */, + 2AE1262D296C24560051DB0F /* libimobiledevice-glue-1.0.0.dylib in Embed Libraries */, + 2A3E771129ACA1590079E6B4 /* libimg3tool.0.dylib in Embed Libraries */, + 2AE12621296C1F6B0051DB0F /* libgeneral.0.dylib in Embed Libraries */, + 2AF0D6342C63BFA000CDBC03 /* libirecovery-1.0.5.dylib in Embed Libraries */, + 2AE12627296C1F830051DB0F /* libidevicerestore.0.dylib in Embed Libraries */, + 2A8D85DC296D7056004894E4 /* libra1nsn0w.0.dylib in Embed Libraries */, + 2A76ED892A5BFBED0074B9E4 /* libtsschecker.0.dylib in Embed Libraries */, ); name = "Embed Libraries"; runOnlyForDeploymentPostprocessing = 0; @@ -71,6 +70,21 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 2A3E770F29ACA1590079E6B4 /* libimg3tool.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libimg3tool.0.dylib; path = ../../../../usr/local/lib/libimg3tool.0.dylib; sourceTree = ""; }; + 2A4C88292DF810E10010BA7E /* libfwkeyfetch.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libfwkeyfetch.0.dylib; path = ../../../../usr/local/lib/libfwkeyfetch.0.dylib; sourceTree = ""; }; + 2A76ED872A5BFBED0074B9E4 /* libtsschecker.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libtsschecker.0.dylib; path = ../../../../usr/local/lib/libtsschecker.0.dylib; sourceTree = ""; }; + 2A8D85DA296D7056004894E4 /* libra1nsn0w.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libra1nsn0w.0.dylib; path = ../../../../usr/local/lib/libra1nsn0w.0.dylib; sourceTree = ""; }; + 2A8D85DD296D75B1004894E4 /* libpatchfinder.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpatchfinder.0.dylib; path = ../../../../usr/local/lib/libpatchfinder.0.dylib; sourceTree = ""; }; + 2AC7AB912A8279A0004F21C9 /* libplist-2.0.4.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libplist-2.0.4.dylib"; path = "../../../../usr/local/lib/libplist-2.0.4.dylib"; sourceTree = ""; }; + 2AE1261F296C1F6B0051DB0F /* libgeneral.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libgeneral.0.dylib; path = ../../../../usr/local/lib/libgeneral.0.dylib; sourceTree = ""; }; + 2AE12622296C1F760051DB0F /* libirecovery-1.0.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libirecovery-1.0.3.dylib"; path = "../../../../usr/local/lib/libirecovery-1.0.3.dylib"; sourceTree = ""; }; + 2AE12625296C1F830051DB0F /* libidevicerestore.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libidevicerestore.0.dylib; path = ../../../../usr/local/lib/libidevicerestore.0.dylib; sourceTree = ""; }; + 2AE12628296C1F9C0051DB0F /* libipatcher.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipatcher.0.dylib; path = ../../../../usr/local/lib/libipatcher.0.dylib; sourceTree = ""; }; + 2AE1262B296C24560051DB0F /* libimobiledevice-glue-1.0.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libimobiledevice-glue-1.0.0.dylib"; path = "../../../../usr/local/lib/libimobiledevice-glue-1.0.0.dylib"; sourceTree = ""; }; + 2AE1262E296C270B0051DB0F /* libplist-2.0.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libplist-2.0.3.dylib"; path = "../../../../usr/local/lib/libplist-2.0.3.dylib"; sourceTree = ""; }; + 2AE12631296C278E0051DB0F /* libimobiledevice-1.0.6.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libimobiledevice-1.0.6.dylib"; path = "../../../../usr/local/lib/libimobiledevice-1.0.6.dylib"; sourceTree = ""; }; + 2AE12634296C306A0051DB0F /* libimg4tool.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libimg4tool.0.dylib; path = ../../../../usr/local/lib/libimg4tool.0.dylib; sourceTree = ""; }; + 2AF0D6322C63BFA000CDBC03 /* libirecovery-1.0.5.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libirecovery-1.0.5.dylib"; path = "../../../../usr/local/lib/libirecovery-1.0.5.dylib"; sourceTree = ""; }; 5669111C23B3D86E00C93279 /* libbz2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbz2.a; path = ../../../../../usr/local/lib/libbz2.a; sourceTree = ""; }; 5669111E23B3D88200C93279 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = ../../../../../usr/local/lib/libcrypto.a; sourceTree = ""; }; 5669112023B3D89B00C93279 /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; }; @@ -86,60 +100,8 @@ 5669113423B3D94300C93279 /* libzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libzip.a; path = ../../../../../usr/local/lib/libzip.a; sourceTree = ""; }; 878587431D89CFDC008689F0 /* futurerestore */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = futurerestore; sourceTree = BUILT_PRODUCTS_DIR; }; 878587461D89CFDC008689F0 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; - 8785874F1D89D1C1008689F0 /* asr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asr.c; sourceTree = ""; }; - 878587501D89D1C1008689F0 /* asr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asr.h; sourceTree = ""; }; - 878587511D89D1C1008689F0 /* common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = common.c; sourceTree = ""; }; - 878587521D89D1C1008689F0 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; - 878587531D89D1C1008689F0 /* dfu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dfu.c; sourceTree = ""; }; - 878587541D89D1C1008689F0 /* dfu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dfu.h; sourceTree = ""; }; - 878587551D89D1C1008689F0 /* download.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = download.c; sourceTree = ""; }; - 878587561D89D1C1008689F0 /* download.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = download.h; sourceTree = ""; }; - 878587571D89D1C1008689F0 /* endianness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endianness.h; sourceTree = ""; }; - 878587581D89D1C1008689F0 /* fdr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fdr.c; sourceTree = ""; }; - 878587591D89D1C1008689F0 /* fdr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fdr.h; sourceTree = ""; }; - 8785875A1D89D1C1008689F0 /* fls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fls.c; sourceTree = ""; }; - 8785875B1D89D1C1008689F0 /* fls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fls.h; sourceTree = ""; }; - 8785875C1D89D1C1008689F0 /* idevicerestore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = idevicerestore.c; sourceTree = ""; }; - 8785875D1D89D1C1008689F0 /* idevicerestore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = idevicerestore.h; sourceTree = ""; }; - 8785875E1D89D1C1008689F0 /* img3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = img3.c; sourceTree = ""; }; - 8785875F1D89D1C1008689F0 /* img3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = img3.h; sourceTree = ""; }; - 878587601D89D1C1008689F0 /* img4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = img4.c; sourceTree = ""; }; - 878587611D89D1C1008689F0 /* img4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = img4.h; sourceTree = ""; }; - 878587621D89D1C1008689F0 /* ipsw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ipsw.c; sourceTree = ""; }; - 878587631D89D1C1008689F0 /* ipsw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsw.h; sourceTree = ""; }; - 878587641D89D1C1008689F0 /* limera1n.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = limera1n.c; sourceTree = ""; }; - 878587651D89D1C1008689F0 /* limera1n.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = limera1n.h; sourceTree = ""; }; - 878587661D89D1C1008689F0 /* limera1n_payload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = limera1n_payload.h; sourceTree = ""; }; - 878587671D89D1C1008689F0 /* locking.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locking.c; sourceTree = ""; }; - 878587681D89D1C1008689F0 /* locking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = locking.h; sourceTree = ""; }; - 8785876A1D89D1C1008689F0 /* mbn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mbn.c; sourceTree = ""; }; - 8785876B1D89D1C1008689F0 /* mbn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mbn.h; sourceTree = ""; }; - 8785876C1D89D1C1008689F0 /* normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = normal.c; sourceTree = ""; }; - 8785876D1D89D1C1008689F0 /* normal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = normal.h; sourceTree = ""; }; - 8785876E1D89D1C1008689F0 /* recovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = recovery.c; sourceTree = ""; }; - 8785876F1D89D1C1008689F0 /* recovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = recovery.h; sourceTree = ""; }; - 878587701D89D1C1008689F0 /* restore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = restore.c; sourceTree = ""; }; - 878587711D89D1C1008689F0 /* restore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = restore.h; sourceTree = ""; }; - 878587721D89D1C1008689F0 /* socket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = socket.c; sourceTree = ""; }; - 878587731D89D1C1008689F0 /* socket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = socket.h; sourceTree = ""; }; - 878587741D89D1C1008689F0 /* thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = thread.c; sourceTree = ""; }; - 878587751D89D1C1008689F0 /* thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thread.h; sourceTree = ""; }; - 878587761D89D1C1008689F0 /* tss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tss.c; sourceTree = ""; }; - 878587771D89D1C1008689F0 /* tss.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tss.h; sourceTree = ""; }; - 878587981D89D2BA008689F0 /* download.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = download.c; sourceTree = ""; }; - 878587991D89D2BA008689F0 /* download.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = download.h; sourceTree = ""; }; - 8785879A1D89D2BA008689F0 /* jssy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = jssy.c; path = ../external/jssy/jssy/jssy.c; sourceTree = ""; }; - 8785879B1D89D2BA008689F0 /* jssy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jssy.h; path = ../external/jssy/jssy/jssy.h; sourceTree = ""; }; - 8785879F1D89D2BA008689F0 /* tsschecker.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tsschecker.c; sourceTree = ""; }; - 878587A01D89D2BA008689F0 /* tsschecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tsschecker.h; sourceTree = ""; }; 8799B0B01D89D99D002F4D5F /* futurerestore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = futurerestore.cpp; sourceTree = ""; }; 8799B0B11D89D99D002F4D5F /* futurerestore.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = futurerestore.hpp; sourceTree = ""; }; - 87B517C1236EF36B009EAB8F /* ftab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ftab.c; sourceTree = ""; }; - 87B517C2236EF36B009EAB8F /* ftab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ftab.h; sourceTree = ""; }; - 87B517C4236EF3B0009EAB8F /* json_plist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_plist.h; sourceTree = ""; }; - 87B517C5236EF3B0009EAB8F /* json_plist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = json_plist.c; sourceTree = ""; }; - 87B517C7236EF3CD009EAB8F /* jsmn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jsmn.c; sourceTree = ""; }; - 87B517C8236EF3CD009EAB8F /* jsmn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsmn.h; sourceTree = ""; }; 87F574C71E151DA6008D5C4D /* libcommonCrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcommonCrypto.tbd; path = usr/lib/system/libcommonCrypto.tbd; sourceTree = SDKROOT; }; 87F574CC1E151EF8008D5C4D /* libcorecrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcorecrypto.tbd; path = usr/lib/system/libcorecrypto.tbd; sourceTree = SDKROOT; }; 87F574CE1E151F11008D5C4D /* libSystem.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libSystem.tbd; path = usr/lib/libSystem.tbd; sourceTree = SDKROOT; }; @@ -150,19 +112,18 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5669113323B3D92B00C93279 /* libplist.a in Frameworks */, - 5669111D23B3D86E00C93279 /* libbz2.a in Frameworks */, - 5669112523B3D8B200C93279 /* libfragmentzip.a in Frameworks */, - 5669112923B3D8CF00C93279 /* libimg4tool.a in Frameworks */, - 5669112D23B3D8E200C93279 /* libipatcher.a in Frameworks */, - 5669112B23B3D8DA00C93279 /* libimobiledevice.a in Frameworks */, - 5669112F23B3D8ED00C93279 /* libirecovery.a in Frameworks */, - 5669113123B3D91B00C93279 /* libpartialzip-1.0.a in Frameworks */, - 5669112723B3D8BE00C93279 /* libgeneral.a in Frameworks */, - 5669112123B3D89B00C93279 /* libcurl.tbd in Frameworks */, - 5669112323B3D89E00C93279 /* libz.tbd in Frameworks */, - 5669111F23B3D88200C93279 /* libcrypto.a in Frameworks */, - 5669113523B3D94300C93279 /* libzip.a in Frameworks */, + 2AC7AB922A8279A0004F21C9 /* libplist-2.0.4.dylib in Frameworks */, + 2A3E771029ACA1590079E6B4 /* libimg3tool.0.dylib in Frameworks */, + 2AF0D6332C63BFA000CDBC03 /* libirecovery-1.0.5.dylib in Frameworks */, + 2AE12632296C278E0051DB0F /* libimobiledevice-1.0.6.dylib in Frameworks */, + 2A4C882A2DF810E10010BA7E /* libfwkeyfetch.0.dylib in Frameworks */, + 2A76ED882A5BFBED0074B9E4 /* libtsschecker.0.dylib in Frameworks */, + 2A8D85DB296D7056004894E4 /* libra1nsn0w.0.dylib in Frameworks */, + 2A8D85DE296D75B1004894E4 /* libpatchfinder.0.dylib in Frameworks */, + 2AE12635296C306A0051DB0F /* libimg4tool.0.dylib in Frameworks */, + 2AE1262C296C24560051DB0F /* libimobiledevice-glue-1.0.0.dylib in Frameworks */, + 2AE12620296C1F6B0051DB0F /* libgeneral.0.dylib in Frameworks */, + 2AE12626296C1F830051DB0F /* libidevicerestore.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -189,7 +150,6 @@ 878587451D89CFDC008689F0 /* futurerestore */ = { isa = PBXGroup; children = ( - 8785874D1D89D1A4008689F0 /* external */, 8799B0B11D89D99D002F4D5F /* futurerestore.hpp */, 8799B0B01D89D99D002F4D5F /* futurerestore.cpp */, 878587461D89CFDC008689F0 /* main.cpp */, @@ -197,86 +157,24 @@ path = futurerestore; sourceTree = ""; }; - 8785874D1D89D1A4008689F0 /* external */ = { - isa = PBXGroup; - children = ( - 878587961D89D2BA008689F0 /* tsschecker */, - 8785874E1D89D1C1008689F0 /* idevicerestore */, - ); - name = external; - sourceTree = ""; - }; - 8785874E1D89D1C1008689F0 /* idevicerestore */ = { - isa = PBXGroup; - children = ( - 8785874F1D89D1C1008689F0 /* asr.c */, - 878587501D89D1C1008689F0 /* asr.h */, - 878587511D89D1C1008689F0 /* common.c */, - 878587521D89D1C1008689F0 /* common.h */, - 878587531D89D1C1008689F0 /* dfu.c */, - 878587541D89D1C1008689F0 /* dfu.h */, - 878587551D89D1C1008689F0 /* download.c */, - 878587561D89D1C1008689F0 /* download.h */, - 878587571D89D1C1008689F0 /* endianness.h */, - 878587581D89D1C1008689F0 /* fdr.c */, - 878587591D89D1C1008689F0 /* fdr.h */, - 8785875A1D89D1C1008689F0 /* fls.c */, - 8785875B1D89D1C1008689F0 /* fls.h */, - 8785875C1D89D1C1008689F0 /* idevicerestore.c */, - 8785875D1D89D1C1008689F0 /* idevicerestore.h */, - 8785875E1D89D1C1008689F0 /* img3.c */, - 8785875F1D89D1C1008689F0 /* img3.h */, - 878587601D89D1C1008689F0 /* img4.c */, - 878587611D89D1C1008689F0 /* img4.h */, - 87B517C5236EF3B0009EAB8F /* json_plist.c */, - 87B517C4236EF3B0009EAB8F /* json_plist.h */, - 87B517C1236EF36B009EAB8F /* ftab.c */, - 87B517C2236EF36B009EAB8F /* ftab.h */, - 87B517C7236EF3CD009EAB8F /* jsmn.c */, - 87B517C8236EF3CD009EAB8F /* jsmn.h */, - 878587621D89D1C1008689F0 /* ipsw.c */, - 878587631D89D1C1008689F0 /* ipsw.h */, - 878587641D89D1C1008689F0 /* limera1n.c */, - 878587651D89D1C1008689F0 /* limera1n.h */, - 878587661D89D1C1008689F0 /* limera1n_payload.h */, - 878587671D89D1C1008689F0 /* locking.c */, - 878587681D89D1C1008689F0 /* locking.h */, - 8785876A1D89D1C1008689F0 /* mbn.c */, - 8785876B1D89D1C1008689F0 /* mbn.h */, - 8785876C1D89D1C1008689F0 /* normal.c */, - 8785876D1D89D1C1008689F0 /* normal.h */, - 8785876E1D89D1C1008689F0 /* recovery.c */, - 8785876F1D89D1C1008689F0 /* recovery.h */, - 878587701D89D1C1008689F0 /* restore.c */, - 878587711D89D1C1008689F0 /* restore.h */, - 878587721D89D1C1008689F0 /* socket.c */, - 878587731D89D1C1008689F0 /* socket.h */, - 878587741D89D1C1008689F0 /* thread.c */, - 878587751D89D1C1008689F0 /* thread.h */, - 878587761D89D1C1008689F0 /* tss.c */, - 878587771D89D1C1008689F0 /* tss.h */, - ); - name = idevicerestore; - path = external/idevicerestore/src; - sourceTree = SOURCE_ROOT; - }; - 878587961D89D2BA008689F0 /* tsschecker */ = { - isa = PBXGroup; - children = ( - 878587991D89D2BA008689F0 /* download.h */, - 878587981D89D2BA008689F0 /* download.c */, - 8785879B1D89D2BA008689F0 /* jssy.h */, - 8785879A1D89D2BA008689F0 /* jssy.c */, - 878587A01D89D2BA008689F0 /* tsschecker.h */, - 8785879F1D89D2BA008689F0 /* tsschecker.c */, - ); - name = tsschecker; - path = external/tsschecker/tsschecker; - sourceTree = SOURCE_ROOT; - }; 87F574C21E151CDE008D5C4D /* Frameworks */ = { isa = PBXGroup; children = ( + 2A4C88292DF810E10010BA7E /* libfwkeyfetch.0.dylib */, + 2AF0D6322C63BFA000CDBC03 /* libirecovery-1.0.5.dylib */, + 2AC7AB912A8279A0004F21C9 /* libplist-2.0.4.dylib */, + 2A76ED872A5BFBED0074B9E4 /* libtsschecker.0.dylib */, + 2A3E770F29ACA1590079E6B4 /* libimg3tool.0.dylib */, + 2A8D85DD296D75B1004894E4 /* libpatchfinder.0.dylib */, + 2A8D85DA296D7056004894E4 /* libra1nsn0w.0.dylib */, + 2AE12634296C306A0051DB0F /* libimg4tool.0.dylib */, + 2AE12631296C278E0051DB0F /* libimobiledevice-1.0.6.dylib */, + 2AE1262E296C270B0051DB0F /* libplist-2.0.3.dylib */, + 2AE1262B296C24560051DB0F /* libimobiledevice-glue-1.0.0.dylib */, + 2AE12628296C1F9C0051DB0F /* libipatcher.0.dylib */, + 2AE12625296C1F830051DB0F /* libidevicerestore.0.dylib */, + 2AE12622296C1F760051DB0F /* libirecovery-1.0.3.dylib */, + 2AE1261F296C1F6B0051DB0F /* libgeneral.0.dylib */, 5669111C23B3D86E00C93279 /* libbz2.a */, 87F574C71E151DA6008D5C4D /* libcommonCrypto.tbd */, 87F574CC1E151EF8008D5C4D /* libcorecrypto.tbd */, @@ -354,31 +252,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8799B0C11D89DB38002F4D5F /* fls.c in Sources */, - 8799B0B41D89DAF6002F4D5F /* tss.c in Sources */, - 8799B0C01D89DB38002F4D5F /* fdr.c in Sources */, - 8799B0BC1D89DB27002F4D5F /* ipsw.c in Sources */, - 87B517C3236EF36B009EAB8F /* ftab.c in Sources */, - 8799B0CC1D89F7B9002F4D5F /* download.c in Sources */, - 8799B0B91D89DB0D002F4D5F /* img3.c in Sources */, - 8799B0B51D89DAFF002F4D5F /* common.c in Sources */, - 8799B0C41D89DB55002F4D5F /* mbn.c in Sources */, - 8799B0B81D89DAFF002F4D5F /* recovery.c in Sources */, - 8799B0B31D89DAE7002F4D5F /* idevicerestore.c in Sources */, - 8799B0BB1D89DB12002F4D5F /* download.c in Sources */, - 8799B0B71D89DAFF002F4D5F /* normal.c in Sources */, - 87B517C9236EF3CD009EAB8F /* jsmn.c in Sources */, - 8799B0C31D89DB4B002F4D5F /* socket.c in Sources */, - 8799B0C21D89DB46002F4D5F /* thread.c in Sources */, - 8799B0B61D89DAFF002F4D5F /* dfu.c in Sources */, - 8799B0BD1D89DB27002F4D5F /* limera1n.c in Sources */, - 8799B0C51D89DB67002F4D5F /* locking.c in Sources */, 878587471D89CFDC008689F0 /* main.cpp in Sources */, - 87B517C6236EF3B0009EAB8F /* json_plist.c in Sources */, - 8799B0BF1D89DB38002F4D5F /* asr.c in Sources */, - 8799B0BE1D89DB27002F4D5F /* restore.c in Sources */, - 8799B0CB1D89F796002F4D5F /* tsschecker.c in Sources */, - 8799B0CA1D89E371002F4D5F /* img4.c in Sources */, 8799B0B21D89D99D002F4D5F /* futurerestore.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -493,12 +367,13 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", "IDEVICERESTORE_NOMAIN=1", - "CUSTOM_LOGGING=1", "HAVE_REALPATH=1", + XCODE, ); HEADER_SEARCH_PATHS = ""; LIBRARY_SEARCH_PATHS = ( @@ -507,6 +382,7 @@ /usr/local/opt/openssl/lib, "$(SDKROOT)/usr/lib/system", ); + MACOSX_DEPLOYMENT_TARGET = 14.6; OTHER_CFLAGS = "-DHAVE_LIBIPATCHER"; PRODUCT_NAME = "$(TARGET_NAME)"; USER_HEADER_SEARCH_PATHS = "/usr/local/opt/openssl/include /usr/local/include $(SRCROOT)/external/libgeneral/include $(SRCROOT)/external/tsschecker/external/jssy/jssy $(SRCROOT)/external/idevicerestore/src"; @@ -517,6 +393,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; HEADER_SEARCH_PATHS = ""; LIBRARY_SEARCH_PATHS = ( /usr/local/lib, @@ -524,6 +401,7 @@ /usr/local/opt/openssl/lib, "$(SDKROOT)/usr/lib/system", ); + MACOSX_DEPLOYMENT_TARGET = 14.6; OTHER_CFLAGS = "-DHAVE_LIBIPATCHER"; PRODUCT_NAME = "$(TARGET_NAME)"; USER_HEADER_SEARCH_PATHS = "/usr/local/opt/openssl/include /usr/local/include $(SRCROOT)/external/libgeneral/include $(SRCROOT)/external/tsschecker/external/jssy/jssy $(SRCROOT)/external/idevicerestore/src"; diff --git a/futurerestore/Makefile.am b/futurerestore/Makefile.am index ea0e03a2..19668482 100644 --- a/futurerestore/Makefile.am +++ b/futurerestore/Makefile.am @@ -1,12 +1,9 @@ -AM_CFLAGS = -I$(top_srcdir)/external/libgeneral/include -I$(top_srcdir)/external/tsschecker/external/jssy/jssy -I$(top_srcdir)/external/tsschecker/tsschecker -I$(top_srcdir)/external/idevicerestore/src $(libplist_CFLAGS) $(libzip_CFLAGS) $(libimobiledevice_CFLAGS) $(libfragmentzip_CFLAGS) $(libirecovery_CFLAGS) $(libimg4tool_CFLAGS) $(libgeneral_CFLAGS) -AM_LDFLAGS = $(libplist_LIBS) $(libzip_LIBS) $(libimobiledevice_LIBS) $(libfragmentzip_LIBS) $(libirecovery_LIBS) $(libimg4tool_LIBS) $(libgeneral_LIBS) - -if HAVE_LIBIPATCHER -AM_LDFLAGS += $(libipatcher_LIBS) -AM_CFLAGS += $(libipatcher_CFLAGS) -endif +AM_CFLAGS = $(libplist_CFLAGS) $(libzip_CFLAGS) $(libimobiledevice_CFLAGS) $(libfragmentzip_CFLAGS) $(libfwkeyfetch_CFLAGS) \ + $(libirecovery_CFLAGS) $(libimg4tool_CFLAGS) $(libgeneral_CFLAGS) $(libidevicerestore_CFLAGS) $(libra1nsn0w_CFLAGS) +AM_LDFLAGS = $(libplist_LIBS) $(libzip_LIBS) $(libimobiledevice_LIBS) $(libfragmentzip_LIBS) $(libfwkeyfetch_LIBS) \ + $(libirecovery_LIBS) $(libimg4tool_LIBS) $(libgeneral_LIBS) $(libidevicerestore_LIBS) $(libra1nsn0w_LIBS) bin_PROGRAMS = futurerestore futurerestore_CXXFLAGS = $(AM_CFLAGS) -futurerestore_LDADD = $(top_srcdir)/external/idevicerestore/src/libidevicerestore.la $(top_srcdir)/external/tsschecker/tsschecker/libtsschecker.la $(top_srcdir)/external/tsschecker/tsschecker/libjssy.a $(AM_LDFLAGS) +futurerestore_LDADD = $(AM_LDFLAGS) futurerestore_SOURCES = futurerestore.cpp main.cpp diff --git a/futurerestore/futurerestore.cpp b/futurerestore/futurerestore.cpp index 639d13d9..6faaad60 100644 --- a/futurerestore/futurerestore.cpp +++ b/futurerestore/futurerestore.cpp @@ -7,30 +7,41 @@ // #include +#include #include #include #include #include #include #include +#include +#include #include "futurerestore.hpp" -#ifdef HAVE_LIBIPATCHER -#include -#endif - #include +#include +#include + +#include +#include + +#include +#include extern "C"{ -#include "common.h" -#include "normal.h" -#include "recovery.h" -#include "dfu.h" -#include "ipsw.h" -#include "locking.h" -#include "restore.h" -#include "tsschecker.h" #include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include } //(re)define __mkdir @@ -45,8 +56,6 @@ extern "C"{ #define __mkdir(path, mode) mkdir(path, mode) #endif -#define USEC_PER_SEC 1000000 - #ifdef WIN32 #define FUTURERESTORE_TMP_PATH "download" #else @@ -55,22 +64,18 @@ extern "C"{ #endif #define BASEBAND_TMP_PATH FUTURERESTORE_TMP_PATH"/baseband.bbfw" -#define BASEBAND_MANIFEST_TMP_PATH FUTURERESTORE_TMP_PATH"/basebandManifest.plist" -#define SEP_TMP_PATH FUTURERESTORE_TMP_PATH"/sep.im4p" -#define SEP_MANIFEST_TMP_PATH FUTURERESTORE_TMP_PATH"/sepManifest.plist" + +#define USEC_PER_SEC 1000000 #ifdef __APPLE__ # include # define SHA1(d, n, md) CC_SHA1(d, n, md) # define SHA384(d, n, md) CC_SHA384(d, n, md) +# define SHA_DIGEST_LENGTH CC_SHA1_DIGEST_LENGTH #else # include #endif // __APPLE__ -#ifndef HAVE_LIBIPATCHER -#define _enterPwnRecoveryRequested false -#endif - using namespace tihmstar; #pragma mark helpers @@ -79,299 +84,187 @@ extern "C"{ void idevice_event_cb(const idevice_event_t *event, void *userdata); }; +tihmstar::Mem getIPSWComponent(struct idevicerestore_client_t* client, plist_t build_identity, std::string component){ + char *path = NULL; + void* component_data = NULL; + cleanup([&]{ + safeFree(component_data); + safeFree(path); + }); + size_t component_size = 0; + + retassure(!build_identity_get_component_path(build_identity, component.c_str(), &path),"ERROR: Unable to get path for component '%s'", component.c_str()); + retassure(!extract_component(client->ipsw, (char*)path, &component_data, &component_size),"ERROR: Unable to extract component: %s", component.c_str()); + { + Mem ret{component_data,component_size}; component_data = NULL; component_size = 0; + return ret; + } +} + +void get_custom_component_decrypted(struct idevicerestore_client_t* client, plist_t build_identity, const char* component, unsigned char** data, size_t *size) noexcept{ +#ifndef HAVE_LIBIPATCHER + reterror("compiled without libipatcher"); +#else + try { + auto comp = getIPSWComponent(client, build_identity, component); + tihmstar::Mem comp_dec; + { + auto keys = libfwkeyfetch::getFirmwareKeyForComponent(client->device->product_type, client->build, component); + if (client->image4supported) { + auto dec = ra1nsn0w::patchIMG4(comp.data(), comp.size(), keys.iv, keys.key, "Apple", [](void*, size_t, void*)->int{return 0;}, NULL); + comp_dec = {(const void*)dec.buf(), dec.size()}; + }else{ + comp_dec = ra1nsn0w::patchIMG3(comp.data(), comp.size(), keys.iv, keys.key, "Apple", [](void*, size_t, void*)->int{return 0;}, NULL); + } + } + *data = (unsigned char*)comp_dec.data(); + *size = (unsigned int)comp_dec.size(); + comp_dec.disown(); + } catch (tihmstar::exception &e) { + reterror("ERROR: libipatcher failed with reason %d (%s)",e.code(),e.what()); + } +#endif +} + #pragma mark futurerestore -futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu) : _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu){ - _client = idevicerestore_client_new(); - if (_client == NULL) throw std::string("could not create idevicerestore client\n"); +futurerestore::futurerestore(uint64_t ecid, bool isUpdateInstall, bool isPwnDfu) +: _client(NULL) +, _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu), _no_ticket_needed(false), _restorePwnage(false), _restore24kpwn(false), _needsDecryptedRamdisk(false) +, _p_latestManifestCache(NULL) +, _persist_cfg{} +{ + bool didInit = false; + cleanup([&]{ + if (!didInit) { + this->~futurerestore(); + } + }) + irecv_error_t err_irecv = {}; + idevice_error_t err_idev = {}; + retassure(_client = idevicerestore_client_new(), "Failed to create idevicerestore client"); + _client->ecid = ecid; + retassure(!(err_irecv = irecv_device_event_subscribe(&_client->irecv_e_ctx, irecv_event_cb, _client)),"Failed to irecv_device_event_subscribe with err=%d",err_irecv); + retassure(!(err_idev = idevice_event_subscribe(idevice_event_cb, _client)),"Failed to idevice_event_subscribe with err=%d",err_irecv); + _client->idevice_e_ctx = (void*)idevice_event_cb; struct stat st{0}; if (stat(FUTURERESTORE_TMP_PATH, &st) == -1) __mkdir(FUTURERESTORE_TMP_PATH, 0755); - nocache = 1; //tsschecker nocache - _foundnonce = -1; + auto mode = getDeviceMode(); + info("Found device in %s mode", mode->string); + + _client->image4supported = is_image4_supported(_client); + + didInit = true; } -bool futurerestore::init(){ - if (_didInit) return _didInit; - _didInit = (check_mode(_client) != MODE_UNKNOWN); - if (!(_client->image4supported = is_image4_supported(_client))){ - info("[INFO] 32-bit device detected\n"); - }else{ - info("[INFO] 64-bit device detected\n"); +futurerestore::~futurerestore(){ + safeFreeCustom(_p_latestManifestCache, plist_free); + while (_aptickets.size()) { + auto t = _aptickets.back(); + safeFreeCustom(t, plist_free); + _aptickets.pop_back(); } - return _didInit; + safeFreeCustom(_client, idevicerestore_client_free); } -uint64_t futurerestore::getDeviceEcid(){ - retassure(_didInit, "did not init\n"); - uint64_t ecid; - get_ecid(_client, &ecid); - return ecid; -} - -int futurerestore::getDeviceMode(bool reRequest){ - retassure(_didInit, "did not init\n"); - if (!reRequest && _client->mode && _client->mode->index != MODE_UNKNOWN) { - return _client->mode->index; - }else{ - dfu_client_free(_client); - recovery_client_free(_client); - return check_mode(_client); +#pragma mark private +const plist_t futurerestore::loadBuilmanifestForLatestFirmware(){ + if (!_p_latestManifestCache) { + auto latestFirmwareInfo = tsschecker::getLatestFirmwareForDevice(getDeviceCPID(), getDeviceBDID()); + _latestFirmwareUrl = latestFirmwareInfo.url; + _p_latestManifestCache = tsschecker::getBuildManifestFromUrl(_latestFirmwareUrl.c_str()); } + return _p_latestManifestCache; } -void futurerestore::putDeviceIntoRecovery(){ - retassure(_didInit, "did not init\n"); - -#ifdef HAVE_LIBIPATCHER - _enterPwnRecoveryRequested = _isPwnDfu; -#endif +tihmstar::Mem futurerestore::getComponentFromIPSW(const char *ipswPath, const char *component){ + plist_t p_buildmanifest = NULL; + char *componentPath = NULL; + void *componentBuf = NULL; + ipsw_archive_t ipswArchive = NULL; + cleanup([&]{ + safeFreeCustom(ipswArchive, ipsw_close); + safeFree(componentBuf); + safeFree(componentPath); + safeFreeCustom(p_buildmanifest, plist_free); + }); + size_t componentBufSize = 0; + plist_t p_buildidentity = NULL; - getDeviceMode(false); - info("Found device in %s mode\n", _client->mode->string); - if (_client->mode->index == MODE_NORMAL){ -#ifdef HAVE_LIBIPATCHER - retassure(!_isPwnDfu, "isPwnDfu enabled, but device was found in normal mode\n"); -#endif - info("Entering recovery mode...\n"); - retassure(!normal_enter_recovery(_client),"Unable to place device into recovery mode from %s mode\n", _client->mode->string); - }else if (_client->mode->index == MODE_RECOVERY){ - info("Device already in recovery mode\n"); - }else if (_client->mode->index == MODE_DFU && _isPwnDfu && -#ifdef HAVE_LIBIPATCHER - true -#else - false -#endif - ){ - info("requesting to get into pwnRecovery later\n"); - }else if (!_client->image4supported){ - info("32-bit device in DFU mode found, assuming user wants to use iOS 9.x re-restore bug. Not failing here\n"); - }else{ - reterror("unsupported device mode, please put device in recovery or normal mode\n"); - } - - safeFree(_client->udid); //only needs to be freed manually when function did't throw exception - - //these get also freed by destructor - dfu_client_free(_client); - recovery_client_free(_client); -} - -void futurerestore::setAutoboot(bool val){ - retassure(_didInit, "did not init\n"); - - retassure(getDeviceMode(false) == MODE_RECOVERY, "can't set auto-boot, when device isn't in recovery mode\n"); - retassure(!_client->recovery && recovery_client_new(_client),"Could not connect to device in recovery mode.\n"); - retassure(!recovery_set_autoboot(_client, val),"Setting auto-boot failed?!\n"); -} - -void futurerestore::exitRecovery() { - setAutoboot(true); - recovery_send_reset(_client); - recovery_client_free(_client); -} - -plist_t futurerestore::nonceMatchesApTickets(){ - retassure(_didInit, "did not init\n"); - - if (getDeviceMode(true) != MODE_RECOVERY){ - if (getDeviceMode(false) != MODE_DFU || *_client->version != '9') - reterror("Device is not in recovery mode, can't check ApNonce\n"); - else - _rerestoreiOS9 = (info("Detected iOS 9.x 32-bit re-restore, proceeding in DFU mode\n"),true); - } - - unsigned char* realnonce; - int realNonceSize = 0; - if (_rerestoreiOS9) { - info("Skipping ApNonce check\n"); - }else{ - recovery_get_ap_nonce(_client, &realnonce, &realNonceSize); - - info("Got ApNonce from device: "); - int i = 0; - for (i = 0; i < realNonceSize; i++) { - info("%02x ", ((unsigned char *)realnonce)[i]); - } - info("\n"); - } - - vectornonces; - - if (_client->image4supported){ - for (int i=0; i< _im4ms.size(); i++){ - auto nonce = img4tool::getValFromIM4M({_im4ms[i].first,_im4ms[i].second}, 'BNCH'); - if (nonce.payloadSize() == realNonceSize && memcmp(realnonce, nonce.payload(), realNonceSize) == 0) return _aptickets[i]; - } - }else{ - for (int i=0; i< _im4ms.size(); i++){ - size_t ticketNonceSize = 0; - const char *nonce = NULL; - try { - //nonce might not exist, which we use in re-restoring iOS 9.x for 32-bit - auto n = getNonceFromSCAB(_im4ms[i].first, _im4ms[i].second); - ticketNonceSize = n.second; - nonce = n.first; - } catch (...) - { } - if (memcmp(realnonce, nonce, ticketNonceSize) == 0 && - ( (ticketNonceSize == realNonceSize && realNonceSize+ticketNonceSize > 0) || - (!ticketNonceSize && *_client->version == '9' && - (getDeviceMode(false) == MODE_DFU || - ( getDeviceMode(false) == MODE_RECOVERY && !strncmp(getiBootBuild(), "iBoot-2817", strlen("iBoot-2817")) ) - ) - ) - ) - ) - //either nonce needs to match or using re-restore bug in iOS 9.x - return _aptickets[i]; + retassure(ipswArchive = ipsw_open(ipswPath), "Failed to open IPSW '%s'",ipswPath); + { + int unused = 0; + if (ipsw_extract_build_manifest(ipswArchive, &p_buildmanifest, &unused)) { + error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.", ipswPath); + retassure(!ipsw_extract_restore_plist(ipswArchive, &p_buildmanifest),"ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.", ipswPath); + tsschecker::buildIdentityFromRestorePlist(p_buildmanifest); } } - return NULL; -} - -std::pair futurerestore::nonceMatchesIM4Ms(){ - retassure(_didInit, "did not init\n"); - - retassure(getDeviceMode(true) == MODE_RECOVERY, "Device is not in recovery mode, can't check ApNonce\n"); + retassure(p_buildidentity = build_manifest_get_build_identity_for_model_with_variant(p_buildmanifest, getDeviceBoardNoCopy(), ""/*any*/, 0),"ERROR: Unable to find any build identities for IPSW"); - unsigned char* realnonce; - int realNonceSize = 0; - recovery_get_ap_nonce(_client, &realnonce, &realNonceSize); + retassure(!build_identity_get_component_path(p_buildidentity, component, &componentPath), "ERROR: Unable to get path for '%s' component",component); - vectornonces; - - if (_client->image4supported) { - for (int i=0; i< _im4ms.size(); i++){ - auto nonce = img4tool::getValFromIM4M({_im4ms[i].first,_im4ms[i].second}, 'BNCH'); - if (nonce.payloadSize() == realNonceSize && memcmp(realnonce, nonce.payload(), realNonceSize) == 0) return _im4ms[i]; - } - }else{ - for (int i=0; i< _im4ms.size(); i++){ - size_t ticketNonceSize = 0; - const char *nonce = NULL; - try { - //nonce might not exist, which we use in re-restoring iOS 9.x for 32-bit - auto n = getNonceFromSCAB(_im4ms[i].first, _im4ms[i].second); - ticketNonceSize = n.second; - nonce = n.first; - } catch (...) { - // - } - if (memcmp(realnonce, nonce, ticketNonceSize) == 0) return _im4ms[i]; - } + retassure(!extract_component(ipswArchive, componentPath, &componentBuf, &componentBufSize),"Failed to extract component"); + { + tihmstar::Mem ret{componentBuf,componentBufSize}; componentBuf = NULL; //transfer ownership + return ret; } - - return {NULL,0}; } -void futurerestore::waitForNonce(vectornonces, size_t nonceSize){ - retassure(_didInit, "did not init\n"); - setAutoboot(false); - - unsigned char* realnonce; - int realNonceSize = 0; - - for (auto nonce : nonces){ - info("waiting for ApNonce: "); - int i = 0; - for (i = 0; i < nonceSize; i++) { - info("%02x ", ((unsigned char *)nonce)[i]); - } - info("\n"); - } - - do { - if (realNonceSize){ - recovery_send_reset(_client); - recovery_client_free(_client); - usleep(1*USEC_PER_SEC); - } - while (getDeviceMode(true) != MODE_RECOVERY) usleep(USEC_PER_SEC*0.5); - retassure(!recovery_client_new(_client), "Could not connect to device in recovery mode\n"); - - recovery_get_ap_nonce(_client, &realnonce, &realNonceSize); - info("Got ApNonce from device: "); - int i = 0; - for (i = 0; i < realNonceSize; i++) { - info("%02x ", realnonce[i]); - } - info("\n"); - for (int i=0; inonces; - - retassure(_client->image4supported, "Error: ApNonce collision function is not supported on 32-bit devices\n"); - - for (auto im4m : _im4ms){ - auto nonce = img4tool::getValFromIM4M({im4m.first,im4m.second}, 'BNCH'); - if (!nonceSize) { - nonceSize = nonce.payloadSize(); - } - retassure(nonceSize == nonce.payloadSize(), "Nonces have different lengths!"); - nonces.push_back((const char*)nonce.payload()); - } - - waitForNonce(nonces,nonceSize); +void futurerestore::setRestorePwnage(bool restorePwnage){ + _restorePwnage = restorePwnage; } -void futurerestore::loadAPTickets(const vector &apticketPaths){ +void futurerestore::setRestore24kpwn(bool restore24kpwn){ + _restore24kpwn = restore24kpwn; + if (restore24kpwn) _restorePwnage = restore24kpwn; +} + +void futurerestore::setNeedsDecryptedRamdisk(bool needsDecryptedRamdisk){ + _needsDecryptedRamdisk = needsDecryptedRamdisk; +} + +void futurerestore::setNoTicketNeeded(bool ticketIsNotNeeded){ + _no_ticket_needed = ticketIsNotNeeded; +} + +void futurerestore::loadAPTickets(const std::vector &apticketPaths){ for (auto apticketPath : apticketPaths){ + int fd = -1; plist_t apticket = NULL; + char *buf = NULL; char *im4m = NULL; + cleanup([&]{ + safeFree(im4m); + safeFree(buf); + safeFreeCustom(apticket, plist_free); + safeClose(fd); + }); + size_t bufSize = 0; struct stat fst; - retassure(!stat(apticketPath, &fst), "failed to load APTicket at %s\n",apticketPath); - - gzFile zf = gzopen(apticketPath, "rb"); - if (zf) { - int blen = 0; - int readsize = 16384; //0x4000 - int bufsize = readsize; - char* bin = (char*)malloc(bufsize); - char* p = bin; - do { - int bytes_read = gzread(zf, p, readsize); - retassure(bytes_read>0, "Error reading gz compressed data\n"); - blen += bytes_read; - if (bytes_read < readsize) { - if (gzeof(zf)) { - bufsize += bytes_read; - break; - } - } - bufsize += readsize; - bin = (char*)realloc(bin, bufsize); - p = bin + blen; - } while (!gzeof(zf)); - gzclose(zf); - if (blen > 0) { - if (memcmp(bin, "bplist00", 8) == 0) - plist_from_bin(bin, blen, &apticket); - else - plist_from_xml(bin, blen, &apticket); - } - free(bin); - } + retassure((fd = open(apticketPath, O_RDONLY)) != -1, "failed to load APTicket at %s",apticketPath); + retassure(!fstat(fd, &fst), "Failed to stat"); + retassure(buf = (char*)malloc(bufSize = fst.st_size), "Failed to malloc mem"); + retassure(read(fd, buf, bufSize) == bufSize, "Failed to read ticket"); + plist_from_memory(buf, (uint32_t)bufSize, &apticket, NULL); if (_isUpdateInstall) { if(plist_t update = plist_dict_get_item(apticket, "updateInstall")){ - plist_t cpy = plist_copy(update); - plist_free(apticket); - apticket = cpy; + plist_t cpy = NULL; + cleanup([&]{ + safeFreeCustom(cpy, plist_free); + }); + assure(cpy = plist_copy(update)); + std::swap(cpy, apticket); } } @@ -379,956 +272,1168 @@ void futurerestore::loadAPTickets(const vector &apticketPaths){ uint64_t im4msize=0; plist_get_data_val(ticket, &im4m, &im4msize); - retassure(im4msize, "Error: failed to load signing ticket file %s\n",apticketPath); - - _im4ms.push_back({im4m,im4msize}); - _aptickets.push_back(apticket); - printf("reading signing ticket %s is done\n",apticketPath); - } -} - -uint64_t futurerestore::getBasebandGoldCertIDFromDevice(){ - if (!_client->preflight_info){ - if (normal_get_preflight_info(_client, &_client->preflight_info) == -1){ - printf("[WARNING] failed to read BasebandGoldCertID from device! Is it already in recovery?\n"); - return 0; - } - } - 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"); - return 0; - } - uint64_t val = 0; - plist_get_uint_val(node, &val); - return val; -} - -char *futurerestore::getiBootBuild(){ - if (!_ibootBuild){ - if (_client->recovery == NULL) { - retassure(!recovery_client_new(_client), "Error: can't create new recovery client"); - } - irecv_getenv(_client->recovery->client, "build-version", &_ibootBuild); - retassure(_ibootBuild, "Error: can't get a build-version"); - } - return _ibootBuild; -} - -pair, size_t> getIPSWComponent(struct idevicerestore_client_t* client, plist_t build_identity, string component){ - ptr_smart path; - unsigned char* component_data = NULL; - unsigned int component_size = 0; - - if (!(char*)path) { - retassure(!build_identity_get_component_path(build_identity, component.c_str(), &path),"ERROR: Unable to get path for component '%s'\n", component.c_str()); - } - - retassure(!extract_component(client->ipsw, (char*)path, &component_data, &component_size),"ERROR: Unable to extract component: %s\n", component.c_str()); - - return {(char*)component_data,component_size}; -} - -void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){ -#ifndef HAVE_LIBIPATCHER - reterror("compiled without libipatcher"); -#else - if (_client->image4supported) { - retassure(libipatcher::has64bitSupport(), "libipatcher was compiled without 64-bit support"); - std::string generator = getGeneratorFromSHSH2(_client->tss); - retassure(img4tool::isGeneratorValidForIM4M({_im4ms[0].first,_im4ms[0].second}, generator), "generator returned from device is not valid from APTicket"); - } - - int mode = 0; - libipatcher::fw_key iBSSKeys; - libipatcher::fw_key iBECKeys; - - retassure(!dfu_client_new(_client),"Unable to connect to DFU device\n"); - - irecv_get_mode(_client->dfu->client, &mode); - - try { - iBSSKeys = libipatcher::getFirmwareKey(_client->device->product_type, _client->build, "iBSS"); - iBECKeys = libipatcher::getFirmwareKey(_client->device->product_type, _client->build, "iBEC"); - } catch (tihmstar::exception &e) { - reterror("getting keys failed with error: %d (%s). Are keys publicly available?",e.code(),e.what()); - } - - auto iBSS = getIPSWComponent(_client, build_identity, "iBSS"); - iBSS = move(libipatcher::patchiBSS((char*)iBSS.first, iBSS.second, iBSSKeys)); - - auto iBEC = getIPSWComponent(_client, build_identity, "iBEC"); - iBEC = move(libipatcher::patchiBEC((char*)iBEC.first, iBEC.second, iBECKeys, bootargs)); - - if (_client->image4supported) { - /* if this is 64-bit, we need to back IM4P to IMG4 - also due to the nature of iBoot64Patchers sigpatches we need to stich a valid signed im4m to it (but nonce is ignored) */ - iBSS = move(libipatcher::packIM4PToIMG4(iBSS.first, iBSS.second, _im4ms[0].first, _im4ms[0].second)); - iBEC = move(libipatcher::packIM4PToIMG4(iBEC.first, iBEC.second, _im4ms[0].first, _im4ms[0].second)); - } - - bool modeIsRecovery = false; - if (mode != IRECV_K_DFU_MODE) { - info("NOTE: device is not in DFU mode, assuming pwn recovery mode.\n"); - for (int i=IRECV_K_RECOVERY_MODE_1; i<=IRECV_K_RECOVERY_MODE_4; i++) { - if (mode == i) - modeIsRecovery = true; - } - retassure(modeIsRecovery, "device is not in recovery mode\n"); - }else{ - info("Sending %s (%lu bytes)...\n", "iBSS", iBSS.second); - mutex_lock(&_client->device_event_mutex); - irecv_error_t err = irecv_send_buffer(_client->dfu->client, (unsigned char*)(char*)iBSS.first, (unsigned long)iBSS.second, 1); - retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBSS", irecv_strerror(err)); - - /* reconnect */ - dfu_client_free(_client); - - debug("Waiting for device to disconnect...\n"); - cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); - retassure((_client->mode == &idevicerestore_modes[MODE_UNKNOWN] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBSS. Reset device and try again"); - mutex_unlock(&_client->device_event_mutex); - - debug("Waiting for device to reconnect...\n"); - mutex_lock(&_client->device_event_mutex); - cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); - retassure((_client->mode == &idevicerestore_modes[MODE_DFU] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBSS. Reset device and try again"); - mutex_unlock(&_client->device_event_mutex); - - dfu_client_new(_client); - } - - if (_client->build_major > 8) { - retassure(!irecv_usb_set_configuration(_client->dfu->client, 1),"ERROR: set configuration failed\n"); - /* send iBEC */ - info("Sending %s (%lu bytes)...\n", "iBEC", iBEC.second); - mutex_lock(&_client->device_event_mutex); - irecv_error_t err = irecv_send_buffer(_client->dfu->client, (unsigned char*)(char*)iBEC.first, (unsigned long)iBEC.second, 1); - retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBEC", irecv_strerror(err)); - printf("waiting for device to reconnect...\n"); - if (modeIsRecovery){ - irecv_send_command(_client->dfu->client, "go"); - recovery_client_free(_client); + if (!im4msize){ + warning("SHSH file does NOT contain APTicket!"); }else{ - dfu_client_free(_client); + _im4ms.push_back({im4m,im4msize}); im4m = NULL; im4msize = 0; } - - debug("Waiting for device to disconnect...\n"); - cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); - retassure((_client->mode == &idevicerestore_modes[MODE_UNKNOWN] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBEC. Reset device and try again"); - mutex_unlock(&_client->device_event_mutex); + _aptickets.push_back(apticket); apticket = NULL; + info("reading signing ticket %s is done",apticketPath); } +} - debug("Waiting for device to reconnect...\n"); +idevicerestore_mode_t *futurerestore::getDeviceMode(){ mutex_lock(&_client->device_event_mutex); - cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); - retassure((_client->mode == &idevicerestore_modes[MODE_RECOVERY] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not reconnect. Possibly invalid iBEC. Reset device and try again"); - mutex_unlock(&_client->device_event_mutex); - - // Reconnect to device, but this time make sure we're not still in DFU mode - if (recovery_client_new(_client) < 0) { - if (_client->recovery->client) { - irecv_close(_client->recovery->client); - _client->recovery->client = NULL; - } - reterror("ERROR: Unable to connect to recovery device\n"); - } - - if (_client->image4supported) { - char *deviceGen = NULL; - cleanup([&]{ - safeFree(deviceGen); - }); - /* IMG4 requires to have a generator set for the device to successfully boot after restore - set generator now and make sure the nonce is the one we are trying to restore */ - - assure(!irecv_send_command(_client->recovery->client, "bgcolor 255 0 0")); - sleep(2); //yes, I like displaying colored screens to the user and making him wait for no reason :P - - auto nonceelem = img4tool::getValFromIM4M({_im4ms[0].first,_im4ms[0].second}, 'BNCH'); - - printf("ApNonce pre-hax:\n"); - get_ap_nonce(_client, &_client->nonce, &_client->nonce_size); - std::string generator = getGeneratorFromSHSH2(_client->tss); - - if (memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) != 0) { - printf("ApNonce from device doesn't match IM4M nonce, applying hax...\n"); - - assure(_client->tss); - printf("Writing generator=%s to nvram!\n",generator.c_str()); - - retassure(!irecv_setenv(_client->recovery->client, "com.apple.System.boot-nonce", generator.c_str()),"failed to write generator to nvram"); - retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram"); - - /* send iBEC */ - info("Sending %s (%lu bytes)...\n", "iBEC", iBEC.second); - mutex_lock(&_client->device_event_mutex); - irecv_error_t err = irecv_send_buffer(_client->recovery->client, (unsigned char*)(char*)iBEC.first, (unsigned long)iBEC.second, 1); - retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBEC", irecv_strerror(err)); - printf("waiting for device to reconnect...\n"); - retassure(!irecv_send_command(_client->recovery->client, "go"),"failed to re-launch iBEC after ApNonce hax"); - recovery_client_free(_client); - - debug("Waiting for device to disconnect...\n"); - cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); - retassure((_client->mode == &idevicerestore_modes[MODE_UNKNOWN] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not disconnect after sending hax-iBEC in pwn-iBEC mode"); - mutex_unlock(&_client->device_event_mutex); - - debug("Waiting for device to reconnect...\n"); - mutex_lock(&_client->device_event_mutex); - cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); - retassure((_client->mode == &idevicerestore_modes[MODE_RECOVERY] || (mutex_unlock(&_client->device_event_mutex),0)), "Device did not reconnect after sending hax-iBEC in pwn-iBEC mode"); - mutex_unlock(&_client->device_event_mutex); - - retassure(!recovery_client_new(_client), "failed to reconnect to recovery after ApNonce hax"); - - printf("APnonce post-hax:\n"); - get_ap_nonce(_client, &_client->nonce, &_client->nonce_size); - assure(!irecv_send_command(_client->recovery->client, "bgcolor 255 255 0")); - retassure(memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) == 0, "ApNonce from device doesn't match IM4M nonce after applying ApNonce hax. Aborting!"); - }else{ - printf("APNonce from device already matches IM4M nonce, no need for extra hax...\n"); - } - retassure(!irecv_setenv(_client->recovery->client, "com.apple.System.boot-nonce", generator.c_str()),"failed to write generator to nvram"); - retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram"); - - sleep(2); //yes, I like displaying colored screens to the user and making him wait for no reason :P - } - -#endif //HAVE_LIBIPATCHER -} - -void get_custom_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component, unsigned char** data, unsigned int *size){ -#ifndef HAVE_LIBIPATCHER - reterror("compiled without libipatcher"); -#else - try { - auto comp = getIPSWComponent(client, build_identity, component); - comp = move(libipatcher::decryptFile3((char*)comp.first, comp.second, libipatcher::getFirmwareKey(client->device->product_type, client->build, component))); - *data = (unsigned char*)(char*)comp.first; - *size = comp.second; - comp.first = NULL; //don't free on destruction - } catch (tihmstar::exception &e) { - reterror("ERROR: libipatcher failed with reason %d (%s)\n",e.code(),e.what()); - } - -#endif -} - -void futurerestore::doRestore(const char *ipsw){ - plist_t buildmanifest = NULL; - int delete_fs = 0; - char* filesystem = NULL; cleanup([&]{ - info("Cleaning up...\n"); - safeFreeCustom(buildmanifest, plist_free); - if (delete_fs && filesystem) unlink(filesystem); + mutex_unlock(&_client->device_event_mutex); }); - struct idevicerestore_client_t* client = _client; - plist_t build_identity = NULL; - plist_t sep_build_identity = NULL; - - client->ipsw = strdup(ipsw); - if (!_isUpdateInstall) client->flags |= FLAG_ERASE; - - irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client); - idevice_event_subscribe(idevice_event_cb, client); - client->idevice_e_ctx = (void*)idevice_event_cb; - - mutex_lock(&client->device_event_mutex); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - - retassure(client->mode != &idevicerestore_modes[MODE_UNKNOWN], "Unable to discover device mode. Please make sure a device is attached.\n"); - if (client->mode != &idevicerestore_modes[MODE_RECOVERY]) { - retassure(client->mode == &idevicerestore_modes[MODE_DFU], "Device is in unexpected mode detected!"); - retassure(_enterPwnRecoveryRequested, "Device is in DFU mode detected, but we were expecting recovery mode!"); - }else{ - retassure(!_enterPwnRecoveryRequested, "--use-pwndfu was specified, but device found in recovery mode!"); + if (_client->mode == MODE_UNKNOWN) { + info("Waiting for device to enter restore mode..."); + cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 120000); + if (_client->mode == MODE_UNKNOWN) { + reterror("ERROR: Unable to discover device mode. Please make sure a device is attached."); + } } - - info("Found device in %s mode\n", client->mode->string); - mutex_unlock(&client->device_event_mutex); + return _client->mode; +} - info("Identified device as %s, %s\n", getDeviceBoardNoCopy(), getDeviceModelNoCopy()); +bool futurerestore::isInRestoreMode(){ + return getDeviceMode() == MODE_RESTORE; +} - retassure(!access(client->ipsw, F_OK),"ERROR: Firmware file %s does not exist.\n", client->ipsw); // verify if ipsw file exists +void futurerestore::putDeviceIntoRecovery(){ + auto mode = getDeviceMode(); + + info("Found device in %s mode", mode->string); + if (mode == MODE_NORMAL){ +#ifdef HAVE_LIBIPATCHER + retassure(!_isPwnDfu, "isPwnDfu enabled, but device was found in normal mode"); +#endif + info("Entering recovery mode..."); + retassure(!normal_enter_recovery(_client),"Unable to place device into recovery mode from %s mode", _client->mode->string); + }else if (mode == MODE_RECOVERY){ + info("Device already in recovery mode"); + }else if (_client->mode == MODE_DFU && _isPwnDfu && +#ifdef HAVE_LIBIPATCHER + true +#else + false +#endif + ){ + info("requesting to get into pwnRecovery later"); + }else if (!_client->image4supported){ + info("32-bit device in DFU mode found, assuming user wants to use iOS 9.x re-restore bug. Not failing here"); + }else{ + reterror("unsupported device mode, please put device in recovery or normal mode"); + } - info("Extracting BuildManifest from iPSW\n"); + //these get also freed by destructor + dfu_client_free(_client); + recovery_client_free(_client); +} + +tihmstar::Mem futurerestore::getRamdiskForDevice(const char *ipswpath){ + plist_t buildmanifest = NULL; + char* rdiskPath = NULL; + void *ramdisk = NULL; + ipsw_archive_t ipsw = NULL; + cleanup([&]{ + safeFreeCustom(ipsw, ipsw_close); + safeFree(ramdisk); + safeFree(rdiskPath); + safeFreeCustom(buildmanifest, plist_free); + }); + size_t ramdiskSize = 0; + plist_t build_identity = NULL; + + if (getDeviceMode() == MODE_WTF ) { + info("Booting WTF into pwnDFU mode!"); + tihmstar::ra1nsn0w::iOSDevice ra1nDevice; + + tihmstar::ra1nsn0w::launchConfig cfg{ + .is32Bit = true, + .justDFU = true + }; + + dfu_client_free(_client); + std::string file = "file://"; + file += ipswpath; + ra1nsn0w::launchDevice(ra1nDevice, file, cfg); + } + + info("Extracting BuildManifest from IPSW"); + assure(ipsw = ipsw_open(ipswpath)); { int unused; - retassure(!ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &unused),"ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw); + if (ipsw_extract_build_manifest(ipsw, &buildmanifest, &unused)) { + error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.", ipswpath); + retassure(!ipsw_extract_restore_plist(ipsw, &buildmanifest),"ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.", ipswpath); + tsschecker::buildIdentityFromRestorePlist(buildmanifest); + } } - + info("Identified device as %s, %s", getDeviceBoardNoCopy(), getDeviceModelNoCopy()); + /* check if device type is supported by the given build manifest */ - retassure(!build_manifest_check_compatibility(buildmanifest, client->device->product_type),"ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n"); + retassure(!build_manifest_check_compatibility(buildmanifest, _client->device->product_type),"ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue."); /* print iOS information from the manifest */ - build_manifest_get_version_information(buildmanifest, client); - info("Product version: %s\n", client->version); - info("Product build: %s Major: %d\n", client->build, client->build_major); - client->image4supported = is_image4_supported(client); - info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); + build_manifest_get_version_information(buildmanifest, _client); + info("Product version: %s", _client->version); + info("Product build: %s Major: %d", _client->build, _client->build_major); - if (_enterPwnRecoveryRequested) //we are in pwnDFU, so we don't need to check nonces - client->tss = _aptickets.at(0); - else if (!(client->tss = nonceMatchesApTickets())) - reterror("Device ApNonce does not match APTicket nonce\n"); - - plist_dict_remove_item(client->tss, "BBTicket"); - plist_dict_remove_item(client->tss, "BasebandFirmware"); - - if (_enterPwnRecoveryRequested && _client->image4supported) { - retassure(plist_dict_get_item(_client->tss, "generator"), "signing ticket file does not contain generator. But a generator is required for 64-bit pwnDFU restore"); + retassure(build_identity = build_manifest_get_build_identity_for_model_with_variant(buildmanifest, _client->device->hardware_model, _isUpdateInstall ? RESTORE_VARIANT_UPGRADE_INSTALL : RESTORE_VARIANT_ERASE_INSTALL, 0),"ERROR: Unable to find any build identities for iPSW"); + + retassure(!build_identity_get_component_path(build_identity, "RestoreRamDisk", &rdiskPath), "ERROR: Unable to get path for RestoreRamDisk component"); + + retassure(!extract_component(ipsw, rdiskPath, &ramdisk, &ramdiskSize),"Failed to extract ramdisk"); + { + Mem ret{ramdisk,ramdiskSize}; ramdisk = NULL; ramdiskSize = 0; + return ret; } - - retassure(build_identity = getBuildidentityWithBoardconfig(buildmanifest, client->device->hardware_model, _isUpdateInstall),"ERROR: Unable to find any build identities for iPSW\n"); +} - if (_client->image4supported) { - if (!(sep_build_identity = getBuildidentityWithBoardconfig(_sepbuildmanifest, client->device->hardware_model, _isUpdateInstall))){ - retassure(_isPwnDfu, "ERROR: Unable to find any build identities for SEP\n"); - warning("can't find buildidentity for SEP with InstallType=%s. However pwnDFU was requested, so trying fallback to %s",(_isUpdateInstall ? "UPDATE" : "ERASE"),(!_isUpdateInstall ? "UPDATE" : "ERASE")); - retassure((sep_build_identity = getBuildidentityWithBoardconfig(_sepbuildmanifest, client->device->hardware_model, !_isUpdateInstall)), - "ERROR: Unable to find any build identities for SEP\n"); + +void futurerestore::doRestore(const char *ipswpath){ + plist_t build_identity = NULL; + bool build_identity_needs_free = false; + cleanup([&]{ + if (build_identity_needs_free) { + safeFreeCustom(build_identity, plist_free); } - } + }); - plist_t manifest = plist_dict_get_item(build_identity, "Manifest"); //this is the buildidentity used for restore + struct idevicerestore_client_t* client = _client; + int isRestorePlist = 0; - printf("checking APTicket to be valid for this restore...\n"); //if we are in pwnDFU, just use first APTicket. We don't need to check nonces. - auto im4m = (_enterPwnRecoveryRequested || _rerestoreiOS9) ? _im4ms.at(0) : nonceMatchesIM4Ms(); - - uint64_t deviceEcid = getDeviceEcid(); - uint64_t im4mEcid = 0; - if (_client->image4supported) { - auto ecid = img4tool::getValFromIM4M({im4m.first,im4m.second}, 'ECID'); - im4mEcid = ecid.getIntegerValue(); - }else{ - im4mEcid = getEcidFromSCAB(im4m.first, im4m.second); - } - - retassure(im4mEcid, "Failed to read ECID from APTicket\n"); - - if (im4mEcid != deviceEcid) { - error("ECID inside APTicket does not match device ECID\n"); - printf("APTicket is valid for %16llu (dec) but device is %16llu (dec)\n",im4mEcid,deviceEcid); - reterror("APTicket can't be used for restoring this device\n"); - }else - printf("Verified ECID in APTicket matches device ECID\n"); - - if (_client->image4supported) { - printf("checking APTicket to be valid for this restore...\n"); - uint64_t deviceEcid = getDeviceEcid(); - - if (im4mEcid != deviceEcid) { - error("ECID inside APTicket does not match device ECID\n"); - printf("APTicket is valid for %16llu (dec) but device is %16llu (dec)\n",im4mEcid,deviceEcid); - reterror("APTicket can't be used for restoring this device\n"); - }else - printf("Verified ECID in APTicket matches device ECID\n"); - - plist_t ticketIdentity = NULL; - + if (!_client->tss && !_no_ticket_needed) { try { - ticketIdentity = img4tool::getBuildIdentityForIm4m({im4m.first,im4m.second}, buildmanifest); - } catch (tihmstar::exception &e) { - // + _client->tss = _aptickets.at(0); + } catch (...) { + reterror("Failed to load apticket"); } - - if (!ticketIdentity) { - printf("Failed to get exact match for build identity, using fallback to ignore certain values\n"); - ticketIdentity = img4tool::getBuildIdentityForIm4m({im4m.first,im4m.second}, buildmanifest, {"RestoreRamDisk","RestoreTrustCache"}); - } - - /* TODO: make this nicer! - for now a simple pointercompare should be fine, because both plist_t should point into the same buildidentity inside the buildmanifest */ - if (ticketIdentity != build_identity ){ - error("BuildIdentity selected for restore does not match APTicket\n\n"); - printf("BuildIdentity selected for restore:\n"); - img4tool::printGeneralBuildIdentityInformation(build_identity); - printf("\nBuildIdentity is valid for the APTicket:\n"); - - if (ticketIdentity) img4tool::printGeneralBuildIdentityInformation(ticketIdentity),putchar('\n'); - else{ - printf("IM4M is not valid for any restore within the Buildmanifest\n"); - printf("This APTicket can't be used for restoring this firmware\n"); - } - reterror("APTicket can't be used for this restore\n"); - }else{ - if (!img4tool::isIM4MSignatureValid({im4m.first,im4m.second})){ - printf("IM4M signature is not valid!\n"); - reterror("APTicket can't be used for this restore\n"); - } - printf("Verified APTicket to be valid for this restore\n"); - } - }else if (_enterPwnRecoveryRequested){ - info("[WARNING] skipping ramdisk hash check, since device is in pwnDFU according to user\n"); - - }else{ - info("[WARNING] full buildidentity check is not implemented, only comparing ramdisk hash.\n"); - - auto ticket = getRamdiskHashFromSCAB(im4m.first, im4m.second); - const char *tickethash = ticket.first; - size_t tickethashSize = ticket.second; - - uint64_t manifestDigestSize = 0; - char *manifestDigest = NULL; - - plist_t restoreRamdisk = plist_dict_get_item(manifest, "RestoreRamDisk"); - plist_t digest = plist_dict_get_item(restoreRamdisk, "Digest"); - - plist_get_data_val(digest, &manifestDigest, &manifestDigestSize); - - if (tickethashSize == manifestDigestSize && memcmp(tickethash, manifestDigest, tickethashSize) == 0){ - printf("Verified APTicket to be valid for this restore\n"); - free(manifestDigest); - }else{ - free(manifestDigest); - printf("APTicket ramdisk hash does not match the ramdisk we are trying to boot. Are you using correct install type (Update/Erase)?\n"); - reterror("APTicket can't be used for this restore\n"); - } - } - - if (_basebandbuildmanifest){ - if (!(client->basebandBuildIdentity = getBuildidentityWithBoardconfig(_basebandbuildmanifest, client->device->hardware_model, _isUpdateInstall))){ - retassure(client->basebandBuildIdentity = getBuildidentityWithBoardconfig(_basebandbuildmanifest, client->device->hardware_model, !_isUpdateInstall), "ERROR: Unable to find any build identities for Baseband\n"); - info("[WARNING] Unable to find Baseband buildidentities for restore type %s, using fallback %s\n", (_isUpdateInstall) ? "Update" : "Erase",(!_isUpdateInstall) ? "Update" : "Erase"); - } - - client->bbfwtmp = (char*)_basebandPath; - - plist_t bb_manifest = plist_dict_get_item(client->basebandBuildIdentity, "Manifest"); - plist_t bb_baseband = plist_copy(plist_dict_get_item(bb_manifest, "BasebandFirmware")); - plist_dict_set_item(manifest, "BasebandFirmware", bb_baseband); - - retassure(_client->basebandBuildIdentity, "BasebandBuildIdentity not loaded, refusing to continue"); - }else{ - warning("WARNING: we don't have a basebandbuildmanifest, does not flashing baseband!\n"); - } - - if (_client->image4supported) { - //check SEP - plist_t sep_manifest = plist_dict_get_item(sep_build_identity, "Manifest"); - plist_t sep_sep = plist_copy(plist_dict_get_item(sep_manifest, "SEP")); - plist_dict_set_item(manifest, "SEP", sep_sep); - unsigned char genHash[48]; //SHA384 digest length - ptr_smartsephash = NULL; - uint64_t sephashlen = 0; - plist_t digest = plist_dict_get_item(sep_sep, "Digest"); - - retassure(digest && plist_get_node_type(digest) == PLIST_DATA, "ERROR: can't find SEP digest\n"); - - plist_get_data_val(digest, reinterpret_cast(&sephash), &sephashlen); - - if (sephashlen == 20) - SHA1((unsigned char*)_client->sepfwdata, (unsigned int)_client->sepfwdatasize, genHash); - else - SHA384((unsigned char*)_client->sepfwdata, (unsigned int)_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 - if (_enterPwnRecoveryRequested){ - retassure(getDeviceMode(true) == MODE_DFU, "unexpected device mode\n"); - enterPwnRecovery(build_identity); + info("Loaded APticket at index 0"); } - // Get filesystem name from build identity - char* fsname = NULL; - retassure(!build_identity_get_component_path(build_identity, "OS", &fsname), "ERROR: Unable to get path for filesystem component\n"); + safeFreeCustom(client->ipsw, ipsw_close); + retassure(client->ipsw = ipsw_open(ipswpath),"ERROR: Failed to open ipsw %s does not exist.",ipswpath); + + if (!_isUpdateInstall) client->flags |= FLAG_ERASE; - // check if we already have an extracted filesystem - struct stat st; - memset(&st, '\0', sizeof(struct stat)); - char tmpf[1024]; - if (client->cache_dir) { - if (stat(client->cache_dir, &st) < 0) { - mkdir_with_parents(client->cache_dir, 0755); - } - strcpy(tmpf, client->cache_dir); - strcat(tmpf, "/"); - char *ipswtmp = strdup(client->ipsw); - strcat(tmpf, basename(ipswtmp)); - free(ipswtmp); - } else { - strcpy(tmpf, client->ipsw); - } - char* p = strrchr(tmpf, '.'); - if (p) { - *p = '\0'; + { + auto mode = getDeviceMode(); + info("Found device in %s mode", mode->string); + retassure(mode->index == _MODE_RESTORE, "Device not in restore mode"); } - if (stat(tmpf, &st) < 0) { - __mkdir(tmpf, 0755); - } - strcat(tmpf, "/"); - strcat(tmpf, fsname); - - memset(&st, '\0', sizeof(struct stat)); - if (stat(tmpf, &st) == 0) { - off_t fssize = 0; - ipsw_get_file_size(client->ipsw, fsname, (uint64_t*)&fssize); - if ((fssize > 0) && (st.st_size == fssize)) { - info("Using cached filesystem from '%s'\n", tmpf); - filesystem = strdup(tmpf); - } - } - - if (!filesystem) { - char extfn[1024]; - strcpy(extfn, tmpf); - strcat(extfn, ".extract"); - char lockfn[1024]; - strcpy(lockfn, tmpf); - strcat(lockfn, ".lock"); - lock_info_t li; - - lock_file(lockfn, &li); - FILE* extf = NULL; - if (access(extfn, F_OK) != 0) { - extf = fopen(extfn, "w"); - } - unlock_file(&li); - if (!extf) { - // use temp filename - filesystem = tempnam(NULL, "ipsw_"); - if (!filesystem) { - error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname); - filesystem = strdup(fsname); + info("Identified device as %s, %s", getDeviceBoardNoCopy(), getDeviceModelNoCopy()); + info("Extracting BuildManifest from iPSW"); + { + int unused; + if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &unused) < 0) { + error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.", client->ipsw->path); + if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { + reterror("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.", client->ipsw->path); } - delete_fs = 1; - } else { - // use .extract as filename - filesystem = strdup(extfn); - fclose(extf); - } - remove(lockfn); - - info("Extracting filesystem from iPSW\n"); - retassure(!ipsw_extract_to_file_with_progress(client->ipsw, fsname, filesystem, 1),"ERROR: Unable to extract filesystem from iPSW\n"); - - // rename .extract to - if (strstr(filesystem, ".extract")) { - remove(tmpf); - rename(filesystem, tmpf); - free(filesystem); - filesystem = strdup(tmpf); + isRestorePlist = 1; } } + + if (isRestorePlist) { + build_identity = plist_new_dict(); + build_identity_needs_free = true; - if (_rerestoreiOS9) { - mutex_lock(&_client->device_event_mutex); - if (dfu_send_component(client, build_identity, "iBSS") < 0) { - irecv_close(client->dfu->client); - client->dfu->client = NULL; - reterror("ERROR: Unable to send iBSS to device\n"); - } - - /* reconnect */ - dfu_client_free(client); - - debug("Waiting for device to disconnect...\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - retassure((client->mode == &idevicerestore_modes[MODE_UNKNOWN] || (mutex_unlock(&client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBSS. Reset device and try again"); - mutex_unlock(&client->device_event_mutex); - - debug("Waiting for device to reconnect...\n"); - mutex_lock(&_client->device_event_mutex); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - retassure((client->mode == &idevicerestore_modes[MODE_DFU] || (mutex_unlock(&client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBSS. Reset device and try again"); - mutex_unlock(&client->device_event_mutex); - - dfu_client_new(client); - - /* send iBEC */ - if (dfu_send_component(client, build_identity, "iBEC") < 0) { - irecv_close(client->dfu->client); - client->dfu->client = NULL; - reterror("ERROR: Unable to send iBEC to device\n"); - } - - dfu_client_free(client); - - debug("Waiting for device to disconnect...\n"); - mutex_lock(&_client->device_event_mutex); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - retassure((client->mode == &idevicerestore_modes[MODE_UNKNOWN] || (mutex_unlock(&client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBEC. Reset device and try again"); - mutex_unlock(&client->device_event_mutex); - - debug("Waiting for device to reconnect...\n"); - mutex_lock(&_client->device_event_mutex); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - retassure((client->mode == &idevicerestore_modes[MODE_RECOVERY] || (mutex_unlock(&client->device_event_mutex),0)), "Device did not reconnect. Possibly invalid iBEC. Reset device and try again"); - mutex_unlock(&client->device_event_mutex); - - }else{ - if ((client->build_major > 8)) { - if (!client->image4supported) { - /* send APTicket */ - if (recovery_send_ticket(client) < 0) { - error("WARNING: Unable to send APTicket\n"); + if (client->mode == MODE_WTF){ + /* + If we're still in WTF mode (i.e. when restoring iOS 1) we can't correctly identify the device yet. + We'll just assume that this firmware is correct for the device and identify the device base on the firmware. + Not ideal, but there is no other way to distinguish iPod1,1 from iPhone1,1 restoring iOS 1 + */ + plist_t p_ProductType = plist_dict_get_item(client->build_manifest, "ProductType"); + if (!p_ProductType){ + error("ERROR: Unable to get ProductType from Restore.plist"); + }else{ + char *firmwareProductType = NULL; + plist_get_string_val(p_ProductType, &firmwareProductType); + if (!firmwareProductType){ + error("ERROR: ProductType from Restore.plist is not of type PLIST_STRING"); + }else{ + irecv_error_t ierr = IRECV_E_SUCCESS; + ierr = irecv_devices_get_device_by_product_type(firmwareProductType, &client->device); + if (ierr){ + error("ERROR: Failed to identify device from ProductType"); + } + free(firmwareProductType); } } } - } - if (_enterPwnRecoveryRequested){ - if (!_client->image4supported) { - if (strncmp(client->version, "10.", 3))//if pwnrecovery send all components decrypted, unless we're dealing with iOS 10 - client->recovery_custom_component_function = get_custom_component; + { + plist_t node; + plist_t comp; + plist_t inf; + plist_t manifest; + + char tmpstr[256]; + char p_all_flash[128]; + char lcmodel[8]; + strcpy(lcmodel, client->device->hardware_model); + int x = 0; + while (lcmodel[x]) { + lcmodel[x] = tolower(lcmodel[x]); + x++; + } + + sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production"); + strcpy(tmpstr, p_all_flash); + strcat(tmpstr, "/manifest"); + + // get all_flash file manifest + char *files[16]; + char *fmanifest = NULL; + size_t msize = 0; + if (ipsw_extract_to_memory(client->ipsw, tmpstr, (void**)&fmanifest, &msize) < 0) { + reterror("ERROR: could not extract %s from IPSW", tmpstr); + } + + char *tok = strtok(fmanifest, "\r\n"); + int fc = 0; + while (tok) { + files[fc++] = strdup(tok); + if (fc >= 16) { + break; + } + tok = strtok(NULL, "\r\n"); + } + free(fmanifest); + + manifest = plist_new_dict(); + + for (x = 0; x < fc; x++) { + inf = plist_new_dict(); + strcpy(tmpstr, p_all_flash); + strcat(tmpstr, "/"); + strcat(tmpstr, files[x]); + plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); + comp = plist_new_dict(); + plist_dict_set_item(comp, "Info", inf); + const char* compname = get_component_name(files[x]); + if (compname) { + plist_dict_set_item(manifest, compname, comp); + if (!strncmp(files[x], "DeviceTree", 10)) { + plist_dict_set_item(manifest, "RestoreDeviceTree", plist_copy(comp)); + } + } else { + error("WARNING: unhandled component %s", files[x]); + plist_free(comp); + } + free(files[x]); + files[x] = NULL; + } + + // add iBSS + sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE"); + inf = plist_new_dict(); + plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); + comp = plist_new_dict(); + plist_dict_set_item(comp, "Info", inf); + plist_dict_set_item(manifest, "iBSS", comp); + + // add iBEC + sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE"); + inf = plist_new_dict(); + if (ipsw_file_exists(client->ipsw, tmpstr)){ + /* + iOS 1.0 doesn't actually have iBEC + */ + plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); + comp = plist_new_dict(); + plist_dict_set_item(comp, "Info", inf); + plist_dict_set_item(manifest, "iBEC", comp); + } + + //add logo + { + const char *logopath = NULL; + snprintf(tmpstr,sizeof(tmpstr), "Firmware/all_flash/all_flash.%s.production/applelogo.img2",lcmodel); + if (ipsw_file_exists(client->ipsw,tmpstr)){ + logopath = tmpstr; + }else{ + snprintf(tmpstr,sizeof(tmpstr), "Firmware/all_flash/all_flash.%s.production/applelogo.s5l8900x.img3",lcmodel); + if (ipsw_file_exists(client->ipsw,tmpstr)){ + logopath = tmpstr; + } + } + if (logopath){ + inf = plist_new_dict(); + plist_dict_set_item(inf, "Path", plist_new_string(logopath)); + comp = plist_new_dict(); + plist_dict_set_item(comp, "Info", inf); + plist_dict_set_item(manifest, "RestoreLogo", comp); + } + } + + //add logo + { + const char *logopath = NULL; + snprintf(tmpstr,sizeof(tmpstr), "Firmware/all_flash/all_flash.%s.production/applelogo.img2",lcmodel); + if (ipsw_file_exists(client->ipsw,tmpstr)){ + logopath = tmpstr; + }else{ + snprintf(tmpstr,sizeof(tmpstr), "Firmware/all_flash/all_flash.%s.production/applelogo.s5l8900x.img3",lcmodel); + if (ipsw_file_exists(client->ipsw,tmpstr)){ + logopath = tmpstr; + } + } + if (logopath){ + inf = plist_new_dict(); + plist_dict_set_item(inf, "Path", plist_new_string(logopath)); + comp = plist_new_dict(); + plist_dict_set_item(comp, "Info", inf); + plist_dict_set_item(manifest, "RestoreLogo", comp); + } + } + + // add kernel cache + plist_t kdict = NULL; + + node = plist_dict_get_item(client->build_manifest, "KernelCachesByTarget"); + if (node && (plist_get_node_type(node) == PLIST_DICT)) { + char tt[4]; + strncpy(tt, lcmodel, 3); + tt[3] = 0; + kdict = plist_dict_get_item(node, tt); + } else { + // Populated in older iOS IPSWs + kdict = plist_dict_get_item(client->build_manifest, "RestoreKernelCaches"); + } + if (kdict && (plist_get_node_type(kdict) == PLIST_DICT)) { + plist_t kc = plist_dict_get_item(kdict, "Release"); + if (kc && (plist_get_node_type(kc) == PLIST_STRING)) { + inf = plist_new_dict(); + plist_dict_set_item(inf, "Path", plist_copy(kc)); + comp = plist_new_dict(); + plist_dict_set_item(comp, "Info", inf); + plist_dict_set_item(manifest, "KernelCache", comp); + plist_dict_set_item(manifest, "RestoreKernelCache", plist_copy(comp)); + } + } + + // add ramdisk + node = plist_dict_get_item(client->build_manifest, "RestoreRamDisks"); + if (node && (plist_get_node_type(node) == PLIST_DICT)) { + plist_t rd = plist_dict_get_item(node, (client->flags & FLAG_ERASE) ? "User" : "Update"); + // if no "Update" ram disk entry is found try "User" ram disk instead + if (!rd && !(client->flags & FLAG_ERASE)) { + rd = plist_dict_get_item(node, "User"); + // also, set the ERASE flag since we actually change the restore variant + client->flags |= FLAG_ERASE; + } + if (rd && (plist_get_node_type(rd) == PLIST_STRING)) { + inf = plist_new_dict(); + plist_dict_set_item(inf, "Path", plist_copy(rd)); + comp = plist_new_dict(); + plist_dict_set_item(comp, "Info", inf); + plist_dict_set_item(manifest, "RestoreRamDisk", comp); + } + } + + // add OS filesystem + node = plist_dict_get_item(client->build_manifest, "SystemRestoreImages"); + if (!node) { + error("ERROR: missing SystemRestoreImages in Restore.plist"); + } + plist_t os = plist_dict_get_item(node, "User"); + if (!os) { + error("ERROR: missing filesystem in Restore.plist"); + } else { + inf = plist_new_dict(); + plist_dict_set_item(inf, "Path", plist_copy(os)); + comp = plist_new_dict(); + plist_dict_set_item(comp, "Info", inf); + plist_dict_set_item(manifest, "OS", comp); + } + + // add info + inf = plist_new_dict(); + plist_dict_set_item(inf, "RestoreBehavior", plist_new_string((client->flags & FLAG_ERASE) ? "Erase" : "Update")); + plist_dict_set_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer " RESTORE_VARIANT_ERASE_INSTALL : "Customer " RESTORE_VARIANT_UPGRADE_INSTALL)); + plist_dict_set_item(build_identity, "Info", inf); + + // finally add manifest + plist_dict_set_item(build_identity, "Manifest", manifest); } - }else if (!_rerestoreiOS9){ - /* now we load the iBEC */ - retassure(!recovery_send_ibec(client, build_identity),"ERROR: Unable to send iBEC\n"); + } - printf("waiting for device to reconnect... "); - recovery_client_free(client); + + + /* check if device type is supported by the given build manifest */ + retassure(!build_manifest_check_compatibility(client->build_manifest, client->device->product_type),"ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue."); + + /* print iOS information from the manifest */ + build_manifest_get_version_information(client->build_manifest, client); + info("Product version: %s", client->version); + info("Product build: %s Major: %d", client->build, client->build_major); + client->image4supported = is_image4_supported(client); + info("Device supports Image4: %s", (client->image4supported) ? "true" : "false"); + + if (client->tss) { + plist_dict_remove_item(client->tss, "BBTicket"); + plist_dict_remove_item(client->tss, "BasebandFirmware"); + } + + if (!build_identity) retassure(build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, _isUpdateInstall ? RESTORE_VARIANT_UPGRADE_INSTALL : RESTORE_VARIANT_ERASE_INSTALL, 0),"ERROR: Unable to find any build identities for iPSW"); + + build_identity_print_information(build_identity); // print information about current build identity + + // Get filesystem name from build identity + char* os_path = NULL; + retassure(!build_identity_get_component_path(build_identity, "OS", &os_path), "ERROR: Unable to get path for filesystem component"); + + { + /* check if IPSW has OS component 'stored' in ZIP archive, otherwise we need to extract it */ + int needs_os_extraction = 0; + if (client->ipsw->zip) { + ipsw_file_handle_t zfile = ipsw_file_open(client->ipsw, os_path); + if (zfile) { + if (!zfile->seekable) { + needs_os_extraction = 1; + } + ipsw_file_close(zfile); + } + } + + if (needs_os_extraction && !(client->flags & FLAG_SHSHONLY)) { + char* tmpf = NULL; + cleanup([&]{ + if (tmpf){ + unlink(tmpf); + safeFree(tmpf); + } + }); + struct stat st = {}; + if (client->cache_dir) { + char* ipsw_basename = NULL; + cleanup([&]{ + safeFree(ipsw_basename); + }); + memset(&st, '\0', sizeof(struct stat)); + if (stat(client->cache_dir, &st) < 0) { + mkdir_with_parents(client->cache_dir, 0755); + } + ipsw_basename = strdup(path_get_basename(client->ipsw->path)); + char* p = strrchr(ipsw_basename, '.'); + if (p && isalpha(*(p+1))) { + *p = '\0'; + } + tmpf = string_build_path(client->cache_dir, ipsw_basename, NULL); + mkdir_with_parents(tmpf, 0755); + tmpf = string_build_path(client->cache_dir, ipsw_basename, os_path, NULL); + } else { + tmpf = get_temp_filename(NULL); + client->delete_fs = 1; + } + + /* check if we already have it extracted */ + uint64_t fssize = 0; + ipsw_get_file_size(client->ipsw, os_path, &fssize); + memset(&st, '\0', sizeof(struct stat)); + if (stat(tmpf, &st) == 0) { + if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) { + info("Using cached filesystem from '%s'", tmpf); + client->filesystem = tmpf; tmpf = NULL; + } + } + + if (!client->filesystem) { + info("Extracting filesystem from IPSW: %s", os_path); + if (ipsw_extract_to_file_with_progress(client->ipsw, os_path, tmpf, 1) < 0) { + error("ERROR: Unable to extract filesystem from IPSW"); + info("Removing %s", tmpf); + reterror("ERROR: Unable to extract filesystem from IPSW"); + } + client->filesystem = tmpf; tmpf = NULL; + } + } + } - debug("Waiting for device to disconnect...\n"); - mutex_unlock(&client->device_event_mutex); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - retassure((client->mode == &idevicerestore_modes[MODE_UNKNOWN] || (mutex_unlock(&client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBEC. Reset device and try again"); - mutex_unlock(&client->device_event_mutex); - - debug("Waiting for device to reconnect...\n"); - mutex_unlock(&client->device_event_mutex); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - retassure((client->mode == &idevicerestore_modes[MODE_RECOVERY] || (mutex_unlock(&client->device_event_mutex),0)), "Device did not disconnect. Possibly invalid iBEC. Reset device and try again"); - mutex_unlock(&client->device_event_mutex); + info("About to restore device... "); + { + int result = 0; + client->user_cb_data = this; + client->restore_custom_component_function = [](struct idevicerestore_client_t* client, const char* name, void**data, size_t *dataSize)->int{ + tihmstar::Mem fcomponent; + const tihmstar::Mem *unsigned_component = NULL; + futurerestore *_this = (futurerestore*)(client->user_cb_data); + debug("restore_custom_component_function called with component '%s'",name); + + if (_this->_restorePwnage) { + if (_this->_persist_cfg.bootlogoIm4p.size() && !strcmp(name, "AppleLogo")){ + unsigned_component = &_this->_persist_cfg.bootlogoIm4p; + }else if (!strcmp(name, "KernelCache") || + !strcmp(name, "LLB") || + !strcmp(name, "iBoot")) { + fcomponent = _this->getComponentFromIPSW(client->ipsw->path,name); + + auto keys = libfwkeyfetch::getFirmwareKeyForComponent(client->device->product_type, client->build, name, client->device->chip_id); + ra1nsn0w::bootconfig bcfg = {&_this->_persist_cfg}; + if (!strcmp(name, "KernelCache")){ + fcomponent = ra1nsn0w::patchIMG3(fcomponent.data(), fcomponent.size(), keys.iv, keys.key, "Apple", (int(*)(void*,size_t,void*))ra1nsn0w::patchFuncKernel, &bcfg); + }else if (!strcmp(name, "LLB") || + !strcmp(name, "iBoot")) { + fcomponent = ra1nsn0w::patchIMG3(fcomponent.data(), fcomponent.size(), keys.iv, keys.key, "Apple", (int(*)(void*,size_t,void*))ra1nsn0w::patchFunciBoot, &bcfg); + } + unsigned_component = &fcomponent; + } else if (client->device->chip_id == 0x8900 && (!strcmp(client->version, "3.0") || !strcmp(client->version, "3.0.1"))) { + info("Force decrypting nor component '%s' for iOS 3.0/3.0.1 gid issue workaround",name); + fcomponent = _this->getComponentFromIPSW(client->ipsw->path, name); + auto keys = libfwkeyfetch::getFirmwareKeyForComponent(client->device->product_type, client->build, name, client->device->chip_id); + fcomponent = ra1nsn0w::patchIMG3(fcomponent.data(), fcomponent.size(), keys.iv, keys.key, "", [](void*, size_t, void*)->int{return 0;}, NULL); + unsigned_component = &fcomponent; + } + }else if (_this->_donorLLB.size() && strcmp(name, "LLB") == 0) { + unsigned_component = &_this->_donorLLB; + }else if (_this->_sep.size() && strcmp(name, "SEP") == 0){ + unsigned_component = &_this->_sep; + }else if (_this->_donorIPSW.size()){ + if (!strcmp(name, "BatteryCharging0") || + !strcmp(name, "BatteryCharging1") || + !strcmp(name, "BatteryFull") || + !strcmp(name, "BatteryLow0") || + !strcmp(name, "BatteryLow1") || + !strcmp(name, "BatteryPlugin") || + !strcmp(name, "RecoveryMode") || + !strcmp(name, "iBoot")) { + /* + Send valid iBoot and logos so that we can get out of battery charge trap + */ + fcomponent = _this->getComponentFromIPSW(_this->_donorIPSW.c_str(),name); + unsigned_component = &fcomponent; + } + } + + if (unsigned_component) { + if (client->image4supported) { + auto img4 = img4tool::getEmptyIMG4Container(); + img4 = img4tool::appendIM4PToIMG4(img4, {unsigned_component->data(),unsigned_component->size()}); + if (strcmp(name, "SEP") == 0) { + retassure(_this->_sepTicket.size(), "No SEP ticket found!"); + img4 = img4tool::appendIM4MToIMG4(img4, {_this->_sepTicket.data(),_this->_sepTicket.size()}); + } else if (!strcmp(name, "LLB") || + !strcmp(name, "BatteryCharging0") || + !strcmp(name, "BatteryCharging1") || + !strcmp(name, "BatteryFull") || + !strcmp(name, "BatteryLow0") || + !strcmp(name, "BatteryLow1") || + !strcmp(name, "BatteryPlugin") || + !strcmp(name, "RecoveryMode") || + !strcmp(name, "iBoot") + ) { + tihmstar::Mem im4mRaw; + try { + im4mRaw = _this->_im4ms.at(0); + } catch (...) { + reterror("Failed to get IM4M!"); + } + img4 = img4tool::appendIM4MToIMG4(img4, {im4mRaw.data(),im4mRaw.size()}); + }else{ + reterror("Unexpected component '%s'",name); + } + if (dataSize) *dataSize = img4.size(); + if (data){ + safeFree(*data); + void *ldata = malloc(img4.size()); + memcpy(ldata, img4.buf(), img4.size()); + *data = (unsigned char*)ldata; + } + return 0; + }else{ + tihmstar::Mem signedComponent; + if (!strcmp(name, "LLB") && _this->_restore24kpwn){ + info("Injecting 24kpwn exploit into LLB!"); + signedComponent = img3tool::do24kpwn(unsigned_component->data(), unsigned_component->size(), client->device->chip_id); + } else if (_this->_no_ticket_needed) { + warning("Not personalizing component '%s' because we're told that no ticket is needed",name); + signedComponent = *unsigned_component; + }else{ + retassure(_this->_client->tss, "We're asked to personalize '%s', but we don't have a ticket!!",name); + signedComponent = img3tool::signIMG3WithSHSH(unsigned_component->data(), unsigned_component->size(), _this->_client->tss); + } + if (dataSize) *dataSize = (unsigned int)signedComponent.size(); + if (data) { + safeFree(*data); + void *ldata = malloc(signedComponent.size()); + memcpy(ldata, signedComponent.data(), signedComponent.size()); + *data = (unsigned char*)ldata; + } + return 0; + } + } + return 1; + }; + retassure(!(result = restore_device(client, build_identity)), "ERROR: Unable to restore device"); + client->user_cb_data = NULL; + client->restore_custom_component_function = NULL; } +} - retassure(client->mode == &idevicerestore_modes[MODE_RECOVERY], "failed to reconnect to device in recovery (iBEC) mode\n"); - - //do magic - if (_client->image4supported) get_sep_nonce(client, &client->sepnonce, &client->sepnonce_size); - get_ap_nonce(client, &client->nonce, &client->nonce_size); - get_ecid(client, &client->ecid); - - if (client->mode->index == MODE_RECOVERY) { - retassure(client->srnm,"ERROR: could not retrieve device serial number. Can't continue.\n"); - - retassure(!irecv_send_command(client->recovery->client, "bgcolor 0 255 0"), "ERROR: Unable to set bgcolor\n"); - info("[WARNING] Setting bgcolor to green! If you don't see a green screen, then your device didn't boot iBEC correctly\n"); - sleep(2); //show the user a green screen! - - retassure(!recovery_enter_restore(client, build_identity),"ERROR: Unable to place device into restore mode\n"); - - recovery_client_free(client); - } - - if (_client->image4supported) { - info("getting SEP ticket\n"); - retassure(!get_tss_response(client, sep_build_identity, &client->septss), "ERROR: Unable to get signing tickets for SEP\n"); - retassure(_client->sepfwdatasize && _client->sepfwdata, "SEP is not loaded, refusing to continue"); +void futurerestore::enterPwnRestore(const char *ipswpath, bool is32Bit, const char *bootargs, ra1nsn0w::launchConfig cfg){ + bool hasSEP = false; + { + unsigned char* nonce = NULL; + cleanup([&]{ + safeFree(nonce); + }); + unsigned int nonceSize = 0; + + retassure(!get_sep_nonce(_client, &nonce, &nonceSize),"Failed to query sepnonce"); + hasSEP = nonce != NULL; } - mutex_lock(&client->device_event_mutex); - debug("Waiting for device to enter restore mode...\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 180000); - retassure((client->mode == &idevicerestore_modes[MODE_RESTORE] || (mutex_unlock(&client->device_event_mutex),0)), "Device can't enter to restore mode"); - mutex_unlock(&client->device_event_mutex); - - info("About to restore device... \n"); - int result = 0; - retassure(!(result = restore_device(client, build_identity, filesystem)), "ERROR: Unable to restore device\n"); -} - -int futurerestore::doJustBoot(const char *ipsw, string bootargs){ - reterror("not implemented"); -// int err = 0; -// //some memory might not get freed if this function throws an exception, but you probably don't want to catch that anyway. -// -// struct idevicerestore_client_t* client = _client; -// int unused; -// int result = 0; -// plist_t buildmanifest = NULL; -// plist_t build_identity = NULL; -// -// client->ipsw = strdup(ipsw); -// -// getDeviceMode(true); -// info("Found device in %s mode\n", client->mode->string); -// -// retassure((client->mode->index == MODE_DFU || client->mode->index == MODE_RECOVERY) && _enterPwnRecoveryRequested, "device not in DFU/Recovery mode\n"); -// -// // discover the device type -// retassure(check_hardware_model(client) && client->device,"ERROR: Unable to discover device model\n"); -// info("Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type); -// -// // verify if ipsw file exists -// retassure(!access(client->ipsw, F_OK), "ERROR: Firmware file %s does not exist.\n", client->ipsw); -// info("Extracting BuildManifest from IPSW\n"); -// -// retassure(!ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &unused),"ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw); -// -// /* check if device type is supported by the given build manifest */ -// retassure(!build_manifest_check_compatibility(buildmanifest, client->device->product_type),"ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n"); -// -// /* print iOS information from the manifest */ -// build_manifest_get_version_information(buildmanifest, client); -// -// info("Product Version: %s\n", client->version); -// info("Product Build: %s Major: %d\n", client->build, client->build_major); -// -// client->image4supported = is_image4_supported(client); -// info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); -// -// retassure(build_identity = getBuildidentityWithBoardconfig(buildmanifest, client->device->hardware_model, 0),"ERROR: Unable to find any build identities for IPSW\n"); -// -// /* print information about current build identity */ -// build_identity_print_information(build_identity); -// -// //check for enterpwnrecovery, because we could be in DFU mode -// retassure(_enterPwnRecoveryRequested, "enterPwnRecoveryRequested is not set, but required"); -// -// retassure(getDeviceMode(true) == MODE_DFU || getDeviceMode(false) == MODE_RECOVERY, "unexpected device mode\n"); -// -// enterPwnRecovery(build_identity, bootargs); -// -// client->recovery_custom_component_function = get_custom_component; -// -// for (int i=0;getDeviceMode(true) != MODE_RECOVERY && i<40; i++) putchar('.'),usleep(USEC_PER_SEC*0.5); -// putchar('\n'); -// -// retassure(check_mode(client), "failed to reconnect to device in recovery (iBEC) mode\n"); -// -// get_ecid(client, &client->ecid); -// -// client->flags |= FLAG_BOOT; -// -// if (client->mode->index == MODE_RECOVERY) { -// retassure(client->srnm,"ERROR: could not retrieve device serial number. Can't continue.\n"); -// -// retassure(!irecv_send_command(client->recovery->client, "bgcolor 0 255 0"), "ERROR: Unable to set bgcolor\n"); -// -// info("[WARNING] Setting bgcolor to green! If you don't see a green screen, then your device didn't boot iBEC correctly\n"); -// sleep(2); //show the user a green screen! -// client->image4supported = true; //dirty hack to not require apticket -// -// retassure(!recovery_enter_restore(client, build_identity),"ERROR: Unable to place device into restore mode\n"); -// -// client->image4supported = false; -// recovery_client_free(client); -// } -// -// info("Cleaning up...\n"); -// -//error: -// safeFree(client->sepfwdata); -// safeFreeCustom(buildmanifest, plist_free); -// if (!result && !err) info("DONE\n"); -// return result ? abs(result) : err; -} - -futurerestore::~futurerestore(){ - recovery_client_free(_client); - idevicerestore_client_free(_client); - for (auto im4m : _im4ms){ - safeFree(im4m.first); + tihmstar::Mem ticket; + try { + _client->tss = _aptickets.at(0); + } catch (...) { + retassure(_no_ticket_needed,"failed to get ticket"); } - safeFree(_ibootBuild); - safeFree(_firmwareJson); - safeFree(_firmwareTokens); - safeFree(__latestManifest); - safeFree(__latestFirmwareUrl); - for (auto plist : _aptickets){ - safeFreeCustom(plist, plist_free); + + try { + ticket = _im4ms.at(0); + } catch (...) { + error("failed to get ticket data"); } - safeFreeCustom(_sepbuildmanifest, plist_free); - safeFreeCustom(_basebandbuildmanifest, plist_free); -} -void futurerestore::loadFirmwareTokens(){ - if (!_firmwareTokens){ - if (!_firmwareJson) _firmwareJson = getFirmwareJson(); - retassure(_firmwareJson,"[TSSC] could not get firmware.json\n"); - int cnt = parseTokens(_firmwareJson, &_firmwareTokens); - retassure(cnt>0,"[TSSC] parsing %s.json failed\n",(0) ? "ota" : "firmware"); + + cfg.restoreBoot = true; + _persist_cfg.is32Bit = cfg.is32Bit = is32Bit; + if (_sep.size()) { + auto img4 = img4tool::getEmptyIMG4Container(); + img4 = img4tool::appendIM4PToIMG4(img4, {_sep.data(),_sep.size()}); + img4 = img4tool::appendIM4MToIMG4(img4, {_sepTicket.data(),_sepTicket.size()}); + cfg.sepIm4p = {img4.buf(),img4.size()}; } -} - -const char *futurerestore::getDeviceModelNoCopy(){ - if (!_client->device || !_client->device->product_type){ - - int mode = getDeviceMode(true); - retassure(mode == MODE_NORMAL || mode == MODE_RECOVERY || mode == MODE_DFU, "unexpected device mode=%d\n",mode); - - switch (mode) { - case MODE_RESTORE: - _client->device = restore_get_irecv_device(_client); - break; - case MODE_NORMAL: - _client->device = normal_get_irecv_device(_client); - break; - case MODE_DFU: - case MODE_RECOVERY: - _client->device = dfu_get_irecv_device(_client); - break; - default: - break; + if (bootargs) { + cfg.bootargs = bootargs; + } + + if (_customRamdisk.size()) { + cfg.kpatch_codesig = tihmstar::ra1nsn0w::kPatchcfgYes; + cfg.ramdiskIm4p = _customRamdisk; + }else{ + cfg.ramdiskIm4p = getRamdiskForDevice(ipswpath); + } + + if (getDeviceCPID() == 0x8900 && (!strcmp(_client->version, "3.0") || !strcmp(_client->version, "3.0.1"))) { + /* + Workaround for weird dummy gid issue which turns out to actually tie iboot hash or something to the key + We can avoid bad key by just having everything already decrypted + */ + info("Enabling 0x8900 iOS 3.0 / 3.0.1 workaround!"); + _needsDecryptedRamdisk = true; + cfg.decrypt_devicetree = true; + } + + if (_needsDecryptedRamdisk) { + if (_client->image4supported) { + reterror("TODO"); + }else{ + auto kb = img3tool::getKBAG(cfg.ramdiskIm4p.data(), cfg.ramdiskIm4p.size(), 1); + std::string kbhex; + kbhex.resize(kb.size()*1+2); + size_t kbhexSize = kbhex.size(); + tihmstar::bytesToHex(kb.data(), kb.size(), (char*)kbhex.data(), &kbhexSize); + auto keys = libfwkeyfetch::getFirmwareKeyForKBAG(kbhex); + cfg.ramdiskIm4p = ra1nsn0w::patchIMG3(cfg.ramdiskIm4p.data(), cfg.ramdiskIm4p.size(), keys.iv, keys.key, "Apple", [](void*, size_t, void*)->int{return 0;}, NULL); } } - return _client->device->product_type; + if (ticket.size()) { + if (_client->image4supported) { + cfg.boot_manifest_hash.resize(SHA_DIGEST_LENGTH); + SHA1((const unsigned char *)ticket.data(), (uint32_t)ticket.size(), (unsigned char*)cfg.boot_manifest_hash.data()); + }else{ + if (!_client->version || atoi(_client->version) >= 5) { + cfg.root_ticket_hash.resize(SHA_DIGEST_LENGTH); + SHA1((const unsigned char *)ticket.data(), (uint32_t)ticket.size(), (unsigned char*)cfg.root_ticket_hash.data()); + } + } + } + dfu_client_free(_client); + recovery_client_free(_client); + + std::string file = "file://"; + file += ipswpath; + img4tool::ASN1DERElement im4mData; + if (_im4ms.size()) { + retassure(_im4ms.size() == 1, "TODO: selection of im4m is not implemented!"); + auto t = _im4ms.at(0); + im4mData = {t.data(),t.size()}; + }else{ + retassure(!_client->image4supported, "img4 always needs APTicket for sigcheck bypass!"); + } + + { + ra1nsn0w::iOSDevice dev(_client->ecid); + ra1nsn0w::launchDevice(dev, file, cfg, im4mData); + } +} + +void futurerestore::enterRestore(const char *ipswpath){ + plist_t p_buildmanifest = NULL; + cleanup([&]{ + safeFreeCustom(p_buildmanifest, plist_free); + }); + int err = 0; + plist_t p_buildidentity = NULL; + + { + auto mode = getDeviceMode(); + info("Found device in %s mode", mode->string); + } + info("Identified device as %s, %s", getDeviceBoardNoCopy(), getDeviceModelNoCopy()); + + safeFreeCustom(_client->ipsw, ipsw_close); + retassure(_client->ipsw = ipsw_open(ipswpath), "Failed to open ipsw '%s'",ipswpath); + + { + int unused = 0; + retassure(!(err = ipsw_extract_build_manifest(_client->ipsw, &p_buildmanifest, &unused)), "Failed to extract BuildManifest.plist from"); + } + + retassure(!build_manifest_check_compatibility(p_buildmanifest, _client->device->product_type),"ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue."); + + /* print iOS information from the manifest */ + build_manifest_get_version_information(p_buildmanifest, _client); + info("Product version: %s", _client->version); + info("Product build: %s Major: %d", _client->build, _client->build_major); + + retassure(p_buildidentity = build_manifest_get_build_identity_for_model_with_variant(p_buildmanifest, getDeviceBoardNoCopy(), ""/*any*/, 0),"ERROR: Unable to find any build identities for IPSW"); + + try { + retassure(_client->tss = plist_copy(_aptickets.at(0)),"plist_copy tss failed"); + } catch (...) { + reterror("failed to read apticket!"); + } + + if (getDeviceMode() == MODE_DFU) { + retassure(!(err = dfu_enter_recovery(_client, p_buildidentity)),"Failed to enter recovery mode"); + } + + if (getDeviceMode() == MODE_RECOVERY) { + retassure(!(err = recovery_enter_restore(_client, p_buildidentity)),"Failed to enter restore mode"); + } + + if (getDeviceMode() != MODE_RESTORE){ + reterror("Failed to enter restore mode!"); + } +} + +void futurerestore::setLLBFromIPSW(const char *llbipswpath){ + plist_t p_buildmanifest = NULL; + char *llbpath = NULL; + void *llbbuf = NULL; + ipsw_archive_t llbipsw = NULL; + cleanup([&]{ + safeFreeCustom(llbipsw, ipsw_close); + safeFree(llbbuf); + safeFree(llbpath); + safeFreeCustom(p_buildmanifest, plist_free); + }); + size_t llbbufsize = 0; + plist_t p_buildidentity = NULL; + + int err = 0; + + { + auto mode = getDeviceMode(); + info("Found device in %s mode", mode->string); + } + info("Identified device as %s, %s", getDeviceBoardNoCopy(), getDeviceModelNoCopy()); + + retassure(llbipsw = ipsw_open(llbipswpath), "Failed to open llbipsw '%s'",llbipswpath); + + { + int unused = 0; + retassure(!(err = ipsw_extract_build_manifest(llbipsw, &p_buildmanifest, &unused)), "Failed to extract BuildManifest.plist from '%s'",llbipsw); + } + + retassure(p_buildidentity = build_manifest_get_build_identity_for_model_with_variant(p_buildmanifest, getDeviceBoardNoCopy(), ""/*any*/, 0),"ERROR: Unable to find any build identities for IPSW"); + + retassure(!build_identity_get_component_path(p_buildidentity, "LLB", &llbpath), "ERROR: Unable to get path for LLB component"); + + retassure(!extract_component(llbipsw, llbpath, &llbbuf, &llbbufsize),"Failed to extract ramdisk"); + _donorLLB = {llbbuf,llbbufsize}; llbbuf = NULL; llbbufsize = 0; + + { + debug("Checking if APTicket is valid for donorLLB..."); + if (_client->image4supported) { + tihmstar::Mem im4mRaw; + try { + im4mRaw = _im4ms.at(0); + } catch (...) { + reterror("Failed to get APTicket"); + } + img4tool::ASN1DERElement im4m{im4mRaw.data(),im4mRaw.size()}; + retassure(img4tool::isIM4PValidForIM4M({_donorLLB.data(), _donorLLB.size()}, im4m), "APTicket is not valid for donorLLB"); + retassure(img4tool::isIM4MSignatureValid(im4m), "APTicket is not valid"); + }else{ + plist_t ticket = NULL; + try { + ticket = _aptickets.at(0); + } catch (...) { + reterror("Failed to get APTicket"); + } + retassure(img3tool::verifySignedIMG3FileForSHSH(_donorLLB.data(), _donorLLB.size(), ticket), "APTicket is not valid for donorLLB"); + } + info("APTicket is valid for donorLLB!"); + } + _donorIPSW = llbipswpath; } const char *futurerestore::getDeviceBoardNoCopy(){ if (!_client->device || !_client->device->product_type){ - - int mode = getDeviceMode(true); - retassure(mode == MODE_NORMAL || mode == MODE_RECOVERY || mode == MODE_DFU, "unexpected device mode=%d\n",mode); + auto mode = getDeviceMode(); + retassure(mode == MODE_NORMAL || mode == MODE_RECOVERY || mode == MODE_DFU || mode == MODE_RESTORE, "unexpected device mode=%d",mode->index); - switch (mode) { - case MODE_RESTORE: + switch (mode->index) { + case _MODE_RESTORE: _client->device = restore_get_irecv_device(_client); break; - case MODE_NORMAL: + case _MODE_NORMAL: _client->device = normal_get_irecv_device(_client); break; - case MODE_DFU: - case MODE_RECOVERY: + case _MODE_RECOVERY: + _client->device = recovery_get_irecv_device(_client); + break; + case _MODE_DFU: + dfu_client_free(_client); _client->device = dfu_get_irecv_device(_client); break; default: break; } } + retassure(_client->device,"Failed to get device board"); return _client->device->hardware_model; } -char *futurerestore::getLatestManifest(){ - if (!__latestManifest){ - loadFirmwareTokens(); - - const char *device = getDeviceModelNoCopy(); - t_iosVersion versVals; - memset(&versVals, 0, sizeof(versVals)); +const char *futurerestore::getDeviceModelNoCopy(){ + if (!_client->device || !_client->device->product_type){ + auto mode = getDeviceMode(); + retassure(mode == MODE_NORMAL || mode == MODE_RECOVERY || mode == MODE_DFU, "unexpected device mode=%d",mode); - int versionCnt = 0; - int i = 0; - char **versions = getListOfiOSForDevice(_firmwareTokens, device, 0, &versionCnt); - retassure(versionCnt, "[TSSC] failed finding latest firmware version\n"); - char *bpos = NULL; - while((bpos = strstr((char*)(versVals.version = strdup(versions[i++])),"[B]")) != 0){ - free((char*)versVals.version); - if (--versionCnt == 0) reterror("[TSSC] automatic selection of firmware couldn't find for non-beta versions\n"); + switch (mode->index) { + case _MODE_RESTORE: + _client->device = restore_get_irecv_device(_client); + break; + case _MODE_NORMAL: + _client->device = normal_get_irecv_device(_client); + break; + case _MODE_RECOVERY: + _client->device = recovery_get_irecv_device(_client); + break; + case _MODE_DFU: + dfu_client_free(_client); + _client->device = dfu_get_irecv_device(_client); + break; + default: + break; } - info("[TSSC] selecting latest firmware version: %s\n",versVals.version); - if (bpos) *bpos= '\0'; - if (versions) free(versions[versionCnt-1]),free(versions); - - ptr_smartautofree(versVals.version); //make sure it get's freed after function finishes execution by either reaching end or throwing exception - - __latestFirmwareUrl = getFirmwareUrl(device, &versVals, _firmwareTokens); - 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(_client->device,"Failed to get device board"); + return _client->device->product_type; +} + +plist_t futurerestore::nonceMatchesApTickets(){ + reterror("todo"); +} + +tihmstar::Mem futurerestore::nonceMatchesIM4Ms(){ + reterror("todo"); +// retassure(_didInit, "did not init"); +// +// retassure(getDeviceMode(true) == MODE_RECOVERY, "Device is not in recovery mode, can't check ApNonce"); +// +// unsigned char* realnonce; +// int realNonceSize = 0; +// recovery_get_ap_nonce(_client, &realnonce, &realNonceSize); +// +// vectornonces; +// +// if (_client->image4supported) { +// for (int i=0; i< _im4ms.size(); i++){ +// auto nonce = img4tool::getValFromIM4M({_im4ms[i].first,_im4ms[i].second}, 'BNCH'); +// if (nonce.payloadSize() == realNonceSize && memcmp(realnonce, nonce.payload(), realNonceSize) == 0) return _im4ms[i]; +// } +// }else{ +// for (int i=0; i< _im4ms.size(); i++){ +// size_t ticketNonceSize = 0; +// const char *nonce = NULL; +// try { +// //nonce might not exist, which we use in re-restoring iOS 9.x for 32-bit +// auto n = getNonceFromSCAB(_im4ms[i].first, _im4ms[i].second); +// ticketNonceSize = n.second; +// nonce = n.first; +// } catch (...) { +// // +// } +// if (memcmp(realnonce, nonce, ticketNonceSize) == 0) return _im4ms[i]; +// } +// } +// +// return {}; +} + +uint64_t futurerestore::getDeviceEcid(){ + uint64_t ecid = _client->ecid; + retassure(ecid, "Failed to get ecid"); + return ecid; +} + +uint32_t futurerestore::getDeviceCPID(){ + uint32_t cpid = 0; + auto mode = getDeviceMode(); + switch (mode->index) { + case _MODE_WTF: + return 0x8900; //there is no other device with WTF mode + + case _MODE_DFU: + retassure(!dfu_get_cpid(_client, &cpid),"Failed to get CPID in DFU mode"); + break; + case _MODE_RECOVERY: + retassure(!recovery_get_cpid(_client, &cpid),"Failed to get CPID in recovery mode"); + break; + default: + reterror("Found device in unexpected mode '%s'",mode->string); + break; + } + return cpid; +} + +uint32_t futurerestore::getDeviceBDID(){ + uint32_t bdid = 0; + auto mode = getDeviceMode(); + switch (mode->index) { + case _MODE_DFU: + retassure(!dfu_get_bdid(_client, &bdid),"Failed to get BDID in DFU mode"); + break; + case _MODE_RECOVERY: + retassure(!recovery_get_bdid(_client, &bdid),"Failed to get BDID in recovery mode"); + break; + + default: + reterror("Found device in unexpected mode '%s'",mode->string); + break; + } + return bdid; +} + +void futurerestore::requestFreshAPTicket(plist_t p_BuildManifest, const char *variant){ + uint8_t *sepnonce = NULL; + plist_t p_APTicket = NULL; + cleanup([&]{ + safeFreeCustom(p_APTicket, plist_free); + safeFree(sepnonce); + }); + size_t sepnonceSize = 0; + int err = 0; - return __latestManifest; -} - -char *futurerestore::getLatestFirmwareUrl(){ - return getLatestManifest(),__latestFirmwareUrl; -} - -void futurerestore::loadLatestBaseband(){ - char * manifeststr = getLatestManifest(); - char *pathStr = getPathOfElementInManifest("BasebandFirmware", manifeststr, getDeviceModelNoCopy(), 0); - info("downloading Baseband\n\n"); - retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, _basebandPath = BASEBAND_TMP_PATH), "could not download baseband\n"); - saveStringToFile(manifeststr, BASEBAND_MANIFEST_TMP_PATH); - setBasebandManifestPath(BASEBAND_MANIFEST_TMP_PATH); - setBasebandPath(BASEBAND_TMP_PATH); -} - -void futurerestore::loadLatestSep(){ - char * manifeststr = getLatestManifest(); - char *pathStr = getPathOfElementInManifest("SEP", manifeststr, getDeviceModelNoCopy(), 0); - info("downloading SEP\n\n"); - retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, SEP_TMP_PATH), "could not download SEP\n"); - loadSep(SEP_TMP_PATH); - saveStringToFile(manifeststr, SEP_MANIFEST_TMP_PATH); - setSepManifestPath(SEP_MANIFEST_TMP_PATH); -} - -void futurerestore::setSepManifestPath(const char *sepManifestPath){ - retassure(_sepbuildmanifest = loadPlistFromFile(_sepbuildmanifestPath = sepManifestPath), "failed to load SEPManifest"); -} - -void futurerestore::setBasebandManifestPath(const char *basebandManifestPath){ - retassure(_basebandbuildmanifest = loadPlistFromFile(_basebandbuildmanifestPath = basebandManifestPath), "failed to load BasebandManifest"); -}; - -void futurerestore::loadSep(const char *sepPath){ - FILE *fsep = NULL; - retassure(fsep = fopen(sepPath, "rb"), "failed to read SEP\n"); + if (!variant) variant = RESTORE_VARIANT_ERASE_INSTALL; + tsschecker::TssRequest req(p_BuildManifest,variant); + req.setDeviceVals(getDeviceCPID(), getDeviceBDID()); + req.setEcid(getDeviceEcid()); - fseek(fsep, 0, SEEK_END); - _client->sepfwdatasize = ftell(fsep); - fseek(fsep, 0, SEEK_SET); + retassure(!(err = get_ap_nonce(_client, &_client->nonce, &_client->nonce_size)), "Failed to get APNonce with err=%d",err); + if (_client->nonce_size) req.setAPNonce(_client->nonce,_client->nonce_size); - retassure(_client->sepfwdata = (char*)malloc(_client->sepfwdatasize), "failed to malloc memory for SEP\n"); + retassure(!(err = get_sep_nonce(_client, &sepnonce, (unsigned int*)&sepnonceSize)), "Failed to get SEPNonce with err=%d",err); + if (sepnonceSize) req.setSEPNonce(sepnonce,sepnonceSize); - size_t freadRet=0; - retassure((freadRet = fread(_client->sepfwdata, 1, _client->sepfwdatasize, fsep)) == _client->sepfwdatasize, - "failed to load SEP. size=%zu but fread returned %zu\n",_client->sepfwdatasize,freadRet); + req.addDefaultAPTagsToRequest(); + req.addAllAPComponentsToRequest(); - fclose(fsep); + p_APTicket = req.getTSSResponce(); + { + char *im4m = NULL; + cleanup([&]{ + safeFree(im4m); + }); + uint64_t im4msize=0; + plist_t ticket = plist_dict_get_item(p_APTicket, (_client->image4supported) ? "ApImg4Ticket" : "APTicket"); + plist_get_data_val(ticket, &im4m, &im4msize); + if (!im4msize){ + warning("SHSH file does NOT contain APTicket!"); + } + _im4ms.push_back({im4m,im4msize}); im4m = NULL; im4msize = 0; + } + _aptickets.push_back(p_APTicket); p_APTicket = NULL; } -void futurerestore::setBasebandPath(const char *basebandPath){ - FILE *fbb = NULL; - - retassure(fbb = fopen(basebandPath, "rb"), "failed to read Baseband"); - _basebandPath = basebandPath; - fclose(fbb); -} - -#pragma mark static methods -inline void futurerestore::saveStringToFile(const char *str, const char *path){ - FILE *f = NULL; - retassure(f = fopen(path, "w"), "can't save file at %s\n",path); - size_t len = strlen(str); - size_t wlen = fwrite(str, 1, len, f); - fclose(f); - retassure(len == wlen, "saving file failed, wrote=%zu actual=%zu\n",wlen,len); -} - -std::pair futurerestore::getNonceFromSCAB(const char* scab, size_t scabSize){ - retassure(scab, "Got empty SCAB\n"); +void futurerestore::requestFreshSEPTicket(plist_t p_BuildManifest, const char *variant){ + uint8_t *sepnonce; + plist_t p_APTicket = NULL; + cleanup([&]{ + safeFreeCustom(p_APTicket, plist_free); + safeFree(sepnonce); + }); + size_t sepnonceSize = 0; + int err = 0; + if (!variant) variant = RESTORE_VARIANT_ERASE_INSTALL; + tsschecker::TssRequest req(p_BuildManifest,variant); + req.setDeviceVals(getDeviceCPID(), getDeviceBDID()); + req.setEcid(getDeviceEcid()); + + retassure(!(err = get_ap_nonce(_client, &_client->nonce, &_client->nonce_size)), "Failed to get APNonce with err=%d",err); + if (_client->nonce_size) req.setAPNonce(_client->nonce,_client->nonce_size); + + retassure(!(err = get_sep_nonce(_client, &sepnonce, (unsigned int*)&sepnonceSize)), "Failed to get SEPNonce with err=%d",err); + if (sepnonceSize) req.setSEPNonce(sepnonce,sepnonceSize); + + req.addDefaultAPTagsToRequest(); + req.addComponent("SEP"); + req.addComponent("RestoreSEP"); + + p_APTicket = req.getTSSResponce(); + + { + char *im4m = NULL; + cleanup([&]{ + safeFree(im4m); + }); + uint64_t im4msize=0; + plist_t ticket = plist_dict_get_item(p_APTicket, (_client->image4supported) ? "ApImg4Ticket" : "APTicket"); + plist_get_data_val(ticket, &im4m, &im4msize); + retassure(im4msize, "SHSH file does NOT contain SEP-APTicket!"); + _sepTicket = {im4m,im4msize}; im4m = NULL; im4msize = 0; + } +} + +void futurerestore::requestFreshAPTicket(const char *ipswpath, const char *variant){ + char *buf = NULL; + plist_t p_BuildManifest = NULL; + ipsw_archive_t ipsw = NULL; + cleanup([&]{ + safeFreeCustom(ipsw, ipsw_close); + safeFreeCustom(p_BuildManifest, plist_free); + safeFree(buf); + }); + size_t bufSize = 0; + int err = 0; + plist_err_t perr = PLIST_ERR_SUCCESS; + + retassure(ipsw = ipsw_open(ipswpath), "Failed to open ipsw '%s'",ipswpath); + + retassure(!(err = ipsw_extract_to_memory(ipsw, "BuildManifest.plist", (void**)&buf, &bufSize)), "Failed to extract BuildManifest.plist with err=%d from ipsw at path=%s",err,ipsw); + retassure(!(perr = plist_from_memory(buf, (uint32_t)bufSize, &p_BuildManifest, NULL)),"Failed to parse BuildManifest.plist"); + return requestFreshAPTicket(p_BuildManifest, variant); +} + +void futurerestore::fetchLatestBaseband(){ + plist_t p_latestManifest = loadBuilmanifestForLatestFirmware(); + plist_t p_BuildIdentity = tsschecker::TssRequest::getBuildIdentityForDevice(p_latestManifest, getDeviceCPID(), getDeviceBDID()); + + safeFreeCustom(_client->bbfw_buildidentity, plist_free); + _client->bbfw_buildidentity = plist_copy(p_BuildIdentity); + + auto bbfwpath = tsschecker::TssRequest::getPathForComponentBuildIdentity(p_BuildIdentity, "BasebandFirmware"); + auto bbfw = tsschecker::downloadFileFromIPSW(_latestFirmwareUrl.c_str(), bbfwpath.c_str()); + tihmstar::writeFile(BASEBAND_TMP_PATH, bbfw.data(), bbfw.size()); + safeFree(_client->bbfwpath); + _client->bbfwpath = strdup(BASEBAND_TMP_PATH); +} + +void futurerestore::fetchLatestSEP(){ + plist_t p_latestManifest = loadBuilmanifestForLatestFirmware(); + plist_t p_BuildIdentity = tsschecker::TssRequest::getBuildIdentityForDevice(p_latestManifest, getDeviceCPID(), getDeviceBDID()); + + safeFreeCustom(_client->bbfw_buildidentity, plist_free); + _client->bbfw_buildidentity = plist_copy(p_BuildIdentity); + + auto fwpath = tsschecker::TssRequest::getPathForComponentBuildIdentity(p_BuildIdentity, "SEP"); + _sep = tsschecker::downloadFileFromIPSW(_latestFirmwareUrl.c_str(), fwpath.c_str()); + requestFreshSEPTicket(p_latestManifest); +} + +void futurerestore::setCustomBasebandPath(const char *basebandPath){ + safeFree(_client->bbfwpath); + _client->bbfwpath = strdup(basebandPath); + retassure(!tihmstar::fileExists(_client->bbfwpath), "Faile does not exist at path '%s'",_client->bbfwpath); +} + +void futurerestore::setCustomSEPPath(const char *sepPath){ + _sep = tihmstar::readFile(sepPath); +} + +void futurerestore::setCustomBasebandManifest(plist_t basebandManifest){ + safeFreeCustom(_client->bbfw_buildidentity, plist_free); + _client->bbfw_buildidentity = plist_copy(basebandManifest); +} + +void futurerestore::setCustomSEPManifest(plist_t SEPManifest){ + requestFreshSEPTicket(SEPManifest); +} + +void futurerestore::setCustomRamdisk(const char *ramdiskPath){ + _customRamdisk = readFile(ramdiskPath); +} + +void futurerestore::verifyBasebandTicketCanBeRequested(){ + if (_client->bbfw_buildidentity) { + info("Checking whether Baseband Ticket can be requested"); + tsschecker::TssRequest req(_client->bbfw_buildidentity, "", true); + req.addBasebandComponentsToRequest(); + req.setDeviceVals(getDeviceCPID(), getDeviceBDID()); + req.setEcid(getDeviceEcid()); + req.setDefaultBbGoldCertId(); + req.setRandomSNUM(); + try { + plist_t p_BBTicket = NULL; + cleanup([&]{ + safeFreeCustom(p_BBTicket, plist_free); + }); + p_BBTicket = req.getTSSResponce(); + }catch (tihmstar::exception &e){ + reterror("Failed to verify that requesting Baseband ticket is possible. Erro:\n%s",e.dumpStr().c_str()); + } + info("Success checking Baseband ticket availablility!"); + }else{ + info("Custom Baseband ticket was not requested for this restore"); + retassure(!tsschecker::getGoldCertIDForDevice(tsschecker::getProductTypeFromCPIDandBDID(getDeviceCPID(), getDeviceBDID())), "Custom Baseband ticket was not requested, but device has a baseband!"); + } +} + +#pragma mark static +tihmstar::Mem futurerestore::getRamdiskHashFromSCAB(const void* scab, size_t scabSize){ + retassure(scab, "Got empty SCAB"); + img4tool::ASN1DERElement bacs(scab,scabSize); - + try { bacs[3]; } catch (...) { - reterror("unexpected number of Elements in SCAB sequence (expects 4)\n"); + reterror("unexpected number of Elements in SCAB sequence (expects 4)"); } - + img4tool::ASN1DERElement mainSet = bacs[1]; for (auto &elem : mainSet) { - if (*(uint8_t*)elem.buf() == 0x92) { - return {(char*)elem.payload(),elem.payloadSize()}; + if (*(uint8_t*)elem.buf() == 0x9A) { + return {(const uint8_t*)elem.payload(),elem.payloadSize()}; } } reterror("failed to get nonce from SCAB"); - return {NULL,0}; + return {}; } -uint64_t futurerestore::getEcidFromSCAB(const char* scab, size_t scabSize){ - retassure(scab, "Got empty SCAB\n"); +uint64_t futurerestore::getEcidFromSCAB(const void* scab, size_t scabSize){ + retassure(scab, "Got empty SCAB"); img4tool::ASN1DERElement bacs(scab,scabSize); try { bacs[3]; } catch (...) { - reterror("unexpected number of Elements in SCAB sequence (expects 4)\n"); + reterror("unexpected number of Elements in SCAB sequence (expects 4)"); } img4tool::ASN1DERElement mainSet = bacs[1]; @@ -1336,7 +1441,7 @@ uint64_t futurerestore::getEcidFromSCAB(const char* scab, size_t scabSize){ for (auto &elem : mainSet) { if (*(uint8_t*)elem.buf() == 0x81) { uint64_t ret = 0; - for (int i=0; i=0; i--) { ret <<=8; ret |= ((uint8_t*)elem.payload())[i]; } @@ -1348,97 +1453,3 @@ uint64_t futurerestore::getEcidFromSCAB(const char* scab, size_t scabSize){ return 0; } -std::pairfuturerestore::getRamdiskHashFromSCAB(const char* scab, size_t scabSize){ - retassure(scab, "Got empty SCAB\n"); - - img4tool::ASN1DERElement bacs(scab,scabSize); - - try { - bacs[3]; - } catch (...) { - reterror("unexpected number of Elements in SCAB sequence (expects 4)\n"); - } - - img4tool::ASN1DERElement mainSet = bacs[1]; - - for (auto &elem : mainSet) { - if (*(uint8_t*)elem.buf() == 0x9A) { - return {(char*)elem.payload(),elem.payloadSize()}; - } - } - reterror("failed to get nonce from SCAB"); - return {NULL,0}; -} - -plist_t futurerestore::loadPlistFromFile(const char *path){ - plist_t ret = NULL; - - FILE *f = fopen(path,"rb"); - if (!f){ - error("could not open file %s\n",path); - return NULL; - } - fseek(f, 0, SEEK_END); - size_t bufSize = ftell(f); - fseek(f, 0, SEEK_SET); - - char *buf = (char*)malloc(bufSize); - if (!buf){ - error("failed to alloc memory\n"); - return NULL; - } - - size_t freadRet = 0; - if ((freadRet = fread(buf, 1, bufSize, f)) != bufSize){ - error("fread=%zu but bufsize=%zu",freadRet,bufSize); - return NULL; - } - fclose(f); - - if (memcmp(buf, "bplist00", 8) == 0) - plist_from_bin(buf, (uint32_t)bufSize, &ret); - else - plist_from_xml(buf, (uint32_t)bufSize, &ret); - free(buf); - - return ret; -} - -char *futurerestore::getPathOfElementInManifest(const char *element, const char *manifeststr, const char *model, int isUpdateInstall){ - char *pathStr = NULL; - ptr_smart buildmanifest(NULL,plist_free); - - plist_from_xml(manifeststr, (uint32_t)strlen(manifeststr), &buildmanifest); - - if (plist_t identity = getBuildidentity(buildmanifest._p, model, isUpdateInstall)) - if (plist_t manifest = plist_dict_get_item(identity, "Manifest")) - if (plist_t elem = plist_dict_get_item(manifest, element)) - if (plist_t info = plist_dict_get_item(elem, "Info")) - if (plist_t path = plist_dict_get_item(info, "Path")) - if (plist_get_string_val(path, &pathStr), pathStr) - goto noerror; - - reterror("could not get %s path\n",element); -noerror: - return pathStr; -} - -std::string futurerestore::getGeneratorFromSHSH2(const plist_t shsh2){ - plist_t pGenerator = NULL; - uint64_t gen = 0; - char *genstr = NULL; - cleanup([&]{ - safeFree(genstr); - }); - retassure(pGenerator = plist_dict_get_item(shsh2, "generator"), "signing ticket file does not contain generator"); - - retassure(plist_get_node_type(pGenerator) == PLIST_STRING, "generator has unexpected type! We expect string of the format 0x%16llx"); - - plist_get_string_val(pGenerator, &genstr); - assure(genstr); - - sscanf(genstr, "0x%16llx",&gen); - retassure(gen, "failed to parse generator. Make sure it is in format 0x%16llx"); - - return {genstr}; -} diff --git a/futurerestore/futurerestore.hpp b/futurerestore/futurerestore.hpp index 2f9a5824..d8126eff 100644 --- a/futurerestore/futurerestore.hpp +++ b/futurerestore/futurerestore.hpp @@ -19,107 +19,98 @@ #include #include #include -#include "idevicerestore.h" -#include #include +#include -using namespace std; +#include -template -class ptr_smart { - std::function _ptr_free = NULL; -public: - T _p; - ptr_smart(T p, function ptr_free){static_assert(is_pointer(), "error: this is for pointers only\n"); _p = p;_ptr_free = ptr_free;} - ptr_smart(T p){_p = p;} - ptr_smart(){_p = NULL;} - ptr_smart(ptr_smart &&p){ _p = p._p; _ptr_free = p._ptr_free; p._p = NULL; p._ptr_free = NULL;} - ptr_smart& operator =(ptr_smart &&p){_p = p._p; _ptr_free = p._ptr_free; p._p = NULL; p._ptr_free = NULL; return *this;} - T operator =(T p){ _p = p; return _p;} - T operator =(T &p){_p = p; p = NULL; return _p;} - T *operator&(){return &_p;} - explicit operator const T() const {return _p;} - operator const void*() const {return _p;} - ~ptr_smart(){if (_p) (_ptr_free) ? _ptr_free(_p) : free((void*)_p);} +extern "C"{ +#include }; -class futurerestore { - struct idevicerestore_client_t* _client; - char *_ibootBuild = NULL; - bool _didInit = false; - vector _aptickets; - vector>_im4ms; - int _foundnonce = -1; - bool _isUpdateInstall = false; - bool _isPwnDfu = false; - - char *_firmwareJson = NULL; - jssytok_t *_firmwareTokens = NULL;; - char *__latestManifest = NULL; - char *__latestFirmwareUrl = NULL; - - plist_t _sepbuildmanifest = NULL; - plist_t _basebandbuildmanifest = NULL; - - const char *_basebandPath = NULL;; - const char *_sepbuildmanifestPath = NULL; - const char *_basebandbuildmanifestPath = NULL; - - bool _enterPwnRecoveryRequested = false; - bool _rerestoreiOS9 = false; - //methods - void enterPwnRecovery(plist_t build_identity, std::string bootargs = ""); - -public: - futurerestore(bool isUpdateInstall = false, bool isPwnDfu = false); - bool init(); - int getDeviceMode(bool reRequest); - uint64_t getDeviceEcid(); - void putDeviceIntoRecovery(); - void setAutoboot(bool val); - void exitRecovery(); - void waitForNonce(); - void waitForNonce(vectornonces, size_t nonceSize); - void loadAPTickets(const vector &apticketPaths); - char *getiBootBuild(); - - plist_t nonceMatchesApTickets(); - std::pair nonceMatchesIM4Ms(); +struct idevicerestore_mode_t; - void loadFirmwareTokens(); - const char *getDeviceModelNoCopy(); - const char *getDeviceBoardNoCopy(); - char *getLatestManifest(); - char *getLatestFirmwareUrl(); - void loadLatestBaseband(); - void loadLatestSep(); +class futurerestore { + idevicerestore_client_t *_client; + + std::vector _aptickets; + std::vector_im4ms; + tihmstar::Mem _donorLLB; + std::string _donorIPSW; + tihmstar::Mem _sep; + std::string _latestFirmwareUrl; - void setSepManifestPath(const char *sepManifestPath); - void setBasebandManifestPath(const char *basebandManifestPath); - void loadSep(const char *sepPath); - void setBasebandPath(const char *basebandPath); - bool isUpdateInstall(){return _isUpdateInstall;}; - - plist_t sepManifest(){return _sepbuildmanifest;}; - plist_t basebandManifest(){return _basebandbuildmanifest;}; - const char *sepManifestPath(){return _sepbuildmanifestPath;}; - const char *basebandManifestPath(){return _basebandbuildmanifestPath;}; - bool is32bit(){return !is_image4_supported(_client);}; - - uint64_t getBasebandGoldCertIDFromDevice(); - - void doRestore(const char *ipsw); - int doJustBoot(const char *ipsw, std::string bootargs = ""); + tihmstar::Mem _customRamdisk; + tihmstar::Mem _sepTicket; + plist_t _p_latestManifestCache; + tihmstar::ra1nsn0w::launchConfig _persist_cfg; + + bool _isUpdateInstall; + bool _isPwnDfu; + bool _no_ticket_needed; + bool _restorePwnage; + bool _restore24kpwn; + bool _needsDecryptedRamdisk; +private: + const plist_t loadBuilmanifestForLatestFirmware(); + tihmstar::Mem getComponentFromIPSW(const char *ipswPath, const char *component); + +public: + futurerestore(uint64_t ecid = 0, bool isUpdateInstall = false, bool isPwnDfu = true); ~futurerestore(); - static std::pair getRamdiskHashFromSCAB(const char* scab, size_t scabSize); - static std::pair getNonceFromSCAB(const char* scab, size_t scabSize); - static uint64_t getEcidFromSCAB(const char* scab, size_t scabSize); - static plist_t loadPlistFromFile(const char *path); - static void saveStringToFile(const char *str, const char *path); - static char *getPathOfElementInManifest(const char *element, const char *manifeststr, const char *model, int isUpdateInstall); - static std::string getGeneratorFromSHSH2(const plist_t shsh2); + void setPersistCfg(tihmstar::ra1nsn0w::launchConfig cfg); + void setRestorePwnage(bool restorePwnage); + void setRestore24kpwn(bool restore24kpwn); + void setNeedsDecryptedRamdisk(bool needsDecryptedRamdisk); + void setNoTicketNeeded(bool ticketIsNotNeeded); + void loadAPTickets(const std::vector &APTicketPaths); + + idevicerestore_mode_t *getDeviceMode(); + bool isInRestoreMode(); + void putDeviceIntoRecovery(); + + tihmstar::Mem getRamdiskForDevice(const char *ipswpath); + + void doRestore(const char *ipswpath); + void enterPwnRestore(const char *ipswpath, bool is32bit, const char *bootargs = NULL, tihmstar::ra1nsn0w::launchConfig = {}); + void enterRestore(const char *ipswpath); + + void setLLBFromIPSW(const char *llbipswpath); + + const char *getDeviceBoardNoCopy(); + const char *getDeviceModelNoCopy(); + + plist_t nonceMatchesApTickets(); + tihmstar::Mem nonceMatchesIM4Ms(); + uint64_t getDeviceEcid(); + uint32_t getDeviceCPID(); + uint32_t getDeviceBDID(); + + void requestFreshAPTicket(plist_t buildManifest, const char *variant = NULL); + void requestFreshAPTicket(const char *ipsw, const char *variant = NULL); + void requestFreshSEPTicket(plist_t buildManifest, const char *variant = NULL); + void fetchLatestBaseband(); + void fetchLatestSEP(); + + void setCustomBasebandPath(const char *basebandPath); + void setCustomSEPPath(const char *SEPPath); + void setCustomBasebandManifest(plist_t basebandManifest); + void setCustomSEPManifest(plist_t SEPManifest); + + void setCustomRamdisk(const char *ramdiskPath); + + void verifyBasebandTicketCanBeRequested(); + +#pragma mark static + static tihmstar::Mem getRamdiskHashFromSCAB(const void* scab, size_t scabSize); +// static std::pair getNonceFromSCAB(const char* scab, size_t scabSize); + static uint64_t getEcidFromSCAB(const void* scab, size_t scabSize); +// static plist_t loadPlistFromFile(const char *path); +// static void saveStringToFile(const char *str, const char *path); +// static char *getPathOfElementInManifest(const char *element, const char *manifeststr, const char *model, int isUpdateInstall); +// static std::string getGeneratorFromSHSH2(const plist_t shsh2); }; #endif /* futurerestore_hpp */ diff --git a/futurerestore/main.cpp b/futurerestore/main.cpp index 3319f317..d6ca4941 100644 --- a/futurerestore/main.cpp +++ b/futurerestore/main.cpp @@ -13,16 +13,12 @@ #include #include "futurerestore.hpp" -extern "C"{ -#include "tsschecker.h" -#undef VERSION_COMMIT_SHA -#undef VERSION_COMMIT_COUNT -}; - #include -#ifdef HAVE_LIBIPATCHER -#include -#endif + +#include +#include + +#include #ifdef WIN32 #include @@ -31,155 +27,217 @@ extern "C"{ #endif #endif +extern int idevicerestore_debug; + static struct option longopts[] = { + { "debug", no_argument, NULL, 'd' }, + { "ecid", required_argument, NULL, 'e' }, + { "ramdisk", required_argument, NULL, 'r' }, { "apticket", required_argument, NULL, 't' }, - { "baseband", required_argument, NULL, 'b' }, - { "baseband-manifest", required_argument, NULL, 'p' }, + { "fresh-apticket", optional_argument, NULL, 'T' }, + { "update", no_argument, NULL, 'u' }, + { "32bit", no_argument, NULL, 0 }, + { "decrypt-ramdisk", no_argument, NULL, 0 }, + { "no-ticket", no_argument, NULL, 0 }, + { "ra1nsn0warg", required_argument, NULL, 0 }, + { "ra1nsn0warg-persist",required_argument, NULL, 0 }, + { "restore-pwnage", no_argument, NULL, 0 }, + { "restore-24kpwn", no_argument, NULL, 0 }, + + { "tethered-downgrade", required_argument, NULL, 0 }, + { "bootargs", required_argument, NULL, 'b' }, + + { "default-sep", no_argument, NULL, 0 }, + { "latest-sep", no_argument, NULL, 0 }, { "sep", required_argument, NULL, 's' }, { "sep-manifest", required_argument, NULL, 'm' }, - { "wait", no_argument, NULL, 'w' }, - { "update", no_argument, NULL, 'u' }, - { "debug", no_argument, NULL, 'd' }, - { "exit-recovery", no_argument, NULL, 'e' }, - { "latest-sep", no_argument, NULL, '0' }, - { "latest-baseband", no_argument, NULL, '1' }, - { "no-baseband", no_argument, NULL, '2' }, -#ifdef HAVE_LIBIPATCHER - { "use-pwndfu", no_argument, NULL, '3' }, - { "just-boot", optional_argument, NULL, '4' }, -#endif + + { "latest-baseband", no_argument, NULL, 0 }, + { "baseband", required_argument, NULL, 'B' }, + { "baseband-manifest", required_argument, NULL, 'M' }, + { "no-baseband", no_argument, NULL, 0 }, + { NULL, 0, NULL, 0 } }; -#define FLAG_WAIT 1 << 0 -#define FLAG_UPDATE 1 << 1 -#define FLAG_LATEST_SEP 1 << 2 -#define FLAG_LATEST_BASEBAND 1 << 3 -#define FLAG_NO_BASEBAND 1 << 4 -#define FLAG_IS_PWN_DFU 1 << 5 - void cmd_help(){ - printf("Usage: futurerestore [OPTIONS] iPSW\n"); - printf("Allows restoring to non-matching firmware with custom SEP+baseband\n"); - printf("\nGeneral options:\n"); - printf(" -t, --apticket PATH\t\tSigning tickets used for restoring\n"); - printf(" -u, --update\t\t\tUpdate instead of erase install (requires appropriate APTicket)\n"); - printf(" \t\t\tDO NOT use this parameter, if you update from jailbroken firmware!\n"); - printf(" -w, --wait\t\t\tKeep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable)\n"); - printf(" -d, --debug\t\t\tShow all code, use to save a log for debug testing\n"); - printf(" -e, --exit-recovery\t\tExit recovery mode and quit\n"); - -#ifdef HAVE_LIBIPATCHER - 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(" --just-boot=\"-v\"\t\tTethered booting the device from pwned DFU mode. You can optionally set boot-args\n"); -#endif - - printf("\nOptions for SEP:\n"); - printf(" --latest-sep\t\tUse latest signed SEP instead of manually specifying one (may cause bad restore)\n"); - printf(" -s, --sep PATH\t\tSEP to be flashed\n"); - printf(" -m, --sep-manifest PATH\tBuildManifest for requesting SEP ticket\n"); - - printf("\nOptions for baseband:\n"); - printf(" --latest-baseband\t\tUse latest signed baseband instead of manually specifying one (may cause bad restore)\n"); - printf(" -b, --baseband PATH\t\tBaseband to be flashed\n"); - printf(" -p, --baseband-manifest PATH\tBuildManifest for requesting baseband ticket\n"); - printf(" --no-baseband\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( + "Usage: futurerestore [OPTIONS] IPSW\n" + "Allows restoring to non-matching firmware with custom SEP+baseband\n" + "\nGeneral options:\n" + " -d, --debug\t\t\t\tShow all code, use to save a log for debug testing\n" + " -e, --ecid\t\t\t\tSet device ECID\n" + " -r, --ramdisk PATH\t\t\tBoot custom ramdisk\n" + " -t, --apticket PATH\t\t\tSigning tickets used for restoring\n" + " -T, --fresh-apticket [VARIANT]\tSigning tickets used for restoring\n" + " -u, --update\t\t\t\tUpdate instead of erase install (requires appropriate APTicket)\n" + " \t\t\t\tDO NOT use this parameter, if you update from jailbroken firmware!\n" + " --32bit\t\t\t\tUse 32bit patchfinder instead of 64bit\n" + " --decrypt-ramdisk\t\t\tDecrypt ramdisk before sending (needed for iOS 3.0 and 3.0.1 restore)\n" + " --no-ticket\t\t\tDon't expect ticket (used for iOS 2.0 restore)\n" + " --ra1nsn0warg \t\tPass extra arg to ra1nsn0w (can use multiple times)\n" + " --ra1nsn0warg-persist \t\tPass extra arg to ra1nsn0w for persistent patches (for use with restore-pwnage)\n" + " --restore-pwnage\t\tFlash jailbroken bootchain (only works for 0x8900 devices)\n" + " --restore-24kpwn\t\tFlash jailbroken bootchain with 24kpwn exploit (only works for 0x8720 and 0x8920 devices)\n" + + "\nOptions for downgrading with Odysseus:\n" + " -b, --bootargs=\"-v\"\t\t\tSet bootargs\n" + " --tethered-downgrade=\tSkip APTicket checks when downgrading (flash donor LLB from other IPSW)\n" + + "\nOptions for SEP:\n" + " -s, --sep PATH\t\tSEP to be flashed\n" + " -m, --sep-manifest PATH\tBuildManifest for requesting SEP ticket\n" + " --latest-sep\t\tUse latest signed SEP instead of manually specifying one (may cause bad restore)\n" + " --default-sep\t\tUse the SEP inside the IPSW\n" + + + "\nOptions for baseband:\n" + " -B, --baseband PATH\t\tBaseband to be flashed\n" + " -M, --baseband-manifest PATH\tBuildManifest for requesting baseband ticket\n" + " --latest-baseband\t\tUse latest signed baseband instead of manually specifying one (may cause bad restore)\n" + " --no-baseband\t\tSkip baseband checks\n" + " \t\tOnly use this for device without a baseband (eg. iPod touch or some Wi-Fi only iPads)\n\n" + ); } - -#ifdef WIN32 - DWORD termFlags; - HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); - if (GetConsoleMode(handle, &termFlags)) - SetConsoleMode(handle, termFlags | ENABLE_VIRTUAL_TERMINAL_PROCESSING); -#endif - -using namespace std; using namespace tihmstar; + +MAINFUNCTION int main_r(int argc, const char * argv[]) { - int err=0; - printf("Version: " VERSION_COMMIT_SHA " - " VERSION_COMMIT_COUNT "\n"); -#ifdef HAVE_LIBIPATCHER - printf("%s\n",libipatcher::version()); - printf("Odysseus for 32-bit support: yes\n"); - printf("Odysseus for 64-bit support: %s\n",(libipatcher::has64bitSupport() ? "yes" : "no")); -#else - printf("Odysseus support: no\n"); -#endif + info("%s", VERSION_STRING); + + if (ra1nsn0w::loadPlugins()) { + info("ra1nsn0w plugin support: yes"); + }else{ + info("ra1nsn0w plugin support: no"); + } int optindex = 0; int opt = 0; - long flags = 0; - bool exitRecovery = false; - - int isSepManifestSigned = 0; - int isBasebandSigned = 0; - + + uint64_t ecid = 0; + const char *ipsw = NULL; + const char *llbipsw = NULL; + const char *bootargs = NULL; + const char *requestFreshAPTicketVariant = NULL; const char *basebandPath = NULL; const char *basebandManifestPath = NULL; - const char *sepPath = NULL; - const char *sepManifestPath = NULL; - const char *bootargs = NULL; - - vector apticketPaths; - - t_devicevals devVals = {0}; - t_iosVersion versVals = {0}; - + const char *SEPPath = NULL; + const char *SEPManifestPath = NULL; + const char *ramdiskPath = NULL; + + bool is32Bit = false; + bool isUpdateRestore = false; + bool getLatestBaseband = false; + bool getLatestSEP = false; + bool useDefaultSEP = false; + bool skipBasebandChecks = false; + bool dontExpectAPTicket = false; + bool doRestorePwnage = false; + bool doRestore24kPwn = false; + bool needsDecryptedRamdisk = false; + + tihmstar::ra1nsn0w::launchConfig cfg = {}; + tihmstar::ra1nsn0w::launchConfig cfg_persist = {}; + + std::vector apticketPaths; + if (argc == 1){ cmd_help(); return -1; } + + std::vector ra1nargs; + std::vector ra1nargs_persist; + ra1nargs.push_back(""); + ra1nargs_persist.push_back(""); - while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:wude0123", longopts, &optindex)) > 0) { + while ((opt = getopt_long(argc, (char* const *)argv, "hb:B:de:m:M:r:s:t:T::u", longopts, &optindex)) >= 0) { switch (opt) { + case 0: //long opts + { + std::string curopt = longopts[optindex].name; + + if (curopt == "32bit") { + is32Bit = true; + }else if (curopt == "decrypt-ramdisk"){ + needsDecryptedRamdisk = true; + }else if (curopt == "default-sep"){ + useDefaultSEP = true; + }else if (curopt == "latest-baseband"){ + getLatestBaseband = true; + }else if (curopt == "latest-sep"){ + getLatestSEP = true; + }else if (curopt == "no-baseband"){ + skipBasebandChecks = true; + }else if (curopt == "no-ticket"){ + dontExpectAPTicket = true; + }else if (curopt == "ra1nsn0warg"){ + ra1nargs.push_back(optarg); + }else if (curopt == "ra1nsn0warg-persist"){ + ra1nargs_persist.push_back(optarg); + }else if (curopt == "restore-pwnage"){ + doRestorePwnage = true; + }else if (curopt == "restore-24kpwn"){ + doRestore24kPwn = true; + }else if (curopt == "tethered-downgrade"){ + if (optarg){ + llbipsw = optarg; + } + }else{ + reterror("Unknown longopt '%s'",curopt.c_str()); + } + } + break; + case 'b': //long option: "boot-args" + bootargs = optarg; + break; + + case 'B': //long option: "baseband" + basebandPath = optarg; + break; + + case 'd': // long option: "debug"; can be called as short option + idevicerestore_debug++; + break; + + case 'e': // long option: "buildid" + if (strncmp(optarg, "0x", 2) == 0) { + ecid = strtoul_l(optarg, NULL, 16, LC_GLOBAL_LOCALE); + }else{ + ecid = strtoul_l(optarg, NULL, 10, LC_GLOBAL_LOCALE); + } + break; + + case 'm': //long option: "sep-manifest" + SEPManifestPath = optarg; + break; + + case 'M': //long option: "baseband-manifest" + basebandManifestPath = optarg; + break; + + case 'r': //long option: "ramdisk" + ramdiskPath = optarg; + break; + + case 's': //long option: "sep" + SEPPath = optarg; + break; + case 't': // long option: "apticket"; can be called as short option apticketPaths.push_back(optarg); break; - case 'b': // long option: "baseband"; can be called as short option - basebandPath = optarg; - break; - case 'p': // long option: "baseband-manifest"; can be called as short option - basebandManifestPath = optarg; - break; - case 's': // long option: "sep"; can be called as short option - sepPath = optarg; - break; - case 'm': // long option: "sep-manifest"; can be called as short option - sepManifestPath = optarg; - break; - case 'w': // long option: "wait"; can be called as short option - flags |= FLAG_WAIT; + + case 'T': // long option: "fresh-apticket"; can be called as short option + if (!(requestFreshAPTicketVariant = optarg)) requestFreshAPTicketVariant = RESTORE_VARIANT_ERASE_INSTALL; break; + case 'u': // long option: "update"; can be called as short option - flags |= FLAG_UPDATE; - break; - case '0': // long option: "latest-sep"; - flags |= FLAG_LATEST_SEP; - break; - case '1': // long option: "latest-baseband"; - flags |= FLAG_LATEST_BASEBAND; - break; - case '2': // long option: "no-baseband"; - flags |= FLAG_NO_BASEBAND; - break; -#ifdef HAVE_LIBIPATCHER - case '3': // long option: "use-pwndfu"; - flags |= FLAG_IS_PWN_DFU; - break; - case '4': // long option: "just-boot"; - bootargs = (optarg) ? optarg : ""; - break; - break; -#endif - case 'e': // long option: "exit-recovery"; can be called as short option - exitRecovery = true; - break; - case 'd': // long option: "debug"; can be called as short option - idevicerestore_debug = 1; + isUpdateRestore = true; break; + + default: cmd_help(); return -1; @@ -191,141 +249,146 @@ int main_r(int argc, const char * argv[]) { argv += optind; ipsw = argv[0]; - }else if (argc == optind && flags & FLAG_WAIT) { - info("User requested to only wait for ApNonce to match, but not for actually restoring\n"); - }else if (exitRecovery){ - info("Exiting to recovery mode\n"); }else{ - error("argument parsing failed! agrc=%d optind=%d\n",argc,optind); - if (idevicerestore_debug){ - for (int i=0; i= 0) { + std::string curopt = rlongopts[roptindex].name; + if (ropt) { + for (const struct option *clo = rlongopts; clo->name; clo++) { + if (clo->val == ropt){ + curopt = clo->name; + break; + } + } + } + if (!ra1nsn0w::parseArgument(cfg, curopt, optarg)) { + std::string orig; + try { + orig = ra1nargs.at(optind-1); + } catch (...) { + // + } + error("Unrecognised ra1nsn0w longopt '%s' ('%s')",curopt.c_str(),orig.c_str()); + return -5; + } + } + } + + if (doRestorePwnage || doRestore24kPwn){ + optind = 0; + optopt = 0; + opterr = 0; +#ifdef _OPTRESET + optreset = 1; +#endif + + int ropt = 0; + int roptindex = 0; + const struct option *rlongopts = ra1nsn0w::getLongOpts(); + const char *rshortopts = ra1nsn0w::getShortOpts(); + ra1nargs_persist.push_back(NULL); + + while ((ropt = getopt_long((int)(ra1nargs_persist.size()-1), (char * const *)ra1nargs_persist.data(), rshortopts, rlongopts, &roptindex)) >= 0) { + std::string curopt = rlongopts[roptindex].name; + if (ropt) { + for (const struct option *clo = rlongopts; clo->name; clo++) { + if (clo->val == ropt){ + curopt = clo->name; + break; + } + } + } + if (!ra1nsn0w::parseArgument(cfg_persist, curopt, optarg)) { + std::string orig; + try { + orig = ra1nargs_persist.at(optind-1); + } catch (...) { + // + } + error("Unrecognised ra1nsn0w-persist longopt '%s' ('%s')",curopt.c_str(),orig.c_str()); + return -5; + } + } + } + + futurerestore client(ecid, isUpdateRestore); + + if (doRestorePwnage || doRestore24kPwn) { + client.setRestorePwnage(doRestorePwnage); + client.setPersistCfg(cfg_persist); + } + if (doRestore24kPwn) client.setRestore24kpwn(doRestore24kPwn); + if (needsDecryptedRamdisk) client.setNeedsDecryptedRamdisk(needsDecryptedRamdisk); + if (apticketPaths.size()) client.loadAPTickets(apticketPaths); + if (requestFreshAPTicketVariant){ + if (llbipsw) { + client.requestFreshAPTicket(llbipsw, requestFreshAPTicketVariant); + }else{ + client.requestFreshAPTicket(ipsw, requestFreshAPTicketVariant); + } + } + if (llbipsw) client.setLLBFromIPSW(llbipsw); + + if (ramdiskPath) client.setCustomRamdisk(ramdiskPath); + + if (getLatestBaseband){ + client.fetchLatestBaseband(); + } else { + if (basebandPath) client.setCustomBasebandPath(basebandPath); + if (basebandManifestPath){ + plist_t p_BuildManifest = NULL; + cleanup([&]{ + safeFreeCustom(p_BuildManifest, plist_free); + }); + plist_err_t perr = PLIST_ERR_SUCCESS; + retassure(!(perr = plist_read_from_file(basebandManifestPath, &p_BuildManifest, NULL)), "Failed to read plist from path '%s' with err=%d",basebandManifestPath,perr); + client.setCustomBasebandManifest(p_BuildManifest); + } + } + if (!skipBasebandChecks) client.verifyBasebandTicketCanBeRequested(); + + if (useDefaultSEP) { + info("Using default SEP from IPSW"); + }else if (getLatestSEP){ + client.fetchLatestSEP(); + } else { + if (SEPPath) client.setCustomSEPPath(SEPPath); + if (SEPManifestPath){ + plist_t p_BuildManifest = NULL; + cleanup([&]{ + safeFreeCustom(p_BuildManifest, plist_free); + }); + plist_err_t perr = PLIST_ERR_SUCCESS; + retassure(!(perr = plist_read_from_file(SEPManifestPath, &p_BuildManifest, NULL)), "Failed to read plist from path '%s' with err=%d",SEPManifestPath,perr); + client.setCustomSEPManifest(p_BuildManifest); + } + } + + client.setNoTicketNeeded(dontExpectAPTicket); + + if (!client.isInRestoreMode()) { + client.enterPwnRestore(ipsw, is32Bit, bootargs, cfg); + } + + client.doRestore(ipsw); + info("Done: restoring succeeded!"); + + return 0; }