diff --git a/src/ace3.c b/src/ace3.c index b96e6b4f..7486d343 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -22,8 +22,8 @@ #include #include #include -#include - +//#include +#include "nskeyedarchive.h" #include "common.h" #include "ace3.h" #include "endianness.h" diff --git a/src/common.h b/src/common.h index f771d432..8498a2e6 100644 --- a/src/common.h +++ b/src/common.h @@ -47,6 +47,8 @@ extern "C" { #define _MODE_RECOVERY 3 #define _MODE_RESTORE 4 #define _MODE_NORMAL 5 +#define _MODE_PORTDFU 6 + #define MODE_UNKNOWN &idevicerestore_modes[_MODE_UNKNOWN] #define MODE_WTF &idevicerestore_modes[_MODE_WTF] diff --git a/src/idevicerestore.c b/src/idevicerestore.c deleted file mode 100644 index 99b5b51f..00000000 --- a/src/idevicerestore.c +++ /dev/null @@ -1,3010 +0,0 @@ -/* - * idevicerestore.c - * Restore device firmware and filesystem - * - * Copyright (c) 2012-2019 Nikias Bassen. All Rights Reserved. - * Copyright (c) 2010-2015 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2010 Joshua Hill. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef HAVE_OPENSSL -#include -#else -#include "sha512.h" -#define SHA384 sha384 -#endif - -#include "ace3.h" -#include "dfu.h" -#include "tss.h" -#include "img3.h" -#include "img4.h" -#include "ipsw.h" -#include "common.h" -#include "normal.h" -#include "restore.h" -#include "download.h" -#include "recovery.h" -#include "idevicerestore.h" - -#include "limera1n.h" - -#include "locking.h" - -#define VERSION_XML "version.xml" - -#ifndef IDEVICERESTORE_NOMAIN -static struct option longopts[] = { - { "ecid", required_argument, NULL, 'i' }, - { "udid", required_argument, NULL, 'u' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "erase", no_argument, NULL, 'e' }, - { "custom", no_argument, NULL, 'c' }, - { "latest", no_argument, NULL, 'l' }, - { "cydia", no_argument, NULL, 's' }, - { "exclude", no_argument, NULL, 'x' }, - { "shsh", no_argument, NULL, 't' }, - { "keep-pers", no_argument, NULL, 'k' }, - { "pwn", no_argument, NULL, 'p' }, - { "no-action", no_argument, NULL, 'n' }, - { "cache-path", required_argument, NULL, 'C' }, - { "no-input", no_argument, NULL, 'y' }, - { "plain-progress", no_argument, NULL, 'P' }, - { "restore-mode", no_argument, NULL, 'R' }, - { "ticket", required_argument, NULL, 'T' }, - { "no-restore", no_argument, NULL, 'z' }, - { "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 } -}; - -static void usage(int argc, char* argv[], int err) -{ - char* name = strrchr(argv[0], '/'); - fprintf((err) ? stderr : stdout, - "Usage: %s [OPTIONS] PATH\n" \ - "\n" \ - "Restore IPSW firmware at PATH to an iOS device.\n" \ - "\n" \ - "PATH can be a compressed .ipsw file or a directory containing all files\n" \ - "extracted from an IPSW.\n" \ - "\n" \ - "OPTIONS:\n" \ - " -i, --ecid ECID Target specific device by its ECID\n" \ - " e.g. 0xaabb123456 (hex) or 1234567890 (decimal)\n" \ - " -u, --udid UDID Target specific device by its device UDID\n" \ - " NOTE: only works with devices in normal mode.\n" \ - " -l, --latest Use latest available firmware (with download on demand).\n" \ - " Before performing any action it will interactively ask\n" \ - " to select one of the currently signed firmware versions,\n" \ - " unless -y has been given too.\n" \ - " The PATH argument is ignored when using this option.\n" \ - " DO NOT USE if you need to preserve the baseband/unlock!\n" \ - " USE WITH CARE if you want to keep a jailbreakable\n" \ - " firmware!\n" \ - " -e, --erase Perform full restore instead of update, erasing all data\n" \ - " DO NOT USE if you want to preserve user data on the device!\n" \ - " -y, --no-input Non-interactive mode, do not ask for any input.\n" \ - " WARNING: This will disable certain checks/prompts that\n" \ - " are supposed to prevent DATA LOSS. Use with caution.\n" \ - " -n, --no-action Do not perform any restore action. If combined with -l\n" \ - " option the on-demand ipsw download is performed before\n" \ - " exiting.\n" \ - " --ipsw-info Print information about the IPSW at PATH and exit.\n" \ - " -h, --help Prints this usage information\n" \ - " -C, --cache-path DIR Use specified directory for caching extracted or other\n" \ - " reused files.\n" \ - " -d, --debug Enable communication debugging\n" \ - " -v, --version Print version information\n" \ - "\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" \ - " -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" \ - " -p, --pwn Put device in pwned DFU mode and exit (limera1n devices)\n" \ - " -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" \ - " or only partially functioning. Use with caution.\n" \ - "\n" \ - "Homepage: <" PACKAGE_URL ">\n" \ - "Bug Reports: <" PACKAGE_BUGREPORT ">\n", - (name ? name + 1 : argv[0])); -} -#endif - -const uint8_t lpol_file[22] = { - 0x30, 0x14, 0x16, 0x04, 0x49, 0x4d, 0x34, 0x50, - 0x16, 0x04, 0x6c, 0x70, 0x6f, 0x6c, 0x16, 0x03, - 0x31, 0x2e, 0x30, 0x04, 0x01, 0x00 -}; -const uint32_t lpol_file_length = 22; - -static int idevicerestore_keep_pers = 0; - -static int load_version_data(struct idevicerestore_client_t* client) -{ - if (!client) { - return -1; - } - - struct stat fst; - int cached = 0; - - char version_xml[1024]; - - if (client->cache_dir) { - if (stat(client->cache_dir, &fst) < 0) { - mkdir_with_parents(client->cache_dir, 0755); - } - strcpy(version_xml, client->cache_dir); - strcat(version_xml, "/"); - strcat(version_xml, VERSION_XML); - } else { - strcpy(version_xml, VERSION_XML); - } - - if ((stat(version_xml, &fst) < 0) || ((time(NULL)-86400) > fst.st_mtime)) { - char version_xml_tmp[1024]; - strcpy(version_xml_tmp, version_xml); - strcat(version_xml_tmp, ".tmp"); - - if (download_to_file("http://itunes.apple.com/check/version", version_xml_tmp, 0) == 0) { - remove(version_xml); - if (rename(version_xml_tmp, version_xml) < 0) { - error("ERROR: Could not update '%s'\n", version_xml); - } else { - info("NOTE: Updated version data.\n"); - } - } - } else { - cached = 1; - } - - char *verbuf = NULL; - size_t verlen = 0; - read_file(version_xml, (void**)&verbuf, &verlen); - - if (!verbuf) { - error("ERROR: Could not load '%s'\n", version_xml); - return -1; - } - - client->version_data = NULL; - plist_from_xml(verbuf, verlen, &client->version_data); - free(verbuf); - - if (!client->version_data) { - remove(version_xml); - error("ERROR: Cannot parse plist data from '%s'.\n", version_xml); - return -1; - } - - if (cached) { - info("NOTE: using cached version data\n"); - } - - return 0; -} - -static int32_t get_version_num(const char *s_ver) -{ - int vers[3] = {0, 0, 0}; - if (sscanf(s_ver, "%d.%d.%d", &vers[0], &vers[1], &vers[2]) >= 2) { - return ((vers[0] & 0xFF) << 16) | ((vers[1] & 0xFF) << 8) | (vers[2] & 0xFF); - } - return 0x00FFFFFF; -} - -static int compare_versions(const char *s_ver1, const char *s_ver2) -{ - return (get_version_num(s_ver1) & 0xFFFF00) - (get_version_num(s_ver2) & 0xFFFF00); -} - -static void idevice_event_cb(const idevice_event_t *event, void *userdata) -{ - struct idevicerestore_client_t *client = (struct idevicerestore_client_t*)userdata; -#ifdef HAVE_ENUM_IDEVICE_CONNECTION_TYPE - if (event->conn_type != CONNECTION_USBMUXD) { - // ignore everything but devices connected through USB - return; - } -#endif - if (event->event == IDEVICE_DEVICE_ADD) { - if (client->ignore_device_add_events) { - return; - } - if (normal_check_mode(client) == 0) { - mutex_lock(&client->device_event_mutex); - client->mode = MODE_NORMAL; - debug("%s: device %016" PRIx64 " (udid: %s) connected in normal mode\n", __func__, client->ecid, client->udid); - cond_signal(&client->device_event_cond); - mutex_unlock(&client->device_event_mutex); - } else if (client->ecid && restore_check_mode(client) == 0) { - mutex_lock(&client->device_event_mutex); - client->mode = MODE_RESTORE; - debug("%s: device %016" PRIx64 " (udid: %s) connected in restore mode\n", __func__, client->ecid, client->udid); - cond_signal(&client->device_event_cond); - mutex_unlock(&client->device_event_mutex); - } - } else if (event->event == IDEVICE_DEVICE_REMOVE) { - if (client->udid && !strcmp(event->udid, client->udid)) { - 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->ignore_device_add_events = 0; - cond_signal(&client->device_event_cond); - mutex_unlock(&client->device_event_mutex); - } - } -} - -static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) -{ - struct idevicerestore_client_t *client = (struct idevicerestore_client_t*)userdata; - if (event->type == IRECV_DEVICE_ADD) { - if (!client->udid && !client->ecid) { - client->ecid = event->device_info->ecid; - } - if (client->ecid && event->device_info->ecid == client->ecid) { - mutex_lock(&client->device_event_mutex); - switch (event->mode) { - case IRECV_K_WTF_MODE: - client->mode = MODE_WTF; - break; - 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: - case IRECV_K_RECOVERY_MODE_4: - client->mode = MODE_RECOVERY; - break; - default: - client->mode = MODE_UNKNOWN; - } - debug("%s: device %016" PRIx64 " (udid: %s) connected in %s mode\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A", client->mode->string); - cond_signal(&client->device_event_cond); - mutex_unlock(&client->device_event_mutex); - } - } else if (event->type == IRECV_DEVICE_REMOVE) { - if (client->ecid && event->device_info->ecid == client->ecid) { - 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 idevicerestore_start(struct idevicerestore_client_t* client) -{ - int tss_enabled = 0; - int result = 0; - - if (!client) { - return -1; - } - - if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) { - error("ERROR: FLAG_LATEST cannot be used with FLAG_CUSTOM.\n"); - return -1; - } - - if (!client->ipsw && !(client->flags & FLAG_PWN) && !(client->flags & FLAG_LATEST)) { - error("ERROR: no ipsw file given\n"); - return -1; - } - - if (client->flags & FLAG_DEBUG) { - idevice_set_debug_level(1); - irecv_set_debug_level(1); - idevicerestore_debug = 1; - } - - idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0); - - irecv_device_event_subscribe(&client->irecv_e_ctx, irecv_event_cb, client); - - idevice_event_subscribe(idevice_event_cb, client); - client->idevice_e_ctx = idevice_event_cb; - - // check which mode the device is currently in so we know where to start - mutex_lock(&client->device_event_mutex); - if (client->mode == MODE_UNKNOWN) { - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - if (client->mode == MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { - mutex_unlock(&client->device_event_mutex); - error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n"); - return -1; - } - } - idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.1); - info("Found device in %s mode\n", client->mode->string); - mutex_unlock(&client->device_event_mutex); - - if (client->mode == MODE_WTF) { - unsigned int cpid = 0; - - if (dfu_client_new(client) != 0) { - error("ERROR: Could not open device in WTF mode\n"); - return -1; - } - if ((dfu_get_cpid(client, &cpid) < 0) || (cpid == 0)) { - error("ERROR: Could not get CPID for WTF mode device\n"); - dfu_client_free(client); - return -1; - } - - char wtfname[256]; - sprintf(wtfname, "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid); - unsigned char* wtftmp = NULL; - unsigned int wtfsize = 0; - - // Prefer to get WTF file from the restore IPSW - ipsw_extract_to_memory(client->ipsw, wtfname, &wtftmp, &wtfsize); - if (!wtftmp) { - // update version data (from cache, or apple if too old) - load_version_data(client); - - // Download WTF IPSW - char* s_wtfurl = NULL; - plist_t wtfurl = plist_access_path(client->version_data, 7, "MobileDeviceSoftwareVersionsByVersion", "5", "RecoverySoftwareVersions", "WTF", "304218112", "5", "FirmwareURL"); - if (wtfurl && (plist_get_node_type(wtfurl) == PLIST_STRING)) { - plist_get_string_val(wtfurl, &s_wtfurl); - } - if (!s_wtfurl) { - info("Using hardcoded x12220000_5_Recovery.ipsw URL\n"); - s_wtfurl = strdup("http://appldnld.apple.com.edgesuite.net/content.info.apple.com/iPhone/061-6618.20090617.Xse7Y/x12220000_5_Recovery.ipsw"); - } - - // make a local file name - char* fnpart = strrchr(s_wtfurl, '/'); - if (!fnpart) { - fnpart = (char*)"x12220000_5_Recovery.ipsw"; - } else { - fnpart++; - } - struct stat fst; - char wtfipsw[1024]; - if (client->cache_dir) { - if (stat(client->cache_dir, &fst) < 0) { - mkdir_with_parents(client->cache_dir, 0755); - } - strcpy(wtfipsw, client->cache_dir); - strcat(wtfipsw, "/"); - strcat(wtfipsw, fnpart); - } else { - strcpy(wtfipsw, fnpart); - } - if (stat(wtfipsw, &fst) != 0) { - download_to_file(s_wtfurl, wtfipsw, 0); - } - - ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize); - if (!wtftmp) { - error("ERROR: Could not extract \n"); - } - } - - mutex_lock(&client->device_event_mutex); - if (wtftmp) { - if (dfu_send_buffer(client, wtftmp, wtfsize) != 0) { - error("ERROR: Could not send WTF...\n"); - } - } - dfu_client_free(client); - - free(wtftmp); - - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000); - if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) { - mutex_unlock(&client->device_event_mutex); - /* TODO: verify if it actually goes from 0x1222 -> 0x1227 */ - error("ERROR: Failed to put device into DFU from WTF mode\n"); - return -1; - } - mutex_unlock(&client->device_event_mutex); - } - - // discover the device type - client->device = get_irecv_device(client); - if (client->device == NULL) { - 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); - - if ((client->flags & FLAG_PWN) && (client->mode != MODE_DFU)) { - error("ERROR: you need to put your device into DFU mode to pwn it.\n"); - return -1; - } - - if (client->flags & FLAG_PWN) { - recovery_client_free(client); - - if (client->mode != MODE_DFU) { - error("ERROR: Device needs to be in DFU mode for this option.\n"); - return -1; - } - - info("connecting to DFU\n"); - if (dfu_client_new(client) < 0) { - return -1; - } - - // Check if device is vulnerable to limera1n - unsigned int cpid = 0; - dfu_get_cpid(client, &cpid); - - int limera1nDevices[] = {8920, 8922, 8930}; - int limera1nDevicesLen = sizeof limera1nDevices / sizeof limera1nDevices[0]; - int limera1nVuln = 0; - - for (int i = 0; i < limera1nDevicesLen; i++) { - if (limera1nDevices[i] == cpid) { - limera1nVuln = 1; - break; - } - } - - if (limera1nVuln == 1) { - 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; - } - } - - if (client->flags & FLAG_LATEST) { - char *fwurl = NULL; - unsigned char fwsha1[20]; - unsigned char *p_fwsha1 = NULL; - plist_t signed_fws = NULL; - int res = ipsw_get_signed_firmwares(client->device->product_type, &signed_fws); - if (res < 0) { - error("ERROR: Could not fetch list of signed firmwares.\n"); - return res; - } - uint32_t count = plist_array_get_size(signed_fws); - if (count == 0) { - plist_free(signed_fws); - error("ERROR: No firmwares are currently being signed for %s (REALLY?!)\n", client->device->product_type); - return -1; - } - plist_t selected_fw = NULL; - if (client->flags & FLAG_INTERACTIVE) { - uint32_t i = 0; - info("The following firmwares are currently being signed for %s:\n", client->device->product_type); - for (i = 0; i < count; i++) { - plist_t fw = plist_array_get_item(signed_fws, i); - plist_t p_version = plist_dict_get_item(fw, "version"); - plist_t p_build = plist_dict_get_item(fw, "buildid"); - char *s_version = NULL; - char *s_build = NULL; - plist_get_string_val(p_version, &s_version); - plist_get_string_val(p_build, &s_build); - info(" [%d] %s (build %s)\n", i+1, s_version, s_build); - free(s_version); - free(s_build); - } - while (1) { - char input[64]; - printf("Select the firmware you want to restore: "); - fflush(stdout); - fflush(stdin); - get_user_input(input, 63, 0); - if (*input == '\0') { - plist_free(signed_fws); - return -1; - } - if (client->flags & FLAG_QUIT) { - return -1; - } - unsigned long selected = strtoul(input, NULL, 10); - if (selected == 0 || selected > count) { - printf("Invalid input value. Must be in range: 1..%u\n", count); - continue; - } - selected_fw = plist_array_get_item(signed_fws, (uint32_t)selected-1); - break; - } - } else { - info("NOTE: Running non-interactively, automatically selecting latest available version\n"); - selected_fw = plist_array_get_item(signed_fws, 0); - } - if (!selected_fw) { - error("ERROR: failed to select latest firmware?!\n"); - plist_free(signed_fws); - return -1; - } else { - plist_t p_version = plist_dict_get_item(selected_fw, "version"); - plist_t p_build = plist_dict_get_item(selected_fw, "buildid"); - char *s_version = NULL; - char *s_build = NULL; - plist_get_string_val(p_version, &s_version); - plist_get_string_val(p_build, &s_build); - info("Selected firmware %s (build %s)\n", s_version, s_build); - free(s_version); - free(s_build); - plist_t p_url = plist_dict_get_item(selected_fw, "url"); - plist_t p_sha1 = plist_dict_get_item(selected_fw, "sha1sum"); - char *s_sha1 = NULL; - plist_get_string_val(p_url, &fwurl); - plist_get_string_val(p_sha1, &s_sha1); - if (strlen(s_sha1) == 40) { - int i; - int v; - for (i = 0; i < 40; i+=2) { - v = 0; - sscanf(s_sha1+i, "%02x", &v); - fwsha1[i/2] = (unsigned char)v; - } - p_fwsha1 = &fwsha1[0]; - } else { - error("ERROR: unexpected size of sha1sum\n"); - } - } - plist_free(signed_fws); - - if (!fwurl || !p_fwsha1) { - error("ERROR: Missing firmware URL or SHA1\n"); - return -1; - } - - char* ipsw = NULL; - res = ipsw_download_fw(fwurl, p_fwsha1, client->cache_dir, &ipsw); - if (res != 0) { - if (ipsw) { - free(ipsw); - } - return res; - } else { - client->ipsw = ipsw; - } - } - idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.6); - - if (client->flags & FLAG_NOACTION) { - return 0; - } - - 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 (restore_reboot(client) < 0) { - error("ERROR: Unable to exit restore mode\n"); - return -2; - } - - // we need to refresh the current mode again - mutex_lock(&client->device_event_mutex); - 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); - error("ERROR: Unable to discover device mode. Please make sure a device is attached.\n"); - return -1; - } - info("Found device in %s mode\n", client->mode->string); - mutex_unlock(&client->device_event_mutex); - } - } - - // 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; - } - - // 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); - 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); - return -1; - } - } - if (client->mode == MODE_PORTDFU) { - unsigned int pdfu_bdid = 0; - unsigned int pdfu_cpid = 0; - unsigned int prev = 0; - - if (dfu_get_bdid(client, &pdfu_bdid) < 0) { - error("ERROR: Failed to get bdid for Port DFU device!\n"); - return -1; - } - 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 */ - if (build_manifest_check_compatibility(client->build_manifest, client->device->product_type) < 0) { - error("ERROR: Could not make sure this firmware is suitable for the current device. Refusing to continue.\n"); - return -1; - } - - /* 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); - - 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; - plist_t inf; - plist_t manifest; - - char tmpstr[256]; - char p_all_flash[128]; - char lcmodel[8]; - strcpy(lcmodel, client->device->hardware_model); - int x = 0; - while (lcmodel[x]) { - lcmodel[x] = tolower(lcmodel[x]); - x++; - } - - sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production"); - strcpy(tmpstr, p_all_flash); - strcat(tmpstr, "/manifest"); - - // get all_flash file manifest - char *files[16]; - char *fmanifest = NULL; - 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; - } - - char *tok = strtok(fmanifest, "\r\n"); - int fc = 0; - while (tok) { - files[fc++] = strdup(tok); - if (fc >= 16) { - break; - } - tok = strtok(NULL, "\r\n"); - } - free(fmanifest); - - manifest = plist_new_dict(); - - for (x = 0; x < fc; x++) { - inf = plist_new_dict(); - strcpy(tmpstr, p_all_flash); - strcat(tmpstr, "/"); - strcat(tmpstr, files[x]); - plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); - comp = plist_new_dict(); - plist_dict_set_item(comp, "Info", inf); - const char* compname = get_component_name(files[x]); - if (compname) { - plist_dict_set_item(manifest, compname, comp); - if (!strncmp(files[x], "DeviceTree", 10)) { - plist_dict_set_item(manifest, "RestoreDeviceTree", plist_copy(comp)); - } - } else { - error("WARNING: unhandled component %s\n", files[x]); - plist_free(comp); - } - free(files[x]); - files[x] = NULL; - } - - // add iBSS - sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE"); - inf = plist_new_dict(); - plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); - comp = plist_new_dict(); - plist_dict_set_item(comp, "Info", inf); - plist_dict_set_item(manifest, "iBSS", comp); - - // add iBEC - sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE"); - inf = plist_new_dict(); - plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); - comp = plist_new_dict(); - plist_dict_set_item(comp, "Info", inf); - plist_dict_set_item(manifest, "iBEC", comp); - - // add kernel cache - plist_t kdict = NULL; - - node = plist_dict_get_item(client->build_manifest, "KernelCachesByTarget"); - if (node && (plist_get_node_type(node) == PLIST_DICT)) { - char tt[4]; - strncpy(tt, lcmodel, 3); - tt[3] = 0; - kdict = plist_dict_get_item(node, tt); - } else { - // Populated in older iOS IPSWs - kdict = plist_dict_get_item(client->build_manifest, "RestoreKernelCaches"); - } - if (kdict && (plist_get_node_type(kdict) == PLIST_DICT)) { - plist_t kc = plist_dict_get_item(kdict, "Release"); - if (kc && (plist_get_node_type(kc) == PLIST_STRING)) { - inf = plist_new_dict(); - plist_dict_set_item(inf, "Path", plist_copy(kc)); - comp = plist_new_dict(); - plist_dict_set_item(comp, "Info", inf); - plist_dict_set_item(manifest, "KernelCache", comp); - plist_dict_set_item(manifest, "RestoreKernelCache", plist_copy(comp)); - } - } - - // add ramdisk - node = plist_dict_get_item(client->build_manifest, "RestoreRamDisks"); - if (node && (plist_get_node_type(node) == PLIST_DICT)) { - plist_t rd = plist_dict_get_item(node, (client->flags & FLAG_ERASE) ? "User" : "Update"); - // if no "Update" ram disk entry is found try "User" ram disk instead - if (!rd && !(client->flags & FLAG_ERASE)) { - rd = plist_dict_get_item(node, "User"); - // also, set the ERASE flag since we actually change the restore variant - client->flags |= FLAG_ERASE; - } - if (rd && (plist_get_node_type(rd) == PLIST_STRING)) { - inf = plist_new_dict(); - plist_dict_set_item(inf, "Path", plist_copy(rd)); - comp = plist_new_dict(); - plist_dict_set_item(comp, "Info", inf); - plist_dict_set_item(manifest, "RestoreRamDisk", comp); - } - } - - // add OS filesystem - node = plist_dict_get_item(client->build_manifest, "SystemRestoreImages"); - if (!node) { - error("ERROR: missing SystemRestoreImages in Restore.plist\n"); - } - plist_t os = plist_dict_get_item(node, "User"); - if (!os) { - error("ERROR: missing filesystem in Restore.plist\n"); - } else { - inf = plist_new_dict(); - plist_dict_set_item(inf, "Path", plist_copy(os)); - comp = plist_new_dict(); - plist_dict_set_item(comp, "Info", inf); - plist_dict_set_item(manifest, "OS", comp); - } - - // 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 " 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, RESTORE_VARIANT_ERASE_INSTALL, 0); - } else { - 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->flags & FLAG_INTERACTIVE) { - char input[64]; - char spaces[16]; - int num_spaces = 13 - strlen(client->version) - strlen(device_version); - memset(spaces, ' ', num_spaces); - spaces[num_spaces] = '\0'; - printf("################################ [ WARNING ] #################################\n" - "# You are trying to DOWNGRADE a %s device with an IPSW for %s while%s #\n" - "# trying to preserve the user data (Upgrade restore). This *might* work, but #\n" - "# there is a VERY HIGH chance it might FAIL BADLY with COMPLETE DATA LOSS. #\n" - "# Hit CTRL+C now if you want to abort the restore. #\n" - "# 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); - while (1) { - printf("> "); - fflush(stdout); - fflush(stdin); - input[0] = '\0'; - get_user_input(input, 63, 0); - if (client->flags & FLAG_QUIT) { - return -1; - } - if (*input != '\0' && !strcmp(input, "YES")) { - break; - } else { - printf("Invalid input. Please type YES or hit CTRL+C to abort.\n"); - continue; - } - } - } - } - free(device_version); - } - - if (client->flags & FLAG_ERASE && client->flags & FLAG_INTERACTIVE) { - char input[64]; - printf("################################ [ WARNING ] #################################\n" - "# You are about to perform an *ERASE* restore. ALL DATA on the target device #\n" - "# will be IRREVERSIBLY DESTROYED. If you want to update your device without #\n" - "# erasing the user data, hit CTRL+C now and restart without -e or --erase #\n" - "# command line switch. #\n" - "# If you want to continue with the ERASE, please type YES and press ENTER. #\n" - "##############################################################################\n"); - while (1) { - printf("> "); - fflush(stdout); - fflush(stdin); - input[0] = '\0'; - get_user_input(input, 63, 0); - if (client->flags & FLAG_QUIT) { - return -1; - } - if (*input != '\0' && !strcmp(input, "YES")) { - break; - } else { - printf("Invalid input. Please type YES or hit CTRL+C to abort.\n"); - continue; - } - } - } - - idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.0); - - /* 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); - 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) { - 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); - } - 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 == '.') { - *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; - } else { - // use .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; - } - - if (strstr(filesystem, ".extract")) { - // rename .extract to - remove(tmpf); - rename(filesystem, tmpf); - free(filesystem); - filesystem = strdup(tmpf); - } - } - - idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.2); - - /* retrieve shsh blobs if required */ - if (tss_enabled) { - int stashbag_commit_required = 0; - - if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) { - plist_t node = normal_get_lockdown_value(client, NULL, "HasSiDP"); - uint8_t needs_preboard = 0; - if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { - plist_get_bool_val(node, &needs_preboard); - } - if (needs_preboard) { - info("Checking if device requires stashbag...\n"); - plist_t manifest; - if (get_preboard_manifest(client, build_identity, &manifest) < 0) { - error("ERROR: Unable to create preboard manifest.\n"); - return -1; - } - debug("DEBUG: creating stashbag...\n"); - int err = normal_handle_create_stashbag(client, manifest); - if (err < 0) { - if (err == -2) { - error("ERROR: Could not create stashbag (timeout).\n"); - } else { - error("ERROR: An error occurred while creating the stashbag.\n"); - } - return -1; - } else if (err == 1) { - stashbag_commit_required = 1; - } - plist_free(manifest); - } - } - - if (client->build_major > 8) { - unsigned char* nonce = NULL; - 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"); - } - - if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) { - if (client->nonce) { - free(client->nonce); - } - client->nonce = nonce; - client->nonce_size = nonce_size; - } else { - free(nonce); - } - } - - if (client->flags & FLAG_QUIT) { - 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->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) { - plist_t ticket = plist_dict_get_item(client->tss, "ApImg4Ticket"); - if (!ticket || plist_get_node_type(ticket) != PLIST_DATA) { - error("ERROR: Missing ApImg4Ticket in TSS response for stashbag commit\n"); - return -1; - } - info("Committing stashbag...\n"); - int err = normal_handle_commit_stashbag(client, ticket); - if (err < 0) { - error("ERROR: Could not commit stashbag (%d). Aborting.\n", err); - return -1; - } - } - } - - if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); - return -1; - } - if (client->flags & FLAG_SHSHONLY) { - if (!tss_enabled) { - info("This device does not require a TSS record\n"); - return 0; - } - if (!client->tss) { - error("ERROR: could not fetch TSS record\n"); - return -1; - } else { - char *bin = NULL; - uint32_t blen = 0; - plist_to_bin(client->tss, &bin, &blen); - if (bin) { - char zfn[1024]; - if (client->cache_dir) { - strcpy(zfn, client->cache_dir); - strcat(zfn, "/shsh"); - } else { - strcpy(zfn, "shsh"); - } - mkdir_with_parents(zfn, 0755); - sprintf(zfn+strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); - struct stat fst; - if (stat(zfn, &fst) != 0) { - gzFile zf = gzopen(zfn, "wb"); - gzwrite(zf, bin, blen); - gzclose(zf); - info("SHSH saved to '%s'\n", zfn); - } else { - info("SHSH '%s' already present.\n", zfn); - } - free(bin); - } else { - error("ERROR: could not get TSS record data\n"); - } - plist_free(client->tss); - return 0; - } - } - - /* verify if we have tss records if required */ - if ((tss_enabled) && (client->tss == NULL)) { - error("ERROR: Unable to proceed without a TSS record.\n"); - return -1; - } - - if ((tss_enabled) && client->tss) { - /* fix empty dicts */ - fixup_tss(client->tss); - } - idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.25); - if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); - return -1; - } - - // if the device is in normal mode, place device into recovery mode - if (client->mode == MODE_NORMAL) { - info("Entering recovery mode... WELL\n"); - if (normal_enter_recovery(client) < 0) { - error("ERROR: Unable to place device into recovery mode from normal mode\n"); - if (client->tss) - plist_free(client->tss); - return -5; - } - } - - idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.3); - if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); - return -1; - } - - if (client->mode == MODE_DFU) { - // if the device is in DFU mode, place it into recovery mode - dfu_client_free(client); - recovery_client_free(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); - info("exploited\n"); - } - if (dfu_enter_recovery(client, build_identity) < 0) { - 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) { - // device is in recovery mode - if ((client->build_major > 8) && !(client->flags & FLAG_CUSTOM)) { - if (!client->image4supported) { - /* send ApTicket */ - if (recovery_send_ticket(client) < 0) { - error("ERROR: Unable to send APTicket\n"); - if (delete_fs && filesystem) - unlink(filesystem); - return -2; - } - } - } - - mutex_lock(&client->device_event_mutex); - - /* now we load the iBEC */ - 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...3\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); - int tries = 3 ; - while(tries-- && (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT))) { - debug("cond_wait_timeout retry\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 3000); - } - 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, 60000); - tries = 3 ; - while(tries-- && (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT))) { - debug("cond_wait_timeout retry\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 3000); - } - 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; - 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; - } - - if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) { - nonce_changed = 1; - if (client->nonce) { - free(client->nonce); - } - client->nonce = nonce; - client->nonce_size = nonce_size; - } else { - free(nonce); - } - - if (nonce_changed && !(client->flags & FLAG_CUSTOM)) { - // Welcome iOS5. We have to re-request the TSS with our nonce. - 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); - } - } - 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 (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); - } - idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.9); - - if (client->mode != MODE_RESTORE) { - mutex_lock(&client->device_event_mutex); - info("Waiting for device to enter restore mode...\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 180000); - int tries = 3 ; - while(tries-- && (client->mode != MODE_RESTORE || (client->flags & FLAG_QUIT))) { - debug("cond_wait_timeout retry\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 3000); - } - if (client->mode != MODE_RESTORE || (client->flags & FLAG_QUIT)) { - 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); - } - - // device is finally in restore mode, let's do this - if (client->mode == MODE_RESTORE) { - if ((client->flags & FLAG_NO_RESTORE) != 0) { - info("Device is now in restore mode. Exiting as requested."); - return 0; - } - client->ignore_device_add_events = 1; - info("About to restore device... \n"); - result = restore_device(client, build_identity, filesystem); - 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) { - if (recovery_set_autoboot(client, 1) == 0) { - recovery_send_reset(client); - } else { - error("Setting auto-boot failed?!\n"); - } - } else { - error("Could not connect to device in recovery mode.\n"); - } - } - - info("DONE\n"); - - if (result == 0) { - idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0); - } - - if (build_identity_needs_free) - plist_free(build_identity); - - return result; -} - -struct idevicerestore_client_t* idevicerestore_client_new(void) -{ - struct idevicerestore_client_t* client = (struct idevicerestore_client_t*) malloc(sizeof(struct idevicerestore_client_t)); - if (client == NULL) { - error("ERROR: Out of memory\n"); - return NULL; - } - memset(client, '\0', sizeof(struct idevicerestore_client_t)); - client->mode = MODE_UNKNOWN; - mutex_init(&client->device_event_mutex); - cond_init(&client->device_event_cond); - return client; -} - -void idevicerestore_client_free(struct idevicerestore_client_t* client) -{ - if (!client) { - return; - } - - if (client->irecv_e_ctx) { - irecv_device_event_unsubscribe(client->irecv_e_ctx); - } - if (client->idevice_e_ctx) { - idevice_event_unsubscribe(); - } - cond_destroy(&client->device_event_cond); - mutex_destroy(&client->device_event_mutex); - - if (client->tss_url) { - free(client->tss_url); - } - if (client->version_data) { - plist_free(client->version_data); - } - if (client->nonce) { - free(client->nonce); - } - if (client->udid) { - free(client->udid); - } - if (client->srnm) { - free(client->srnm); - } - if (client->ipsw) { - free(client->ipsw); - } - if (client->version) { - free(client->version); - } - if (client->build) { - free(client->build); - } - if (client->restore_boot_args) { - free(client->restore_boot_args); - } - if (client->cache_dir) { - free(client->cache_dir); - } - if (client->root_ticket) { - free(client->root_ticket); - } - if (client->build_manifest) { - plist_free(client->build_manifest); - } - if (client->preflight_info) { - plist_free(client->preflight_info); - } - free(client->restore_variant); - free(client); -} - -void idevicerestore_set_ecid(struct idevicerestore_client_t* client, uint64_t ecid) -{ - if (!client) - return; - client->ecid = ecid; -} - -void idevicerestore_set_udid(struct idevicerestore_client_t* client, const char* udid) -{ - if (!client) - return; - if (client->udid) { - free(client->udid); - client->udid = NULL; - } - if (udid) { - client->udid = strdup(udid); - } -} - -void idevicerestore_set_flags(struct idevicerestore_client_t* client, int flags) -{ - if (!client) - return; - client->flags = flags; -} - -void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* path) -{ - if (!client) - return; - if (client->ipsw) { - free(client->ipsw); - client->ipsw = NULL; - } - if (path) { - client->ipsw = strdup(path); - } -} - -void idevicerestore_set_cache_path(struct idevicerestore_client_t* client, const char* path) -{ - if (!client) - return; - if (client->cache_dir) { - free(client->cache_dir); - client->cache_dir = NULL; - } - if (path) { - client->cache_dir = strdup(path); - } -} - -void idevicerestore_set_progress_callback(struct idevicerestore_client_t* client, idevicerestore_progress_cb_t cbfunc, void* userdata) -{ - if (!client) - return; - client->progress_cb = cbfunc; - client->progress_cb_data = userdata; -} - -#ifndef IDEVICERESTORE_NOMAIN -static struct idevicerestore_client_t* idevicerestore_client = NULL; - -static void handle_signal(int sig) -{ - if (idevicerestore_client) { - idevicerestore_client->flags |= FLAG_QUIT; - ipsw_cancel(); - } -} - -void plain_progress_cb(int step, double step_progress, void* userdata) -{ - printf("progress: %u %f\n", step, step_progress); - fflush(stdout); - fflush(stderr); -} - -int main(int argc, char* argv[]) { - setbuf(stdout, NULL); - int opt = 0; - int optindex = 0; - char* ipsw = NULL; - int ipsw_info = 0; - int result = 0; - - struct idevicerestore_client_t* client = idevicerestore_client_new(); - if (client == NULL) { - error("ERROR: could not create idevicerestore client\n"); - return EXIT_FAILURE; - } - - idevicerestore_client = client; - -#ifdef WIN32 - signal(SIGINT, handle_signal); - signal(SIGTERM, handle_signal); - signal(SIGABRT, handle_signal); -#else - struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = handle_signal; - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGQUIT, &sa, NULL); - sa.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &sa, NULL); -#endif - - if (!isatty(fileno(stdin)) || !isatty(fileno(stdout))) { - client->flags &= ~FLAG_INTERACTIVE; - } else { - client->flags |= FLAG_INTERACTIVE; - } - - while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) { - switch (opt) { - case 'h': - usage(argc, argv, 0); - return EXIT_SUCCESS; - - case 'd': - client->flags |= FLAG_DEBUG; - break; - - case 'e': - client->flags |= FLAG_ERASE; - break; - - case 'c': - client->flags |= FLAG_CUSTOM; - break; - - case 's': - client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2"); - break; - - case 'x': - client->flags |= FLAG_EXCLUDE; - break; - - case 'l': - client->flags |= FLAG_LATEST; - break; - - case 'i': - if (optarg) { - char* tail = NULL; - client->ecid = strtoull(optarg, &tail, 0); - if (tail && (tail[0] != '\0')) { - client->ecid = 0; - } - if (client->ecid == 0) { - error("ERROR: Could not parse ECID from '%s'\n", optarg); - return EXIT_FAILURE; - } - } - break; - - case 'u': - if (!*optarg) { - error("ERROR: UDID must not be empty!\n"); - usage(argc, argv, 1); - return EXIT_FAILURE; - } - client->udid = strdup(optarg); - break; - - case 't': - client->flags |= FLAG_SHSHONLY; - break; - - case 'k': - idevicerestore_keep_pers = 1; - break; - - case 'p': - client->flags |= FLAG_PWN; - break; - - case 'n': - client->flags |= FLAG_NOACTION; - break; - - case 'C': - client->cache_dir = strdup(optarg); - break; - - case 'y': - client->flags &= ~FLAG_INTERACTIVE; - break; - - case 'P': - idevicerestore_set_progress_callback(client, plain_progress_cb, NULL); - break; - - case 'R': - client->flags |= FLAG_ALLOW_RESTORE_MODE; - break; - - case 'z': - client->flags |= FLAG_NO_RESTORE; - break; - - case 'v': - info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); - return EXIT_SUCCESS; - - case 'T': { - size_t root_ticket_len = 0; - unsigned char* root_ticket = NULL; - if (read_file(optarg, (void**)&root_ticket, &root_ticket_len) != 0) { - return EXIT_FAILURE; - } - client->root_ticket = root_ticket; - client->root_ticket_len = (int)root_ticket_len; - info("Using ApTicket found at %s length %u\n", optarg, client->root_ticket_len); - break; - } - - case 'I': - ipsw_info = 1; - break; - - case 1: - 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; - } - } - - if (ipsw_info) { - if (argc-optind != 1) { - error("ERROR: --ipsw-info requires an IPSW path.\n"); - usage(argc, argv, 1); - return EXIT_FAILURE; - } - return (ipsw_print_info(*(argv + optind)) == 0) ? EXIT_SUCCESS : EXIT_FAILURE; - } - - if (((argc-optind) == 1) || (client->flags & FLAG_PWN) || (client->flags & FLAG_LATEST)) { - argc -= optind; - argv += optind; - - ipsw = argv[0]; - } else { - usage(argc, argv, 1); - return EXIT_FAILURE; - } - - if ((client->flags & FLAG_LATEST) && (client->flags & FLAG_CUSTOM)) { - error("ERROR: You can't use --custom and --latest options at the same time.\n"); - return EXIT_FAILURE; - } - - info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); - - if (ipsw) { - client->ipsw = strdup(ipsw); - } - - curl_global_init(CURL_GLOBAL_ALL); - - result = idevicerestore_start(client); - - idevicerestore_client_free(client); - - curl_global_cleanup(); - - return (result == 0) ? EXIT_SUCCESS : EXIT_FAILURE; -} -#endif - -irecv_device_t get_irecv_device(struct idevicerestore_client_t *client) -{ - int mode = _MODE_UNKNOWN; - - if (client->mode) { - mode = client->mode->index; - } - - switch (mode) { - case _MODE_RESTORE: - return restore_get_irecv_device(client); - - case _MODE_NORMAL: - return normal_get_irecv_device(client); - - case _MODE_DFU: - case _MODE_PORTDFU: - case _MODE_RECOVERY: - return dfu_get_irecv_device(client); - - default: - return NULL; - } -} - -int is_image4_supported(struct idevicerestore_client_t* client) -{ - int res = 0; - int mode = _MODE_UNKNOWN; - - if (client->mode) { - mode = client->mode->index; - } - - switch (mode) { - case _MODE_NORMAL: - res = normal_is_image4_supported(client); - break; - case _MODE_RESTORE: - res = restore_is_image4_supported(client); - break; - case _MODE_DFU: - res = dfu_is_image4_supported(client); - break; - case _MODE_RECOVERY: - res = recovery_is_image4_supported(client); - break; - default: - error("ERROR: Device is in an invalid state\n"); - return 0; - } - return res; -} - -int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) -{ - int mode = _MODE_UNKNOWN; - - *nonce = NULL; - *nonce_size = 0; - - info("Getting ApNonce "); - - if (client->mode) { - mode = client->mode->index; - } - - switch (mode) { - case _MODE_NORMAL: - info("in normal mode... "); - if (normal_get_ap_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); - return -1; - } - break; - case _MODE_DFU: - info("in dfu mode... "); - if (dfu_get_ap_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); - return -1; - } - break; - case _MODE_RECOVERY: - info("in recovery mode... "); - if (recovery_get_ap_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); - return -1; - } - break; - - default: - info("failed\n"); - error("ERROR: Device is in an invalid state\n"); - return -1; - } - - int i = 0; - for (i = 0; i < *nonce_size; i++) { - info("%02x ", (*nonce)[i]); - } - info("\n"); - - return 0; -} - -int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) -{ - int mode = _MODE_UNKNOWN; - - *nonce = NULL; - *nonce_size = 0; - - info("Getting SepNonce "); - - if (client->mode) { - mode = client->mode->index; - } - - switch (mode) { - case _MODE_NORMAL: - info("in normal mode... "); - if (normal_get_sep_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); - return -1; - } - break; - case _MODE_DFU: - info("in dfu mode... "); - if (dfu_get_sep_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); - return -1; - } - break; - case _MODE_RECOVERY: - info("in recovery mode... "); - if (recovery_get_sep_nonce(client, nonce, nonce_size) < 0) { - info("failed\n"); - return -1; - } - break; - - default: - info("failed\n"); - error("ERROR: Device is in an invalid state\n"); - return -1; - } - - int i = 0; - for (i = 0; i < *nonce_size; i++) { - info("%02x ", (*nonce)[i]); - } - info("\n"); - - return 0; -} - -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) { - error("ERROR: Unable to find build identities node\n"); - return NULL; - } - - uint32_t i; - for (i = 0; i < plist_array_get_size(build_identities_array); i++) { - plist_t ident = plist_array_get_item(build_identities_array, i); - if (!ident || plist_get_node_type(ident) != PLIST_DICT) { - continue; - } - plist_t info_dict = plist_dict_get_item(ident, "Info"); - if (!info_dict || plist_get_node_type(ident) != PLIST_DICT) { - continue; - } - plist_t devclass = plist_dict_get_item(info_dict, "DeviceClass"); - if (!devclass || plist_get_node_type(devclass) != PLIST_STRING) { - continue; - } - const char *str = plist_get_string_ptr(devclass, NULL); - if (strcasecmp(str, hardware_model) != 0) { - continue; - } - if (variant) { - plist_t rvariant = plist_dict_get_item(info_dict, "Variant"); - if (!rvariant || plist_get_node_type(rvariant) != PLIST_STRING) { - continue; - } - 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 { - return ident; - } - } else { - return ident; - } - } - - return NULL; -} - -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, 0); -} - -int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest) -{ - plist_t request = NULL; - *manifest = NULL; - - if (!client->image4supported) { - return -1; - } - - /* populate parameters */ - plist_t parameters = plist_new_dict(); - - 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(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, true); - - /* create basic request */ - request = tss_request_new(NULL); - if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); - plist_free(parameters); - return -1; - } - - /* add common tags from manifest */ - if (tss_request_add_common_tags(request, parameters, overrides) < 0) { - error("ERROR: Unable to add common tags\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - plist_dict_set_item(parameters, "_OnlyFWComponents", plist_new_bool(1)); - - /* add tags from manifest */ - if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add ap tags\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - plist_t local_manifest = NULL; - int res = img4_create_local_manifest(request, build_identity, &local_manifest); - - *manifest = local_manifest; - - plist_free(request); - plist_free(parameters); - plist_free(overrides); - - return res; -} - -int get_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss) -{ - plist_t request = NULL; - plist_t response = NULL; - *tss = NULL; - - if ((client->build_major <= 8) || (client->flags & FLAG_CUSTOM)) { - error("checking for local shsh\n"); - - /* first check for local copy */ - char zfn[1024]; - if (client->version) { - if (client->cache_dir) { - sprintf(zfn, "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version); - } else { - sprintf(zfn, "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); - } - struct stat fst; - if (stat(zfn, &fst) == 0) { - gzFile zf = gzopen(zfn, "rb"); - if (zf) { - int blen = 0; - int readsize = 16384; - int bufsize = readsize; - char* bin = (char*)malloc(bufsize); - char* p = bin; - do { - int bytes_read = gzread(zf, p, readsize); - if (bytes_read < 0) { - fprintf(stderr, "Error reading gz compressed data\n"); - exit(EXIT_FAILURE); - } - blen += bytes_read; - if (bytes_read < readsize) { - if (gzeof(zf)) { - bufsize += bytes_read; - break; - } - } - bufsize += readsize; - bin = realloc(bin, bufsize); - p = bin + blen; - } while (!gzeof(zf)); - gzclose(zf); - if (blen > 0) { - if (memcmp(bin, "bplist00", 8) == 0) { - plist_from_bin(bin, blen, tss); - } else { - plist_from_xml(bin, blen, tss); - } - } - free(bin); - } - } else { - error("no local file %s\n", zfn); - } - } else { - error("No version found?!\n"); - } - } - - if (*tss) { - info("Using cached SHSH\n"); - return 0; - } else { - info("Trying to fetch new SHSH blob\n"); - } - - /* populate parameters */ - plist_t parameters = plist_new_dict(); - plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); - if (client->nonce) { - 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; - get_sep_nonce(client, &sep_nonce, &sep_nonce_size); - - if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); - free(sep_nonce); - } - - plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); - if (client->image4supported) { - plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); - plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1)); - } else { - plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); - } - - tss_parameters_add_from_manifest(parameters, build_identity, true); - - /* create basic request */ - request = tss_request_new(NULL); - if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); - plist_free(parameters); - return -1; - } - - /* add common tags from manifest */ - if (tss_request_add_common_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - /* add tags from manifest */ - if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - if (client->image4supported) { - /* add personalized parameters */ - if (tss_request_add_ap_img4_tags(request, parameters) < 0) { - error("ERROR: Unable to add img4 tags to TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - } else { - /* add personalized parameters */ - if (tss_request_add_ap_img3_tags(request, parameters) < 0) { - error("ERROR: Unable to add img3 tags to TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - } - - if (client->mode == MODE_NORMAL) { - /* normal mode; request baseband ticket aswell */ - plist_t pinfo = NULL; - normal_get_preflight_info(client, &pinfo); - if (pinfo) { - _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); - - _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); - } - } - client->preflight_info = pinfo; - } - - /* send request and grab response */ - response = tss_request_send(request, client->tss_url); - if (response == NULL) { - info("ERROR: Unable to send TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - info("Received SHSH blobs\n"); - - plist_free(request); - plist_free(parameters); - - *tss = response; - - return 0; -} - -int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss) -{ - plist_t request = NULL; - plist_t response = NULL; - *tss = NULL; - - /* populate parameters */ - plist_t parameters = plist_new_dict(); - - /* ApECID */ - plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); - plist_dict_set_item(parameters, "Ap,LocalBoot", plist_new_bool(0)); - - /* ApNonce */ - if (client->nonce) { - 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; - get_sep_nonce(client, &sep_nonce, &sep_nonce_size); - - /* ApSepNonce */ - if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); - free(sep_nonce); - } - - /* ApProductionMode */ - plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); - - /* ApSecurityMode */ - if (client->image4supported) { - plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); - plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1)); - } else { - plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); - } - - tss_parameters_add_from_manifest(parameters, build_identity, true); - - /* create basic request */ - /* Adds @HostPlatformInfo, @VersionInfo, @UUID */ - request = tss_request_new(NULL); - if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); - plist_free(parameters); - return -1; - } - - /* add common tags from manifest */ - /* 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); - plist_free(parameters); - return -1; - } - - /* add AP tags from manifest */ - if (tss_request_add_common_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - /* add AP tags from manifest */ - /* Fills digests & co */ - if (tss_request_add_ap_recovery_tags(request, parameters, NULL) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - /* send request and grab response */ - response = tss_request_send(request, client->tss_url); - if (response == NULL) { - info("ERROR: Unable to send TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - // request_add_ap_tags - - info("Received SHSH blobs\n"); - - plist_free(request); - plist_free(parameters); - - *tss = response; - - return 0; -} - -int get_recovery_os_local_policy_tss_response( - struct idevicerestore_client_t* client, - plist_t build_identity, - plist_t* tss, - plist_t args) -{ - plist_t request = NULL; - plist_t response = NULL; - *tss = NULL; - - /* populate parameters */ - plist_t parameters = plist_new_dict(); - plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); - plist_dict_set_item(parameters, "Ap,LocalBoot", plist_new_bool(1)); - - plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); - if (client->image4supported) { - plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); - plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1)); - } else { - plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); - } - - tss_parameters_add_from_manifest(parameters, build_identity, true); - - // Add Ap,LocalPolicy - uint8_t digest[SHA384_DIGEST_LENGTH]; - SHA384(lpol_file, lpol_file_length, digest); - plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); - plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); - plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); - - _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; - plist_get_string_val(vol_uuid_node, &vol_uuid_str); - unsigned int vuuid[16]; - unsigned char vol_uuid[16]; - if (sscanf(vol_uuid_str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", &vuuid[0], &vuuid[1], &vuuid[2], &vuuid[3], &vuuid[4], &vuuid[5], &vuuid[6], &vuuid[7], &vuuid[8], &vuuid[9], &vuuid[10], &vuuid[11], &vuuid[12], &vuuid[13], &vuuid[14], &vuuid[15]) != 16) { - error("ERROR: Failed to parse Ap,VolumeUUID (%s)\n", vol_uuid_str); - free(vol_uuid_str); - return -1; - } - free(vol_uuid_str); - int i; - for (i = 0; i < 16; i++) { - vol_uuid[i] = (unsigned char)vuuid[i]; - } - plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data((char*)vol_uuid, 16)); - - /* create basic request */ - request = tss_request_new(NULL); - if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); - plist_free(parameters); - return -1; - } - - /* add common tags from manifest */ - if (tss_request_add_local_policy_tags(request, parameters) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - /* send request and grab response */ - response = tss_request_send(request, client->tss_url); - if (response == NULL) { - info("ERROR: Unable to send TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - info("Received SHSH blobs\n"); - - plist_free(request); - plist_free(parameters); - - *tss = response; - - return 0; -} - -int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss) -{ - plist_t request = NULL; - plist_t response = NULL; - *tss = NULL; - - /* populate parameters */ - plist_t parameters = plist_new_dict(); - plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); - plist_dict_set_item(parameters, "Ap,LocalBoot", plist_new_bool(0)); - if (client->nonce) { - 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; - get_sep_nonce(client, &sep_nonce, &sep_nonce_size); - - if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); - free(sep_nonce); - } - - plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); - if (client->image4supported) { - plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); - plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1)); - } else { - plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); - } - - tss_parameters_add_from_manifest(parameters, build_identity, true); - - // Add Ap,LocalPolicy - uint8_t digest[SHA384_DIGEST_LENGTH]; - SHA384(lpol_file, lpol_file_length, digest); - plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); - plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); - plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); - - // Add Ap,NextStageIM4MHash - // Get previous TSS ticket - uint8_t* ticket = NULL; - uint32_t ticket_length = 0; - tss_response_get_ap_img4_ticket(client->tss, &ticket, &ticket_length); - // Hash it and add it as Ap,NextStageIM4MHash - uint8_t hash[SHA384_DIGEST_LENGTH]; - SHA384(ticket, ticket_length, hash); - plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data((char*)hash, SHA384_DIGEST_LENGTH)); - - /* create basic request */ - request = tss_request_new(NULL); - if (request == NULL) { - error("ERROR: Unable to create TSS request\n"); - plist_free(parameters); - return -1; - } - - /* add common tags from manifest */ - if (tss_request_add_local_policy_tags(request, parameters) < 0) { - error("ERROR: Unable to add common tags to TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - /* send request and grab response */ - response = tss_request_send(request, client->tss_url); - if (response == NULL) { - info("ERROR: Unable to send TSS request\n"); - plist_free(request); - plist_free(parameters); - return -1; - } - - info("Received SHSH blobs\n"); - - plist_free(request); - plist_free(parameters); - - *tss = response; - - return 0; -} - -void fixup_tss(plist_t tss) -{ - plist_t node; - plist_t node2; - node = plist_dict_get_item(tss, "RestoreLogo"); - if (node && (plist_get_node_type(node) == PLIST_DICT) && (plist_dict_get_size(node) == 0)) { - node2 = plist_dict_get_item(tss, "AppleLogo"); - if (node2 && (plist_get_node_type(node2) == PLIST_DICT)) { - plist_dict_remove_item(tss, "RestoreLogo"); - plist_dict_set_item(tss, "RestoreLogo", plist_copy(node2)); - } - } - node = plist_dict_get_item(tss, "RestoreDeviceTree"); - if (node && (plist_get_node_type(node) == PLIST_DICT) && (plist_dict_get_size(node) == 0)) { - node2 = plist_dict_get_item(tss, "DeviceTree"); - if (node2 && (plist_get_node_type(node2) == PLIST_DICT)) { - plist_dict_remove_item(tss, "RestoreDeviceTree"); - plist_dict_set_item(tss, "RestoreDeviceTree", plist_copy(node2)); - } - } - node = plist_dict_get_item(tss, "RestoreKernelCache"); - if (node && (plist_get_node_type(node) == PLIST_DICT) && (plist_dict_get_size(node) == 0)) { - node2 = plist_dict_get_item(tss, "KernelCache"); - if (node2 && (plist_get_node_type(node2) == PLIST_DICT)) { - plist_dict_remove_item(tss, "RestoreKernelCache"); - plist_dict_set_item(tss, "RestoreKernelCache", plist_copy(node2)); - } - } -} - -int build_manifest_get_identity_count(plist_t build_manifest) -{ - // fetch build identities array from BuildManifest - 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) { - error("ERROR: Unable to find build identities node\n"); - return -1; - } - 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) -{ - char* component_name = NULL; - if (!ipsw || !path || !component_data || !component_size) { - return -1; - } - - component_name = strrchr(path, '/'); - if (component_name != NULL) - component_name++; - else - component_name = (char*) path; - - 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); - return -1; - } - - return 0; -} - -int personalize_component(const char *component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size) -{ - unsigned char* component_blob = NULL; - unsigned int component_blob_size = 0; - unsigned char* stitched_component = NULL; - unsigned int stitched_component_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, 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) { - debug("NOTE: No SHSH blob found for component %s\n", component_name); - } - - if (component_blob != NULL) { - if (img3_stitch_component(component_name, component_data, component_size, component_blob, 64, &stitched_component, &stitched_component_size) < 0) { - error("ERROR: Unable to replace %s IMG3 signature\n", component_name); - free(component_blob); - return -1; - } - } else { - info("Not personalizing component %s...\n", component_name); - stitched_component = (unsigned char*)malloc(component_size); - if (stitched_component) { - stitched_component_size = component_size; - memcpy(stitched_component, component_data, component_size); - } - } - } - free(component_blob); - - if (idevicerestore_keep_pers) { - write_file(component_name, stitched_component, stitched_component_size); - } - - *personalized_component = stitched_component; - *personalized_component_size = stitched_component_size; - return 0; -} - -int build_manifest_check_compatibility(plist_t build_manifest, const char* product) -{ - int res = -1; - plist_t node = plist_dict_get_item(build_manifest, "SupportedProductTypes"); - if (!node || (plist_get_node_type(node) != PLIST_ARRAY)) { - debug("%s: ERROR: SupportedProductTypes key missing\n", __func__); - debug("%s: WARNING: If attempting to install iPhoneOS 2.x, be advised that Restore.plist does not contain the", __func__); - debug("%s: WARNING: key 'SupportedProductTypes'. Recommendation is to manually add it to the Restore.plist.", __func__); - return -1; - } - uint32_t pc = plist_array_get_size(node); - uint32_t i; - for (i = 0; i < pc; i++) { - plist_t prod = plist_array_get_item(node, i); - if (plist_get_node_type(prod) == PLIST_STRING) { - char *val = NULL; - plist_get_string_val(prod, &val); - if (val && (strcmp(val, product) == 0)) { - res = 0; - free(val); - break; - } - } - } - return res; -} - -void build_manifest_get_version_information(plist_t build_manifest, struct idevicerestore_client_t* client) -{ - plist_t node = NULL; - client->version = NULL; - client->build = NULL; - - node = plist_dict_get_item(build_manifest, "ProductVersion"); - if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to find ProductVersion node\n"); - return; - } - plist_get_string_val(node, &client->version); - - node = plist_dict_get_item(build_manifest, "ProductBuildVersion"); - if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to find ProductBuildVersion node\n"); - return; - } - plist_get_string_val(node, &client->build); - - client->build_major = strtoul(client->build, NULL, 10); -} - -void build_identity_print_information(plist_t build_identity) -{ - char* value = NULL; - plist_t info_node = NULL; - plist_t node = NULL; - - info_node = plist_dict_get_item(build_identity, "Info"); - if (!info_node || plist_get_node_type(info_node) != PLIST_DICT) { - error("ERROR: Unable to find Info node\n"); - return; - } - - node = plist_dict_get_item(info_node, "Variant"); - if (!node || plist_get_node_type(node) != PLIST_STRING) { - error("ERROR: Unable to find Variant node\n"); - return; - } - plist_get_string_val(node, &value); - - info("Variant: %s\n", value); - - 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); - - info_node = NULL; - node = NULL; -} - -int build_identity_check_components_in_ipsw(plist_t build_identity, const char *ipsw) -{ - plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - return -1; - } - int res = 0; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - plist_t node = NULL; - char *key = NULL; - do { - node = NULL; - key = NULL; - plist_dict_next_item(manifest_node, iter, &key, &node); - if (key && node) { - plist_t path = plist_access_path(node, 2, "Info", "Path"); - if (path) { - char *comp_path = NULL; - plist_get_string_val(path, &comp_path); - if (comp_path) { - if (!ipsw_file_exists(ipsw, comp_path)) { - error("ERROR: %s file %s not found in IPSW\n", key, comp_path); - res = -1; - } - free(comp_path); - } - } - } - free(key); - } while (node); - return res; -} - -int build_identity_has_component(plist_t build_identity, const char* component) -{ - plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - return 0; - } - - plist_t component_node = plist_dict_get_item(manifest_node, component); - if (!component_node || plist_get_node_type(component_node) != PLIST_DICT) { - return 0; - } - - return 1; -} - -int build_identity_get_component_path(plist_t build_identity, const char* component, char** path) -{ - char* filename = NULL; - - plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: Unable to find manifest node\n"); - if (filename) - free(filename); - return -1; - } - - plist_t component_node = plist_dict_get_item(manifest_node, component); - if (!component_node || plist_get_node_type(component_node) != PLIST_DICT) { - error("ERROR: Unable to find component node for %s\n", component); - if (filename) - free(filename); - return -1; - } - - plist_t component_info_node = plist_dict_get_item(component_node, "Info"); - if (!component_info_node || plist_get_node_type(component_info_node) != PLIST_DICT) { - error("ERROR: Unable to find component info node for %s\n", component); - if (filename) - free(filename); - return -1; - } - - plist_t component_info_path_node = plist_dict_get_item(component_info_node, "Path"); - if (!component_info_path_node || plist_get_node_type(component_info_path_node) != PLIST_STRING) { - error("ERROR: Unable to find component info path node for %s\n", component); - if (filename) - free(filename); - return -1; - } - plist_get_string_val(component_info_path_node, &filename); - - *path = filename; - return 0; -} - -const char* get_component_name(const char* filename) -{ - 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; -} \ No newline at end of file diff --git a/src/ipsw.c b/src/ipsw.c index 2c23d2a3..d3028473 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -134,7 +134,7 @@ int ipsw_print_info(const char* path) } plist_t manifest = NULL; - plist_from_memory(plist_buf, plist_len, &manifest); + plist_from_memory(plist_buf, plist_len, &manifest,NULL); free(plist_buf); plist_t val;