summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/dfu.c16
-rw-r--r--src/idevicerestore.c79
-rw-r--r--src/idevicerestore.h4
-rw-r--r--src/img3.c16
-rw-r--r--src/img3.h2
-rw-r--r--src/img4.c140
-rw-r--r--src/img4.h35
-rw-r--r--src/recovery.c31
-rw-r--r--src/restore.c57
10 files changed, 318 insertions, 64 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 680e43f..f0e85c0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,7 +20,7 @@ AM_LDADD = $(AC_LDADD)
bin_PROGRAMS = idevicerestore
-idevicerestore_SOURCES = idevicerestore.c common.c tss.c fls.c mbn.c img3.c ipsw.c normal.c dfu.c recovery.c restore.c asr.c limera1n.c download.c locking.c
+idevicerestore_SOURCES = idevicerestore.c common.c tss.c fls.c mbn.c img3.c img4.c ipsw.c normal.c dfu.c recovery.c restore.c asr.c limera1n.c download.c locking.c
idevicerestore_CFLAGS = $(AM_CFLAGS)
idevicerestore_LDFLAGS = $(AM_LDFLAGS)
idevicerestore_LDADD = $(AM_LDADD)
diff --git a/src/dfu.c b/src/dfu.c
index 5fdbfd5..6050ed0 100644
--- a/src/dfu.c
+++ b/src/dfu.c
@@ -179,11 +179,23 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
}
}
- if (ipsw_get_component_by_path(client->ipsw, client->tss, component, path, &data, &size) < 0) {
- error("ERROR: Unable to get component: %s\n", component);
+ unsigned char* component_data = NULL;
+ unsigned int component_size = 0;
+
+ if (extract_component(client->ipsw, path, &component_data, &component_size) < 0) {
+ error("ERROR: Unable to extract component: %s\n", component);
+ free(path);
+ return -1;
+ }
+
+ if (personalize_component(component, component_data, component_size, client->tss, &data, &size) < 0) {
+ error("ERROR: Unable to get personalized component: %s\n", component);
+ free(component_data);
free(path);
return -1;
}
+ free(component_data);
+ component_data = NULL;
if (!(client->flags & FLAG_CUSTOM) && (strcmp(component, "iBEC") == 0)) {
unsigned char* ticket = NULL;
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index c47e805..6eb25a9 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -34,6 +34,7 @@
#include "dfu.h"
#include "tss.h"
#include "img3.h"
+#include "img4.h"
#include "ipsw.h"
#include "common.h"
#include "normal.h"
@@ -788,9 +789,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
client->mode = &idevicerestore_modes[MODE_RECOVERY];
} else {
if ((client->build_major > 8) && !(client->flags & FLAG_CUSTOM)) {
- /* send ApTicket */
- if (recovery_send_ticket(client) < 0) {
- error("WARNING: Unable to send APTicket\n");
+ if (!client->image4supported) {
+ /* send ApTicket */
+ if (recovery_send_ticket(client) < 0) {
+ error("WARNING: Unable to send APTicket\n");
+ }
}
}
@@ -1520,13 +1523,12 @@ int build_manifest_get_identity_count(plist_t build_manifest) {
return plist_array_get_size(build_identities_array);
}
-int ipsw_get_component_by_path(const char* ipsw, plist_t tss, const char* component, const char* path, unsigned char** data, unsigned int* size) {
- unsigned int component_size = 0;
- unsigned char* component_data = NULL;
- unsigned char* component_blob = NULL;
+int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size)
+{
char* component_name = NULL;
- unsigned char* stitched_component = NULL;
- unsigned int stitched_component_size = 0;
+ if (!ipsw || !path || !component_data || !component_size) {
+ return -1;
+ }
component_name = strrchr(path, '/');
if (component_name != NULL)
@@ -1535,50 +1537,51 @@ int ipsw_get_component_by_path(const char* ipsw, plist_t tss, const char* compon
component_name = (char*) path;
info("Extracting %s...\n", component_name);
-
- if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) {
+ 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;
}
- if (tss) {
- /* try to get blob for current component from tss response */
- if (component) {
- if (tss_response_get_blob_by_entry(tss, component, &component_blob) < 0) {
- debug("NOTE: No SHSH blob found for TSS entry %s from component %s\n", component_name, component);
- }
+ 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) {
+ if (tss_response_get_ap_img4_ticket(tss_response, &component_blob, &component_blob_size) == 0) {
+ /* stitch ApImg4Ticket into IMG4 file */
+ img4_stitch_component(component_name, component_data, component_size, component_blob, component_blob_size, &stitched_component, &stitched_component_size);
} else {
- if (tss_response_get_blob_by_path(tss, path, &component_blob) < 0) {
- debug("NOTE: No SHSH blob found for TSS entry %s from path %s\n", component_name, path);
+ /* try to get blob for current component from tss response */
+ if (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) {
- info("Personalizing component %s...\n", component_name);
-
- if (img3_stitch_component(component_data, component_size, component_blob, 64, &stitched_component, &stitched_component_size) < 0) {
- error("ERROR: Unable to replace IMG3 signature\n");
- free(component_blob);
- return -1;
+ 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);
}
- free(component_data);
- component_data = stitched_component;
- component_size = stitched_component_size;
- } else {
- info("Not personalizing component %s...\n", component_name);
+ if (component_blob)
+ free(component_blob);
}
-
- if (component_blob)
- free(component_blob);
}
if (idevicerestore_debug) {
- write_file(component_name, component_data, component_size);
+ write_file(component_name, stitched_component, stitched_component_size);
}
- *data = component_data;
- *size = component_size;
+ *personalized_component = stitched_component;
+ *personalized_component_size = stitched_component_size;
return 0;
}
diff --git a/src/idevicerestore.h b/src/idevicerestore.h
index 148c78d..b6ca084 100644
--- a/src/idevicerestore.h
+++ b/src/idevicerestore.h
@@ -88,7 +88,9 @@ int build_manifest_get_build_count(plist_t build_manifest);
void build_identity_print_information(plist_t build_identity);
int build_identity_get_component_path(plist_t build_identity, const char* component, char** path);
int ipsw_extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem);
-int ipsw_get_component_by_path(const char* ipsw, plist_t tss, const char* component, const char* path, unsigned char** data, unsigned int* size);
+int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size);
+int personalize_component(const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size);
+
const char* get_component_name(const char* filename);
#ifdef __cplusplus
diff --git a/src/img3.c b/src/img3.c
index ed7646d..1c70df2 100644
--- a/src/img3.c
+++ b/src/img3.c
@@ -402,39 +402,41 @@ static int img3_get_data(img3_file* image, unsigned char** pdata, unsigned int*
return 0;
}
-int img3_stitch_component(const unsigned char* component, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img3_data, unsigned int *img3_size)
+int img3_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img3_data, unsigned int *img3_size)
{
img3_file *img3 = NULL;
unsigned char* outbuf = NULL;
unsigned int outsize = 0;
- if (!component || component_size == 0 || !blob || blob_size == 0 || !img3_data || !img3_size) {
+ if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img3_data || !img3_size) {
return -1;
}
+
+ info("Personalizing IMG3 component %s...\n", component_name);
/* parse current component as img3 */
- img3 = img3_parse_file(component, component_size);
+ img3 = img3_parse_file(component_data, component_size);
if (img3 == NULL) {
- error("ERROR: Unable to parse IMG3 file\n");
+ error("ERROR: Unable to parse %s IMG3 file\n", component_name);
return -1;
}
if (((img3_element_header*)blob)->full_size != blob_size) {
- error("ERROR: the size %d embedded in the blob does not match the passed size of %d\n", ((img3_element_header*)blob)->full_size, blob_size);
+ error("ERROR: Invalid blob passed for %s IMG3: The size %d embedded in the blob does not match the passed size of %d\n", component_name, ((img3_element_header*)blob)->full_size, blob_size, component_name);
img3_free(img3);
return -1;
}
/* personalize the component using the blob */
if (img3_replace_signature(img3, blob) < 0) {
- error("ERROR: Unable to replace IMG3 signature\n");
+ error("ERROR: Unable to replace %s IMG3 signature\n", component_name);
img3_free(img3);
return -1;
}
/* get the img3 file as data */
if (img3_get_data(img3, &outbuf, &outsize) < 0) {
- error("ERROR: Unable to reconstruct IMG3\n");
+ error("ERROR: Unable to reconstruct %s IMG3\n", component_name);
img3_free(img3);
return -1;
}
diff --git a/src/img3.h b/src/img3.h
index d1119a6..4a088b7 100644
--- a/src/img3.h
+++ b/src/img3.h
@@ -95,7 +95,7 @@ typedef struct {
img3_element* unkn_element;*/
} img3_file;
-int img3_stitch_component(const unsigned char* component, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img3_data, unsigned int *img3_size);
+int img3_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img3_data, unsigned int *img3_size);
#ifdef __cplusplus
}s
diff --git a/src/img4.c b/src/img4.c
new file mode 100644
index 0000000..e18b419
--- /dev/null
+++ b/src/img4.c
@@ -0,0 +1,140 @@
+/*
+ * img4.c
+ * Functions for handling the new IMG4 format
+ *
+ * Copyright (c) 2013 Nikias Bassen. 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
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "img4.h"
+
+#define ASN1_CONSTRUCTED 0x20
+#define ASN1_SEQUENCE 0x10
+#define ASN1_CONTEXT_SPECIFIC 0x80
+#define ASN1_IA5_STRING 0x16
+
+#define IMG4_MAGIC "IMG4"
+#define IMG4_MAGIC_SIZE 4
+
+static unsigned char* asn1_create_element_header(unsigned char type, unsigned int size, unsigned char** data, unsigned int *data_size)
+{
+ unsigned char buf[5];
+ unsigned int off = 0;
+
+ if (!type || size == 0 || !data || !data_size) {
+ return NULL;
+ }
+
+ buf[off++] = type;
+
+ // first, calculate the size
+ if (size >= 0x1000000) {
+ // 1+4 bytes length
+ buf[off++] = 0x84;
+ buf[off++] = (size >> 24) & 0xFF;
+ buf[off++] = (size >> 16) & 0xFF;
+ buf[off++] = (size >> 8) & 0xFF;
+ buf[off++] = size & 0xFF;
+ } else if (size >= 0x10000) {
+ // 1+3 bytes length
+ buf[off++] = 0x83;
+ buf[off++] = (size >> 16) & 0xFF;
+ buf[off++] = (size >> 8) & 0xFF;
+ buf[off++] = size & 0xFF;
+ } else if (size >= 0x100) {
+ // 1+2 bytes length
+ buf[off++] = 0x82;
+ buf[off++] = (size >> 8) & 0xFF;
+ buf[off++] = (size & 0xFF);
+ } else if (size >= 0x80) {
+ // 1+1 byte length
+ buf[off++] = 0x81;
+ buf[off++] = (size & 0xFF);
+ } else {
+ // 1 byte length
+ buf[off++] = size & 0xFF;
+ }
+
+ *data = malloc(off);
+ memcpy(*data, buf, off);
+ *data_size = off;
+
+ return *data;
+}
+
+int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size)
+{
+ unsigned char* magic_header = NULL;
+ unsigned int magic_header_size = 0;
+ unsigned char* blob_header = NULL;
+ unsigned int blob_header_size = 0;
+ unsigned char* img4header = NULL;
+ unsigned int img4header_size = 0;
+ unsigned int content_size;
+ unsigned char* outbuf;
+ unsigned char* p;
+
+ if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img4_data || !img4_size) {
+ return -1;
+ }
+
+ /* first we need check if we have to change the tag for the given component */
+ // FIXME: write proper ASN1 handling code for this
+ if (strcmp(component_name, "RestoreKernelCache") == 0) {
+ memcpy((char*)component_data+0xD, "rkrn", 4);
+ } else if (strcmp(component_name, "RestoreDeviceTree") == 0) {
+ memcpy((char*)component_data+0xD, "rdtr", 4);
+ }
+
+ // create element header for the "IMG4" magic
+ asn1_create_element_header(ASN1_IA5_STRING, IMG4_MAGIC_SIZE, &magic_header, &magic_header_size);
+ // create element header for the blob (ApImg4Ticket)
+ asn1_create_element_header(ASN1_CONTEXT_SPECIFIC|ASN1_CONSTRUCTED, blob_size, &blob_header, &blob_header_size);
+
+ // calculate the size for the final IMG4 file (asn1 sequence)
+ content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size;
+
+ // create element header for the final IMG4 asn1 blob
+ asn1_create_element_header(ASN1_SEQUENCE|ASN1_CONSTRUCTED, content_size, &img4header, &img4header_size);
+
+ outbuf = (unsigned char*)malloc(img4header_size + content_size);
+ if (!outbuf) {
+ return -1;
+ }
+ p = outbuf;
+
+ // now put everything together
+ memcpy(p, img4header, img4header_size);
+ p += img4header_size;
+ memcpy(p, magic_header, magic_header_size);
+ p += magic_header_size;
+ memcpy(p, IMG4_MAGIC, IMG4_MAGIC_SIZE);
+ p += IMG4_MAGIC_SIZE;
+ memcpy(p, component_data, component_size);
+ p += component_size;
+ memcpy(p, blob_header, blob_header_size);
+ p += blob_header_size;
+ memcpy(p, blob, blob_size);
+ p += blob_size;
+
+ *img4_data = outbuf;
+ *img4_size = (p - outbuf);
+
+ return 0;
+}
diff --git a/src/img4.h b/src/img4.h
new file mode 100644
index 0000000..97a61aa
--- /dev/null
+++ b/src/img4.h
@@ -0,0 +1,35 @@
+/*
+ * img4.h
+ * Functions for handling the new IMG4 format
+ *
+ * Copyright (c) 2013 Nikias Bassen. 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
+ */
+
+#ifndef IDEVICERESTORE_IMG4_H
+#define IDEVICERESTORE_IMG4_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size);
+
+#ifdef __cplusplus
+}s
+#endif
+
+#endif
diff --git a/src/recovery.c b/src/recovery.c
index 518b0b8..e866531 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -158,10 +158,12 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build
}
if ((client->build_major > 8) && !(client->flags & FLAG_CUSTOM)) {
- /* send ApTicket */
- if (recovery_send_ticket(client) < 0) {
- error("ERROR: Unable to send APTicket\n");
- return -1;
+ if (!client->image4supported) {
+ /* send ApTicket */
+ if (recovery_send_ticket(client) < 0) {
+ error("ERROR: Unable to send APTicket\n");
+ return -1;
+ }
}
}
@@ -280,11 +282,23 @@ int recovery_send_component(struct idevicerestore_client_t* client, plist_t buil
}
}
- if (ipsw_get_component_by_path(client->ipsw, client->tss, component, path, &data, &size) < 0) {
- error("ERROR: Unable to get component: %s\n", component);
+ unsigned char* component_data = NULL;
+ unsigned int component_size = 0;
+
+ if (extract_component(client->ipsw, path, &component_data, &component_size) < 0) {
+ error("ERROR: Unable to extract component: %s\n", component);
+ free(path);
+ return -1;
+ }
+
+ if (personalize_component(component, component_data, component_size, client->tss, &data, &size) < 0) {
+ error("ERROR: Unable to get personalized component: %s\n", component);
+ free(component_data);
free(path);
return -1;
}
+ free(component_data);
+ component_data = NULL;
info("Sending %s (%d bytes)...\n", component, size);
@@ -342,7 +356,7 @@ int recovery_send_applelogo(struct idevicerestore_client_t* client, plist_t buil
return -1;
}
- recovery_error = irecv_send_command(client->recovery->client, "setpicture 0");
+ recovery_error = irecv_send_command(client->recovery->client, "setpicture 2");
if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to set %s\n", component);
return -1;
@@ -391,6 +405,9 @@ int recovery_send_ramdisk(struct idevicerestore_client_t* client, plist_t build_
}
}
+ irecv_send_command(client->recovery->client, "getenv ramdisk-size");
+ irecv_receive(client->recovery->client);
+
if (recovery_send_component(client, build_identity, component) < 0) {
error("ERROR: Unable to send %s to device.\n", component);
return -1;
diff --git a/src/restore.c b/src/restore.c
index 845a670..ed3006b 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -787,11 +787,25 @@ int restore_send_kernelcache(restored_client_t restore, struct idevicerestore_cl
}
}
- if (ipsw_get_component_by_path(client->ipsw, client->tss, "KernelCache", path, &data, &size) < 0) {
- error("ERROR: Unable to get kernelcache file\n");
+ const char* component = "KernelCache";
+ unsigned char* component_data = NULL;
+ unsigned int component_size = 0;
+
+ if (extract_component(client->ipsw, path, &component_data, &component_size) < 0) {
+ error("ERROR: Unable to extract component: %s\n", component);
+ free(path);
return -1;
}
+ if (personalize_component(component, component_data, component_size, client->tss, &data, &size) < 0) {
+ error("ERROR: Unable to get personalized component: %s\n", component);
+ free(component_data);
+ free(path);
+ return -1;
+ }
+ free(component_data);
+ component_data = NULL;
+
dict = plist_new_dict();
blob = plist_new_data((char*)data, size);
plist_dict_insert_item(dict, "KernelCacheFile", blob);
@@ -864,11 +878,25 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
return -1;
}
- if (ipsw_get_component_by_path(client->ipsw, client->tss, "LLB", llb_path, &llb_data, &llb_size) < 0) {
- error("ERROR: Unable to get personalized LLB\n");
+ const char* component = "LLB";
+ unsigned char* component_data = NULL;
+ unsigned int component_size = 0;
+
+ if (extract_component(client->ipsw, llb_path, &component_data, &component_size) < 0) {
+ error("ERROR: Unable to extract component: %s\n", component);
+ free(llb_path);
return -1;
}
+ if (personalize_component(component, component_data, component_size, client->tss, &llb_data, &llb_size) < 0) {
+ error("ERROR: Unable to get personalized component: %s\n", component);
+ free(component_data);
+ free(llb_path);
+ return -1;
+ }
+ free(component_data);
+ component_data = NULL;
+
dict = plist_new_dict();
plist_dict_insert_item(dict, "LlbImageData", plist_new_data((char*)llb_data, (uint64_t) llb_size));
@@ -883,10 +911,25 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
}
memset(firmware_filename, '\0', sizeof(firmware_filename));
snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
- if (ipsw_get_component_by_path(client->ipsw, client->tss, get_component_name(filename), firmware_filename, &nor_data, &nor_size) < 0) {
- error("ERROR: Unable to get personalized firmware file %s\n", firmware_filename);
- break;
+
+ component = get_component_name(filename);
+ component_data = NULL;
+ unsigned int component_size = 0;
+
+ if (extract_component(client->ipsw, firmware_filename, &component_data, &component_size) < 0) {
+ error("ERROR: Unable to extract component: %s\n", component);
+ free(llb_path);
+ return -1;
+ }
+
+ if (personalize_component(component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) {
+ error("ERROR: Unable to get personalized component: %s\n", component);
+ free(component_data);
+ free(llb_path);
+ return -1;
}
+ free(component_data);
+ component_data = NULL;
plist_array_append_item(norimage_array, plist_new_data((char*)nor_data, (uint64_t)nor_size));
free(nor_data);