diff options
Diffstat (limited to 'src/idevicerestore.c')
-rw-r--r-- | src/idevicerestore.c | 883 |
1 files changed, 477 insertions, 406 deletions
diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 017b45c..fdb340e 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -45,6 +45,9 @@ #define SHA384 sha384 #endif +#include <libimobiledevice-glue/utils.h> + +#include "ace3.h" #include "dfu.h" #include "tss.h" #include "img3.h" @@ -72,7 +75,7 @@ static struct option longopts[] = { { "erase", no_argument, NULL, 'e' }, { "custom", no_argument, NULL, 'c' }, { "latest", no_argument, NULL, 'l' }, - { "cydia", no_argument, NULL, 's' }, + { "server", required_argument, NULL, 's' }, { "exclude", no_argument, NULL, 'x' }, { "shsh", no_argument, NULL, 't' }, { "keep-pers", no_argument, NULL, 'k' }, @@ -87,6 +90,7 @@ static struct option longopts[] = { { "version", no_argument, NULL, 'v' }, { "ipsw-info", no_argument, NULL, 'I' }, { "ignore-errors", no_argument, NULL, 1 }, + { "variant", required_argument, NULL, 2 }, { NULL, 0, NULL, 0 } }; @@ -131,8 +135,8 @@ static void usage(int argc, char* argv[], int err) "\n" \ "Advanced/experimental options:\n" " -c, --custom Restore with a custom firmware (requires bootrom exploit)\n" \ - " -s, --cydia Use Cydia's signature service instead of Apple's\n" \ - " -x, --exclude Exclude nor/baseband upgrade\n" \ + " -s, --server URL Override default signing server request URL\n" \ + " -x, --exclude Exclude nor/baseband upgrade (legacy devices)\n" \ " -t, --shsh Fetch TSS record and save to .shsh file, then exit\n" \ " -z, --no-restore Do not restore and end after booting to the ramdisk\n" \ " -k, --keep-pers Write personalized components to files for debugging\n" \ @@ -140,6 +144,8 @@ static void usage(int argc, char* argv[], int err) " -P, --plain-progress Print progress as plain step and progress\n" \ " -R, --restore-mode Allow restoring from Restore mode\n" \ " -T, --ticket PATH Use file at PATH to send as AP ticket\n" \ + " --variant VARIANT Use given VARIANT to match the build identity to use,\n" \ + " e.g. 'Customer Erase Install (IPSW)'\n" \ " --ignore-errors Try to continue the restore process after certain\n" \ " errors (like a failed baseband update)\n" \ " WARNING: This might render the device unable to boot\n" \ @@ -293,6 +299,9 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) case IRECV_K_DFU_MODE: client->mode = MODE_DFU; break; + case IRECV_K_PORT_DFU_MODE: + client->mode = MODE_PORTDFU; + break; case IRECV_K_RECOVERY_MODE_1: case IRECV_K_RECOVERY_MODE_2: case IRECV_K_RECOVERY_MODE_3: @@ -311,12 +320,20 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) mutex_lock(&client->device_event_mutex); client->mode = MODE_UNKNOWN; debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A"); + if (event->mode == IRECV_K_PORT_DFU_MODE) { + // We have to reset the ECID here if a port DFU device disconnects, + // because when the device reconnects in a different mode, it will + // have the actual device ECID and wouldn't get detected. + client->ecid = 0; + } cond_signal(&client->device_event_cond); mutex_unlock(&client->device_event_mutex); } } } +int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive_t ipsw); + int idevicerestore_start(struct idevicerestore_client_t* client) { int tss_enabled = 0; @@ -336,10 +353,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - if (client->flags & FLAG_DEBUG) { - idevice_set_debug_level(1); - irecv_set_debug_level(1); + if (client->debug_level > 0) { idevicerestore_debug = 1; + if (client->debug_level > 1) { + idevice_set_debug_level(1); + irecv_set_debug_level(1); + } } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0); @@ -421,7 +440,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) download_to_file(s_wtfurl, wtfipsw, 0); } - ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize); + ipsw_archive_t wtf_ipsw = ipsw_open(wtfipsw); + ipsw_extract_to_memory(wtf_ipsw, wtfname, &wtftmp, &wtfsize); + ipsw_close(wtf_ipsw); if (!wtftmp) { error("ERROR: Could not extract WTF\n"); } @@ -453,6 +474,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to discover device type\n"); return -1; } + if (client->ecid == 0) { + error("ERROR: Unable to determine ECID\n"); + return -1; + } + info("ECID: %" PRIu64 "\n", client->ecid); + idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.2); info("Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type); @@ -461,6 +488,21 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } + if (client->mode == MODE_NORMAL) { + plist_t pver = normal_get_lockdown_value(client, NULL, "ProductVersion"); + if (pver) { + plist_get_string_val(pver, &client->device_version); + plist_free(pver); + } + pver = normal_get_lockdown_value(client, NULL, "BuildVersion"); + if (pver) { + plist_get_string_val(pver, &client->device_build); + plist_free(pver); + } + } + info("Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A"); + info("Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A"); + if (client->flags & FLAG_PWN) { recovery_client_free(client); @@ -473,17 +515,24 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (dfu_client_new(client) < 0) { return -1; } - info("exploiting with limera1n...\n"); - // TODO: check for non-limera1n device and fail - if (limera1n_exploit(client->device, &client->dfu->client) != 0) { - error("ERROR: limera1n exploit failed\n"); + + if (limera1n_is_supported(client->device)) { + info("exploiting with limera1n...\n"); + if (limera1n_exploit(client->device, &client->dfu->client) != 0) { + error("ERROR: limera1n exploit failed\n"); + dfu_client_free(client); + return -1; + } + dfu_client_free(client); + info("Device should be in pwned DFU state now.\n"); + + return 0; + } + else { dfu_client_free(client); + error("ERROR: This device is not supported by the limera1n exploit"); return -1; } - dfu_client_free(client); - info("Device should be in pwned DFU state now.\n"); - - return 0; } if (client->flags & FLAG_LATEST) { @@ -585,12 +634,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client) char* ipsw = NULL; res = ipsw_download_fw(fwurl, p_fwsha1, client->cache_dir, &ipsw); if (res != 0) { - if (ipsw) { - free(ipsw); - } + free(ipsw); return res; } else { - client->ipsw = ipsw; + client->ipsw = ipsw_open(ipsw); + if (!client->ipsw) { + error("ERROR: Failed to open ipsw '%s'\n", ipsw); + free(ipsw); + return -1; + } + free(ipsw); } } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.6); @@ -599,14 +652,29 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return 0; } + // extract buildmanifest + if (client->flags & FLAG_CUSTOM) { + info("Extracting Restore.plist from IPSW\n"); + if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { + error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); + return -1; + } + } else { + info("Extracting BuildManifest from IPSW\n"); + if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { + error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); + return -1; + } + } + + if (client->flags & FLAG_CUSTOM) { + // prevent attempt to sign custom firmware + tss_enabled = 0; + info("Custom firmware requested; TSS has been disabled.\n"); + } + if (client->mode == MODE_RESTORE) { - if (client->flags & FLAG_ALLOW_RESTORE_MODE) { - tss_enabled = 0; - if (!client->root_ticket) { - client->root_ticket = (void*)strdup(""); - client->root_ticket_len = 0; - } - } else { + if (!(client->flags & FLAG_ALLOW_RESTORE_MODE)) { if (restore_reboot(client) < 0) { error("ERROR: Unable to exit restore mode\n"); return -2; @@ -625,26 +693,152 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } - // verify if ipsw file exists - if (access(client->ipsw, F_OK) < 0) { - error("ERROR: Firmware file %s does not exist.\n", client->ipsw); - return -1; - } + if (client->mode == MODE_PORTDFU) { + unsigned int pdfu_bdid = 0; + unsigned int pdfu_cpid = 0; + unsigned int prev = 0; - // extract buildmanifest - if (client->flags & FLAG_CUSTOM) { - info("Extracting Restore.plist from IPSW\n"); - if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { - error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw); + if (dfu_get_bdid(client, &pdfu_bdid) < 0) { + error("ERROR: Failed to get bdid for Port DFU device!\n"); return -1; } - } else { - info("Extracting BuildManifest from IPSW\n"); - if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { - error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw); + if (dfu_get_cpid(client, &pdfu_cpid) < 0) { + error("ERROR: Failed to get cpid for Port DFU device!\n"); return -1; } + if (dfu_get_prev(client, &prev) < 0) { + error("ERROR: Failed to get PREV for Port DFU device!\n"); + return -1; + } + + unsigned char* pdfu_nonce = NULL; + unsigned int pdfu_nsize = 0; + if (dfu_get_portdfu_nonce(client, &pdfu_nonce, &pdfu_nsize) < 0) { + error("ERROR: Failed to get nonce for Port DFU device!\n"); + return -1; + } + + plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0); + if (!build_identity) { + error("ERORR: Failed to get build identity\n"); + return -1; + } + + unsigned int b_pdfu_cpid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,ChipID"); + if (b_pdfu_cpid != pdfu_cpid) { + error("ERROR: cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid); + return -1; + } + unsigned int b_pdfu_bdid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,BoardID"); + if (b_pdfu_bdid != pdfu_bdid) { + error("ERROR: bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid); + return -1; + } + + plist_t parameters = plist_new_dict(); + plist_dict_set_item(parameters, "@USBPortController1,Ticket", plist_new_bool(1)); + plist_dict_set_item(parameters, "USBPortController1,ECID", plist_new_int(client->ecid)); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + plist_dict_set_item(parameters, "USBPortController1,SecurityMode", plist_new_bool(1)); + plist_dict_set_item(parameters, "USBPortController1,ProductionMode", plist_new_bool(1)); + plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware"); + if (!usbf) { + plist_free(parameters); + error("ERROR: Unable to find USBPortController1,USBFirmware in build identity\n"); + return -1; + } + plist_t p_fwpath = plist_access_path(usbf, 2, "Info", "Path"); + if (!p_fwpath) { + plist_free(parameters); + error("ERROR: Unable to find path of USBPortController1,USBFirmware component\n"); + return -1; + } + const char* fwpath = plist_get_string_ptr(p_fwpath, NULL); + if (!fwpath) { + plist_free(parameters); + error("ERROR: Unable to get path of USBPortController1,USBFirmware component\n"); + return -1; + } + unsigned char* uarp_buf = NULL; + unsigned int uarp_size = 0; + if (ipsw_extract_to_memory(client->ipsw, fwpath, &uarp_buf, &uarp_size) < 0) { + plist_free(parameters); + error("ERROR: Unable to extract '%s' from IPSW\n", fwpath); + return -1; + } + usbf = plist_copy(usbf); + plist_dict_remove_item(usbf, "Info"); + plist_dict_set_item(parameters, "USBPortController1,USBFirmware", usbf); + plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data((const char*)pdfu_nonce, pdfu_nsize)); + + plist_t request = tss_request_new(NULL); + if (request == NULL) { + plist_free(parameters); + error("ERROR: Unable to create TSS request\n"); + return -1; + } + plist_dict_merge(&request, parameters); + plist_free(parameters); + + // send request and grab response + plist_t response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to send TSS request\n"); + return -1; + } + info("Received USBPortController1,Ticket\n"); + + info("Creating Ace3Binary\n"); + unsigned char* ace3bin = NULL; + size_t ace3bin_size = 0; + if (ace3_create_binary(uarp_buf, uarp_size, pdfu_bdid, prev, response, &ace3bin, &ace3bin_size) < 0) { + error("ERROR: Could not create Ace3Binary\n"); + return -1; + } + plist_free(response); + free(uarp_buf); + + if (idevicerestore_keep_pers) { + write_file("Ace3Binary", (const char*)ace3bin, ace3bin_size); + } + + if (dfu_send_buffer_with_options(client, ace3bin, ace3bin_size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH | IRECV_SEND_OPT_DFU_SMALL_PKT) < 0) { + error("ERROR: Could not send Ace3Buffer to device\n"); + return -1; + } + + debug("Waiting for device to disconnect...\n"); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); + if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { + mutex_unlock(&client->device_event_mutex); + + if (!(client->flags & FLAG_QUIT)) { + error("ERROR: Device did not disconnect. Port DFU failed.\n"); + } + return -2; + } + debug("Waiting for device to reconnect in DFU mode...\n"); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); + if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) { + mutex_unlock(&client->device_event_mutex); + if (!(client->flags & FLAG_QUIT)) { + error("ERROR: Device did not reconnect in DFU mode. Port DFU failed.\n"); + } + return -2; + } + mutex_unlock(&client->device_event_mutex); + + if (client->flags & FLAG_NOACTION) { + info("Port DFU restore successful.\n"); + return 0; + } else { + info("Port DFU restore successful. Continuing.\n"); + } } + idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.8); /* check if device type is supported by the given build manifest */ @@ -656,23 +850,19 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* print iOS information from the manifest */ build_manifest_get_version_information(client->build_manifest, client); - info("Product Version: %s\n", client->version); - info("Product Build: %s Major: %d\n", client->build, client->build_major); + info("IPSW Product Version: %s\n", client->version); + info("IPSW Product Build: %s Major: %d\n", client->build, client->build_major); client->image4supported = is_image4_supported(client); info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); - if (client->flags & FLAG_CUSTOM) { - /* prevent signing custom firmware */ - tss_enabled = 0; - info("Custom firmware requested. Disabled TSS request.\n"); - } - // choose whether this is an upgrade or a restore (default to upgrade) client->tss = NULL; plist_t build_identity = NULL; + int build_identity_needs_free = 0; if (client->flags & FLAG_CUSTOM) { build_identity = plist_new_dict(); + build_identity_needs_free = 1; { plist_t node; plist_t comp; @@ -699,6 +889,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) uint32_t msize = 0; if (ipsw_extract_to_memory(client->ipsw, tmpstr, (unsigned char**)&fmanifest, &msize) < 0) { error("ERROR: could not extract %s from IPSW\n", tmpstr); + free(build_identity); return -1; } @@ -816,40 +1007,42 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // add info inf = plist_new_dict(); plist_dict_set_item(inf, "RestoreBehavior", plist_new_string((client->flags & FLAG_ERASE) ? "Erase" : "Update")); - plist_dict_set_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer Erase Install (IPSW)" : "Customer Upgrade Install (IPSW)")); + plist_dict_set_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer " RESTORE_VARIANT_ERASE_INSTALL : "Customer " RESTORE_VARIANT_UPGRADE_INSTALL)); plist_dict_set_item(build_identity, "Info", inf); // finally add manifest plist_dict_set_item(build_identity, "Manifest", manifest); } + } else if (client->restore_variant) { + build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, client->restore_variant, 1); } else if (client->flags & FLAG_ERASE) { - build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, "Customer Erase Install (IPSW)"); - if (build_identity == NULL) { - error("ERROR: Unable to find any build identities\n"); - return -1; - } + build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0); } else { - build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, "Customer Upgrade Install (IPSW)"); + build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_UPGRADE_INSTALL, 0); if (!build_identity) { build_identity = build_manifest_get_build_identity_for_model(client->build_manifest, client->device->hardware_model); } } + if (build_identity == NULL) { + error("ERROR: Unable to find a matching build identity\n"); + return -1; + } + + client->macos_variant = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_MACOS_RECOVERY_OS, 1); /* print information about current build identity */ build_identity_print_information(build_identity); + if (client->macos_variant) { + info("Performing macOS restore\n"); + } + if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) { - plist_t pver = normal_get_lockdown_value(client, NULL, "ProductVersion"); - char *device_version = NULL; - if (pver) { - plist_get_string_val(pver, &device_version); - plist_free(pver); - } - if (device_version && (compare_versions(device_version, client->version) > 0)) { + if (client->device_version && (compare_versions(client->device_version, client->version) > 0)) { if (client->flags & FLAG_INTERACTIVE) { char input[64]; char spaces[16]; - int num_spaces = 13 - strlen(client->version) - strlen(device_version); + int num_spaces = 13 - strlen(client->version) - strlen(client->device_version); memset(spaces, ' ', num_spaces); spaces[num_spaces] = '\0'; printf("################################ [ WARNING ] #################################\n" @@ -860,7 +1053,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) "# If you want to take the risk (and have a backup of your important data!) #\n" "# type YES and press ENTER to continue. You have been warned. #\n" "##############################################################################\n", - device_version, client->version, spaces); + client->device_version, client->version, spaces); while (1) { printf("> "); fflush(stdout); @@ -879,7 +1072,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } } - free(device_version); } if (client->flags & FLAG_ERASE && client->flags & FLAG_INTERACTIVE) { @@ -914,112 +1106,74 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* check if all components we need are actually there */ info("Checking IPSW for required components...\n"); if (build_identity_check_components_in_ipsw(build_identity, client->ipsw) < 0) { - error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw); + error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw->path); return -1; } info("All required components found in IPSW\n"); - // Get filesystem name from build identity - char* fsname = NULL; - if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { + /* Get OS (filesystem) name from build identity */ + char* os_path = NULL; + if (build_identity_get_component_path(build_identity, "OS", &os_path) < 0) { error("ERROR: Unable to get path for filesystem component\n"); return -1; } - // check if we already have an extracted filesystem - int delete_fs = 0; - char* filesystem = NULL; - struct stat st; - memset(&st, '\0', sizeof(struct stat)); - char tmpf[1024]; - if (client->cache_dir) { - if (stat(client->cache_dir, &st) < 0) { - mkdir_with_parents(client->cache_dir, 0755); + /* check if IPSW has OS component 'stored' in ZIP archive, otherwise we need to extract it */ + int needs_os_extraction = 0; + if (client->ipsw->zip) { + ipsw_file_handle_t zfile = ipsw_file_open(client->ipsw, os_path); + if (zfile) { + if (!zfile->seekable) { + needs_os_extraction = 1; + } + ipsw_file_close(zfile); } - strcpy(tmpf, client->cache_dir); - strcat(tmpf, "/"); - char *ipswtmp = strdup(client->ipsw); - strcat(tmpf, basename(ipswtmp)); - free(ipswtmp); - } else { - strcpy(tmpf, client->ipsw); } - if (!ipsw_is_directory(client->ipsw)) { - // strip off file extension if given ipsw is not a directory - char* s = tmpf + strlen(tmpf) - 1; - char* p = s; - while (*p != '\0' && *p != '.' && *p != '/' && *p != '\\') p--; - if (s - p < 6) { - if (*p == '.') { + if (needs_os_extraction && !(client->flags & FLAG_SHSHONLY)) { + char* tmpf = NULL; + struct stat st; + if (client->cache_dir) { + memset(&st, '\0', sizeof(struct stat)); + if (stat(client->cache_dir, &st) < 0) { + mkdir_with_parents(client->cache_dir, 0755); + } + char* ipsw_basename = strdup(path_get_basename(client->ipsw->path)); + char* p = strrchr(ipsw_basename, '.'); + if (p && isalpha(*(p+1))) { *p = '\0'; } - } - } - - if (stat(tmpf, &st) < 0) { - __mkdir(tmpf, 0755); - } - strcat(tmpf, "/"); - strcat(tmpf, fsname); - - memset(&st, '\0', sizeof(struct stat)); - if (stat(tmpf, &st) == 0) { - uint64_t fssize = 0; - ipsw_get_file_size(client->ipsw, fsname, &fssize); - if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) { - info("Using cached filesystem from '%s'\n", tmpf); - filesystem = strdup(tmpf); - } - } - - if (!filesystem && !(client->flags & FLAG_SHSHONLY)) { - char extfn[1024]; - strcpy(extfn, tmpf); - strcat(extfn, ".extract"); - char lockfn[1024]; - strcpy(lockfn, tmpf); - strcat(lockfn, ".lock"); - lock_info_t li; - - lock_file(lockfn, &li); - FILE* extf = NULL; - if (access(extfn, F_OK) != 0) { - extf = fopen(extfn, "wb"); - } - unlock_file(&li); - if (!extf) { - // use temp filename - filesystem = get_temp_filename("ipsw_"); - if (!filesystem) { - error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname); - filesystem = strdup(fsname); - } - delete_fs = 1; + tmpf = string_build_path(client->cache_dir, ipsw_basename, NULL); + mkdir_with_parents(tmpf, 0755); + free(tmpf); + tmpf = string_build_path(client->cache_dir, ipsw_basename, os_path, NULL); + free(ipsw_basename); } else { - // use <fsname>.extract as filename - filesystem = strdup(extfn); - fclose(extf); - } - remove(lockfn); - - // Extract filesystem from IPSW - info("Extracting filesystem from IPSW: %s\n", fsname); - if (ipsw_extract_to_file_with_progress(client->ipsw, fsname, filesystem, 1) < 0) { - error("ERROR: Unable to extract filesystem from IPSW\n"); - if (client->tss) - plist_free(client->tss); - info("Removing %s\n", filesystem); - unlink(filesystem); - return -1; + tmpf = get_temp_filename(NULL); + client->delete_fs = 1; } - if (strstr(filesystem, ".extract")) { - // rename <fsname>.extract to <fsname> - remove(tmpf); - rename(filesystem, tmpf); - free(filesystem); - filesystem = strdup(tmpf); + /* check if we already have it extracted */ + uint64_t fssize = 0; + ipsw_get_file_size(client->ipsw, os_path, &fssize); + memset(&st, '\0', sizeof(struct stat)); + if (stat(tmpf, &st) == 0) { + if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) { + info("Using cached filesystem from '%s'\n", tmpf); + client->filesystem = tmpf; + } + } + + if (!client->filesystem) { + info("Extracting filesystem from IPSW: %s\n", os_path); + if (ipsw_extract_to_file_with_progress(client->ipsw, os_path, tmpf, 1) < 0) { + error("ERROR: Unable to extract filesystem from IPSW\n"); + info("Removing %s\n", tmpf); + unlink(tmpf); + free(tmpf); + return -1; + } + client->filesystem = tmpf; } } @@ -1028,13 +1182,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* retrieve shsh blobs if required */ if (tss_enabled) { int stashbag_commit_required = 0; - debug("Getting device's ECID for TSS request\n"); - /* fetch the device's ECID for the TSS request */ - if (get_ecid(client, &client->ecid) < 0) { - error("ERROR: Unable to find device ECID\n"); - return -1; - } - info("Found ECID %" PRIu64 "\n", client->ecid); if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) { plist_t node = normal_get_lockdown_value(client, NULL, "HasSiDP"); @@ -1067,7 +1214,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->build_major > 8) { unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { /* the first nonce request with older firmware releases can fail and it's OK */ info("NOTE: Unable to get nonce from device\n"); @@ -1088,20 +1235,33 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - if (get_tss_response(client, build_identity, &client->tss) < 0) { - error("ERROR: Unable to get SHSH blobs for this device\n"); - return -1; - } - if (client->build_major >= 20) { - if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) { - error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); + if (client->mode == MODE_RESTORE && client->root_ticket) { + plist_t ap_ticket = plist_new_data(client->root_ticket, client->root_ticket_len); + if (!ap_ticket) { + error("ERROR: Failed to create ApImg4Ticket node value.\n"); + return -1; + } + client->tss = plist_new_dict(); + if (!client->tss) { + error("ERROR: Failed to create ApImg4Ticket node.\n"); return -1; } - if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < - 0) { - error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); + plist_dict_set_item(client->tss, "ApImg4Ticket", ap_ticket); + } else { + if (get_tss_response(client, build_identity, &client->tss) < 0) { + error("ERROR: Unable to get SHSH blobs for this device\n"); return -1; } + if (client->macos_variant) { + if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) { + error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); + return -1; + } + if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < 0) { + error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); + return -1; + } + } } if (stashbag_commit_required) { @@ -1120,8 +1280,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } if (client->flags & FLAG_SHSHONLY) { @@ -1176,8 +1334,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.25); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1194,8 +1350,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.3); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1206,17 +1360,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) { info("connecting to DFU\n"); if (dfu_client_new(client) < 0) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } info("exploiting with limera1n\n"); - // TODO: check for non-limera1n device and fail if (limera1n_exploit(client->device, &client->dfu->client) != 0) { error("ERROR: limera1n exploit failed\n"); dfu_client_free(client); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } dfu_client_free(client); @@ -1226,8 +1375,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to place device into recovery mode from DFU mode\n"); if (client->tss) plist_free(client->tss); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } } else if (client->mode == MODE_RECOVERY) { @@ -1237,8 +1384,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* send ApTicket */ if (recovery_send_ticket(client) < 0) { error("ERROR: Unable to send APTicket\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } } @@ -1250,54 +1395,44 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (recovery_send_ibec(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); error("ERROR: Unable to send iBEC\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } recovery_client_free(client); debug("Waiting for device to disconnect...\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { error("ERROR: Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n"); } - if (delete_fs && filesystem) - unlink(filesystem); return -2; } debug("Waiting for device to reconnect in recovery mode...\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { error("ERROR: Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n"); } - if (delete_fs && filesystem) - unlink(filesystem); return -2; } mutex_unlock(&client->device_event_mutex); } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.5); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } if (!client->image4supported && (client->build_major > 8)) { // we need another tss request with nonce. unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; int nonce_changed = 0; if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get nonce from device!\n"); recovery_send_reset(client); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } @@ -1317,14 +1452,10 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_free(client->tss); if (get_tss_response(client, build_identity, &client->tss) < 0) { error("ERROR: Unable to get SHSH blobs for this device\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } if (!client->tss) { error("ERROR: can't continue without TSS\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } fixup_tss(client->tss); @@ -1332,25 +1463,15 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.7); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } // now finally do the magic to put the device into restore mode if (client->mode == MODE_RECOVERY) { - if (client->srnm == NULL) { - error("ERROR: could not retrieve device serial number. Can't continue.\n"); - if (delete_fs && filesystem) - unlink(filesystem); - return -1; - } if (recovery_enter_restore(client, build_identity) < 0) { error("ERROR: Unable to place device into restore mode\n"); if (client->tss) plist_free(client->tss); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } recovery_client_free(client); @@ -1365,8 +1486,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) mutex_unlock(&client->device_event_mutex); error("ERROR: Device failed to enter restore mode.\n"); error("Please make sure that usbmuxd is running.\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } mutex_unlock(&client->device_event_mutex); @@ -1380,19 +1499,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } client->ignore_device_add_events = 1; info("About to restore device... \n"); - result = restore_device(client, build_identity, filesystem); + result = restore_device(client, build_identity); if (result < 0) { error("ERROR: Unable to restore device\n"); - if (delete_fs && filesystem) - unlink(filesystem); return result; } } - info("Cleaning up...\n"); - if (delete_fs && filesystem) - unlink(filesystem); - /* special handling of older AppleTVs as they enter Recovery mode on boot when plugged in to USB */ if ((strncmp(client->device->product_type, "AppleTV", 7) == 0) && (client->device->product_type[7] < '5')) { if (recovery_client_new(client) == 0) { @@ -1412,7 +1525,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0); } - if (build_identity) + if (build_identity_needs_free) plist_free(build_identity); return result; @@ -1463,14 +1576,18 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) free(client->srnm); } if (client->ipsw) { - free(client->ipsw); - } - if (client->version) { - free(client->version); + ipsw_close(client->ipsw); } - if (client->build) { - free(client->build); + if (client->filesystem) { + if (client->delete_fs) { + unlink(client->filesystem); + } + free(client->filesystem); } + free(client->version); + free(client->build); + free(client->device_version); + free(client->device_build); if (client->restore_boot_args) { free(client->restore_boot_args); } @@ -1486,6 +1603,7 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) if (client->preflight_info) { plist_free(client->preflight_info); } + free(client->restore_variant); free(client); } @@ -1521,11 +1639,11 @@ void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* if (!client) return; if (client->ipsw) { - free(client->ipsw); + ipsw_close(client->ipsw); client->ipsw = NULL; } if (path) { - client->ipsw = strdup(path); + client->ipsw = ipsw_open(path); } } @@ -1603,7 +1721,7 @@ int main(int argc, char* argv[]) { client->flags |= FLAG_INTERACTIVE; } - while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) { + while ((opt = getopt_long(argc, argv, "dhces:xtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) { switch (opt) { case 'h': usage(argc, argv, 0); @@ -1611,6 +1729,7 @@ int main(int argc, char* argv[]) { case 'd': client->flags |= FLAG_DEBUG; + client->debug_level++; break; case 'e': @@ -1621,8 +1740,35 @@ int main(int argc, char* argv[]) { client->flags |= FLAG_CUSTOM; break; - case 's': - client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2"); + case 's': { + if (!*optarg) { + error("ERROR: URL argument for --server must not be empty!\n"); + usage(argc, argv, 1); + return EXIT_FAILURE; + } + char *baseurl = NULL; + if (!strncmp(optarg, "http://", 7) && (strlen(optarg) > 7) && (optarg[7] != '/')) { + baseurl = optarg+7; + } else if (!strncmp(optarg, "https://", 8) && (strlen(optarg) > 8) && (optarg[8] != '/')) { + baseurl = optarg+8; + } + if (baseurl) { + char *p = strchr(baseurl, '/'); + if (!p || *(p+1) == '\0') { + // no path component, add default path + const char default_path[] = "/TSS/controller?action=2"; + char* newurl = malloc(strlen(optarg)+sizeof(default_path)); + sprintf(newurl, "%s%s", optarg, (p) ? default_path+1 : default_path); + client->tss_url = newurl; + } else { + client->tss_url = strdup(optarg); + } + } else { + error("ERROR: URL argument for --server is invalid, must start with http:// or https://\n"); + usage(argc, argv, 1); + return EXIT_FAILURE; + } + } break; case 'x': @@ -1716,6 +1862,11 @@ int main(int argc, char* argv[]) { client->flags |= FLAG_IGNORE_ERRORS; break; + case 2: + free(client->restore_variant); + client->restore_variant = strdup(optarg); + break; + default: usage(argc, argv, 1); return EXIT_FAILURE; @@ -1746,8 +1897,15 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } + info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); + if (ipsw) { - client->ipsw = strdup(ipsw); + // verify if ipsw file exists + client->ipsw = ipsw_open(ipsw); + if (!client->ipsw) { + error("ERROR: Firmware file %s cannot be opened.\n", ipsw); + return -1; + } } curl_global_init(CURL_GLOBAL_ALL); @@ -1778,6 +1936,7 @@ irecv_device_t get_irecv_device(struct idevicerestore_client_t *client) return normal_get_irecv_device(client); case _MODE_DFU: + case _MODE_PORTDFU: case _MODE_RECOVERY: return dfu_get_irecv_device(client); @@ -1815,46 +1974,7 @@ int is_image4_supported(struct idevicerestore_client_t* client) return res; } -int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) -{ - int mode = _MODE_UNKNOWN; - - if (client->mode) { - mode = client->mode->index; - } - - switch (mode) { - case _MODE_NORMAL: - if (normal_get_ecid(client, ecid) < 0) { - *ecid = 0; - return -1; - } - break; - - case _MODE_DFU: - if (dfu_get_ecid(client, ecid) < 0) { - *ecid = 0; - return -1; - } - break; - - case _MODE_RECOVERY: - if (recovery_get_ecid(client, ecid) < 0) { - *ecid = 0; - return -1; - } - break; - - default: - error("ERROR: Device is in an invalid state\n"); - *ecid = 0; - return -1; - } - - return 0; -} - -int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { int mode = _MODE_UNKNOWN; @@ -1905,7 +2025,7 @@ int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, return 0; } -int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { int mode = _MODE_UNKNOWN; @@ -1956,7 +2076,7 @@ int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, return 0; } -plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant) +plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant, int exact) { plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities"); if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { @@ -1978,30 +2098,27 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m if (!devclass || plist_get_node_type(devclass) != PLIST_STRING) { continue; } - char *str = NULL; - plist_get_string_val(devclass, &str); + const char *str = plist_get_string_ptr(devclass, NULL); if (strcasecmp(str, hardware_model) != 0) { - free(str); continue; } - free(str); - str = NULL; if (variant) { plist_t rvariant = plist_dict_get_item(info_dict, "Variant"); if (!rvariant || plist_get_node_type(rvariant) != PLIST_STRING) { continue; } - plist_get_string_val(rvariant, &str); - if (strcasecmp(str, variant) != 0) { - free(str); + str = plist_get_string_ptr(rvariant, NULL); + if (strcmp(str, variant) != 0) { + /* if it's not a full match, let's try a partial match, but ignore "*Research*" */ + if (!exact && strstr(str, variant) && !strstr(str, "Research")) { + return ident; + } continue; } else { - free(str); - return plist_copy(ident); + return ident; } - free(str); } else { - return plist_copy(ident); + return ident; } } @@ -2010,7 +2127,7 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m plist_t build_manifest_get_build_identity_for_model(plist_t build_manifest, const char *hardware_model) { - return build_manifest_get_build_identity_for_model_with_variant(build_manifest, hardware_model, NULL); + return build_manifest_get_build_identity_for_model_with_variant(build_manifest, hardware_model, NULL, 0); } int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest) @@ -2028,13 +2145,13 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ plist_t overrides = plist_new_dict(); plist_dict_set_item(overrides, "@APTicket", plist_new_bool(1)); plist_dict_set_item(overrides, "ApProductionMode", plist_new_uint(0)); - plist_dict_set_item(overrides, "ApSecurityDomain", plist_new_uint(0)); + plist_dict_set_item(overrides, "ApSecurityDomain", plist_new_uint(1)); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(0)); plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(0)); plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1)); - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* create basic request */ request = tss_request_new(NULL); @@ -2052,7 +2169,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ return -1; } - plist_dict_set_item(parameters, "_OnlyFWComponents", plist_new_bool(1)); + plist_dict_set_item(parameters, "_OnlyFWOrTrustedComponents", plist_new_bool(1)); /* add tags from manifest */ if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { @@ -2149,7 +2266,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { @@ -2165,7 +2282,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); } - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* create basic request */ request = tss_request_new(NULL); @@ -2214,50 +2331,20 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_t pinfo = NULL; normal_get_preflight_info(client, &pinfo); if (pinfo) { - plist_t node; - node = plist_dict_get_item(pinfo, "Nonce"); - if (node) { - plist_dict_set_item(parameters, "BbNonce", plist_copy(node)); - } - node = plist_dict_get_item(pinfo, "ChipID"); - if (node) { - plist_dict_set_item(parameters, "BbChipID", plist_copy(node)); - } - node = plist_dict_get_item(pinfo, "CertID"); - if (node) { - plist_dict_set_item(parameters, "BbGoldCertId", plist_copy(node)); - } - node = plist_dict_get_item(pinfo, "ChipSerialNo"); - if (node) { - plist_dict_set_item(parameters, "BbSNUM", plist_copy(node)); - } + _plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce"); + _plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID"); + _plist_dict_copy_uint(parameters, pinfo, "BbGoldCertId", "CertID"); + _plist_dict_copy_data(parameters, pinfo, "BbSNUM", "ChipSerialNo"); /* add baseband parameters */ tss_request_add_baseband_tags(request, parameters, NULL); - node = plist_dict_get_item(pinfo, "EUICCChipID"); - uint64_t euiccchipid = 0; - if (node && plist_get_node_type(node) == PLIST_UINT) { - plist_get_uint_val(node, &euiccchipid); - plist_dict_set_item(parameters, "eUICC,ChipID", plist_copy(node)); - } - if (euiccchipid >= 5) { - node = plist_dict_get_item(pinfo, "EUICCCSN"); - if (node) { - plist_dict_set_item(parameters, "eUICC,EID", plist_copy(node)); - } - node = plist_dict_get_item(pinfo, "EUICCCertIdentifier"); - if (node) { - plist_dict_set_item(parameters, "eUICC,RootKeyIdentifier", plist_copy(node)); - } - node = plist_dict_get_item(pinfo, "EUICCGoldNonce"); - if (node) { - plist_dict_set_item(parameters, "EUICCGoldNonce", plist_copy(node)); - } - node = plist_dict_get_item(pinfo, "EUICCMainNonce"); - if (node) { - plist_dict_set_item(parameters, "EUICCMainNonce", plist_copy(node)); - } + _plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID"); + if (_plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) { + _plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN"); + _plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier"); + _plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL); + _plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL); /* add vinyl parameters */ tss_request_add_vinyl_tags(request, parameters, NULL); @@ -2303,7 +2390,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); /* ApSepNonce */ @@ -2323,10 +2410,10 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); } - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); /* create basic request */ - /* Adds @BBTicket, @HostPlatformInfo, @VersionInfo, @UUID */ + /* Adds @HostPlatformInfo, @VersionInfo, @UUID */ request = tss_request_new(NULL); if (request == NULL) { error("ERROR: Unable to create TSS request\n"); @@ -2335,7 +2422,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie } /* add common tags from manifest */ - /* Adds Ap,OSLongVersion, AppNonce, @ApImg4Ticket */ + /* Adds Ap,OSLongVersion, ApNonce, @ApImg4Ticket */ if (tss_request_add_ap_img4_tags(request, parameters) < 0) { error("ERROR: Unable to add AP IMG4 tags to TSS request\n"); plist_free(request); @@ -2403,7 +2490,7 @@ int get_recovery_os_local_policy_tss_response( plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); } - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); // Add Ap,LocalPolicy uint8_t digest[SHA384_DIGEST_LENGTH]; @@ -2413,11 +2500,8 @@ int get_recovery_os_local_policy_tss_response( plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); - plist_t im4m_hash = plist_dict_get_item(args, "Ap,NextStageIM4MHash"); - plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_copy(im4m_hash)); - - plist_t nonce_hash = plist_dict_get_item(args, "Ap,RecoveryOSPolicyNonceHash"); - plist_dict_set_item(parameters, "Ap,RecoveryOSPolicyNonceHash", plist_copy(nonce_hash)); + _plist_dict_copy_data(parameters, args, "Ap,NextStageIM4MHash", NULL); + _plist_dict_copy_data(parameters, args, "Ap,RecoveryOSPolicyNonceHash", NULL); plist_t vol_uuid_node = plist_dict_get_item(args, "Ap,VolumeUUID"); char* vol_uuid_str = NULL; @@ -2485,7 +2569,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { @@ -2501,7 +2585,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); } - tss_parameters_add_from_manifest(parameters, build_identity); + tss_parameters_add_from_manifest(parameters, build_identity, true); // Add Ap,LocalPolicy uint8_t digest[SHA384_DIGEST_LENGTH]; @@ -2594,12 +2678,10 @@ int build_manifest_get_identity_count(plist_t build_manifest) error("ERROR: Unable to find build identities node\n"); return -1; } - - // check and make sure this identity exists in buildmanifest return plist_array_get_size(build_identities_array); } -int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size) +int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size) { char* component_name = NULL; if (!ipsw || !path || !component_data || !component_size) { @@ -2614,7 +2696,7 @@ int extract_component(const char* ipsw, const char* path, unsigned char** compon info("Extracting %s (%s)...\n", component_name, path); if (ipsw_extract_to_memory(ipsw, path, component_data, component_size) < 0) { - error("ERROR: Unable to extract %s from %s\n", component_name, ipsw); + error("ERROR: Unable to extract %s from %s\n", component_name, ipsw->path); return -1; } @@ -2628,9 +2710,9 @@ int personalize_component(const char *component_name, const unsigned char* compo unsigned char* stitched_component = NULL; unsigned int stitched_component_size = 0; - if (tss_response && tss_response_get_ap_img4_ticket(tss_response, &component_blob, &component_blob_size) == 0) { + if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) { /* stitch ApImg4Ticket into IMG4 file */ - img4_stitch_component(component_name, component_data, component_size, component_blob, component_blob_size, &stitched_component, &stitched_component_size); + img4_stitch_component(component_name, component_data, component_size, tss_response, &stitched_component, &stitched_component_size); } else { /* try to get blob for current component from tss response */ if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) { @@ -2733,20 +2815,13 @@ void build_identity_print_information(plist_t build_identity) plist_get_string_val(node, &value); info("Variant: %s\n", value); - free(value); - - node = plist_dict_get_item(info_node, "RestoreBehavior"); - if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to find RestoreBehavior node\n"); - return; - } - plist_get_string_val(node, &value); - - if (!strcmp(value, "Erase")) - info("This restore will erase your device data.\n"); - if (!strcmp(value, "Update")) - info("This restore will update your device without erasing user data.\n"); + if (strstr(value, RESTORE_VARIANT_UPGRADE_INSTALL)) + info("This restore will update the device without erasing user data.\n"); + else if (strstr(value, RESTORE_VARIANT_ERASE_INSTALL)) + info("This restore will erase all device data.\n"); + else + info("Unknown Variant '%s'\n", value); free(value); @@ -2754,7 +2829,7 @@ void build_identity_print_information(plist_t build_identity) node = NULL; } -int build_identity_check_components_in_ipsw(plist_t build_identity, const char *ipsw) +int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive_t ipsw) { plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { @@ -2846,42 +2921,38 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon const char* get_component_name(const char* filename) { - if (!strncmp(filename, "LLB", 3)) { - return "LLB"; - } else if (!strncmp(filename, "iBoot", 5)) { - return "iBoot"; - } else if (!strncmp(filename, "DeviceTree", 10)) { - return "DeviceTree"; - } else if (!strncmp(filename, "applelogo", 9)) { - return "AppleLogo"; - } else if (!strncmp(filename, "liquiddetect", 12)) { - return "Liquid"; - } else if (!strncmp(filename, "lowpowermode", 12)) { - return "LowPowerWallet0"; - } else if (!strncmp(filename, "recoverymode", 12)) { - return "RecoveryMode"; - } else if (!strncmp(filename, "batterylow0", 11)) { - return "BatteryLow0"; - } else if (!strncmp(filename, "batterylow1", 11)) { - return "BatteryLow1"; - } else if (!strncmp(filename, "glyphcharging", 13)) { - return "BatteryCharging"; - } else if (!strncmp(filename, "glyphplugin", 11)) { - return "BatteryPlugin"; - } else if (!strncmp(filename, "batterycharging0", 16)) { - return "BatteryCharging0"; - } else if (!strncmp(filename, "batterycharging1", 16)) { - return "BatteryCharging1"; - } else if (!strncmp(filename, "batteryfull", 11)) { - return "BatteryFull"; - } else if (!strncmp(filename, "needservice", 11)) { - return "NeedService"; - } else if (!strncmp(filename, "SCAB", 4)) { - return "SCAB"; - } else if (!strncmp(filename, "sep-firmware", 12)) { - return "RestoreSEP"; - } else { - error("WARNING: Unhandled component '%s'", filename); - return NULL; + struct filename_component_map { + const char *fnprefix; + int matchlen; + const char *compname; + }; + struct filename_component_map fn_comp_map[] = { + { "LLB", 3, "LLB" }, + { "iBoot", 5, "iBoot" }, + { "DeviceTree", 10, "DeviceTree" }, + { "applelogo", 9, "AppleLogo" }, + { "liquiddetect", 12, "Liquid" }, + { "lowpowermode", 12, "LowPowerWallet0" }, + { "recoverymode", 12, "RecoveryMode" }, + { "batterylow0", 11, "BatteryLow0" }, + { "batterylow1", 11, "BatteryLow1" }, + { "glyphcharging", 13, "BatteryCharging" }, + { "glyphplugin", 11, "BatteryPlugin" }, + { "batterycharging0", 16, "BatteryCharging0" }, + { "batterycharging1", 16, "BatteryCharging1" }, + { "batteryfull", 11, "BatteryFull" }, + { "needservice", 11, "NeedService" }, + { "SCAB", 4, "SCAB" }, + { "sep-firmware", 12, "RestoreSEP" }, + { NULL, 0, NULL } + }; + int i = 0; + while (fn_comp_map[i].fnprefix) { + if (!strncmp(filename, fn_comp_map[i].fnprefix, fn_comp_map[i].matchlen)) { + return fn_comp_map[i].compname; + } + i++; } + error("WARNING: Unhandled component '%s'", filename); + return NULL; } |