diff options
-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 { |