├── .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 |
111 | *Prometheus*
112 |
113 |
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 |
*futurerestore + libipatcher*
232 |
233 |
*kDFU app*
234 |
235 |
*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