├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── TODO ├── autogen.sh ├── config.guess ├── config.sub ├── configure.ac ├── depcomp ├── docs ├── Makefile.am └── idevicerestore.1 ├── install-sh ├── missing └── src ├── Makefile.am ├── asr.c ├── asr.h ├── common.c ├── common.h ├── dfu.c ├── dfu.h ├── download.c ├── download.h ├── fls.c ├── fls.h ├── idevicerestore.c ├── idevicerestore.h ├── img3.c ├── img3.h ├── ipsw.c ├── ipsw.h ├── limera1n.c ├── limera1n.h ├── limera1n_payload.h ├── locking.c ├── locking.h ├── mbn.c ├── mbn.h ├── normal.c ├── normal.h ├── recovery.c ├── recovery.h ├── restore.c ├── restore.h ├── tss.c └── tss.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.patch 2 | *.diff 3 | .*.swp 4 | Makefile 5 | Makefile.in 6 | aclocal.m4 7 | autom4te.cache 8 | config.h 9 | config.h.in 10 | config.log 11 | config.status 12 | configure 13 | libtool 14 | ltmain.sh 15 | m4 16 | src/*.o 17 | src/idevicerestore 18 | src/.libs 19 | src/.deps 20 | stamp-h1 21 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Joshua Hill 2 | Martin Szulecki 3 | Nikias Bassen -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chronic-Dev/idevicerestore/7d0b43eaf4b75f09664262f7eeb9453c34ab2c8d/ChangeLog -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 6 | 7 | This file is free documentation; the Free Software Foundation gives 8 | unlimited permission to copy, distribute and modify it. 9 | 10 | Basic Installation 11 | ================== 12 | 13 | Briefly, the shell commands `./configure; make; make install' should 14 | configure, build, and install this package. The following 15 | more-detailed instructions are generic; see the `README' file for 16 | instructions specific to this package. 17 | 18 | The `configure' shell script attempts to guess correct values for 19 | various system-dependent variables used during compilation. It uses 20 | those values to create a `Makefile' in each directory of the package. 21 | It may also create one or more `.h' files containing system-dependent 22 | definitions. Finally, it creates a shell script `config.status' that 23 | you can run in the future to recreate the current configuration, and a 24 | file `config.log' containing compiler output (useful mainly for 25 | debugging `configure'). 26 | 27 | It can also use an optional file (typically called `config.cache' 28 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 29 | the results of its tests to speed up reconfiguring. Caching is 30 | disabled by default to prevent problems with accidental use of stale 31 | cache files. 32 | 33 | If you need to do unusual things to compile the package, please try 34 | to figure out how `configure' could check whether to do them, and mail 35 | diffs or instructions to the address given in the `README' so they can 36 | be considered for the next release. If you are using the cache, and at 37 | some point `config.cache' contains results you don't want to keep, you 38 | may remove or edit it. 39 | 40 | The file `configure.ac' (or `configure.in') is used to create 41 | `configure' by a program called `autoconf'. You need `configure.ac' if 42 | you want to change it or regenerate `configure' using a newer version 43 | of `autoconf'. 44 | 45 | The simplest way to compile this package is: 46 | 47 | 1. `cd' to the directory containing the package's source code and type 48 | `./configure' to configure the package for your system. 49 | 50 | Running `configure' might take a while. While running, it prints 51 | some messages telling which features it is checking for. 52 | 53 | 2. Type `make' to compile the package. 54 | 55 | 3. Optionally, type `make check' to run any self-tests that come with 56 | the package. 57 | 58 | 4. Type `make install' to install the programs and any data files and 59 | documentation. 60 | 61 | 5. You can remove the program binaries and object files from the 62 | source code directory by typing `make clean'. To also remove the 63 | files that `configure' created (so you can compile the package for 64 | a different kind of computer), type `make distclean'. There is 65 | also a `make maintainer-clean' target, but that is intended mainly 66 | for the package's developers. If you use it, you may have to get 67 | all sorts of other programs in order to regenerate files that came 68 | with the distribution. 69 | 70 | 6. Often, you can also type `make uninstall' to remove the installed 71 | files again. 72 | 73 | Compilers and Options 74 | ===================== 75 | 76 | Some systems require unusual options for compilation or linking that 77 | the `configure' script does not know about. Run `./configure --help' 78 | for details on some of the pertinent environment variables. 79 | 80 | You can give `configure' initial values for configuration parameters 81 | by setting variables in the command line or in the environment. Here 82 | is an example: 83 | 84 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 85 | 86 | *Note Defining Variables::, for more details. 87 | 88 | Compiling For Multiple Architectures 89 | ==================================== 90 | 91 | You can compile the package for more than one kind of computer at the 92 | same time, by placing the object files for each architecture in their 93 | own directory. To do this, you can use GNU `make'. `cd' to the 94 | directory where you want the object files and executables to go and run 95 | the `configure' script. `configure' automatically checks for the 96 | source code in the directory that `configure' is in and in `..'. 97 | 98 | With a non-GNU `make', it is safer to compile the package for one 99 | architecture at a time in the source code directory. After you have 100 | installed the package for one architecture, use `make distclean' before 101 | reconfiguring for another architecture. 102 | 103 | On MacOS X 10.5 and later systems, you can create libraries and 104 | executables that work on multiple system types--known as "fat" or 105 | "universal" binaries--by specifying multiple `-arch' options to the 106 | compiler but only a single `-arch' option to the preprocessor. Like 107 | this: 108 | 109 | ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 110 | CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 111 | CPP="gcc -E" CXXCPP="g++ -E" 112 | 113 | This is not guaranteed to produce working output in all cases, you 114 | may have to build one architecture at a time and combine the results 115 | using the `lipo' tool if you have problems. 116 | 117 | Installation Names 118 | ================== 119 | 120 | By default, `make install' installs the package's commands under 121 | `/usr/local/bin', include files under `/usr/local/include', etc. You 122 | can specify an installation prefix other than `/usr/local' by giving 123 | `configure' the option `--prefix=PREFIX'. 124 | 125 | You can specify separate installation prefixes for 126 | architecture-specific files and architecture-independent files. If you 127 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 128 | PREFIX as the prefix for installing programs and libraries. 129 | Documentation and other data files still use the regular prefix. 130 | 131 | In addition, if you use an unusual directory layout you can give 132 | options like `--bindir=DIR' to specify different values for particular 133 | kinds of files. Run `configure --help' for a list of the directories 134 | you can set and what kinds of files go in them. 135 | 136 | If the package supports it, you can cause programs to be installed 137 | with an extra prefix or suffix on their names by giving `configure' the 138 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 139 | 140 | Optional Features 141 | ================= 142 | 143 | Some packages pay attention to `--enable-FEATURE' options to 144 | `configure', where FEATURE indicates an optional part of the package. 145 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 146 | is something like `gnu-as' or `x' (for the X Window System). The 147 | `README' should mention any `--enable-' and `--with-' options that the 148 | package recognizes. 149 | 150 | For packages that use the X Window System, `configure' can usually 151 | find the X include and library files automatically, but if it doesn't, 152 | you can use the `configure' options `--x-includes=DIR' and 153 | `--x-libraries=DIR' to specify their locations. 154 | 155 | Particular systems 156 | ================== 157 | 158 | On HP-UX, the default C compiler is not ANSI C compatible. If GNU 159 | CC is not installed, it is recommended to use the following options in 160 | order to use an ANSI C compiler: 161 | 162 | ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" 163 | 164 | and if that doesn't work, install pre-built binaries of GCC for HP-UX. 165 | 166 | On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot 167 | parse its `' header file. The option `-nodtk' can be used as 168 | a workaround. If GNU CC is not installed, it is therefore recommended 169 | to try 170 | 171 | ./configure CC="cc" 172 | 173 | and if that doesn't work, try 174 | 175 | ./configure CC="cc -nodtk" 176 | 177 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 178 | directory contains several dysfunctional programs; working variants of 179 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 180 | in your `PATH', put it _after_ `/usr/bin'. 181 | 182 | On Haiku, software installed for all users goes in `/boot/common', 183 | not `/usr/local'. It is recommended to use the following options: 184 | 185 | ./configure --prefix=/boot/common 186 | 187 | Specifying the System Type 188 | ========================== 189 | 190 | There may be some features `configure' cannot figure out 191 | automatically, but needs to determine by the type of machine the package 192 | will run on. Usually, assuming the package is built to be run on the 193 | _same_ architectures, `configure' can figure that out, but if it prints 194 | a message saying it cannot guess the machine type, give it the 195 | `--build=TYPE' option. TYPE can either be a short name for the system 196 | type, such as `sun4', or a canonical name which has the form: 197 | 198 | CPU-COMPANY-SYSTEM 199 | 200 | where SYSTEM can have one of these forms: 201 | 202 | OS 203 | KERNEL-OS 204 | 205 | See the file `config.sub' for the possible values of each field. If 206 | `config.sub' isn't included in this package, then this package doesn't 207 | need to know the machine type. 208 | 209 | If you are _building_ compiler tools for cross-compiling, you should 210 | use the option `--target=TYPE' to select the type of system they will 211 | produce code for. 212 | 213 | If you want to _use_ a cross compiler, that generates code for a 214 | platform different from the build platform, you should specify the 215 | "host" platform (i.e., that on which the generated programs will 216 | eventually be run) with `--host=TYPE'. 217 | 218 | Sharing Defaults 219 | ================ 220 | 221 | If you want to set default values for `configure' scripts to share, 222 | you can create a site shell script called `config.site' that gives 223 | default values for variables like `CC', `cache_file', and `prefix'. 224 | `configure' looks for `PREFIX/share/config.site' if it exists, then 225 | `PREFIX/etc/config.site' if it exists. Or, you can set the 226 | `CONFIG_SITE' environment variable to the location of the site script. 227 | A warning: not all `configure' scripts look for a site script. 228 | 229 | Defining Variables 230 | ================== 231 | 232 | Variables not defined in a site shell script can be set in the 233 | environment passed to `configure'. However, some packages may run 234 | configure again during the build, and the customized values of these 235 | variables may be lost. In order to avoid this problem, you should set 236 | them in the `configure' command line, using `VAR=value'. For example: 237 | 238 | ./configure CC=/usr/local2/bin/gcc 239 | 240 | causes the specified `gcc' to be used as the C compiler (unless it is 241 | overridden in the site shell script). 242 | 243 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 244 | an Autoconf bug. Until the bug is fixed you can use this workaround: 245 | 246 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 247 | 248 | `configure' Invocation 249 | ====================== 250 | 251 | `configure' recognizes the following options to control how it 252 | operates. 253 | 254 | `--help' 255 | `-h' 256 | Print a summary of all of the options to `configure', and exit. 257 | 258 | `--help=short' 259 | `--help=recursive' 260 | Print a summary of the options unique to this package's 261 | `configure', and exit. The `short' variant lists options used 262 | only in the top level, while the `recursive' variant lists options 263 | also present in any nested packages. 264 | 265 | `--version' 266 | `-V' 267 | Print the version of Autoconf used to generate the `configure' 268 | script, and exit. 269 | 270 | `--cache-file=FILE' 271 | Enable the cache: use and save the results of the tests in FILE, 272 | traditionally `config.cache'. FILE defaults to `/dev/null' to 273 | disable caching. 274 | 275 | `--config-cache' 276 | `-C' 277 | Alias for `--cache-file=config.cache'. 278 | 279 | `--quiet' 280 | `--silent' 281 | `-q' 282 | Do not print messages saying which checks are being made. To 283 | suppress all normal output, redirect it to `/dev/null' (any error 284 | messages will still be shown). 285 | 286 | `--srcdir=DIR' 287 | Look for the package's source code in directory DIR. Usually 288 | `configure' can determine that directory automatically. 289 | 290 | `--prefix=DIR' 291 | Use DIR as the installation prefix. *Note Installation Names:: 292 | for more details, including other options available for fine-tuning 293 | the installation locations. 294 | 295 | `--no-create' 296 | `-n' 297 | Run the configure checks, but stop before creating any output 298 | files. 299 | 300 | `configure' also accepts some other, not widely useful, options. Run 301 | `configure --help' for more details. 302 | 303 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src docs 2 | EXTRA_DIST = docs 3 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Sample NEWS file for idevicerestore project. 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | 4 | The idevicerestore tool allows to restore firmware files to iOS devices. 5 | 6 | It is a full reimplementation of all granular steps which are performed during 7 | restore of a firmware to a device. 8 | 9 | In general, upgrades and downgrades are possible, however subject to 10 | availability of SHSH blobs from Apple for signing the firmare files. 11 | 12 | To restore a device to some firmware, simply run the following: 13 | $ sudo idevicerestore -l 14 | 15 | This will download and restore a device to the latest firmware available. 16 | 17 | Requirements 18 | ============ 19 | 20 | Development Packages of: 21 | libimobiledevice 22 | libirecovery 23 | libusbmuxd 24 | libplist 25 | libzip 26 | openssl 27 | 28 | Software: 29 | usbmuxd 30 | make 31 | autoheader 32 | automake 33 | autoconf 34 | libtool 35 | pkg-config 36 | gcc 37 | 38 | Installation 39 | ============ 40 | 41 | To compile run: 42 | ./configure 43 | make 44 | sudo make install 45 | 46 | Who/What/Where? 47 | =============== 48 | 49 | Home: 50 | http://www.libimobiledevice.org/ 51 | http://www.openjailbreak.org/ 52 | 53 | Code: 54 | git clone http://git.sukimashita.com/idevicerestore.git 55 | 56 | Code (Mirror): 57 | git clone https://github.com/libimobiledevice/idevicerestore 58 | 59 | Tickets: 60 | http://github.com/libimobiledevice/idevicerestore/issues 61 | 62 | Mailing List: 63 | http://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel 64 | 65 | IRC: 66 | irc://irc.freenode.net#libimobiledevice 67 | 68 | Credits 69 | ======= 70 | 71 | Apple, iPhone, iPod, and iPod Touch are trademarks of Apple Inc. 72 | idevicerestore is an independent software tool and has not been 73 | authorized, sponsored, or otherwise approved by Apple Inc. 74 | 75 | README Updated on: 76 | 2013-09-23 -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | TODO List 2 | ------------------------------------------------ 3 | 4 | o) Instead of assumeing upgrade or restore, the program should query all avaiable build identitiys and find which ones are valid, if more then one is valid then display a menu asking whether to resore or upgrade. (This would also benifit users by cacheing both upgrade and restore SHSH blobs to sauriks server so users aren't stuck with only being able to upgrade or restore.) (in progress...) 5 | o) Also img3 should be updated to be able to fetch tags from each image such as the VERS tag to be able to compare with the current iBoot version. 6 | o) Need to add 8900 file support into img3.c. 7 | o) Cacheing TSS and activation info locally so the program doesn't need to query apple/cydia servers everytime would be nice. 8 | o) Need to add support to handle and display status messages correctly. 9 | o) Writing restore logs to an external file for debugging would be a great help. 10 | o) Would be nice to add options to keep some connections open during similar operations rather then reopening and closing them each time. (in progress...) 11 | o) Extracting and signing all firmware files at one time rather then extracting and signing each one as we need it could speed things up as well. 12 | o) Double check restore_send_kernelcache() 13 | o) Clean up and refactor restore_send_nor() 14 | o) Finishing cleaning up asr_perform_validation 15 | o) Double check asr_send_payload() 16 | o) Cleanup dfu.c/dfu.h 17 | o) Cleanup recovery.c/recovery.h 18 | o) Cleanup normal.c/normal.h 19 | o) Cleanup restore.c/restore.h 20 | o) Cleanup tss.c/tss.h 21 | o) Cleanup img3.c/img3.h 22 | o) Cleanup ipsw.c/ipsw.h 23 | o) Make ipsw.c a proxy to tss.c and img3.c 24 | o) Make all components only have access to their own context instead of a single global application context (less coupling) -------------------------------------------------------------------------------- /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 | autoheader 10 | automake --add-missing 11 | autoconf 12 | 13 | if [ -z "$NOCONFIGURE" ]; then 14 | ./configure "$@" 15 | fi 16 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | 3 | AC_PREREQ(2.61) 4 | AC_INIT(idevicerestore, 1.0) 5 | 6 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) 7 | 8 | AC_CONFIG_SRCDIR([src/]) 9 | AC_CONFIG_HEADERS([config.h]) 10 | AC_CONFIG_MACRO_DIR([m4]) 11 | 12 | AC_CANONICAL_SYSTEM 13 | AM_INIT_AUTOMAKE() 14 | 15 | AC_PROG_CC 16 | AM_PROG_CC_C_O 17 | AC_PROG_LIBTOOL 18 | 19 | PKG_CHECK_MODULES(libirecovery, libirecovery >= 0.2.0) 20 | PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.1.6) 21 | PKG_CHECK_MODULES(libplist, libplist >= 0.15) 22 | PKG_CHECK_MODULES(libzip, libzip >= 0.8) 23 | PKG_CHECK_MODULES(libcurl, libcurl >= 7.0) 24 | PKG_CHECK_MODULES(openssl, openssl >= 0.9.8) 25 | 26 | GLOBAL_CFLAGS="" 27 | AC_LDADD="" 28 | AC_LDFLAGS="" 29 | case "$host_os" in 30 | darwin*) 31 | AC_LDADD="-lusb-1.0" 32 | ;; 33 | linux*) 34 | AC_LDADD="-lusb-1.0" 35 | ;; 36 | mingw32) 37 | GLOBAL_CFLAGS+="-DWIN32 -D__LITTLE_ENDIAN__=1" 38 | AC_LDFLAGS+="-static-libgcc" 39 | AC_LDADD="-lsetupapi" 40 | ;; 41 | *) 42 | ;; 43 | esac 44 | 45 | AC_SUBST(GLOBAL_CFLAGS) 46 | AC_SUBST(AC_LDFLAGS) 47 | AC_SUBST(AC_LDADD) 48 | 49 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) 50 | 51 | AC_OUTPUT([ 52 | Makefile 53 | src/Makefile 54 | docs/Makefile 55 | ]) 56 | 57 | echo " 58 | Configuration for $PACKAGE $VERSION: 59 | ------------------------------------------- 60 | 61 | Install prefix: .........: $prefix 62 | 63 | Now type 'make' to build $PACKAGE $VERSION, 64 | and then 'make install' for installation. 65 | " 66 | -------------------------------------------------------------------------------- /docs/Makefile.am: -------------------------------------------------------------------------------- 1 | man_MANS = idevicerestore.1 2 | EXTRA_DIST = $(man_MANS) -------------------------------------------------------------------------------- /docs/idevicerestore.1: -------------------------------------------------------------------------------- 1 | .TH "idevicerestore" 1 2 | .SH NAME 3 | idevicerestore \- Restore IPSW firmware FILE to an iOS device 4 | .SH SYNOPSIS 5 | .B idevicerestore 6 | [OPTIONS] FILE 7 | 8 | .SH DESCRIPTION 9 | 10 | Restore firmware files to iOS devices while either erasing the device or 11 | updating to preserve content and settings. 12 | 13 | .SH OPTIONS 14 | .TP 15 | .B \-i, \-\-ecid ECID 16 | target specific device by its hexadecimal ECID e.g. 0xaabb123456 or 00000012AABBCCDD. 17 | .TP 18 | .B \-u, \-\-udid UDID 19 | target specific device by its 40-digit device UDID. 20 | NOTE: only works with devices in normal mode. 21 | .TP 22 | .B \-e, \-\-erase 23 | perform a full restore, erasing all data (defaults to update). 24 | .TP 25 | .B \-c, \-\-custom 26 | restore with a custom firmware. 27 | .TP 28 | .B \-l, \-\-latest 29 | use latest available firmware (with download on demand). \ 30 | DO NOT USE if you need to preserve the baseband (unlock)! \ 31 | USE WITH CARE if you want to keep a jailbreakable firmware! \ 32 | The FILE argument is ignored when using this option. 33 | .TP 34 | .B \-s, \-\-cydia 35 | use Cydia's signature service instead of Apple's. 36 | .TP 37 | .B \-x, \-\-exclude 38 | exclude nor/baseband upgrade. 39 | .TP 40 | .B \-t, \-\-shsh 41 | fetch TSS record and save to .shsh file, then exit. 42 | .TP 43 | .B \-p, \-\-pwn 44 | put device in pwned DFU mode and exit (limera1n devices only). 45 | .TP 46 | .B \-n, \-\-no\-action 47 | do not perform any restore action. If combined with -l option the on demand 48 | IPSW download is performed before exiting. 49 | .TP 50 | .B \-C, \-\-cache\-path DIR 51 | use specified directory for caching extracted or other reused files. 52 | .TP 53 | .B \-d, \-\-debug 54 | enable communication debugging. 55 | .TP 56 | .B \-h, \-\-help 57 | prints usage information. 58 | 59 | .SH AUTHORS 60 | Martin Szulecki 61 | 62 | Nikias Bassen 63 | 64 | Joshua Hill 65 | 66 | .SH ON THE WEB 67 | http://www.libimobiledevice.org 68 | 69 | http://www.openjailbreak.org 70 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2009-04-28.21; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -t DIRECTORY install into DIRECTORY. 124 | -T report an error if DSTFILE is a directory. 125 | 126 | Environment variables override the default commands: 127 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 128 | RMPROG STRIPPROG 129 | " 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *' '* | *' 147 | '* | *'*'* | *'?'* | *'['*) 148 | echo "$0: invalid mode: $mode" >&2 149 | exit 1;; 150 | esac 151 | shift;; 152 | 153 | -o) chowncmd="$chownprog $2" 154 | shift;; 155 | 156 | -s) stripcmd=$stripprog;; 157 | 158 | -t) dst_arg=$2 159 | shift;; 160 | 161 | -T) no_target_directory=true;; 162 | 163 | --version) echo "$0 $scriptversion"; exit $?;; 164 | 165 | --) shift 166 | break;; 167 | 168 | -*) echo "$0: invalid option: $1" >&2 169 | exit 1;; 170 | 171 | *) break;; 172 | esac 173 | shift 174 | done 175 | 176 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 177 | # When -d is used, all remaining arguments are directories to create. 178 | # When -t is used, the destination is already specified. 179 | # Otherwise, the last argument is the destination. Remove it from $@. 180 | for arg 181 | do 182 | if test -n "$dst_arg"; then 183 | # $@ is not empty: it contains at least $arg. 184 | set fnord "$@" "$dst_arg" 185 | shift # fnord 186 | fi 187 | shift # arg 188 | dst_arg=$arg 189 | done 190 | fi 191 | 192 | if test $# -eq 0; then 193 | if test -z "$dir_arg"; then 194 | echo "$0: no input file specified." >&2 195 | exit 1 196 | fi 197 | # It's OK to call `install-sh -d' without argument. 198 | # This can happen when creating conditional directories. 199 | exit 0 200 | fi 201 | 202 | if test -z "$dir_arg"; then 203 | trap '(exit $?); exit' 1 2 13 15 204 | 205 | # Set umask so as not to create temps with too-generous modes. 206 | # However, 'strip' requires both read and write access to temps. 207 | case $mode in 208 | # Optimize common cases. 209 | *644) cp_umask=133;; 210 | *755) cp_umask=22;; 211 | 212 | *[0-7]) 213 | if test -z "$stripcmd"; then 214 | u_plus_rw= 215 | else 216 | u_plus_rw='% 200' 217 | fi 218 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 219 | *) 220 | if test -z "$stripcmd"; then 221 | u_plus_rw= 222 | else 223 | u_plus_rw=,u+rw 224 | fi 225 | cp_umask=$mode$u_plus_rw;; 226 | esac 227 | fi 228 | 229 | for src 230 | do 231 | # Protect names starting with `-'. 232 | case $src in 233 | -*) src=./$src;; 234 | esac 235 | 236 | if test -n "$dir_arg"; then 237 | dst=$src 238 | dstdir=$dst 239 | test -d "$dstdir" 240 | dstdir_status=$? 241 | else 242 | 243 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 244 | # might cause directories to be created, which would be especially bad 245 | # if $src (and thus $dsttmp) contains '*'. 246 | if test ! -f "$src" && test ! -d "$src"; then 247 | echo "$0: $src does not exist." >&2 248 | exit 1 249 | fi 250 | 251 | if test -z "$dst_arg"; then 252 | echo "$0: no destination specified." >&2 253 | exit 1 254 | fi 255 | 256 | dst=$dst_arg 257 | # Protect names starting with `-'. 258 | case $dst in 259 | -*) dst=./$dst;; 260 | esac 261 | 262 | # If destination is a directory, append the input filename; won't work 263 | # if double slashes aren't ignored. 264 | if test -d "$dst"; then 265 | if test -n "$no_target_directory"; then 266 | echo "$0: $dst_arg: Is a directory" >&2 267 | exit 1 268 | fi 269 | dstdir=$dst 270 | dst=$dstdir/`basename "$src"` 271 | dstdir_status=0 272 | else 273 | # Prefer dirname, but fall back on a substitute if dirname fails. 274 | dstdir=` 275 | (dirname "$dst") 2>/dev/null || 276 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 277 | X"$dst" : 'X\(//\)[^/]' \| \ 278 | X"$dst" : 'X\(//\)$' \| \ 279 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 280 | echo X"$dst" | 281 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 282 | s//\1/ 283 | q 284 | } 285 | /^X\(\/\/\)[^/].*/{ 286 | s//\1/ 287 | q 288 | } 289 | /^X\(\/\/\)$/{ 290 | s//\1/ 291 | q 292 | } 293 | /^X\(\/\).*/{ 294 | s//\1/ 295 | q 296 | } 297 | s/.*/./; q' 298 | ` 299 | 300 | test -d "$dstdir" 301 | dstdir_status=$? 302 | fi 303 | fi 304 | 305 | obsolete_mkdir_used=false 306 | 307 | if test $dstdir_status != 0; then 308 | case $posix_mkdir in 309 | '') 310 | # Create intermediate dirs using mode 755 as modified by the umask. 311 | # This is like FreeBSD 'install' as of 1997-10-28. 312 | umask=`umask` 313 | case $stripcmd.$umask in 314 | # Optimize common cases. 315 | *[2367][2367]) mkdir_umask=$umask;; 316 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 317 | 318 | *[0-7]) 319 | mkdir_umask=`expr $umask + 22 \ 320 | - $umask % 100 % 40 + $umask % 20 \ 321 | - $umask % 10 % 4 + $umask % 2 322 | `;; 323 | *) mkdir_umask=$umask,go-w;; 324 | esac 325 | 326 | # With -d, create the new directory with the user-specified mode. 327 | # Otherwise, rely on $mkdir_umask. 328 | if test -n "$dir_arg"; then 329 | mkdir_mode=-m$mode 330 | else 331 | mkdir_mode= 332 | fi 333 | 334 | posix_mkdir=false 335 | case $umask in 336 | *[123567][0-7][0-7]) 337 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 338 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 339 | ;; 340 | *) 341 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 342 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 343 | 344 | if (umask $mkdir_umask && 345 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 346 | then 347 | if test -z "$dir_arg" || { 348 | # Check for POSIX incompatibilities with -m. 349 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 350 | # other-writeable bit of parent directory when it shouldn't. 351 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 352 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 353 | case $ls_ld_tmpdir in 354 | d????-?r-*) different_mode=700;; 355 | d????-?--*) different_mode=755;; 356 | *) false;; 357 | esac && 358 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 359 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 360 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 361 | } 362 | } 363 | then posix_mkdir=: 364 | fi 365 | rmdir "$tmpdir/d" "$tmpdir" 366 | else 367 | # Remove any dirs left behind by ancient mkdir implementations. 368 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 369 | fi 370 | trap '' 0;; 371 | esac;; 372 | esac 373 | 374 | if 375 | $posix_mkdir && ( 376 | umask $mkdir_umask && 377 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 378 | ) 379 | then : 380 | else 381 | 382 | # The umask is ridiculous, or mkdir does not conform to POSIX, 383 | # or it failed possibly due to a race condition. Create the 384 | # directory the slow way, step by step, checking for races as we go. 385 | 386 | case $dstdir in 387 | /*) prefix='/';; 388 | -*) prefix='./';; 389 | *) prefix='';; 390 | esac 391 | 392 | eval "$initialize_posix_glob" 393 | 394 | oIFS=$IFS 395 | IFS=/ 396 | $posix_glob set -f 397 | set fnord $dstdir 398 | shift 399 | $posix_glob set +f 400 | IFS=$oIFS 401 | 402 | prefixes= 403 | 404 | for d 405 | do 406 | test -z "$d" && continue 407 | 408 | prefix=$prefix$d 409 | if test -d "$prefix"; then 410 | prefixes= 411 | else 412 | if $posix_mkdir; then 413 | (umask=$mkdir_umask && 414 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 415 | # Don't fail if two instances are running concurrently. 416 | test -d "$prefix" || exit 1 417 | else 418 | case $prefix in 419 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 420 | *) qprefix=$prefix;; 421 | esac 422 | prefixes="$prefixes '$qprefix'" 423 | fi 424 | fi 425 | prefix=$prefix/ 426 | done 427 | 428 | if test -n "$prefixes"; then 429 | # Don't fail if two instances are running concurrently. 430 | (umask $mkdir_umask && 431 | eval "\$doit_exec \$mkdirprog $prefixes") || 432 | test -d "$dstdir" || exit 1 433 | obsolete_mkdir_used=true 434 | fi 435 | fi 436 | fi 437 | 438 | if test -n "$dir_arg"; then 439 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 440 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 441 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 442 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 443 | else 444 | 445 | # Make a couple of temp file names in the proper directory. 446 | dsttmp=$dstdir/_inst.$$_ 447 | rmtmp=$dstdir/_rm.$$_ 448 | 449 | # Trap to clean up those temp files at exit. 450 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 451 | 452 | # Copy the file name to the temp name. 453 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 454 | 455 | # and set any options; do chmod last to preserve setuid bits. 456 | # 457 | # If any of these fail, we abort the whole thing. If we want to 458 | # ignore errors from any of these, just make sure not to ignore 459 | # errors from the above "$doit $cpprog $src $dsttmp" command. 460 | # 461 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 462 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 463 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 464 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 465 | 466 | # If -C, don't bother to copy if it wouldn't change the file. 467 | if $copy_on_change && 468 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 469 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 470 | 471 | eval "$initialize_posix_glob" && 472 | $posix_glob set -f && 473 | set X $old && old=:$2:$4:$5:$6 && 474 | set X $new && new=:$2:$4:$5:$6 && 475 | $posix_glob set +f && 476 | 477 | test "$old" = "$new" && 478 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 479 | then 480 | rm -f "$dsttmp" 481 | else 482 | # Rename the file to the real destination. 483 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 484 | 485 | # The rename failed, perhaps because mv can't rename something else 486 | # to itself, or perhaps because mv is so ancient that it does not 487 | # support -f. 488 | { 489 | # Now remove or move aside any old file at destination location. 490 | # We try this two ways since rm can't unlink itself on some 491 | # systems and the destination file might be busy for other 492 | # reasons. In this case, the final cleanup might fail but the new 493 | # file should still install successfully. 494 | { 495 | test ! -f "$dst" || 496 | $doit $rmcmd -f "$dst" 2>/dev/null || 497 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 498 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 499 | } || 500 | { echo "$0: cannot unlink or rename $dst" >&2 501 | (exit 1); exit 1 502 | } 503 | } && 504 | 505 | # Now rename the file to the real destination. 506 | $doit $mvcmd "$dsttmp" "$dst" 507 | } 508 | fi || exit 1 509 | 510 | trap '' 0 511 | fi 512 | done 513 | 514 | # Local variables: 515 | # eval: (add-hook 'write-file-hooks 'time-stamp) 516 | # time-stamp-start: "scriptversion=" 517 | # time-stamp-format: "%:y-%02m-%02d.%02H" 518 | # time-stamp-time-zone: "UTC" 519 | # time-stamp-end: "; # UTC" 520 | # End: 521 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common stub for a few missing GNU programs while installing. 3 | 4 | scriptversion=2009-04-28.21; # UTC 5 | 6 | # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 7 | # 2008, 2009 Free Software Foundation, Inc. 8 | # Originally by Fran,cois Pinard , 1996. 9 | 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program. If not, see . 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | if test $# -eq 0; then 29 | echo 1>&2 "Try \`$0 --help' for more information" 30 | exit 1 31 | fi 32 | 33 | run=: 34 | sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' 35 | sed_minuso='s/.* -o \([^ ]*\).*/\1/p' 36 | 37 | # In the cases where this matters, `missing' is being run in the 38 | # srcdir already. 39 | if test -f configure.ac; then 40 | configure_ac=configure.ac 41 | else 42 | configure_ac=configure.in 43 | fi 44 | 45 | msg="missing on your system" 46 | 47 | case $1 in 48 | --run) 49 | # Try to run requested program, and just exit if it succeeds. 50 | run= 51 | shift 52 | "$@" && exit 0 53 | # Exit code 63 means version mismatch. This often happens 54 | # when the user try to use an ancient version of a tool on 55 | # a file that requires a minimum version. In this case we 56 | # we should proceed has if the program had been absent, or 57 | # if --run hadn't been passed. 58 | if test $? = 63; then 59 | run=: 60 | msg="probably too old" 61 | fi 62 | ;; 63 | 64 | -h|--h|--he|--hel|--help) 65 | echo "\ 66 | $0 [OPTION]... PROGRAM [ARGUMENT]... 67 | 68 | Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an 69 | error status if there is no known handling for PROGRAM. 70 | 71 | Options: 72 | -h, --help display this help and exit 73 | -v, --version output version information and exit 74 | --run try to run the given command, and emulate it if it fails 75 | 76 | Supported PROGRAM values: 77 | aclocal touch file \`aclocal.m4' 78 | autoconf touch file \`configure' 79 | autoheader touch file \`config.h.in' 80 | autom4te touch the output file, or create a stub one 81 | automake touch all \`Makefile.in' files 82 | bison create \`y.tab.[ch]', if possible, from existing .[ch] 83 | flex create \`lex.yy.c', if possible, from existing .c 84 | help2man touch the output file 85 | lex create \`lex.yy.c', if possible, from existing .c 86 | makeinfo touch the output file 87 | tar try tar, gnutar, gtar, then tar without non-portable flags 88 | yacc create \`y.tab.[ch]', if possible, from existing .[ch] 89 | 90 | Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and 91 | \`g' are ignored when checking the name. 92 | 93 | Send bug reports to ." 94 | exit $? 95 | ;; 96 | 97 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 98 | echo "missing $scriptversion (GNU Automake)" 99 | exit $? 100 | ;; 101 | 102 | -*) 103 | echo 1>&2 "$0: Unknown \`$1' option" 104 | echo 1>&2 "Try \`$0 --help' for more information" 105 | exit 1 106 | ;; 107 | 108 | esac 109 | 110 | # normalize program name to check for. 111 | program=`echo "$1" | sed ' 112 | s/^gnu-//; t 113 | s/^gnu//; t 114 | s/^g//; t'` 115 | 116 | # Now exit if we have it, but it failed. Also exit now if we 117 | # don't have it and --version was passed (most likely to detect 118 | # the program). This is about non-GNU programs, so use $1 not 119 | # $program. 120 | case $1 in 121 | lex*|yacc*) 122 | # Not GNU programs, they don't have --version. 123 | ;; 124 | 125 | tar*) 126 | if test -n "$run"; then 127 | echo 1>&2 "ERROR: \`tar' requires --run" 128 | exit 1 129 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 130 | exit 1 131 | fi 132 | ;; 133 | 134 | *) 135 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 136 | # We have it, but it failed. 137 | exit 1 138 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 139 | # Could not run --version or --help. This is probably someone 140 | # running `$TOOL --version' or `$TOOL --help' to check whether 141 | # $TOOL exists and not knowing $TOOL uses missing. 142 | exit 1 143 | fi 144 | ;; 145 | esac 146 | 147 | # If it does not exist, or fails to run (possibly an outdated version), 148 | # try to emulate it. 149 | case $program in 150 | aclocal*) 151 | echo 1>&2 "\ 152 | WARNING: \`$1' is $msg. You should only need it if 153 | you modified \`acinclude.m4' or \`${configure_ac}'. You might want 154 | to install the \`Automake' and \`Perl' packages. Grab them from 155 | any GNU archive site." 156 | touch aclocal.m4 157 | ;; 158 | 159 | autoconf*) 160 | echo 1>&2 "\ 161 | WARNING: \`$1' is $msg. You should only need it if 162 | you modified \`${configure_ac}'. You might want to install the 163 | \`Autoconf' and \`GNU m4' packages. Grab them from any GNU 164 | archive site." 165 | touch configure 166 | ;; 167 | 168 | autoheader*) 169 | echo 1>&2 "\ 170 | WARNING: \`$1' is $msg. You should only need it if 171 | you modified \`acconfig.h' or \`${configure_ac}'. You might want 172 | to install the \`Autoconf' and \`GNU m4' packages. Grab them 173 | from any GNU archive site." 174 | files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` 175 | test -z "$files" && files="config.h" 176 | touch_files= 177 | for f in $files; do 178 | case $f in 179 | *:*) touch_files="$touch_files "`echo "$f" | 180 | sed -e 's/^[^:]*://' -e 's/:.*//'`;; 181 | *) touch_files="$touch_files $f.in";; 182 | esac 183 | done 184 | touch $touch_files 185 | ;; 186 | 187 | automake*) 188 | echo 1>&2 "\ 189 | WARNING: \`$1' is $msg. You should only need it if 190 | you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. 191 | You might want to install the \`Automake' and \`Perl' packages. 192 | Grab them from any GNU archive site." 193 | find . -type f -name Makefile.am -print | 194 | sed 's/\.am$/.in/' | 195 | while read f; do touch "$f"; done 196 | ;; 197 | 198 | autom4te*) 199 | echo 1>&2 "\ 200 | WARNING: \`$1' is needed, but is $msg. 201 | You might have modified some files without having the 202 | proper tools for further handling them. 203 | You can get \`$1' as part of \`Autoconf' from any GNU 204 | archive site." 205 | 206 | file=`echo "$*" | sed -n "$sed_output"` 207 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 208 | if test -f "$file"; then 209 | touch $file 210 | else 211 | test -z "$file" || exec >$file 212 | echo "#! /bin/sh" 213 | echo "# Created by GNU Automake missing as a replacement of" 214 | echo "# $ $@" 215 | echo "exit 0" 216 | chmod +x $file 217 | exit 1 218 | fi 219 | ;; 220 | 221 | bison*|yacc*) 222 | echo 1>&2 "\ 223 | WARNING: \`$1' $msg. You should only need it if 224 | you modified a \`.y' file. You may need the \`Bison' package 225 | in order for those modifications to take effect. You can get 226 | \`Bison' from any GNU archive site." 227 | rm -f y.tab.c y.tab.h 228 | if test $# -ne 1; then 229 | eval LASTARG="\${$#}" 230 | case $LASTARG in 231 | *.y) 232 | SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 233 | if test -f "$SRCFILE"; then 234 | cp "$SRCFILE" y.tab.c 235 | fi 236 | SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` 237 | if test -f "$SRCFILE"; then 238 | cp "$SRCFILE" y.tab.h 239 | fi 240 | ;; 241 | esac 242 | fi 243 | if test ! -f y.tab.h; then 244 | echo >y.tab.h 245 | fi 246 | if test ! -f y.tab.c; then 247 | echo 'main() { return 0; }' >y.tab.c 248 | fi 249 | ;; 250 | 251 | lex*|flex*) 252 | echo 1>&2 "\ 253 | WARNING: \`$1' is $msg. You should only need it if 254 | you modified a \`.l' file. You may need the \`Flex' package 255 | in order for those modifications to take effect. You can get 256 | \`Flex' from any GNU archive site." 257 | rm -f lex.yy.c 258 | if test $# -ne 1; then 259 | eval LASTARG="\${$#}" 260 | case $LASTARG in 261 | *.l) 262 | SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` 263 | if test -f "$SRCFILE"; then 264 | cp "$SRCFILE" lex.yy.c 265 | fi 266 | ;; 267 | esac 268 | fi 269 | if test ! -f lex.yy.c; then 270 | echo 'main() { return 0; }' >lex.yy.c 271 | fi 272 | ;; 273 | 274 | help2man*) 275 | echo 1>&2 "\ 276 | WARNING: \`$1' is $msg. You should only need it if 277 | you modified a dependency of a manual page. You may need the 278 | \`Help2man' package in order for those modifications to take 279 | effect. You can get \`Help2man' from any GNU archive site." 280 | 281 | file=`echo "$*" | sed -n "$sed_output"` 282 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 283 | if test -f "$file"; then 284 | touch $file 285 | else 286 | test -z "$file" || exec >$file 287 | echo ".ab help2man is required to generate this page" 288 | exit $? 289 | fi 290 | ;; 291 | 292 | makeinfo*) 293 | echo 1>&2 "\ 294 | WARNING: \`$1' is $msg. You should only need it if 295 | you modified a \`.texi' or \`.texinfo' file, or any other file 296 | indirectly affecting the aspect of the manual. The spurious 297 | call might also be the consequence of using a buggy \`make' (AIX, 298 | DU, IRIX). You might want to install the \`Texinfo' package or 299 | the \`GNU make' package. Grab either from any GNU archive site." 300 | # The file to touch is that specified with -o ... 301 | file=`echo "$*" | sed -n "$sed_output"` 302 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 303 | if test -z "$file"; then 304 | # ... or it is the one specified with @setfilename ... 305 | infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` 306 | file=`sed -n ' 307 | /^@setfilename/{ 308 | s/.* \([^ ]*\) *$/\1/ 309 | p 310 | q 311 | }' $infile` 312 | # ... or it is derived from the source name (dir/f.texi becomes f.info) 313 | test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info 314 | fi 315 | # If the file does not exist, the user really needs makeinfo; 316 | # let's fail without touching anything. 317 | test -f $file || exit 1 318 | touch $file 319 | ;; 320 | 321 | tar*) 322 | shift 323 | 324 | # We have already tried tar in the generic part. 325 | # Look for gnutar/gtar before invocation to avoid ugly error 326 | # messages. 327 | if (gnutar --version > /dev/null 2>&1); then 328 | gnutar "$@" && exit 0 329 | fi 330 | if (gtar --version > /dev/null 2>&1); then 331 | gtar "$@" && exit 0 332 | fi 333 | firstarg="$1" 334 | if shift; then 335 | case $firstarg in 336 | *o*) 337 | firstarg=`echo "$firstarg" | sed s/o//` 338 | tar "$firstarg" "$@" && exit 0 339 | ;; 340 | esac 341 | case $firstarg in 342 | *h*) 343 | firstarg=`echo "$firstarg" | sed s/h//` 344 | tar "$firstarg" "$@" && exit 0 345 | ;; 346 | esac 347 | fi 348 | 349 | echo 1>&2 "\ 350 | WARNING: I can't seem to be able to run \`tar' with the given arguments. 351 | You may want to install GNU tar or Free paxutils, or check the 352 | command line arguments." 353 | exit 1 354 | ;; 355 | 356 | *) 357 | echo 1>&2 "\ 358 | WARNING: \`$1' is needed, and is $msg. 359 | You might have modified some files without having the 360 | proper tools for further handling them. Check the \`README' file, 361 | it often tells you about the needed prerequisites for installing 362 | this package. You may also peek at any GNU archive site, in case 363 | some other package would contain this missing \`$1' program." 364 | exit 1 365 | ;; 366 | esac 367 | 368 | exit 0 369 | 370 | # Local variables: 371 | # eval: (add-hook 'write-file-hooks 'time-stamp) 372 | # time-stamp-start: "scriptversion=" 373 | # time-stamp-format: "%:y-%02m-%02d.%02H" 374 | # time-stamp-time-zone: "UTC" 375 | # time-stamp-end: "; # UTC" 376 | # End: 377 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = \ 2 | $(GLOBAL_CFLAGS) \ 3 | $(libirecovery_CFLAGS) \ 4 | $(libimobiledevice_CFLAGS) \ 5 | $(libplist_CFLAGS) \ 6 | $(libzip_CFLAGS) \ 7 | $(openssl_CFLAGS) \ 8 | $(libcurl_CFLAGS) 9 | 10 | AM_LDFLAGS =\ 11 | $(AC_LDFLAGS) \ 12 | $(libirecovery_LIBS) \ 13 | $(libimobiledevice_LIBS) \ 14 | $(libplist_LIBS) \ 15 | $(libzip_LIBS) \ 16 | $(openssl_LIBS) \ 17 | $(libcurl_LIBS) 18 | 19 | AM_LDADD = $(AC_LDADD) 20 | 21 | bin_PROGRAMS = idevicerestore 22 | 23 | idevicerestore_SOURCES = idevicerestore.c common.c tss.c fls.c mbn.c img3.c ipsw.c normal.c dfu.c recovery.c restore.c asr.c limera1n.c download.c locking.c 24 | idevicerestore_CFLAGS = $(AM_CFLAGS) 25 | idevicerestore_LDFLAGS = $(AM_LDFLAGS) 26 | idevicerestore_LDADD = $(AM_LDADD) 27 | -------------------------------------------------------------------------------- /src/asr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * asr.h 3 | * Functions for handling asr connections 4 | * 5 | * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "asr.h" 32 | #include "idevicerestore.h" 33 | #include "common.h" 34 | 35 | #define ASR_VERSION 1 36 | #define ASR_STREAM_ID 1 37 | #define ASR_PORT 12345 38 | #define ASR_BUFFER_SIZE 65536 39 | #define ASR_FEC_SLICE_STRIDE 40 40 | #define ASR_PACKETS_PER_FEC 25 41 | #define ASR_PAYLOAD_PACKET_SIZE 1450 42 | #define ASR_CHECKSUM_CHUNK_SIZE 131072 43 | 44 | int asr_open_with_timeout(idevice_t device, asr_client_t* asr) { 45 | int i = 0; 46 | int attempts = 10; 47 | idevice_connection_t connection = NULL; 48 | idevice_error_t device_error = IDEVICE_E_SUCCESS; 49 | 50 | *asr = NULL; 51 | 52 | if (device == NULL) { 53 | return -1; 54 | } 55 | 56 | debug("Connecting to ASR\n"); 57 | for (i = 1; i <= attempts; i++) { 58 | device_error = idevice_connect(device, ASR_PORT, &connection); 59 | if (device_error == IDEVICE_E_SUCCESS) { 60 | break; 61 | } 62 | 63 | if (i >= attempts) { 64 | error("ERROR: Unable to connect to ASR client\n"); 65 | return -1; 66 | } 67 | 68 | sleep(2); 69 | debug("Retrying connection...\n"); 70 | } 71 | 72 | asr_client_t asr_loc = (asr_client_t)malloc(sizeof(struct asr_client)); 73 | memset(asr_loc, '\0', sizeof(struct asr_client)); 74 | asr_loc->connection = connection; 75 | 76 | /* receive Initiate command message */ 77 | plist_t data = NULL; 78 | asr_loc->checksum_chunks = 0; 79 | if (asr_receive(asr_loc, &data) < 0) { 80 | error("ERROR: Unable to receive data from ASR\n"); 81 | asr_free(asr_loc); 82 | plist_free(data); 83 | return -1; 84 | } 85 | plist_t node; 86 | node = plist_dict_get_item(data, "Command"); 87 | if (node && (plist_get_node_type(node) == PLIST_STRING)) { 88 | char* strval = NULL; 89 | plist_get_string_val(node, &strval); 90 | if (strval && (strcmp(strval, "Initiate") != 0)) { 91 | error("ERROR: unexpected ASR plist received:\n"); 92 | debug_plist(data); 93 | plist_free(data); 94 | asr_free(asr_loc); 95 | return -1; 96 | } 97 | } 98 | 99 | node = plist_dict_get_item(data, "Checksum Chunks"); 100 | if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) { 101 | plist_get_bool_val(node, &(asr_loc->checksum_chunks)); 102 | } 103 | plist_free(data); 104 | 105 | *asr = asr_loc; 106 | 107 | return 0; 108 | } 109 | 110 | void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t cbfunc, void* userdata) 111 | { 112 | if (!asr) { 113 | return; 114 | } 115 | asr->progress_cb = cbfunc; 116 | asr->progress_cb_data = userdata; 117 | } 118 | 119 | int asr_receive(asr_client_t asr, plist_t* data) { 120 | uint32_t size = 0; 121 | char* buffer = NULL; 122 | plist_t request = NULL; 123 | idevice_error_t device_error = IDEVICE_E_SUCCESS; 124 | 125 | *data = NULL; 126 | 127 | buffer = (char*) malloc(ASR_BUFFER_SIZE); 128 | if (buffer == NULL) { 129 | error("ERROR: Unable to allocate memory for ASR receive buffer\n"); 130 | return -1; 131 | } 132 | memset(buffer, '\0', ASR_BUFFER_SIZE); 133 | 134 | device_error = idevice_connection_receive(asr->connection, buffer, ASR_BUFFER_SIZE, &size); 135 | if (device_error != IDEVICE_E_SUCCESS) { 136 | error("ERROR: Unable to receive data from ASR\n"); 137 | free(buffer); 138 | return -1; 139 | } 140 | plist_from_xml(buffer, size, &request); 141 | 142 | *data = request; 143 | 144 | debug("Received %d bytes:\n", size); 145 | if (idevicerestore_debug) 146 | debug_plist(request); 147 | free(buffer); 148 | return 0; 149 | } 150 | 151 | int asr_send(asr_client_t asr, plist_t data) { 152 | uint32_t size = 0; 153 | char* buffer = NULL; 154 | 155 | plist_to_xml(data, &buffer, &size); 156 | if (asr_send_buffer(asr, buffer, size) < 0) { 157 | error("ERROR: Unable to send plist to ASR\n"); 158 | free(buffer); 159 | return -1; 160 | } 161 | 162 | debug("Sent %d bytes:\n", size); 163 | 164 | if (buffer) 165 | free(buffer); 166 | return 0; 167 | } 168 | 169 | int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size) { 170 | uint32_t bytes = 0; 171 | idevice_error_t device_error = IDEVICE_E_SUCCESS; 172 | 173 | device_error = idevice_connection_send(asr->connection, data, size, &bytes); 174 | if (device_error != IDEVICE_E_SUCCESS || bytes != size) { 175 | error("ERROR: Unable to send data to ASR. Sent %u of %u bytes.\n", bytes, size); 176 | return -1; 177 | } 178 | 179 | debug("Sent %d bytes buffer\n", bytes); 180 | 181 | return 0; 182 | } 183 | 184 | void asr_free(asr_client_t asr) { 185 | if (asr != NULL) { 186 | if (asr->connection != NULL) { 187 | idevice_disconnect(asr->connection); 188 | asr->connection = NULL; 189 | } 190 | free(asr); 191 | asr = NULL; 192 | } 193 | } 194 | 195 | int asr_perform_validation(asr_client_t asr, const char* filesystem) { 196 | FILE* file = NULL; 197 | uint64_t length = 0; 198 | char* command = NULL; 199 | plist_t node = NULL; 200 | plist_t packet = NULL; 201 | plist_t packet_info = NULL; 202 | plist_t payload_info = NULL; 203 | int attempts = 0; 204 | 205 | file = fopen(filesystem, "rb"); 206 | if (file == NULL) { 207 | return -1; 208 | } 209 | 210 | fseek(file, 0, SEEK_END); 211 | length = ftell(file); 212 | fseek(file, 0, SEEK_SET); 213 | 214 | payload_info = plist_new_dict(); 215 | plist_dict_insert_item(payload_info, "Port", plist_new_uint(1)); 216 | plist_dict_insert_item(payload_info, "Size", plist_new_uint(length)); 217 | 218 | packet_info = plist_new_dict(); 219 | if (asr->checksum_chunks) { 220 | plist_dict_insert_item(packet_info, "Checksum Chunk Size", plist_new_uint(ASR_CHECKSUM_CHUNK_SIZE)); 221 | } 222 | plist_dict_insert_item(packet_info, "FEC Slice Stride", plist_new_uint(ASR_FEC_SLICE_STRIDE)); 223 | plist_dict_insert_item(packet_info, "Packet Payload Size", plist_new_uint(ASR_PAYLOAD_PACKET_SIZE)); 224 | plist_dict_insert_item(packet_info, "Packets Per FEC", plist_new_uint(ASR_PACKETS_PER_FEC)); 225 | plist_dict_insert_item(packet_info, "Payload", payload_info); 226 | plist_dict_insert_item(packet_info, "Stream ID", plist_new_uint(ASR_STREAM_ID)); 227 | plist_dict_insert_item(packet_info, "Version", plist_new_uint(ASR_VERSION)); 228 | 229 | if (asr_send(asr, packet_info)) { 230 | error("ERROR: Unable to sent packet information to ASR\n"); 231 | plist_free(packet_info); 232 | return -1; 233 | } 234 | plist_free(packet_info); 235 | 236 | while (1) { 237 | if (asr_receive(asr, &packet) < 0) { 238 | error("ERROR: Unable to receive validation packet\n"); 239 | return -1; 240 | } 241 | 242 | if (packet == NULL) { 243 | if (attempts < 5) { 244 | info("Retrying to receive validation packet... %d\n", attempts); 245 | attempts++; 246 | sleep(1); 247 | continue; 248 | } 249 | } 250 | 251 | attempts = 0; 252 | 253 | node = plist_dict_get_item(packet, "Command"); 254 | if (!node || plist_get_node_type(node) != PLIST_STRING) { 255 | error("ERROR: Unable to find command node in validation request\n"); 256 | return -1; 257 | } 258 | plist_get_string_val(node, &command); 259 | 260 | if (!strcmp(command, "OOBData")) { 261 | asr_handle_oob_data_request(asr, packet, file); 262 | plist_free(packet); 263 | } else if(!strcmp(command, "Payload")) { 264 | plist_free(packet); 265 | break; 266 | 267 | } else { 268 | error("ERROR: Unknown command received from ASR\n"); 269 | plist_free(packet); 270 | return -1; 271 | } 272 | } 273 | 274 | return 0; 275 | } 276 | 277 | int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file) { 278 | char* oob_data = NULL; 279 | uint64_t oob_offset = 0; 280 | uint64_t oob_length = 0; 281 | plist_t oob_length_node = NULL; 282 | plist_t oob_offset_node = NULL; 283 | 284 | oob_length_node = plist_dict_get_item(packet, "OOB Length"); 285 | if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) { 286 | error("ERROR: Unable to find OOB data length\n"); 287 | return -1; 288 | } 289 | plist_get_uint_val(oob_length_node, &oob_length); 290 | 291 | oob_offset_node = plist_dict_get_item(packet, "OOB Offset"); 292 | if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) { 293 | error("ERROR: Unable to find OOB data offset\n"); 294 | return -1; 295 | } 296 | plist_get_uint_val(oob_offset_node, &oob_offset); 297 | 298 | oob_data = (char*) malloc(oob_length); 299 | if (oob_data == NULL) { 300 | error("ERROR: Out of memory\n"); 301 | plist_free(packet); 302 | return -1; 303 | } 304 | 305 | fseek(file, oob_offset, SEEK_SET); 306 | if (fread(oob_data, 1, oob_length, file) != oob_length) { 307 | error("ERROR: Unable to read OOB data from filesystem offset\n"); 308 | plist_free(packet); 309 | free(oob_data); 310 | return -1; 311 | } 312 | 313 | if (asr_send_buffer(asr, oob_data, oob_length) < 0) { 314 | error("ERROR: Unable to send OOB data to ASR\n"); 315 | plist_free(packet); 316 | free(oob_data); 317 | return -1; 318 | } 319 | free(oob_data); 320 | return 0; 321 | } 322 | 323 | int asr_send_payload(asr_client_t asr, const char* filesystem) { 324 | int i = 0; 325 | char data[ASR_PAYLOAD_PACKET_SIZE]; 326 | FILE* file = NULL; 327 | uint32_t bytes = 0; 328 | uint32_t count = 0; 329 | uint32_t length = 0; 330 | double progress = 0; 331 | 332 | file = fopen(filesystem, "rb"); 333 | if (file == NULL) { 334 | return -1; 335 | } 336 | 337 | fseek(file, 0, SEEK_END); 338 | length = ftell(file); 339 | fseek(file, 0, SEEK_SET); 340 | 341 | int chunk = 0; 342 | int add_checksum = 0; 343 | 344 | SHA_CTX sha1; 345 | 346 | if (asr->checksum_chunks) { 347 | SHA1_Init(&sha1); 348 | } 349 | 350 | int size = 0; 351 | for (i = length; i > 0; i -= size) { 352 | size = ASR_PAYLOAD_PACKET_SIZE; 353 | if (i < ASR_PAYLOAD_PACKET_SIZE) { 354 | size = i; 355 | } 356 | 357 | if (add_checksum) { 358 | add_checksum = 0; 359 | } 360 | 361 | if (asr->checksum_chunks && ((chunk + size) >= ASR_CHECKSUM_CHUNK_SIZE)) { 362 | // reduce packet size to match checksum chunk size 363 | size -= ((chunk + size) - ASR_CHECKSUM_CHUNK_SIZE); 364 | add_checksum = 1; 365 | } 366 | 367 | if (fread(data, 1, size, file) != (unsigned int) size) { 368 | error("Error reading filesystem\n"); 369 | fclose(file); 370 | return -1; 371 | } 372 | 373 | if (asr_send_buffer(asr, data, size) < 0) { 374 | error("ERROR: Unable to send filesystem payload\n"); 375 | fclose(file); 376 | return -1; 377 | } 378 | 379 | if (asr->checksum_chunks) { 380 | SHA1_Update(&sha1, data, size); 381 | chunk += size; 382 | 383 | if (add_checksum) { 384 | // get sha1 of last chunk 385 | SHA1_Final((unsigned char*)data, &sha1); 386 | 387 | // send checksum 388 | if (asr_send_buffer(asr, data, 20) < 0) { 389 | error("ERROR: Unable to send chunk checksum\n"); 390 | fclose(file); 391 | return -1; 392 | } 393 | 394 | // reset SHA1 context 395 | SHA1_Init(&sha1); 396 | 397 | // reset chunk byte counter 398 | chunk = 0; 399 | } 400 | } 401 | 402 | bytes += size; 403 | progress = ((double) bytes/ (double) length); 404 | if (asr->progress_cb && ((int)(progress*100) > asr->lastprogress)) { 405 | asr->progress_cb(progress, asr->progress_cb_data); 406 | asr->lastprogress = (int)(progress*100); 407 | } 408 | } 409 | 410 | // if last chunk wasn't terminated with a checksum we do it here 411 | if (asr->checksum_chunks && !add_checksum) { 412 | // get sha1 of last chunk 413 | SHA1_Final((unsigned char*)data, &sha1); 414 | 415 | // send checksum 416 | if (asr_send_buffer(asr, data, 20) < 0) { 417 | error("ERROR: Unable to send chunk checksum\n"); 418 | fclose(file); 419 | return -1; 420 | } 421 | } 422 | 423 | fclose(file); 424 | return 0; 425 | } 426 | -------------------------------------------------------------------------------- /src/asr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * asr.h 3 | * Functions for handling asr connections 4 | * 5 | * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_ASR_H 25 | #define IDEVICERESTORE_ASR_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | 33 | typedef void (*asr_progress_cb_t)(double, void*); 34 | 35 | struct asr_client { 36 | idevice_connection_t connection; 37 | uint8_t checksum_chunks; 38 | int lastprogress; 39 | asr_progress_cb_t progress_cb; 40 | void* progress_cb_data; 41 | }; 42 | typedef struct asr_client *asr_client_t; 43 | 44 | int asr_open_with_timeout(idevice_t device, asr_client_t* asr); 45 | void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata); 46 | int asr_send(asr_client_t asr, plist_t data); 47 | int asr_receive(asr_client_t asr, plist_t* data); 48 | int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size); 49 | void asr_free(asr_client_t asr); 50 | int asr_perform_validation(asr_client_t asr, const char* filesystem); 51 | int asr_send_payload(asr_client_t asr, const char* filesystem); 52 | int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file); 53 | 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * common.c 3 | * Misc functions used in idevicerestore 4 | * 5 | * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "common.h" 32 | 33 | int idevicerestore_debug = 0; 34 | 35 | #define idevicerestore_err_buff_size 256 36 | static char idevicerestore_err_buff[idevicerestore_err_buff_size] = {0, }; 37 | 38 | static FILE* info_stream = NULL; 39 | static FILE* error_stream = NULL; 40 | static FILE* debug_stream = NULL; 41 | 42 | static int info_disabled = 0; 43 | static int error_disabled = 0; 44 | static int debug_disabled = 0; 45 | 46 | void info(const char* format, ...) 47 | { 48 | if (info_disabled) return; 49 | va_list vargs; 50 | va_start(vargs, format); 51 | vfprintf((info_stream) ? info_stream : stdout, format, vargs); 52 | va_end(vargs); 53 | } 54 | 55 | void error(const char* format, ...) 56 | { 57 | va_list vargs, vargs2; 58 | va_start(vargs, format); 59 | va_copy(vargs2, vargs); 60 | vsnprintf(idevicerestore_err_buff, idevicerestore_err_buff_size, format, vargs); 61 | va_end(vargs); 62 | if (!error_disabled) { 63 | vfprintf((error_stream) ? error_stream : stderr, format, vargs2); 64 | } 65 | va_end(vargs2); 66 | } 67 | 68 | void debug(const char* format, ...) 69 | { 70 | if (debug_disabled) return; 71 | if (!idevicerestore_debug) { 72 | return; 73 | } 74 | va_list vargs; 75 | va_start(vargs, format); 76 | vfprintf((debug_stream) ? debug_stream : stderr, format, vargs); 77 | va_end(vargs); 78 | } 79 | 80 | void idevicerestore_set_info_stream(FILE* strm) 81 | { 82 | if (strm) { 83 | info_disabled = 0; 84 | info_stream = strm; 85 | } else { 86 | info_disabled = 1; 87 | } 88 | } 89 | 90 | void idevicerestore_set_error_stream(FILE* strm) 91 | { 92 | if (strm) { 93 | error_disabled = 0; 94 | error_stream = strm; 95 | } else { 96 | error_disabled = 1; 97 | } 98 | } 99 | 100 | void idevicerestore_set_debug_stream(FILE* strm) 101 | { 102 | if (strm) { 103 | debug_disabled = 0; 104 | debug_stream = strm; 105 | } else { 106 | debug_disabled = 1; 107 | } 108 | } 109 | 110 | const char* idevicerestore_get_error() 111 | { 112 | if (idevicerestore_err_buff[0] == 0) { 113 | return NULL; 114 | } else { 115 | char* p = NULL; 116 | while ((strlen(idevicerestore_err_buff) > 0) && (p = strrchr(idevicerestore_err_buff, '\n'))) { 117 | p[0] = '\0'; 118 | } 119 | return (const char*)idevicerestore_err_buff; 120 | } 121 | } 122 | 123 | int write_file(const char* filename, const void* data, size_t size) { 124 | size_t bytes = 0; 125 | FILE* file = NULL; 126 | 127 | debug("Writing data to %s\n", filename); 128 | file = fopen(filename, "wb"); 129 | if (file == NULL) { 130 | error("read_file: Unable to open file %s\n", filename); 131 | return -1; 132 | } 133 | 134 | bytes = fwrite(data, 1, size, file); 135 | fclose(file); 136 | 137 | if (bytes != size) { 138 | error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size); 139 | return -1; 140 | } 141 | 142 | return size; 143 | } 144 | 145 | int read_file(const char* filename, void** data, size_t* size) { 146 | size_t bytes = 0; 147 | size_t length = 0; 148 | FILE* file = NULL; 149 | char* buffer = NULL; 150 | debug("Reading data from %s\n", filename); 151 | 152 | *size = 0; 153 | *data = NULL; 154 | 155 | file = fopen(filename, "rb"); 156 | if (file == NULL) { 157 | error("read_file: File %s not found\n", filename); 158 | return -1; 159 | } 160 | 161 | fseek(file, 0, SEEK_END); 162 | length = ftell(file); 163 | rewind(file); 164 | 165 | buffer = (char*) malloc(length); 166 | if (buffer == NULL) { 167 | error("ERROR: Out of memory\n"); 168 | fclose(file); 169 | return -1; 170 | } 171 | bytes = fread(buffer, 1, length, file); 172 | fclose(file); 173 | 174 | if (bytes != length) { 175 | error("ERROR: Unable to read entire file\n"); 176 | free(buffer); 177 | return -1; 178 | } 179 | 180 | *size = length; 181 | *data = buffer; 182 | return 0; 183 | } 184 | 185 | void debug_plist(plist_t plist) { 186 | uint32_t size = 0; 187 | char* data = NULL; 188 | plist_to_xml(plist, &data, &size); 189 | info("%s", data); 190 | free(data); 191 | } 192 | 193 | void print_progress_bar(double progress) { 194 | #ifndef WIN32 195 | if (info_disabled) return; 196 | int i = 0; 197 | if(progress < 0) return; 198 | if(progress > 100) progress = 100; 199 | info("\r["); 200 | for(i = 0; i < 50; i++) { 201 | if(i < progress / 2) info("="); 202 | else info(" "); 203 | } 204 | info("] %5.1f%%", progress); 205 | if(progress == 100) info("\n"); 206 | fflush((info_stream) ? info_stream : stdout); 207 | #endif 208 | } 209 | 210 | #define GET_RAND(min, max) ((rand() % (max - min)) + min) 211 | 212 | char *generate_guid() 213 | { 214 | char *guid = (char *) malloc(sizeof(char) * 37); 215 | const char *chars = "ABCDEF0123456789"; 216 | srand(time(NULL)); 217 | int i = 0; 218 | 219 | for (i = 0; i < 36; i++) { 220 | if (i == 8 || i == 13 || i == 18 || i == 23) { 221 | guid[i] = '-'; 222 | continue; 223 | } else { 224 | guid[i] = chars[GET_RAND(0, 16)]; 225 | } 226 | } 227 | guid[36] = '\0'; 228 | return guid; 229 | } 230 | 231 | int mkdir_with_parents(const char *dir, int mode) 232 | { 233 | if (!dir) return -1; 234 | if (__mkdir(dir, mode) == 0) { 235 | return 0; 236 | } else { 237 | if (errno == EEXIST) return 0; 238 | } 239 | int res; 240 | char *parent = strdup(dir); 241 | parent = dirname(parent); 242 | if (parent && (strcmp(parent, ".") != 0) && (strcmp(parent, dir) != 0)) { 243 | res = mkdir_with_parents(parent, mode); 244 | } else { 245 | res = -1; 246 | } 247 | free(parent); 248 | if (res == 0) { 249 | mkdir_with_parents(dir, mode); 250 | } 251 | return res; 252 | } 253 | 254 | void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress) 255 | { 256 | if(client && client->progress_cb) { 257 | client->progress_cb(step, progress, client->progress_cb_data); 258 | } else { 259 | // we don't want to be too verbose in regular idevicerestore. 260 | if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_FLASH_FS) || (step == RESTORE_STEP_FLASH_NOR)) { 261 | print_progress_bar(100.0f * progress); 262 | } 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * common.h 3 | * Misc functions used in idevicerestore 4 | * 5 | * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_COMMON_H 25 | #define IDEVICERESTORE_COMMON_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include 33 | 34 | #include "idevicerestore.h" 35 | 36 | #define MODE_UNKNOWN -1 37 | #define MODE_WTF 0 38 | #define MODE_DFU 1 39 | #define MODE_RECOVERY 2 40 | #define MODE_RESTORE 3 41 | #define MODE_NORMAL 4 42 | 43 | #define FLAG_QUIT 1 44 | 45 | struct dfu_client_t; 46 | struct normal_client_t; 47 | struct restore_client_t; 48 | struct recovery_client_t; 49 | 50 | struct idevicerestore_mode_t { 51 | int index; 52 | const char* string; 53 | }; 54 | 55 | struct idevicerestore_entry_t { 56 | char* name; 57 | char* path; 58 | char* filename; 59 | char* blob_data; 60 | uint32_t blob_size; 61 | struct idevicerestore_entry* next; 62 | struct idevicerestore_entry* prev; 63 | }; 64 | 65 | struct idevicerestore_client_t { 66 | int flags; 67 | plist_t tss; 68 | char* tss_url; 69 | plist_t version_data; 70 | uint64_t ecid; 71 | unsigned char* nonce; 72 | int nonce_size; 73 | char* udid; 74 | char* srnm; 75 | char* ipsw; 76 | const char* filesystem; 77 | struct dfu_client_t* dfu; 78 | struct normal_client_t* normal; 79 | struct restore_client_t* restore; 80 | struct recovery_client_t* recovery; 81 | irecv_device_t device; 82 | struct idevicerestore_entry_t** entries; 83 | struct idevicerestore_mode_t* mode; 84 | char* version; 85 | char* build; 86 | int build_major; 87 | char* restore_boot_args; 88 | char* cache_dir; 89 | idevicerestore_progress_cb_t progress_cb; 90 | void* progress_cb_data; 91 | }; 92 | 93 | static struct idevicerestore_mode_t idevicerestore_modes[] = { 94 | { 0, "WTF" }, 95 | { 1, "DFU" }, 96 | { 2, "Recovery" }, 97 | { 3, "Restore" }, 98 | { 4, "Normal" }, 99 | { -1, NULL } 100 | }; 101 | 102 | extern int idevicerestore_debug; 103 | 104 | void info(const char* format, ...); 105 | void error(const char* format, ...); 106 | void debug(const char* format, ...); 107 | 108 | void debug_plist(plist_t plist); 109 | void print_progress_bar(double progress); 110 | int read_file(const char* filename, void** data, size_t* size); 111 | int write_file(const char* filename, const void* data, size_t size); 112 | 113 | char *generate_guid(); 114 | 115 | #ifdef WIN32 116 | #include 117 | #define __mkdir(path, mode) mkdir(path) 118 | #define FMT_qu "%I64u" 119 | #ifndef sleep 120 | #define sleep(x) Sleep(x*1000) 121 | #endif 122 | #else 123 | #include 124 | #define __mkdir(path, mode) mkdir(path, mode) 125 | #define FMT_qu "%qu" 126 | #endif 127 | 128 | int mkdir_with_parents(const char *dir, int mode); 129 | 130 | void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress); 131 | 132 | #ifdef __cplusplus 133 | } 134 | #endif 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /src/dfu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dfu.c 3 | * Functions for handling idevices in DFU mode 4 | * 5 | * Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "dfu.h" 31 | #include "tss.h" 32 | #include "recovery.h" 33 | #include "idevicerestore.h" 34 | #include "common.h" 35 | 36 | int dfu_progress_callback(irecv_client_t client, const irecv_event_t* event) { 37 | if (event->type == IRECV_PROGRESS) { 38 | print_progress_bar(event->progress); 39 | } 40 | return 0; 41 | } 42 | 43 | int dfu_client_new(struct idevicerestore_client_t* client) { 44 | int i = 0; 45 | int attempts = 10; 46 | irecv_client_t dfu = NULL; 47 | irecv_error_t dfu_error = IRECV_E_UNKNOWN_ERROR; 48 | 49 | if (client->dfu == NULL) { 50 | client->dfu = (struct dfu_client_t*)malloc(sizeof(struct dfu_client_t)); 51 | memset(client->dfu, 0, sizeof(struct dfu_client_t)); 52 | if (client->dfu == NULL) { 53 | error("ERROR: Out of memory\n"); 54 | return -1; 55 | } 56 | } 57 | 58 | for (i = 1; i <= attempts; i++) { 59 | dfu_error = irecv_open_with_ecid(&dfu, client->ecid); 60 | if (dfu_error == IRECV_E_SUCCESS) { 61 | break; 62 | } 63 | 64 | if (i >= attempts) { 65 | error("ERROR: Unable to connect to device in DFU mode\n"); 66 | return -1; 67 | } 68 | 69 | sleep(1); 70 | debug("Retrying connection...\n"); 71 | } 72 | 73 | irecv_event_subscribe(dfu, IRECV_PROGRESS, &dfu_progress_callback, NULL); 74 | client->dfu->client = dfu; 75 | return 0; 76 | } 77 | 78 | void dfu_client_free(struct idevicerestore_client_t* client) { 79 | if(client != NULL) { 80 | if (client->dfu != NULL) { 81 | if(client->dfu->client != NULL) { 82 | irecv_close(client->dfu->client); 83 | client->dfu->client = NULL; 84 | } 85 | free(client->dfu); 86 | } 87 | client->dfu = NULL; 88 | } 89 | } 90 | 91 | int dfu_check_mode(struct idevicerestore_client_t* client, int* mode) { 92 | irecv_client_t dfu = NULL; 93 | irecv_error_t dfu_error = IRECV_E_SUCCESS; 94 | int probe_mode = -1; 95 | 96 | irecv_init(); 97 | dfu_error = irecv_open_with_ecid(&dfu, client->ecid); 98 | if (dfu_error != IRECV_E_SUCCESS) { 99 | return -1; 100 | } 101 | 102 | irecv_get_mode(dfu, &probe_mode); 103 | 104 | if ((probe_mode != IRECV_K_DFU_MODE) && (probe_mode != IRECV_K_WTF_MODE)) { 105 | irecv_close(dfu); 106 | return -1; 107 | } 108 | 109 | *mode = (probe_mode == IRECV_K_WTF_MODE) ? MODE_WTF : MODE_DFU; 110 | 111 | irecv_close(dfu); 112 | 113 | return 0; 114 | } 115 | 116 | const char* dfu_check_product_type(struct idevicerestore_client_t* client) { 117 | irecv_client_t dfu = NULL; 118 | irecv_error_t dfu_error = IRECV_E_SUCCESS; 119 | irecv_device_t device = NULL; 120 | 121 | irecv_init(); 122 | dfu_error = irecv_open_with_ecid(&dfu, client->ecid); 123 | if (dfu_error != IRECV_E_SUCCESS) { 124 | return NULL; 125 | } 126 | 127 | dfu_error = irecv_devices_get_device_by_client(dfu, &device); 128 | if (dfu_error != IRECV_E_SUCCESS) { 129 | return NULL; 130 | } 131 | 132 | irecv_close(dfu); 133 | 134 | return device->product_type; 135 | } 136 | 137 | int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size) 138 | { 139 | irecv_error_t err = 0; 140 | 141 | info("Sending data (%d bytes)...\n", size); 142 | 143 | err = irecv_send_buffer(client->dfu->client, buffer, size, 1); 144 | if (err != IRECV_E_SUCCESS) { 145 | error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); 146 | return -1; 147 | } 148 | 149 | err = irecv_reset(client->dfu->client); 150 | if (err != IRECV_E_SUCCESS) { 151 | error("ERROR: Unable to reset device\n"); 152 | irecv_close(client->dfu->client); 153 | client->dfu->client = NULL; 154 | return -1; 155 | } 156 | 157 | return 0; 158 | } 159 | 160 | int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) { 161 | uint32_t size = 0; 162 | unsigned char* data = NULL; 163 | char* path = NULL; 164 | unsigned char* blob = NULL; 165 | irecv_error_t err = 0; 166 | int flag = 1; 167 | 168 | if (client->tss) { 169 | if (tss_get_entry_path(client->tss, component, &path) < 0) { 170 | debug("NOTE: No path for component %s in TSS, will fetch from build_identity\n", component); 171 | } 172 | } 173 | if (!path) { 174 | if (build_identity_get_component_path(build_identity, component, &path) < 0) { 175 | error("ERROR: Unable to get path for component '%s'\n", component); 176 | if (path) 177 | free(path); 178 | return -1; 179 | } 180 | } 181 | 182 | if (ipsw_get_component_by_path(client->ipsw, client->tss, component, path, &data, &size) < 0) { 183 | error("ERROR: Unable to get component: %s\n", component); 184 | free(path); 185 | return -1; 186 | } 187 | 188 | if (!(client->flags & FLAG_CUSTOM) && (strcmp(component, "iBEC") == 0)) { 189 | unsigned char* ticket = NULL; 190 | unsigned int tsize = 0; 191 | if (tss_get_ticket(client->tss, &ticket, &tsize) < 0) { 192 | error("ERROR: Unable to get ApTicket from TSS request\n"); 193 | return -1; 194 | } 195 | uint32_t fillsize = 0; 196 | if ((tsize % 0x100) != 0) { 197 | fillsize = ((tsize / 0x100) + 1) * 0x100; 198 | } 199 | debug("ticket size = %d\nfillsize = %d\n", tsize, fillsize); 200 | unsigned char* newdata = (unsigned char*)malloc(size + fillsize); 201 | memcpy(newdata, ticket, tsize); 202 | memset(newdata+tsize, '\xFF', fillsize - tsize); 203 | memcpy(newdata+fillsize, data, size); 204 | free(data); 205 | data = newdata; 206 | size += fillsize; 207 | flag = 1; 208 | } 209 | 210 | info("Sending %s (%d bytes)...\n", component, size); 211 | 212 | // FIXME: Did I do this right???? 213 | err = irecv_send_buffer(client->dfu->client, data, size, flag); 214 | free(path); 215 | if (err != IRECV_E_SUCCESS) { 216 | error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err)); 217 | free(data); 218 | return -1; 219 | } 220 | 221 | free(data); 222 | return 0; 223 | } 224 | 225 | int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) { 226 | irecv_error_t dfu_error = IRECV_E_SUCCESS; 227 | 228 | if(client->dfu == NULL) { 229 | if (dfu_client_new(client) < 0) { 230 | return -1; 231 | } 232 | } 233 | 234 | dfu_error = irecv_get_cpid(client->dfu->client, cpid); 235 | if (dfu_error != IRECV_E_SUCCESS) { 236 | return -1; 237 | } 238 | 239 | return 0; 240 | } 241 | 242 | int dfu_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) { 243 | irecv_error_t dfu_error = IRECV_E_SUCCESS; 244 | 245 | if(client->dfu == NULL) { 246 | if (dfu_client_new(client) < 0) { 247 | return -1; 248 | } 249 | } 250 | 251 | dfu_error = irecv_get_nonce(client->dfu->client, nonce, nonce_size); 252 | if (dfu_error != IRECV_E_SUCCESS) { 253 | return -1; 254 | } 255 | 256 | return 0; 257 | } 258 | 259 | int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity) { 260 | irecv_error_t dfu_error = IRECV_E_SUCCESS; 261 | int mode = 0; 262 | 263 | if (dfu_client_new(client) < 0) { 264 | error("ERROR: Unable to connect to DFU device\n"); 265 | return -1; 266 | } 267 | 268 | irecv_get_mode(client->dfu->client, &mode); 269 | 270 | if (mode != IRECV_K_DFU_MODE) { 271 | info("NOTE: device is not in DFU mode, assuming recovery mode.\n"); 272 | client->mode = &idevicerestore_modes[MODE_RECOVERY]; 273 | return 0; 274 | } 275 | 276 | if (dfu_send_component(client, build_identity, "iBSS") < 0) { 277 | error("ERROR: Unable to send iBSS to device\n"); 278 | irecv_close(client->dfu->client); 279 | client->dfu->client = NULL; 280 | return -1; 281 | } 282 | 283 | irecv_usb_control_transfer(client->dfu->client, 0x21, 1, 0, 0, 0, 0, 5000); 284 | 285 | dfu_error = irecv_reset(client->dfu->client); 286 | if (dfu_error != IRECV_E_SUCCESS) { 287 | error("ERROR: Unable to reset device\n"); 288 | irecv_close(client->dfu->client); 289 | client->dfu->client = NULL; 290 | return -1; 291 | } 292 | 293 | if (client->build_major > 8) { 294 | /* reconnect */ 295 | dfu_client_free(client); 296 | sleep(2); 297 | dfu_client_new(client); 298 | 299 | /* get nonce */ 300 | unsigned char* nonce = NULL; 301 | int nonce_size = 0; 302 | int nonce_changed = 0; 303 | if (dfu_get_nonce(client, &nonce, &nonce_size) < 0) { 304 | error("ERROR: Unable to get nonce from device!\n"); 305 | return -1; 306 | } 307 | 308 | if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) { 309 | nonce_changed = 1; 310 | if (client->nonce) { 311 | free(client->nonce); 312 | } 313 | client->nonce = nonce; 314 | client->nonce_size = nonce_size; 315 | } else { 316 | free(nonce); 317 | } 318 | 319 | info("Nonce: "); 320 | int i; 321 | for (i = 0; i < client->nonce_size; i++) { 322 | info("%02x ", client->nonce[i]); 323 | } 324 | info("\n"); 325 | 326 | if (nonce_changed && !(client->flags & FLAG_CUSTOM)) { 327 | // Welcome iOS5. We have to re-request the TSS with our nonce. 328 | plist_free(client->tss); 329 | if (get_shsh_blobs(client, client->ecid, client->nonce, client->nonce_size, build_identity, &client->tss) < 0) { 330 | error("ERROR: Unable to get SHSH blobs for this device\n"); 331 | return -1; 332 | } 333 | if (!client->tss) { 334 | error("ERROR: can't continue without TSS\n"); 335 | return -1; 336 | } 337 | fixup_tss(client->tss); 338 | } 339 | 340 | if (irecv_usb_set_configuration(client->dfu->client, 1) < 0) { 341 | error("ERROR: set configuration failed\n"); 342 | } 343 | 344 | /* send iBEC */ 345 | if (dfu_send_component(client, build_identity, "iBEC") < 0) { 346 | error("ERROR: Unable to send iBEC to device\n"); 347 | irecv_close(client->dfu->client); 348 | client->dfu->client = NULL; 349 | return -1; 350 | } 351 | 352 | irecv_usb_control_transfer(client->dfu->client, 0x21, 1, 0, 0, 0, 0, 5000); 353 | 354 | dfu_error = irecv_reset(client->dfu->client); 355 | if (dfu_error != IRECV_E_SUCCESS) { 356 | error("ERROR: Unable to reset device\n"); 357 | irecv_close(client->dfu->client); 358 | client->dfu->client = NULL; 359 | return -1; 360 | } 361 | } 362 | 363 | dfu_client_free(client); 364 | 365 | sleep(7); 366 | 367 | // Reconnect to device, but this time make sure we're not still in DFU mode 368 | if (recovery_client_new(client) < 0) { 369 | error("ERROR: Unable to connect to recovery device\n"); 370 | if (client->recovery->client) { 371 | irecv_close(client->recovery->client); 372 | client->recovery->client = NULL; 373 | } 374 | return -1; 375 | } 376 | 377 | irecv_get_mode(client->recovery->client, &mode); 378 | 379 | if (mode == IRECV_K_DFU_MODE) { 380 | error("ERROR: Unable to connect to recovery device\n"); 381 | if (client->recovery->client) { 382 | irecv_close(client->recovery->client); 383 | client->recovery->client = NULL; 384 | } 385 | return -1; 386 | } 387 | 388 | return 0; 389 | } 390 | 391 | -------------------------------------------------------------------------------- /src/dfu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dfu.h 3 | * Functions for handling idevices in normal mode 4 | * 5 | * Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_DFU_H 25 | #define IDEVICERESTORE_DFU_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include "common.h" 33 | 34 | struct dfu_client_t { 35 | irecv_client_t client; 36 | const char* ipsw; 37 | plist_t tss; 38 | }; 39 | 40 | int dfu_client_new(struct idevicerestore_client_t* client); 41 | void dfu_client_free(struct idevicerestore_client_t* client); 42 | int dfu_check_mode(struct idevicerestore_client_t* client, int* mode); 43 | const char* dfu_check_product_type(struct idevicerestore_client_t* client); 44 | int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size); 45 | int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); 46 | int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid); 47 | int dfu_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); 48 | int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity); 49 | 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/download.c: -------------------------------------------------------------------------------- 1 | /* 2 | * download.c 3 | * file download helper functions 4 | * 5 | * Copyright (c) 2012-2013 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "download.h" 28 | #include "common.h" 29 | 30 | #ifdef WIN32 31 | #define ftello(x) ftell(x) 32 | #endif 33 | 34 | typedef struct { 35 | int length; 36 | char* content; 37 | } curl_response; 38 | 39 | static size_t download_write_buffer_callback(char* data, size_t size, size_t nmemb, curl_response* response) { 40 | size_t total = size * nmemb; 41 | if (total != 0) { 42 | response->content = realloc(response->content, response->length + total + 1); 43 | memcpy(response->content + response->length, data, total); 44 | response->content[response->length + total] = '\0'; 45 | response->length += total; 46 | } 47 | return total; 48 | } 49 | 50 | int download_to_buffer(const char* url, char** buf, uint32_t* length) 51 | { 52 | int res = 0; 53 | curl_global_init(CURL_GLOBAL_ALL); 54 | CURL* handle = curl_easy_init(); 55 | if (handle == NULL) { 56 | error("ERROR: could not initialize CURL\n"); 57 | return -1; 58 | } 59 | 60 | curl_response response; 61 | response.length = 0; 62 | response.content = malloc(1); 63 | response.content[0] = '\0'; 64 | 65 | if (idevicerestore_debug) 66 | curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); 67 | 68 | /* disable SSL verification to allow download from untrusted https locations */ 69 | curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); 70 | 71 | curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&download_write_buffer_callback); 72 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, &response); 73 | curl_easy_setopt(handle, CURLOPT_USERAGENT, "InetURL/1.0"); 74 | curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); 75 | curl_easy_setopt(handle, CURLOPT_URL, url); 76 | 77 | curl_easy_perform(handle); 78 | curl_easy_cleanup(handle); 79 | 80 | if (response.length > 0) { 81 | *length = response.length; 82 | *buf = response.content; 83 | } else { 84 | res = -1; 85 | } 86 | 87 | curl_global_cleanup(); 88 | 89 | return res; 90 | } 91 | 92 | static int lastprogress = 0; 93 | 94 | int download_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) 95 | { 96 | double p = (dlnow / dltotal) * 100; 97 | 98 | if (p < 100.0f) { 99 | if ((int)p > lastprogress) { 100 | info("downloading: %d%%\n", (int)p); 101 | lastprogress = (int)p; 102 | } 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | int download_to_file(const char* url, const char* filename, int enable_progress) 109 | { 110 | int res = 0; 111 | curl_global_init(CURL_GLOBAL_ALL); 112 | CURL* handle = curl_easy_init(); 113 | if (handle == NULL) { 114 | error("ERROR: could not initialize CURL\n"); 115 | return -1; 116 | } 117 | 118 | FILE* f = fopen(filename, "wb"); 119 | if (!f) { 120 | error("ERROR: cannot open '%s' for writing\n", filename); 121 | return -1; 122 | } 123 | 124 | lastprogress = 0; 125 | 126 | if (idevicerestore_debug) 127 | curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); 128 | 129 | /* disable SSL verification to allow download from untrusted https locations */ 130 | curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); 131 | 132 | curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, NULL); 133 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, f); 134 | 135 | if (enable_progress > 0) 136 | curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&download_progress); 137 | 138 | curl_easy_setopt(handle, CURLOPT_NOPROGRESS, enable_progress > 0 ? 0: 1); 139 | curl_easy_setopt(handle, CURLOPT_USERAGENT, "InetURL/1.0"); 140 | curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); 141 | curl_easy_setopt(handle, CURLOPT_URL, url); 142 | 143 | curl_easy_perform(handle); 144 | curl_easy_cleanup(handle); 145 | 146 | off_t sz = ftello(f); 147 | fclose(f); 148 | 149 | if ((sz == 0) || (sz == (off_t)-1)) { 150 | res = -1; 151 | remove(filename); 152 | } 153 | 154 | curl_global_cleanup(); 155 | 156 | return res; 157 | } 158 | -------------------------------------------------------------------------------- /src/download.h: -------------------------------------------------------------------------------- 1 | /* 2 | * download.h 3 | * file download helper functions (header file) 4 | * 5 | * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef IDEVICERESTORE_DOWNLOAD_H 23 | #define IDEVICERESTORE_DOWNLOAD_H 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include 30 | 31 | int download_to_buffer(const char* url, char** buf, uint32_t* length); 32 | int download_to_file(const char* url, const char* filename, int enable_progress); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/fls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fls.c 3 | * support for .fls file format (found in .bbfw files) 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include 22 | #include 23 | #include 24 | #include "fls.h" 25 | #include "common.h" 26 | 27 | #ifndef offsetof 28 | #define offsetof(type, member) __builtin_offsetof (type, member) 29 | #endif 30 | 31 | static void fls_parse_elements(fls_file* fls) 32 | { 33 | /* FIXME: the following code is not big endian safe */ 34 | if (!fls || !fls->data) { 35 | return; 36 | } 37 | uint32_t offset = 0; 38 | uint32_t max = fls->size; 39 | fls->max_elements = 32; 40 | fls->elements = (fls_element**)malloc(sizeof(fls_element*) * fls->max_elements); 41 | 42 | fls_element* cur = NULL; 43 | do { 44 | void* p = fls->data + offset; 45 | uint32_t hdrsize = 0; 46 | cur = (fls_element*)p; 47 | if ((offset + cur->size) > fls->size) { 48 | break; 49 | } 50 | fls_element* ne; 51 | switch (cur->type) { 52 | case 0x0c: 53 | { 54 | hdrsize = offsetof(fls_0c_element, data); 55 | fls_0c_element* xe = (fls_0c_element*)malloc(sizeof(fls_0c_element)); 56 | memset(xe, '\0', sizeof(fls_0c_element)); 57 | memcpy((void*)xe, p, hdrsize); 58 | xe->data = (xe->size > hdrsize) ? xe->data = p + hdrsize : NULL; 59 | ne = (fls_element*)xe; 60 | fls->c_element = xe; 61 | } 62 | break; 63 | case 0x10: 64 | { 65 | hdrsize = offsetof(fls_10_element, data); 66 | fls_10_element* xe = (fls_10_element*)malloc(sizeof(fls_10_element)); 67 | memset(xe, '\0', sizeof(fls_10_element)); 68 | memcpy((void*)xe, p, hdrsize); 69 | xe->data = (xe->size > hdrsize) ? xe->data = p + hdrsize : NULL; 70 | ne = (fls_element*)xe; 71 | } 72 | break; 73 | case 0x14: 74 | { 75 | hdrsize = offsetof(fls_14_element, data); 76 | fls_14_element* xe = (fls_14_element*)malloc(sizeof(fls_14_element)); 77 | memset(xe, '\0', sizeof(fls_14_element)); 78 | memcpy((void*)xe, p, hdrsize); 79 | xe->data = (xe->size > hdrsize) ? xe->data = p + hdrsize : NULL; 80 | ne = (fls_element*)xe; 81 | } 82 | break; 83 | default: 84 | hdrsize = offsetof(fls_element, data); 85 | ne = (fls_element*)malloc(sizeof(fls_element)); 86 | memset(ne, '\0', sizeof(fls_element)); 87 | ne->type = cur->type; 88 | ne->size = cur->size; 89 | ne->data = (ne->size > hdrsize) ? ne->data = p + hdrsize : NULL; 90 | break; 91 | } 92 | if ((fls->num_elements + 1) > fls->max_elements) { 93 | fls->max_elements += 10; 94 | fls->elements = (fls_element**)realloc(fls->elements, sizeof(fls_element*) * fls->max_elements); 95 | } 96 | fls->elements[fls->num_elements++] = ne; 97 | offset += cur->size; 98 | } while (offset < fls->size); 99 | if (offset != fls->size) { 100 | error("ERROR: %s: error parsing elements\n", __func__); 101 | return; 102 | } 103 | } 104 | 105 | fls_file* fls_parse(unsigned char* data, unsigned int size) 106 | { 107 | fls_file* fls = (fls_file*)malloc(sizeof(fls_file)); 108 | if (!fls) { 109 | return NULL; 110 | } 111 | memset(fls, '\0', sizeof(fls_file)); 112 | fls->data = malloc(size); 113 | fls->size = size; 114 | memcpy(fls->data, data, size); 115 | fls_parse_elements(fls); 116 | return fls; 117 | } 118 | 119 | void fls_free(fls_file* fls) 120 | { 121 | if (fls) { 122 | if (fls->num_elements > 0) { 123 | int i; 124 | for (i = fls->num_elements-1; i >=0; i--) { 125 | free(fls->elements[i]); 126 | } 127 | free(fls->elements); 128 | } 129 | if (fls->data) { 130 | free(fls->data); 131 | } 132 | free(fls); 133 | } 134 | } 135 | 136 | int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned int siglen) 137 | { 138 | /* FIXME: the code in this function is not big endian safe */ 139 | if (!fls || !fls->num_elements) { 140 | error("ERROR: %s: no data\n", __func__); 141 | return -1; 142 | } 143 | if (!fls->c_element) { 144 | error("ERROR: %s: no fls_0c_element in fls data\n", __func__); 145 | return -1; 146 | } 147 | 148 | uint32_t datasize = *(uint32_t*)(fls->c_element->data + 0x10); 149 | if (datasize != fls->c_element->data_size) { 150 | error("ERROR: %s: data size mismatch (0x%x != 0x%x)\n", __func__, datasize, fls->c_element->data_size); 151 | return -1; 152 | } 153 | uint32_t sigoffset = *(uint32_t*)(fls->c_element->data + 0x14); 154 | if (sigoffset > datasize) { 155 | error("ERROR: %s: signature offset greater than data size (0x%x > 0x%x)\n", __func__, sigoffset, datasize); 156 | return -1; 157 | } 158 | 159 | uint32_t oldsiglen = datasize - sigoffset; 160 | uint32_t newsize = fls->size - oldsiglen + siglen; 161 | 162 | int i; 163 | uint32_t offset = 0; 164 | void* newdata = malloc(newsize); 165 | if (!newdata) { 166 | error("ERROR: %s: out of memory\n", __func__); 167 | return -1; 168 | } 169 | uint32_t hdrsize = 0; 170 | uint32_t firstpartlen = 0; 171 | for (i = 0; i < fls->num_elements; i++) { 172 | switch (fls->elements[i]->type) { 173 | case 0x0c: 174 | hdrsize = offsetof(fls_0c_element, data); 175 | // update offset 176 | ((fls_0c_element*)fls->elements[i])->offset = offset+hdrsize; 177 | // copy first part of data 178 | firstpartlen = fls->elements[i]->size - hdrsize - oldsiglen; 179 | memcpy(newdata+offset+hdrsize, ((fls_0c_element*)fls->elements[i])->data, firstpartlen); 180 | // copy new signature data 181 | memcpy(newdata+offset+hdrsize+firstpartlen, sigdata, siglen); 182 | ((fls_0c_element*)fls->elements[i])->data = newdata+offset+hdrsize; 183 | fls->elements[i]->size -= oldsiglen; 184 | fls->elements[i]->size += siglen; 185 | ((fls_0c_element*)fls->elements[i])->data_size -= oldsiglen; 186 | ((fls_0c_element*)fls->elements[i])->data_size += siglen; 187 | memcpy(newdata+offset+hdrsize+0x10, &(((fls_0c_element*)fls->elements[i])->data_size), 4); 188 | // copy header 189 | memcpy(newdata+offset, fls->elements[i], hdrsize); 190 | break; 191 | case 0x10: 192 | hdrsize = offsetof(fls_10_element, data); 193 | // update offset 194 | ((fls_10_element*)fls->elements[i])->offset = offset+hdrsize; 195 | // copy header 196 | memcpy(newdata+offset, fls->elements[i], hdrsize); 197 | // copy data 198 | if (fls->elements[i]->size > hdrsize) { 199 | memcpy(newdata+offset+hdrsize, ((fls_10_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize); 200 | ((fls_10_element*)fls->elements[i])->data = newdata+offset+hdrsize; 201 | } else { 202 | ((fls_10_element*)fls->elements[i])->data = NULL; 203 | } 204 | break; 205 | case 0x14: 206 | hdrsize = offsetof(fls_14_element, data); 207 | // update offset 208 | ((fls_14_element*)fls->elements[i])->offset = offset+hdrsize; 209 | // copy header 210 | memcpy(newdata+offset, fls->elements[i], hdrsize); 211 | // copy data 212 | if (fls->elements[i]->size > hdrsize) { 213 | memcpy(newdata+offset+hdrsize, ((fls_14_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize); 214 | ((fls_14_element*)fls->elements[i])->data = newdata+offset+hdrsize; 215 | } else { 216 | ((fls_14_element*)fls->elements[i])->data = NULL; 217 | } 218 | break; 219 | default: 220 | hdrsize = offsetof(fls_element, data); 221 | // copy header 222 | memcpy(newdata+offset, fls->elements[i], hdrsize); 223 | // copy data 224 | if (fls->elements[i]->size > hdrsize) { 225 | memcpy(newdata+offset+hdrsize, fls->elements[i]->data, fls->elements[i]->size - hdrsize); 226 | fls->elements[i]->data = newdata+offset+hdrsize; 227 | } else { 228 | fls->elements[i]->data = NULL; 229 | } 230 | break; 231 | } 232 | offset += fls->elements[i]->size; 233 | } 234 | if (fls->data) { 235 | free(fls->data); 236 | } 237 | fls->data = newdata; 238 | fls->size = newsize; 239 | 240 | return 0; 241 | } 242 | 243 | int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size) 244 | { 245 | /* FIXME: the code in this function is not big endian safe */ 246 | if (!fls || !fls->num_elements) { 247 | error("ERROR: %s: no data\n", __func__); 248 | return -1; 249 | } 250 | if (!fls->c_element) { 251 | error("ERROR: %s: no fls_0c_element in fls data\n", __func__); 252 | return -1; 253 | } 254 | 255 | uint32_t padding = 0; 256 | if (size%4 != 0) { 257 | padding = 4-(size%4); 258 | } 259 | uint32_t newsize = fls->size + size + padding; 260 | int i; 261 | uint32_t offset = 0; 262 | void* newdata = malloc(newsize); 263 | if (!newdata) { 264 | error("ERROR: %s: out of memory\n", __func__); 265 | return -1; 266 | } 267 | uint32_t hdrsize = 0; 268 | for (i = 0; i < fls->num_elements; i++) { 269 | switch (fls->elements[i]->type) { 270 | case 0x0c: 271 | hdrsize = offsetof(fls_0c_element, data); 272 | // update offset 273 | ((fls_0c_element*)fls->elements[i])->offset = offset+hdrsize; 274 | // copy ticket data 275 | memcpy(newdata+offset+hdrsize, data, size); 276 | if (padding > 0) { 277 | // padding 278 | memset(newdata+offset+hdrsize+size, '\xFF', padding); 279 | } 280 | // copy remaining data 281 | memcpy(newdata+offset+hdrsize+size+padding, ((fls_0c_element*)fls->elements[i])->data, fls->elements[i]->size); 282 | ((fls_0c_element*)fls->elements[i])->data = newdata+offset+hdrsize; 283 | fls->elements[i]->size += (size + padding); 284 | ((fls_0c_element*)fls->elements[i])->data_size += (size + padding); 285 | // copy header 286 | memcpy(newdata+offset, fls->elements[i], hdrsize); 287 | break; 288 | case 0x10: 289 | hdrsize = offsetof(fls_10_element, data); 290 | // update offset 291 | ((fls_10_element*)fls->elements[i])->offset = offset+hdrsize; 292 | // copy header 293 | memcpy(newdata+offset, fls->elements[i], hdrsize); 294 | // copy data 295 | if (fls->elements[i]->size > hdrsize) { 296 | memcpy(newdata+offset+hdrsize, ((fls_10_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize); 297 | ((fls_10_element*)fls->elements[i])->data = newdata+offset+hdrsize; 298 | } else { 299 | ((fls_10_element*)fls->elements[i])->data = NULL; 300 | } 301 | break; 302 | case 0x14: 303 | hdrsize = offsetof(fls_14_element, data); 304 | // update offset 305 | ((fls_14_element*)fls->elements[i])->offset = offset+hdrsize; 306 | // copy header 307 | memcpy(newdata+offset, fls->elements[i], hdrsize); 308 | // copy data 309 | if (fls->elements[i]->size > hdrsize) { 310 | memcpy(newdata+offset+hdrsize, ((fls_14_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize); 311 | ((fls_14_element*)fls->elements[i])->data = newdata+offset+hdrsize; 312 | } else { 313 | ((fls_14_element*)fls->elements[i])->data = NULL; 314 | } 315 | break; 316 | default: 317 | hdrsize = offsetof(fls_element, data); 318 | // copy header 319 | memcpy(newdata+offset, fls->elements[i], hdrsize); 320 | // copy data 321 | if (fls->elements[i]->size > hdrsize) { 322 | memcpy(newdata+offset+hdrsize, fls->elements[i]->data, fls->elements[i]->size - hdrsize); 323 | fls->elements[i]->data = newdata+offset+hdrsize; 324 | } else { 325 | fls->elements[i]->data = NULL; 326 | } 327 | break; 328 | } 329 | offset += fls->elements[i]->size; 330 | } 331 | if (fls->data) { 332 | free(fls->data); 333 | } 334 | fls->data = newdata; 335 | fls->size = newsize; 336 | 337 | return 0; 338 | } 339 | 340 | -------------------------------------------------------------------------------- /src/fls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * fls.h 3 | * support for .fls file format (found in .bbfw files) 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef FLS_H 22 | #define FLS_H 23 | 24 | #include 25 | 26 | struct _fls_element { 27 | uint32_t type; 28 | uint32_t size; 29 | uint32_t empty; 30 | const unsigned char* data; 31 | } __attribute__((packed)); 32 | typedef struct _fls_element fls_element; 33 | 34 | struct _fls_0c_element { 35 | uint32_t type; 36 | uint32_t size; 37 | uint32_t empty; 38 | uint32_t off_0x0c; 39 | uint32_t off_0x10; 40 | uint32_t off_0x14; 41 | uint32_t off_0x18; 42 | uint32_t data_size; // size without header 43 | uint32_t off_0x20; 44 | uint32_t offset; // absolute offset of data in file 45 | const unsigned char* data; // data+0x14 contains offset to sig blob 46 | } __attribute__((packed)); 47 | typedef struct _fls_0c_element fls_0c_element; 48 | 49 | struct _fls_10_element { 50 | uint32_t type; 51 | uint32_t size; 52 | uint32_t empty; 53 | uint32_t data_size; // size without header 54 | uint32_t off_0x10; 55 | uint32_t offset; 56 | const unsigned char* data; 57 | } __attribute__((packed)); 58 | typedef struct _fls_10_element fls_10_element; 59 | 60 | struct _fls_14_element { 61 | uint32_t type; 62 | uint32_t size; 63 | uint32_t empty; 64 | uint32_t data_size; // size without header 65 | uint32_t off_0x10; 66 | uint32_t offset; 67 | const unsigned char* data; 68 | } __attribute__((packed)); 69 | typedef struct _fls_14_element fls_14_element; 70 | 71 | typedef struct { 72 | unsigned int num_elements; 73 | unsigned int max_elements; 74 | fls_element** elements; 75 | const fls_0c_element* c_element; 76 | void* data; 77 | uint32_t size; 78 | } fls_file; 79 | 80 | fls_file* fls_parse(unsigned char* data, unsigned int size); 81 | void fls_free(fls_file* fls); 82 | int fls_update_sig_blob(fls_file* fls, const unsigned char* data, unsigned int size); 83 | int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/idevicerestore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * idevicerestore.h 3 | * Restore device firmware and filesystem 4 | * 5 | * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_H 25 | #define IDEVICERESTORE_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include 33 | 34 | // the flag with value 1 is reserved for internal use only. don't use it. 35 | #define FLAG_DEBUG 1 << 1 36 | #define FLAG_ERASE 1 << 2 37 | #define FLAG_CUSTOM 1 << 3 38 | #define FLAG_EXCLUDE 1 << 4 39 | #define FLAG_PWN 1 << 5 40 | #define FLAG_NOACTION 1 << 6 41 | #define FLAG_SHSHONLY 1 << 7 42 | #define FLAG_LATEST 1 << 8 43 | 44 | struct idevicerestore_client_t; 45 | 46 | enum { 47 | RESTORE_STEP_DETECT = 0, 48 | RESTORE_STEP_PREPARE, 49 | RESTORE_STEP_UPLOAD_FS, 50 | RESTORE_STEP_FLASH_FS, 51 | RESTORE_STEP_FLASH_NOR, 52 | RESTORE_STEP_FLASH_BB, 53 | RESTORE_NUM_STEPS 54 | }; 55 | 56 | typedef void (*idevicerestore_progress_cb_t)(int step, double step_progress, void* userdata); 57 | 58 | struct idevicerestore_client_t* idevicerestore_client_new(); 59 | void idevicerestore_client_free(struct idevicerestore_client_t* client); 60 | 61 | void idevicerestore_set_ecid(struct idevicerestore_client_t* client, unsigned long long ecid); 62 | void idevicerestore_set_udid(struct idevicerestore_client_t* client, const char* udid); 63 | void idevicerestore_set_flags(struct idevicerestore_client_t* client, int flags); 64 | void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* path); 65 | void idevicerestore_set_cache_path(struct idevicerestore_client_t* client, const char* path); 66 | void idevicerestore_set_progress_callback(struct idevicerestore_client_t* client, idevicerestore_progress_cb_t cbfunc, void* userdata); 67 | void idevicerestore_set_info_stream(FILE* strm); 68 | void idevicerestore_set_error_stream(FILE* strm); 69 | void idevicerestore_set_debug_stream(FILE* strm); 70 | 71 | int idevicerestore_start(struct idevicerestore_client_t* client); 72 | const char* idevicerestore_get_error(); 73 | 74 | void usage(int argc, char* argv[]); 75 | int check_mode(struct idevicerestore_client_t* client); 76 | const char* check_product_type(struct idevicerestore_client_t* client); 77 | int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); 78 | int get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); 79 | int get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); 80 | int get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); 81 | int get_shsh_blobs(struct idevicerestore_client_t* client, uint64_t ecid, unsigned char* nonce, int nonce_size, plist_t build_identity, plist_t* tss); 82 | void fixup_tss(plist_t tss); 83 | int build_manifest_get_identity_count(plist_t build_manifest); 84 | int build_manifest_check_compatibility(plist_t build_manifest, const char* product); 85 | void build_manifest_get_version_information(plist_t build_manifest, struct idevicerestore_client_t* client); 86 | plist_t build_manifest_get_build_identity(plist_t build_manifest, uint32_t identity); 87 | int build_manifest_get_build_count(plist_t build_manifest); 88 | void build_identity_print_information(plist_t build_identity); 89 | int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); 90 | int ipsw_extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem); 91 | int ipsw_get_component_by_path(const char* ipsw, plist_t tss, const char* component, const char* path, unsigned char** data, unsigned int* size); 92 | const char* get_component_name(const char* filename); 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /src/img3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * img3.c 3 | * Functions for handling with Apple's IMG3 format 4 | * 5 | * Copyright (c) 2012-2013 Nikias Bassen. All Rights Reserved. 6 | * Copyright (c) 2010 Martin Szulecki. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "img3.h" 29 | #include "common.h" 30 | #include "idevicerestore.h" 31 | 32 | img3_file* img3_parse_file(unsigned char* data, unsigned int size) { 33 | unsigned int data_offset = 0; 34 | img3_element* element; 35 | img3_header* header = (img3_header*) data; 36 | if (header->signature != kImg3Container) { 37 | error("ERROR: Invalid IMG3 file\n"); 38 | return NULL; 39 | } 40 | 41 | img3_file* image = (img3_file*) malloc(sizeof(img3_file)); 42 | if (image == NULL) { 43 | error("ERROR: Unable to allocate memory for IMG3 file\n"); 44 | return NULL; 45 | } 46 | memset(image, '\0', sizeof(img3_file)); 47 | image->idx_ecid_element = -1; 48 | image->idx_shsh_element = -1; 49 | image->idx_cert_element = -1; 50 | 51 | image->header = (img3_header*) malloc(sizeof(img3_header)); 52 | if (image->header == NULL) { 53 | error("ERROR: Unable to allocate memory for IMG3 header\n"); 54 | img3_free(image); 55 | return NULL; 56 | } 57 | memcpy(image->header, data, sizeof(img3_header)); 58 | data_offset += sizeof(img3_header); 59 | 60 | img3_element_header* current = NULL; 61 | while (data_offset < size) { 62 | current = (img3_element_header*) &data[data_offset]; 63 | switch (current->signature) { 64 | case kTypeElement: 65 | element = img3_parse_element(&data[data_offset]); 66 | if (element == NULL) { 67 | error("ERROR: Unable to parse TYPE element\n"); 68 | img3_free(image); 69 | return NULL; 70 | } 71 | image->elements[image->num_elements++] = element; 72 | debug("Parsed TYPE element\n"); 73 | break; 74 | 75 | case kDataElement: 76 | element = img3_parse_element(&data[data_offset]); 77 | if (element == NULL) { 78 | error("ERROR: Unable to parse DATA element\n"); 79 | img3_free(image); 80 | return NULL; 81 | } 82 | image->elements[image->num_elements++] = element; 83 | debug("Parsed DATA element\n"); 84 | break; 85 | 86 | case kVersElement: 87 | element = img3_parse_element(&data[data_offset]); 88 | if (element == NULL) { 89 | error("ERROR: Unable to parse VERS element\n"); 90 | img3_free(image); 91 | return NULL; 92 | } 93 | image->elements[image->num_elements++] = element; 94 | debug("Parsed VERS element\n"); 95 | break; 96 | 97 | case kSepoElement: 98 | element = img3_parse_element(&data[data_offset]); 99 | if (element == NULL) { 100 | error("ERROR: Unable to parse SEPO element\n"); 101 | img3_free(image); 102 | return NULL; 103 | } 104 | image->elements[image->num_elements++] = element; 105 | debug("Parsed SEPO element\n"); 106 | break; 107 | 108 | case kBordElement: 109 | element = img3_parse_element(&data[data_offset]); 110 | if (element == NULL) { 111 | error("ERROR: Unable to parse BORD element\n"); 112 | img3_free(image); 113 | return NULL; 114 | } 115 | image->elements[image->num_elements++] = element; 116 | debug("Parsed BORD element\n"); 117 | break; 118 | 119 | case kChipElement: 120 | element = img3_parse_element(&data[data_offset]); 121 | if (element == NULL) { 122 | error("ERROR: Unable to parse CHIP element\n"); 123 | img3_free(image); 124 | return NULL; 125 | } 126 | image->elements[image->num_elements++] = element; 127 | debug("Parsed CHIP element\n"); 128 | break; 129 | 130 | case kKbagElement: 131 | element = img3_parse_element(&data[data_offset]); 132 | if (element == NULL) { 133 | error("ERROR: Unable to parse first KBAG element\n"); 134 | img3_free(image); 135 | return NULL; 136 | } 137 | image->elements[image->num_elements++] = element; 138 | debug("Parsed KBAG element\n"); 139 | break; 140 | 141 | case kEcidElement: 142 | element = img3_parse_element(&data[data_offset]); 143 | if (element == NULL) { 144 | error("ERROR: Unable to parse ECID element\n"); 145 | img3_free(image); 146 | return NULL; 147 | } 148 | image->idx_ecid_element = image->num_elements; 149 | image->elements[image->num_elements++] = element; 150 | debug("Parsed ECID element\n"); 151 | break; 152 | 153 | case kShshElement: 154 | element = img3_parse_element(&data[data_offset]); 155 | if (element == NULL) { 156 | error("ERROR: Unable to parse SHSH element\n"); 157 | img3_free(image); 158 | return NULL; 159 | } 160 | image->idx_shsh_element = image->num_elements; 161 | image->elements[image->num_elements++] = element; 162 | debug("Parsed SHSH element\n"); 163 | break; 164 | 165 | case kCertElement: 166 | element = img3_parse_element(&data[data_offset]); 167 | if (element == NULL) { 168 | error("ERROR: Unable to parse CERT element\n"); 169 | img3_free(image); 170 | return NULL; 171 | } 172 | image->idx_cert_element = image->num_elements; 173 | image->elements[image->num_elements++] = element; 174 | debug("Parsed CERT element\n"); 175 | break; 176 | 177 | case kUnknElement: 178 | element = img3_parse_element(&data[data_offset]); 179 | if (element == NULL) { 180 | error("ERROR: Unable to parse UNKN element\n"); 181 | img3_free(image); 182 | return NULL; 183 | } 184 | image->elements[image->num_elements++] = element; 185 | debug("Parsed UNKN element\n"); 186 | break; 187 | 188 | default: 189 | error("ERROR: Unknown IMG3 element type %08x\n", current->signature); 190 | img3_free(image); 191 | return NULL; 192 | } 193 | data_offset += current->full_size; 194 | } 195 | 196 | return image; 197 | } 198 | 199 | img3_element* img3_parse_element(unsigned char* data) { 200 | img3_element_header* element_header = (img3_element_header*) data; 201 | img3_element* element = (img3_element*) malloc(sizeof(img3_element)); 202 | if (element == NULL) { 203 | error("ERROR: Unable to allocate memory for IMG3 element\n"); 204 | return NULL; 205 | } 206 | memset(element, '\0', sizeof(img3_element)); 207 | 208 | element->data = (unsigned char*) malloc(element_header->full_size); 209 | if (element->data == NULL) { 210 | error("ERROR: Unable to allocate memory for IMG3 element data\n"); 211 | free(element); 212 | return NULL; 213 | } 214 | memcpy(element->data, data, element_header->full_size); 215 | element->header = (img3_element_header*) element->data; 216 | element->type = (img3_element_type) element->header->signature; 217 | 218 | return element; 219 | } 220 | 221 | void img3_free(img3_file* image) { 222 | if (image != NULL) { 223 | if (image->header != NULL) { 224 | free(image->header); 225 | } 226 | 227 | int i; 228 | for (i = 0; i < image->num_elements; i++) { 229 | img3_free_element(image->elements[i]); 230 | image->elements[i] = NULL; 231 | } 232 | free(image); 233 | image = NULL; 234 | } 235 | } 236 | 237 | void img3_free_element(img3_element* element) { 238 | if (element != NULL) { 239 | if (element->data != NULL) { 240 | free(element->data); 241 | element->data = NULL; 242 | } 243 | free(element); 244 | element = NULL; 245 | } 246 | } 247 | 248 | int img3_replace_signature(img3_file* image, unsigned char* signature) { 249 | int i, oldidx; 250 | int offset = 0; 251 | img3_element* ecid = img3_parse_element(&signature[offset]); 252 | if (ecid == NULL || ecid->type != kEcidElement) { 253 | error("ERROR: Unable to find ECID element in signature\n"); 254 | return -1; 255 | } 256 | offset += ecid->header->full_size; 257 | 258 | img3_element* shsh = img3_parse_element(&signature[offset]); 259 | if (shsh == NULL || shsh->type != kShshElement) { 260 | error("ERROR: Unable to find SHSH element in signature\n"); 261 | return -1; 262 | } 263 | offset += shsh->header->full_size; 264 | 265 | img3_element* cert = img3_parse_element(&signature[offset]); 266 | if (cert == NULL || cert->type != kCertElement) { 267 | error("ERROR: Unable to find CERT element in signature\n"); 268 | return -1; 269 | } 270 | offset += cert->header->full_size; 271 | 272 | if (image->idx_ecid_element >= 0) { 273 | img3_free_element(image->elements[image->idx_ecid_element]); 274 | image->elements[image->idx_ecid_element] = ecid; 275 | } else { 276 | if (image->idx_shsh_element >= 0) { 277 | // move elements by 1 278 | oldidx = image->idx_shsh_element; 279 | for (i = image->num_elements-1; i >= oldidx; i--) { 280 | image->elements[i+1] = image->elements[i]; 281 | switch (image->elements[i+1]->type) { 282 | case kShshElement: 283 | image->idx_shsh_element = i+1; 284 | break; 285 | case kCertElement: 286 | image->idx_cert_element = i+1; 287 | break; 288 | case kEcidElement: 289 | image->idx_ecid_element = i+1; 290 | break; 291 | default: 292 | break; 293 | } 294 | } 295 | image->elements[oldidx] = ecid; 296 | image->idx_ecid_element = oldidx; 297 | image->num_elements++; 298 | } else { 299 | // append if not found 300 | image->elements[image->num_elements] = ecid; 301 | image->idx_ecid_element = image->num_elements; 302 | image->num_elements++; 303 | } 304 | } 305 | 306 | if (image->idx_shsh_element >= 0) { 307 | img3_free_element(image->elements[image->idx_shsh_element]); 308 | image->elements[image->idx_shsh_element] = shsh; 309 | } else { 310 | if (image->idx_cert_element >= 0) { 311 | // move elements by 1 312 | oldidx = image->idx_cert_element; 313 | for (i = image->num_elements-1; i >= oldidx; i--) { 314 | image->elements[i+1] = image->elements[i]; 315 | switch (image->elements[i+1]->type) { 316 | case kShshElement: 317 | image->idx_shsh_element = i+1; 318 | break; 319 | case kCertElement: 320 | image->idx_cert_element = i+1; 321 | break; 322 | case kEcidElement: 323 | image->idx_ecid_element = i+1; 324 | break; 325 | default: 326 | break; 327 | } 328 | } 329 | image->elements[oldidx] = shsh; 330 | image->idx_shsh_element = oldidx; 331 | image->num_elements++; 332 | } else { 333 | // append if not found 334 | image->elements[image->num_elements] = shsh; 335 | image->idx_shsh_element = image->num_elements; 336 | image->num_elements++; 337 | } 338 | } 339 | 340 | if (image->idx_cert_element >= 0) { 341 | img3_free_element(image->elements[image->idx_cert_element]); 342 | image->elements[image->idx_cert_element] = cert; 343 | } else { 344 | // append if not found 345 | image->elements[image->num_elements] = cert; 346 | image->idx_cert_element = image->num_elements; 347 | image->num_elements++; 348 | } 349 | 350 | return 0; 351 | } 352 | 353 | int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int* psize) { 354 | int i; 355 | int offset = 0; 356 | int size = sizeof(img3_header); 357 | 358 | // Add up the size of the image first so we can allocate our memory 359 | for (i = 0; i < image->num_elements; i++) { 360 | size += image->elements[i]->header->full_size; 361 | } 362 | 363 | info("reconstructed size: %d\n", size); 364 | 365 | unsigned char* data = (unsigned char*) malloc(size); 366 | if (data == NULL) { 367 | error("ERROR: Unable to allocate memory for IMG3 data\n"); 368 | return -1; 369 | } 370 | 371 | // Add data to our new header (except shsh_offset) 372 | img3_header* header = (img3_header*) data; 373 | header->full_size = size; 374 | header->signature = image->header->signature; 375 | header->data_size = size - sizeof(img3_header); 376 | header->image_type = image->header->image_type; 377 | offset += sizeof(img3_header); 378 | 379 | // Copy each section over to the new buffer 380 | for (i = 0; i < image->num_elements; i++) { 381 | memcpy(&data[offset], image->elements[i]->data, image->elements[i]->header->full_size); 382 | if (image->elements[i]->type == kShshElement) { 383 | header->shsh_offset = offset - sizeof(img3_header); 384 | } 385 | offset += image->elements[i]->header->full_size; 386 | } 387 | 388 | if (offset != size) { 389 | error("ERROR: Incorrectly sized image data\n"); 390 | free(data); 391 | *pdata = 0; 392 | *psize = 0; 393 | return -1; 394 | } 395 | 396 | *pdata = data; 397 | *psize = size; 398 | return 0; 399 | } 400 | -------------------------------------------------------------------------------- /src/img3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * img3.h 3 | * Functions for handling with Apple's IMG3 format 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * Copyright (c) 2010 Martin Szulecki. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_IMG3_H 25 | #define IDEVICERESTORE_IMG3_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | typedef enum { 32 | kNorContainer = 0x696D6733, // img3 33 | kImg3Container = 0x496D6733, // Img3 34 | k8900Container = 0x30303938, // 8900 35 | kImg2Container = 0x494D4732 // IMG2 36 | } img3_container; 37 | 38 | typedef enum { 39 | kDataElement = 0x44415441, // DATA 40 | kTypeElement = 0x54595045, // TYPE 41 | kKbagElement = 0x4B424147, // KBAG 42 | kShshElement = 0x53485348, // SHSH 43 | kCertElement = 0x43455254, // CERT 44 | kChipElement = 0x43484950, // CHIP 45 | kProdElement = 0x50524F44, // PROD 46 | kSdomElement = 0x53444F4D, // SDOM 47 | kVersElement = 0x56455253, // VERS 48 | kBordElement = 0x424F5244, // BORD 49 | kSepoElement = 0x5345504F, // SEPO 50 | kEcidElement = 0x45434944, // ECID 51 | kUnknElement = 0x53414c54 // FIXME 52 | } img3_element_type; 53 | 54 | typedef struct { 55 | unsigned int signature; 56 | unsigned int full_size; 57 | unsigned int data_size; 58 | unsigned int shsh_offset; 59 | unsigned int image_type; 60 | } img3_header; 61 | 62 | typedef struct { 63 | unsigned int signature; 64 | unsigned int full_size; 65 | unsigned int data_size; 66 | } img3_element_header; 67 | 68 | typedef struct { 69 | img3_element_header* header; 70 | img3_element_type type; 71 | unsigned char* data; 72 | } img3_element; 73 | 74 | typedef struct { 75 | unsigned char* data; 76 | img3_header* header; 77 | int num_elements; 78 | img3_element* elements[16]; 79 | int idx_ecid_element; 80 | int idx_shsh_element; 81 | int idx_cert_element; 82 | /* img3_element* type_element; 83 | img3_element* data_element; 84 | img3_element* vers_element; 85 | img3_element* sepo_element; 86 | img3_element* bord_element; 87 | img3_element* sepo2_element; 88 | img3_element* chip_element; 89 | img3_element* bord2_element; 90 | img3_element* kbag1_element; 91 | img3_element* kbag2_element; 92 | img3_element* ecid_element; 93 | img3_element* shsh_element; 94 | img3_element* cert_element; 95 | img3_element* unkn_element;*/ 96 | } img3_file; 97 | 98 | void img3_free(img3_file* image); 99 | img3_element* img3_parse_element(unsigned char* data); 100 | void img3_free_element(img3_element* element); 101 | img3_file* img3_parse_file(unsigned char* data, unsigned int size); 102 | int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int* psize); 103 | int img3_replace_signature(img3_file* image, unsigned char* signature); 104 | 105 | 106 | #ifdef __cplusplus 107 | }s 108 | #endif 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /src/ipsw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ipsw.c 3 | * Utilities for extracting and manipulating IPSWs 4 | * 5 | * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "ipsw.h" 31 | #include "locking.h" 32 | #include "download.h" 33 | #include "common.h" 34 | #include "idevicerestore.h" 35 | 36 | #define BUFSIZE 0x100000 37 | 38 | typedef struct { 39 | struct zip* zip; 40 | } ipsw_archive; 41 | 42 | ipsw_archive* ipsw_open(const char* ipsw); 43 | void ipsw_close(ipsw_archive* archive); 44 | 45 | ipsw_archive* ipsw_open(const char* ipsw) { 46 | int err = 0; 47 | ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive)); 48 | if (archive == NULL) { 49 | error("ERROR: Out of memory\n"); 50 | return NULL; 51 | } 52 | 53 | archive->zip = zip_open(ipsw, 0, &err); 54 | if (archive->zip == NULL) { 55 | error("ERROR: zip_open: %s: %d\n", ipsw, err); 56 | free(archive); 57 | return NULL; 58 | } 59 | 60 | return archive; 61 | } 62 | 63 | int ipsw_get_file_size(const char* ipsw, const char* infile, off_t* size) { 64 | ipsw_archive* archive = ipsw_open(ipsw); 65 | if (archive == NULL || archive->zip == NULL) { 66 | error("ERROR: Invalid archive\n"); 67 | return -1; 68 | } 69 | 70 | int zindex = zip_name_locate(archive->zip, infile, 0); 71 | if (zindex < 0) { 72 | error("ERROR: zip_name_locate: %s\n", infile); 73 | return -1; 74 | } 75 | 76 | struct zip_stat zstat; 77 | zip_stat_init(&zstat); 78 | if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { 79 | error("ERROR: zip_stat_index: %s\n", infile); 80 | return -1; 81 | } 82 | 83 | *size = zstat.size; 84 | 85 | ipsw_close(archive); 86 | return 0; 87 | } 88 | 89 | int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile) { 90 | ipsw_archive* archive = ipsw_open(ipsw); 91 | if (archive == NULL || archive->zip == NULL) { 92 | error("ERROR: Invalid archive\n"); 93 | return -1; 94 | } 95 | 96 | int zindex = zip_name_locate(archive->zip, infile, 0); 97 | if (zindex < 0) { 98 | error("ERROR: zip_name_locate: %s\n", infile); 99 | return -1; 100 | } 101 | 102 | struct zip_stat zstat; 103 | zip_stat_init(&zstat); 104 | if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { 105 | error("ERROR: zip_stat_index: %s\n", infile); 106 | return -1; 107 | } 108 | 109 | char* buffer = (char*) malloc(BUFSIZE); 110 | if (buffer == NULL) { 111 | error("ERROR: Unable to allocate memory\n"); 112 | return -1; 113 | } 114 | 115 | struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); 116 | if (zfile == NULL) { 117 | error("ERROR: zip_fopen_index: %s\n", infile); 118 | return -1; 119 | } 120 | 121 | FILE* fd = fopen(outfile, "wb"); 122 | if (fd == NULL) { 123 | error("ERROR: Unable to open output file: %s\n", outfile); 124 | zip_fclose(zfile); 125 | return -1; 126 | } 127 | 128 | int i = 0; 129 | int size = 0; 130 | int bytes = 0; 131 | int count = 0; 132 | double progress = 0; 133 | for(i = zstat.size; i > 0; i -= count) { 134 | if (i < BUFSIZE) 135 | size = i; 136 | else 137 | size = BUFSIZE; 138 | count = zip_fread(zfile, buffer, size); 139 | if (count < 0) { 140 | error("ERROR: zip_fread: %s\n", infile); 141 | zip_fclose(zfile); 142 | free(buffer); 143 | return -1; 144 | } 145 | fwrite(buffer, 1, count, fd); 146 | 147 | bytes += size; 148 | progress = ((double) bytes/ (double) zstat.size) * 100.0; 149 | print_progress_bar(progress); 150 | } 151 | 152 | fclose(fd); 153 | zip_fclose(zfile); 154 | ipsw_close(archive); 155 | free(buffer); 156 | return 0; 157 | } 158 | 159 | int ipsw_file_exists(const char* ipsw, const char* infile) 160 | { 161 | ipsw_archive* archive = ipsw_open(ipsw); 162 | if (archive == NULL || archive->zip == NULL) { 163 | return -1; 164 | } 165 | 166 | int zindex = zip_name_locate(archive->zip, infile, 0); 167 | if (zindex < 0) { 168 | ipsw_close(archive); 169 | return -2; 170 | } 171 | 172 | ipsw_close(archive); 173 | 174 | return 0; 175 | } 176 | 177 | int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize) { 178 | ipsw_archive* archive = ipsw_open(ipsw); 179 | if (archive == NULL || archive->zip == NULL) { 180 | error("ERROR: Invalid archive\n"); 181 | return -1; 182 | } 183 | 184 | int zindex = zip_name_locate(archive->zip, infile, 0); 185 | if (zindex < 0) { 186 | error("ERROR: zip_name_locate: %s\n", infile); 187 | return -1; 188 | } 189 | 190 | struct zip_stat zstat; 191 | zip_stat_init(&zstat); 192 | if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { 193 | error("ERROR: zip_stat_index: %s\n", infile); 194 | return -1; 195 | } 196 | 197 | struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); 198 | if (zfile == NULL) { 199 | error("ERROR: zip_fopen_index: %s\n", infile); 200 | return -1; 201 | } 202 | 203 | int size = zstat.size; 204 | unsigned char* buffer = (unsigned char*) malloc(size+1); 205 | if (buffer == NULL) { 206 | error("ERROR: Out of memory\n"); 207 | zip_fclose(zfile); 208 | return -1; 209 | } 210 | 211 | if (zip_fread(zfile, buffer, size) != size) { 212 | error("ERROR: zip_fread: %s\n", infile); 213 | zip_fclose(zfile); 214 | free(buffer); 215 | return -1; 216 | } 217 | 218 | buffer[size] = '\0'; 219 | 220 | zip_fclose(zfile); 221 | ipsw_close(archive); 222 | 223 | *pbuffer = buffer; 224 | *psize = size; 225 | return 0; 226 | } 227 | 228 | int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled) { 229 | unsigned int size = 0; 230 | unsigned char* data = NULL; 231 | 232 | *tss_enabled = 0; 233 | 234 | /* older devices don't require personalized firmwares and use a BuildManifesto.plist */ 235 | if (ipsw_file_exists(ipsw, "BuildManifesto.plist") == 0) { 236 | if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) == 0) { 237 | plist_from_xml((char*)data, size, buildmanifest); 238 | free(data); 239 | return 0; 240 | } 241 | } 242 | 243 | data = NULL; 244 | size = 0; 245 | 246 | /* whereas newer devices do not require personalized firmwares and use a BuildManifest.plist */ 247 | if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) == 0) { 248 | *tss_enabled = 1; 249 | plist_from_xml((char*)data, size, buildmanifest); 250 | free(data); 251 | return 0; 252 | } 253 | 254 | return -1; 255 | } 256 | 257 | int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) { 258 | unsigned int size = 0; 259 | unsigned char* data = NULL; 260 | 261 | if (ipsw_extract_to_memory(ipsw, "Restore.plist", &data, &size) == 0) { 262 | plist_from_xml((char*)data, size, restore_plist); 263 | free(data); 264 | return 0; 265 | } 266 | 267 | return -1; 268 | } 269 | 270 | void ipsw_close(ipsw_archive* archive) { 271 | if (archive != NULL) { 272 | zip_unchange_all(archive->zip); 273 | zip_close(archive->zip); 274 | free(archive); 275 | } 276 | } 277 | 278 | int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, unsigned char* sha1buf) 279 | { 280 | *fwurl = NULL; 281 | if (sha1buf != NULL) { 282 | memset(sha1buf, '\0', 20); 283 | } 284 | 285 | plist_t n1 = plist_dict_get_item(version_data, "MobileDeviceSoftwareVersionsByVersion"); 286 | if (!n1) { 287 | error("%s: ERROR: Can't find MobileDeviceSoftwareVersionsByVersion dict in version data\n", __func__); 288 | return -1; 289 | } 290 | 291 | plist_dict_iter iter = NULL; 292 | plist_dict_new_iter(n1, &iter); 293 | if (!iter) { 294 | error("%s: ERROR: Can't get dict iter\n", __func__); 295 | return -1; 296 | } 297 | char* key = NULL; 298 | long long unsigned int major = 0; 299 | plist_t val = NULL; 300 | do { 301 | plist_dict_next_item(n1, iter, &key, &val); 302 | if (key) { 303 | plist_t pr = plist_access_path(n1, 3, key, "MobileDeviceSoftwareVersions", product); 304 | if (pr) { 305 | long long unsigned int v = strtoull(key, NULL, 10); 306 | if (v > major) 307 | major = v; 308 | } 309 | free(key); 310 | } 311 | } while (val); 312 | free(iter); 313 | 314 | if (major == 0) { 315 | error("%s: ERROR: Can't find major version?!\n", __func__); 316 | return -1; 317 | } 318 | 319 | char majstr[32]; // should be enough for a uint64_t value 320 | sprintf(majstr, FMT_qu, (long long unsigned int)major); 321 | n1 = plist_access_path(version_data, 7, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, "Unknown", "Universal", "Restore"); 322 | if (!n1) { 323 | error("%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__); 324 | return -1; 325 | } 326 | 327 | plist_t n2 = plist_dict_get_item(n1, "BuildVersion"); 328 | if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) { 329 | error("%s: ERROR: Can't get build version node?!\n", __func__); 330 | return -1; 331 | } 332 | 333 | char* strval = NULL; 334 | plist_get_string_val(n2, &strval); 335 | 336 | n1 = plist_access_path(version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, strval); 337 | if (!n1) { 338 | error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s node?!\n", __func__, strval); 339 | free(strval); 340 | return -1; 341 | } 342 | free(strval); 343 | 344 | strval = NULL; 345 | n2 = plist_dict_get_item(n1, "SameAs"); 346 | if (n2) { 347 | plist_get_string_val(n2, &strval); 348 | } 349 | if (strval) { 350 | n1 = plist_access_path(version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, strval); 351 | free(strval); 352 | strval = NULL; 353 | if (!n1 || (plist_dict_get_size(n1) == 0)) { 354 | error("%s: ERROR: Can't get MobileDeviceSoftwareVersions/%s dict\n", __func__, product); 355 | return -1; 356 | } 357 | } 358 | 359 | n2 = plist_access_path(n1, 2, "Update", "BuildVersion"); 360 | if (n2) { 361 | strval = NULL; 362 | plist_get_string_val(n2, &strval); 363 | if (strval) { 364 | n1 = plist_access_path(version_data, 5, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, strval); 365 | free(strval); 366 | strval = NULL; 367 | } 368 | } 369 | 370 | n2 = plist_access_path(n1, 2, "Restore", "FirmwareURL"); 371 | if (!n2 || (plist_get_node_type(n2) != PLIST_STRING)) { 372 | error("%s: ERROR: Can't get FirmwareURL node\n", __func__); 373 | return -1; 374 | } 375 | 376 | plist_get_string_val(n2, fwurl); 377 | 378 | if (sha1buf != NULL) { 379 | n2 = plist_access_path(n1, 2, "Restore", "FirmwareSHA1"); 380 | if (n2 && plist_get_node_type(n2) == PLIST_STRING) { 381 | strval = NULL; 382 | plist_get_string_val(n2, &strval); 383 | if (strval) { 384 | if (strlen(strval) == 40) { 385 | int i; 386 | int v; 387 | for (i = 0; i < 40; i+=2) { 388 | v = 0; 389 | sscanf(strval+i, "%02x", &v); 390 | sha1buf[i/2] = (unsigned char)v; 391 | } 392 | } 393 | free(strval); 394 | } 395 | } 396 | } 397 | 398 | return 0; 399 | } 400 | 401 | static int sha1_verify_fp(FILE* f, unsigned char* expected_sha1) 402 | { 403 | unsigned char tsha1[20]; 404 | char buf[8192]; 405 | if (!f) return 0; 406 | SHA_CTX sha1ctx; 407 | SHA1_Init(&sha1ctx); 408 | rewind(f); 409 | while (!feof(f)) { 410 | size_t sz = fread(buf, 1, 8192, f); 411 | SHA1_Update(&sha1ctx, (const void*)buf, sz); 412 | } 413 | SHA1_Final(tsha1, &sha1ctx); 414 | return (memcmp(expected_sha1, tsha1, 20) == 0) ? 1 : 0; 415 | } 416 | 417 | int ipsw_download_latest_fw(plist_t version_data, const char* product, const char* todir, char** ipswfile) 418 | { 419 | char* fwurl = NULL; 420 | unsigned char isha1[20]; 421 | 422 | *ipswfile = NULL; 423 | 424 | if ((ipsw_get_latest_fw(version_data, product, &fwurl, isha1) < 0) || !fwurl) { 425 | error("ERROR: can't get URL for latest firmware\n"); 426 | return -1; 427 | } 428 | char* fwfn = strrchr(fwurl, '/'); 429 | if (!fwfn) { 430 | error("ERROR: can't get local filename for firmware ipsw\n"); 431 | return -2; 432 | } 433 | fwfn++; 434 | 435 | info("Latest firmware is %s\n", fwfn); 436 | 437 | char fwlfn[256]; 438 | sprintf(fwlfn, "%s/%s", todir, fwfn); 439 | 440 | char fwlock[256]; 441 | sprintf(fwlock, "%s.lock", fwlfn); 442 | 443 | lock_info_t lockinfo; 444 | 445 | if (lock_file(fwlock, &lockinfo) != 0) { 446 | error("WARNING: Could not lock file '%s'\n", fwlock); 447 | } 448 | 449 | int need_dl = 0; 450 | unsigned char zsha1[20] = {0, }; 451 | FILE* f = fopen(fwlfn, "rb"); 452 | if (f) { 453 | if (memcmp(zsha1, isha1, 20) != 0) { 454 | info("Verifying '%s'...\n", fwlfn); 455 | if (sha1_verify_fp(f, isha1)) { 456 | info("Checksum matches.\n"); 457 | } else { 458 | info("Checksum does not match.\n"); 459 | need_dl = 1; 460 | } 461 | } 462 | fclose(f); 463 | } else { 464 | need_dl = 1; 465 | } 466 | 467 | int res = 0; 468 | if (need_dl) { 469 | if (strncmp(fwurl, "protected:", 10) == 0) { 470 | error("ERROR: Can't download '%s' because it needs a purchase.\n", fwfn); 471 | res = -3; 472 | } else { 473 | remove(fwlfn); 474 | info("Downloading latest firmware (%s)\n", fwurl); 475 | download_to_file(fwurl, fwlfn, 1); 476 | if (memcmp(isha1, zsha1, 20) != 0) { 477 | info("\nVerifying '%s'...\n", fwlfn); 478 | FILE* f = fopen(fwlfn, "rb"); 479 | if (f) { 480 | if (sha1_verify_fp(f, isha1)) { 481 | info("Checksum matches.\n"); 482 | } else { 483 | error("ERROR: File download failed (checksum mismatch).\n"); 484 | res = -4; 485 | } 486 | fclose(f); 487 | 488 | // make sure to remove invalid files 489 | if (res < 0) 490 | remove(fwlfn); 491 | } else { 492 | error("ERROR: Can't open '%s' for checksum verification\n", fwlfn); 493 | res = -5; 494 | } 495 | } 496 | } 497 | } 498 | free(fwurl); 499 | if (res == 0) { 500 | *ipswfile = strdup(fwlfn); 501 | } 502 | 503 | if (unlock_file(&lockinfo) != 0) { 504 | error("WARNING: Could not unlock file '%s'\n", fwlock); 505 | } 506 | 507 | return res; 508 | } 509 | -------------------------------------------------------------------------------- /src/ipsw.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ipsw.h 3 | * Definitions for IPSW utilities 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * Copyright (c) 2010 Martin Szulecki. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_IPSW_H 25 | #define IDEVICERESTORE_IPSW_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | typedef struct { 36 | int index; 37 | char* name; 38 | unsigned int size; 39 | unsigned char* data; 40 | } ipsw_file; 41 | 42 | int ipsw_get_file_size(const char* ipsw, const char* infile, off_t* size); 43 | int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile); 44 | int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); 45 | int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled); 46 | int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist); 47 | void ipsw_free_file(ipsw_file* file); 48 | 49 | int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, unsigned char* sha1buf); 50 | int ipsw_download_latest_fw(plist_t version_data, const char* product, const char* todir, char** ipswfile); 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/limera1n.c: -------------------------------------------------------------------------------- 1 | /* 2 | * limera1n.c 3 | * Helper code for limera1n exploit based on discovery by geohot 4 | * 5 | * Copyright (c) 2012-2013 Nikias Bassen. All Rights Reserved. 6 | * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. 7 | * Copyright (C) 2010 Chronic-Dev Team 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "common.h" 30 | #include "limera1n.h" 31 | #include "limera1n_payload.h" 32 | 33 | int limera1n_is_supported(struct irecv_device *device) 34 | { 35 | irecv_device_t iphone4 = NULL; 36 | irecv_device_t iphone3gs = NULL; 37 | irecv_device_t ipod3g = NULL; 38 | 39 | irecv_devices_get_device_by_product_type("iPhone3,1", &iphone4); 40 | irecv_devices_get_device_by_product_type("iPhone2,1", &iphone3gs); 41 | irecv_devices_get_device_by_product_type("iPod3,1", &ipod3g); 42 | 43 | return ((device->chip_id == iphone4->chip_id) || 44 | (device->chip_id == iphone3gs->chip_id) || 45 | (device->chip_id == ipod3g->chip_id)); 46 | } 47 | 48 | int limera1n_exploit(struct irecv_device *device, irecv_client_t *pclient) 49 | { 50 | irecv_error_t err = IRECV_E_SUCCESS; 51 | unsigned int i = 0; 52 | unsigned char buf[0x800]; 53 | unsigned char shellcode[0x800]; 54 | unsigned int max_size = 0x24000; 55 | //unsigned int load_address = 0x84000000; 56 | unsigned int stack_address = 0; 57 | unsigned int shellcode_address = 0; 58 | unsigned int shellcode_length = 0; 59 | 60 | irecv_device_t iphone4 = NULL; 61 | irecv_device_t iphone3gs = NULL; 62 | irecv_device_t ipod3g = NULL; 63 | int mode = 0; 64 | 65 | irecv_devices_get_device_by_product_type("iPhone3,1", &iphone4); 66 | irecv_devices_get_device_by_product_type("iPhone2,1", &iphone3gs); 67 | irecv_devices_get_device_by_product_type("iPod3,1", &ipod3g); 68 | 69 | if (device->chip_id == iphone4->chip_id) { 70 | max_size = 0x2C000; 71 | stack_address = 0x8403BF9C; 72 | shellcode_address = 0x8402B001; 73 | } else if (device->chip_id == iphone3gs->chip_id) { 74 | max_size = 0x24000; 75 | stack_address = 0x84033FA4; 76 | shellcode_address = 0x84023001; 77 | } else if (device->chip_id == ipod3g->chip_id) { 78 | max_size = 0x24000; 79 | stack_address = 0x84033F98; 80 | shellcode_address = 0x84023001; 81 | } else { 82 | error("Unsupported ChipID 0x%04x. Can't exploit with limera1n.\n", device->chip_id); 83 | return -1; 84 | } 85 | 86 | memset(shellcode, 0x0, 0x800); 87 | shellcode_length = sizeof(limera1n_payload); 88 | memcpy(shellcode, limera1n_payload, sizeof(limera1n_payload)); 89 | 90 | irecv_client_t client = *pclient; 91 | 92 | debug("Resetting device counters\n"); 93 | err = irecv_reset_counters(client); 94 | if (err != IRECV_E_SUCCESS) { 95 | error("%s\n", irecv_strerror(err)); 96 | return -1; 97 | } 98 | 99 | memset(buf, 0xCC, 0x800); 100 | for(i = 0; i < 0x800; i += 0x40) { 101 | unsigned int* heap = (unsigned int*)(buf+i); 102 | heap[0] = 0x405; 103 | heap[1] = 0x101; 104 | heap[2] = shellcode_address; 105 | heap[3] = stack_address; 106 | } 107 | 108 | debug("Sending chunk headers\n"); 109 | irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 1000); 110 | 111 | memset(buf, 0xCC, 0x800); 112 | for(i = 0; i < (max_size - (0x800 * 3)); i += 0x800) { 113 | irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 1000); 114 | } 115 | 116 | debug("Sending exploit payload\n"); 117 | irecv_usb_control_transfer(client, 0x21, 1, 0, 0, shellcode, 0x800, 1000); 118 | 119 | debug("Sending fake data\n"); 120 | memset(buf, 0xBB, 0x800); 121 | irecv_usb_control_transfer(client, 0xA1, 1, 0, 0, buf, 0x800, 1000); 122 | irecv_usb_control_transfer(client, 0x21, 1, 0, 0, buf, 0x800, 10); 123 | 124 | //debug("Executing exploit\n"); 125 | irecv_usb_control_transfer(client, 0x21, 2, 0, 0, buf, 0, 1000); 126 | 127 | irecv_reset(client); 128 | irecv_finish_transfer(client); 129 | debug("Exploit sent\n"); 130 | 131 | debug("Reconnecting to device\n"); 132 | *pclient = irecv_reconnect(client, 7); 133 | if (*pclient == NULL) { 134 | error("Unable to reconnect\n"); 135 | return -1; 136 | } 137 | 138 | irecv_get_mode((*pclient), &mode); 139 | 140 | if (mode != IRECV_K_DFU_MODE) { 141 | error("Device reconnected in non-DFU mode\n"); 142 | return -1; 143 | } 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /src/limera1n.h: -------------------------------------------------------------------------------- 1 | /* 2 | * limera1n.h 3 | * Helper code for limera1n exploit based on discovery by geohot 4 | * 5 | * Copyright (c) 2012-2013 Nikias Bassen. All Rights Reserved. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #ifndef __LIMERA1N_H 23 | #define __LIMERA1N_H 24 | #include 25 | 26 | int limera1n_is_supported(struct irecv_device *device); 27 | int limera1n_exploit(struct irecv_device *device, irecv_client_t *client); 28 | 29 | #endif /* __LIMERA1N_H */ 30 | -------------------------------------------------------------------------------- /src/limera1n_payload.h: -------------------------------------------------------------------------------- 1 | /* 2 | * limera1n.h 3 | * Payload for limera1n exploit 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | unsigned char limera1n_payload[] = { 23 | 0x7f, 0x46, 0x07, 0xe0, 0xc0, 0x46, 0xc0, 0x46, 24 | 0xc0, 0x46, 0xc0, 0x46, 0xc0, 0x46, 0xc0, 0x46, 25 | 0xc0, 0x46, 0xc0, 0x46, 0x61, 0x48, 0x02, 0x68, 26 | 0x61, 0x48, 0x90, 0x42, 0x06, 0xd1, 0x61, 0x49, 27 | 0x39, 0x60, 0x61, 0x49, 0x79, 0x60, 0x61, 0x49, 28 | 0xb9, 0x60, 0x1c, 0xe0, 0x60, 0x48, 0x90, 0x42, 29 | 0x06, 0xd1, 0x60, 0x49, 0x39, 0x60, 0x60, 0x49, 30 | 0x79, 0x60, 0x60, 0x49, 0xb9, 0x60, 0x12, 0xe0, 31 | 0x5f, 0x48, 0x90, 0x42, 0x06, 0xd1, 0x5f, 0x49, 32 | 0x39, 0x60, 0x5f, 0x49, 0x79, 0x60, 0x5f, 0x49, 33 | 0xb9, 0x60, 0x08, 0xe0, 0x5e, 0x48, 0x90, 0x42, 34 | 0x05, 0xd1, 0x5e, 0x49, 0x39, 0x60, 0x5a, 0x49, 35 | 0x79, 0x60, 0x5d, 0x49, 0xb9, 0x60, 0x5d, 0x48, 36 | 0x5d, 0x49, 0x3b, 0x68, 0x98, 0x47, 0x5d, 0x48, 37 | 0x5a, 0x49, 0x4a, 0x68, 0x00, 0xf0, 0x80, 0xf8, 38 | 0x00, 0x28, 0xcb, 0xd0, 0x06, 0x1c, 0x5a, 0x48, 39 | 0x56, 0x49, 0x4a, 0x68, 0x00, 0xf0, 0x78, 0xf8, 40 | 0x00, 0x28, 0xc3, 0xd0, 0x05, 0x1c, 0x11, 0x20, 41 | 0x14, 0x24, 0x29, 0x19, 0x2a, 0x19, 0x30, 0x23, 42 | 0x54, 0x4c, 0x00, 0x94, 0x00, 0x24, 0x01, 0x94, 43 | 0x00, 0x24, 0x02, 0x94, 0x7c, 0x68, 0xa0, 0x47, 44 | 0x11, 0x20, 0x0c, 0x24, 0x31, 0x19, 0x32, 0x19, 45 | 0xb3, 0x68, 0x4f, 0x4c, 0x00, 0x94, 0x24, 0x24, 46 | 0x64, 0x19, 0x01, 0x94, 0x14, 0x24, 0x64, 0x19, 47 | 0x02, 0x94, 0x7c, 0x68, 0xa0, 0x47, 0x45, 0x48, 48 | 0x0c, 0x21, 0x89, 0x19, 0xb2, 0x68, 0x15, 0x1c, 49 | 0x00, 0xf0, 0x4a, 0xf8, 0x47, 0x48, 0x41, 0x49, 50 | 0x2a, 0x1c, 0x00, 0xf0, 0x4d, 0xf8, 0x00, 0x28, 51 | 0x08, 0xd0, 0x01, 0x1c, 0x44, 0x48, 0x45, 0x4a, 52 | 0x00, 0xf0, 0x46, 0xf8, 0x00, 0x28, 0x01, 0xd0, 53 | 0x43, 0x49, 0x01, 0x60, 0x43, 0x48, 0x39, 0x49, 54 | 0x2a, 0x1c, 0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 55 | 0x08, 0xd0, 0x01, 0x1c, 0x40, 0x48, 0x3d, 0x4a, 56 | 0x00, 0xf0, 0x36, 0xf8, 0x00, 0x28, 0x01, 0xd0, 57 | 0x3e, 0x49, 0x01, 0x60, 0x3e, 0x48, 0x31, 0x49, 58 | 0x2a, 0x1c, 0x00, 0xf0, 0x2d, 0xf8, 0x00, 0x28, 59 | 0x08, 0xd0, 0x01, 0x1c, 0x3b, 0x48, 0x35, 0x4a, 60 | 0x00, 0xf0, 0x26, 0xf8, 0x00, 0x28, 0x01, 0xd0, 61 | 0x33, 0x49, 0x01, 0x60, 0x38, 0x48, 0x29, 0x49, 62 | 0x2a, 0x1c, 0x38, 0x4b, 0x00, 0xf0, 0x1e, 0xf8, 63 | 0x00, 0x28, 0x07, 0xd1, 0x36, 0x48, 0x25, 0x49, 64 | 0x2a, 0x1c, 0x36, 0x4b, 0x00, 0xf0, 0x16, 0xf8, 65 | 0x00, 0x28, 0x03, 0xd0, 0x34, 0x49, 0x01, 0x60, 66 | 0x34, 0x49, 0x41, 0x60, 0x00, 0x20, 0x1f, 0x49, 67 | 0x00, 0x22, 0xbb, 0x68, 0x98, 0x47, 0x55, 0xe7, 68 | 0x0b, 0x68, 0x03, 0x60, 0x01, 0x30, 0x01, 0x31, 69 | 0x01, 0x3a, 0x00, 0x2a, 0xf8, 0xd1, 0x70, 0x47, 70 | 0x00, 0x23, 0xff, 0xe7, 0x10, 0xb5, 0x0c, 0x68, 71 | 0x84, 0x42, 0x04, 0xd1, 0x00, 0x2b, 0x07, 0xd0, 72 | 0x4c, 0x68, 0x9c, 0x42, 0x04, 0xd0, 0x02, 0x31, 73 | 0x02, 0x3a, 0x00, 0x2a, 0xf3, 0xd1, 0x00, 0x21, 74 | 0x08, 0x1c, 0x10, 0xbd, 0x88, 0x02, 0x00, 0x00, 75 | 0x39, 0x2e, 0x35, 0x00, 0xe5, 0x36, 0x00, 0x00, 76 | 0x19, 0x09, 0x00, 0x00, 0xdd, 0x39, 0x00, 0x00, 77 | 0x34, 0x2e, 0x34, 0x00, 0x85, 0x4c, 0x00, 0x00, 78 | 0x6d, 0x68, 0x00, 0x00, 0x5d, 0x5a, 0x00, 0x00, 79 | 0x39, 0x2e, 0x33, 0x00, 0x9d, 0x34, 0x00, 0x00, 80 | 0x25, 0x09, 0x00, 0x00, 0x69, 0x39, 0x00, 0x00, 81 | 0x39, 0x2e, 0x33, 0x2e, 0xa5, 0x34, 0x00, 0x00, 82 | 0x71, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 83 | 0x00, 0xc0, 0x02, 0x00, 0x41, 0x54, 0x41, 0x44, 84 | 0x47, 0x41, 0x42, 0x4b, 0x00, 0x02, 0x00, 0x20, 85 | 0x00, 0x00, 0x00, 0x20, 0x1a, 0x78, 0xff, 0x2a, 86 | 0x4f, 0xf0, 0xff, 0x30, 0x00, 0x02, 0x00, 0x00, 87 | 0x00, 0x20, 0x00, 0x20, 0xf3, 0xdf, 0x90, 0xb5, 88 | 0x07, 0x4b, 0x1b, 0x68, 0x4f, 0xf0, 0xff, 0x33, 89 | 0x11, 0x9a, 0xd3, 0xf1, 0x18, 0xbf, 0x01, 0x20, 90 | 0x80, 0xb5, 0x00, 0xaf, 0x82, 0xb0, 0x4f, 0xf0, 91 | 0xb0, 0xb5, 0x02, 0xaf, 0x82, 0xb0, 0x01, 0x28, 92 | 0x00, 0x4b, 0x18, 0x47, 0x00, 0x00, 0x00, 0x41 93 | }; 94 | unsigned int limera1n_payload_len = 560; 95 | -------------------------------------------------------------------------------- /src/locking.c: -------------------------------------------------------------------------------- 1 | /* 2 | * locking.c 3 | * locking extras 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifdef WIN32 22 | #include 23 | #else 24 | #include 25 | #endif 26 | 27 | #include "locking.h" 28 | #include "common.h" 29 | 30 | int lock_file(const char* filename, lock_info_t* lockinfo) 31 | { 32 | if (!lockinfo) { 33 | return -1; 34 | } 35 | #ifdef WIN32 36 | lockinfo->fp = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 37 | if (lockinfo->fp == INVALID_HANDLE_VALUE) { 38 | debug("ERROR: could not open or create lockfile '%s'\n", filename); 39 | return -1; 40 | } 41 | 42 | lockinfo->ldata.Offset = 0; 43 | lockinfo->ldata.OffsetHigh = 0; 44 | 45 | if (!LockFileEx(lockinfo->fp, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &lockinfo->ldata)) { 46 | debug("ERROR: can't lock file, error %d\n", GetLastError()); 47 | CloseHandle(lockinfo->fp); 48 | lockinfo->fp = INVALID_HANDLE_VALUE; 49 | return -1; 50 | } 51 | #else 52 | lockinfo->fp = fopen(filename, "a+"); 53 | 54 | if (!lockinfo->fp) { 55 | debug("ERROR: could not open or create lockfile '%s'\n", filename); 56 | return -1; 57 | } 58 | 59 | lockinfo->ldata.l_type = F_WRLCK; 60 | lockinfo->ldata.l_whence = SEEK_SET; 61 | lockinfo->ldata.l_start = 0; 62 | lockinfo->ldata.l_len = 0; 63 | 64 | if (fcntl(fileno(lockinfo->fp), F_SETLKW, &lockinfo->ldata) < 0) { 65 | debug("ERROR: can't lock file, error %d\n", errno); 66 | fclose(lockinfo->fp); 67 | lockinfo->fp = NULL; 68 | return -1; 69 | } 70 | #endif 71 | return 0; 72 | } 73 | 74 | int unlock_file(lock_info_t* lockinfo) 75 | { 76 | if (!lockinfo) { 77 | return -1; 78 | } 79 | #ifdef WIN32 80 | if (lockinfo->fp == INVALID_HANDLE_VALUE) { 81 | return -1; 82 | } 83 | 84 | lockinfo->ldata.Offset = 0; 85 | lockinfo->ldata.OffsetHigh = 0; 86 | 87 | if (!UnlockFileEx(lockinfo->fp, 0, 1, 0, &lockinfo->ldata)) { 88 | debug("ERROR: can't unlock file, error %d\n", GetLastError()); 89 | CloseHandle(lockinfo->fp); 90 | lockinfo->fp = INVALID_HANDLE_VALUE; 91 | return -1; 92 | } 93 | CloseHandle(lockinfo->fp); 94 | lockinfo->fp = INVALID_HANDLE_VALUE; 95 | #else 96 | if (!lockinfo->fp) { 97 | return -1; 98 | } 99 | 100 | lockinfo->ldata.l_type = F_UNLCK; 101 | lockinfo->ldata.l_whence = SEEK_SET; 102 | lockinfo->ldata.l_start = 0; 103 | lockinfo->ldata.l_len = 0; 104 | 105 | if (fcntl(fileno(lockinfo->fp), F_SETLK, &lockinfo->ldata) < 0) { 106 | debug("ERROR: can't unlock file, error %d\n", errno); 107 | fclose(lockinfo->fp); 108 | lockinfo->fp = NULL; 109 | return -1; 110 | } 111 | fclose(lockinfo->fp); 112 | lockinfo->fp = NULL; 113 | #endif 114 | return 0; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /src/locking.h: -------------------------------------------------------------------------------- 1 | /* 2 | * locking.h 3 | * locking extras header file 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef LOCKING_H 22 | #define LOCKING_H 23 | #include 24 | #ifdef WIN32 25 | #include 26 | #else 27 | #include 28 | #endif 29 | 30 | typedef struct { 31 | #ifdef WIN32 32 | HANDLE fp; 33 | OVERLAPPED ldata; 34 | #else 35 | FILE* fp; 36 | struct flock ldata; 37 | #endif 38 | } lock_info_t; 39 | 40 | int lock_file(const char* filename, lock_info_t* lockp); 41 | int unlock_file(lock_info_t* lockp); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/mbn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mbn.c 3 | * support for .mbn file format (found in .bbfw files) 4 | * 5 | * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include "mbn.h" 26 | #include "common.h" 27 | 28 | mbn_file* mbn_parse(unsigned char* data, unsigned int size) 29 | { 30 | mbn_file* mbn = (mbn_file*)malloc(sizeof(mbn_file)); 31 | if (!mbn) { 32 | return NULL; 33 | } 34 | memset(mbn, '\0', sizeof(mbn_file)); 35 | mbn->data = malloc(size); 36 | mbn->size = size; 37 | memcpy(mbn->data, data, size); 38 | /* FIXME: header parsing is not big endian safe */ 39 | memcpy(&mbn->header, data, sizeof(mbn_header)); 40 | mbn->parsed_size = mbn->header.data_size + sizeof(mbn_header); 41 | if (mbn->parsed_size != mbn->size) { 42 | debug("WARNING: size mismatch when parsing MBN file.\n"); 43 | } 44 | return mbn; 45 | } 46 | 47 | void mbn_free(mbn_file* mbn) 48 | { 49 | if (mbn) { 50 | if (mbn->data) { 51 | free(mbn->data); 52 | } 53 | free(mbn); 54 | } 55 | } 56 | 57 | int mbn_update_sig_blob(mbn_file* mbn, const unsigned char* sigdata, unsigned int siglen) 58 | { 59 | if (!mbn) { 60 | error("ERROR: %s: no data\n", __func__); 61 | return -1; 62 | } 63 | mbn->parsed_sig_offset = mbn->size - siglen; 64 | if ((mbn->parsed_sig_offset + siglen) > mbn->size) { 65 | error("ERROR: %s: signature is larger than mbn file size\n", __func__); 66 | return -1; 67 | } 68 | 69 | memcpy(mbn->data + mbn->parsed_sig_offset, sigdata, siglen); 70 | 71 | return 0; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/mbn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mbn.h 3 | * support for .mbn file format (found in .bbfw files) 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef MBN_H 22 | #define MBN_H 23 | 24 | #include 25 | 26 | struct _mbn_header { 27 | uint32_t type; // the signed .mbn files have 0xA as value. 28 | uint32_t unk_0x04; 29 | uint32_t unk_0x08; 30 | uint32_t unk_0x0c; 31 | uint32_t data_size; // data_size = total_size - sizeof(mbn_header) 32 | uint32_t sig_offset; // real offset = enc_sig_offset & 0xFFFFFF00 33 | uint32_t unk_0x18; 34 | uint32_t unk_0x1c; 35 | uint32_t unk_0x20; 36 | uint32_t unk_0x24; 37 | } __attribute__((packed)); 38 | typedef struct _mbn_header mbn_header; 39 | 40 | typedef struct { 41 | mbn_header header; 42 | uint32_t parsed_size; 43 | uint32_t parsed_sig_offset; 44 | void* data; 45 | uint32_t size; 46 | } mbn_file; 47 | 48 | mbn_file* mbn_parse(unsigned char* data, unsigned int size); 49 | void mbn_free(mbn_file* mbn); 50 | int mbn_update_sig_blob(mbn_file* mbn, const unsigned char* data, unsigned int size); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/normal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * normal.h 3 | * Functions for handling idevices in normal mode 4 | * 5 | * Copyright (c) 2012-2013 Nikias Bassen. All Rights Reserved. 6 | * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "common.h" 33 | #include "normal.h" 34 | #include "recovery.h" 35 | 36 | static int normal_device_connected = 0; 37 | 38 | void normal_device_callback(const idevice_event_t* event, void* userdata) { 39 | struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) userdata; 40 | if (event->event == IDEVICE_DEVICE_ADD) { 41 | normal_device_connected = 1; 42 | 43 | } else if (event->event == IDEVICE_DEVICE_REMOVE) { 44 | normal_device_connected = 0; 45 | client->flags &= FLAG_QUIT; 46 | } 47 | } 48 | 49 | int normal_client_new(struct idevicerestore_client_t* client) { 50 | struct normal_client_t* normal = (struct normal_client_t*) malloc(sizeof(struct normal_client_t)); 51 | if (normal == NULL) { 52 | error("ERROR: Out of memory\n"); 53 | return -1; 54 | } 55 | 56 | if (normal_open_with_timeout(client) < 0) { 57 | normal_client_free(client); 58 | return -1; 59 | } 60 | 61 | client->normal = normal; 62 | return 0; 63 | } 64 | 65 | void normal_client_free(struct idevicerestore_client_t* client) { 66 | struct normal_client_t* normal = NULL; 67 | if (client) { 68 | normal = client->normal; 69 | if(normal) { 70 | if(normal->client) { 71 | lockdownd_client_free(normal->client); 72 | normal->client = NULL; 73 | } 74 | if(normal->device) { 75 | idevice_free(normal->device); 76 | normal->device = NULL; 77 | } 78 | } 79 | free(normal); 80 | client->normal = NULL; 81 | } 82 | } 83 | 84 | static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t* device) 85 | { 86 | int num_devices = 0; 87 | char **devices = NULL; 88 | idevice_get_device_list(&devices, &num_devices); 89 | if (num_devices == 0) { 90 | return -1; 91 | } 92 | *device = NULL; 93 | idevice_t dev = NULL; 94 | idevice_error_t device_error; 95 | lockdownd_client_t lockdown = NULL; 96 | int j; 97 | for (j = 0; j < num_devices; j++) { 98 | if (lockdown != NULL) { 99 | lockdownd_client_free(lockdown); 100 | lockdown = NULL; 101 | } 102 | if (dev != NULL) { 103 | idevice_free(dev); 104 | dev = NULL; 105 | } 106 | device_error = idevice_new(&dev, devices[j]); 107 | if (device_error != IDEVICE_E_SUCCESS) { 108 | error("ERROR: %s: can't open device with UDID %s", __func__, devices[j]); 109 | continue; 110 | } 111 | 112 | if (lockdownd_client_new(dev, &lockdown, "idevicerestore") != LOCKDOWN_E_SUCCESS) { 113 | error("ERROR: %s: can't connect to lockdownd on device with UDID %s", __func__, devices[j]); 114 | continue; 115 | 116 | } 117 | char* type = NULL; 118 | if (lockdownd_query_type(lockdown, &type) != LOCKDOWN_E_SUCCESS) { 119 | continue; 120 | } 121 | if (strcmp(type, "com.apple.mobile.lockdown") != 0) { 122 | free(type); 123 | continue; 124 | } 125 | free(type); 126 | 127 | if (client->ecid != 0) { 128 | plist_t node = NULL; 129 | if ((lockdownd_get_value(lockdown, NULL, "UniqueChipID", &node) != LOCKDOWN_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_UINT)){ 130 | if (node) { 131 | plist_free(node); 132 | } 133 | continue; 134 | } 135 | lockdownd_client_free(lockdown); 136 | lockdown = NULL; 137 | 138 | uint64_t this_ecid = 0; 139 | plist_get_uint_val(node, &this_ecid); 140 | plist_free(node); 141 | 142 | if (this_ecid != client->ecid) { 143 | continue; 144 | } 145 | } 146 | if (lockdown) { 147 | lockdownd_client_free(lockdown); 148 | lockdown = NULL; 149 | } 150 | client->udid = strdup(devices[j]); 151 | *device = dev; 152 | break; 153 | } 154 | idevice_device_list_free(devices); 155 | 156 | return 0; 157 | } 158 | 159 | int normal_check_mode(struct idevicerestore_client_t* client) { 160 | idevice_t device = NULL; 161 | 162 | normal_idevice_new(client, &device); 163 | if (!device) { 164 | return -1; 165 | } 166 | idevice_free(device); 167 | 168 | return 0; 169 | } 170 | 171 | int normal_open_with_timeout(struct idevicerestore_client_t* client) { 172 | int i = 0; 173 | int attempts = 10; 174 | idevice_t device = NULL; 175 | lockdownd_client_t lockdownd = NULL; 176 | idevice_error_t device_error = IDEVICE_E_SUCCESS; 177 | lockdownd_error_t lockdownd_error = LOCKDOWN_E_SUCCESS; 178 | 179 | // no context exists so bail 180 | if(client == NULL) { 181 | return -1; 182 | } 183 | 184 | normal_device_connected = 0; 185 | 186 | // create our normal client if it doesn't yet exist 187 | if(client->normal == NULL) { 188 | client->normal = (struct normal_client_t*) malloc(sizeof(struct normal_client_t)); 189 | if(client->normal == NULL) { 190 | error("ERROR: Out of memory\n"); 191 | return -1; 192 | } 193 | } 194 | 195 | for (i = 1; i <= attempts; i++) { 196 | normal_idevice_new(client, &device); 197 | if (device) { 198 | normal_device_connected = 1; 199 | break; 200 | } 201 | 202 | if (i == attempts) { 203 | error("ERROR: Unable to connect to device in normal mode\n"); 204 | return -1; 205 | } 206 | sleep(2); 207 | } 208 | 209 | client->normal->device = device; 210 | 211 | return 0; 212 | } 213 | 214 | const char* normal_check_product_type(struct idevicerestore_client_t* client) { 215 | int i = 0; 216 | idevice_t device = NULL; 217 | char* product_type = NULL; 218 | irecv_device_t irecv_device = NULL; 219 | plist_t product_type_node = NULL; 220 | lockdownd_client_t lockdown = NULL; 221 | idevice_error_t device_error = IDEVICE_E_SUCCESS; 222 | lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; 223 | 224 | normal_idevice_new(client, &device); 225 | if (!device) { 226 | return product_type; 227 | } 228 | 229 | lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); 230 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 231 | lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); 232 | } 233 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 234 | idevice_free(device); 235 | return product_type; 236 | } 237 | 238 | plist_t pval = NULL; 239 | lockdownd_get_value(lockdown, NULL, "HardwareModel", &pval); 240 | if (pval && (plist_get_node_type(pval) == PLIST_STRING)) { 241 | char* strval = NULL; 242 | plist_get_string_val(pval, &strval); 243 | if (strval) { 244 | irecv_devices_get_device_by_hardware_model(strval, &irecv_device); 245 | if (irecv_device) { 246 | product_type = strdup(irecv_device->product_type); 247 | } 248 | free(strval); 249 | } 250 | } 251 | if (pval) { 252 | plist_free(pval); 253 | } 254 | 255 | if (product_type == NULL) { 256 | lockdown_error = lockdownd_get_value(lockdown, NULL, "ProductType", &product_type_node); 257 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 258 | lockdownd_client_free(lockdown); 259 | idevice_free(device); 260 | return product_type; 261 | } 262 | } 263 | 264 | lockdownd_client_free(lockdown); 265 | idevice_free(device); 266 | lockdown = NULL; 267 | device = NULL; 268 | 269 | if (irecv_device) { 270 | if (product_type) 271 | free(product_type); 272 | 273 | return irecv_device->product_type; 274 | } 275 | 276 | if (product_type_node != NULL) { 277 | if (!product_type_node || plist_get_node_type(product_type_node) != PLIST_STRING) { 278 | if (product_type_node) 279 | plist_free(product_type_node); 280 | return product_type; 281 | } 282 | plist_get_string_val(product_type_node, &product_type); 283 | plist_free(product_type_node); 284 | 285 | irecv_devices_get_device_by_product_type(product_type, &irecv_device); 286 | if (irecv_device && irecv_device->product_type) { 287 | free(product_type); 288 | return irecv_device->product_type; 289 | } 290 | } 291 | 292 | return product_type; 293 | } 294 | 295 | int normal_enter_recovery(struct idevicerestore_client_t* client) { 296 | idevice_t device = NULL; 297 | irecv_client_t recovery = NULL; 298 | lockdownd_client_t lockdown = NULL; 299 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 300 | idevice_error_t device_error = IDEVICE_E_SUCCESS; 301 | lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS; 302 | 303 | device_error = idevice_new(&device, client->udid); 304 | if (device_error != IDEVICE_E_SUCCESS) { 305 | error("ERROR: Unable to find device\n"); 306 | return -1; 307 | } 308 | 309 | lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); 310 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 311 | error("ERROR: Unable to connect to lockdownd service\n"); 312 | idevice_free(device); 313 | return -1; 314 | } 315 | 316 | lockdown_error = lockdownd_enter_recovery(lockdown); 317 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 318 | error("ERROR: Unable to place device in recovery mode\n"); 319 | lockdownd_client_free(lockdown); 320 | idevice_free(device); 321 | return -1; 322 | } 323 | 324 | lockdownd_client_free(lockdown); 325 | idevice_free(device); 326 | lockdown = NULL; 327 | device = NULL; 328 | 329 | if (recovery_client_new(client) < 0) { 330 | error("ERROR: Unable to enter recovery mode\n"); 331 | return -1; 332 | } 333 | 334 | client->mode = &idevicerestore_modes[MODE_RECOVERY]; 335 | recovery = NULL; 336 | return 0; 337 | } 338 | 339 | int normal_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) { 340 | idevice_t device = NULL; 341 | plist_t nonce_node = NULL; 342 | lockdownd_client_t lockdown = NULL; 343 | idevice_error_t device_error = IDEVICE_E_SUCCESS; 344 | lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; 345 | 346 | device_error = idevice_new(&device, client->udid); 347 | if (device_error != IDEVICE_E_SUCCESS) { 348 | return -1; 349 | } 350 | 351 | lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); 352 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 353 | error("ERROR: Unable to connect to lockdownd\n"); 354 | idevice_free(device); 355 | return -1; 356 | } 357 | 358 | lockdown_error = lockdownd_get_value(lockdown, NULL, "ApNonce", &nonce_node); 359 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 360 | error("ERROR: Unable to get ApNonce from lockdownd\n"); 361 | lockdownd_client_free(lockdown); 362 | idevice_free(device); 363 | return -1; 364 | } 365 | 366 | if (!nonce_node || plist_get_node_type(nonce_node) != PLIST_DATA) { 367 | error("ERROR: Unable to get nonce\n"); 368 | lockdownd_client_free(lockdown); 369 | idevice_free(device); 370 | return -1; 371 | } 372 | 373 | uint64_t n_size = 0; 374 | plist_get_data_val(nonce_node, (char**)nonce, &n_size); 375 | *nonce_size = (int)n_size; 376 | plist_free(nonce_node); 377 | 378 | lockdownd_client_free(lockdown); 379 | idevice_free(device); 380 | lockdown = NULL; 381 | device = NULL; 382 | return 0; 383 | } 384 | 385 | int normal_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { 386 | return 0; 387 | } 388 | 389 | int normal_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { 390 | return 0; 391 | } 392 | 393 | int normal_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { 394 | idevice_t device = NULL; 395 | plist_t unique_chip_node = NULL; 396 | lockdownd_client_t lockdown = NULL; 397 | idevice_error_t device_error = IDEVICE_E_SUCCESS; 398 | lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS; 399 | 400 | device_error = idevice_new(&device, client->udid); 401 | if (device_error != IDEVICE_E_SUCCESS) { 402 | return -1; 403 | } 404 | 405 | lockdown_error = lockdownd_client_new(device, &lockdown, "idevicerestore"); 406 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 407 | error("ERROR: Unable to connect to lockdownd\n"); 408 | idevice_free(device); 409 | return -1; 410 | } 411 | 412 | lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node); 413 | if (lockdown_error != LOCKDOWN_E_SUCCESS) { 414 | error("ERROR: Unable to get UniqueChipID from lockdownd\n"); 415 | lockdownd_client_free(lockdown); 416 | idevice_free(device); 417 | return -1; 418 | } 419 | 420 | if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) { 421 | error("ERROR: Unable to get ECID\n"); 422 | lockdownd_client_free(lockdown); 423 | idevice_free(device); 424 | return -1; 425 | } 426 | plist_get_uint_val(unique_chip_node, ecid); 427 | plist_free(unique_chip_node); 428 | 429 | lockdownd_client_free(lockdown); 430 | idevice_free(device); 431 | lockdown = NULL; 432 | device = NULL; 433 | return 0; 434 | } 435 | -------------------------------------------------------------------------------- /src/normal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * normal.h 3 | * Functions for handling idevices in normal mode 4 | * 5 | * Copyright (c) 2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_NORMAL_H 25 | #define IDEVICERESTORE_NORMAL_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | struct normal_client_t { 36 | idevice_t device; 37 | lockdownd_client_t client; 38 | const char* ipsw; 39 | plist_t tss; 40 | }; 41 | 42 | 43 | int normal_check_mode(struct idevicerestore_client_t* client); 44 | const char* normal_check_product_type(struct idevicerestore_client_t* client); 45 | int normal_client_new(struct idevicerestore_client_t* client); 46 | void normal_client_free(struct idevicerestore_client_t* client); 47 | int normal_open_with_timeout(struct idevicerestore_client_t* client); 48 | int normal_enter_recovery(struct idevicerestore_client_t* client); 49 | int normal_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); 50 | int normal_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); 51 | int normal_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); 52 | int normal_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/recovery.c: -------------------------------------------------------------------------------- 1 | /* 2 | * recovery.c 3 | * Functions for handling idevices in recovery mode 4 | * 5 | * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "idevicerestore.h" 33 | #include "tss.h" 34 | #include "img3.h" 35 | #include "restore.h" 36 | #include "recovery.h" 37 | 38 | int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event) { 39 | if (event->type == IRECV_PROGRESS) { 40 | //print_progress_bar(event->progress); 41 | } 42 | return 0; 43 | } 44 | 45 | void recovery_client_free(struct idevicerestore_client_t* client) { 46 | if(client) { 47 | if (client->recovery) { 48 | if(client->recovery->client) { 49 | irecv_close(client->recovery->client); 50 | client->recovery->client = NULL; 51 | } 52 | free(client->recovery); 53 | client->recovery = NULL; 54 | } 55 | } 56 | } 57 | 58 | int recovery_client_new(struct idevicerestore_client_t* client) { 59 | int i = 0; 60 | int attempts = 20; 61 | irecv_client_t recovery = NULL; 62 | irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR; 63 | 64 | if(client->recovery == NULL) { 65 | client->recovery = (struct recovery_client_t*)malloc(sizeof(struct recovery_client_t)); 66 | if (client->recovery == NULL) { 67 | error("ERROR: Out of memory\n"); 68 | return -1; 69 | } 70 | memset(client->recovery, 0, sizeof(struct recovery_client_t)); 71 | } 72 | 73 | for (i = 1; i <= attempts; i++) { 74 | recovery_error = irecv_open_with_ecid(&recovery, client->ecid); 75 | if (recovery_error == IRECV_E_SUCCESS) { 76 | break; 77 | } 78 | 79 | if (i >= attempts) { 80 | error("ERROR: Unable to connect to device in recovery mode\n"); 81 | return -1; 82 | } 83 | 84 | sleep(4); 85 | debug("Retrying connection...\n"); 86 | } 87 | 88 | if (client->srnm == NULL) { 89 | char snbuf[256]; 90 | snbuf[0] = '\0'; 91 | irecv_get_srnm(recovery, snbuf); 92 | if (snbuf[0] != '\0') { 93 | client->srnm = strdup(snbuf); 94 | info("INFO: device serial number is %s\n", client->srnm); 95 | } 96 | } 97 | 98 | irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); 99 | client->recovery->client = recovery; 100 | return 0; 101 | } 102 | 103 | int recovery_check_mode(struct idevicerestore_client_t* client) { 104 | irecv_client_t recovery = NULL; 105 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 106 | int mode = 0; 107 | 108 | irecv_init(); 109 | recovery_error=irecv_open_with_ecid(&recovery, client->ecid); 110 | 111 | if (recovery_error != IRECV_E_SUCCESS) { 112 | return -1; 113 | } 114 | 115 | irecv_get_mode(recovery, &mode); 116 | 117 | if ((mode == IRECV_K_DFU_MODE) || (mode == IRECV_K_WTF_MODE)) { 118 | irecv_close(recovery); 119 | return -1; 120 | } 121 | 122 | irecv_close(recovery); 123 | recovery = NULL; 124 | 125 | return 0; 126 | } 127 | 128 | int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable) { 129 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 130 | 131 | recovery_error = irecv_send_command(client->recovery->client, (enable) ? "setenv auto-boot true" : "setenv auto-boot false"); 132 | if (recovery_error != IRECV_E_SUCCESS) { 133 | error("ERROR: Unable to set auto-boot environmental variable\n"); 134 | return -1; 135 | } 136 | 137 | recovery_error = irecv_send_command(client->recovery->client, "saveenv"); 138 | if (recovery_error != IRECV_E_SUCCESS) { 139 | error("ERROR: Unable to save environmental variable\n"); 140 | return -1; 141 | } 142 | 143 | return 0; 144 | } 145 | 146 | int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build_identity) { 147 | idevice_t device = NULL; 148 | restored_client_t restore = NULL; 149 | 150 | if (client->build_major >= 8) { 151 | client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress"); 152 | } 153 | 154 | /* upload data to make device boot restore mode */ 155 | 156 | if(client->recovery == NULL) { 157 | if (recovery_client_new(client) < 0) { 158 | return -1; 159 | } 160 | } 161 | 162 | if ((client->build_major > 8) && !(client->flags & FLAG_CUSTOM)) { 163 | /* send ApTicket */ 164 | if (recovery_send_ticket(client) < 0) { 165 | error("ERROR: Unable to send APTicket\n"); 166 | return -1; 167 | } 168 | } 169 | 170 | if (recovery_set_autoboot(client, 0) < 0) { 171 | return -1; 172 | } 173 | 174 | info("Recovery Mode Environment:\n"); 175 | char* value = NULL; 176 | irecv_getenv(client->recovery->client, "build-version", &value); 177 | info("iBoot build-version=%s\n", (value) ? value : "(unknown)"); 178 | if (value) { 179 | free(value); 180 | value = NULL; 181 | } 182 | irecv_getenv(client->recovery->client, "build-style", &value); 183 | info("iBoot build-style=%s\n", (value) ? value : "(unknown)"); 184 | if (value) { 185 | free(value); 186 | value = NULL; 187 | } 188 | unsigned long radio_error = 0; 189 | irecv_getenv(client->recovery->client, "radio-error", &value); 190 | if (value) { 191 | radio_error = strtoul(value, NULL, 0); 192 | } 193 | if (radio_error > 0) { 194 | info("radio-error=%s\n", value); 195 | free(value); 196 | value = NULL; 197 | irecv_getenv(client->recovery->client, "radio-error-string", &value); 198 | if (value) { 199 | info("radio-error-string=%s\n", value); 200 | free(value); 201 | value = NULL; 202 | } 203 | } 204 | 205 | /* send logo and show it */ 206 | if (recovery_send_applelogo(client, build_identity) < 0) { 207 | error("ERROR: Unable to send AppleLogo\n"); 208 | return -1; 209 | } 210 | 211 | /* send ramdisk and run it */ 212 | if (recovery_send_ramdisk(client, build_identity) < 0) { 213 | error("ERROR: Unable to send Ramdisk\n"); 214 | return -1; 215 | } 216 | 217 | /* send devicetree and load it */ 218 | if (recovery_send_devicetree(client, build_identity) < 0) { 219 | error("ERROR: Unable to send DeviceTree\n"); 220 | return -1; 221 | } 222 | 223 | if (recovery_send_kernelcache(client, build_identity) < 0) { 224 | error("ERROR: Unable to send KernelCache\n"); 225 | return -1; 226 | } 227 | 228 | client->mode = &idevicerestore_modes[MODE_RESTORE]; 229 | return 0; 230 | } 231 | 232 | int recovery_send_ticket(struct idevicerestore_client_t* client) 233 | { 234 | if (!client->tss) { 235 | error("ERROR: ApTicket requested but no TSS present\n"); 236 | return -1; 237 | } 238 | 239 | unsigned char* data = NULL; 240 | uint32_t size = 0; 241 | if (tss_get_ticket(client->tss, &data, &size) < 0) { 242 | error("ERROR: Unable to get ApTicket from TSS request\n"); 243 | return -1; 244 | } 245 | 246 | info("Sending APTicket (%d bytes)\n", size); 247 | irecv_error_t err = irecv_send_buffer(client->recovery->client, data, size, 0); 248 | if (err != IRECV_E_SUCCESS) { 249 | error("ERROR: Unable to send APTicket: %s\n", irecv_strerror(err)); 250 | free(data); 251 | return -1; 252 | } 253 | free(data); 254 | 255 | err = irecv_send_command(client->recovery->client, "ticket"); 256 | if (err != IRECV_E_SUCCESS) { 257 | error("ERROR: Unable to send ticket command\n"); 258 | return -1; 259 | } 260 | 261 | return 0; 262 | } 263 | 264 | int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) { 265 | unsigned int size = 0; 266 | unsigned char* data = NULL; 267 | char* path = NULL; 268 | char* blob = NULL; 269 | irecv_error_t err = 0; 270 | 271 | if (client->tss) { 272 | if (tss_get_entry_path(client->tss, component, &path) < 0) { 273 | debug("NOTE: No path for component %s in TSS, will fetch from build_identity\n", component); 274 | } 275 | } 276 | if (!path) { 277 | if (build_identity_get_component_path(build_identity, component, &path) < 0) { 278 | error("ERROR: Unable to get path for component '%s'\n", component); 279 | if (path) 280 | free(path); 281 | return -1; 282 | } 283 | } 284 | 285 | if (ipsw_get_component_by_path(client->ipsw, client->tss, component, path, &data, &size) < 0) { 286 | error("ERROR: Unable to get component: %s\n", component); 287 | free(path); 288 | return -1; 289 | } 290 | 291 | info("Sending %s (%d bytes)...\n", component, size); 292 | 293 | // FIXME: Did I do this right???? 294 | err = irecv_send_buffer(client->recovery->client, data, size, 0); 295 | free(path); 296 | if (err != IRECV_E_SUCCESS) { 297 | error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err)); 298 | free(data); 299 | return -1; 300 | } 301 | 302 | free(data); 303 | return 0; 304 | } 305 | 306 | int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_identity) { 307 | const char* component = "iBEC"; 308 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 309 | 310 | if (client->recovery == NULL) { 311 | if (recovery_client_new(client) < 0) { 312 | return -1; 313 | } 314 | } 315 | 316 | if (recovery_send_component(client, build_identity, component) < 0) { 317 | error("ERROR: Unable to send %s to device.\n", component); 318 | return -1; 319 | } 320 | 321 | recovery_error = irecv_send_command(client->recovery->client, "go"); 322 | if (recovery_error != IRECV_E_SUCCESS) { 323 | error("ERROR: Unable to execute %s\n", component); 324 | return -1; 325 | } 326 | irecv_usb_control_transfer(client->recovery->client, 0x21, 1, 0, 0, 0, 0, 5000); 327 | 328 | return 0; 329 | } 330 | 331 | int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t build_identity) { 332 | const char* component = "AppleLogo"; 333 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 334 | 335 | info("Sending %s...\n", component); 336 | if (client->recovery == NULL) { 337 | if (recovery_client_new(client) < 0) { 338 | return -1; 339 | } 340 | } 341 | 342 | if (recovery_send_component(client, build_identity, component) < 0) { 343 | error("ERROR: Unable to send %s to device.\n", component); 344 | return -1; 345 | } 346 | 347 | recovery_error = irecv_send_command(client->recovery->client, "setpicture 0"); 348 | if (recovery_error != IRECV_E_SUCCESS) { 349 | error("ERROR: Unable to set %s\n", component); 350 | return -1; 351 | } 352 | 353 | recovery_error = irecv_send_command(client->recovery->client, "bgcolor 0 0 0"); 354 | if (recovery_error != IRECV_E_SUCCESS) { 355 | error("ERROR: Unable to display %s\n", component); 356 | return -1; 357 | } 358 | 359 | return 0; 360 | } 361 | 362 | int recovery_send_devicetree(struct idevicerestore_client_t* client, plist_t build_identity) { 363 | const char* component = "RestoreDeviceTree"; 364 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 365 | 366 | if(client->recovery == NULL) { 367 | if (recovery_client_new(client) < 0) { 368 | return -1; 369 | } 370 | } 371 | 372 | if (recovery_send_component(client, build_identity, component) < 0) { 373 | error("ERROR: Unable to send %s to device.\n", component); 374 | return -1; 375 | } 376 | 377 | recovery_error = irecv_send_command(client->recovery->client, "devicetree"); 378 | if (recovery_error != IRECV_E_SUCCESS) { 379 | error("ERROR: Unable to execute %s\n", component); 380 | return -1; 381 | } 382 | 383 | return 0; 384 | } 385 | 386 | int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_identity) { 387 | const char *component = "RestoreRamDisk"; 388 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 389 | 390 | if(client->recovery == NULL) { 391 | if (recovery_client_new(client) < 0) { 392 | return -1; 393 | } 394 | } 395 | 396 | if (recovery_send_component(client, build_identity, component) < 0) { 397 | error("ERROR: Unable to send %s to device.\n", component); 398 | return -1; 399 | } 400 | 401 | irecv_send_command(client->recovery->client, "getenv ramdisk-delay"); 402 | 403 | recovery_error = irecv_send_command(client->recovery->client, "ramdisk"); 404 | if (recovery_error != IRECV_E_SUCCESS) { 405 | error("ERROR: Unable to execute %s\n", component); 406 | return -1; 407 | } 408 | 409 | sleep(2); 410 | 411 | return 0; 412 | } 413 | 414 | int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t build_identity) { 415 | const char* component = "RestoreKernelCache"; 416 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 417 | 418 | if (client->recovery == NULL) { 419 | if (recovery_client_new(client) < 0) { 420 | return -1; 421 | } 422 | } 423 | 424 | if (recovery_send_component(client, build_identity, component) < 0) { 425 | error("ERROR: Unable to send %s to device.\n", component); 426 | return -1; 427 | } 428 | 429 | irecv_usb_control_transfer(client->recovery->client, 0x21, 1, 0, 0, 0, 0, 5000); 430 | 431 | if (client->restore_boot_args) { 432 | char setba[256]; 433 | strcpy(setba, "setenv boot-args "); 434 | strcat(setba, client->restore_boot_args); 435 | recovery_error = irecv_send_command(client->recovery->client, setba); 436 | } 437 | 438 | recovery_error = irecv_send_command(client->recovery->client, "bootx"); 439 | if (recovery_error != IRECV_E_SUCCESS) { 440 | error("ERROR: Unable to execute %s\n", component); 441 | return -1; 442 | } 443 | 444 | return 0; 445 | } 446 | 447 | int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { 448 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 449 | 450 | if(client->recovery == NULL) { 451 | if (recovery_client_new(client) < 0) { 452 | return -1; 453 | } 454 | } 455 | 456 | recovery_error = irecv_get_ecid(client->recovery->client, (long long unsigned int*)ecid); 457 | if (recovery_error != IRECV_E_SUCCESS) { 458 | return -1; 459 | } 460 | 461 | return 0; 462 | } 463 | 464 | int recovery_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) { 465 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 466 | 467 | if(client->recovery == NULL) { 468 | if (recovery_client_new(client) < 0) { 469 | return -1; 470 | } 471 | } 472 | 473 | recovery_error = irecv_get_nonce(client->recovery->client, nonce, nonce_size); 474 | if (recovery_error != IRECV_E_SUCCESS) { 475 | return -1; 476 | } 477 | 478 | return 0; 479 | } 480 | 481 | int recovery_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { 482 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 483 | 484 | if(client->recovery == NULL) { 485 | if (recovery_client_new(client) < 0) { 486 | return -1; 487 | } 488 | } 489 | 490 | recovery_error = irecv_get_cpid(client->recovery->client, cpid); 491 | if (recovery_error != IRECV_E_SUCCESS) { 492 | return -1; 493 | } 494 | 495 | return 0; 496 | } 497 | 498 | int recovery_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { 499 | irecv_error_t recovery_error = IRECV_E_SUCCESS; 500 | 501 | if(client->recovery == NULL) { 502 | if (recovery_client_new(client) < 0) { 503 | return -1; 504 | } 505 | } 506 | 507 | recovery_error = irecv_get_bdid(client->recovery->client, bdid); 508 | if (recovery_error != IRECV_E_SUCCESS) { 509 | return -1; 510 | } 511 | 512 | return 0; 513 | } 514 | 515 | int recovery_send_reset(struct idevicerestore_client_t* client) 516 | { 517 | irecv_error_t recovery_error = irecv_send_command(client->recovery->client, "reset"); 518 | return 0; 519 | } 520 | 521 | -------------------------------------------------------------------------------- /src/recovery.h: -------------------------------------------------------------------------------- 1 | /* 2 | * recovery.h 3 | * Functions for handling idevices in recovery mode 4 | * 5 | * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_RECOVERY_H 25 | #define IDEVICERESTORE_RECOVERY_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include "common.h" 36 | 37 | struct recovery_client_t { 38 | irecv_client_t client; 39 | const char* ipsw; 40 | plist_t tss; 41 | }; 42 | 43 | int recovery_check_mode(struct idevicerestore_client_t* client); 44 | int recovery_client_new(struct idevicerestore_client_t* client); 45 | void recovery_client_free(struct idevicerestore_client_t* client); 46 | int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build_identity); 47 | int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); 48 | int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_identity); 49 | int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t build_identity); 50 | int recovery_send_devicetree(struct idevicerestore_client_t* client, plist_t build_identity); 51 | int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_identity); 52 | int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t build_identity); 53 | int recovery_send_reset(struct idevicerestore_client_t* client); 54 | int recovery_send_ticket(struct idevicerestore_client_t* client); 55 | int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable); 56 | int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); 57 | int recovery_get_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); 58 | int recovery_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid); 59 | int recovery_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid); 60 | 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/restore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * restore.h 3 | * Functions for handling idevices in restore mode 4 | * 5 | * Copyright (c) 2010-2012 Martin Szulecki. All Rights Reserved. 6 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 7 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef IDEVICERESTORE_RESTORE_H 25 | #define IDEVICERESTORE_RESTORE_H 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | struct restore_client_t { 36 | plist_t tss; 37 | plist_t bbtss; 38 | idevice_t device; 39 | char* udid; 40 | unsigned int operation; 41 | const char* filesystem; 42 | uint64_t protocol_version; 43 | restored_client_t client; 44 | }; 45 | 46 | int restore_check_mode(struct idevicerestore_client_t* client); 47 | const char* restore_check_product_type(struct idevicerestore_client_t* client); 48 | int restore_client_new(struct idevicerestore_client_t* client); 49 | void restore_client_free(struct idevicerestore_client_t* client); 50 | int restore_reboot(struct idevicerestore_client_t* client); 51 | const char* restore_progress_string(unsigned int operation); 52 | int restore_handle_status_msg(restored_client_t client, plist_t msg); 53 | int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); 54 | int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem); 55 | int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity); 56 | int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); 57 | int restore_send_kernelcache(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity); 58 | int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem); 59 | int restore_open_with_timeout(struct idevicerestore_client_t* client); 60 | int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem); 61 | 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/tss.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tss.h 3 | * Definitions for communicating with Apple's TSS server. 4 | * 5 | * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. 6 | * Copyright (c) 2010 Joshua Hill. All Rights Reserved. 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #ifndef IDEVICERESTORE_TSS_H 24 | #define IDEVICERESTORE_TSS_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | 32 | plist_t tss_send_request(plist_t request, const char* server_url_string); 33 | plist_t tss_create_request(plist_t build_identity, uint64_t ecid, unsigned char* nonce, int nonce_size); 34 | plist_t tss_create_baseband_request(plist_t build_identity, uint64_t ecid, uint64_t bb_cert_id, unsigned char* bb_snum, uint64_t bb_snum_size, unsigned char* bb_nonce, int bb_nonce_size); 35 | int tss_get_ticket(plist_t tss, unsigned char** ticket, unsigned int* tlen); 36 | int tss_get_entry_path(plist_t tss, const char* entry, char** path); 37 | int tss_get_blob_by_path(plist_t tss, const char* path, unsigned char** blob); 38 | int tss_get_blob_by_name(plist_t tss, const char* entry, unsigned char** blob); 39 | 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | --------------------------------------------------------------------------------