diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/fls.c | 339 | ||||
| -rw-r--r-- | src/fls.h | 85 | ||||
| -rw-r--r-- | src/restore.c | 529 | 
4 files changed, 954 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 4d498a0..15d2552 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 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 img3.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/fls.c b/src/fls.c new file mode 100644 index 0000000..0970a8e --- /dev/null +++ b/src/fls.c @@ -0,0 +1,339 @@ +/* + * fls.c + * support for .fls file format (found in .bbfw files) + * + * Copyright (c) 2012 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "fls.h" +#include "common.h" + +#ifndef offsetof +#define offsetof(type, member)  __builtin_offsetof (type, member) +#endif + +static void fls_parse_elements(fls_file* fls) +{ +	/* FIXME: the following code is not big endian safe */ +	if (!fls || !fls->data) { +		return; +	} +	uint32_t offset = 0; +	uint32_t max = fls->size; +	fls->max_elements = 32; +	fls->elements = (fls_element**)malloc(sizeof(fls_element*) * fls->max_elements); + +	fls_element* cur = NULL; +	do { +		void* p = fls->data + offset; +		uint32_t hdrsize = 0; +		cur = (fls_element*)p; +		if ((offset + cur->size) > fls->size) { +			break; +		} +		fls_element* ne; +		switch (cur->type) { +		case 0x0c: +			{ +			hdrsize = offsetof(fls_0c_element, data); +			fls_0c_element* xe = (fls_0c_element*)malloc(sizeof(fls_0c_element)); +			memset(xe, '\0', sizeof(fls_0c_element)); +			memcpy((void*)xe, p, hdrsize); +			xe->data = (xe->size > hdrsize) ? xe->data = p + hdrsize : NULL; +			ne = (fls_element*)xe; +			fls->c_element = xe; +			} +			break; +		case 0x10: +			{ +			hdrsize = offsetof(fls_10_element, data); +			fls_10_element* xe = (fls_10_element*)malloc(sizeof(fls_10_element)); +			memset(xe, '\0', sizeof(fls_10_element)); +			memcpy((void*)xe, p, hdrsize); +			xe->data = (xe->size > hdrsize) ? xe->data = p + hdrsize : NULL; +			ne = (fls_element*)xe; +			} +			break; +		case 0x14: +			{ +			hdrsize = offsetof(fls_14_element, data); +			fls_14_element* xe = (fls_14_element*)malloc(sizeof(fls_14_element)); +			memset(xe, '\0', sizeof(fls_14_element)); +			memcpy((void*)xe, p, hdrsize); +			xe->data = (xe->size > hdrsize) ? xe->data = p + hdrsize : NULL; +			ne = (fls_element*)xe; +			} +			break; +		default: +			hdrsize = offsetof(fls_element, data); +			ne = (fls_element*)malloc(sizeof(fls_element)); +			memset(ne, '\0', sizeof(fls_element)); +			ne->type = cur->type; +			ne->size = cur->size; +			ne->data = (ne->size > hdrsize) ? ne->data = p + hdrsize : NULL; +			break; +		} +		if ((fls->num_elements + 1) > fls->max_elements) { +			fls->max_elements += 10; +			fls->elements = (fls_element**)realloc(fls->elements, sizeof(fls_element*) * fls->max_elements); +		} +		fls->elements[fls->num_elements++] = ne; +		offset += cur->size; +	} while (offset < fls->size); +	if (offset != fls->size) { +		error("ERROR: %s: error parsing elements\n", __func__); +		return; +	} +} + +fls_file* fls_parse(unsigned char* data, unsigned int size) +{ +	fls_file* fls = (fls_file*)malloc(sizeof(fls_file)); +	if (!fls) { +		return NULL; +	} +	memset(fls, '\0', sizeof(fls_file)); +	fls->data = malloc(size); +	fls->size = size; +	memcpy(fls->data, data, size); +	fls_parse_elements(fls); +	return fls; +} + +void fls_free(fls_file* fls) +{ +	if (fls) { +		if (fls->num_elements > 0) { +			int i; +			for (i = fls->num_elements-1; i >=0; i--) { +				free(fls->elements[i]); +			} +			free(fls->elements); +		} +		if (fls->data) { +			free(fls->data); +		} +		free(fls); +	} +} + +int fls_update_sig_blob(fls_file* fls, const unsigned char* sigdata, unsigned int siglen) +{ +	/* FIXME: the code in this function is not big endian safe */ +	if (!fls || !fls->num_elements) { +		error("ERROR: %s: no data\n", __func__); +		return -1; +	} +	if (!fls->c_element) { +		error("ERROR: %s: no fls_0c_element in fls data\n", __func__); +		return -1; +	} + +	uint32_t datasize = *(uint32_t*)(fls->c_element->data + 0x10); +	if (datasize != fls->c_element->data_size) { +		error("ERROR: %s: data size mismatch (0x%x != 0x%x)\n", __func__, datasize, fls->c_element->data_size); +		return -1; +	} +	uint32_t sigoffset = *(uint32_t*)(fls->c_element->data + 0x14); +	if (sigoffset > datasize) { +		error("ERROR: %s: signature offset greater than data size (0x%x > 0x%x)\n", __func__, sigoffset, datasize); +		return -1; +	} + +	uint32_t oldsiglen = datasize - sigoffset; +	uint32_t newsize = fls->size - oldsiglen + siglen; + +	int i; +	uint32_t offset = 0; +	void* newdata = malloc(newsize); +	if (!newdata) { +		error("ERROR: %s: out of memory\n", __func__); +		return -1; +	} +	uint32_t hdrsize = 0; +	uint32_t firstpartlen = 0; +	for (i = 0; i < fls->num_elements; i++) { +		switch (fls->elements[i]->type) { +		case 0x0c: +			hdrsize = offsetof(fls_0c_element, data); +			// update offset +			((fls_0c_element*)fls->elements[i])->offset = offset+hdrsize; +			// copy first part of data +			firstpartlen = fls->elements[i]->size - hdrsize - oldsiglen; +			memcpy(newdata+offset+hdrsize, ((fls_0c_element*)fls->elements[i])->data, firstpartlen); +			// copy new signature data +			memcpy(newdata+offset+hdrsize+firstpartlen, sigdata, siglen); +			((fls_0c_element*)fls->elements[i])->data = newdata+offset+hdrsize; +			fls->elements[i]->size -= oldsiglen; +			fls->elements[i]->size += siglen; +			((fls_0c_element*)fls->elements[i])->data_size -= oldsiglen; +			((fls_0c_element*)fls->elements[i])->data_size += siglen; +			memcpy(newdata+offset+hdrsize+0x10, &(((fls_0c_element*)fls->elements[i])->data_size), 4); +			// copy header +			memcpy(newdata+offset, fls->elements[i], hdrsize); +			break; +		case 0x10: +			hdrsize = offsetof(fls_10_element, data); +			// update offset +			((fls_10_element*)fls->elements[i])->offset = offset+hdrsize; +			// copy header +			memcpy(newdata+offset, fls->elements[i], hdrsize); +			// copy data +			if (fls->elements[i]->size > hdrsize) { +				memcpy(newdata+offset+hdrsize, ((fls_10_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize); +				((fls_10_element*)fls->elements[i])->data = newdata+offset+hdrsize; +			} else { +				((fls_10_element*)fls->elements[i])->data = NULL; +			} +			break; +		case 0x14: +			hdrsize = offsetof(fls_14_element, data); +			// update offset +			((fls_14_element*)fls->elements[i])->offset = offset+hdrsize; +			// copy header +			memcpy(newdata+offset, fls->elements[i], hdrsize); +			// copy data +			if (fls->elements[i]->size > hdrsize) { +				memcpy(newdata+offset+hdrsize, ((fls_14_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize); +				((fls_14_element*)fls->elements[i])->data = newdata+offset+hdrsize; +			} else { +				((fls_14_element*)fls->elements[i])->data = NULL; +			} +			break; +		default: +			hdrsize = offsetof(fls_element, data); +			// copy header +			memcpy(newdata+offset, fls->elements[i], hdrsize); +			// copy data +			if (fls->elements[i]->size > hdrsize) { +				memcpy(newdata+offset+hdrsize, fls->elements[i]->data, fls->elements[i]->size - hdrsize); +				fls->elements[i]->data = newdata+offset+hdrsize; +			} else { +				fls->elements[i]->data = NULL; +			} +			break; +		} +		offset += fls->elements[i]->size; +	} +	if (fls->data) { +		free(fls->data); +	} +	fls->data = newdata; +	fls->size = newsize; + +	return 0; +} + +int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size) +{ +	/* FIXME: the code in this function is not big endian safe */ +	if (!fls || !fls->num_elements) { +		error("ERROR: %s: no data\n", __func__); +		return -1; +	} +	if (!fls->c_element) { +		error("ERROR: %s: no fls_0c_element in fls data\n", __func__); +		return -1; +	} + +	uint32_t padding = 0; +	if (size%4 != 0) { +		padding = 4-(size%4); +	} +	uint32_t newsize = fls->size + size + padding; +	int i; +	uint32_t offset = 0; +	void* newdata = malloc(newsize); +	if (!newdata) { +		error("ERROR: %s: out of memory\n", __func__); +		return -1; +	} +	uint32_t hdrsize = 0; +	for (i = 0; i < fls->num_elements; i++) { +		switch (fls->elements[i]->type) { +		case 0x0c: +			hdrsize = offsetof(fls_0c_element, data); +			// update offset +			((fls_0c_element*)fls->elements[i])->offset = offset+hdrsize; +			// copy ticket data +			memcpy(newdata+offset+hdrsize, data, size); +			if (padding > 0) { +				// padding +				memset(newdata+offset+hdrsize+size, '\xFF', padding); +			} +			// copy remaining data +			memcpy(newdata+offset+hdrsize+size+padding, ((fls_0c_element*)fls->elements[i])->data, fls->elements[i]->size); +			((fls_0c_element*)fls->elements[i])->data = newdata+offset+hdrsize; +			fls->elements[i]->size += (size + padding); +			((fls_0c_element*)fls->elements[i])->data_size += (size + padding); +			// copy header +			memcpy(newdata+offset, fls->elements[i], hdrsize); +			break; +		case 0x10: +			hdrsize = offsetof(fls_10_element, data); +			// update offset +			((fls_10_element*)fls->elements[i])->offset = offset+hdrsize; +			// copy header +			memcpy(newdata+offset, fls->elements[i], hdrsize); +			// copy data +			if (fls->elements[i]->size > hdrsize) { +				memcpy(newdata+offset+hdrsize, ((fls_10_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize); +				((fls_10_element*)fls->elements[i])->data = newdata+offset+hdrsize; +			} else { +				((fls_10_element*)fls->elements[i])->data = NULL; +			} +			break; +		case 0x14: +			hdrsize = offsetof(fls_14_element, data); +			// update offset +			((fls_14_element*)fls->elements[i])->offset = offset+hdrsize; +			// copy header +			memcpy(newdata+offset, fls->elements[i], hdrsize); +			// copy data +			if (fls->elements[i]->size > hdrsize) { +				memcpy(newdata+offset+hdrsize, ((fls_14_element*)fls->elements[i])->data, fls->elements[i]->size - hdrsize); +				((fls_14_element*)fls->elements[i])->data = newdata+offset+hdrsize; +			} else { +				((fls_14_element*)fls->elements[i])->data = NULL; +			} +			break; +		default: +			hdrsize = offsetof(fls_element, data); +			// copy header +			memcpy(newdata+offset, fls->elements[i], hdrsize); +			// copy data +			if (fls->elements[i]->size > hdrsize) { +				memcpy(newdata+offset+hdrsize, fls->elements[i]->data, fls->elements[i]->size - hdrsize); +				fls->elements[i]->data = newdata+offset+hdrsize; +			} else { +				fls->elements[i]->data = NULL; +			} +			break; +		} +		offset += fls->elements[i]->size; +	} +	if (fls->data) { +		free(fls->data); +	} +	fls->data = newdata; +	fls->size = newsize; + +	return 0; +} + diff --git a/src/fls.h b/src/fls.h new file mode 100644 index 0000000..57b3869 --- /dev/null +++ b/src/fls.h @@ -0,0 +1,85 @@ +/* + * fls.h + * support for .fls file format (found in .bbfw files) + * + * Copyright (c) 2012 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 FLS_H +#define FLS_H + +#include <stdint.h> + +struct _fls_element { +	uint32_t type; +	uint32_t size; +	uint32_t empty; +	const unsigned char* data; +} __attribute__((packed)); +typedef struct _fls_element fls_element; + +struct _fls_0c_element { +	uint32_t type; +	uint32_t size; +	uint32_t empty; +	uint32_t off_0x0c; +	uint32_t off_0x10; +	uint32_t off_0x14; +	uint32_t off_0x18; +	uint32_t data_size; // size without header +	uint32_t off_0x20; +	uint32_t offset; // absolute offset of data in file +	const unsigned char* data; // data+0x14 contains offset to sig blob +} __attribute__((packed)); +typedef struct _fls_0c_element fls_0c_element; + +struct _fls_10_element { +	uint32_t type; +	uint32_t size; +	uint32_t empty; +	uint32_t data_size; // size without header +	uint32_t off_0x10; +	uint32_t offset; +	const unsigned char* data; +} __attribute__((packed)); +typedef struct _fls_10_element fls_10_element; + +struct _fls_14_element { +	uint32_t type; +	uint32_t size; +	uint32_t empty; +	uint32_t data_size; // size without header +	uint32_t off_0x10; +	uint32_t offset; +	const unsigned char* data; +} __attribute__((packed)); +typedef struct _fls_14_element fls_14_element; + +typedef struct { +	unsigned int num_elements; +	unsigned int max_elements; +	fls_element** elements; +	const fls_0c_element* c_element; +	void* data; +	uint32_t size; +} fls_file; + +fls_file* fls_parse(unsigned char* data, unsigned int size); +void fls_free(fls_file* fls); +int fls_update_sig_blob(fls_file* fls, const unsigned char* data, unsigned int size); +int fls_insert_ticket(fls_file* fls, const unsigned char* data, unsigned int size); + +#endif diff --git a/src/restore.c b/src/restore.c index e96fed9..5da614f 100644 --- a/src/restore.c +++ b/src/restore.c @@ -23,8 +23,10 @@  #include <stdlib.h>  #include <string.h>  #include <libimobiledevice/restore.h> +#include <zip.h>  #include "asr.h" +#include "fls.h"  #include "tss.h"  #include "common.h"  #include "restore.h" @@ -510,6 +512,35 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) {  	return result;  } +int restore_handle_bb_update_status_msg(restored_client_t client, plist_t msg) +{ +	int result = -1; +	plist_t node = plist_dict_get_item(msg, "Accepted"); +	uint8_t accepted = 0; +	plist_get_bool_val(node, &accepted); +	debug_plist(msg); + +	if (!accepted) { +		error("ERROR: device didn't accept BasebandData\n"); +		return result; +	} + +	uint8_t done = 0; +	node = plist_access_path(msg, 2, "Output", "done"); +	if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { +		plist_get_bool_val(node, &done); +	} + +	if (done) { +		info("Updating Baseband completed.\n"); +	} else { +		info("Updating Baseband in progress...\n"); +	} +	result = 0; + +	return result; +} +  int restore_send_filesystem(idevice_t device, const char* filesystem) {  	int i = 0;  	FILE* file = NULL; @@ -737,6 +768,492 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*  	return 0;  } +int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +{ +	int res = -1; +	uint64_t bb_cert_id = 0; +	unsigned char* bb_snum = NULL; +	uint64_t bb_snum_size = 0; +	unsigned char* bb_nonce = NULL; +	uint64_t bb_nonce_size = 0; + +	// setup request data +	plist_t arguments = plist_dict_get_item(message, "Arguments"); +	if (arguments && plist_get_node_type(arguments) == PLIST_DICT) { +		plist_t bb_cert_id_node = plist_dict_get_item(arguments, "CertID"); +		if (bb_cert_id_node && plist_get_node_type(bb_cert_id_node) == PLIST_UINT) { +			plist_get_uint_val(bb_cert_id_node, &bb_cert_id); +		} +		plist_t bb_snum_node = plist_dict_get_item(arguments, "ChipSerialNo"); +		if (bb_snum_node && plist_get_node_type(bb_snum_node) == PLIST_DATA) { +			plist_get_data_val(bb_snum_node, (char**)&bb_snum, &bb_snum_size); +		} +		plist_t bb_nonce_node = plist_dict_get_item(arguments, "Nonce"); +		if (bb_nonce_node && plist_get_node_type(bb_nonce_node) == PLIST_DATA) { +			plist_get_data_val(bb_nonce_node, (char**)&bb_nonce, &bb_nonce_size); +		} +	} + +	// create Baseband TSS request +	plist_t request = tss_create_baseband_request(build_identity, client->ecid, bb_cert_id, bb_snum, bb_snum_size, bb_nonce, bb_nonce_size); +	if (request == NULL) { +		error("ERROR: Unable to create Baseand TSS request\n"); +		return -1; +	} + +	// send Baseband TSS request +	debug_plist(request); +	info("Sending Baseband TSS request... "); +	plist_t response = tss_send_request(request); +	plist_free(request); +	if (response == NULL) { +		error("ERROR: Unable to fetch Baseband TSS\n"); +		return -1; +	} +	debug_plist(response); + +	// check for BBTicket in result +	plist_t bbticket = plist_dict_get_item(response, "BBTicket"); +	if (!bbticket || plist_get_node_type(bbticket) != PLIST_DATA) { +		error("ERROR: Could not find BBTicket in Baseband TSS response\n"); +		free(response); +		return -1; +	} + +	// check for RamPSI-Blob in result +	plist_t rampsi = plist_access_path(response, 2, "BasebandFirmware", "RamPSI-Blob"); +	if (!rampsi || plist_get_node_type(rampsi) != PLIST_DATA) { +		error("ERROR: Could not find RamPSI-Blob in Baseband TSS response\n"); +		free(response); +		return -1; +	} + +	// check for FlashPSI-Blob in result +	plist_t flashpsi = plist_access_path(response, 2, "BasebandFirmware", "FlashPSI-Blob"); +	if (!flashpsi || plist_get_node_type(flashpsi) != PLIST_DATA) { +		error("ERROR: Could not find FlashPSI-Blob in Baseband TSS response\n"); +		free(response); +		return -1; +	} + +	// get baseband firmware file path from build identity +	plist_t bbfw_path = plist_access_path(build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path"); +	if (!bbfw_path || plist_get_node_type(bbfw_path) != PLIST_STRING) { +		error("ERROR: Unable to get BasebandFirmware/Info/Path node\n"); +		free(response); +		return -1; +	} +	char* bbfwpath = NULL; +	plist_get_string_val(bbfw_path, &bbfwpath);	 +	if (!bbfwpath) { +		error("ERROR: Unable to get baseband path\n"); +		free(response); +		return -1; +	} + +	// extract baseband firmware to temp file +	char* bbfwtmp = tempnam(NULL, "bbfw_"); +	if (!bbfwtmp) { +		error("WARNING: Could not generate temporary filename, using bbfw.tmp\n"); +		bbfwtmp = strdup("bbfw.tmp"); +	} +	if (ipsw_extract_to_file(client->ipsw, bbfwpath, bbfwtmp) != 0) { +		error("ERROR: Unable to extract baseband firmware from ipsw\n"); +		free(response); +		return -1; +	} + +	unsigned char* buffer = NULL; +	unsigned char* blob = NULL; +	unsigned char* flsdata = NULL; +	off_t flssize = 0; +	uint64_t blob_size = 0; +	int zerr = 0; +	int zindex = -1; +	int size = 0; +	struct zip_stat zstat; +	struct zip_file* zfile = NULL; +	struct zip* za = NULL; +	struct zip_source* zs = NULL; +	fls_file* fls = NULL; + +	za = zip_open(bbfwtmp, 0, &zerr); +	if (!za) { +		error("ERROR: Could not open ZIP archive '%s': %d\n", bbfwtmp, zerr); +		goto leave; +	} + +	if (!bb_nonce) { +		// just sign psi_ram.fls +		zindex = zip_name_locate(za, "psi_ram.fls", 0); +		if (zindex < 0) { +			error("ERROR: can't locate 'psi_ram.fls' in '%s'\n", bbfwtmp); +			goto leave; +		} + +		zip_stat_init(&zstat); +		if (zip_stat_index(za, zindex, 0, &zstat) != 0) { +			error("ERROR: zip_stat_index failed for index %d\n", zindex); +			goto leave; +		} + +		zfile = zip_fopen_index(za, zindex, 0); +		if (zfile == NULL) { +			error("ERROR: zip_fopen_index failed for index %d\n", zindex); +			goto leave; +		} + +		size = zstat.size; +		buffer = (unsigned char*) malloc(size+1); +		if (buffer == NULL) { +			error("ERROR: Out of memory\n"); +			goto leave; +		} + +		if (zip_fread(zfile, buffer, size) != size) { +			error("ERROR: zip_fread: failed\n"); +			goto leave; +		} +		buffer[size] = '\0'; + +		zip_fclose(zfile); +		zfile = NULL; + +		fls = fls_parse(buffer, size); +		free(buffer); +		buffer = NULL; +		if (!fls) { +			error("ERROR: could not parse fls file\n"); +			goto leave; +		} + +		blob = NULL; +		blob_size = 0; +		plist_get_data_val(rampsi, (char**)&blob, &blob_size); +		if (!blob) { +			error("ERROR: could not get RamPSI-Blob data\n"); +			goto leave; +		} + +		if (fls_update_sig_blob(fls, blob, (unsigned int)blob_size) != 0) { +			error("ERROR: could not sign psi_ram.fls\n"); +			goto leave; +		} +		free(blob); +		blob = NULL; + +		// remove all files from zip +		int i; +		int numf = zip_get_num_files(za); +		for (i = 0; i < numf; i++) { +			zip_delete(za, i); +		} + +		flssize = fls->size; +		flsdata = (unsigned char*)malloc(flssize); +		memcpy(flsdata, fls->data, flssize); +		fls_free(fls); +		fls = NULL; + +		zs = zip_source_buffer(za, flsdata, flssize, 1); +		if (!zs) { +			error("ERROR: out of memory\n"); +			goto leave; +		} + +		if (zip_add(za, "psi_ram.fls", zs) == -1) { +			error("ERROR: could not add signed psi_ram.fls to archive\n"); +			goto leave; +		} +	} else { +		// sign psi_ram.fls +		zindex = zip_name_locate(za, "psi_ram.fls", 0); +		if (zindex < 0) { +			error("ERROR: can't locate 'psi_ram.fls' in '%s'\n", bbfwtmp); +			goto leave; +		} + +		zip_stat_init(&zstat); +		if (zip_stat_index(za, zindex, 0, &zstat) != 0) { +			error("ERROR: zip_stat_index failed for index %d\n", zindex); +			goto leave; +		} + +		zfile = zip_fopen_index(za, zindex, 0); +		if (zfile == NULL) { +			error("ERROR: zip_fopen_index failed for index %d\n", zindex); +			goto leave; +		} + +		size = zstat.size; +		buffer = (unsigned char*) malloc(size+1); +		if (buffer == NULL) { +			error("ERROR: Out of memory\n"); +			goto leave; +		} + +		if (zip_fread(zfile, buffer, size) != size) { +			error("ERROR: zip_fread: failed\n"); +			goto leave; +		} +		buffer[size] = '\0'; + +		zip_fclose(zfile); +		zfile = NULL; + +		fls = fls_parse(buffer, size); +		free(buffer); +		buffer = NULL; +		if (!fls) { +			error("ERROR: could not parse fls file\n"); +			goto leave; +		} + +		blob = NULL; +		blob_size = 0; +		plist_get_data_val(rampsi, (char**)&blob, &blob_size); +		if (!blob) { +			error("ERROR: could not get RamPSI-Blob data\n"); +			goto leave; +		} + +		if (fls_update_sig_blob(fls, blob, (unsigned int)blob_size) != 0) { +			error("ERROR: could not sign psi_ram.fls\n"); +			goto leave; +		} +		free(blob); +		blob = NULL; + +		flssize = fls->size; +		flsdata = (unsigned char*)malloc(flssize); +		memcpy(flsdata, fls->data, flssize); +		fls_free(fls); +		fls = NULL; + +		zs = zip_source_buffer(za, flsdata, flssize, 1); +		if (!zs) { +			error("ERROR: out of memory\n"); +			goto leave; +		} + +		if (zip_replace(za, zindex, zs) == -1) { +			error("ERROR: could not add signed psi_ram.fls to archive\n"); +			goto leave; +		} + +		// sign psi_flash.fls +		zindex = zip_name_locate(za, "psi_flash.fls", 0); +		if (zindex < 0) { +			error("ERROR: can't locate 'psi_flash.fls' in '%s'\n", bbfwtmp); +			goto leave; +		} + +		zip_stat_init(&zstat); +		if (zip_stat_index(za, zindex, 0, &zstat) != 0) { +			error("ERROR: zip_stat_index failed for index %d\n", zindex); +			goto leave; +		} + +		zfile = zip_fopen_index(za, zindex, 0); +		if (zfile == NULL) { +			error("ERROR: zip_fopen_index failed for index %d\n", zindex); +			goto leave; +		} + +		size = zstat.size; +		buffer = (unsigned char*) malloc(size+1); +		if (buffer == NULL) { +			error("ERROR: Out of memory\n"); +			goto leave; +		} + +		if (zip_fread(zfile, buffer, size) != size) { +			error("ERROR: zip_fread: failed\n"); +			goto leave; +		} +		buffer[size] = '\0'; + +		zip_fclose(zfile); +		zfile = NULL; + +		fls = fls_parse(buffer, size); +		free(buffer); +		buffer = NULL; +		if (!fls) { +			error("ERROR: could not parse fls file\n"); +			goto leave; +		} + +		blob = NULL; +		blob_size = 0; +		plist_get_data_val(flashpsi, (char**)&blob, &blob_size); +		if (!blob) { +			error("ERROR: could not get FlashPSI-Blob data\n"); +			goto leave; +		} + +		if (fls_update_sig_blob(fls, blob, (unsigned int)blob_size) != 0) { +			error("ERROR: could not sign psi_flash.fls\n"); +			goto leave; +		} +		free(blob); +		blob = NULL; + +		flssize = fls->size; +		flsdata = (unsigned char*)malloc(flssize); +		memcpy(flsdata, fls->data, flssize); +		fls_free(fls); +		fls = NULL; + +		zs = zip_source_buffer(za, flsdata, flssize, 1); +		if (!zs) { +			error("ERROR: out of memory\n"); +			goto leave; +		} + +		if (zip_replace(za, zindex, zs) == -1) { +			error("ERROR: could not add signed psi_flash.fls to archive\n"); +			goto leave; +		} + +		// add ticket to ebl.fls +		zindex = zip_name_locate(za, "ebl.fls", 0); +		if (zindex < 0) { +			error("ERROR: can't locate 'ebl.fls' in '%s'\n", bbfwtmp); +			goto leave; +		} + +		zip_stat_init(&zstat); +		if (zip_stat_index(za, zindex, 0, &zstat) != 0) { +			error("ERROR: zip_stat_index failed for index %d\n", zindex); +			goto leave; +		} + +		zfile = zip_fopen_index(za, zindex, 0); +		if (zfile == NULL) { +			error("ERROR: zip_fopen_index failed for index %d\n", zindex); +			goto leave; +		} + +		size = zstat.size; +		buffer = (unsigned char*) malloc(size+1); +		if (buffer == NULL) { +			error("ERROR: Out of memory\n"); +			goto leave; +		} + +		if (zip_fread(zfile, buffer, size) != size) { +			error("ERROR: zip_fread: failed\n"); +			goto leave; +		} +		buffer[size] = '\0'; + +		zip_fclose(zfile); +		zfile = NULL; + +		fls = fls_parse(buffer, size); +		free(buffer); +		buffer = NULL; +		if (!fls) { +			error("ERROR: could not parse fls file\n"); +			goto leave; +		} + +		blob = NULL; +		blob_size = 0; +		plist_get_data_val(bbticket, (char**)&blob, &blob_size); +		if (!blob) { +			error("ERROR: could not get BBTicket data\n"); +			goto leave; +		} + +		if (fls_insert_ticket(fls, blob, (unsigned int)blob_size) != 0) { +			error("ERROR: could not insert BBTicket to ebl.fls\n"); +			goto leave; +		} +		free(blob); +		blob = NULL; + +		flssize = fls->size; +		flsdata = (unsigned char*)malloc(flssize); +		memcpy(flsdata, fls->data, flssize); +		fls_free(fls); +		fls = NULL; + +		zs = zip_source_buffer(za, flsdata, flssize, 1); +		if (!zs) { +			error("ERROR: out of memory\n"); +			goto leave; +		} + +		if (zip_replace(za, zindex, zs) == -1) { +			error("ERROR: could not add ticketed ebl.fls to archive\n"); +			goto leave; +		} +	} + +	// this will write out the modified zip +	zip_close(za); +	za = NULL; +	zs = NULL; + +	buffer = NULL; +	size_t sz = 0; +	if (read_file(bbfwtmp, (void**)&buffer, &sz) < 0) { +		error("ERROR: could not read updated bbfw archive\n"); +		goto leave; +	} + +	// send file +	plist_t dict = plist_new_dict(); +	plist_dict_insert_item(dict, "BasebandData", plist_new_data(buffer, (uint64_t)sz)); +	free(buffer); +	buffer = NULL; + +	if (restored_send(restore, dict) != RESTORE_E_SUCCESS) { +		error("ERROR: Unable to send BasebandData data\n"); +		goto leave; +	} + +	plist_free(dict); +	dict = NULL; + +	res = 0; + +leave: +	if (dict) { +		plist_free(dict); +	} +	if (fls) { +		fls_free(fls); +	} +	if (zfile) { +		zip_fclose(zfile); +	} +	if (zs) { +		zip_source_free(zs); +	} +	if (za) { +		zip_unchange_all(za); +		zip_close(za); +	} +	if (buffer) { +		free(buffer); +	} +	if (blob) { +		free(blob); +	} +	if (bbfwtmp) { +		remove(bbfwtmp); +		free(bbfwtmp); +	} +	if (response) { +		free(response); +	} + +	return res; +} +  int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem) {  	char* type = NULL;  	plist_t node = NULL; @@ -781,6 +1298,13 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev  				info("Not sending NORData... Quitting...\n");  				client->flags |= FLAG_QUIT;  			} +		} + +		else if (!strcmp(type, "BasebandData")) { +			if(restore_send_baseband_data(restore, client, build_identity, message) < 0) { +				error("ERROR: Unable to send baseband data\n"); +				return -1; +			}  		} else {  			// Unknown DataType!! @@ -929,6 +1453,11 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit  			}  		} +		// baseband update message +		else if (!strcmp(type, "BBUpdateStatusMsg")) { +			error = restore_handle_bb_update_status_msg(restore, message); +		} +  		// there might be some other message types i'm not aware of, but I think  		// at least the "previous error logs" messages usually end up here  		else {  | 
