diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/idevicerestore.c | 158 |
1 files changed, 153 insertions, 5 deletions
diff --git a/src/idevicerestore.c b/src/idevicerestore.c index d02864e..6733a59 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -156,10 +156,18 @@ int main(int argc, char* argv[]) { // extract buildmanifest plist_t buildmanifest = NULL; - info("Extracting BuildManifest from IPSW\n"); - if (ipsw_extract_build_manifest(ipsw, &buildmanifest, &tss_enabled) < 0) { - error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); - return -1; + if (client->flags & FLAG_CUSTOM) { + info("Extracting Restore.plist from IPSW\n"); + if (ipsw_extract_restore_plist(ipsw, &buildmanifest) < 0) { + error("ERROR: Unable to extract Restore.plist from %s\n", ipsw); + return -1; + } + } else { + info("Extracting BuildManifest from IPSW\n"); + if (ipsw_extract_build_manifest(ipsw, &buildmanifest, &tss_enabled) < 0) { + error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); + return -1; + } } /* check if device type is supported by the given build manifest */ @@ -183,7 +191,147 @@ int main(int argc, char* argv[]) { // choose whether this is an upgrade or a restore (default to upgrade) client->tss = NULL; plist_t build_identity = NULL; - if (client->flags & FLAG_ERASE) { + if (client->flags & FLAG_CUSTOM) { + build_identity = plist_new_dict(); + { + plist_t node; + plist_t comp; + plist_t info; + plist_t manifest; + + info = plist_new_dict(); + plist_dict_insert_item(info, "RestoreBehavior", plist_new_string((client->flags & FLAG_ERASE) ? "Erase" : "Update")); + plist_dict_insert_item(info, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer Erase Install (IPSW)" : "Customer Upgrade Install (IPSW)")); + plist_dict_insert_item(build_identity, "Info", info); + + manifest = plist_new_dict(); + + char tmpstr[256]; + char p_all_flash[128]; + char lcmodel[8]; + strcpy(lcmodel, client->device->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(ipsw, tmpstr, &fmanifest, &msize) < 0) { + error("ERROR: could not extract %s from IPSW\n", tmpstr); + 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); + + for (x = 0; x < fc; x++) { + info = plist_new_dict(); + strcpy(tmpstr, p_all_flash); + strcat(tmpstr, "/"); + strcat(tmpstr, files[x]); + plist_dict_insert_item(info, "Path", plist_new_string(tmpstr)); + comp = plist_new_dict(); + plist_dict_insert_item(comp, "Info", info); + const char* compname = get_component_name(files[x]); + if (compname) { + plist_dict_insert_item(manifest, compname, comp); + if (!strncmp(files[x], "DeviceTree", 10)) { + plist_dict_insert_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"); + info = plist_new_dict(); + plist_dict_insert_item(info, "Path", plist_new_string(tmpstr)); + comp = plist_new_dict(); + plist_dict_insert_item(comp, "Info", info); + plist_dict_insert_item(manifest, "iBSS", comp); + + // add iBEC + sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE"); + info = plist_new_dict(); + plist_dict_insert_item(info, "Path", plist_new_string(tmpstr)); + comp = plist_new_dict(); + plist_dict_insert_item(comp, "Info", info); + plist_dict_insert_item(manifest, "iBEC", comp); + + // add kernel cache + node = plist_dict_get_item(buildmanifest, "KernelCachesByTarget"); + if (node && (plist_get_node_type(node) == PLIST_DICT)) { + char tt[4]; + strncpy(tt, lcmodel, 3); + tt[3] = 0; + plist_t kdict = plist_dict_get_item(node, tt); + 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)) { + info = plist_new_dict(); + plist_dict_insert_item(info, "Path", plist_copy(kc)); + comp = plist_new_dict(); + plist_dict_insert_item(comp, "Info", info); + plist_dict_insert_item(manifest, "KernelCache", comp); + plist_dict_insert_item(manifest, "RestoreKernelCache", plist_copy(comp)); + + } + } + } + + // add ramdisk + node = plist_dict_get_item(buildmanifest, "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 (rd && (plist_get_node_type(rd) == PLIST_STRING)) { + info = plist_new_dict(); + plist_dict_insert_item(info, "Path", plist_copy(rd)); + comp = plist_new_dict(); + plist_dict_insert_item(comp, "Info", info); + plist_dict_insert_item(manifest, "RestoreRamDisk", comp); + } + } + + // add OS filesystem + node = plist_dict_get_item(buildmanifest, "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 { + info = plist_new_dict(); + plist_dict_insert_item(info, "Path", plist_copy(os)); + comp = plist_new_dict(); + plist_dict_insert_item(comp, "Info", info); + plist_dict_insert_item(manifest, "OS", comp); + } + + // finally add manifest + plist_dict_insert_item(build_identity, "Manifest", manifest); + } + } else if (client->flags & FLAG_ERASE) { build_identity = build_manifest_get_build_identity(buildmanifest, 0); if (build_identity == NULL) { error("ERROR: Unable to find any build identities\n"); |