diff options
Diffstat (limited to 'src/idevicerestore.c')
-rw-r--r-- | src/idevicerestore.c | 971 |
1 files changed, 471 insertions, 500 deletions
diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 69363fb..aaff4d6 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -23,7 +23,6 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <getopt.h> #include <plist/plist.h> #include <libirecovery.h> #include <libimobiledevice/restore.h> @@ -39,70 +38,46 @@ #include "recovery.h" #include "idevicerestore.h" -int idevicerestore_quit = 0; -int idevicerestore_debug = 0; -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} -}; +#define UNKNOWN_MODE 0 +#define DFU_MODE 1 +#define NORMAL_MODE 2 +#define RECOVERY_MODE 3 +#define RESTORE_MODE 4 -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 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 main(int argc, char* argv[]) { int opt = 0; - int optindex = 0; char* ipsw = NULL; char* uuid = NULL; uint64_t ecid = 0; - while ((opt = getopt_long(argc, argv, "vdhcexu:", long_opts, &optindex)) > 0) { + while ((opt = getopt(argc, argv, "vdhcu:")) > 0) { switch (opt) { case 'h': usage(argc, argv); break; - case 'd': - idevicerestore_debug = 1; - break; - - case 'e': - idevicerestore_erase = 1; + case 'v': + idevicerestore_debug += 1; break; case 'c': idevicerestore_custom = 1; break; - case 'x': - idevicerestore_exclude = 1; - break; - - case 'v': - idevicerestore_verbose = 1; + case 'd': + idevicerestore_debug = 3; break; case 'u': @@ -111,608 +86,604 @@ int main(int argc, char* argv[]) { default: usage(argc, argv); - return -1; + break; } } argc -= optind; argv += optind; - if (argc == 1) { + if (argc == 1) ipsw = argv[0]; - } else { - usage(argc, argv); - return -1; - } - - if(idevicerestore_debug) { - idevice_set_debug_level(5); - } - - // 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 - int id = check_device(uuid); - if (id < 0) { - error("ERROR: Unable to discover device type\n"); + if (ipsw == NULL) { + error("ERROR: Please supply an IPSW\n"); return -1; } - idevicerestore_device = &idevicerestore_devices[id]; - if (idevicerestore_mode == MODE_RESTORE) { - if (restore_reboot(uuid) < 0) { - error("ERROR: Unable to exit restore mode\n"); + 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; - // 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; + } else { + info("Found device in normal mode\n"); + idevicerestore_mode = NORMAL_MODE; } - // 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); + /* 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; } - } 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"); + 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); + 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"); + 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; } + + 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); + 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; + } - // 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; - } + /* 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; + } - 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; - } + plist_t manifest = NULL; + plist_from_xml(buildmanifest_data, buildmanifest_size, &manifest); - } else { - error("ERROR: Unable to fetch SHSH blobs for this firmware\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); - // Extract filesystem from IPSW and return its name + 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; + } + info("Got TSS response\n"); + + // Get name of filesystem DMG in IPSW 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); + 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); 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_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; } - // 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; - } + 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; } + plist_get_string_val(filesystem_info_path_node, &filesystem); + plist_free(tss_request); - // 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; - } + info("Extracting filesystem from IPSW\n"); + if (ipsw_extract_to_file(ipsw, filesystem, filesystem) < 0) { + error("ERROR: Unable to extract filesystem\n"); + return -1; } - // 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"); + /* 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); return -1; } - } - // 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"); + 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); return -1; } - if (activation == 0) { - info("Activating device... \n"); - if (activate_device(uuid) < 0) { - error("ERROR: Unable to activate 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); + 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; + lockdownd_client_free(lockdown); + idevice_free(device); + lockdown = NULL; + device = NULL; + } - if (recovery_check_mode() == 0) { - info("Found device in recovery mode\n"); - mode = MODE_RECOVERY; + /* 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; } + sleep(1); - else if (dfu_check_mode() == 0) { - info("Found device in DFU mode\n"); - mode = MODE_DFU; + if (recovery_send_applelogo(ipsw, tss_response) < 0) { + error("ERROR: Unable to send AppleLogo\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_devicetree(ipsw, tss_response) < 0) { + error("ERROR: Unable to send DeviceTree\n"); + plist_free(tss_response); + return -1; } - else if (restore_check_mode(uuid) == 0) { - info("Found device in restore mode\n"); - mode = MODE_RESTORE; + if (recovery_send_ramdisk(ipsw, tss_response) < 0) { + error("ERROR: Unable to send Ramdisk\n"); + plist_free(tss_response); + return -1; } - return mode; -} + // 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(); -int check_device(const char* uuid) { - int device = DEVICE_UNKNOWN; - uint32_t bdid = 0; - uint32_t cpid = 0; + if (recovery_send_kernelcache(ipsw, tss_response) < 0) { + error("ERROR: Unable to send KernelCache\n"); + plist_free(tss_response); + return -1; + } - switch (idevicerestore_mode) { - case MODE_RESTORE: - device = restore_check_device(uuid); - if (device < 0) { - device = DEVICE_UNKNOWN; - } - break; + 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); + } - case MODE_NORMAL: - device = normal_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_DFU: - case MODE_RECOVERY: - if (get_cpid(uuid, &cpid) < 0) { - error("ERROR: Unable to get device CPID\n"); - 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; + } - 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; + 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 (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; + if (RESTORE_E_SUCCESS != restore_error) { + error("Invalid return status %d\n", restore_error); + //idevicerestore_quit = 1; } - break; - - case CPID_IPHONE3GS: - device = DEVICE_IPHONE3GS; - break; - - case CPID_IPOD2G: - device = DEVICE_IPOD2G; - break; - case CPID_IPOD3G: - device = DEVICE_IPOD3G; - break; - - case CPID_IPAD1G: - device = DEVICE_IPAD1G; - break; - - default: - device = DEVICE_UNKNOWN; - break; + plist_free(message); } - break; - - default: - device = DEVICE_UNKNOWN; - break; - + } else { + error("ERROR: Could not start restore. %d\n", restore_error); } - return device; + restored_client_free(restore); + plist_free(tss_response); + idevice_free(device); + unlink(filesystem); + return 0; } -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; +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; } - - return 0; } -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; +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); +} - default: - error("ERROR: Device is in an invalid state\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; } - return 0; -} - -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; - - case MODE_DFU: - case MODE_RECOVERY: - if (recovery_get_ecid(ecid) < 0) { - *ecid = 0; - return -1; - } - break; + int bytes = fwrite(data, 1, size, file); + fclose(file); - default: - error("ERROR: Device is in an invalid state\n"); + if (bytes != size) { + error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size); return -1; } - return 0; + return size; } -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; +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; } - } 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) { + 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; + } - } else { - return -1; + free(key); } + plist_free(tss_entry); - plist_from_xml(data, size, buildmanifest); - return 0; + return -1; } -plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { +int get_tss_data_by_name(plist_t tss, const char* entry, char** ppath, char** pblob) { + *ppath = NULL; + *pblob = NULL; - // 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; + 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; } - // check and make sure this identity exists in buildmanifest - if (identity >= plist_array_get_size(build_identities_array)) { - 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; } + plist_get_string_val(path_node, &path); - 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; + 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); - return plist_copy(build_identity); + *ppath = path; + *pblob = blob; + return 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; +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; - request = tss_create_request(build_identity, ecid); - if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); + 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; } - info("Sending TSS request\n"); - response = tss_send_request(request); - if (response == NULL) { - plist_free(request); + 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; } - 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"); + img3 = img3_parse_file(data, size); + if (img3 == NULL) { + error("ERROR: Unable to parse IMG3: %s\n", path); + free(data); + free(path); + free(blob); return -1; } + if (data) { + free(data); + data = NULL; + } - 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 (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_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"); + if (img3_get_data(img3, &data, &size) < 0) { + error("ERROR: Unable to reconstruct IMG3\n"); + img3_free(img3); + free(path); 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"); - return -1; + if (idevicerestore_debug) { + char* out = strrchr(path, '/'); + if (out != NULL) { + out++; + } else { + out = path; + } + write_file(out, data, size); } - plist_get_string_val(filesystem_info_path_node, &filename); - info("Extracting filesystem from IPSW\n"); - if (ipsw_extract_to_file(ipsw, filename, filename) < 0) { - error("ERROR: Unable to extract filesystem\n"); - return -1; + if (img3) { + img3_free(img3); + img3 = NULL; + } + if (blob) { + free(blob); + blob = NULL; + } + if (path) { + free(path); + path = NULL; } - *filesystem = filename; + *pdata = data; + *psize = size; return 0; } -int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { +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; - 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); + 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; } - img3 = img3_parse_file(component_data, component_size); - if (img3 == NULL) { - error("ERROR: Unable to parse IMG3: %s\n", component_name); - free(component_data); + 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; } - 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", component_name); - img3_free(img3); + img3 = img3_parse_file(data, size); + if (img3 == NULL) { + error("ERROR: Unable to parse IMG3: %s\n", path); + free(data); + free(path); + free(blob); return -1; } + if (data) { + free(data); + data = NULL; + } - if (idevicerestore_device->device_id > DEVICE_IPOD2G && idevicerestore_custom == 0) { - if (img3_replace_signature(img3, component_blob) < 0) { + if (idevicerestore_custom == 0) { + if (img3_replace_signature(img3, blob) < 0) { error("ERROR: Unable to replace IMG3 signature\n"); - free(component_blob); - img3_free(img3); + free(name); + free(blob); return -1; } } - free(component_blob); - if (img3_get_data(img3, &component_data, &component_size) < 0) { + if (img3_get_data(img3, &data, &size) < 0) { error("ERROR: Unable to reconstruct IMG3\n"); img3_free(img3); + free(name); return -1; } - img3_free(img3); if (idevicerestore_debug) { - write_file(component_name, component_data, component_size); - } - - *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; - } - - 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; + char* out = strrchr(path, '/'); + if (out != NULL) { + out++; + } else { + out = path; + } + write_file(out, data, size); } - 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; + if (img3) { + img3_free(img3); + img3 = NULL; } - - 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; + if (blob) { + free(blob); + blob = NULL; } - bytes = fread(buffer, 1, length, file); - fclose(file); - - if(bytes != length) { - error("ERROR: Unable to read entire file\n"); - free(buffer); - return -1; + if (path) { + free(name); + name = NULL; } - *size = length; - *data = buffer; + *pdata = data; + *psize = size; return 0; } - |