summaryrefslogtreecommitdiffstats
path: root/src/idevicerestore.c
diff options
context:
space:
mode:
authorGravatar Joshua Hill2010-06-21 05:03:27 -0400
committerGravatar Joshua Hill2010-06-21 05:03:27 -0400
commitef2a1037524ad559658a31793d4a96e07773cebc (patch)
tree45416d3eadabe83df85c97a7ce326f27258376c3 /src/idevicerestore.c
parent8708123ecfd708239137445c9f83c86a96ae63b7 (diff)
parentb39abb66ffa5e26f38cb2ba03562d091decafc84 (diff)
downloadidevicerestore-ef2a1037524ad559658a31793d4a96e07773cebc.tar.gz
idevicerestore-ef2a1037524ad559658a31793d4a96e07773cebc.tar.bz2
Merge branch 'rcg'
Diffstat (limited to 'src/idevicerestore.c')
-rw-r--r--src/idevicerestore.c971
1 files changed, 500 insertions, 471 deletions
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index aaff4d6..69363fb 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <getopt.h>
#include <plist/plist.h>
#include <libirecovery.h>
#include <libimobiledevice/restore.h>
@@ -38,46 +39,70 @@
#include "recovery.h"
#include "idevicerestore.h"
-#define UNKNOWN_MODE 0
-#define DFU_MODE 1
-#define NORMAL_MODE 2
-#define RECOVERY_MODE 3
-#define RESTORE_MODE 4
-
+int idevicerestore_quit = 0;
int idevicerestore_debug = 0;
-static int idevicerestore_mode = 0;
-static int idevicerestore_quit = 0;
-static int idevicerestore_custom = 0;
-
-void usage(int argc, char* argv[]);
-int write_file(const char* filename, char* data, int size);
-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 idevicerestore_erase = 0;
+int idevicerestore_custom = 0;
+int idevicerestore_verbose = 0;
+int idevicerestore_exclude = 0;
+int idevicerestore_mode = MODE_UNKNOWN;
+idevicerestore_device_t* idevicerestore_device = NULL;
+
+static struct option long_opts[] = {
+ { "uuid", required_argument, NULL, 'u' },
+ { "debug", no_argument, NULL, 'd' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
+ { "erase", no_argument, NULL, 'e' },
+ { "custom", no_argument, NULL, 'c' },
+ { "exclude", no_argument, NULL, 'x' },
+ { NULL, 0, NULL, 0}
+};
+
+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(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n");
+ printf(" -d, --debug\t\tenable communication debugging\n");
+ printf(" -v, --verbose\t\tenable verbose output\n");
+ printf(" -h, --help\t\tprints usage information\n");
+ printf(" -e, --erase\t\tperform a full restore, erasing all data\n");
+ printf(" -c, --custom\t\trestore with a custom firmware\n");
+ printf(" -x, --exclude\t\texclude nor/baseband upgrade\n");
+ printf("\n");
+}
int main(int argc, char* argv[]) {
int opt = 0;
+ int optindex = 0;
char* ipsw = NULL;
char* uuid = NULL;
uint64_t ecid = 0;
- while ((opt = getopt(argc, argv, "vdhcu:")) > 0) {
+ while ((opt = getopt_long(argc, argv, "vdhcexu:", long_opts, &optindex)) > 0) {
switch (opt) {
case 'h':
usage(argc, argv);
break;
- case 'v':
- idevicerestore_debug += 1;
+ case 'd':
+ idevicerestore_debug = 1;
+ break;
+
+ case 'e':
+ idevicerestore_erase = 1;
break;
case 'c':
idevicerestore_custom = 1;
break;
- case 'd':
- idevicerestore_debug = 3;
+ case 'x':
+ idevicerestore_exclude = 1;
+ break;
+
+ case 'v':
+ idevicerestore_verbose = 1;
break;
case 'u':
@@ -86,604 +111,608 @@ int main(int argc, char* argv[]) {
default:
usage(argc, argv);
- break;
+ return -1;
}
}
argc -= optind;
argv += optind;
- if (argc == 1)
+ if (argc == 1) {
ipsw = argv[0];
-
- if (ipsw == NULL) {
- error("ERROR: Please supply an IPSW\n");
+ } else {
+ usage(argc, argv);
return -1;
}
- idevice_t device = NULL;
- irecv_client_t recovery = NULL;
- lockdownd_client_t lockdown = NULL;
- irecv_error_t recovery_error = IRECV_E_SUCCESS;
- idevice_error_t device_error = IDEVICE_E_SUCCESS;
- lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS;
-
- /* determine recovery or normal mode */
- info("Checking for device in normal mode...\n");
- device_error = idevice_new(&device, uuid);
- if (device_error != IDEVICE_E_SUCCESS) {
- info("Checking for the device in recovery mode...\n");
- recovery_error = irecv_open(&recovery);
- if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to find device, is it plugged in?\n");
- return -1;
- }
- info("Found device in recovery mode\n");
- idevicerestore_mode = RECOVERY_MODE;
+ if(idevicerestore_debug) {
+ idevice_set_debug_level(5);
+ }
- } else {
- info("Found device in normal mode\n");
- idevicerestore_mode = NORMAL_MODE;
+ // 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;
}
- /* retrieve ECID */
- if (idevicerestore_mode == NORMAL_MODE) {
- lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
- if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Unable to connect to lockdownd\n");
- idevice_free(device);
- return -1;
- }
+ // discover the device type
+ int id = check_device(uuid);
+ if (id < 0) {
+ error("ERROR: Unable to discover device type\n");
+ return -1;
+ }
+ idevicerestore_device = &idevicerestore_devices[id];
- plist_t unique_chip_node = NULL;
- lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node);
- if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Unable to get UniqueChipID from lockdownd\n");
- lockdownd_client_free(lockdown);
- idevice_free(device);
+ if (idevicerestore_mode == MODE_RESTORE) {
+ if (restore_reboot(uuid) < 0) {
+ error("ERROR: Unable to exit restore mode\n");
return -1;
}
+ }
- if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {
- error("ERROR: Unable to get ECID\n");
- lockdownd_client_free(lockdown);
- idevice_free(device);
- 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;
+ }
- plist_get_uint_val(unique_chip_node, &ecid);
- lockdownd_client_free(lockdown);
- plist_free(unique_chip_node);
- idevice_free(device);
- lockdown = NULL;
- device = NULL;
-
- } else if (idevicerestore_mode == RECOVERY_MODE) {
- recovery_error = irecv_get_ecid(recovery, &ecid);
- if (recovery_error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to get device ECID\n");
- irecv_close(recovery);
+ // 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;
}
- irecv_close(recovery);
- recovery = NULL;
- }
- if (ecid != 0) {
- info("Found ECID %llu\n", ecid);
} else {
- error("Unable to find device ECID\n");
- return -1;
+ 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");
+ }
}
- /* parse buildmanifest */
- int buildmanifest_size = 0;
- char* buildmanifest_data = NULL;
- info("Extracting BuildManifest.plist from IPSW\n");
- if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &buildmanifest_data, &buildmanifest_size) < 0) {
- error("ERROR: Unable to extract BuildManifest.plist IPSW\n");
- return -1;
- }
+ // 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->device_id > DEVICE_IPOD2G) {
+ 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);
- plist_t manifest = NULL;
- plist_from_xml(buildmanifest_data, buildmanifest_size, &manifest);
+ // 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;
+ }
- info("Creating TSS request\n");
- plist_t tss_request = tss_create_request(manifest, ecid);
- if (tss_request == NULL) {
- error("ERROR: Unable to create TSS request\n");
- plist_free(manifest);
- return -1;
- }
- plist_free(manifest);
+ 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;
+ }
- info("Sending TSS request\n");
- plist_t tss_response = tss_send_request(tss_request);
- if (tss_response == NULL) {
- error("ERROR: Unable to get response from TSS server\n");
- plist_free(tss_request);
- return -1;
+ } else {
+ error("ERROR: Unable to fetch SHSH blobs for this firmware\n");
+ plist_free(buildmanifest);
+ return -1;
+ }
+ }
}
- info("Got TSS response\n");
- // Get name of filesystem DMG in IPSW
+ // Extract filesystem from IPSW and return its name
char* filesystem = NULL;
- plist_t filesystem_node = plist_dict_get_item(tss_request, "OS");
- if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) {
- error("ERROR: Unable to find filesystem node\n");
- plist_free(tss_request);
+ 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;
}
- plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info");
- if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) {
- error("ERROR: Unable to find filesystem info node\n");
- plist_free(tss_request);
- return -1;
- }
-
- plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path");
- if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) {
- error("ERROR: Unable to find filesystem info path node\n");
- plist_free(tss_request);
- return -1;
+ // if the device is in normal mode, place device into recovery mode
+ if (idevicerestore_mode == MODE_NORMAL) {
+ 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;
+ }
}
- plist_get_string_val(filesystem_info_path_node, &filesystem);
- plist_free(tss_request);
- info("Extracting filesystem from IPSW\n");
- if (ipsw_extract_to_file(ipsw, filesystem, filesystem) < 0) {
- error("ERROR: Unable to extract filesystem\n");
- return -1;
+ // if the device is in DFU mode, place device into recovery mode
+ if (idevicerestore_mode == MODE_DFU) {
+ 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;
+ }
}
- /* place device into recovery mode if required */
- if (idevicerestore_mode == NORMAL_MODE) {
- info("Entering recovery mode...\n");
- device_error = idevice_new(&device, uuid);
- if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to find device\n");
- plist_free(tss_response);
+ // if the device is in recovery mode, place device into restore mode
+ if (idevicerestore_mode == MODE_RECOVERY) {
+ 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;
}
+ }
- lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore");
- if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Unable to connect to lockdownd service\n");
- plist_free(tss_response);
- idevice_free(device);
+ // device is finally in restore mode, let's do this
+ if (idevicerestore_mode == MODE_RESTORE) {
+ info("Restoring device... \n");
+ if (restore_device(uuid, ipsw, tss, filesystem) < 0) {
+ error("ERROR: Unable to restore device\n");
return -1;
}
+ }
- lockdown_error = lockdownd_enter_recovery(lockdown);
- if (lockdown_error != LOCKDOWN_E_SUCCESS) {
- error("ERROR: Unable to place device in recovery mode\n");
- lockdownd_client_free(lockdown);
- plist_free(tss_response);
- idevice_free(device);
+ // device has finished restoring, lets see if we need to activate
+ if (idevicerestore_mode == MODE_NORMAL) {
+ info("Checking activation status\n");
+ int activation = activate_check_status(uuid);
+ if (activation < 0) {
+ error("ERROR: Unable to check activation status\n");
return -1;
}
- lockdownd_client_free(lockdown);
- idevice_free(device);
- lockdown = NULL;
- device = NULL;
+ if (activation == 0) {
+ info("Activating device... \n");
+ if (activate_device(uuid) < 0) {
+ error("ERROR: Unable to activate device\n");
+ return -1;
+ }
+ }
}
- /* upload data to make device boot restore mode */
- if (recovery_send_ibec(ipsw, tss_response) < 0) {
- error("ERROR: Unable to send iBEC\n");
- plist_free(tss_response);
- return -1;
+ info("Cleaning up...\n");
+ if (filesystem)
+ unlink(filesystem);
+
+ info("DONE\n");
+ return 0;
+}
+
+int check_mode(const char* uuid) {
+ int mode = MODE_UNKNOWN;
+
+ if (recovery_check_mode() == 0) {
+ info("Found device in recovery mode\n");
+ mode = MODE_RECOVERY;
}
- sleep(1);
- if (recovery_send_applelogo(ipsw, tss_response) < 0) {
- error("ERROR: Unable to send AppleLogo\n");
- plist_free(tss_response);
- return -1;
+ else if (dfu_check_mode() == 0) {
+ info("Found device in DFU mode\n");
+ mode = MODE_DFU;
}
- if (recovery_send_devicetree(ipsw, tss_response) < 0) {
- error("ERROR: Unable to send DeviceTree\n");
- plist_free(tss_response);
- return -1;
+ else if (normal_check_mode(uuid) == 0) {
+ info("Found device in normal mode\n");
+ mode = MODE_NORMAL;
}
- if (recovery_send_ramdisk(ipsw, tss_response) < 0) {
- error("ERROR: Unable to send Ramdisk\n");
- plist_free(tss_response);
- return -1;
+ else if (restore_check_mode(uuid) == 0) {
+ info("Found device in restore mode\n");
+ mode = MODE_RESTORE;
}
- // for some reason iboot requires a hard reset after ramdisk
- // or things start getting wacky
- printf("Please unplug your device, then plug it back in\n");
- printf("Hit any key to continue...");
- getchar();
+ return mode;
+}
- if (recovery_send_kernelcache(ipsw, tss_response) < 0) {
- error("ERROR: Unable to send KernelCache\n");
- plist_free(tss_response);
- return -1;
- }
+int check_device(const char* uuid) {
+ int device = DEVICE_UNKNOWN;
+ uint32_t bdid = 0;
+ uint32_t cpid = 0;
- 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);
- }
+ switch (idevicerestore_mode) {
+ case MODE_RESTORE:
+ device = restore_check_device(uuid);
+ if (device < 0) {
+ device = DEVICE_UNKNOWN;
+ }
+ break;
- device_error = idevice_new(&device, uuid);
- if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to open device\n");
- plist_free(tss_response);
- return -1;
- }
+ case MODE_NORMAL:
+ device = normal_check_device(uuid);
+ if (device < 0) {
+ device = DEVICE_UNKNOWN;
+ }
+ break;
- 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_response);
- idevice_free(device);
- return -1;
- }
+ case MODE_DFU:
+ case MODE_RECOVERY:
+ if (get_cpid(uuid, &cpid) < 0) {
+ error("ERROR: Unable to get device CPID\n");
+ break;
+ }
- 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_response);
- 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")) {
- asr_send_system_image_data_from_file(device, restore, filesystem);
-
- } else if (!strcmp(datatype, "KernelCache")) {
- int kernelcache_size = 0;
- char* kernelcache_data = NULL;
- if (get_signed_component_by_name(ipsw, tss_response, "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_data(restore, ipsw, tss_response);
-
- } 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);
- }
+ switch (cpid) {
+ case CPID_IPHONE2G:
+ // iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID
+ // so we need to check the BoardID
+ if (get_bdid(uuid, &bdid) < 0) {
+ error("ERROR: Unable to get device BDID\n");
+ break;
}
- if (RESTORE_E_SUCCESS != restore_error) {
- error("Invalid return status %d\n", restore_error);
- //idevicerestore_quit = 1;
+ switch (bdid) {
+ case BDID_IPHONE2G:
+ device = DEVICE_IPHONE2G;
+ break;
+
+ case BDID_IPHONE3G:
+ device = DEVICE_IPHONE3G;
+ break;
+
+ case BDID_IPOD1G:
+ device = DEVICE_IPOD1G;
+ break;
+
+ default:
+ device = DEVICE_UNKNOWN;
+ break;
}
+ break;
+
+ case CPID_IPHONE3GS:
+ device = DEVICE_IPHONE3GS;
+ break;
+
+ case CPID_IPOD2G:
+ device = DEVICE_IPOD2G;
+ break;
- plist_free(message);
+ case CPID_IPOD3G:
+ device = DEVICE_IPOD3G;
+ break;
+
+ case CPID_IPAD1G:
+ device = DEVICE_IPAD1G;
+ break;
+
+ default:
+ device = DEVICE_UNKNOWN;
+ break;
}
- } else {
- error("ERROR: Could not start restore. %d\n", restore_error);
- }
+ break;
- restored_client_free(restore);
- plist_free(tss_response);
- idevice_free(device);
- unlink(filesystem);
- return 0;
-}
+ default:
+ device = DEVICE_UNKNOWN;
+ break;
-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 incremental levels of verboseness\n");
- printf("\n");
- exit(1);
+ return device;
}
-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);
+int get_bdid(const char* uuid, uint32_t* bdid) {
+ switch (idevicerestore_mode) {
+ case MODE_NORMAL:
+ if (normal_get_bdid(uuid, bdid) < 0) {
+ *bdid = -1;
+ return -1;
+ }
+ break;
+
+ case MODE_DFU:
+ case MODE_RECOVERY:
+ if (recovery_get_bdid(bdid) < 0) {
+ *bdid = -1;
+ return -1;
+ }
+ break;
+
+ default:
+ error("ERROR: Device is in an invalid state\n");
return -1;
}
- int bytes = fwrite(data, 1, size, file);
- fclose(file);
+ return 0;
+}
- if (bytes != size) {
- error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size);
+int get_cpid(const char* uuid, uint32_t* cpid) {
+ switch (idevicerestore_mode) {
+ case MODE_NORMAL:
+ if (normal_get_cpid(uuid, cpid) < 0) {
+ *cpid = 0;
+ return -1;
+ }
+ break;
+
+ case MODE_DFU:
+ case MODE_RECOVERY:
+ if (recovery_get_cpid(cpid) < 0) {
+ *cpid = 0;
+ return -1;
+ }
+ break;
+
+ default:
+ error("ERROR: Device is in an invalid state\n");
return -1;
}
- return size;
+ return 0;
}
-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;
+int get_ecid(const char* uuid, uint64_t* ecid) {
+ switch (idevicerestore_mode) {
+ case MODE_NORMAL:
+ if (normal_get_ecid(uuid, ecid) < 0) {
+ *ecid = 0;
+ return -1;
+ }
+ break;
- if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) {
- continue;
+ case MODE_DFU:
+ case MODE_RECOVERY:
+ if (recovery_get_ecid(ecid) < 0) {
+ *ecid = 0;
+ return -1;
}
+ break;
+
+ default:
+ error("ERROR: Device is in an invalid state\n");
+ return -1;
+ }
- 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 0;
+}
+
+int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) {
+ int size = 0;
+ char* data = NULL;
+ int device = idevicerestore_device->device_id;
+ if (device >= DEVICE_IPHONE2G && device <= DEVICE_IPOD2G) {
+ // Older devices that don't require personalized firmwares use BuildManifesto.plist
+ if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) < 0) {
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;
+
+ } else if (device >= DEVICE_IPHONE3GS && device <= DEVICE_IPAD1G) {
+ // Whereas newer devices that do require personalized firmwares use BuildManifest.plist
+ if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) < 0) {
+ return -1;
}
- free(key);
+ } else {
+ return -1;
}
- plist_free(tss_entry);
- return -1;
+ plist_from_xml(data, size, buildmanifest);
+ return 0;
}
-int get_tss_data_by_name(plist_t tss, const char* entry, char** ppath, char** pblob) {
- *ppath = NULL;
- *pblob = NULL;
+plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) {
- 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;
+ // fetch build identities array from BuildManifest
+ plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities");
+ if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
+ error("ERROR: Unable to find build identities node\n");
+ return NULL;
}
- 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;
+ // check and make sure this identity exists in buildmanifest
+ if (identity >= plist_array_get_size(build_identities_array)) {
+ return NULL;
}
- 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_t build_identity = plist_array_get_item(build_identities_array, identity);
+ if (!build_identity || plist_get_node_type(build_identity) != PLIST_DICT) {
+ error("ERROR: Unable to find build identities node\n");
+ return NULL;
}
- plist_get_data_val(blob_node, &blob, &blob_size);
- *ppath = path;
- *pblob = blob;
- return 0;
+ return plist_copy(build_identity);
}
-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;
- img3_file* img3 = NULL;
- irecv_error_t error = 0;
+int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) {
+ plist_t request = NULL;
+ plist_t response = NULL;
+ *tss = NULL;
- 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);
+ request = tss_create_request(build_identity, ecid);
+ if (request == NULL) {
+ error("ERROR: Unable to create TSS request\n");
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);
+ info("Sending TSS request\n");
+ response = tss_send_request(request);
+ if (response == NULL) {
+ plist_free(request);
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);
+ plist_free(request);
+ *tss = response;
+ return 0;
+}
+
+int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) {
+ char* filename = NULL;
+
+ 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");
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(path);
- free(blob);
- return -1;
- }
+ plist_t filesystem_node = plist_dict_get_item(manifest_node, "OS");
+ if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) {
+ error("ERROR: Unable to find filesystem node\n");
+ return -1;
}
- if (img3_get_data(img3, &data, &size) < 0) {
- error("ERROR: Unable to reconstruct IMG3\n");
- img3_free(img3);
- free(path);
+ plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info");
+ if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) {
+ error("ERROR: Unable to find filesystem info node\n");
return -1;
}
- if (idevicerestore_debug) {
- char* out = strrchr(path, '/');
- if (out != NULL) {
- out++;
- } else {
- out = path;
- }
- write_file(out, data, size);
+ plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path");
+ if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) {
+ error("ERROR: Unable to find filesystem info path node\n");
+ return -1;
}
+ plist_get_string_val(filesystem_info_path_node, &filename);
- if (img3) {
- img3_free(img3);
- img3 = NULL;
- }
- if (blob) {
- free(blob);
- blob = NULL;
- }
- if (path) {
- free(path);
- path = NULL;
+ info("Extracting filesystem from IPSW\n");
+ if (ipsw_extract_to_file(ipsw, filename, filename) < 0) {
+ error("ERROR: Unable to extract filesystem\n");
+ return -1;
}
- *pdata = data;
- *psize = size;
+ *filesystem = filename;
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;
+int get_signed_component(const 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", path);
- if (get_tss_data_by_path(tss, path, &name, &blob) < 0) {
- error("ERROR: Unable to get data for TSS %s entry\n", path);
+ uint32_t component_size = 0;
+ char* component_data = NULL;
+ char* component_blob = NULL;
+ char* component_name = NULL;
+
+ component_name = strrchr(path, '/');
+ if (component_name != NULL) component_name++;
+ else component_name = (char*) path;
+
+ info("Extracting %s\n", component_name);
+ if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) {
+ error("ERROR: Unable to extract %s from %s\n", component_name, ipsw);
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);
+ img3 = img3_parse_file(component_data, component_size);
+ if (img3 == NULL) {
+ error("ERROR: Unable to parse IMG3: %s\n", component_name);
+ free(component_data);
return -1;
}
+ free(component_data);
- img3 = img3_parse_file(data, size);
- if (img3 == NULL) {
- error("ERROR: Unable to parse IMG3: %s\n", path);
- free(data);
- free(path);
- free(blob);
+ if (tss_get_blob_by_path(tss, path, &component_blob) < 0) {
+ error("ERROR: Unable to get SHSH blob for TSS %s entry\n", component_name);
+ img3_free(img3);
return -1;
}
- if (data) {
- free(data);
- data = NULL;
- }
- if (idevicerestore_custom == 0) {
- if (img3_replace_signature(img3, blob) < 0) {
+ if (idevicerestore_device->device_id > DEVICE_IPOD2G && idevicerestore_custom == 0) {
+ if (img3_replace_signature(img3, component_blob) < 0) {
error("ERROR: Unable to replace IMG3 signature\n");
- free(name);
- 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(name);
return -1;
}
+ img3_free(img3);
if (idevicerestore_debug) {
- char* out = strrchr(path, '/');
- if (out != NULL) {
- out++;
- } else {
- out = path;
- }
- write_file(out, data, size);
+ write_file(component_name, component_data, component_size);
}
- if (img3) {
- img3_free(img3);
- img3 = NULL;
+ *data = component_data;
+ *size = component_size;
+ return 0;
+}
+
+int write_file(const char* filename, const void* data, size_t size) {
+ size_t bytes = 0;
+ FILE* file = NULL;
+
+ info("Writing data to %s\n", filename);
+ file = fopen(filename, "wb");
+ if (file == NULL) {
+ error("read_file: Unable to open file %s\n", filename);
+ return -1;
}
- if (blob) {
- free(blob);
- blob = NULL;
+
+ 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;
}
- if (path) {
- free(name);
- name = NULL;
+
+ return size;
+}
+
+int read_file(const char* filename, char** data, uint32_t* size) {
+ size_t bytes = 0;
+ size_t length = 0;
+ FILE* file = NULL;
+ char* buffer = NULL;
+ debug("Reading data from %s\n", filename);
+
+ *size = 0;
+ *data = NULL;
+
+ file = fopen(filename, "rb");
+ if (file == NULL) {
+ error("read_file: File %s not found\n", filename);
+ return -1;
}
- *pdata = data;
- *psize = size;
+ fseek(file, 0, SEEK_END);
+ length = ftell(file);
+ rewind(file);
+
+ buffer = (char*) malloc(length);
+ if(buffer == NULL) {
+ error("ERROR: Out of memory\n");
+ fclose(file);
+ return -1;
+ }
+ bytes = fread(buffer, 1, length, file);
+ fclose(file);
+
+ if(bytes != length) {
+ error("ERROR: Unable to read entire file\n");
+ free(buffer);
+ return -1;
+ }
+
+ *size = length;
+ *data = buffer;
return 0;
}
+