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