diff options
Diffstat (limited to 'src/idevicerestore.c')
-rw-r--r-- | src/idevicerestore.c | 971 |
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; } + |