diff options
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/dfu.c | 16 | ||||
| -rw-r--r-- | src/idevicerestore.c | 79 | ||||
| -rw-r--r-- | src/idevicerestore.h | 4 | ||||
| -rw-r--r-- | src/img3.c | 16 | ||||
| -rw-r--r-- | src/img3.h | 2 | ||||
| -rw-r--r-- | src/img4.c | 140 | ||||
| -rw-r--r-- | src/img4.h | 35 | ||||
| -rw-r--r-- | src/recovery.c | 31 | ||||
| -rw-r--r-- | src/restore.c | 57 | 
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) @@ -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 @@ -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;  	} @@ -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);  | 
