summaryrefslogtreecommitdiffstats
path: root/src/idevicerestore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/idevicerestore.c')
-rw-r--r--src/idevicerestore.c883
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;
}