diff options
Diffstat (limited to 'src/fls.c')
-rw-r--r-- | src/fls.c | 339 |
1 files changed, 339 insertions, 0 deletions
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; +} + |