├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile.am ├── README.md ├── autogen.sh ├── configure.ac ├── futurerestore.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist └── futurerestore ├── Makefile.am ├── futurerestore.cpp ├── futurerestore.hpp └── main.cpp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [tihmstar] 4 | patreon: tihmstar 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.a 3 | *.o 4 | *.la 5 | *.lo 6 | *.so 7 | */.libs 8 | */.deps 9 | *Makefile 10 | *Makefile.in 11 | aclocal.m4 12 | autom4te.cache 13 | compile 14 | config.* 15 | configure 16 | depcomp 17 | install-sh 18 | libtool 19 | ltmain.sh 20 | m4 21 | missing 22 | */futurerestore* 23 | stamp-h1 24 | xcuserdata 25 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/tsschecker"] 2 | path = external/tsschecker 3 | url = https://github.com/tihmstar/tsschecker.git 4 | [submodule "external/idevicerestore"] 5 | path = external/idevicerestore 6 | url = https://github.com/tihmstar/idevicerestore.git 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | ACLOCAL_AMFLAGS = -I m4 3 | SUBDIRS = external/idevicerestore external/tsschecker futurerestore 4 | install installdirs: SUBDIRS = futurerestore 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # futurerestore 2 | _It is a hacked up idevicerestore wrapper, which allows manually specifying SEP and Baseband for restoring._ 3 | 4 | Latest compiled version can be found [here](https://github.com/tihmstar/futurerestore/releases). 5 | 6 | __Only use if you are sure what you're doing.__ 7 | 8 | --- 9 | 10 | # Features 11 | * Supports the following downgrade methods: 12 | * Prometheus 64-bit devices (generator and ApNonce collision mode) 13 | * Odysseus for 32-bit & 64-bit (A7-A11) devices 14 | * Re-restoring 32-bit devices to iOS 9.x with [alitek123](https://github.com/alitek12)'s no-ApNonce method (alternative — [idevicererestore](https://downgrade.party)). 15 | * Allows restoring to non-matching firmware with custom SEP+baseband 16 | 17 | # Dependencies 18 | * ## External libs 19 | Make sure these are installed 20 | * [libzip](https://github.com/nih-at/libzip); 21 | * [libcurl](https://github.com/curl/curl); 22 | * [openssl](https://github.com/openssl/openssl) (or CommonCrypto on macOS/OS X); 23 | * [libplist](https://github.com/libimobiledevice/libplist); 24 | * [libusbmuxd](https://github.com/libimobiledevice/libusbmuxd); 25 | * [libirecovery](https://github.com/libimobiledevice/libirecovery); 26 | * [libimobiledevice](https://github.com/libimobiledevice/libimobiledevice); 27 | * [img4tool](https://github.com/tihmstar/img4tool); 28 | * [liboffsetfinder64](https://github.com/tihmstar/liboffsetfinder64); 29 | * [libipatcher](https://github.com/tihmstar/libipatcher) 30 | 31 | * ## Submodules 32 | Make sure these projects compile on your system (install it's dependencies): 33 | * [jssy](https://github.com/tihmstar/jssy); 34 | * [tsschecker](https://github.com/tihmstar/tsschecker); 35 | * [idevicerestore](https://github.com/tihmstar/idevicerestore) 36 | 37 | ## Report an issue 38 | You can do it [here](https://github.com/tihmstar/futurerestore/issues). 39 | 40 | ### Restoring on Windows 10 41 | 1. Try to restore the device, error `-8` occurs; 42 | 2. Leave the device plugged in, it'll stay on the Recovery screen; 43 | 3. Head over to device manager under control panel in Windows; 44 | 4. Locate "Apple Recovery (iBoot) USB Composite Device" (at the bottom); 45 | 5. Right click and choose "Uninstall device". 46 | You may see a tick box that allows you to uninstall the driver software as well, tick that (all the three Apple mobile device entries under USB devices will disappear); 47 | 6. Unplug the device and re-plug it in; 48 | 7. Go back to futurerestore and send the restore command again (just press the up arrow to get it back, then enter). 49 | Error `-8` is now fixed, but the process will fail again after the screen of your device has turned green; 50 | 8. Go back to device manager and repeat the driver uninstall process as described above (step 4 to 6); 51 | 9. Go back to futurerestore once again and repeat the restore process; 52 | 10. The device will reboot and error `-10` will also be solved; 53 | 11. The restore will now proceed and succeed. 54 | 55 | ### Some about [cURL](https://github.com/curl/curl) 56 | * Linux: Follow [this guide](https://dev.to/jake/using-libcurl3-and-libcurl4-on-ubuntu-1804-bionic-184g) to use tsschecker on Ubuntu 18.04 (Bionic) as it requires libcurl3 which cannot coexist with libcurl4 on this OS. 57 | 58 | # Help 59 | _(might become outdated):_ 60 | 61 | Usage: `futurerestore [OPTIONS] iPSW` 62 | 63 | | option (short) | option (long) | description | 64 | |----------------|------------------------------------------|-----------------------------------------------------------------------------------| 65 | | ` -t ` | ` --apticket PATH ` | Signing tickets used for restoring | 66 | | ` -u ` | ` --update ` | Update instead of erase install (requires appropriate APTicket) | 67 | | | | DO NOT use this parameter, if you update from jailbroken firmware! | 68 | | ` -w ` | ` --wait ` | Keep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable) | 69 | | ` -d ` | ` --debug ` | Show all code, use to save a log for debug testing | 70 | | ` -e ` | ` --exit-recovery ` | Exit recovery mode and quit | 71 | | | ` --use-pwndfu ` | Restoring devices with Odysseus method. Device needs to be in pwned DFU mode already | 72 | | | ` --just-boot "-v" ` | Tethered booting the device from pwned DFU mode. You can optionally set ` boot-args ` | 73 | | | ` --latest-sep ` | Use latest signed SEP instead of manually specifying one (may cause bad restore) | 74 | | ` -s ` | ` --sep PATH ` | SEP to be flashed | 75 | | ` -m ` | ` --sep-manifest PATH ` | BuildManifest for requesting SEP ticket | 76 | | | ` --latest-baseband ` | Use latest signed baseband instead of manually specifying one (may cause bad restore) | 77 | | ` -b ` | ` --baseband PATH ` | Baseband to be flashed | 78 | | ` -p ` | ` --baseband-manifest PATH ` | BuildManifest for requesting baseband ticket | 79 | | | ` --no-baseband ` | Skip checks and don't flash baseband | 80 | | | | Only use this for device without a baseband (eg. iPod touch or some Wi-Fi only iPads) | 81 | 82 | --- 83 | 84 | ## 0) What futurerestore can do 85 | **Downgrade/Upgrade/Re-restore same mobile firmware version.** 86 | Whenever you read "downgrade" nowadays it means you can also upgrade and re-restore if you're on the same firmware version. Basically this allows restoring an firmware version and the installed firmware version doesn't matter. 87 | 88 | --- 89 | 90 | ## 1) Prometheus (64-bit device) - generator method 91 | ### Requirements 92 | - Jailbreak 93 | - signing ticket files (`.shsh`, `.shsh2`, `.plist`) with a generator 94 | - nonceEnabler patch enabled 95 | 96 | ### Info 97 | You can downgrade, if the destination firmware version is compatible with the **latest signed SEP and baseband** and if you **have a signing tickets files with a generator for that firmware version**. 98 | 99 | ### How to use 100 | 1. Device must be jailbroken and nonceEnabler patch must be active 101 | 2. Open signing ticket file and look up the generator 102 | * Looks like this: `generator0xde3318d224cf14a1` 103 | 3. Write the generator to device's NVRAM 104 | * Connect with SSH into the device and run `nvram com.apple.System.boot-nonce=0xde3318d224cf14a1` to set the generator *0xde3318d224cf14a1* 105 | * verify it with `nvram -p` 106 | 4. Connect your device in normal mode to computer 107 | 5. On the computer run `futurerestore -t ticket.shsh --latest-baseband --latest-sep ios.ipsw` 108 | 109 | ### Youtube 110 | Prometheus 111 | *Prometheus* 112 | 113 | Prometheus 114 | *nonceEnabler* 115 | 116 | ### Recommended methods to activate nonceEnabler patch 117 | #### Method 1: ios-kern-utils (iOS 7.x-10.x) 118 | 1. Install DEB-file of [ios-kern-utils](https://github.com/Siguza/ios-kern-utils/releases/) on device; 119 | 2. Run on the device `nvpatch com.apple.System.boot-nonce`. 120 | 121 | #### Method 2: Using special applications 122 | Use utilities for setting boot-nonce generator: 123 | 1. [PhœnixNonce](https://github.com/Siguza/PhoenixNonce) for iOS 9.x; 124 | 2. [v0rtexnonce](https://github.com/arx8x/v0rtexnonce) for iOS 10.x; 125 | 3. [Nonceset1112](https://github.com/julioverne/NonceSet112) for iOS 11.0-11.1.2; 126 | 4. [noncereboot1131UI](https://github.com/s0uthwest/noncereboot1131UI) for iOS 11.0-11.4b3; 127 | 5. [NonceReboot12xx](https://github.com/ur0/NonceReboot12XX) for iOS 12.0-12.1.2; 128 | 6. [GeneratorAutoSetter](https://github.com/Halo-Michael/GeneratorAutoSetter) for checkra1n jailbreak on iOS / iPadOS 13.x. Install it from Cydia's developer repo (https://halo-michael.github.io/repo/) on device. 129 | 130 | #### Method 3: Using jailbreak tools 131 | Use jailbreak tools for setting boot-nonce generator: 132 | 1. [Meridian](https://meridian.sparkes.zone) for iOS 10.x; 133 | 2. [backr00m](https://nito.tv) or greeng0blin for tvOS 10.2-11.1; 134 | 3. [Electra and ElectraTV](https://coolstar.org/electra) for iOS and tvOS 11.x; 135 | 4. [unc0ver](https://unc0ver.dev) for iOS 11.0-12.2, 12.4.x; 136 | 5. [Chimera and ChimeraTV](https://chimera.sh) for iOS 12.0-12.2, 12.4 and tvOS 12.0-12.2, 12.4. 137 | 138 | ### Activate tfp0, if jailbreak doesn't allow it 139 | #### Method 1 (if jailbroken on iOS 9.2-9.3.x) 140 | * reboot; 141 | * reactivate jailbreak with [Luca Todesco](https://github.com/kpwn)'s [JailbreakMe](https://jbme.qwertyoruiop.com/); 142 | * done. 143 | 144 | #### Method 2 (if jailbroken on iOS 8.0-8.1 with [Pangu8](https://en.8.pangu.io)) 145 | * install this [untether DEB-file](http://apt.saurik.com/beta/pangu8-tfp0/io.pangu.xuanyuansword8_0.5_iphoneos-arm.deb) with included tfp0 patch 146 | 147 | #### Method 3 (if jailbroken on iOS 7.x with [Pangu7](https://en.7.pangu.io)) 148 | * install this [untether DEB-file](http://apt.saurik.com/debs/io.pangu.axe7_0.3_iphoneos-arm.deb) with included tfp0 patch 149 | 150 | #### Method 4 151 | * Use [cl0ver](https://github.com/Siguza/cl0ver) for iOS 9.x. 152 | 153 | --- 154 | 155 | ## 2) Prometheus (64-bit device) - ApNonce collision method (Recovery mode) 156 | ### Requirements 157 | - **Device with A7 chip on iOS 9.1 - 10.2 or iOS 10.3 beta 1**; 158 | - Jailbreak doesn't required; 159 | - Signing ticket files (`.shsh`, `.shsh2`, `.plist`) with a customly chosen ApNonce; 160 | - Signing ticket files needs to have one of the ApNonces, which the device generates a lot; 161 | 162 | ### Info 163 | You can downgrade if the destination firmware version, if it is compatible with the **latest signed SEP and baseband**. You also need to have **special signing ticket files**. If you don't know what this is, you probably can **NOT** use this method! 164 | 165 | ### How to use 166 | 1. Connect your device in normal or recovery mode; 167 | 2. On the computer run `futurerestore -w -t ticket.shsh --latest-baseband --latest-sep firmware.ipsw` 168 | * If you have saved multiple signing tickets with different nonces you can specify more than 169 | one to speed up the process: `futurerestore -w -t t1.shsh -t t2.shsh -t t3.shsh -t t4.shsh --latest-baseband --latest-sep firmware.ipsw` 170 | 171 | --- 172 | 173 | ## 3) Prometheus (64-bit device) - ApNonce collision method (DFU mode) 174 | ### Requirements 175 | - __Devices with A7 (iPhone 5s, iPad Air, iPad mini 2), A8 (iPhone 6 [+], iPad mini [2,3,4], iPod touch [6th generation]) and A8X (iPad Air 2) chips on all firmwares;__ 176 | - __Devices have been released after ~September, 2015 {PROBABLY};__ 177 | - Jailbreak doesn't required; 178 | - Signing ticket files (`.shsh`, `.shsh2`, `.plist`) with a customly chosen APNonce; 179 | - Signing ticket files needs to have one of the ApNonces, which the device generates a lot; 180 | - __[img4tool](https://github.com/tihmstar/img4tool) can't be used for Windows [problem with signing iBSS/iBEC], now it's TO-DO;__ 181 | 182 | ### Info 183 | You can downgrade if the destination firmware version, if it is compatible with the **latest signed SEP and baseband**. You also need to have **special signing ticket files**. If you don't know what this is, you probably can **NOT** use this method! 184 | 185 | ### How to use 186 | 1. Connect your device in DFU mode; 187 | 2. Use [irecovery](https://github.com/libimobiledevice/libirecovery) for checking ApNonce, which booted in DFU; 188 | 3. Extract iBSS/iBEC from target firmware for downgrade (unsigned); 189 | 4. Check DFU-collisioned ApNonces with [irecovery](https://github.com/libimobiledevice/libirecovery), which booted in DFU. 190 | You can't automatically collision DFU ApNonces. 191 | 192 | __If ApNonce is not collisioned, "use hands" for DFU booting.__ 193 | 194 | __If ApNonce is successfully coliisioned, use this SHSH2 for sign iBSS/iBEC.__ 195 | 5. Use img4tool for sign iBSS: 196 | `img4tool -s ticket.shsh -c iBSS.signed -p `; 197 | 6. Use img4tool for sign iBEC: 198 | `img4tool -s ticket.shsh -c iBEC.signed -p `; 199 | 7. So, after signing we can boot into Recovery with irecovery. 200 | 201 | `irecovery -f iBSS.signed` - loading iBSS; 202 | 203 | `irecovery -f iBEC.signed` - loading iBEC; 204 | 8. So good! On the computer run `futurerestore -t ticket.shsh --latest-baseband --latest-sep -w firmware.ipsw`. 205 | 206 | --- 207 | 208 | ## 4) Odysseus (32-bit / 64-bit devices) 209 | ### Requirements 210 | - futurerestore compiled with libipatcher; 211 | - Jailbreak or bootrom exploit (limera1n, checkm8); 212 | - **32-bit**: firmware keys for the device/destination firmware version must be public (check ipsw.me); 213 | - **64-bit**: devices with **A12** and **A13** chips is **NOT** compatible with this method; 214 | - Signing ticket files (`.shsh`, `.shsh2`, `.plist`) from by destination firmware (OTA blobs work too!). 215 | 216 | ### Info 217 | If you have a jailbroken device, you can downgrade to **any** firmware version you have blobs for. You can still get OTA blobs for iOS 6.1.3, 8.4.1 or 10.3.3 for some devices and use those. 218 | 219 | ### How to use 220 | 1. Get device into kDFU/pwnDFU 221 | * Pre-iPhone4s (limera1n devices): 222 | * Enter to pwnDFU mode with redsn0w or any other tool 223 | * iPhone 4s and later 32-bit devices: 224 | * Enter to kDFU mode with kDFU app (cydia: repo.tihmstar.net) or by loading a pwnediBSS from any existing odysseus bundle 225 | * Any 64-bit device: 226 | * Enter to pwnDFU mode and patch signature check with special fork of [ipwndfu](https://github.com/LinusHenze/ipwndfu_public) 227 | 2. Connect your device to computer in kDFU mode (or pwnDFU mode) 228 | 3. On the computer run `futurerestore --use-pwndfu -t ticket.shsh --latest-baseband firmware.ipsw` 229 | 230 | ### Youtube 231 | Odysseus *futurerestore + libipatcher* 232 | 233 | Odysseus *kDFU app* 234 | 235 | Odysseus *Enter kDFU mode (watch up to the point where the screen goes black)* 236 | 237 | You can use **any** odysseus bundle for this. 238 | 239 | ## 5) iOS 9.x re-restore bug by @alitek123 (only for 32-bit devices) 240 | ### Requirements 241 | - Jailbreak doesn't required; 242 | - Signing ticket files (`.shsh`, `.shsh2`, `.plist`) from by iOS 9.x without ApNonce (noNonce APTickets) 243 | 244 | ### Info 245 | If you have **signing tickets files for iOS 9.x**, which **do not contain a ApNonce**, you can restore to that firmware. 246 | 247 | ### How to use 248 | 1. Connect your device in DFU mode 249 | 2. On the computer run `futurerestore -t ticket.shsh --latest-baseband ios9.ipsw` 250 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | gprefix=`which glibtoolize 2>&1 >/dev/null` 3 | if [ $? -eq 0 ]; then 4 | glibtoolize --force 5 | else 6 | libtoolize --force 7 | fi 8 | aclocal -I m4 9 | autoconf 10 | autoheader 11 | automake --add-missing 12 | autoreconf -i 13 | 14 | export NOCONFIGURE=1 15 | 16 | SUBDIRS="external/idevicerestore external/tsschecker" 17 | for SUB in $SUBDIRS; do 18 | pushd $SUB 19 | ./autogen.sh 20 | popd 21 | done 22 | 23 | unset NOCONFIGURE 24 | 25 | if [ -z "$NOCONFIGURE" ]; then 26 | ./configure "$@" 27 | fi 28 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.69]) 2 | AC_INIT([futurerestore], m4_esyscmd([git rev-list --count HEAD | tr -d '\n']), [tihmstar@gmail.com]) 3 | 4 | AC_CANONICAL_SYSTEM 5 | AC_CANONICAL_HOST 6 | 7 | AM_INIT_AUTOMAKE([subdir-objects]) 8 | AC_CONFIG_HEADERS([config.h]) 9 | AC_CONFIG_MACRO_DIRS([m4]) 10 | 11 | # Versioning. 12 | AC_DEFINE([VERSION_COMMIT_COUNT], "m4_esyscmd([git rev-list --count HEAD | tr -d '\n'])", [Git commit count]) 13 | AC_DEFINE([VERSION_COMMIT_SHA], "m4_esyscmd([git rev-parse HEAD | tr -d '\n'])", [Git commit sha]) 14 | AC_SUBST([VERSION_COMMIT_COUNT], ["m4_esyscmd([git rev-list --count HEAD | tr -d '\n'])"]) 15 | AC_SUBST([VERSION_COMMIT_SHA], ["m4_esyscmd([git rev-parse HEAD | tr -d '\n'])"]) 16 | 17 | # Checks for programs. 18 | AC_PROG_CXX 19 | AC_PROG_CC 20 | 21 | # Check for operating system. 22 | AC_MSG_CHECKING([whether we need platform-specific build settings]) 23 | case $host_os in 24 | darwin* ) 25 | CXXFLAGS+=" -stdlib=libc++" 26 | ;; 27 | esac 28 | 29 | # Checks the flags. 30 | CFLAGS+=" -DIDEVICERESTORE_NOMAIN=1 -DTSSCHECKER_NOMAIN=1" 31 | CXXFLAGS+=" -std=c++11" 32 | CFLAGS+=" -std=c11" 33 | 34 | AC_DEFUN([AX_UNPRECIOUS], [ 35 | m4_define([_AC_PRECIOUS_VARS], m4_bpatsubst(_AC_PRECIOUS_VARS, [$1], [])) 36 | ]) 37 | AX_UNPRECIOUS([CFLAGS]) 38 | export CFLAGS 39 | 40 | AC_CONFIG_SUBDIRS(external/idevicerestore external/tsschecker) 41 | AC_CONFIG_SRCDIR([futurerestore]) 42 | 43 | # Checks the libraries. 44 | LIBIPATCHER_REQUIRES_STR="libipatcher >= 61" 45 | LIBPLIST_REQUIRES_STR="libplist-2.0 >= 2.2.0" 46 | LIBZIP_REQUIRES_STR="libzip >= 0.10" 47 | LIBIMOBILEDEVICE_REQUIRES_STR="libimobiledevice-1.0 >= 1.2.1" 48 | LIBFRAGMENTZIP_REQUIRES_STR="libfragmentzip >= 47" 49 | LIBIRECOVERY_REQUIRES_STR="libirecovery-1.0 >= 1.0.0" 50 | IMG4TOOL_REQUIRES_STR="libimg4tool >= 162" 51 | LIBGENERAL_REQUIRES_STR="libgeneral >= 26" 52 | 53 | PKG_CHECK_MODULES(libplist, $LIBPLIST_REQUIRES_STR) 54 | PKG_CHECK_MODULES(libzip, $LIBZIP_REQUIRES_STR) 55 | PKG_CHECK_MODULES(libimobiledevice, $LIBIMOBILEDEVICE_REQUIRES_STR) 56 | PKG_CHECK_MODULES(libfragmentzip, $LIBFRAGMENTZIP_REQUIRES_STR) 57 | PKG_CHECK_MODULES(libirecovery, $LIBIRECOVERY_REQUIRES_STR) 58 | PKG_CHECK_MODULES(libimg4tool, $IMG4TOOL_REQUIRES_STR) 59 | PKG_CHECK_MODULES(libgeneral, $LIBGENERAL_REQUIRES_STR) 60 | 61 | # Optional module libipatcher 62 | AC_ARG_WITH([libipatcher], 63 | [AS_HELP_STRING([--without-libipatcher], 64 | [build with bundle-less odysseus support (default is yes)])], 65 | [build_libipatcher=false], 66 | [build_libipatcher=true]) 67 | 68 | PKG_PROG_PKG_CONFIG 69 | LIBIPATCHER_FLAGS=$($PKG_CONFIG --cflags libipatcher) 70 | if [test -z "$LIBIPATCHER_FLAGS"]; then 71 | do_libipatcher=no 72 | else 73 | AC_MSG_CHECKING([for futurerestore libipatcher]) 74 | if test "$build_libipatcher" = "true"; then 75 | PKG_CHECK_MODULES(libipatcher, $LIBIPATCHER_REQUIRES_STR) 76 | AC_DEFINE(HAVE_LIBIPATCHER, 1, [Define if you have libipatcher]) 77 | do_libipatcher=yes 78 | else 79 | do_libipatcher=no 80 | fi 81 | fi 82 | AM_CONDITIONAL([HAVE_LIBIPATCHER],[test "x$do_libipatcher" = "xyes"]) 83 | 84 | AC_DEFINE(CUSTOM_LOGGING, 1, [required for futurerestore]) 85 | 86 | LT_INIT 87 | 88 | AC_OUTPUT([ 89 | Makefile 90 | futurerestore/Makefile 91 | ]) 92 | 93 | echo " 94 | Configuration for $PACKAGE $VERSION: 95 | ------------------------------------------- 96 | 97 | Install prefix ..........: $prefix 98 | With libipatcher ........: $do_libipatcher 99 | Now type 'make' to build $PACKAGE $VERSION, 100 | and then 'make install' for installation. 101 | " 102 | -------------------------------------------------------------------------------- /futurerestore.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 47; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5669111D23B3D86E00C93279 /* libbz2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669111C23B3D86E00C93279 /* libbz2.a */; }; 11 | 5669111F23B3D88200C93279 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669111E23B3D88200C93279 /* libcrypto.a */; }; 12 | 5669112123B3D89B00C93279 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112023B3D89B00C93279 /* libcurl.tbd */; }; 13 | 5669112323B3D89E00C93279 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112223B3D89E00C93279 /* libz.tbd */; }; 14 | 5669112523B3D8B200C93279 /* libfragmentzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112423B3D8B200C93279 /* libfragmentzip.a */; }; 15 | 5669112723B3D8BE00C93279 /* libgeneral.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112623B3D8BE00C93279 /* libgeneral.a */; }; 16 | 5669112923B3D8CF00C93279 /* libimg4tool.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112823B3D8CE00C93279 /* libimg4tool.a */; }; 17 | 5669112B23B3D8DA00C93279 /* libimobiledevice.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112A23B3D8DA00C93279 /* libimobiledevice.a */; }; 18 | 5669112D23B3D8E200C93279 /* libipatcher.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112C23B3D8E200C93279 /* libipatcher.a */; }; 19 | 5669112F23B3D8ED00C93279 /* libirecovery.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669112E23B3D8ED00C93279 /* libirecovery.a */; }; 20 | 5669113123B3D91B00C93279 /* libpartialzip-1.0.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669113023B3D91B00C93279 /* libpartialzip-1.0.a */; }; 21 | 5669113323B3D92B00C93279 /* libplist.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669113223B3D92B00C93279 /* libplist.a */; }; 22 | 5669113523B3D94300C93279 /* libzip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5669113423B3D94300C93279 /* libzip.a */; }; 23 | 878587471D89CFDC008689F0 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 878587461D89CFDC008689F0 /* main.cpp */; }; 24 | 8799B0B21D89D99D002F4D5F /* futurerestore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8799B0B01D89D99D002F4D5F /* futurerestore.cpp */; }; 25 | 8799B0B31D89DAE7002F4D5F /* idevicerestore.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785875C1D89D1C1008689F0 /* idevicerestore.c */; }; 26 | 8799B0B41D89DAF6002F4D5F /* tss.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587761D89D1C1008689F0 /* tss.c */; }; 27 | 8799B0B51D89DAFF002F4D5F /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587511D89D1C1008689F0 /* common.c */; }; 28 | 8799B0B61D89DAFF002F4D5F /* dfu.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587531D89D1C1008689F0 /* dfu.c */; }; 29 | 8799B0B71D89DAFF002F4D5F /* normal.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785876C1D89D1C1008689F0 /* normal.c */; }; 30 | 8799B0B81D89DAFF002F4D5F /* recovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785876E1D89D1C1008689F0 /* recovery.c */; }; 31 | 8799B0B91D89DB0D002F4D5F /* img3.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785875E1D89D1C1008689F0 /* img3.c */; }; 32 | 8799B0BB1D89DB12002F4D5F /* download.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587551D89D1C1008689F0 /* download.c */; settings = {COMPILER_FLAGS = "-DPACKAGE_VERSION=\"\""; }; }; 33 | 8799B0BC1D89DB27002F4D5F /* ipsw.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587621D89D1C1008689F0 /* ipsw.c */; }; 34 | 8799B0BD1D89DB27002F4D5F /* limera1n.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587641D89D1C1008689F0 /* limera1n.c */; }; 35 | 8799B0BE1D89DB27002F4D5F /* restore.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587701D89D1C1008689F0 /* restore.c */; }; 36 | 8799B0BF1D89DB38002F4D5F /* asr.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785874F1D89D1C1008689F0 /* asr.c */; }; 37 | 8799B0C01D89DB38002F4D5F /* fdr.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587581D89D1C1008689F0 /* fdr.c */; }; 38 | 8799B0C11D89DB38002F4D5F /* fls.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785875A1D89D1C1008689F0 /* fls.c */; }; 39 | 8799B0C21D89DB46002F4D5F /* thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587741D89D1C1008689F0 /* thread.c */; }; 40 | 8799B0C31D89DB4B002F4D5F /* socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587721D89D1C1008689F0 /* socket.c */; }; 41 | 8799B0C41D89DB55002F4D5F /* mbn.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785876A1D89D1C1008689F0 /* mbn.c */; }; 42 | 8799B0C51D89DB67002F4D5F /* locking.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587671D89D1C1008689F0 /* locking.c */; }; 43 | 8799B0CA1D89E371002F4D5F /* img4.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587601D89D1C1008689F0 /* img4.c */; }; 44 | 8799B0CB1D89F796002F4D5F /* tsschecker.c in Sources */ = {isa = PBXBuildFile; fileRef = 8785879F1D89D2BA008689F0 /* tsschecker.c */; }; 45 | 8799B0CC1D89F7B9002F4D5F /* download.c in Sources */ = {isa = PBXBuildFile; fileRef = 878587981D89D2BA008689F0 /* download.c */; }; 46 | 87B517C3236EF36B009EAB8F /* ftab.c in Sources */ = {isa = PBXBuildFile; fileRef = 87B517C1236EF36B009EAB8F /* ftab.c */; }; 47 | 87B517C6236EF3B0009EAB8F /* json_plist.c in Sources */ = {isa = PBXBuildFile; fileRef = 87B517C5236EF3B0009EAB8F /* json_plist.c */; }; 48 | 87B517C9236EF3CD009EAB8F /* jsmn.c in Sources */ = {isa = PBXBuildFile; fileRef = 87B517C7236EF3CD009EAB8F /* jsmn.c */; }; 49 | /* End PBXBuildFile section */ 50 | 51 | /* Begin PBXCopyFilesBuildPhase section */ 52 | 8762F346236DF4D900F42FDB /* Embed Libraries */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = ""; 56 | dstSubfolderSpec = 10; 57 | files = ( 58 | ); 59 | name = "Embed Libraries"; 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | 878587411D89CFDC008689F0 /* CopyFiles */ = { 63 | isa = PBXCopyFilesBuildPhase; 64 | buildActionMask = 2147483647; 65 | dstPath = /usr/share/man/man1/; 66 | dstSubfolderSpec = 0; 67 | files = ( 68 | ); 69 | runOnlyForDeploymentPostprocessing = 1; 70 | }; 71 | /* End PBXCopyFilesBuildPhase section */ 72 | 73 | /* Begin PBXFileReference section */ 74 | 5669111C23B3D86E00C93279 /* libbz2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbz2.a; path = ../../../../../usr/local/lib/libbz2.a; sourceTree = ""; }; 75 | 5669111E23B3D88200C93279 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = ../../../../../usr/local/lib/libcrypto.a; sourceTree = ""; }; 76 | 5669112023B3D89B00C93279 /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; }; 77 | 5669112223B3D89E00C93279 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 78 | 5669112423B3D8B200C93279 /* libfragmentzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfragmentzip.a; path = ../../../../../usr/local/lib/libfragmentzip.a; sourceTree = ""; }; 79 | 5669112623B3D8BE00C93279 /* libgeneral.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgeneral.a; path = ../../../../../usr/local/lib/libgeneral.a; sourceTree = ""; }; 80 | 5669112823B3D8CE00C93279 /* libimg4tool.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libimg4tool.a; path = ../../../../../usr/local/lib/libimg4tool.a; sourceTree = ""; }; 81 | 5669112A23B3D8DA00C93279 /* libimobiledevice.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libimobiledevice.a; path = ../../../../../usr/local/lib/libimobiledevice.a; sourceTree = ""; }; 82 | 5669112C23B3D8E200C93279 /* libipatcher.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libipatcher.a; path = ../../../../../usr/local/lib/libipatcher.a; sourceTree = ""; }; 83 | 5669112E23B3D8ED00C93279 /* libirecovery.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libirecovery.a; path = ../../../../../usr/local/lib/libirecovery.a; sourceTree = ""; }; 84 | 5669113023B3D91B00C93279 /* libpartialzip-1.0.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libpartialzip-1.0.a"; path = "../../../../../usr/local/lib/libpartialzip-1.0.a"; sourceTree = ""; }; 85 | 5669113223B3D92B00C93279 /* libplist.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libplist.a; path = ../../../../../usr/local/lib/libplist.a; sourceTree = ""; }; 86 | 5669113423B3D94300C93279 /* libzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libzip.a; path = ../../../../../usr/local/lib/libzip.a; sourceTree = ""; }; 87 | 878587431D89CFDC008689F0 /* futurerestore */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = futurerestore; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | 878587461D89CFDC008689F0 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; 89 | 8785874F1D89D1C1008689F0 /* asr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asr.c; sourceTree = ""; }; 90 | 878587501D89D1C1008689F0 /* asr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asr.h; sourceTree = ""; }; 91 | 878587511D89D1C1008689F0 /* common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = common.c; sourceTree = ""; }; 92 | 878587521D89D1C1008689F0 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; 93 | 878587531D89D1C1008689F0 /* dfu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dfu.c; sourceTree = ""; }; 94 | 878587541D89D1C1008689F0 /* dfu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dfu.h; sourceTree = ""; }; 95 | 878587551D89D1C1008689F0 /* download.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = download.c; sourceTree = ""; }; 96 | 878587561D89D1C1008689F0 /* download.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = download.h; sourceTree = ""; }; 97 | 878587571D89D1C1008689F0 /* endianness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endianness.h; sourceTree = ""; }; 98 | 878587581D89D1C1008689F0 /* fdr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fdr.c; sourceTree = ""; }; 99 | 878587591D89D1C1008689F0 /* fdr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fdr.h; sourceTree = ""; }; 100 | 8785875A1D89D1C1008689F0 /* fls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fls.c; sourceTree = ""; }; 101 | 8785875B1D89D1C1008689F0 /* fls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fls.h; sourceTree = ""; }; 102 | 8785875C1D89D1C1008689F0 /* idevicerestore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = idevicerestore.c; sourceTree = ""; }; 103 | 8785875D1D89D1C1008689F0 /* idevicerestore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = idevicerestore.h; sourceTree = ""; }; 104 | 8785875E1D89D1C1008689F0 /* img3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = img3.c; sourceTree = ""; }; 105 | 8785875F1D89D1C1008689F0 /* img3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = img3.h; sourceTree = ""; }; 106 | 878587601D89D1C1008689F0 /* img4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = img4.c; sourceTree = ""; }; 107 | 878587611D89D1C1008689F0 /* img4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = img4.h; sourceTree = ""; }; 108 | 878587621D89D1C1008689F0 /* ipsw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ipsw.c; sourceTree = ""; }; 109 | 878587631D89D1C1008689F0 /* ipsw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsw.h; sourceTree = ""; }; 110 | 878587641D89D1C1008689F0 /* limera1n.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = limera1n.c; sourceTree = ""; }; 111 | 878587651D89D1C1008689F0 /* limera1n.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = limera1n.h; sourceTree = ""; }; 112 | 878587661D89D1C1008689F0 /* limera1n_payload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = limera1n_payload.h; sourceTree = ""; }; 113 | 878587671D89D1C1008689F0 /* locking.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = locking.c; sourceTree = ""; }; 114 | 878587681D89D1C1008689F0 /* locking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = locking.h; sourceTree = ""; }; 115 | 8785876A1D89D1C1008689F0 /* mbn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mbn.c; sourceTree = ""; }; 116 | 8785876B1D89D1C1008689F0 /* mbn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mbn.h; sourceTree = ""; }; 117 | 8785876C1D89D1C1008689F0 /* normal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = normal.c; sourceTree = ""; }; 118 | 8785876D1D89D1C1008689F0 /* normal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = normal.h; sourceTree = ""; }; 119 | 8785876E1D89D1C1008689F0 /* recovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = recovery.c; sourceTree = ""; }; 120 | 8785876F1D89D1C1008689F0 /* recovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = recovery.h; sourceTree = ""; }; 121 | 878587701D89D1C1008689F0 /* restore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = restore.c; sourceTree = ""; }; 122 | 878587711D89D1C1008689F0 /* restore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = restore.h; sourceTree = ""; }; 123 | 878587721D89D1C1008689F0 /* socket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = socket.c; sourceTree = ""; }; 124 | 878587731D89D1C1008689F0 /* socket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = socket.h; sourceTree = ""; }; 125 | 878587741D89D1C1008689F0 /* thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = thread.c; sourceTree = ""; }; 126 | 878587751D89D1C1008689F0 /* thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = thread.h; sourceTree = ""; }; 127 | 878587761D89D1C1008689F0 /* tss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tss.c; sourceTree = ""; }; 128 | 878587771D89D1C1008689F0 /* tss.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tss.h; sourceTree = ""; }; 129 | 878587981D89D2BA008689F0 /* download.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = download.c; sourceTree = ""; }; 130 | 878587991D89D2BA008689F0 /* download.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = download.h; sourceTree = ""; }; 131 | 8785879A1D89D2BA008689F0 /* jssy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = jssy.c; path = ../external/jssy/jssy/jssy.c; sourceTree = ""; }; 132 | 8785879B1D89D2BA008689F0 /* jssy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jssy.h; path = ../external/jssy/jssy/jssy.h; sourceTree = ""; }; 133 | 8785879F1D89D2BA008689F0 /* tsschecker.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tsschecker.c; sourceTree = ""; }; 134 | 878587A01D89D2BA008689F0 /* tsschecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tsschecker.h; sourceTree = ""; }; 135 | 8799B0B01D89D99D002F4D5F /* futurerestore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = futurerestore.cpp; sourceTree = ""; }; 136 | 8799B0B11D89D99D002F4D5F /* futurerestore.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = futurerestore.hpp; sourceTree = ""; }; 137 | 87B517C1236EF36B009EAB8F /* ftab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ftab.c; sourceTree = ""; }; 138 | 87B517C2236EF36B009EAB8F /* ftab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ftab.h; sourceTree = ""; }; 139 | 87B517C4236EF3B0009EAB8F /* json_plist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_plist.h; sourceTree = ""; }; 140 | 87B517C5236EF3B0009EAB8F /* json_plist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = json_plist.c; sourceTree = ""; }; 141 | 87B517C7236EF3CD009EAB8F /* jsmn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jsmn.c; sourceTree = ""; }; 142 | 87B517C8236EF3CD009EAB8F /* jsmn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jsmn.h; sourceTree = ""; }; 143 | 87F574C71E151DA6008D5C4D /* libcommonCrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcommonCrypto.tbd; path = usr/lib/system/libcommonCrypto.tbd; sourceTree = SDKROOT; }; 144 | 87F574CC1E151EF8008D5C4D /* libcorecrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcorecrypto.tbd; path = usr/lib/system/libcorecrypto.tbd; sourceTree = SDKROOT; }; 145 | 87F574CE1E151F11008D5C4D /* libSystem.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libSystem.tbd; path = usr/lib/libSystem.tbd; sourceTree = SDKROOT; }; 146 | /* End PBXFileReference section */ 147 | 148 | /* Begin PBXFrameworksBuildPhase section */ 149 | 878587401D89CFDC008689F0 /* Frameworks */ = { 150 | isa = PBXFrameworksBuildPhase; 151 | buildActionMask = 2147483647; 152 | files = ( 153 | 5669113323B3D92B00C93279 /* libplist.a in Frameworks */, 154 | 5669111D23B3D86E00C93279 /* libbz2.a in Frameworks */, 155 | 5669112523B3D8B200C93279 /* libfragmentzip.a in Frameworks */, 156 | 5669112923B3D8CF00C93279 /* libimg4tool.a in Frameworks */, 157 | 5669112D23B3D8E200C93279 /* libipatcher.a in Frameworks */, 158 | 5669112B23B3D8DA00C93279 /* libimobiledevice.a in Frameworks */, 159 | 5669112F23B3D8ED00C93279 /* libirecovery.a in Frameworks */, 160 | 5669113123B3D91B00C93279 /* libpartialzip-1.0.a in Frameworks */, 161 | 5669112723B3D8BE00C93279 /* libgeneral.a in Frameworks */, 162 | 5669112123B3D89B00C93279 /* libcurl.tbd in Frameworks */, 163 | 5669112323B3D89E00C93279 /* libz.tbd in Frameworks */, 164 | 5669111F23B3D88200C93279 /* libcrypto.a in Frameworks */, 165 | 5669113523B3D94300C93279 /* libzip.a in Frameworks */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXFrameworksBuildPhase section */ 170 | 171 | /* Begin PBXGroup section */ 172 | 8785873A1D89CFDC008689F0 = { 173 | isa = PBXGroup; 174 | children = ( 175 | 878587451D89CFDC008689F0 /* futurerestore */, 176 | 878587441D89CFDC008689F0 /* Products */, 177 | 87F574C21E151CDE008D5C4D /* Frameworks */, 178 | ); 179 | sourceTree = ""; 180 | }; 181 | 878587441D89CFDC008689F0 /* Products */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | 878587431D89CFDC008689F0 /* futurerestore */, 185 | ); 186 | name = Products; 187 | sourceTree = ""; 188 | }; 189 | 878587451D89CFDC008689F0 /* futurerestore */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | 8785874D1D89D1A4008689F0 /* external */, 193 | 8799B0B11D89D99D002F4D5F /* futurerestore.hpp */, 194 | 8799B0B01D89D99D002F4D5F /* futurerestore.cpp */, 195 | 878587461D89CFDC008689F0 /* main.cpp */, 196 | ); 197 | path = futurerestore; 198 | sourceTree = ""; 199 | }; 200 | 8785874D1D89D1A4008689F0 /* external */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | 878587961D89D2BA008689F0 /* tsschecker */, 204 | 8785874E1D89D1C1008689F0 /* idevicerestore */, 205 | ); 206 | name = external; 207 | sourceTree = ""; 208 | }; 209 | 8785874E1D89D1C1008689F0 /* idevicerestore */ = { 210 | isa = PBXGroup; 211 | children = ( 212 | 8785874F1D89D1C1008689F0 /* asr.c */, 213 | 878587501D89D1C1008689F0 /* asr.h */, 214 | 878587511D89D1C1008689F0 /* common.c */, 215 | 878587521D89D1C1008689F0 /* common.h */, 216 | 878587531D89D1C1008689F0 /* dfu.c */, 217 | 878587541D89D1C1008689F0 /* dfu.h */, 218 | 878587551D89D1C1008689F0 /* download.c */, 219 | 878587561D89D1C1008689F0 /* download.h */, 220 | 878587571D89D1C1008689F0 /* endianness.h */, 221 | 878587581D89D1C1008689F0 /* fdr.c */, 222 | 878587591D89D1C1008689F0 /* fdr.h */, 223 | 8785875A1D89D1C1008689F0 /* fls.c */, 224 | 8785875B1D89D1C1008689F0 /* fls.h */, 225 | 8785875C1D89D1C1008689F0 /* idevicerestore.c */, 226 | 8785875D1D89D1C1008689F0 /* idevicerestore.h */, 227 | 8785875E1D89D1C1008689F0 /* img3.c */, 228 | 8785875F1D89D1C1008689F0 /* img3.h */, 229 | 878587601D89D1C1008689F0 /* img4.c */, 230 | 878587611D89D1C1008689F0 /* img4.h */, 231 | 87B517C5236EF3B0009EAB8F /* json_plist.c */, 232 | 87B517C4236EF3B0009EAB8F /* json_plist.h */, 233 | 87B517C1236EF36B009EAB8F /* ftab.c */, 234 | 87B517C2236EF36B009EAB8F /* ftab.h */, 235 | 87B517C7236EF3CD009EAB8F /* jsmn.c */, 236 | 87B517C8236EF3CD009EAB8F /* jsmn.h */, 237 | 878587621D89D1C1008689F0 /* ipsw.c */, 238 | 878587631D89D1C1008689F0 /* ipsw.h */, 239 | 878587641D89D1C1008689F0 /* limera1n.c */, 240 | 878587651D89D1C1008689F0 /* limera1n.h */, 241 | 878587661D89D1C1008689F0 /* limera1n_payload.h */, 242 | 878587671D89D1C1008689F0 /* locking.c */, 243 | 878587681D89D1C1008689F0 /* locking.h */, 244 | 8785876A1D89D1C1008689F0 /* mbn.c */, 245 | 8785876B1D89D1C1008689F0 /* mbn.h */, 246 | 8785876C1D89D1C1008689F0 /* normal.c */, 247 | 8785876D1D89D1C1008689F0 /* normal.h */, 248 | 8785876E1D89D1C1008689F0 /* recovery.c */, 249 | 8785876F1D89D1C1008689F0 /* recovery.h */, 250 | 878587701D89D1C1008689F0 /* restore.c */, 251 | 878587711D89D1C1008689F0 /* restore.h */, 252 | 878587721D89D1C1008689F0 /* socket.c */, 253 | 878587731D89D1C1008689F0 /* socket.h */, 254 | 878587741D89D1C1008689F0 /* thread.c */, 255 | 878587751D89D1C1008689F0 /* thread.h */, 256 | 878587761D89D1C1008689F0 /* tss.c */, 257 | 878587771D89D1C1008689F0 /* tss.h */, 258 | ); 259 | name = idevicerestore; 260 | path = external/idevicerestore/src; 261 | sourceTree = SOURCE_ROOT; 262 | }; 263 | 878587961D89D2BA008689F0 /* tsschecker */ = { 264 | isa = PBXGroup; 265 | children = ( 266 | 878587991D89D2BA008689F0 /* download.h */, 267 | 878587981D89D2BA008689F0 /* download.c */, 268 | 8785879B1D89D2BA008689F0 /* jssy.h */, 269 | 8785879A1D89D2BA008689F0 /* jssy.c */, 270 | 878587A01D89D2BA008689F0 /* tsschecker.h */, 271 | 8785879F1D89D2BA008689F0 /* tsschecker.c */, 272 | ); 273 | name = tsschecker; 274 | path = external/tsschecker/tsschecker; 275 | sourceTree = SOURCE_ROOT; 276 | }; 277 | 87F574C21E151CDE008D5C4D /* Frameworks */ = { 278 | isa = PBXGroup; 279 | children = ( 280 | 5669111C23B3D86E00C93279 /* libbz2.a */, 281 | 87F574C71E151DA6008D5C4D /* libcommonCrypto.tbd */, 282 | 87F574CC1E151EF8008D5C4D /* libcorecrypto.tbd */, 283 | 5669111E23B3D88200C93279 /* libcrypto.a */, 284 | 5669112023B3D89B00C93279 /* libcurl.tbd */, 285 | 5669112223B3D89E00C93279 /* libz.tbd */, 286 | 5669112623B3D8BE00C93279 /* libgeneral.a */, 287 | 5669112423B3D8B200C93279 /* libfragmentzip.a */, 288 | 5669112823B3D8CE00C93279 /* libimg4tool.a */, 289 | 5669112A23B3D8DA00C93279 /* libimobiledevice.a */, 290 | 5669112C23B3D8E200C93279 /* libipatcher.a */, 291 | 5669112E23B3D8ED00C93279 /* libirecovery.a */, 292 | 5669113023B3D91B00C93279 /* libpartialzip-1.0.a */, 293 | 5669113223B3D92B00C93279 /* libplist.a */, 294 | 87F574CE1E151F11008D5C4D /* libSystem.tbd */, 295 | 5669113423B3D94300C93279 /* libzip.a */, 296 | ); 297 | name = Frameworks; 298 | sourceTree = ""; 299 | }; 300 | /* End PBXGroup section */ 301 | 302 | /* Begin PBXNativeTarget section */ 303 | 878587421D89CFDC008689F0 /* futurerestore */ = { 304 | isa = PBXNativeTarget; 305 | buildConfigurationList = 8785874A1D89CFDC008689F0 /* Build configuration list for PBXNativeTarget "futurerestore" */; 306 | buildPhases = ( 307 | 8785873F1D89CFDC008689F0 /* Sources */, 308 | 878587401D89CFDC008689F0 /* Frameworks */, 309 | 878587411D89CFDC008689F0 /* CopyFiles */, 310 | 8762F346236DF4D900F42FDB /* Embed Libraries */, 311 | ); 312 | buildRules = ( 313 | ); 314 | dependencies = ( 315 | ); 316 | name = futurerestore; 317 | productName = futurerestore; 318 | productReference = 878587431D89CFDC008689F0 /* futurerestore */; 319 | productType = "com.apple.product-type.tool"; 320 | }; 321 | /* End PBXNativeTarget section */ 322 | 323 | /* Begin PBXProject section */ 324 | 8785873B1D89CFDC008689F0 /* Project object */ = { 325 | isa = PBXProject; 326 | attributes = { 327 | LastUpgradeCheck = 1130; 328 | ORGANIZATIONNAME = tihmstar; 329 | TargetAttributes = { 330 | 878587421D89CFDC008689F0 = { 331 | CreatedOnToolsVersion = 7.3.1; 332 | }; 333 | }; 334 | }; 335 | buildConfigurationList = 8785873E1D89CFDC008689F0 /* Build configuration list for PBXProject "futurerestore" */; 336 | compatibilityVersion = "Xcode 6.3"; 337 | developmentRegion = en; 338 | hasScannedForEncodings = 0; 339 | knownRegions = ( 340 | en, 341 | ); 342 | mainGroup = 8785873A1D89CFDC008689F0; 343 | productRefGroup = 878587441D89CFDC008689F0 /* Products */; 344 | projectDirPath = ""; 345 | projectRoot = ""; 346 | targets = ( 347 | 878587421D89CFDC008689F0 /* futurerestore */, 348 | ); 349 | }; 350 | /* End PBXProject section */ 351 | 352 | /* Begin PBXSourcesBuildPhase section */ 353 | 8785873F1D89CFDC008689F0 /* Sources */ = { 354 | isa = PBXSourcesBuildPhase; 355 | buildActionMask = 2147483647; 356 | files = ( 357 | 8799B0C11D89DB38002F4D5F /* fls.c in Sources */, 358 | 8799B0B41D89DAF6002F4D5F /* tss.c in Sources */, 359 | 8799B0C01D89DB38002F4D5F /* fdr.c in Sources */, 360 | 8799B0BC1D89DB27002F4D5F /* ipsw.c in Sources */, 361 | 87B517C3236EF36B009EAB8F /* ftab.c in Sources */, 362 | 8799B0CC1D89F7B9002F4D5F /* download.c in Sources */, 363 | 8799B0B91D89DB0D002F4D5F /* img3.c in Sources */, 364 | 8799B0B51D89DAFF002F4D5F /* common.c in Sources */, 365 | 8799B0C41D89DB55002F4D5F /* mbn.c in Sources */, 366 | 8799B0B81D89DAFF002F4D5F /* recovery.c in Sources */, 367 | 8799B0B31D89DAE7002F4D5F /* idevicerestore.c in Sources */, 368 | 8799B0BB1D89DB12002F4D5F /* download.c in Sources */, 369 | 8799B0B71D89DAFF002F4D5F /* normal.c in Sources */, 370 | 87B517C9236EF3CD009EAB8F /* jsmn.c in Sources */, 371 | 8799B0C31D89DB4B002F4D5F /* socket.c in Sources */, 372 | 8799B0C21D89DB46002F4D5F /* thread.c in Sources */, 373 | 8799B0B61D89DAFF002F4D5F /* dfu.c in Sources */, 374 | 8799B0BD1D89DB27002F4D5F /* limera1n.c in Sources */, 375 | 8799B0C51D89DB67002F4D5F /* locking.c in Sources */, 376 | 878587471D89CFDC008689F0 /* main.cpp in Sources */, 377 | 87B517C6236EF3B0009EAB8F /* json_plist.c in Sources */, 378 | 8799B0BF1D89DB38002F4D5F /* asr.c in Sources */, 379 | 8799B0BE1D89DB27002F4D5F /* restore.c in Sources */, 380 | 8799B0CB1D89F796002F4D5F /* tsschecker.c in Sources */, 381 | 8799B0CA1D89E371002F4D5F /* img4.c in Sources */, 382 | 8799B0B21D89D99D002F4D5F /* futurerestore.cpp in Sources */, 383 | ); 384 | runOnlyForDeploymentPostprocessing = 0; 385 | }; 386 | /* End PBXSourcesBuildPhase section */ 387 | 388 | /* Begin XCBuildConfiguration section */ 389 | 878587481D89CFDC008689F0 /* Debug */ = { 390 | isa = XCBuildConfiguration; 391 | buildSettings = { 392 | ALWAYS_SEARCH_USER_PATHS = NO; 393 | CLANG_ANALYZER_NONNULL = YES; 394 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 395 | CLANG_CXX_LIBRARY = "libc++"; 396 | CLANG_ENABLE_MODULES = YES; 397 | CLANG_ENABLE_OBJC_ARC = YES; 398 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 399 | CLANG_WARN_BOOL_CONVERSION = YES; 400 | CLANG_WARN_COMMA = YES; 401 | CLANG_WARN_CONSTANT_CONVERSION = YES; 402 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 403 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 404 | CLANG_WARN_EMPTY_BODY = YES; 405 | CLANG_WARN_ENUM_CONVERSION = YES; 406 | CLANG_WARN_INFINITE_RECURSION = YES; 407 | CLANG_WARN_INT_CONVERSION = YES; 408 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 409 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 410 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 411 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 412 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 413 | CLANG_WARN_STRICT_PROTOTYPES = YES; 414 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 415 | CLANG_WARN_UNREACHABLE_CODE = YES; 416 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 417 | CODE_SIGN_IDENTITY = "-"; 418 | COPY_PHASE_STRIP = NO; 419 | DEBUG_INFORMATION_FORMAT = dwarf; 420 | ENABLE_STRICT_OBJC_MSGSEND = YES; 421 | ENABLE_TESTABILITY = YES; 422 | GCC_C_LANGUAGE_STANDARD = gnu99; 423 | GCC_DYNAMIC_NO_PIC = NO; 424 | GCC_NO_COMMON_BLOCKS = YES; 425 | GCC_OPTIMIZATION_LEVEL = 0; 426 | GCC_PREPROCESSOR_DEFINITIONS = ( 427 | "DEBUG=1", 428 | "$(inherited)", 429 | ); 430 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 431 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 432 | GCC_WARN_UNDECLARED_SELECTOR = YES; 433 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 434 | GCC_WARN_UNUSED_FUNCTION = YES; 435 | GCC_WARN_UNUSED_VARIABLE = YES; 436 | INSTALL_PATH = /usr/local/bin; 437 | MACOSX_DEPLOYMENT_TARGET = 10.11; 438 | MTL_ENABLE_DEBUG_INFO = YES; 439 | ONLY_ACTIVE_ARCH = YES; 440 | SDKROOT = macosx; 441 | }; 442 | name = Debug; 443 | }; 444 | 878587491D89CFDC008689F0 /* Release */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | ALWAYS_SEARCH_USER_PATHS = NO; 448 | CLANG_ANALYZER_NONNULL = YES; 449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 450 | CLANG_CXX_LIBRARY = "libc++"; 451 | CLANG_ENABLE_MODULES = YES; 452 | CLANG_ENABLE_OBJC_ARC = YES; 453 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 454 | CLANG_WARN_BOOL_CONVERSION = YES; 455 | CLANG_WARN_COMMA = YES; 456 | CLANG_WARN_CONSTANT_CONVERSION = YES; 457 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 458 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 459 | CLANG_WARN_EMPTY_BODY = YES; 460 | CLANG_WARN_ENUM_CONVERSION = YES; 461 | CLANG_WARN_INFINITE_RECURSION = YES; 462 | CLANG_WARN_INT_CONVERSION = YES; 463 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 464 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 465 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 467 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 468 | CLANG_WARN_STRICT_PROTOTYPES = YES; 469 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 470 | CLANG_WARN_UNREACHABLE_CODE = YES; 471 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 472 | CODE_SIGN_IDENTITY = "-"; 473 | COPY_PHASE_STRIP = NO; 474 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 475 | ENABLE_NS_ASSERTIONS = NO; 476 | ENABLE_STRICT_OBJC_MSGSEND = YES; 477 | GCC_C_LANGUAGE_STANDARD = gnu99; 478 | GCC_NO_COMMON_BLOCKS = YES; 479 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 480 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 481 | GCC_WARN_UNDECLARED_SELECTOR = YES; 482 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 483 | GCC_WARN_UNUSED_FUNCTION = YES; 484 | GCC_WARN_UNUSED_VARIABLE = YES; 485 | INSTALL_PATH = /usr/local/bin; 486 | MACOSX_DEPLOYMENT_TARGET = 10.11; 487 | MTL_ENABLE_DEBUG_INFO = NO; 488 | SDKROOT = macosx; 489 | }; 490 | name = Release; 491 | }; 492 | 8785874B1D89CFDC008689F0 /* Debug */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | ALWAYS_SEARCH_USER_PATHS = YES; 496 | GCC_PREPROCESSOR_DEFINITIONS = ( 497 | "DEBUG=1", 498 | "$(inherited)", 499 | "IDEVICERESTORE_NOMAIN=1", 500 | "CUSTOM_LOGGING=1", 501 | "HAVE_REALPATH=1", 502 | ); 503 | HEADER_SEARCH_PATHS = ""; 504 | LIBRARY_SEARCH_PATHS = ( 505 | /usr/local/lib, 506 | /usr/lib, 507 | /usr/local/opt/openssl/lib, 508 | "$(SDKROOT)/usr/lib/system", 509 | ); 510 | OTHER_CFLAGS = "-DHAVE_LIBIPATCHER"; 511 | PRODUCT_NAME = "$(TARGET_NAME)"; 512 | 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"; 513 | }; 514 | name = Debug; 515 | }; 516 | 8785874C1D89CFDC008689F0 /* Release */ = { 517 | isa = XCBuildConfiguration; 518 | buildSettings = { 519 | ALWAYS_SEARCH_USER_PATHS = YES; 520 | HEADER_SEARCH_PATHS = ""; 521 | LIBRARY_SEARCH_PATHS = ( 522 | /usr/local/lib, 523 | /usr/lib, 524 | /usr/local/opt/openssl/lib, 525 | "$(SDKROOT)/usr/lib/system", 526 | ); 527 | OTHER_CFLAGS = "-DHAVE_LIBIPATCHER"; 528 | PRODUCT_NAME = "$(TARGET_NAME)"; 529 | 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"; 530 | }; 531 | name = Release; 532 | }; 533 | /* End XCBuildConfiguration section */ 534 | 535 | /* Begin XCConfigurationList section */ 536 | 8785873E1D89CFDC008689F0 /* Build configuration list for PBXProject "futurerestore" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | 878587481D89CFDC008689F0 /* Debug */, 540 | 878587491D89CFDC008689F0 /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | 8785874A1D89CFDC008689F0 /* Build configuration list for PBXNativeTarget "futurerestore" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | 8785874B1D89CFDC008689F0 /* Debug */, 549 | 8785874C1D89CFDC008689F0 /* Release */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | /* End XCConfigurationList section */ 555 | }; 556 | rootObject = 8785873B1D89CFDC008689F0 /* Project object */; 557 | } 558 | -------------------------------------------------------------------------------- /futurerestore.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /futurerestore.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /futurerestore/Makefile.am: -------------------------------------------------------------------------------- 1 | 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) 2 | AM_LDFLAGS = $(libplist_LIBS) $(libzip_LIBS) $(libimobiledevice_LIBS) $(libfragmentzip_LIBS) $(libirecovery_LIBS) $(libimg4tool_LIBS) $(libgeneral_LIBS) 3 | 4 | if HAVE_LIBIPATCHER 5 | AM_LDFLAGS += $(libipatcher_LIBS) 6 | AM_CFLAGS += $(libipatcher_CFLAGS) 7 | endif 8 | 9 | bin_PROGRAMS = futurerestore 10 | futurerestore_CXXFLAGS = $(AM_CFLAGS) 11 | 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) 12 | futurerestore_SOURCES = futurerestore.cpp main.cpp 13 | -------------------------------------------------------------------------------- /futurerestore/futurerestore.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // futurerestore.cpp 3 | // futurerestore 4 | // 5 | // Created by tihmstar on 14.09.16. 6 | // Copyright © 2016 tihmstar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "futurerestore.hpp" 17 | 18 | #ifdef HAVE_LIBIPATCHER 19 | #include 20 | #endif 21 | 22 | #include 23 | 24 | extern "C"{ 25 | #include "common.h" 26 | #include "normal.h" 27 | #include "recovery.h" 28 | #include "dfu.h" 29 | #include "ipsw.h" 30 | #include "locking.h" 31 | #include "restore.h" 32 | #include "tsschecker.h" 33 | #include 34 | } 35 | 36 | //(re)define __mkdir 37 | #ifdef __mkdir 38 | #undef __mkdir 39 | #endif 40 | #ifdef WIN32 41 | #include 42 | #define __mkdir(path, mode) mkdir(path) 43 | #else 44 | #include 45 | #define __mkdir(path, mode) mkdir(path, mode) 46 | #endif 47 | 48 | #define USEC_PER_SEC 1000000 49 | 50 | #ifdef WIN32 51 | #define FUTURERESTORE_TMP_PATH "download" 52 | #else 53 | #define TMP_PATH "/tmp" 54 | #define FUTURERESTORE_TMP_PATH TMP_PATH"/futurerestore" 55 | #endif 56 | 57 | #define BASEBAND_TMP_PATH FUTURERESTORE_TMP_PATH"/baseband.bbfw" 58 | #define BASEBAND_MANIFEST_TMP_PATH FUTURERESTORE_TMP_PATH"/basebandManifest.plist" 59 | #define SEP_TMP_PATH FUTURERESTORE_TMP_PATH"/sep.im4p" 60 | #define SEP_MANIFEST_TMP_PATH FUTURERESTORE_TMP_PATH"/sepManifest.plist" 61 | 62 | #ifdef __APPLE__ 63 | # include 64 | # define SHA1(d, n, md) CC_SHA1(d, n, md) 65 | # define SHA384(d, n, md) CC_SHA384(d, n, md) 66 | #else 67 | # include 68 | #endif // __APPLE__ 69 | 70 | #ifndef HAVE_LIBIPATCHER 71 | #define _enterPwnRecoveryRequested false 72 | #endif 73 | 74 | using namespace tihmstar; 75 | 76 | #pragma mark helpers 77 | extern "C"{ 78 | void irecv_event_cb(const irecv_device_event_t* event, void *userdata); 79 | void idevice_event_cb(const idevice_event_t *event, void *userdata); 80 | }; 81 | 82 | #pragma mark futurerestore 83 | futurerestore::futurerestore(bool isUpdateInstall, bool isPwnDfu) : _isUpdateInstall(isUpdateInstall), _isPwnDfu(isPwnDfu){ 84 | _client = idevicerestore_client_new(); 85 | if (_client == NULL) throw std::string("could not create idevicerestore client\n"); 86 | 87 | struct stat st{0}; 88 | if (stat(FUTURERESTORE_TMP_PATH, &st) == -1) __mkdir(FUTURERESTORE_TMP_PATH, 0755); 89 | 90 | nocache = 1; //tsschecker nocache 91 | _foundnonce = -1; 92 | } 93 | 94 | bool futurerestore::init(){ 95 | if (_didInit) return _didInit; 96 | _didInit = (check_mode(_client) != MODE_UNKNOWN); 97 | if (!(_client->image4supported = is_image4_supported(_client))){ 98 | info("[INFO] 32-bit device detected\n"); 99 | }else{ 100 | info("[INFO] 64-bit device detected\n"); 101 | } 102 | return _didInit; 103 | } 104 | 105 | uint64_t futurerestore::getDeviceEcid(){ 106 | retassure(_didInit, "did not init\n"); 107 | uint64_t ecid; 108 | get_ecid(_client, &ecid); 109 | return ecid; 110 | } 111 | 112 | int futurerestore::getDeviceMode(bool reRequest){ 113 | retassure(_didInit, "did not init\n"); 114 | if (!reRequest && _client->mode && _client->mode->index != MODE_UNKNOWN) { 115 | return _client->mode->index; 116 | }else{ 117 | dfu_client_free(_client); 118 | recovery_client_free(_client); 119 | return check_mode(_client); 120 | } 121 | } 122 | 123 | void futurerestore::putDeviceIntoRecovery(){ 124 | retassure(_didInit, "did not init\n"); 125 | 126 | #ifdef HAVE_LIBIPATCHER 127 | _enterPwnRecoveryRequested = _isPwnDfu; 128 | #endif 129 | 130 | getDeviceMode(false); 131 | info("Found device in %s mode\n", _client->mode->string); 132 | if (_client->mode->index == MODE_NORMAL){ 133 | #ifdef HAVE_LIBIPATCHER 134 | retassure(!_isPwnDfu, "isPwnDfu enabled, but device was found in normal mode\n"); 135 | #endif 136 | info("Entering recovery mode...\n"); 137 | retassure(!normal_enter_recovery(_client),"Unable to place device into recovery mode from %s mode\n", _client->mode->string); 138 | }else if (_client->mode->index == MODE_RECOVERY){ 139 | info("Device already in recovery mode\n"); 140 | }else if (_client->mode->index == MODE_DFU && _isPwnDfu && 141 | #ifdef HAVE_LIBIPATCHER 142 | true 143 | #else 144 | false 145 | #endif 146 | ){ 147 | info("requesting to get into pwnRecovery later\n"); 148 | }else if (!_client->image4supported){ 149 | info("32-bit device in DFU mode found, assuming user wants to use iOS 9.x re-restore bug. Not failing here\n"); 150 | }else{ 151 | reterror("unsupported device mode, please put device in recovery or normal mode\n"); 152 | } 153 | 154 | safeFree(_client->udid); //only needs to be freed manually when function did't throw exception 155 | 156 | //these get also freed by destructor 157 | dfu_client_free(_client); 158 | recovery_client_free(_client); 159 | } 160 | 161 | void futurerestore::setAutoboot(bool val){ 162 | retassure(_didInit, "did not init\n"); 163 | 164 | retassure(getDeviceMode(false) == MODE_RECOVERY, "can't set auto-boot, when device isn't in recovery mode\n"); 165 | retassure(!_client->recovery && recovery_client_new(_client),"Could not connect to device in recovery mode.\n"); 166 | retassure(!recovery_set_autoboot(_client, val),"Setting auto-boot failed?!\n"); 167 | } 168 | 169 | void futurerestore::exitRecovery() { 170 | setAutoboot(true); 171 | recovery_send_reset(_client); 172 | recovery_client_free(_client); 173 | } 174 | 175 | plist_t futurerestore::nonceMatchesApTickets(){ 176 | retassure(_didInit, "did not init\n"); 177 | 178 | if (getDeviceMode(true) != MODE_RECOVERY){ 179 | if (getDeviceMode(false) != MODE_DFU || *_client->version != '9') 180 | reterror("Device is not in recovery mode, can't check ApNonce\n"); 181 | else 182 | _rerestoreiOS9 = (info("Detected iOS 9.x 32-bit re-restore, proceeding in DFU mode\n"),true); 183 | } 184 | 185 | unsigned char* realnonce; 186 | int realNonceSize = 0; 187 | if (_rerestoreiOS9) { 188 | info("Skipping ApNonce check\n"); 189 | }else{ 190 | recovery_get_ap_nonce(_client, &realnonce, &realNonceSize); 191 | 192 | info("Got ApNonce from device: "); 193 | int i = 0; 194 | for (i = 0; i < realNonceSize; i++) { 195 | info("%02x ", ((unsigned char *)realnonce)[i]); 196 | } 197 | info("\n"); 198 | } 199 | 200 | vectornonces; 201 | 202 | if (_client->image4supported){ 203 | for (int i=0; i< _im4ms.size(); i++){ 204 | auto nonce = img4tool::getValFromIM4M({_im4ms[i].first,_im4ms[i].second}, 'BNCH'); 205 | if (nonce.payloadSize() == realNonceSize && memcmp(realnonce, nonce.payload(), realNonceSize) == 0) return _aptickets[i]; 206 | } 207 | }else{ 208 | for (int i=0; i< _im4ms.size(); i++){ 209 | size_t ticketNonceSize = 0; 210 | const char *nonce = NULL; 211 | try { 212 | //nonce might not exist, which we use in re-restoring iOS 9.x for 32-bit 213 | auto n = getNonceFromSCAB(_im4ms[i].first, _im4ms[i].second); 214 | ticketNonceSize = n.second; 215 | nonce = n.first; 216 | } catch (...) 217 | { } 218 | if (memcmp(realnonce, nonce, ticketNonceSize) == 0 && 219 | ( (ticketNonceSize == realNonceSize && realNonceSize+ticketNonceSize > 0) || 220 | (!ticketNonceSize && *_client->version == '9' && 221 | (getDeviceMode(false) == MODE_DFU || 222 | ( getDeviceMode(false) == MODE_RECOVERY && !strncmp(getiBootBuild(), "iBoot-2817", strlen("iBoot-2817")) ) 223 | ) 224 | ) 225 | ) 226 | ) 227 | //either nonce needs to match or using re-restore bug in iOS 9.x 228 | return _aptickets[i]; 229 | } 230 | } 231 | 232 | return NULL; 233 | } 234 | 235 | std::pair futurerestore::nonceMatchesIM4Ms(){ 236 | retassure(_didInit, "did not init\n"); 237 | 238 | retassure(getDeviceMode(true) == MODE_RECOVERY, "Device is not in recovery mode, can't check ApNonce\n"); 239 | 240 | unsigned char* realnonce; 241 | int realNonceSize = 0; 242 | recovery_get_ap_nonce(_client, &realnonce, &realNonceSize); 243 | 244 | vectornonces; 245 | 246 | if (_client->image4supported) { 247 | for (int i=0; i< _im4ms.size(); i++){ 248 | auto nonce = img4tool::getValFromIM4M({_im4ms[i].first,_im4ms[i].second}, 'BNCH'); 249 | if (nonce.payloadSize() == realNonceSize && memcmp(realnonce, nonce.payload(), realNonceSize) == 0) return _im4ms[i]; 250 | } 251 | }else{ 252 | for (int i=0; i< _im4ms.size(); i++){ 253 | size_t ticketNonceSize = 0; 254 | const char *nonce = NULL; 255 | try { 256 | //nonce might not exist, which we use in re-restoring iOS 9.x for 32-bit 257 | auto n = getNonceFromSCAB(_im4ms[i].first, _im4ms[i].second); 258 | ticketNonceSize = n.second; 259 | nonce = n.first; 260 | } catch (...) { 261 | // 262 | } 263 | if (memcmp(realnonce, nonce, ticketNonceSize) == 0) return _im4ms[i]; 264 | } 265 | } 266 | 267 | return {NULL,0}; 268 | } 269 | 270 | void futurerestore::waitForNonce(vectornonces, size_t nonceSize){ 271 | retassure(_didInit, "did not init\n"); 272 | setAutoboot(false); 273 | 274 | unsigned char* realnonce; 275 | int realNonceSize = 0; 276 | 277 | for (auto nonce : nonces){ 278 | info("waiting for ApNonce: "); 279 | int i = 0; 280 | for (i = 0; i < nonceSize; i++) { 281 | info("%02x ", ((unsigned char *)nonce)[i]); 282 | } 283 | info("\n"); 284 | } 285 | 286 | do { 287 | if (realNonceSize){ 288 | recovery_send_reset(_client); 289 | recovery_client_free(_client); 290 | usleep(1*USEC_PER_SEC); 291 | } 292 | while (getDeviceMode(true) != MODE_RECOVERY) usleep(USEC_PER_SEC*0.5); 293 | retassure(!recovery_client_new(_client), "Could not connect to device in recovery mode\n"); 294 | 295 | recovery_get_ap_nonce(_client, &realnonce, &realNonceSize); 296 | info("Got ApNonce from device: "); 297 | int i = 0; 298 | for (i = 0; i < realNonceSize; i++) { 299 | info("%02x ", realnonce[i]); 300 | } 301 | info("\n"); 302 | for (int i=0; inonces; 316 | 317 | retassure(_client->image4supported, "Error: ApNonce collision function is not supported on 32-bit devices\n"); 318 | 319 | for (auto im4m : _im4ms){ 320 | auto nonce = img4tool::getValFromIM4M({im4m.first,im4m.second}, 'BNCH'); 321 | if (!nonceSize) { 322 | nonceSize = nonce.payloadSize(); 323 | } 324 | retassure(nonceSize == nonce.payloadSize(), "Nonces have different lengths!"); 325 | nonces.push_back((const char*)nonce.payload()); 326 | } 327 | 328 | waitForNonce(nonces,nonceSize); 329 | } 330 | 331 | void futurerestore::loadAPTickets(const vector &apticketPaths){ 332 | for (auto apticketPath : apticketPaths){ 333 | plist_t apticket = NULL; 334 | char *im4m = NULL; 335 | struct stat fst; 336 | 337 | retassure(!stat(apticketPath, &fst), "failed to load APTicket at %s\n",apticketPath); 338 | 339 | gzFile zf = gzopen(apticketPath, "rb"); 340 | if (zf) { 341 | int blen = 0; 342 | int readsize = 16384; //0x4000 343 | int bufsize = readsize; 344 | char* bin = (char*)malloc(bufsize); 345 | char* p = bin; 346 | do { 347 | int bytes_read = gzread(zf, p, readsize); 348 | retassure(bytes_read>0, "Error reading gz compressed data\n"); 349 | blen += bytes_read; 350 | if (bytes_read < readsize) { 351 | if (gzeof(zf)) { 352 | bufsize += bytes_read; 353 | break; 354 | } 355 | } 356 | bufsize += readsize; 357 | bin = (char*)realloc(bin, bufsize); 358 | p = bin + blen; 359 | } while (!gzeof(zf)); 360 | gzclose(zf); 361 | if (blen > 0) { 362 | if (memcmp(bin, "bplist00", 8) == 0) 363 | plist_from_bin(bin, blen, &apticket); 364 | else 365 | plist_from_xml(bin, blen, &apticket); 366 | } 367 | free(bin); 368 | } 369 | 370 | if (_isUpdateInstall) { 371 | if(plist_t update = plist_dict_get_item(apticket, "updateInstall")){ 372 | plist_t cpy = plist_copy(update); 373 | plist_free(apticket); 374 | apticket = cpy; 375 | } 376 | } 377 | 378 | plist_t ticket = plist_dict_get_item(apticket, (_client->image4supported) ? "ApImg4Ticket" : "APTicket"); 379 | uint64_t im4msize=0; 380 | plist_get_data_val(ticket, &im4m, &im4msize); 381 | 382 | retassure(im4msize, "Error: failed to load signing ticket file %s\n",apticketPath); 383 | 384 | _im4ms.push_back({im4m,im4msize}); 385 | _aptickets.push_back(apticket); 386 | printf("reading signing ticket %s is done\n",apticketPath); 387 | } 388 | } 389 | 390 | uint64_t futurerestore::getBasebandGoldCertIDFromDevice(){ 391 | if (!_client->preflight_info){ 392 | if (normal_get_preflight_info(_client, &_client->preflight_info) == -1){ 393 | printf("[WARNING] failed to read BasebandGoldCertID from device! Is it already in recovery?\n"); 394 | return 0; 395 | } 396 | } 397 | plist_t node; 398 | node = plist_dict_get_item(_client->preflight_info, "CertID"); 399 | if (!node || plist_get_node_type(node) != PLIST_UINT) { 400 | error("Unable to find required BbGoldCertId in parameters\n"); 401 | return 0; 402 | } 403 | uint64_t val = 0; 404 | plist_get_uint_val(node, &val); 405 | return val; 406 | } 407 | 408 | char *futurerestore::getiBootBuild(){ 409 | if (!_ibootBuild){ 410 | if (_client->recovery == NULL) { 411 | retassure(!recovery_client_new(_client), "Error: can't create new recovery client"); 412 | } 413 | irecv_getenv(_client->recovery->client, "build-version", &_ibootBuild); 414 | retassure(_ibootBuild, "Error: can't get a build-version"); 415 | } 416 | return _ibootBuild; 417 | } 418 | 419 | pair, size_t> getIPSWComponent(struct idevicerestore_client_t* client, plist_t build_identity, string component){ 420 | ptr_smart path; 421 | unsigned char* component_data = NULL; 422 | unsigned int component_size = 0; 423 | 424 | if (!(char*)path) { 425 | retassure(!build_identity_get_component_path(build_identity, component.c_str(), &path),"ERROR: Unable to get path for component '%s'\n", component.c_str()); 426 | } 427 | 428 | retassure(!extract_component(client->ipsw, (char*)path, &component_data, &component_size),"ERROR: Unable to extract component: %s\n", component.c_str()); 429 | 430 | return {(char*)component_data,component_size}; 431 | } 432 | 433 | void futurerestore::enterPwnRecovery(plist_t build_identity, string bootargs){ 434 | #ifndef HAVE_LIBIPATCHER 435 | reterror("compiled without libipatcher"); 436 | #else 437 | if (_client->image4supported) { 438 | retassure(libipatcher::has64bitSupport(), "libipatcher was compiled without 64-bit support"); 439 | std::string generator = getGeneratorFromSHSH2(_client->tss); 440 | retassure(img4tool::isGeneratorValidForIM4M({_im4ms[0].first,_im4ms[0].second}, generator), "generator returned from device is not valid from APTicket"); 441 | } 442 | 443 | int mode = 0; 444 | libipatcher::fw_key iBSSKeys; 445 | libipatcher::fw_key iBECKeys; 446 | 447 | retassure(!dfu_client_new(_client),"Unable to connect to DFU device\n"); 448 | 449 | irecv_get_mode(_client->dfu->client, &mode); 450 | 451 | try { 452 | iBSSKeys = libipatcher::getFirmwareKey(_client->device->product_type, _client->build, "iBSS"); 453 | iBECKeys = libipatcher::getFirmwareKey(_client->device->product_type, _client->build, "iBEC"); 454 | } catch (tihmstar::exception &e) { 455 | reterror("getting keys failed with error: %d (%s). Are keys publicly available?",e.code(),e.what()); 456 | } 457 | 458 | auto iBSS = getIPSWComponent(_client, build_identity, "iBSS"); 459 | iBSS = move(libipatcher::patchiBSS((char*)iBSS.first, iBSS.second, iBSSKeys)); 460 | 461 | auto iBEC = getIPSWComponent(_client, build_identity, "iBEC"); 462 | iBEC = move(libipatcher::patchiBEC((char*)iBEC.first, iBEC.second, iBECKeys, bootargs)); 463 | 464 | if (_client->image4supported) { 465 | /* if this is 64-bit, we need to back IM4P to IMG4 466 | also due to the nature of iBoot64Patchers sigpatches we need to stich a valid signed im4m to it (but nonce is ignored) */ 467 | iBSS = move(libipatcher::packIM4PToIMG4(iBSS.first, iBSS.second, _im4ms[0].first, _im4ms[0].second)); 468 | iBEC = move(libipatcher::packIM4PToIMG4(iBEC.first, iBEC.second, _im4ms[0].first, _im4ms[0].second)); 469 | } 470 | 471 | bool modeIsRecovery = false; 472 | if (mode != IRECV_K_DFU_MODE) { 473 | info("NOTE: device is not in DFU mode, assuming pwn recovery mode.\n"); 474 | for (int i=IRECV_K_RECOVERY_MODE_1; i<=IRECV_K_RECOVERY_MODE_4; i++) { 475 | if (mode == i) 476 | modeIsRecovery = true; 477 | } 478 | retassure(modeIsRecovery, "device is not in recovery mode\n"); 479 | }else{ 480 | info("Sending %s (%lu bytes)...\n", "iBSS", iBSS.second); 481 | mutex_lock(&_client->device_event_mutex); 482 | irecv_error_t err = irecv_send_buffer(_client->dfu->client, (unsigned char*)(char*)iBSS.first, (unsigned long)iBSS.second, 1); 483 | retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBSS", irecv_strerror(err)); 484 | 485 | /* reconnect */ 486 | dfu_client_free(_client); 487 | 488 | debug("Waiting for device to disconnect...\n"); 489 | cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); 490 | 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"); 491 | mutex_unlock(&_client->device_event_mutex); 492 | 493 | debug("Waiting for device to reconnect...\n"); 494 | mutex_lock(&_client->device_event_mutex); 495 | cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); 496 | 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"); 497 | mutex_unlock(&_client->device_event_mutex); 498 | 499 | dfu_client_new(_client); 500 | } 501 | 502 | if (_client->build_major > 8) { 503 | retassure(!irecv_usb_set_configuration(_client->dfu->client, 1),"ERROR: set configuration failed\n"); 504 | /* send iBEC */ 505 | info("Sending %s (%lu bytes)...\n", "iBEC", iBEC.second); 506 | mutex_lock(&_client->device_event_mutex); 507 | irecv_error_t err = irecv_send_buffer(_client->dfu->client, (unsigned char*)(char*)iBEC.first, (unsigned long)iBEC.second, 1); 508 | retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBEC", irecv_strerror(err)); 509 | printf("waiting for device to reconnect...\n"); 510 | if (modeIsRecovery){ 511 | irecv_send_command(_client->dfu->client, "go"); 512 | recovery_client_free(_client); 513 | }else{ 514 | dfu_client_free(_client); 515 | } 516 | 517 | debug("Waiting for device to disconnect...\n"); 518 | cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); 519 | 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"); 520 | mutex_unlock(&_client->device_event_mutex); 521 | } 522 | 523 | debug("Waiting for device to reconnect...\n"); 524 | mutex_lock(&_client->device_event_mutex); 525 | cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); 526 | 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"); 527 | mutex_unlock(&_client->device_event_mutex); 528 | 529 | // Reconnect to device, but this time make sure we're not still in DFU mode 530 | if (recovery_client_new(_client) < 0) { 531 | if (_client->recovery->client) { 532 | irecv_close(_client->recovery->client); 533 | _client->recovery->client = NULL; 534 | } 535 | reterror("ERROR: Unable to connect to recovery device\n"); 536 | } 537 | 538 | if (_client->image4supported) { 539 | char *deviceGen = NULL; 540 | cleanup([&]{ 541 | safeFree(deviceGen); 542 | }); 543 | /* IMG4 requires to have a generator set for the device to successfully boot after restore 544 | set generator now and make sure the nonce is the one we are trying to restore */ 545 | 546 | assure(!irecv_send_command(_client->recovery->client, "bgcolor 255 0 0")); 547 | sleep(2); //yes, I like displaying colored screens to the user and making him wait for no reason :P 548 | 549 | auto nonceelem = img4tool::getValFromIM4M({_im4ms[0].first,_im4ms[0].second}, 'BNCH'); 550 | 551 | printf("ApNonce pre-hax:\n"); 552 | get_ap_nonce(_client, &_client->nonce, &_client->nonce_size); 553 | std::string generator = getGeneratorFromSHSH2(_client->tss); 554 | 555 | if (memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) != 0) { 556 | printf("ApNonce from device doesn't match IM4M nonce, applying hax...\n"); 557 | 558 | assure(_client->tss); 559 | printf("Writing generator=%s to nvram!\n",generator.c_str()); 560 | 561 | retassure(!irecv_setenv(_client->recovery->client, "com.apple.System.boot-nonce", generator.c_str()),"failed to write generator to nvram"); 562 | retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram"); 563 | 564 | /* send iBEC */ 565 | info("Sending %s (%lu bytes)...\n", "iBEC", iBEC.second); 566 | mutex_lock(&_client->device_event_mutex); 567 | irecv_error_t err = irecv_send_buffer(_client->recovery->client, (unsigned char*)(char*)iBEC.first, (unsigned long)iBEC.second, 1); 568 | retassure(err == IRECV_E_SUCCESS,"ERROR: Unable to send %s component: %s\n", "iBEC", irecv_strerror(err)); 569 | printf("waiting for device to reconnect...\n"); 570 | retassure(!irecv_send_command(_client->recovery->client, "go"),"failed to re-launch iBEC after ApNonce hax"); 571 | recovery_client_free(_client); 572 | 573 | debug("Waiting for device to disconnect...\n"); 574 | cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); 575 | 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"); 576 | mutex_unlock(&_client->device_event_mutex); 577 | 578 | debug("Waiting for device to reconnect...\n"); 579 | mutex_lock(&_client->device_event_mutex); 580 | cond_wait_timeout(&_client->device_event_cond, &_client->device_event_mutex, 10000); 581 | 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"); 582 | mutex_unlock(&_client->device_event_mutex); 583 | 584 | retassure(!recovery_client_new(_client), "failed to reconnect to recovery after ApNonce hax"); 585 | 586 | printf("APnonce post-hax:\n"); 587 | get_ap_nonce(_client, &_client->nonce, &_client->nonce_size); 588 | assure(!irecv_send_command(_client->recovery->client, "bgcolor 255 255 0")); 589 | retassure(memcmp(_client->nonce, nonceelem.payload(), _client->nonce_size) == 0, "ApNonce from device doesn't match IM4M nonce after applying ApNonce hax. Aborting!"); 590 | }else{ 591 | printf("APNonce from device already matches IM4M nonce, no need for extra hax...\n"); 592 | } 593 | retassure(!irecv_setenv(_client->recovery->client, "com.apple.System.boot-nonce", generator.c_str()),"failed to write generator to nvram"); 594 | retassure(!irecv_saveenv(_client->recovery->client), "failed to save nvram"); 595 | 596 | sleep(2); //yes, I like displaying colored screens to the user and making him wait for no reason :P 597 | } 598 | 599 | #endif //HAVE_LIBIPATCHER 600 | } 601 | 602 | void get_custom_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component, unsigned char** data, unsigned int *size){ 603 | #ifndef HAVE_LIBIPATCHER 604 | reterror("compiled without libipatcher"); 605 | #else 606 | try { 607 | auto comp = getIPSWComponent(client, build_identity, component); 608 | comp = move(libipatcher::decryptFile3((char*)comp.first, comp.second, libipatcher::getFirmwareKey(client->device->product_type, client->build, component))); 609 | *data = (unsigned char*)(char*)comp.first; 610 | *size = comp.second; 611 | comp.first = NULL; //don't free on destruction 612 | } catch (tihmstar::exception &e) { 613 | reterror("ERROR: libipatcher failed with reason %d (%s)\n",e.code(),e.what()); 614 | } 615 | 616 | #endif 617 | } 618 | 619 | void futurerestore::doRestore(const char *ipsw){ 620 | plist_t buildmanifest = NULL; 621 | int delete_fs = 0; 622 | char* filesystem = NULL; 623 | cleanup([&]{ 624 | info("Cleaning up...\n"); 625 | safeFreeCustom(buildmanifest, plist_free); 626 | if (delete_fs && filesystem) unlink(filesystem); 627 | }); 628 | struct idevicerestore_client_t* client = _client; 629 | plist_t build_identity = NULL; 630 | plist_t sep_build_identity = NULL; 631 | 632 | client->ipsw = strdup(ipsw); 633 | if (!_isUpdateInstall) client->flags |= FLAG_ERASE; 634 | 635 | irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client); 636 | idevice_event_subscribe(idevice_event_cb, client); 637 | client->idevice_e_ctx = (void*)idevice_event_cb; 638 | 639 | mutex_lock(&client->device_event_mutex); 640 | cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); 641 | 642 | retassure(client->mode != &idevicerestore_modes[MODE_UNKNOWN], "Unable to discover device mode. Please make sure a device is attached.\n"); 643 | if (client->mode != &idevicerestore_modes[MODE_RECOVERY]) { 644 | retassure(client->mode == &idevicerestore_modes[MODE_DFU], "Device is in unexpected mode detected!"); 645 | retassure(_enterPwnRecoveryRequested, "Device is in DFU mode detected, but we were expecting recovery mode!"); 646 | }else{ 647 | retassure(!_enterPwnRecoveryRequested, "--use-pwndfu was specified, but device found in recovery mode!"); 648 | } 649 | 650 | info("Found device in %s mode\n", client->mode->string); 651 | mutex_unlock(&client->device_event_mutex); 652 | 653 | info("Identified device as %s, %s\n", getDeviceBoardNoCopy(), getDeviceModelNoCopy()); 654 | 655 | retassure(!access(client->ipsw, F_OK),"ERROR: Firmware file %s does not exist.\n", client->ipsw); // verify if ipsw file exists 656 | 657 | info("Extracting BuildManifest from iPSW\n"); 658 | { 659 | int unused; 660 | retassure(!ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &unused),"ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw); 661 | } 662 | 663 | /* check if device type is supported by the given build manifest */ 664 | 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"); 665 | 666 | /* print iOS information from the manifest */ 667 | build_manifest_get_version_information(buildmanifest, client); 668 | info("Product version: %s\n", client->version); 669 | info("Product build: %s Major: %d\n", client->build, client->build_major); 670 | client->image4supported = is_image4_supported(client); 671 | info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); 672 | 673 | if (_enterPwnRecoveryRequested) //we are in pwnDFU, so we don't need to check nonces 674 | client->tss = _aptickets.at(0); 675 | else if (!(client->tss = nonceMatchesApTickets())) 676 | reterror("Device ApNonce does not match APTicket nonce\n"); 677 | 678 | plist_dict_remove_item(client->tss, "BBTicket"); 679 | plist_dict_remove_item(client->tss, "BasebandFirmware"); 680 | 681 | if (_enterPwnRecoveryRequested && _client->image4supported) { 682 | 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"); 683 | } 684 | 685 | retassure(build_identity = getBuildidentityWithBoardconfig(buildmanifest, client->device->hardware_model, _isUpdateInstall),"ERROR: Unable to find any build identities for iPSW\n"); 686 | 687 | if (_client->image4supported) { 688 | if (!(sep_build_identity = getBuildidentityWithBoardconfig(_sepbuildmanifest, client->device->hardware_model, _isUpdateInstall))){ 689 | retassure(_isPwnDfu, "ERROR: Unable to find any build identities for SEP\n"); 690 | 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")); 691 | retassure((sep_build_identity = getBuildidentityWithBoardconfig(_sepbuildmanifest, client->device->hardware_model, !_isUpdateInstall)), 692 | "ERROR: Unable to find any build identities for SEP\n"); 693 | } 694 | } 695 | 696 | plist_t manifest = plist_dict_get_item(build_identity, "Manifest"); //this is the buildidentity used for restore 697 | 698 | 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. 699 | auto im4m = (_enterPwnRecoveryRequested || _rerestoreiOS9) ? _im4ms.at(0) : nonceMatchesIM4Ms(); 700 | 701 | uint64_t deviceEcid = getDeviceEcid(); 702 | uint64_t im4mEcid = 0; 703 | if (_client->image4supported) { 704 | auto ecid = img4tool::getValFromIM4M({im4m.first,im4m.second}, 'ECID'); 705 | im4mEcid = ecid.getIntegerValue(); 706 | }else{ 707 | im4mEcid = getEcidFromSCAB(im4m.first, im4m.second); 708 | } 709 | 710 | retassure(im4mEcid, "Failed to read ECID from APTicket\n"); 711 | 712 | if (im4mEcid != deviceEcid) { 713 | error("ECID inside APTicket does not match device ECID\n"); 714 | printf("APTicket is valid for %16llu (dec) but device is %16llu (dec)\n",im4mEcid,deviceEcid); 715 | reterror("APTicket can't be used for restoring this device\n"); 716 | }else 717 | printf("Verified ECID in APTicket matches device ECID\n"); 718 | 719 | if (_client->image4supported) { 720 | printf("checking APTicket to be valid for this restore...\n"); 721 | uint64_t deviceEcid = getDeviceEcid(); 722 | 723 | if (im4mEcid != deviceEcid) { 724 | error("ECID inside APTicket does not match device ECID\n"); 725 | printf("APTicket is valid for %16llu (dec) but device is %16llu (dec)\n",im4mEcid,deviceEcid); 726 | reterror("APTicket can't be used for restoring this device\n"); 727 | }else 728 | printf("Verified ECID in APTicket matches device ECID\n"); 729 | 730 | plist_t ticketIdentity = NULL; 731 | 732 | try { 733 | ticketIdentity = img4tool::getBuildIdentityForIm4m({im4m.first,im4m.second}, buildmanifest); 734 | } catch (tihmstar::exception &e) { 735 | // 736 | } 737 | 738 | if (!ticketIdentity) { 739 | printf("Failed to get exact match for build identity, using fallback to ignore certain values\n"); 740 | ticketIdentity = img4tool::getBuildIdentityForIm4m({im4m.first,im4m.second}, buildmanifest, {"RestoreRamDisk","RestoreTrustCache"}); 741 | } 742 | 743 | /* TODO: make this nicer! 744 | for now a simple pointercompare should be fine, because both plist_t should point into the same buildidentity inside the buildmanifest */ 745 | if (ticketIdentity != build_identity ){ 746 | error("BuildIdentity selected for restore does not match APTicket\n\n"); 747 | printf("BuildIdentity selected for restore:\n"); 748 | img4tool::printGeneralBuildIdentityInformation(build_identity); 749 | printf("\nBuildIdentity is valid for the APTicket:\n"); 750 | 751 | if (ticketIdentity) img4tool::printGeneralBuildIdentityInformation(ticketIdentity),putchar('\n'); 752 | else{ 753 | printf("IM4M is not valid for any restore within the Buildmanifest\n"); 754 | printf("This APTicket can't be used for restoring this firmware\n"); 755 | } 756 | reterror("APTicket can't be used for this restore\n"); 757 | }else{ 758 | if (!img4tool::isIM4MSignatureValid({im4m.first,im4m.second})){ 759 | printf("IM4M signature is not valid!\n"); 760 | reterror("APTicket can't be used for this restore\n"); 761 | } 762 | printf("Verified APTicket to be valid for this restore\n"); 763 | } 764 | }else if (_enterPwnRecoveryRequested){ 765 | info("[WARNING] skipping ramdisk hash check, since device is in pwnDFU according to user\n"); 766 | 767 | }else{ 768 | info("[WARNING] full buildidentity check is not implemented, only comparing ramdisk hash.\n"); 769 | 770 | auto ticket = getRamdiskHashFromSCAB(im4m.first, im4m.second); 771 | const char *tickethash = ticket.first; 772 | size_t tickethashSize = ticket.second; 773 | 774 | uint64_t manifestDigestSize = 0; 775 | char *manifestDigest = NULL; 776 | 777 | plist_t restoreRamdisk = plist_dict_get_item(manifest, "RestoreRamDisk"); 778 | plist_t digest = plist_dict_get_item(restoreRamdisk, "Digest"); 779 | 780 | plist_get_data_val(digest, &manifestDigest, &manifestDigestSize); 781 | 782 | if (tickethashSize == manifestDigestSize && memcmp(tickethash, manifestDigest, tickethashSize) == 0){ 783 | printf("Verified APTicket to be valid for this restore\n"); 784 | free(manifestDigest); 785 | }else{ 786 | free(manifestDigest); 787 | printf("APTicket ramdisk hash does not match the ramdisk we are trying to boot. Are you using correct install type (Update/Erase)?\n"); 788 | reterror("APTicket can't be used for this restore\n"); 789 | } 790 | } 791 | 792 | if (_basebandbuildmanifest){ 793 | if (!(client->basebandBuildIdentity = getBuildidentityWithBoardconfig(_basebandbuildmanifest, client->device->hardware_model, _isUpdateInstall))){ 794 | retassure(client->basebandBuildIdentity = getBuildidentityWithBoardconfig(_basebandbuildmanifest, client->device->hardware_model, !_isUpdateInstall), "ERROR: Unable to find any build identities for Baseband\n"); 795 | info("[WARNING] Unable to find Baseband buildidentities for restore type %s, using fallback %s\n", (_isUpdateInstall) ? "Update" : "Erase",(!_isUpdateInstall) ? "Update" : "Erase"); 796 | } 797 | 798 | client->bbfwtmp = (char*)_basebandPath; 799 | 800 | plist_t bb_manifest = plist_dict_get_item(client->basebandBuildIdentity, "Manifest"); 801 | plist_t bb_baseband = plist_copy(plist_dict_get_item(bb_manifest, "BasebandFirmware")); 802 | plist_dict_set_item(manifest, "BasebandFirmware", bb_baseband); 803 | 804 | retassure(_client->basebandBuildIdentity, "BasebandBuildIdentity not loaded, refusing to continue"); 805 | }else{ 806 | warning("WARNING: we don't have a basebandbuildmanifest, does not flashing baseband!\n"); 807 | } 808 | 809 | if (_client->image4supported) { 810 | //check SEP 811 | plist_t sep_manifest = plist_dict_get_item(sep_build_identity, "Manifest"); 812 | plist_t sep_sep = plist_copy(plist_dict_get_item(sep_manifest, "SEP")); 813 | plist_dict_set_item(manifest, "SEP", sep_sep); 814 | unsigned char genHash[48]; //SHA384 digest length 815 | ptr_smartsephash = NULL; 816 | uint64_t sephashlen = 0; 817 | plist_t digest = plist_dict_get_item(sep_sep, "Digest"); 818 | 819 | retassure(digest && plist_get_node_type(digest) == PLIST_DATA, "ERROR: can't find SEP digest\n"); 820 | 821 | plist_get_data_val(digest, reinterpret_cast(&sephash), &sephashlen); 822 | 823 | if (sephashlen == 20) 824 | SHA1((unsigned char*)_client->sepfwdata, (unsigned int)_client->sepfwdatasize, genHash); 825 | else 826 | SHA384((unsigned char*)_client->sepfwdata, (unsigned int)_client->sepfwdatasize, genHash); 827 | retassure(!memcmp(genHash, sephash, sephashlen), "ERROR: SEP does not match sepmanifest\n"); 828 | } 829 | 830 | build_identity_print_information(build_identity); // print information about current build identity 831 | 832 | //check for enterpwnrecovery, because we could be in DFU mode 833 | if (_enterPwnRecoveryRequested){ 834 | retassure(getDeviceMode(true) == MODE_DFU, "unexpected device mode\n"); 835 | enterPwnRecovery(build_identity); 836 | } 837 | 838 | // Get filesystem name from build identity 839 | char* fsname = NULL; 840 | retassure(!build_identity_get_component_path(build_identity, "OS", &fsname), "ERROR: Unable to get path for filesystem component\n"); 841 | 842 | // check if we already have an extracted filesystem 843 | struct stat st; 844 | memset(&st, '\0', sizeof(struct stat)); 845 | char tmpf[1024]; 846 | if (client->cache_dir) { 847 | if (stat(client->cache_dir, &st) < 0) { 848 | mkdir_with_parents(client->cache_dir, 0755); 849 | } 850 | strcpy(tmpf, client->cache_dir); 851 | strcat(tmpf, "/"); 852 | char *ipswtmp = strdup(client->ipsw); 853 | strcat(tmpf, basename(ipswtmp)); 854 | free(ipswtmp); 855 | } else { 856 | strcpy(tmpf, client->ipsw); 857 | } 858 | char* p = strrchr(tmpf, '.'); 859 | if (p) { 860 | *p = '\0'; 861 | } 862 | 863 | if (stat(tmpf, &st) < 0) { 864 | __mkdir(tmpf, 0755); 865 | } 866 | strcat(tmpf, "/"); 867 | strcat(tmpf, fsname); 868 | 869 | memset(&st, '\0', sizeof(struct stat)); 870 | if (stat(tmpf, &st) == 0) { 871 | off_t fssize = 0; 872 | ipsw_get_file_size(client->ipsw, fsname, (uint64_t*)&fssize); 873 | if ((fssize > 0) && (st.st_size == fssize)) { 874 | info("Using cached filesystem from '%s'\n", tmpf); 875 | filesystem = strdup(tmpf); 876 | } 877 | } 878 | 879 | if (!filesystem) { 880 | char extfn[1024]; 881 | strcpy(extfn, tmpf); 882 | strcat(extfn, ".extract"); 883 | char lockfn[1024]; 884 | strcpy(lockfn, tmpf); 885 | strcat(lockfn, ".lock"); 886 | lock_info_t li; 887 | 888 | lock_file(lockfn, &li); 889 | FILE* extf = NULL; 890 | if (access(extfn, F_OK) != 0) { 891 | extf = fopen(extfn, "w"); 892 | } 893 | unlock_file(&li); 894 | if (!extf) { 895 | // use temp filename 896 | filesystem = tempnam(NULL, "ipsw_"); 897 | if (!filesystem) { 898 | error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname); 899 | filesystem = strdup(fsname); 900 | } 901 | delete_fs = 1; 902 | } else { 903 | // use .extract as filename 904 | filesystem = strdup(extfn); 905 | fclose(extf); 906 | } 907 | remove(lockfn); 908 | 909 | info("Extracting filesystem from iPSW\n"); 910 | retassure(!ipsw_extract_to_file_with_progress(client->ipsw, fsname, filesystem, 1),"ERROR: Unable to extract filesystem from iPSW\n"); 911 | 912 | // rename .extract to 913 | if (strstr(filesystem, ".extract")) { 914 | remove(tmpf); 915 | rename(filesystem, tmpf); 916 | free(filesystem); 917 | filesystem = strdup(tmpf); 918 | } 919 | } 920 | 921 | if (_rerestoreiOS9) { 922 | mutex_lock(&_client->device_event_mutex); 923 | if (dfu_send_component(client, build_identity, "iBSS") < 0) { 924 | irecv_close(client->dfu->client); 925 | client->dfu->client = NULL; 926 | reterror("ERROR: Unable to send iBSS to device\n"); 927 | } 928 | 929 | /* reconnect */ 930 | dfu_client_free(client); 931 | 932 | debug("Waiting for device to disconnect...\n"); 933 | cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); 934 | 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"); 935 | mutex_unlock(&client->device_event_mutex); 936 | 937 | debug("Waiting for device to reconnect...\n"); 938 | mutex_lock(&_client->device_event_mutex); 939 | cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); 940 | 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"); 941 | mutex_unlock(&client->device_event_mutex); 942 | 943 | dfu_client_new(client); 944 | 945 | /* send iBEC */ 946 | if (dfu_send_component(client, build_identity, "iBEC") < 0) { 947 | irecv_close(client->dfu->client); 948 | client->dfu->client = NULL; 949 | reterror("ERROR: Unable to send iBEC to device\n"); 950 | } 951 | 952 | dfu_client_free(client); 953 | 954 | debug("Waiting for device to disconnect...\n"); 955 | mutex_lock(&_client->device_event_mutex); 956 | cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); 957 | 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"); 958 | mutex_unlock(&client->device_event_mutex); 959 | 960 | debug("Waiting for device to reconnect...\n"); 961 | mutex_lock(&_client->device_event_mutex); 962 | cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); 963 | 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"); 964 | mutex_unlock(&client->device_event_mutex); 965 | 966 | }else{ 967 | if ((client->build_major > 8)) { 968 | if (!client->image4supported) { 969 | /* send APTicket */ 970 | if (recovery_send_ticket(client) < 0) { 971 | error("WARNING: Unable to send APTicket\n"); 972 | } 973 | } 974 | } 975 | } 976 | 977 | if (_enterPwnRecoveryRequested){ 978 | if (!_client->image4supported) { 979 | if (strncmp(client->version, "10.", 3))//if pwnrecovery send all components decrypted, unless we're dealing with iOS 10 980 | client->recovery_custom_component_function = get_custom_component; 981 | } 982 | }else if (!_rerestoreiOS9){ 983 | /* now we load the iBEC */ 984 | retassure(!recovery_send_ibec(client, build_identity),"ERROR: Unable to send iBEC\n"); 985 | 986 | printf("waiting for device to reconnect... "); 987 | recovery_client_free(client); 988 | 989 | debug("Waiting for device to disconnect...\n"); 990 | mutex_unlock(&client->device_event_mutex); 991 | cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); 992 | 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"); 993 | mutex_unlock(&client->device_event_mutex); 994 | 995 | debug("Waiting for device to reconnect...\n"); 996 | mutex_unlock(&client->device_event_mutex); 997 | cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); 998 | 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"); 999 | mutex_unlock(&client->device_event_mutex); 1000 | } 1001 | 1002 | retassure(client->mode == &idevicerestore_modes[MODE_RECOVERY], "failed to reconnect to device in recovery (iBEC) mode\n"); 1003 | 1004 | //do magic 1005 | if (_client->image4supported) get_sep_nonce(client, &client->sepnonce, &client->sepnonce_size); 1006 | get_ap_nonce(client, &client->nonce, &client->nonce_size); 1007 | get_ecid(client, &client->ecid); 1008 | 1009 | if (client->mode->index == MODE_RECOVERY) { 1010 | retassure(client->srnm,"ERROR: could not retrieve device serial number. Can't continue.\n"); 1011 | 1012 | retassure(!irecv_send_command(client->recovery->client, "bgcolor 0 255 0"), "ERROR: Unable to set bgcolor\n"); 1013 | info("[WARNING] Setting bgcolor to green! If you don't see a green screen, then your device didn't boot iBEC correctly\n"); 1014 | sleep(2); //show the user a green screen! 1015 | 1016 | retassure(!recovery_enter_restore(client, build_identity),"ERROR: Unable to place device into restore mode\n"); 1017 | 1018 | recovery_client_free(client); 1019 | } 1020 | 1021 | if (_client->image4supported) { 1022 | info("getting SEP ticket\n"); 1023 | retassure(!get_tss_response(client, sep_build_identity, &client->septss), "ERROR: Unable to get signing tickets for SEP\n"); 1024 | retassure(_client->sepfwdatasize && _client->sepfwdata, "SEP is not loaded, refusing to continue"); 1025 | } 1026 | 1027 | mutex_lock(&client->device_event_mutex); 1028 | debug("Waiting for device to enter restore mode...\n"); 1029 | cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 180000); 1030 | retassure((client->mode == &idevicerestore_modes[MODE_RESTORE] || (mutex_unlock(&client->device_event_mutex),0)), "Device can't enter to restore mode"); 1031 | mutex_unlock(&client->device_event_mutex); 1032 | 1033 | info("About to restore device... \n"); 1034 | int result = 0; 1035 | retassure(!(result = restore_device(client, build_identity, filesystem)), "ERROR: Unable to restore device\n"); 1036 | } 1037 | 1038 | int futurerestore::doJustBoot(const char *ipsw, string bootargs){ 1039 | reterror("not implemented"); 1040 | // int err = 0; 1041 | // //some memory might not get freed if this function throws an exception, but you probably don't want to catch that anyway. 1042 | // 1043 | // struct idevicerestore_client_t* client = _client; 1044 | // int unused; 1045 | // int result = 0; 1046 | // plist_t buildmanifest = NULL; 1047 | // plist_t build_identity = NULL; 1048 | // 1049 | // client->ipsw = strdup(ipsw); 1050 | // 1051 | // getDeviceMode(true); 1052 | // info("Found device in %s mode\n", client->mode->string); 1053 | // 1054 | // retassure((client->mode->index == MODE_DFU || client->mode->index == MODE_RECOVERY) && _enterPwnRecoveryRequested, "device not in DFU/Recovery mode\n"); 1055 | // 1056 | // // discover the device type 1057 | // retassure(check_hardware_model(client) && client->device,"ERROR: Unable to discover device model\n"); 1058 | // info("Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type); 1059 | // 1060 | // // verify if ipsw file exists 1061 | // retassure(!access(client->ipsw, F_OK), "ERROR: Firmware file %s does not exist.\n", client->ipsw); 1062 | // info("Extracting BuildManifest from IPSW\n"); 1063 | // 1064 | // retassure(!ipsw_extract_build_manifest(client->ipsw, &buildmanifest, &unused),"ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw); 1065 | // 1066 | // /* check if device type is supported by the given build manifest */ 1067 | // 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"); 1068 | // 1069 | // /* print iOS information from the manifest */ 1070 | // build_manifest_get_version_information(buildmanifest, client); 1071 | // 1072 | // info("Product Version: %s\n", client->version); 1073 | // info("Product Build: %s Major: %d\n", client->build, client->build_major); 1074 | // 1075 | // client->image4supported = is_image4_supported(client); 1076 | // info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); 1077 | // 1078 | // retassure(build_identity = getBuildidentityWithBoardconfig(buildmanifest, client->device->hardware_model, 0),"ERROR: Unable to find any build identities for IPSW\n"); 1079 | // 1080 | // /* print information about current build identity */ 1081 | // build_identity_print_information(build_identity); 1082 | // 1083 | // //check for enterpwnrecovery, because we could be in DFU mode 1084 | // retassure(_enterPwnRecoveryRequested, "enterPwnRecoveryRequested is not set, but required"); 1085 | // 1086 | // retassure(getDeviceMode(true) == MODE_DFU || getDeviceMode(false) == MODE_RECOVERY, "unexpected device mode\n"); 1087 | // 1088 | // enterPwnRecovery(build_identity, bootargs); 1089 | // 1090 | // client->recovery_custom_component_function = get_custom_component; 1091 | // 1092 | // for (int i=0;getDeviceMode(true) != MODE_RECOVERY && i<40; i++) putchar('.'),usleep(USEC_PER_SEC*0.5); 1093 | // putchar('\n'); 1094 | // 1095 | // retassure(check_mode(client), "failed to reconnect to device in recovery (iBEC) mode\n"); 1096 | // 1097 | // get_ecid(client, &client->ecid); 1098 | // 1099 | // client->flags |= FLAG_BOOT; 1100 | // 1101 | // if (client->mode->index == MODE_RECOVERY) { 1102 | // retassure(client->srnm,"ERROR: could not retrieve device serial number. Can't continue.\n"); 1103 | // 1104 | // retassure(!irecv_send_command(client->recovery->client, "bgcolor 0 255 0"), "ERROR: Unable to set bgcolor\n"); 1105 | // 1106 | // info("[WARNING] Setting bgcolor to green! If you don't see a green screen, then your device didn't boot iBEC correctly\n"); 1107 | // sleep(2); //show the user a green screen! 1108 | // client->image4supported = true; //dirty hack to not require apticket 1109 | // 1110 | // retassure(!recovery_enter_restore(client, build_identity),"ERROR: Unable to place device into restore mode\n"); 1111 | // 1112 | // client->image4supported = false; 1113 | // recovery_client_free(client); 1114 | // } 1115 | // 1116 | // info("Cleaning up...\n"); 1117 | // 1118 | //error: 1119 | // safeFree(client->sepfwdata); 1120 | // safeFreeCustom(buildmanifest, plist_free); 1121 | // if (!result && !err) info("DONE\n"); 1122 | // return result ? abs(result) : err; 1123 | } 1124 | 1125 | futurerestore::~futurerestore(){ 1126 | recovery_client_free(_client); 1127 | idevicerestore_client_free(_client); 1128 | for (auto im4m : _im4ms){ 1129 | safeFree(im4m.first); 1130 | } 1131 | safeFree(_ibootBuild); 1132 | safeFree(_firmwareJson); 1133 | safeFree(_firmwareTokens); 1134 | safeFree(__latestManifest); 1135 | safeFree(__latestFirmwareUrl); 1136 | for (auto plist : _aptickets){ 1137 | safeFreeCustom(plist, plist_free); 1138 | } 1139 | safeFreeCustom(_sepbuildmanifest, plist_free); 1140 | safeFreeCustom(_basebandbuildmanifest, plist_free); 1141 | } 1142 | 1143 | void futurerestore::loadFirmwareTokens(){ 1144 | if (!_firmwareTokens){ 1145 | if (!_firmwareJson) _firmwareJson = getFirmwareJson(); 1146 | retassure(_firmwareJson,"[TSSC] could not get firmware.json\n"); 1147 | int cnt = parseTokens(_firmwareJson, &_firmwareTokens); 1148 | retassure(cnt>0,"[TSSC] parsing %s.json failed\n",(0) ? "ota" : "firmware"); 1149 | } 1150 | } 1151 | 1152 | const char *futurerestore::getDeviceModelNoCopy(){ 1153 | if (!_client->device || !_client->device->product_type){ 1154 | 1155 | int mode = getDeviceMode(true); 1156 | retassure(mode == MODE_NORMAL || mode == MODE_RECOVERY || mode == MODE_DFU, "unexpected device mode=%d\n",mode); 1157 | 1158 | switch (mode) { 1159 | case MODE_RESTORE: 1160 | _client->device = restore_get_irecv_device(_client); 1161 | break; 1162 | case MODE_NORMAL: 1163 | _client->device = normal_get_irecv_device(_client); 1164 | break; 1165 | case MODE_DFU: 1166 | case MODE_RECOVERY: 1167 | _client->device = dfu_get_irecv_device(_client); 1168 | break; 1169 | default: 1170 | break; 1171 | } 1172 | } 1173 | 1174 | return _client->device->product_type; 1175 | } 1176 | 1177 | const char *futurerestore::getDeviceBoardNoCopy(){ 1178 | if (!_client->device || !_client->device->product_type){ 1179 | 1180 | int mode = getDeviceMode(true); 1181 | retassure(mode == MODE_NORMAL || mode == MODE_RECOVERY || mode == MODE_DFU, "unexpected device mode=%d\n",mode); 1182 | 1183 | switch (mode) { 1184 | case MODE_RESTORE: 1185 | _client->device = restore_get_irecv_device(_client); 1186 | break; 1187 | case MODE_NORMAL: 1188 | _client->device = normal_get_irecv_device(_client); 1189 | break; 1190 | case MODE_DFU: 1191 | case MODE_RECOVERY: 1192 | _client->device = dfu_get_irecv_device(_client); 1193 | break; 1194 | default: 1195 | break; 1196 | } 1197 | } 1198 | return _client->device->hardware_model; 1199 | } 1200 | 1201 | char *futurerestore::getLatestManifest(){ 1202 | if (!__latestManifest){ 1203 | loadFirmwareTokens(); 1204 | 1205 | const char *device = getDeviceModelNoCopy(); 1206 | t_iosVersion versVals; 1207 | memset(&versVals, 0, sizeof(versVals)); 1208 | 1209 | int versionCnt = 0; 1210 | int i = 0; 1211 | char **versions = getListOfiOSForDevice(_firmwareTokens, device, 0, &versionCnt); 1212 | retassure(versionCnt, "[TSSC] failed finding latest firmware version\n"); 1213 | char *bpos = NULL; 1214 | while((bpos = strstr((char*)(versVals.version = strdup(versions[i++])),"[B]")) != 0){ 1215 | free((char*)versVals.version); 1216 | if (--versionCnt == 0) reterror("[TSSC] automatic selection of firmware couldn't find for non-beta versions\n"); 1217 | } 1218 | info("[TSSC] selecting latest firmware version: %s\n",versVals.version); 1219 | if (bpos) *bpos= '\0'; 1220 | if (versions) free(versions[versionCnt-1]),free(versions); 1221 | 1222 | ptr_smartautofree(versVals.version); //make sure it get's freed after function finishes execution by either reaching end or throwing exception 1223 | 1224 | __latestFirmwareUrl = getFirmwareUrl(device, &versVals, _firmwareTokens); 1225 | retassure(__latestFirmwareUrl, "could not find url of latest firmware version\n"); 1226 | 1227 | __latestManifest = getBuildManifest(__latestFirmwareUrl, device, versVals.version, versVals.buildID, 0); 1228 | retassure(__latestManifest, "could not get buildmanifest of latest firmware version\n"); 1229 | } 1230 | 1231 | return __latestManifest; 1232 | } 1233 | 1234 | char *futurerestore::getLatestFirmwareUrl(){ 1235 | return getLatestManifest(),__latestFirmwareUrl; 1236 | } 1237 | 1238 | void futurerestore::loadLatestBaseband(){ 1239 | char * manifeststr = getLatestManifest(); 1240 | char *pathStr = getPathOfElementInManifest("BasebandFirmware", manifeststr, getDeviceModelNoCopy(), 0); 1241 | info("downloading Baseband\n\n"); 1242 | retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, _basebandPath = BASEBAND_TMP_PATH), "could not download baseband\n"); 1243 | saveStringToFile(manifeststr, BASEBAND_MANIFEST_TMP_PATH); 1244 | setBasebandManifestPath(BASEBAND_MANIFEST_TMP_PATH); 1245 | setBasebandPath(BASEBAND_TMP_PATH); 1246 | } 1247 | 1248 | void futurerestore::loadLatestSep(){ 1249 | char * manifeststr = getLatestManifest(); 1250 | char *pathStr = getPathOfElementInManifest("SEP", manifeststr, getDeviceModelNoCopy(), 0); 1251 | info("downloading SEP\n\n"); 1252 | retassure(!downloadPartialzip(getLatestFirmwareUrl(), pathStr, SEP_TMP_PATH), "could not download SEP\n"); 1253 | loadSep(SEP_TMP_PATH); 1254 | saveStringToFile(manifeststr, SEP_MANIFEST_TMP_PATH); 1255 | setSepManifestPath(SEP_MANIFEST_TMP_PATH); 1256 | } 1257 | 1258 | void futurerestore::setSepManifestPath(const char *sepManifestPath){ 1259 | retassure(_sepbuildmanifest = loadPlistFromFile(_sepbuildmanifestPath = sepManifestPath), "failed to load SEPManifest"); 1260 | } 1261 | 1262 | void futurerestore::setBasebandManifestPath(const char *basebandManifestPath){ 1263 | retassure(_basebandbuildmanifest = loadPlistFromFile(_basebandbuildmanifestPath = basebandManifestPath), "failed to load BasebandManifest"); 1264 | }; 1265 | 1266 | void futurerestore::loadSep(const char *sepPath){ 1267 | FILE *fsep = NULL; 1268 | retassure(fsep = fopen(sepPath, "rb"), "failed to read SEP\n"); 1269 | 1270 | fseek(fsep, 0, SEEK_END); 1271 | _client->sepfwdatasize = ftell(fsep); 1272 | fseek(fsep, 0, SEEK_SET); 1273 | 1274 | retassure(_client->sepfwdata = (char*)malloc(_client->sepfwdatasize), "failed to malloc memory for SEP\n"); 1275 | 1276 | size_t freadRet=0; 1277 | retassure((freadRet = fread(_client->sepfwdata, 1, _client->sepfwdatasize, fsep)) == _client->sepfwdatasize, 1278 | "failed to load SEP. size=%zu but fread returned %zu\n",_client->sepfwdatasize,freadRet); 1279 | 1280 | fclose(fsep); 1281 | } 1282 | 1283 | void futurerestore::setBasebandPath(const char *basebandPath){ 1284 | FILE *fbb = NULL; 1285 | 1286 | retassure(fbb = fopen(basebandPath, "rb"), "failed to read Baseband"); 1287 | _basebandPath = basebandPath; 1288 | fclose(fbb); 1289 | } 1290 | 1291 | #pragma mark static methods 1292 | inline void futurerestore::saveStringToFile(const char *str, const char *path){ 1293 | FILE *f = NULL; 1294 | retassure(f = fopen(path, "w"), "can't save file at %s\n",path); 1295 | size_t len = strlen(str); 1296 | size_t wlen = fwrite(str, 1, len, f); 1297 | fclose(f); 1298 | retassure(len == wlen, "saving file failed, wrote=%zu actual=%zu\n",wlen,len); 1299 | } 1300 | 1301 | std::pair futurerestore::getNonceFromSCAB(const char* scab, size_t scabSize){ 1302 | retassure(scab, "Got empty SCAB\n"); 1303 | 1304 | img4tool::ASN1DERElement bacs(scab,scabSize); 1305 | 1306 | try { 1307 | bacs[3]; 1308 | } catch (...) { 1309 | reterror("unexpected number of Elements in SCAB sequence (expects 4)\n"); 1310 | } 1311 | 1312 | img4tool::ASN1DERElement mainSet = bacs[1]; 1313 | 1314 | for (auto &elem : mainSet) { 1315 | if (*(uint8_t*)elem.buf() == 0x92) { 1316 | return {(char*)elem.payload(),elem.payloadSize()}; 1317 | } 1318 | } 1319 | reterror("failed to get nonce from SCAB"); 1320 | return {NULL,0}; 1321 | } 1322 | 1323 | uint64_t futurerestore::getEcidFromSCAB(const char* scab, size_t scabSize){ 1324 | retassure(scab, "Got empty SCAB\n"); 1325 | 1326 | img4tool::ASN1DERElement bacs(scab,scabSize); 1327 | 1328 | try { 1329 | bacs[3]; 1330 | } catch (...) { 1331 | reterror("unexpected number of Elements in SCAB sequence (expects 4)\n"); 1332 | } 1333 | 1334 | img4tool::ASN1DERElement mainSet = bacs[1]; 1335 | 1336 | for (auto &elem : mainSet) { 1337 | if (*(uint8_t*)elem.buf() == 0x81) { 1338 | uint64_t ret = 0; 1339 | for (int i=0; ifuturerestore::getRamdiskHashFromSCAB(const char* scab, size_t scabSize){ 1352 | retassure(scab, "Got empty SCAB\n"); 1353 | 1354 | img4tool::ASN1DERElement bacs(scab,scabSize); 1355 | 1356 | try { 1357 | bacs[3]; 1358 | } catch (...) { 1359 | reterror("unexpected number of Elements in SCAB sequence (expects 4)\n"); 1360 | } 1361 | 1362 | img4tool::ASN1DERElement mainSet = bacs[1]; 1363 | 1364 | for (auto &elem : mainSet) { 1365 | if (*(uint8_t*)elem.buf() == 0x9A) { 1366 | return {(char*)elem.payload(),elem.payloadSize()}; 1367 | } 1368 | } 1369 | reterror("failed to get nonce from SCAB"); 1370 | return {NULL,0}; 1371 | } 1372 | 1373 | plist_t futurerestore::loadPlistFromFile(const char *path){ 1374 | plist_t ret = NULL; 1375 | 1376 | FILE *f = fopen(path,"rb"); 1377 | if (!f){ 1378 | error("could not open file %s\n",path); 1379 | return NULL; 1380 | } 1381 | fseek(f, 0, SEEK_END); 1382 | size_t bufSize = ftell(f); 1383 | fseek(f, 0, SEEK_SET); 1384 | 1385 | char *buf = (char*)malloc(bufSize); 1386 | if (!buf){ 1387 | error("failed to alloc memory\n"); 1388 | return NULL; 1389 | } 1390 | 1391 | size_t freadRet = 0; 1392 | if ((freadRet = fread(buf, 1, bufSize, f)) != bufSize){ 1393 | error("fread=%zu but bufsize=%zu",freadRet,bufSize); 1394 | return NULL; 1395 | } 1396 | fclose(f); 1397 | 1398 | if (memcmp(buf, "bplist00", 8) == 0) 1399 | plist_from_bin(buf, (uint32_t)bufSize, &ret); 1400 | else 1401 | plist_from_xml(buf, (uint32_t)bufSize, &ret); 1402 | free(buf); 1403 | 1404 | return ret; 1405 | } 1406 | 1407 | char *futurerestore::getPathOfElementInManifest(const char *element, const char *manifeststr, const char *model, int isUpdateInstall){ 1408 | char *pathStr = NULL; 1409 | ptr_smart buildmanifest(NULL,plist_free); 1410 | 1411 | plist_from_xml(manifeststr, (uint32_t)strlen(manifeststr), &buildmanifest); 1412 | 1413 | if (plist_t identity = getBuildidentity(buildmanifest._p, model, isUpdateInstall)) 1414 | if (plist_t manifest = plist_dict_get_item(identity, "Manifest")) 1415 | if (plist_t elem = plist_dict_get_item(manifest, element)) 1416 | if (plist_t info = plist_dict_get_item(elem, "Info")) 1417 | if (plist_t path = plist_dict_get_item(info, "Path")) 1418 | if (plist_get_string_val(path, &pathStr), pathStr) 1419 | goto noerror; 1420 | 1421 | reterror("could not get %s path\n",element); 1422 | noerror: 1423 | return pathStr; 1424 | } 1425 | 1426 | std::string futurerestore::getGeneratorFromSHSH2(const plist_t shsh2){ 1427 | plist_t pGenerator = NULL; 1428 | uint64_t gen = 0; 1429 | char *genstr = NULL; 1430 | cleanup([&]{ 1431 | safeFree(genstr); 1432 | }); 1433 | retassure(pGenerator = plist_dict_get_item(shsh2, "generator"), "signing ticket file does not contain generator"); 1434 | 1435 | retassure(plist_get_node_type(pGenerator) == PLIST_STRING, "generator has unexpected type! We expect string of the format 0x%16llx"); 1436 | 1437 | plist_get_string_val(pGenerator, &genstr); 1438 | assure(genstr); 1439 | 1440 | sscanf(genstr, "0x%16llx",&gen); 1441 | retassure(gen, "failed to parse generator. Make sure it is in format 0x%16llx"); 1442 | 1443 | return {genstr}; 1444 | } 1445 | -------------------------------------------------------------------------------- /futurerestore/futurerestore.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // futurerestore.hpp 3 | // futurerestore 4 | // 5 | // Created by tihmstar on 14.09.16. 6 | // Copyright © 2016 tihmstar. All rights reserved. 7 | // 8 | 9 | #ifndef futurerestore_hpp 10 | #define futurerestore_hpp 11 | 12 | //make sure WIN32 is defined if compiling for windows 13 | #if defined _WIN32 || defined __CYGWIN__ 14 | #ifndef WIN32 15 | #define WIN32 16 | #endif 17 | #endif 18 | 19 | #include 20 | #include 21 | #include 22 | #include "idevicerestore.h" 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | 28 | template 29 | class ptr_smart { 30 | std::function _ptr_free = NULL; 31 | public: 32 | T _p; 33 | ptr_smart(T p, function ptr_free){static_assert(is_pointer(), "error: this is for pointers only\n"); _p = p;_ptr_free = ptr_free;} 34 | ptr_smart(T p){_p = p;} 35 | ptr_smart(){_p = NULL;} 36 | ptr_smart(ptr_smart &&p){ _p = p._p; _ptr_free = p._ptr_free; p._p = NULL; p._ptr_free = NULL;} 37 | ptr_smart& operator =(ptr_smart &&p){_p = p._p; _ptr_free = p._ptr_free; p._p = NULL; p._ptr_free = NULL; return *this;} 38 | T operator =(T p){ _p = p; return _p;} 39 | T operator =(T &p){_p = p; p = NULL; return _p;} 40 | T *operator&(){return &_p;} 41 | explicit operator const T() const {return _p;} 42 | operator const void*() const {return _p;} 43 | ~ptr_smart(){if (_p) (_ptr_free) ? _ptr_free(_p) : free((void*)_p);} 44 | }; 45 | 46 | class futurerestore { 47 | struct idevicerestore_client_t* _client; 48 | char *_ibootBuild = NULL; 49 | bool _didInit = false; 50 | vector _aptickets; 51 | vector>_im4ms; 52 | int _foundnonce = -1; 53 | bool _isUpdateInstall = false; 54 | bool _isPwnDfu = false; 55 | 56 | char *_firmwareJson = NULL; 57 | jssytok_t *_firmwareTokens = NULL;; 58 | char *__latestManifest = NULL; 59 | char *__latestFirmwareUrl = NULL; 60 | 61 | plist_t _sepbuildmanifest = NULL; 62 | plist_t _basebandbuildmanifest = NULL; 63 | 64 | const char *_basebandPath = NULL;; 65 | const char *_sepbuildmanifestPath = NULL; 66 | const char *_basebandbuildmanifestPath = NULL; 67 | 68 | bool _enterPwnRecoveryRequested = false; 69 | bool _rerestoreiOS9 = false; 70 | //methods 71 | void enterPwnRecovery(plist_t build_identity, std::string bootargs = ""); 72 | 73 | public: 74 | futurerestore(bool isUpdateInstall = false, bool isPwnDfu = false); 75 | bool init(); 76 | int getDeviceMode(bool reRequest); 77 | uint64_t getDeviceEcid(); 78 | void putDeviceIntoRecovery(); 79 | void setAutoboot(bool val); 80 | void exitRecovery(); 81 | void waitForNonce(); 82 | void waitForNonce(vectornonces, size_t nonceSize); 83 | void loadAPTickets(const vector &apticketPaths); 84 | char *getiBootBuild(); 85 | 86 | plist_t nonceMatchesApTickets(); 87 | std::pair nonceMatchesIM4Ms(); 88 | 89 | void loadFirmwareTokens(); 90 | const char *getDeviceModelNoCopy(); 91 | const char *getDeviceBoardNoCopy(); 92 | char *getLatestManifest(); 93 | char *getLatestFirmwareUrl(); 94 | void loadLatestBaseband(); 95 | void loadLatestSep(); 96 | 97 | void setSepManifestPath(const char *sepManifestPath); 98 | void setBasebandManifestPath(const char *basebandManifestPath); 99 | void loadSep(const char *sepPath); 100 | void setBasebandPath(const char *basebandPath); 101 | bool isUpdateInstall(){return _isUpdateInstall;}; 102 | 103 | plist_t sepManifest(){return _sepbuildmanifest;}; 104 | plist_t basebandManifest(){return _basebandbuildmanifest;}; 105 | const char *sepManifestPath(){return _sepbuildmanifestPath;}; 106 | const char *basebandManifestPath(){return _basebandbuildmanifestPath;}; 107 | bool is32bit(){return !is_image4_supported(_client);}; 108 | 109 | uint64_t getBasebandGoldCertIDFromDevice(); 110 | 111 | void doRestore(const char *ipsw); 112 | int doJustBoot(const char *ipsw, std::string bootargs = ""); 113 | 114 | ~futurerestore(); 115 | 116 | static std::pair getRamdiskHashFromSCAB(const char* scab, size_t scabSize); 117 | static std::pair getNonceFromSCAB(const char* scab, size_t scabSize); 118 | static uint64_t getEcidFromSCAB(const char* scab, size_t scabSize); 119 | static plist_t loadPlistFromFile(const char *path); 120 | static void saveStringToFile(const char *str, const char *path); 121 | static char *getPathOfElementInManifest(const char *element, const char *manifeststr, const char *model, int isUpdateInstall); 122 | static std::string getGeneratorFromSHSH2(const plist_t shsh2); 123 | }; 124 | 125 | #endif /* futurerestore_hpp */ 126 | -------------------------------------------------------------------------------- /futurerestore/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // futurerestore 4 | // 5 | // Created by tihmstar on 14.09.16. 6 | // Copyright © 2016 tihmstar. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "futurerestore.hpp" 15 | 16 | extern "C"{ 17 | #include "tsschecker.h" 18 | #undef VERSION_COMMIT_SHA 19 | #undef VERSION_COMMIT_COUNT 20 | }; 21 | 22 | #include 23 | #ifdef HAVE_LIBIPATCHER 24 | #include 25 | #endif 26 | 27 | #ifdef WIN32 28 | #include 29 | #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING 30 | #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 31 | #endif 32 | #endif 33 | 34 | static struct option longopts[] = { 35 | { "apticket", required_argument, NULL, 't' }, 36 | { "baseband", required_argument, NULL, 'b' }, 37 | { "baseband-manifest", required_argument, NULL, 'p' }, 38 | { "sep", required_argument, NULL, 's' }, 39 | { "sep-manifest", required_argument, NULL, 'm' }, 40 | { "wait", no_argument, NULL, 'w' }, 41 | { "update", no_argument, NULL, 'u' }, 42 | { "debug", no_argument, NULL, 'd' }, 43 | { "exit-recovery", no_argument, NULL, 'e' }, 44 | { "latest-sep", no_argument, NULL, '0' }, 45 | { "latest-baseband", no_argument, NULL, '1' }, 46 | { "no-baseband", no_argument, NULL, '2' }, 47 | #ifdef HAVE_LIBIPATCHER 48 | { "use-pwndfu", no_argument, NULL, '3' }, 49 | { "just-boot", optional_argument, NULL, '4' }, 50 | #endif 51 | { NULL, 0, NULL, 0 } 52 | }; 53 | 54 | #define FLAG_WAIT 1 << 0 55 | #define FLAG_UPDATE 1 << 1 56 | #define FLAG_LATEST_SEP 1 << 2 57 | #define FLAG_LATEST_BASEBAND 1 << 3 58 | #define FLAG_NO_BASEBAND 1 << 4 59 | #define FLAG_IS_PWN_DFU 1 << 5 60 | 61 | void cmd_help(){ 62 | printf("Usage: futurerestore [OPTIONS] iPSW\n"); 63 | printf("Allows restoring to non-matching firmware with custom SEP+baseband\n"); 64 | printf("\nGeneral options:\n"); 65 | printf(" -t, --apticket PATH\t\tSigning tickets used for restoring\n"); 66 | printf(" -u, --update\t\t\tUpdate instead of erase install (requires appropriate APTicket)\n"); 67 | printf(" \t\t\tDO NOT use this parameter, if you update from jailbroken firmware!\n"); 68 | printf(" -w, --wait\t\t\tKeep rebooting until ApNonce matches APTicket (ApNonce collision, unreliable)\n"); 69 | printf(" -d, --debug\t\t\tShow all code, use to save a log for debug testing\n"); 70 | printf(" -e, --exit-recovery\t\tExit recovery mode and quit\n"); 71 | 72 | #ifdef HAVE_LIBIPATCHER 73 | printf("\nOptions for downgrading with Odysseus:\n"); 74 | printf(" --use-pwndfu\t\tRestoring devices with Odysseus method. Device needs to be in pwned DFU mode already\n"); 75 | printf(" --just-boot=\"-v\"\t\tTethered booting the device from pwned DFU mode. You can optionally set boot-args\n"); 76 | #endif 77 | 78 | printf("\nOptions for SEP:\n"); 79 | printf(" --latest-sep\t\tUse latest signed SEP instead of manually specifying one (may cause bad restore)\n"); 80 | printf(" -s, --sep PATH\t\tSEP to be flashed\n"); 81 | printf(" -m, --sep-manifest PATH\tBuildManifest for requesting SEP ticket\n"); 82 | 83 | printf("\nOptions for baseband:\n"); 84 | printf(" --latest-baseband\t\tUse latest signed baseband instead of manually specifying one (may cause bad restore)\n"); 85 | printf(" -b, --baseband PATH\t\tBaseband to be flashed\n"); 86 | printf(" -p, --baseband-manifest PATH\tBuildManifest for requesting baseband ticket\n"); 87 | printf(" --no-baseband\t\tSkip checks and don't flash baseband\n"); 88 | printf(" \t\tOnly use this for device without a baseband (eg. iPod touch or some Wi-Fi only iPads)\n\n"); 89 | } 90 | 91 | #ifdef WIN32 92 | DWORD termFlags; 93 | HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); 94 | if (GetConsoleMode(handle, &termFlags)) 95 | SetConsoleMode(handle, termFlags | ENABLE_VIRTUAL_TERMINAL_PROCESSING); 96 | #endif 97 | 98 | using namespace std; 99 | using namespace tihmstar; 100 | int main_r(int argc, const char * argv[]) { 101 | int err=0; 102 | printf("Version: " VERSION_COMMIT_SHA " - " VERSION_COMMIT_COUNT "\n"); 103 | #ifdef HAVE_LIBIPATCHER 104 | printf("%s\n",libipatcher::version()); 105 | printf("Odysseus for 32-bit support: yes\n"); 106 | printf("Odysseus for 64-bit support: %s\n",(libipatcher::has64bitSupport() ? "yes" : "no")); 107 | #else 108 | printf("Odysseus support: no\n"); 109 | #endif 110 | 111 | int optindex = 0; 112 | int opt = 0; 113 | long flags = 0; 114 | bool exitRecovery = false; 115 | 116 | int isSepManifestSigned = 0; 117 | int isBasebandSigned = 0; 118 | 119 | const char *ipsw = NULL; 120 | const char *basebandPath = NULL; 121 | const char *basebandManifestPath = NULL; 122 | const char *sepPath = NULL; 123 | const char *sepManifestPath = NULL; 124 | const char *bootargs = NULL; 125 | 126 | vector apticketPaths; 127 | 128 | t_devicevals devVals = {0}; 129 | t_iosVersion versVals = {0}; 130 | 131 | if (argc == 1){ 132 | cmd_help(); 133 | return -1; 134 | } 135 | 136 | while ((opt = getopt_long(argc, (char* const *)argv, "ht:b:p:s:m:wude0123", longopts, &optindex)) > 0) { 137 | switch (opt) { 138 | case 't': // long option: "apticket"; can be called as short option 139 | apticketPaths.push_back(optarg); 140 | break; 141 | case 'b': // long option: "baseband"; can be called as short option 142 | basebandPath = optarg; 143 | break; 144 | case 'p': // long option: "baseband-manifest"; can be called as short option 145 | basebandManifestPath = optarg; 146 | break; 147 | case 's': // long option: "sep"; can be called as short option 148 | sepPath = optarg; 149 | break; 150 | case 'm': // long option: "sep-manifest"; can be called as short option 151 | sepManifestPath = optarg; 152 | break; 153 | case 'w': // long option: "wait"; can be called as short option 154 | flags |= FLAG_WAIT; 155 | break; 156 | case 'u': // long option: "update"; can be called as short option 157 | flags |= FLAG_UPDATE; 158 | break; 159 | case '0': // long option: "latest-sep"; 160 | flags |= FLAG_LATEST_SEP; 161 | break; 162 | case '1': // long option: "latest-baseband"; 163 | flags |= FLAG_LATEST_BASEBAND; 164 | break; 165 | case '2': // long option: "no-baseband"; 166 | flags |= FLAG_NO_BASEBAND; 167 | break; 168 | #ifdef HAVE_LIBIPATCHER 169 | case '3': // long option: "use-pwndfu"; 170 | flags |= FLAG_IS_PWN_DFU; 171 | break; 172 | case '4': // long option: "just-boot"; 173 | bootargs = (optarg) ? optarg : ""; 174 | break; 175 | break; 176 | #endif 177 | case 'e': // long option: "exit-recovery"; can be called as short option 178 | exitRecovery = true; 179 | break; 180 | case 'd': // long option: "debug"; can be called as short option 181 | idevicerestore_debug = 1; 182 | break; 183 | default: 184 | cmd_help(); 185 | return -1; 186 | } 187 | } 188 | 189 | if (argc-optind == 1) { 190 | argc -= optind; 191 | argv += optind; 192 | 193 | ipsw = argv[0]; 194 | }else if (argc == optind && flags & FLAG_WAIT) { 195 | info("User requested to only wait for ApNonce to match, but not for actually restoring\n"); 196 | }else if (exitRecovery){ 197 | info("Exiting to recovery mode\n"); 198 | }else{ 199 | error("argument parsing failed! agrc=%d optind=%d\n",argc,optind); 200 | if (idevicerestore_debug){ 201 | for (int i=0; i