summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Joshua Hill2010-06-05 11:17:05 +0800
committerGravatar rcg4u2010-06-09 17:17:28 +0800
commit7f98089a5e6663be50521063cf7171ab1bbc9fa2 (patch)
tree73a8cf475e0fb13ba8957fb3a696b7340f5cba9c
parent3761295840ba6c7672aebcb2b084a2dbf7099735 (diff)
downloadidevicerestore-7f98089a5e6663be50521063cf7171ab1bbc9fa2.tar.gz
idevicerestore-7f98089a5e6663be50521063cf7171ab1bbc9fa2.tar.bz2
Even more major cleanups and refactoring, this branch is still broken but starting to mature really well
-rw-r--r--src/activate.c8
-rw-r--r--src/activate.h2
-rw-r--r--src/dfu.c49
-rw-r--r--src/dfu.h5
-rw-r--r--src/idevicerestore.c829
-rw-r--r--src/img3.c120
-rw-r--r--src/img3.h56
-rw-r--r--src/ipsw.c3
-rw-r--r--src/ipsw.h3
-rw-r--r--src/normal.c13
-rw-r--r--src/normal.h2
-rw-r--r--src/recovery.c247
-rw-r--r--src/recovery.h2
-rw-r--r--src/restore.c199
-rw-r--r--src/restore.h15
-rw-r--r--src/tss.c125
-rw-r--r--src/tss.h8
17 files changed, 885 insertions, 801 deletions
diff --git a/src/activate.c b/src/activate.c
index 2cb4452..1fcd2e2 100644
--- a/src/activate.c
+++ b/src/activate.c
@@ -252,3 +252,11 @@ int activate_fetch_record(lockdownd_client_t client, plist_t* record) {
//free(request);
return 0;
}
+
+int activate_check_status(const char* uuid) {
+ return 1;
+}
+
+int activate_device(const char* uuid) {
+ return 0;
+}
diff --git a/src/activate.h b/src/activate.h
index 1feb11e..f992d4f 100644
--- a/src/activate.h
+++ b/src/activate.h
@@ -25,6 +25,8 @@
#include <plist/plist.h>
#include <libimobiledevice/lockdown.h>
+int activate_device(const char* uuid);
+int activate_check_status(const char* uuid);
int activate_fetch_record(lockdownd_client_t lockdown, plist_t* record);
#endif
diff --git a/src/dfu.c b/src/dfu.c
index 1da895d..1a5a037 100644
--- a/src/dfu.c
+++ b/src/dfu.c
@@ -19,10 +19,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <libirecovery.h>
#include "dfu.h"
+#include "recovery.h"
+#include "idevicerestore.h"
int dfu_check_mode() {
irecv_client_t dfu = NULL;
@@ -33,7 +36,7 @@ int dfu_check_mode() {
return -1;
}
- if(dfu->mode != kDfuMode) {
+ if (dfu->mode != kDfuMode) {
irecv_close(dfu);
return -1;
}
@@ -43,14 +46,42 @@ int dfu_check_mode() {
return 0;
}
-int dfu_get_cpid(uint32_t* cpid) {
- return 0;
-}
+int dfu_enter_recovery(const char* ipsw, plist_t tss) {
+ irecv_client_t dfu = NULL;
+ const char* component = "iBSS";
+ irecv_error_t dfu_error = IRECV_E_SUCCESS;
+ if (recovery_open_with_timeout(&dfu) < 0 || dfu->mode != kDfuMode) {
+ error("ERROR: Unable to connect to DFU device\n");
+ if (dfu)
+ irecv_close(dfu);
+ return -1;
+ }
-int dfu_get_bdid(uint32_t* bdid) {
- return 0;
-}
+ if (recovery_send_signed_component(dfu, ipsw, tss, "iBSS") < 0) {
+ error("ERROR: Unable to send %s to device\n", component);
+ irecv_close(dfu);
+ return -1;
+ }
-int dfu_get_ecid(uint64_t* ecid) {
+ dfu_error = irecv_reset(dfu);
+ if (dfu_error != IRECV_E_SUCCESS) {
+ error("ERROR: Unable to reset device\n");
+ irecv_close(dfu);
+ return -1;
+ }
+ irecv_close(dfu);
+ dfu = NULL;
+
+ // Reconnect to device, but this time make sure we're not still in DFU mode
+ if (recovery_open_with_timeout(&dfu) < 0 || dfu->mode == kDfuMode) {
+ error("ERROR: Unable to connect to recovery device\n");
+ if (dfu)
+ irecv_close(dfu);
+ return -1;
+ }
+
+ idevicerestore_mode = RECOVERY_MODE;
+ irecv_close(dfu);
+ dfu = NULL;
return 0;
}
diff --git a/src/dfu.h b/src/dfu.h
index f8f34fc..3577888 100644
--- a/src/dfu.h
+++ b/src/dfu.h
@@ -23,10 +23,9 @@
#define IDEVICERESTORE_DFU_H
#include <stdint.h>
+#include <plist/plist.h>
int dfu_check_mode();
-int dfu_get_cpid(uint32_t* cpid);
-int dfu_get_bdid(uint32_t* bdid);
-int dfu_get_ecid(uint64_t* ecid);
+int dfu_enter_recovery(const char* ipsw, plist_t tss);
#endif
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 4494f04..d2f6039 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -46,21 +46,246 @@ int idevicerestore_verbose = 0;
idevicerestore_mode_t idevicerestore_mode = UNKNOWN_MODE;
idevicerestore_device_t idevicerestore_device = UNKNOWN_DEVICE;
-void usage(int argc, char* argv[]);
-int get_device(const char* uuid);
int check_mode(const char* uuid);
+int check_device(const char* uuid);
+void usage(int argc, char* argv[]);
int get_ecid(const char* uuid, uint64_t* ecid);
int get_bdid(const char* uuid, uint32_t* bdid);
int get_cpid(const char* uuid, uint32_t* cpid);
-int write_file(const char* filename, char* data, int size);
+void device_callback(const idevice_event_t* event, void* user_data);
int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest);
plist_t get_build_identity(plist_t buildmanifest, uint32_t identity);
+int write_file(const char* filename, const char* data, uint32_t size);
+int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss);
int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem);
-int get_tss_data_by_name(plist_t tss, const char* entry, char** path, char** blob);
-int get_tss_data_by_path(plist_t tss, const char* path, char** name, char** blob);
-void device_callback(const idevice_event_t* event, void *user_data);
-int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize);
-int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize);
+int get_signed_component_by_name(char* ipsw, plist_t tss, const char* component, char** data, uint32_t* size);
+int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size);
+
+void usage(int argc, char* argv[]) {
+ char *name = strrchr(argv[0], '/');
+ printf("Usage: %s [OPTIONS] FILE\n", (name ? name + 1 : argv[0]));
+ printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n");
+ printf(" -d, \t\tenable communication debugging\n");
+ printf(" -u, \t\ttarget specific device by its 40-digit device UUID\n");
+ printf(" -h, \t\tprints usage information\n");
+ printf(" -c, \t\trestore with a custom firmware\n");
+ printf(" -v, \t\tenable verbose output\n");
+ printf("\n");
+}
+
+int main(int argc, char* argv[]) {
+ int opt = 0;
+ char* ipsw = NULL;
+ char* uuid = NULL;
+ uint64_t ecid = 0;
+ while ((opt = getopt(argc, argv, "vdhceu:")) > 0) {
+ switch (opt) {
+ case 'h':
+ usage(argc, argv);
+ break;
+
+ case 'd':
+ idevicerestore_debug = 1;
+ break;
+
+ case 'e':
+ idevicerestore_erase = 1;
+ break;
+
+ case 'c':
+ idevicerestore_custom = 1;
+ break;
+
+ case 'v':
+ idevicerestore_verbose = 1;
+ break;
+
+ case 'u':
+ uuid = optarg;
+ break;
+
+ default:
+ usage(argc, argv);
+ return -1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 1)
+ ipsw = argv[0];
+
+ if (ipsw == NULL) {
+ usage(argc, argv);
+ error("ERROR: Please supply an IPSW\n");
+ return -1;
+ }
+
+ // check which mode the device is currently in so we know where to start
+ idevicerestore_mode = check_mode(uuid);
+ if (idevicerestore_mode < 0) {
+ error("ERROR: Unable to discover current device state\n");
+ return -1;
+ }
+
+ // discover the device type
+ idevicerestore_device = check_device(uuid);
+ if (idevicerestore_device < 0) {
+ error("ERROR: Unable to discover device type\n");
+ return -1;
+ }
+
+ // extract buildmanifest
+ plist_t buildmanifest = NULL;
+ info("Extracting BuildManifest from IPSW\n");
+ if (extract_buildmanifest(ipsw, &buildmanifest) < 0) {
+ error("ERROR: Unable to extract BuildManifest from %s\n", ipsw);
+ return -1;
+ }
+
+ // choose whether this is an upgrade or a restore (default to upgrade)
+ plist_t build_identity = NULL;
+ if (idevicerestore_erase) {
+ build_identity = get_build_identity(buildmanifest, 0);
+ if (build_identity == NULL) {
+ error("ERROR: Unable to find build any identities\n");
+ plist_free(buildmanifest);
+ return -1;
+ }
+
+ } else {
+ build_identity = get_build_identity(buildmanifest, 1);
+ if (build_identity == NULL) {
+ build_identity = get_build_identity(buildmanifest, 0);
+ if (build_identity == NULL) {
+ error("ERROR: Unable to find build any identities\n");
+ plist_free(buildmanifest);
+ return -1;
+ }
+ info("No upgrade ramdisk found, default to full restore\n");
+ }
+ }
+
+ // devices are listed in order from oldest to newest
+ // devices that come after iPod2g require personalized firmwares
+ plist_t tss_request = NULL;
+ plist_t tss = NULL;
+ if (idevicerestore_device > IPOD2G_DEVICE) {
+ info("Creating TSS request\n");
+ // fetch the device's ECID for the TSS request
+ if (get_ecid(uuid, &ecid) < 0 || ecid == 0) {
+ error("ERROR: Unable to find device ECID\n");
+ return -1;
+ }
+ info("Found ECID %llu\n", ecid);
+
+ // fetch the SHSH blobs for this build identity
+ if (get_shsh_blobs(ecid, build_identity, &tss) < 0) {
+ // this might fail if the TSS server doesn't have the saved blobs for the
+ // update identity, so go ahead and try again with the restore identity
+ if (idevicerestore_erase != 1) {
+ info("Unable to fetch SHSH blobs for upgrade, retrying with full restore\n");
+ build_identity = get_build_identity(buildmanifest, 0);
+ if (build_identity == NULL) {
+ error("ERROR: Unable to find restore identity\n");
+ plist_free(buildmanifest);
+ return -1;
+ }
+
+ if (get_shsh_blobs(ecid, build_identity, &tss) < 0) {
+ // if this fails then no SHSH blobs have been saved for this firmware
+ error("ERROR: Unable to fetch SHSH blobs for this firmware\n");
+ plist_free(buildmanifest);
+ return -1;
+ }
+
+ } else {
+ error("ERROR: Unable to fetch SHSH blobs for this firmware\n");
+ plist_free(buildmanifest);
+ return -1;
+ }
+ }
+ }
+
+ // Extract filesystem from IPSW and return its name
+ char* filesystem = NULL;
+ if (extract_filesystem(ipsw, build_identity, &filesystem) < 0) {
+ error("ERROR: Unable to extract filesystem from IPSW\n");
+ if (tss)
+ plist_free(tss);
+ plist_free(buildmanifest);
+ return -1;
+ }
+
+ // if the device is in normal mode, place device into recovery mode
+ if (idevicerestore_mode == NORMAL_MODE) {
+ info("Entering recovery mode...\n");
+ if (normal_enter_recovery(uuid) < 0) {
+ error("ERROR: Unable to place device into recovery mode\n");
+ if (tss)
+ plist_free(tss);
+ plist_free(buildmanifest);
+ return -1;
+ }
+ }
+
+ // if the device is in DFU mode, place device into recovery mode
+ if (idevicerestore_mode == DFU_MODE) {
+ if (dfu_enter_recovery(ipsw, tss) < 0) {
+ error("ERROR: Unable to place device into recovery mode\n");
+ plist_free(buildmanifest);
+ if (tss)
+ plist_free(tss);
+ return -1;
+ }
+ }
+
+ // if the device is in recovery mode, place device into restore mode
+ if (idevicerestore_mode == RECOVERY_MODE) {
+ if (recovery_enter_restore(uuid, ipsw, tss) < 0) {
+ error("ERROR: Unable to place device into restore mode\n");
+ plist_free(buildmanifest);
+ if (tss)
+ plist_free(tss);
+ return -1;
+ }
+ }
+
+ // device is finally in restore mode, let's do this
+ if (idevicerestore_mode == RESTORE_MODE) {
+ info("Restoring device... \n");
+ if (restore_device(uuid, ipsw, tss, filesystem) < 0) {
+ error("ERROR: Unable to restore device\n");
+ return -1;
+ }
+ }
+
+ // device has finished restoring, lets see if we need to activate
+ if (idevicerestore_mode == NORMAL_MODE) {
+ info("Checking activation status\n");
+ int activation = activate_check_status(uuid);
+ if (activation < 0) {
+ error("ERROR: Unable to check activation status\n");
+ return -1;
+ }
+
+ if (activation == 0) {
+ info("Activating device... \n");
+ if (activate_device(uuid) < 0) {
+ error("ERROR: Unable to activate device\n");
+ return -1;
+ }
+ }
+ }
+
+ info("Cleaning up...\n");
+ if (filesystem)
+ unlink(filesystem);
+
+ info("DONE\n");
+ return 0;
+}
int check_mode(const char* uuid) {
idevicerestore_mode_t mode = UNKNOWN_MODE;
@@ -87,14 +312,14 @@ int check_mode(const char* uuid) {
return mode;
}
-int get_device(const char* uuid) {
+int check_device(const char* uuid) {
uint32_t bdid = 0;
uint32_t cpid = 0;
idevicerestore_device_t device = UNKNOWN_DEVICE;
switch (idevicerestore_mode) {
case NORMAL_MODE:
- device = normal_get_device(uuid);
+ device = normal_check_device(uuid);
if (device < 0) {
device = UNKNOWN_DEVICE;
}
@@ -175,6 +400,7 @@ int get_bdid(const char* uuid, uint32_t* bdid) {
}
break;
+ case DFU_MODE:
case RECOVERY_MODE:
if (recovery_get_bdid(bdid) < 0) {
*bdid = -1;
@@ -182,13 +408,6 @@ int get_bdid(const char* uuid, uint32_t* bdid) {
}
break;
- case DFU_MODE:
- if (dfu_get_bdid(bdid) < 0) {
- *bdid = -1;
- return -1;
- }
- break;
-
default:
error("ERROR: Device is in an invalid state\n");
return -1;
@@ -206,6 +425,7 @@ int get_cpid(const char* uuid, uint32_t* cpid) {
}
break;
+ case DFU_MODE:
case RECOVERY_MODE:
if (recovery_get_cpid(cpid) < 0) {
*cpid = 0;
@@ -213,13 +433,6 @@ int get_cpid(const char* uuid, uint32_t* cpid) {
}
break;
- case DFU_MODE:
- if (dfu_get_cpid(cpid) < 0) {
- *cpid = 0;
- return -1;
- }
- break;
-
default:
error("ERROR: Device is in an invalid state\n");
return -1;
@@ -237,6 +450,7 @@ int get_ecid(const char* uuid, uint64_t* ecid) {
}
break;
+ case DFU_MODE:
case RECOVERY_MODE:
if (recovery_get_ecid(ecid) < 0) {
*ecid = 0;
@@ -244,13 +458,6 @@ int get_ecid(const char* uuid, uint64_t* ecid) {
}
break;
- case DFU_MODE:
- if (dfu_get_ecid(ecid) < 0) {
- *ecid = 0;
- return -1;
- }
- break;
-
default:
error("ERROR: Device is in an invalid state\n");
return -1;
@@ -292,7 +499,7 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) {
}
// check and make sure this identity exists in buildmanifest
- if(identity >= plist_array_get_size(build_identities_array)) {
+ if (identity >= plist_array_get_size(build_identities_array)) {
return NULL;
}
@@ -302,18 +509,35 @@ plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) {
return NULL;
}
- return build_identity;
+ return plist_copy(build_identity);
+}
+
+int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) {
+ plist_t request = NULL;
+ plist_t response = NULL;
+ *tss = NULL;
+
+ request = tss_create_request(build_identity, ecid);
+ if (request == NULL) {
+ error("ERROR: Unable to create TSS request\n");
+ return -1;
+ }
+
+ info("Sending TSS request\n");
+ response = tss_send_request(request);
+ if (response == NULL) {
+ plist_free(request);
+ return -1;
+ }
+
+ plist_free(request);
+ *tss = response;
+ return 0;
}
int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) {
char* filename = NULL;
- int sz = 0;
- char* xml = NULL;
- plist_to_xml(build_identity, &xml, &sz);
- debug("%s", xml);
- free(xml);
-
plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest");
if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) {
error("ERROR: Unable to find manifest node\n");
@@ -349,538 +573,79 @@ int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesyst
return 0;
}
-int main(int argc, char* argv[]) {
- int opt = 0;
- char* ipsw = NULL;
- char* uuid = NULL;
- uint64_t ecid = 0;
- while ((opt = getopt(argc, argv, "vdhceu:")) > 0) {
- switch (opt) {
- case 'h':
- usage(argc, argv);
- break;
-
- case 'd':
- idevicerestore_debug = 1;
- break;
-
- case 'e':
- idevicerestore_erase = 1;
- break;
-
- case 'c':
- idevicerestore_custom = 1;
- break;
-
- case 'v':
- idevicerestore_verbose = 1;
- break;
-
- case 'u':
- uuid = optarg;
- break;
-
- default:
- usage(argc, argv);
- return -1;
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc == 1)
- ipsw = argv[0];
-
- if (ipsw == NULL) {
- usage(argc, argv);
- error("ERROR: Please supply an IPSW\n");
- return -1;
- }
-
- // check which mode the device is currently in so we know where to start
- idevicerestore_mode = check_mode(uuid);
- if (idevicerestore_mode < 0) {
- error("ERROR: Unable to discover device current mode\n");
- return -1;
- }
-
- // discover the device type
- idevicerestore_device = get_device(uuid);
- if (idevicerestore_device < 0) {
- error("ERROR: Unable to discover device type\n");
- return -1;
- }
-
- // extract buildmanifest
- plist_t buildmanifest = NULL;
- info("Extracting BuildManifest from IPSW\n");
- if (extract_buildmanifest(ipsw, &buildmanifest) < 0) {
- error("ERROR: Unable to extract BuildManifest from %s\n", ipsw);
- return -1;
- }
-
- // choose whether this is an upgrade or a restore (default to upgrade)
- plist_t build_identity = NULL;
- if(idevicerestore_erase) {
- build_identity = get_build_identity(buildmanifest, 0);
- if(build_identity == NULL) {
- error("ERROR: Unable to find build any identities\n");
- plist_free(buildmanifest);
- return -1;
- }
-
- } else {
- build_identity = get_build_identity(buildmanifest, 1);
- if(build_identity == NULL) {
- build_identity = get_build_identity(buildmanifest, 0);
- if(build_identity == NULL) {
- error("ERROR: Unable to find build any identities\n");
- plist_free(buildmanifest);
- return -1;
- }
- info("No upgrade ramdisk found, default to full restore\n");
- }
- }
-
- // devices are listed in order from oldest to newest
- // devices that come after iPod2g require personalized firmwares
- plist_t tss_request = NULL;
- plist_t tss = NULL;
- if(idevicerestore_device > IPOD2G_DEVICE) {
-
- info("Creating TSS request\n");
- // fetch the device's ECID for the TSS request
- if (get_ecid(uuid, &ecid) < 0 || ecid == 0) {
- error("ERROR: Unable to find device ECID\n");
- return -1;
- }
- info("Found ECID %llu\n", ecid);
-
- tss_request = tss_create_request(build_identity, ecid);
- if (tss_request == NULL) {
- error("ERROR: Unable to create TSS request\n");
- plist_free(buildmanifest);
- return -1;
- }
-
- info("Sending TSS request\n");
- tss = tss_send_request(tss_request);
- if (tss == NULL) {
- error("ERROR: Unable to get response from TSS server\n");
- plist_free(tss_request);
- return -1;
- }
- info("Got TSS response\n");
- plist_free(tss_request);
- }
-
- // Extract filesystem from IPSW and return its name
- char* filesystem = NULL;
- if(extract_filesystem(ipsw, build_identity, &filesystem) < 0) {
- error("ERROR: Unable to extract filesystem from IPSW\n");
- if(tss) plist_free(tss);
- plist_free(buildmanifest);
- return -1;
- }
-
- // place device into recovery mode if required
- if (idevicerestore_mode == NORMAL_MODE) {
- info("Entering recovery mode...\n");
- if (normal_enter_recovery(uuid) < 0) {
- error("ERROR: Unable to place device into recovery mode\n");
- if(tss) plist_free(tss);
- plist_free(buildmanifest);
- return -1;
- }
- }
-
- // place device into restore mode if required
- if (idevicerestore_mode == RECOVERY_MODE) {
- if (recovery_enter_restore(ipsw, tss) < 0) {
- error("ERROR: Unable to place device into restore mode\n");
- if(tss) plist_free(tss);
- plist_free(buildmanifest);
- return -1;
- }
- }
-
- idevice_event_subscribe(&device_callback, NULL);
- info("Waiting for device to enter restore mode\n");
- // block program until device has entered restore mode
- while (idevicerestore_mode != RESTORE_MODE) {
- sleep(1);
- }
-
- idevice_t device = NULL;
- idevice_error_t device_error = idevice_new(&device, uuid);
- if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to open device\n");
- plist_free(tss);
- return -1;
- }
-
- restored_client_t restore = NULL;
- restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore");
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to start restored client\n");
- plist_free(tss);
- idevice_free(device);
- return -1;
- }
-
- char* type = NULL;
- uint64_t version = 0;
- if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) {
- error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type);
- plist_free(tss);
- restored_client_free(restore);
- idevice_free(device);
- return -1;
- }
- info("Device has successfully entered restore mode\n");
-
- /* start restore process */
- char* kernelcache = NULL;
- info("Restore protocol version is %llu.\n", version);
- restore_error = restored_start_restore(restore);
- if (restore_error == RESTORE_E_SUCCESS) {
- while (!idevicerestore_quit) {
- plist_t message = NULL;
- restore_error = restored_receive(restore, &message);
- plist_t msgtype_node = plist_dict_get_item(message, "MsgType");
- if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) {
- char *msgtype = NULL;
- plist_get_string_val(msgtype_node, &msgtype);
- if (!strcmp(msgtype, "ProgressMsg")) {
- restore_error = restore_handle_progress_msg(restore, message);
-
- } else if (!strcmp(msgtype, "DataRequestMsg")) {
- // device is requesting data to be sent
- plist_t datatype_node = plist_dict_get_item(message, "DataType");
- if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) {
- char *datatype = NULL;
- plist_get_string_val(datatype_node, &datatype);
- if (!strcmp(datatype, "SystemImageData")) {
- restore_send_filesystem(device, restore, filesystem);
-
- } else if (!strcmp(datatype, "KernelCache")) {
- int kernelcache_size = 0;
- char* kernelcache_data = NULL;
- if (get_signed_component_by_name(ipsw, tss, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) {
- error("ERROR: Unable to get kernelcache file\n");
- return -1;
- }
- restore_send_kernelcache(restore, kernelcache_data, kernelcache_size);
- free(kernelcache_data);
-
- } else if (!strcmp(datatype, "NORData")) {
- restore_send_nor(restore, ipsw, tss);
-
- } else {
- // Unknown DataType!!
- error("Unknown DataType\n");
- return -1;
- }
- }
-
- } else if (!strcmp(msgtype, "StatusMsg")) {
- restore_error = restore_handle_status_msg(restore, message);
-
- } else {
- info("Received unknown message type: %s\n", msgtype);
- }
- }
-
- if (RESTORE_E_SUCCESS != restore_error) {
- error("Invalid return status %d\n", restore_error);
- //idevicerestore_quit = 1;
- }
-
- plist_free(message);
- }
- } else {
- error("ERROR: Could not start restore. %d\n", restore_error);
- }
-
- restored_client_free(restore);
- plist_free(tss);
- idevice_free(device);
- unlink(filesystem);
- return 0;
-}
-
-void device_callback(const idevice_event_t* event, void *user_data) {
- if (event->event == IDEVICE_DEVICE_ADD) {
- idevicerestore_mode = RESTORE_MODE;
- } else if (event->event == IDEVICE_DEVICE_REMOVE) {
- idevicerestore_quit = 1;
- }
-}
-
-void usage(int argc, char* argv[]) {
- char *name = strrchr(argv[0], '/');
- printf("Usage: %s [OPTIONS] FILE\n", (name ? name + 1 : argv[0]));
- printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n");
- printf(" -d, \t\tenable communication debugging\n");
- printf(" -u, \t\ttarget specific device by its 40-digit device UUID\n");
- printf(" -h, \t\tprints usage information\n");
- printf(" -c, \t\trestore with a custom firmware\n");
- printf(" -v, \t\tenable verbose output\n");
- printf("\n");
-}
-
-int write_file(const char* filename, char* data, int size) {
- debug("Writing data to %s\n", filename);
- FILE* file = fopen(filename, "wb");
- if (file == NULL) {
- error("read_file: Unable to open file %s\n", filename);
- return -1;
- }
-
- int bytes = fwrite(data, 1, size, file);
- fclose(file);
-
- if (bytes != size) {
- error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size);
- return -1;
- }
-
- return size;
-}
-
-int get_tss_data_by_path(plist_t tss, const char* path, char** pname, char** pblob) {
- *pname = NULL;
- *pblob = NULL;
-
- char* key = NULL;
- plist_t tss_entry = NULL;
- plist_dict_iter iter = NULL;
- plist_dict_new_iter(tss, &iter);
- while (1) {
- plist_dict_next_item(tss, iter, &key, &tss_entry);
- if (key == NULL)
- break;
-
- if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) {
- continue;
- }
-
- char* entry_path = NULL;
- plist_t entry_path_node = plist_dict_get_item(tss_entry, "Path");
- if (!entry_path_node || plist_get_node_type(entry_path_node) != PLIST_STRING) {
- error("ERROR: Unable to find TSS path node in entry %s\n", key);
- return -1;
- }
- plist_get_string_val(entry_path_node, &entry_path);
- if (strcmp(path, entry_path) == 0) {
- char* blob = NULL;
- uint64_t blob_size = 0;
- plist_t blob_node = plist_dict_get_item(tss_entry, "Blob");
- if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) {
- error("ERROR: Unable to find TSS blob node in entry %s\n", key);
- return -1;
- }
- plist_get_data_val(blob_node, &blob, &blob_size);
- *pname = key;
- *pblob = blob;
- return 0;
- }
-
- free(key);
- }
- plist_free(tss_entry);
-
- return -1;
-}
-
-int get_tss_data_by_name(plist_t tss, const char* entry, char** ppath, char** pblob) {
- *ppath = NULL;
- *pblob = NULL;
-
- plist_t node = plist_dict_get_item(tss, entry);
- if (!node || plist_get_node_type(node) != PLIST_DICT) {
- error("ERROR: Unable to find %s entry in TSS response\n", entry);
- return -1;
- }
-
- char* path = NULL;
- plist_t path_node = plist_dict_get_item(node, "Path");
- if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) {
- error("ERROR: Unable to find %s path in entry\n", path);
- return -1;
- }
- plist_get_string_val(path_node, &path);
-
- char* blob = NULL;
- uint64_t blob_size = 0;
- plist_t blob_node = plist_dict_get_item(node, "Blob");
- if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) {
- error("ERROR: Unable to find %s blob in entry\n", path);
- free(path);
- return -1;
- }
- plist_get_data_val(blob_node, &blob, &blob_size);
-
- *ppath = path;
- *pblob = blob;
- return 0;
-}
-
-int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize) {
- int size = 0;
- char* data = NULL;
- char* path = NULL;
- char* blob = NULL;
+int get_signed_component(char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) {
img3_file* img3 = NULL;
- irecv_error_t error = 0;
-
- info("Extracting %s from TSS response\n", component);
- if (get_tss_data_by_name(tss, component, &path, &blob) < 0) {
- error("ERROR: Unable to get data for TSS %s entry\n", component);
- return -1;
- }
+ uint32_t component_size = 0;
+ char* component_data = NULL;
+ char* component_blob = NULL;
info("Extracting %s from %s\n", path, ipsw);
- if (ipsw_extract_to_memory(ipsw, path, &data, &size) < 0) {
+ if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) {
error("ERROR: Unable to extract %s from %s\n", path, ipsw);
- free(path);
- free(blob);
return -1;
}
- img3 = img3_parse_file(data, size);
+ img3 = img3_parse_file(component_data, component_size);
if (img3 == NULL) {
error("ERROR: Unable to parse IMG3: %s\n", path);
- free(data);
- free(path);
- free(blob);
+ free(component_data);
return -1;
}
- if (data) {
- free(data);
- data = NULL;
+ free(component_data);
+
+ if (tss_get_blob_by_path(tss, path, &component_blob) < 0) {
+ error("ERROR: Unable to get SHSH blob for TSS %s entry\n", path);
+ img3_free(img3);
+ return -1;
}
- if (idevicerestore_custom == 0) {
- if (img3_replace_signature(img3, blob) < 0) {
+ if (idevicerestore_device > IPOD2G_DEVICE && idevicerestore_custom == 0) {
+ if (img3_replace_signature(img3, component_blob) < 0) {
error("ERROR: Unable to replace IMG3 signature\n");
- free(path);
- free(blob);
+ free(component_blob);
+ img3_free(img3);
return -1;
}
}
+ free(component_blob);
- if (img3_get_data(img3, &data, &size) < 0) {
+ if (img3_get_data(img3, &component_data, &component_size) < 0) {
error("ERROR: Unable to reconstruct IMG3\n");
img3_free(img3);
- free(path);
return -1;
}
+ img3_free(img3);
if (idevicerestore_debug) {
char* out = strrchr(path, '/');
if (out != NULL) {
out++;
} else {
- out = path;
+ out = (char*) path;
}
- write_file(out, data, size);
- }
-
- if (img3) {
- img3_free(img3);
- img3 = NULL;
- }
- if (blob) {
- free(blob);
- blob = NULL;
- }
- if (path) {
- free(path);
- path = NULL;
+ write_file(out, component_data, component_size);
}
- *pdata = data;
- *psize = size;
+ *data = component_data;
+ *size = component_size;
return 0;
}
-int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize) {
- int size = 0;
- char* data = NULL;
- char* name = NULL;
- char* blob = NULL;
- img3_file* img3 = NULL;
- irecv_error_t error = 0;
-
- info("Extracting %s from TSS response\n", path);
- if (get_tss_data_by_path(tss, path, &name, &blob) < 0) {
- error("ERROR: Unable to get data for TSS %s entry\n", path);
- return -1;
- }
-
- info("Extracting %s from %s\n", path, ipsw);
- if (ipsw_extract_to_memory(ipsw, path, &data, &size) < 0) {
- error("ERROR: Unable to extract %s from %s\n", path, ipsw);
- free(path);
- free(blob);
- return -1;
- }
-
- img3 = img3_parse_file(data, size);
- if (img3 == NULL) {
- error("ERROR: Unable to parse IMG3: %s\n", path);
- free(data);
- free(path);
- free(blob);
+int write_file(const char* filename, const char* data, uint32_t size) {
+ info("Writing data to %s\n", filename);
+ FILE* file = fopen(filename, "wb");
+ if (file == NULL) {
+ error("read_file: Unable to open file %s\n", filename);
return -1;
}
- if (data) {
- free(data);
- data = NULL;
- }
- if (idevicerestore_custom == 0) {
- if (img3_replace_signature(img3, blob) < 0) {
- error("ERROR: Unable to replace IMG3 signature\n");
- free(name);
- free(blob);
- return -1;
- }
- }
+ int bytes = fwrite(data, 1, size, file);
+ fclose(file);
- if (img3_get_data(img3, &data, &size) < 0) {
- error("ERROR: Unable to reconstruct IMG3\n");
- img3_free(img3);
- free(name);
+ if (bytes != size) {
+ error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size);
return -1;
}
- if (idevicerestore_debug) {
- char* out = strrchr(path, '/');
- if (out != NULL) {
- out++;
- } else {
- out = path;
- }
- write_file(out, data, size);
- }
-
- if (img3) {
- img3_free(img3);
- img3 = NULL;
- }
- if (blob) {
- free(blob);
- blob = NULL;
- }
- if (path) {
- free(name);
- name = NULL;
- }
-
- *pdata = data;
- *psize = size;
- return 0;
+ return size;
}
diff --git a/src/img3.c b/src/img3.c
index ec7bcbf..5c79e54 100644
--- a/src/img3.c
+++ b/src/img3.c
@@ -29,20 +29,20 @@
img3_file* img3_parse_file(char* data, int size) {
int data_offset = 0;
img3_header* header = (img3_header*) data;
- if(header->signature != kImg3Container) {
+ if (header->signature != kImg3Container) {
error("ERROR: Invalid IMG3 file\n");
return NULL;
}
img3_file* image = (img3_file*) malloc(sizeof(img3_file));
- if(image == NULL) {
+ if (image == NULL) {
error("ERROR: Unable to allocate memory for IMG3 file\n");
return NULL;
}
memset(image, '\0', sizeof(img3_file));
image->header = (img3_header*) malloc(sizeof(img3_header));
- if(image->header == NULL) {
+ if (image->header == NULL) {
error("ERROR: Unable to allocate memory for IMG3 header\n");
img3_free(image);
return NULL;
@@ -51,12 +51,12 @@ img3_file* img3_parse_file(char* data, int size) {
data_offset += sizeof(img3_header);
img3_element_header* current = NULL;
- while(data_offset < size) {
+ while (data_offset < size) {
current = (img3_element_header*) &data[data_offset];
- switch(current->signature) {
+ switch (current->signature) {
case kTypeElement:
image->type_element = img3_parse_element(&data[data_offset]);
- if(image->type_element == NULL) {
+ if (image->type_element == NULL) {
error("ERROR: Unable to parse TYPE element\n");
img3_free(image);
return NULL;
@@ -66,7 +66,7 @@ img3_file* img3_parse_file(char* data, int size) {
case kDataElement:
image->data_element = img3_parse_element(&data[data_offset]);
- if(image->data_element == NULL) {
+ if (image->data_element == NULL) {
error("ERROR: Unable to parse DATA element\n");
img3_free(image);
return NULL;
@@ -76,7 +76,7 @@ img3_file* img3_parse_file(char* data, int size) {
case kVersElement:
image->vers_element = img3_parse_element(&data[data_offset]);
- if(image->vers_element == NULL) {
+ if (image->vers_element == NULL) {
error("ERROR: Unable to parse VERS element\n");
img3_free(image);
return NULL;
@@ -86,7 +86,7 @@ img3_file* img3_parse_file(char* data, int size) {
case kSepoElement:
image->sepo_element = img3_parse_element(&data[data_offset]);
- if(image->sepo_element == NULL) {
+ if (image->sepo_element == NULL) {
error("ERROR: Unable to parse SEPO element\n");
img3_free(image);
return NULL;
@@ -96,7 +96,7 @@ img3_file* img3_parse_file(char* data, int size) {
case kBordElement:
image->bord_element = img3_parse_element(&data[data_offset]);
- if(image->bord_element == NULL) {
+ if (image->bord_element == NULL) {
error("ERROR: Unable to parse BORD element\n");
img3_free(image);
return NULL;
@@ -105,9 +105,9 @@ img3_file* img3_parse_file(char* data, int size) {
break;
case kKbagElement:
- if(image->kbag1_element == NULL) {
+ if (image->kbag1_element == NULL) {
image->kbag1_element = img3_parse_element(&data[data_offset]);
- if(image->kbag1_element == NULL) {
+ if (image->kbag1_element == NULL) {
error("ERROR: Unable to parse first KBAG element\n");
img3_free(image);
return NULL;
@@ -115,7 +115,7 @@ img3_file* img3_parse_file(char* data, int size) {
} else {
image->kbag2_element = img3_parse_element(&data[data_offset]);
- if(image->kbag2_element == NULL) {
+ if (image->kbag2_element == NULL) {
error("ERROR: Unable to parse second KBAG element\n");
img3_free(image);
return NULL;
@@ -126,7 +126,7 @@ img3_file* img3_parse_file(char* data, int size) {
case kEcidElement:
image->ecid_element = img3_parse_element(&data[data_offset]);
- if(image->ecid_element == NULL) {
+ if (image->ecid_element == NULL) {
error("ERROR: Unable to parse ECID element\n");
img3_free(image);
return NULL;
@@ -136,7 +136,7 @@ img3_file* img3_parse_file(char* data, int size) {
case kShshElement:
image->shsh_element = img3_parse_element(&data[data_offset]);
- if(image->shsh_element == NULL) {
+ if (image->shsh_element == NULL) {
error("ERROR: Unable to parse SHSH element\n");
img3_free(image);
return NULL;
@@ -146,7 +146,7 @@ img3_file* img3_parse_file(char* data, int size) {
case kCertElement:
image->cert_element = img3_parse_element(&data[data_offset]);
- if(image->cert_element == NULL) {
+ if (image->cert_element == NULL) {
error("ERROR: Unable to parse CERT element\n");
img3_free(image);
return NULL;
@@ -168,14 +168,14 @@ img3_file* img3_parse_file(char* data, int size) {
img3_element* img3_parse_element(char* data) {
img3_element_header* element_header = (img3_element_header*) data;
img3_element* element = (img3_element*) malloc(sizeof(img3_element));
- if(element == NULL) {
+ if (element == NULL) {
error("ERROR: Unable to allocate memory for IMG3 element\n");
return NULL;
}
memset(element, '\0', sizeof(img3_element));
element->data = (char*) malloc(element_header->full_size);
- if(element->data == NULL) {
+ if (element->data == NULL) {
error("ERROR: Unable to allocate memory for IMG3 element data\n");
free(element);
return NULL;
@@ -188,57 +188,57 @@ img3_element* img3_parse_element(char* data) {
}
void img3_free(img3_file* image) {
- if(image != NULL) {
- if(image->header != NULL) {
+ if (image != NULL) {
+ if (image->header != NULL) {
free(image->header);
}
- if(image->type_element != NULL) {
+ if (image->type_element != NULL) {
img3_free_element(image->type_element);
image->type_element = NULL;
}
- if(image->data_element != NULL) {
+ if (image->data_element != NULL) {
img3_free_element(image->data_element);
image->data_element = NULL;
}
- if(image->vers_element != NULL) {
+ if (image->vers_element != NULL) {
img3_free_element(image->vers_element);
image->vers_element = NULL;
}
- if(image->sepo_element != NULL) {
+ if (image->sepo_element != NULL) {
img3_free_element(image->sepo_element);
image->sepo_element = NULL;
}
- if(image->bord_element != NULL) {
+ if (image->bord_element != NULL) {
img3_free_element(image->bord_element);
image->bord_element = NULL;
}
- if(image->kbag1_element != NULL) {
+ if (image->kbag1_element != NULL) {
img3_free_element(image->kbag1_element);
image->kbag1_element = NULL;
}
- if(image->kbag2_element != NULL) {
+ if (image->kbag2_element != NULL) {
img3_free_element(image->kbag2_element);
image->kbag2_element = NULL;
}
- if(image->ecid_element != NULL) {
+ if (image->ecid_element != NULL) {
img3_free_element(image->ecid_element);
image->ecid_element = NULL;
}
- if(image->shsh_element != NULL) {
+ if (image->shsh_element != NULL) {
img3_free_element(image->shsh_element);
image->shsh_element = NULL;
}
- if(image->cert_element != NULL) {
+ if (image->cert_element != NULL) {
img3_free_element(image->cert_element);
image->cert_element = NULL;
}
@@ -249,8 +249,8 @@ void img3_free(img3_file* image) {
}
void img3_free_element(img3_element* element) {
- if(element != NULL) {
- if(element->data != NULL) {
+ if (element != NULL) {
+ if (element->data != NULL) {
free(element->data);
element->data = NULL;
}
@@ -262,37 +262,37 @@ void img3_free_element(img3_element* element) {
int img3_replace_signature(img3_file* image, char* signature) {
int offset = 0;
img3_element* ecid = img3_parse_element(&signature[offset]);
- if(ecid == NULL || ecid->type != kEcidElement) {
+ if (ecid == NULL || ecid->type != kEcidElement) {
error("ERROR: Unable to find ECID element in signature\n");
return -1;
}
offset += ecid->header->full_size;
img3_element* shsh = img3_parse_element(&signature[offset]);
- if(shsh == NULL || shsh->type != kShshElement) {
+ if (shsh == NULL || shsh->type != kShshElement) {
error("ERROR: Unable to find SHSH element in signature\n");
return -1;
}
offset += shsh->header->full_size;
img3_element* cert = img3_parse_element(&signature[offset]);
- if(cert == NULL || cert->type != kCertElement) {
+ if (cert == NULL || cert->type != kCertElement) {
error("ERROR: Unable to find CERT element in signature\n");
return -1;
}
offset += cert->header->full_size;
- if(image->ecid_element != NULL) {
+ if (image->ecid_element != NULL) {
img3_free_element(image->ecid_element);
}
image->ecid_element = ecid;
- if(image->shsh_element != NULL) {
+ if (image->shsh_element != NULL) {
img3_free_element(image->shsh_element);
}
image->shsh_element = shsh;
- if(image->cert_element != NULL) {
+ if (image->cert_element != NULL) {
img3_free_element(image->cert_element);
}
image->cert_element = cert;
@@ -305,39 +305,39 @@ int img3_get_data(img3_file* image, char** pdata, int* psize) {
int size = sizeof(img3_header);
// Add up the size of the image first so we can allocate our memory
- if(image->type_element != NULL) {
+ if (image->type_element != NULL) {
size += image->type_element->header->full_size;
}
- if(image->data_element != NULL) {
+ if (image->data_element != NULL) {
size += image->data_element->header->full_size;
}
- if(image->vers_element != NULL) {
+ if (image->vers_element != NULL) {
size += image->vers_element->header->full_size;
}
- if(image->sepo_element != NULL) {
+ if (image->sepo_element != NULL) {
size += image->sepo_element->header->full_size;
}
- if(image->bord_element != NULL) {
+ if (image->bord_element != NULL) {
size += image->bord_element->header->full_size;
}
- if(image->kbag1_element != NULL) {
+ if (image->kbag1_element != NULL) {
size += image->kbag1_element->header->full_size;
}
- if(image->kbag2_element != NULL) {
+ if (image->kbag2_element != NULL) {
size += image->kbag2_element->header->full_size;
}
- if(image->ecid_element != NULL) {
+ if (image->ecid_element != NULL) {
size += image->ecid_element->header->full_size;
}
- if(image->shsh_element != NULL) {
+ if (image->shsh_element != NULL) {
size += image->shsh_element->header->full_size;
}
- if(image->cert_element != NULL) {
+ if (image->cert_element != NULL) {
size += image->cert_element->header->full_size;
}
char* data = (char*) malloc(size);
- if(data == NULL) {
+ if (data == NULL) {
error("ERROR: Unable to allocate memory for IMG3 data\n");
return -1;
}
@@ -351,49 +351,49 @@ int img3_get_data(img3_file* image, char** pdata, int* psize) {
offset += sizeof(img3_header);
// Copy each section over to the new buffer
- if(image->type_element != NULL) {
+ if (image->type_element != NULL) {
memcpy(&data[offset], image->type_element->data, image->type_element->header->full_size);
offset += image->type_element->header->full_size;
}
- if(image->data_element != NULL) {
+ if (image->data_element != NULL) {
memcpy(&data[offset], image->data_element->data, image->data_element->header->full_size);
offset += image->data_element->header->full_size;
}
- if(image->vers_element != NULL) {
+ if (image->vers_element != NULL) {
memcpy(&data[offset], image->vers_element->data, image->vers_element->header->full_size);
offset += image->vers_element->header->full_size;
}
- if(image->sepo_element != NULL) {
+ if (image->sepo_element != NULL) {
memcpy(&data[offset], image->sepo_element->data, image->sepo_element->header->full_size);
offset += image->sepo_element->header->full_size;
}
- if(image->bord_element != NULL) {
+ if (image->bord_element != NULL) {
memcpy(&data[offset], image->bord_element->data, image->bord_element->header->full_size);
offset += image->bord_element->header->full_size;
}
- if(image->kbag1_element != NULL) {
+ if (image->kbag1_element != NULL) {
memcpy(&data[offset], image->kbag1_element->data, image->kbag1_element->header->full_size);
offset += image->kbag1_element->header->full_size;
}
- if(image->kbag2_element != NULL) {
+ if (image->kbag2_element != NULL) {
memcpy(&data[offset], image->kbag2_element->data, image->kbag2_element->header->full_size);
offset += image->kbag2_element->header->full_size;
}
- if(image->ecid_element != NULL) {
+ if (image->ecid_element != NULL) {
memcpy(&data[offset], image->ecid_element->data, image->ecid_element->header->full_size);
offset += image->ecid_element->header->full_size;
}
- if(image->shsh_element != NULL) {
+ if (image->shsh_element != NULL) {
memcpy(&data[offset], image->shsh_element->data, image->shsh_element->header->full_size);
header->shsh_offset = offset - sizeof(img3_header);
offset += image->shsh_element->header->full_size;
}
- if(image->cert_element != NULL) {
+ if (image->cert_element != NULL) {
memcpy(&data[offset], image->cert_element->data, image->cert_element->header->full_size);
offset += image->cert_element->header->full_size;
}
- if(offset != size) {
+ if (offset != size) {
error("ERROR: Incorrectly sized image data\n");
free(data);
*pdata = 0;
diff --git a/src/img3.h b/src/img3.h
index c172455..5fddbfc 100644
--- a/src/img3.h
+++ b/src/img3.h
@@ -23,39 +23,39 @@
#define IDEVICERESTORE_IMG3_H
typedef enum {
- kNorContainer = 0x696D6733, // img3
- kImg3Container = 0x496D6733, // Img3
- k8900Container = 0x30303938, // 8900
- kImg2Container = 0x494D4732 // IMG2
+ kNorContainer = 0x696D6733, // img3
+ kImg3Container = 0x496D6733, // Img3
+ k8900Container = 0x30303938, // 8900
+ kImg2Container = 0x494D4732 // IMG2
} img3_container;
typedef enum {
- kDataElement = 0x44415441, // DATA
- kTypeElement = 0x54595045, // TYPE
- kKbagElement = 0x4B424147, // KBAG
- kShshElement = 0x53485348, // SHSH
- kCertElement = 0x43455254, // CERT
- kChipElement = 0x43484950, // CHIP
- kProdElement = 0x50524F44, // PROD
- kSdomElement = 0x53444F4D, // SDOM
- kVersElement = 0x56455253, // VERS
- kBordElement = 0x424F5244, // BORD
- kSepoElement = 0x5345504F, // SEPO
- kEcidElement = 0x45434944 // ECID
+ kDataElement = 0x44415441, // DATA
+ kTypeElement = 0x54595045, // TYPE
+ kKbagElement = 0x4B424147, // KBAG
+ kShshElement = 0x53485348, // SHSH
+ kCertElement = 0x43455254, // CERT
+ kChipElement = 0x43484950, // CHIP
+ kProdElement = 0x50524F44, // PROD
+ kSdomElement = 0x53444F4D, // SDOM
+ kVersElement = 0x56455253, // VERS
+ kBordElement = 0x424F5244, // BORD
+ kSepoElement = 0x5345504F, // SEPO
+ kEcidElement = 0x45434944 // ECID
} img3_element_type;
typedef struct {
- unsigned int signature;
- unsigned int full_size;
- unsigned int data_size;
- unsigned int shsh_offset;
- unsigned int image_type;
+ unsigned int signature;
+ unsigned int full_size;
+ unsigned int data_size;
+ unsigned int shsh_offset;
+ unsigned int image_type;
} img3_header;
typedef struct {
- unsigned int signature;
- unsigned int full_size;
- unsigned int data_size;
+ unsigned int signature;
+ unsigned int full_size;
+ unsigned int data_size;
} img3_element_header;
typedef struct {
@@ -79,11 +79,11 @@ typedef struct {
img3_element* cert_element;
} img3_file;
-img3_file* img3_parse_file(char* data, int size);
-img3_element* img3_parse_element(char* data);
-int img3_replace_signature(img3_file* image, char* signature);
void img3_free(img3_file* image);
-int img3_get_data(img3_file* image, char** pdata, int* psize);
+img3_element* img3_parse_element(char* data);
void img3_free_element(img3_element* element);
+img3_file* img3_parse_file(char* data, int size);
+int img3_get_data(img3_file* image, char** pdata, int* psize);
+int img3_replace_signature(img3_file* image, char* signature);
#endif
diff --git a/src/ipsw.c b/src/ipsw.c
index ca28596..6c5d504 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -20,6 +20,7 @@
*/
#include <zip.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -119,7 +120,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi
return 0;
}
-int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, int* psize) {
+int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize) {
ipsw_archive* archive = ipsw_open(ipsw);
if (archive == NULL || archive->zip == NULL) {
error("ERROR: Invalid archive\n");
diff --git a/src/ipsw.h b/src/ipsw.h
index 20f6bf5..aa0fd1d 100644
--- a/src/ipsw.h
+++ b/src/ipsw.h
@@ -23,6 +23,7 @@
#define IDEVICERESTORE_IPSW_H
#include <zip.h>
+#include <stdint.h>
typedef struct {
int index;
@@ -31,7 +32,7 @@ typedef struct {
unsigned char* data;
} ipsw_file;
-int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, int* psize);
+int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, uint32_t* psize);
void ipsw_free_file(ipsw_file* file);
#endif
diff --git a/src/normal.c b/src/normal.c
index 3c2bf5c..ab9216c 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -61,7 +61,7 @@ int normal_check_mode(const char* uuid) {
return 0;
}
-int normal_get_device(const char* uuid) {
+int normal_check_device(const char* uuid) {
idevice_t device = NULL;
char* product_type = NULL;
plist_t product_type_node = NULL;
@@ -88,7 +88,8 @@ int normal_get_device(const char* uuid) {
}
if (!product_type_node || plist_get_node_type(product_type_node) != PLIST_STRING) {
- if(product_type_node) plist_free(product_type_node);
+ if (product_type_node)
+ plist_free(product_type_node);
lockdownd_client_free(lockdown);
idevice_free(device);
return -1;
@@ -102,8 +103,8 @@ int normal_get_device(const char* uuid) {
device = NULL;
int i = 0;
- for(i = 0; idevicerestore_products[i] != NULL; i++) {
- if(!strcmp(product_type, idevicerestore_products[i])) {
+ for (i = 0; idevicerestore_products[i] != NULL; i++) {
+ if (!strcmp(product_type, idevicerestore_products[i])) {
idevicerestore_device = i;
break;
}
@@ -146,7 +147,7 @@ int normal_enter_recovery(const char* uuid) {
lockdown = NULL;
device = NULL;
- if(recovery_open_with_timeout(&recovery) < 0) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
error("ERROR: Unable to enter recovery mode\n");
return -1;
}
@@ -187,7 +188,7 @@ int normal_get_ecid(const char* uuid, uint64_t* ecid) {
lockdownd_error_t lockdown_error = IDEVICE_E_SUCCESS;
device_error = idevice_new(&device, uuid);
- if(device_error != IDEVICE_E_SUCCESS) {
+ if (device_error != IDEVICE_E_SUCCESS) {
return -1;
}
diff --git a/src/normal.h b/src/normal.h
index bde1de0..cdc29ba 100644
--- a/src/normal.h
+++ b/src/normal.h
@@ -25,7 +25,7 @@
#include <stdint.h>
int normal_check_mode(const char* uuid);
-int normal_get_device(const char* uuid);
+int normal_check_device(const char* uuid);
int normal_enter_recovery(const char* uuid);
int normal_get_cpid(const char* uuid, uint32_t* cpid);
int normal_get_bdid(const char* uuid, uint32_t* cpid);
diff --git a/src/recovery.c b/src/recovery.c
index 3bfb97e..a0a1151 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -23,6 +23,8 @@
#include <stdlib.h>
#include <stdint.h>
#include <libirecovery.h>
+#include <libimobiledevice/restore.h>
+#include <libimobiledevice/libimobiledevice.h>
#include "tss.h"
#include "img3.h"
@@ -38,7 +40,7 @@ int recovery_check_mode() {
return -1;
}
- if(recovery->mode == kDfuMode) {
+ if (recovery->mode == kDfuMode) {
irecv_close(recovery);
return -1;
}
@@ -48,7 +50,10 @@ int recovery_check_mode() {
return 0;
}
-int recovery_enter_restore(const char* ipsw, plist_t tss) {
+int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) {
+ idevice_t device = NULL;
+ restored_client_t restore = NULL;
+
// upload data to make device boot restore mode
if (recovery_send_ibec(ipsw, tss) < 0) {
error("ERROR: Unable to send iBEC\n");
@@ -72,7 +77,7 @@ int recovery_enter_restore(const char* ipsw, plist_t tss) {
}
// for some reason iboot requires a hard reset after ramdisk
- // or things start getting wacky
+ // or things start getting wacky
printf("Please unplug your device, then plug it back in\n");
printf("Hit any key to continue...");
getchar();
@@ -82,6 +87,13 @@ int recovery_enter_restore(const char* ipsw, plist_t tss) {
return -1;
}
+ info("Waiting for device to enter restore mode\n");
+ if (restore_open_with_timeout(uuid, &device, &restore) < 0) {
+ error("ERROR: Unable to connect to device in restore mode\n");
+ return -1;
+ }
+ restore_close(device, restore);
+
return 0;
}
@@ -90,244 +102,225 @@ int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plis
char* data = NULL;
char* path = NULL;
char* blob = NULL;
- img3_file* img3 = NULL;
irecv_error_t error = 0;
- if (get_signed_component_by_name(ipsw, tss, component, &data, &size) < 0) {
+ if (tss_get_entry_path(tss, component, &path) < 0) {
+ error("ERROR: Unable to get component path\n");
+ return -1;
+ }
+
+ if (get_signed_component(ipsw, tss, path, &data, &size) < 0) {
error("ERROR: Unable to get signed component: %s\n", component);
+ free(path);
return -1;
}
+ free(path);
info("Sending %s...\n", component);
error = irecv_send_buffer(client, data, size);
if (error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to send IMG3: %s\n", path);
- img3_free(img3);
+ error("ERROR: Unable to send component: %s\n", component);
free(data);
- free(path);
return -1;
}
-
- if (data) {
- free(data);
- data = NULL;
- }
+ free(data);
return 0;
}
-irecv_error_t recovery_open_with_timeout(irecv_client_t* client) {
+int recovery_open_with_timeout(irecv_client_t* client) {
int i = 0;
- irecv_error_t error = 0;
- for (i = 10; i > 0; i--) {
- error = irecv_open(client);
- if (error == IRECV_E_SUCCESS) {
- return error;
+ int attempts = 10;
+ irecv_client_t recovery = NULL;
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+
+ for (i = 1; i <= attempts; i++) {
+ recovery_error = irecv_open(client);
+ if (recovery_error == IRECV_E_SUCCESS) {
+ break;
+ }
+
+ if (i == attempts) {
+ error("ERROR: Unable to connect to device in recovery mode\n");
+ return -1;
}
sleep(2);
- info("Retrying connection...\n");
+ debug("Retrying connection...\n");
}
- error("ERROR: Unable to connect to recovery device.\n");
- return error;
+ *client = recovery;
+ return 0;
}
int recovery_send_ibec(const char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char* component = "iBEC";
+ irecv_client_t recovery = NULL;
+ const char* component = "iBEC";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- error = irecv_send_command(client, "setenv auto-boot true");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "setenv auto-boot true");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to set auto-boot environmental variable\n");
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "saveenv");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "saveenv");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to save environmental variable\n");
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "iBEC") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "go");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "go");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
int recovery_send_applelogo(const char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char* component = "AppleLogo";
+ irecv_client_t recovery = NULL;
+ const char* component = "applelogo";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
info("Sending %s...\n", component);
-
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "AppleLogo") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "setpicture 1");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "setpicture 1");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to set %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "bgcolor 0 0 0");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "bgcolor 0 0 0");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to display %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
int recovery_send_devicetree(const char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char *component = "RestoreDeviceTree";
+ irecv_client_t recovery = NULL;
+ const char* component = "devicetree";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreDeviceTree") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "devicetree");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "devicetree");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
int recovery_send_ramdisk(const char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char *component = "RestoreRamDisk";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+ irecv_client_t recovery = NULL;
+ const char *component = "ramdisk";
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = recovery_open_with_timeout(&recovery);
+ if (recovery_error != IRECV_E_SUCCESS) {
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreRamDisk") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "ramdisk");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "ramdisk");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
int recovery_send_kernelcache(const char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char *component = "RestoreKernelCache";
+ irecv_client_t recovery = NULL;
+ const char* component = "kernelcache";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreKernelCache") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "bootx");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "bootx");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
-
int recovery_get_ecid(uint64_t* ecid) {
irecv_client_t recovery = NULL;
- if(recovery_open_with_timeout(&recovery) < 0) {
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- irecv_error_t error = irecv_get_ecid(recovery, ecid);
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_get_ecid(recovery, ecid);
+ if (recovery_error != IRECV_E_SUCCESS) {
irecv_close(recovery);
return -1;
}
@@ -339,12 +332,14 @@ int recovery_get_ecid(uint64_t* ecid) {
int recovery_get_cpid(uint32_t* cpid) {
irecv_client_t recovery = NULL;
- if(recovery_open_with_timeout(&recovery) < 0) {
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- irecv_error_t error = irecv_get_cpid(recovery, cpid);
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_get_cpid(recovery, cpid);
+ if (recovery_error != IRECV_E_SUCCESS) {
irecv_close(recovery);
return -1;
}
@@ -356,12 +351,14 @@ int recovery_get_cpid(uint32_t* cpid) {
int recovery_get_bdid(uint32_t* bdid) {
irecv_client_t recovery = NULL;
- if(recovery_open_with_timeout(&recovery) < 0) {
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- irecv_error_t error = irecv_get_bdid(recovery, bdid);
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_get_bdid(recovery, bdid);
+ if (recovery_error != IRECV_E_SUCCESS) {
irecv_close(recovery);
return -1;
}
diff --git a/src/recovery.h b/src/recovery.h
index b191aa5..1953c6a 100644
--- a/src/recovery.h
+++ b/src/recovery.h
@@ -26,7 +26,7 @@
#include <plist/plist.h>
int recovery_check_mode();
-int recovery_enter_restore(const char* ipsw, plist_t tss);
+int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss);
int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component);
irecv_error_t recovery_open_with_timeout(irecv_client_t* client);
int recovery_send_ibec(const char* ipsw, plist_t tss);
diff --git a/src/restore.c b/src/restore.c
index fd6fec2..ce9d41b 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <libimobiledevice/restore.h>
+#include "tss.h"
#include "restore.h"
#include "idevicerestore.h"
@@ -44,6 +45,8 @@
#define WAIT_FOR_DEVICE 33
#define LOAD_NOR 36
+static int restore_device_connected = 0;
+
int restore_check_mode(const char* uuid) {
char* type = NULL;
uint64_t version = 0;
@@ -77,8 +80,81 @@ int restore_check_mode(const char* uuid) {
return 0;
}
+void restore_device_callback(const idevice_event_t* event, void* user_data) {
+ if (event->event == IDEVICE_DEVICE_ADD) {
+ restore_device_connected = 1;
+
+ } else if (event->event == IDEVICE_DEVICE_REMOVE) {
+ restore_device_connected = 0;
+ }
+}
+
+int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* restore) {
+ int i = 0;
+ int attempt = 10;
+ char* type = NULL;
+ uint64_t version = 0;
+ idevice_t context = NULL;
+ restored_client_t client = NULL;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+ restored_error_t restore_error = RESTORE_E_SUCCESS;
+
+ *device = NULL;
+ *restore = NULL;
+
+ device_error = idevice_event_subscribe(&restore_device_callback, NULL);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ error("ERROR: Unable to subscribe to device events\n");
+ return -1;
+ }
+
+ for (i = 1; i <= attempt; i++) {
+ if (restore_device_connected == 1) {
+ break;
+ }
+
+ if (i == attempt) {
+ error("ERROR: Unable to connect to device in restore mode\n");
+ }
+
+ sleep(2);
+ }
+
+ device_error = idevice_new(&context, uuid);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ return -1;
+ }
+
+ restore_error = restored_client_new(context, &client, "idevicerestore");
+ if (restore_error != RESTORE_E_SUCCESS) {
+ idevice_event_unsubscribe();
+ idevice_free(context);
+ return -1;
+ }
+
+ restore_error = restored_query_type(client, &type, &version);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ restored_client_free(client);
+ idevice_event_unsubscribe();
+ idevice_free(context);
+ return -1;
+ }
+
+ *device = context;
+ *restore = client;
+ return 0;
+}
+
+void restore_close(idevice_t device, restored_client_t restore) {
+ if (restore)
+ restored_client_free(restore);
+ if (device)
+ idevice_free(device);
+ idevice_event_unsubscribe();
+}
+
const char* restore_progress_string(unsigned int operation) {
- switch(operation) {
+ switch (operation) {
case CREATE_PARTITION_MAP:
return "Creating partition map";
@@ -126,7 +202,6 @@ const char* restore_progress_string(unsigned int operation) {
}
}
-
int restore_handle_progress_msg(restored_client_t client, plist_t msg) {
plist_t node = NULL;
uint64_t operation = 0;
@@ -163,7 +238,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) {
return 0;
}
-int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem) {
+int restore_send_filesystem(idevice_t device, restored_client_t client, const char* filesystem) {
int i = 0;
char buffer[0x1000];
uint32_t recv_bytes = 0;
@@ -327,7 +402,7 @@ int restore_send_filesystem(idevice_t device, restored_client_t client, const ch
return ret;
}
-int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len) {
+int restore_send_kernelcache(restored_client_t client, char* kernel_data, int len) {
info("Sending kernelcache\n");
plist_t kernelcache_node = plist_new_data(kernel_data, len);
@@ -347,19 +422,17 @@ int restore_send_kernelcache(restored_client_t client, char *kernel_data, int le
return 0;
}
-int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) {
+int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) {
char* llb_path = NULL;
- char* llb_blob = NULL;
- if (get_tss_data_by_name(tss, "LLB", &llb_path, &llb_blob) < 0) {
+ if (tss_get_entry_path(tss, "LLB", &llb_path) < 0) {
error("ERROR: Unable to get LLB info from TSS response\n");
return -1;
}
char* llb_filename = strstr(llb_path, "LLB");
if (llb_filename == NULL) {
- error("ERROR: Unable to extrac firmware path from LLB filename\n");
+ error("ERROR: Unable to extract firmware path from LLB filename\n");
free(llb_path);
- free(llb_blob);
return -1;
}
@@ -378,7 +451,6 @@ int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) {
if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) {
error("ERROR: Unable to extract firmware manifest from ipsw\n");
free(llb_path);
- free(llb_blob);
return -1;
}
@@ -392,7 +464,7 @@ int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) {
if (filename != NULL) {
memset(firmware_filename, '\0', sizeof(firmware_filename));
snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
- if (get_signed_component_by_path(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) {
+ if (get_signed_component(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) {
error("ERROR: Unable to get signed LLB\n");
return -1;
}
@@ -407,7 +479,7 @@ int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) {
while (filename != NULL) {
memset(firmware_filename, '\0', sizeof(firmware_filename));
snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
- if (get_signed_component_by_path(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) {
+ if (get_signed_component(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) {
error("ERROR: Unable to get signed firmware %s\n", firmware_filename);
break;
}
@@ -436,3 +508,106 @@ int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss) {
plist_free(dict);
return 0;
}
+
+int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) {
+ idevice_t device = NULL;
+ idevice_error_t device_error = idevice_new(&device, uuid);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ error("ERROR: Unable to open device\n");
+ plist_free(tss);
+ return -1;
+ }
+
+ restored_client_t restore = NULL;
+ restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore");
+ if (restore_error != RESTORE_E_SUCCESS) {
+ error("ERROR: Unable to start restored client\n");
+ plist_free(tss);
+ idevice_free(device);
+ return -1;
+ }
+
+ char* type = NULL;
+ uint64_t version = 0;
+ if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) {
+ error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type);
+ plist_free(tss);
+ restored_client_free(restore);
+ idevice_free(device);
+ return -1;
+ }
+ info("Device has successfully entered restore mode\n");
+
+ /* start restore process */
+ char* kernelcache = NULL;
+ info("Restore protocol version is %llu.\n", version);
+ restore_error = restored_start_restore(restore);
+ if (restore_error == RESTORE_E_SUCCESS) {
+ while (!idevicerestore_quit) {
+ plist_t message = NULL;
+ restore_error = restored_receive(restore, &message);
+ plist_t msgtype_node = plist_dict_get_item(message, "MsgType");
+ if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) {
+ char *msgtype = NULL;
+ plist_get_string_val(msgtype_node, &msgtype);
+ if (!strcmp(msgtype, "ProgressMsg")) {
+ restore_error = restore_handle_progress_msg(restore, message);
+
+ } else if (!strcmp(msgtype, "DataRequestMsg")) {
+ // device is requesting data to be sent
+ plist_t datatype_node = plist_dict_get_item(message, "DataType");
+ if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) {
+ char *datatype = NULL;
+ plist_get_string_val(datatype_node, &datatype);
+ if (!strcmp(datatype, "SystemImageData")) {
+ restore_send_filesystem(device, restore, filesystem);
+
+ } else if (!strcmp(datatype, "KernelCache")) {
+ int kernelcache_size = 0;
+ char* kernelcache_data = NULL;
+ char* kernelcache_path = NULL;
+ if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) {
+ error("ERROR: Unable to find kernelcache path\n");
+ return -1;
+ }
+
+ if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) {
+ error("ERROR: Unable to get kernelcache file\n");
+ return -1;
+ }
+ restore_send_kernelcache(restore, kernelcache_data, kernelcache_size);
+ free(kernelcache_data);
+
+ } else if (!strcmp(datatype, "NORData")) {
+ restore_send_nor(restore, ipsw, tss);
+
+ } else {
+ // Unknown DataType!!
+ error("Unknown DataType\n");
+ return -1;
+ }
+ }
+
+ } else if (!strcmp(msgtype, "StatusMsg")) {
+ restore_error = restore_handle_status_msg(restore, message);
+
+ } else {
+ info("Received unknown message type: %s\n", msgtype);
+ }
+ }
+
+ if (RESTORE_E_SUCCESS != restore_error) {
+ error("Invalid return status %d\n", restore_error);
+ //idevicerestore_quit = 1;
+ }
+
+ plist_free(message);
+ }
+ } else {
+ error("ERROR: Could not start restore. %d\n", restore_error);
+ }
+
+ restored_client_free(restore);
+ idevice_free(device);
+ return 0;
+}
diff --git a/src/restore.h b/src/restore.h
index f344b5d..99ba80b 100644
--- a/src/restore.h
+++ b/src/restore.h
@@ -22,16 +22,19 @@
#ifndef IDEVICERESTORE_RESTORE_H
#define IDEVICERESTORE_RESTORE_H
+#include <plist/plist.h>
#include <libimobiledevice/restore.h>
-
-#include "restore.h"
+#include <libimobiledevice/libimobiledevice.h>
int restore_check_mode(const char* uuid);
-int restore_handle_progress_msg(restored_client_t client, plist_t msg);
+const char* restore_progress_string(unsigned int operation);
+void restore_close(idevice_t device, restored_client_t restore);
int restore_handle_status_msg(restored_client_t client, plist_t msg);
-int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem);
+int restore_handle_progress_msg(restored_client_t client, plist_t msg);
+int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss);
int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len);
-int restore_send_nor(restored_client_t client, char* ipsw, plist_t tss);
-const char* restore_progress_string(unsigned int operation);
+int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem);
+int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* client);
+int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem);
#endif
diff --git a/src/tss.c b/src/tss.c
index a9e9456..6696b60 100644
--- a/src/tss.c
+++ b/src/tss.c
@@ -125,11 +125,13 @@ plist_t tss_create_request(plist_t build_identity, uint64_t ecid) {
free(key);
}
- int sz = 0;
- char* xml = NULL;
- plist_to_xml(tss_request, &xml, &sz);
- debug("%s", xml);
- free(xml);
+ if (idevicerestore_debug) {
+ int sz = 0;
+ char* xml = NULL;
+ plist_to_xml(tss_request, &xml, &sz);
+ debug("%s", xml);
+ free(xml);
+ }
return tss_request;
}
@@ -184,7 +186,6 @@ plist_t tss_send_request(plist_t tss_request) {
curl_global_cleanup();
if (strstr(response->content, "MESSAGE=SUCCESS") == NULL) {
- error("ERROR: Unable to get signature from this firmware\n");
free(response->content);
free(response);
return NULL;
@@ -205,15 +206,115 @@ plist_t tss_send_request(plist_t tss_request) {
free(response->content);
free(response);
- int sz = 0;
- char* xml = NULL;
- plist_to_xml(tss_response, &xml, &sz);
- debug("%s", xml);
- free(xml);
+ if (idevicerestore_debug) {
+ int sz = 0;
+ char* xml = NULL;
+ plist_to_xml(tss_response, &xml, &sz);
+ debug("%s", xml);
+ free(xml);
+ }
return tss_response;
}
-void tss_stitch_img3(img3_file* file, plist_t signature) {
+int tss_get_entry_path(plist_t tss, const char* entry, char** path) {
+ char* path_string = NULL;
+ plist_t path_node = NULL;
+ plist_t entry_node = NULL;
+
+ *path = NULL;
+
+ entry_node = plist_dict_get_item(tss, entry);
+ if (!entry_node || plist_get_node_type(entry_node) != PLIST_DICT) {
+ error("ERROR: Unable to find %s entry in TSS response\n", entry);
+ return -1;
+ }
+
+ path_node = plist_dict_get_item(entry_node, "Path");
+ if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) {
+ error("ERROR: Unable to find %s path in entry\n", path_string);
+ return -1;
+ }
+ plist_get_string_val(path_node, &path_string);
+
+ *path = path_string;
+ return 0;
+}
+
+int tss_get_blob_by_path(plist_t tss, const char* path, char** blob) {
+ int i = 0;
+ uint32_t tss_size = 0;
+ uint64_t blob_size = 0;
+ char* entry_key = NULL;
+ char* blob_data = NULL;
+ char* entry_path = NULL;
+ plist_t tss_entry = NULL;
+ plist_t blob_node = NULL;
+ plist_t path_node = NULL;
+ plist_dict_iter iter = NULL;
+
+ *blob = NULL;
+
+ plist_dict_new_iter(tss, &iter);
+ tss_size = plist_dict_get_size(tss);
+ for (i = 0; i < tss_size; i++) {
+ plist_dict_next_item(tss, iter, &entry_key, &tss_entry);
+ if (entry_key == NULL)
+ break;
+
+ if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) {
+ continue;
+ }
+
+ path_node = plist_dict_get_item(tss_entry, "Path");
+ if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) {
+ error("ERROR: Unable to find TSS path node in entry %s\n", entry_key);
+ return -1;
+ }
+
+ plist_get_string_val(path_node, &entry_path);
+ if (strcmp(path, entry_path) == 0) {
+ blob_node = plist_dict_get_item(tss_entry, "Blob");
+ if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) {
+ error("ERROR: Unable to find TSS blob node in entry %s\n", entry_key);
+ return -1;
+ }
+ plist_get_data_val(blob_node, &blob_data, &blob_size);
+ break;
+ }
+
+ free(entry_key);
+ }
+
+ if (blob_data == NULL || blob_size <= 0) {
+ return -1;
+ }
+
+ *blob = blob_data;
+ return 0;
+}
+
+int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob) {
+ uint64_t blob_size = 0;
+ char* blob_data = NULL;
+ plist_t blob_node = NULL;
+ plist_t tss_entry = NULL;
+
+ *blob = NULL;
+
+ tss_entry = plist_dict_get_item(tss, entry);
+ if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) {
+ error("ERROR: Unable to find %s entry in TSS response\n", entry);
+ return -1;
+ }
+
+ blob_node = plist_dict_get_item(tss_entry, "Blob");
+ if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) {
+ error("ERROR: Unable to find blob in %s entry\n", entry);
+ return -1;
+ }
+ plist_get_data_val(blob_node, &blob_data, &blob_size);
+ *blob = blob_data;
+ return 0;
}
diff --git a/src/tss.h b/src/tss.h
index e18843b..ff60da0 100644
--- a/src/tss.h
+++ b/src/tss.h
@@ -24,10 +24,10 @@
#include <plist/plist.h>
-#include "img3.h"
-
+plist_t tss_send_request(plist_t request);
plist_t tss_create_request(plist_t build_identity, uint64_t ecid);
-plist_t tss_send_request(plist_t tss_request);
-void tss_stitch_img3(img3_file* file, plist_t signature);
+int tss_get_entry_path(plist_t tss, const char* entry, char** path);
+int tss_get_blob_by_path(plist_t tss, const char* path, char** blob);
+int tss_get_blob_by_name(plist_t tss, const char* entry, char** blob);
#endif