| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * |
| * Copyright (C) 2013 Lorenzo Miori |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <getopt.h> |
| #include <stdint.h> |
| #include "common.h" |
| |
| static char* input_dir = NULL; |
| static FILE* output_file = NULL; |
| static struct firmware_data fw; |
| |
| static void cleanup(void) |
| { |
| for (int i = 0; i < YPR0_COMPONENTS_COUNT; i++) |
| { |
| free(fw.component_data[i]); |
| } |
| } |
| |
| static void die(int error) |
| { |
| if (output_file != NULL) |
| fclose(output_file); |
| free(input_dir); |
| cleanup(); |
| exit(error); |
| } |
| |
| static void pad4byte(char byte, FILE* handle) { |
| int padding = 4 - ftell(handle) % 4; |
| if (padding != 4) { |
| while (padding-- > 0) { |
| fwrite(&byte, 1, 1, handle); |
| } |
| } |
| } |
| |
| int main(int argc, char **argv) |
| { |
| FILE* component_handle = NULL; |
| FILE* rev_info_file = NULL; |
| int error = 0; |
| char* tmp_path = malloc(MAX_PATH); |
| |
| memset(&fw, 0, sizeof(fw)); |
| |
| if (argc < 2) |
| { |
| printf( |
| "Crypts Samsung YP-R0/YP-R1 ROM file format\n" |
| "Usage: fwcrypt <output ROM file path\n" |
| ); |
| return 1; |
| } |
| |
| input_dir = malloc(MAX_PATH); |
| input_dir[0] = '\0'; |
| if (argc > 2) |
| { |
| strcpy(input_dir, argv[2]); |
| } |
| |
| /* open the output file for write */ |
| output_file = fopen(argv[1], "wb"); |
| if (output_file == NULL) |
| { |
| fprintf(stderr, "Cannot open file for writing: %m\n"); |
| die(SAMSUNG_WRITE_ERROR); |
| } |
| |
| /* write generic header */ |
| join_path(tmp_path, input_dir, "RevisionInfo.txt"); |
| rev_info_file = fopen(tmp_path, "rb"); |
| if (rev_info_file != NULL) |
| { |
| for (int i = 0; i < GENERIC_HEADER_LINES; i++) |
| { |
| char header[MAX_HEADER_LEN]; |
| error += fgets(header, MAX_HEADER_LEN, rev_info_file) == NULL; |
| error += fprintf(output_file, "%s", header) != (signed)strlen(header); |
| } |
| fclose(rev_info_file); |
| } |
| else |
| { |
| /* write some generic information */ |
| error += fprintf(output_file, YPR0_VERSION) != strlen(YPR0_VERSION); |
| error += fprintf(output_file, YPR0_TARGET) != strlen(YPR0_TARGET); |
| error += fprintf(output_file, YPR0_USER) != strlen(YPR0_USER); |
| error += fprintf(output_file, YPR0_DIR) != strlen(YPR0_DIR); |
| error += fprintf(output_file, YPR0_TIME) != strlen(YPR0_TIME); |
| } |
| |
| if(error != 0) |
| { |
| fprintf(stderr, "Cannot write generic header\n"); |
| die(SAMSUNG_WRITE_ERROR); |
| } |
| |
| for (int i = 0; i < YPR0_COMPONENTS_COUNT; i++) |
| { |
| join_path(tmp_path, input_dir, firmware_filenames[i]); |
| component_handle = fopen(tmp_path, "rb"); |
| if (component_handle == NULL) |
| { |
| fprintf(stderr, "Error while reading firmware component.\n"); |
| die(SAMSUNG_READ_ERROR); |
| } |
| fw.component_size[i] = get_filesize(component_handle); |
| fw.component_data[i] = malloc(fw.component_size[i] * sizeof(char)); |
| fread(fw.component_data[i], sizeof(char), fw.component_size[i], component_handle); |
| fclose(component_handle); |
| |
| /* compute checksum */ |
| md5sum(fw.component_checksum[i], fw.component_data[i], fw.component_size[i]); |
| printf("%s : size(%ld),checksum(%s)\n", firmware_components[i], |
| fw.component_size[i], fw.component_checksum[i]); |
| /* write metadata header to file */ |
| if (fprintf(output_file, "%s : size(%ld),checksum(%s)\n", firmware_components[i], |
| fw.component_size[i], fw.component_checksum[i]) < 0) |
| { |
| fprintf(stderr, "Error writing to output file.\n"); |
| die(SAMSUNG_WRITE_ERROR); |
| } |
| } |
| |
| /* Padding */ |
| pad4byte('\n', output_file); |
| |
| /* write final data to the firmware file */ |
| for (int i = 0; i < YPR0_COMPONENTS_COUNT; i++) |
| { |
| /* the bootloader needs to be patched: add checksum of the components */ |
| if (strcmp("MBoot", firmware_components[i]) == 0) |
| { |
| int index=MBOOT_CHECKSUM_OFFSET; |
| for (int z = 0; z < YPR0_COMPONENTS_COUNT; z++) |
| { |
| index += sprintf(fw.component_data[i] + index, "%ld:%s\n", |
| fw.component_size[z], fw.component_checksum[z]); |
| } |
| } |
| /* crypt data */ |
| cyclic_xor(fw.component_data[i], fw.component_size[i], g_yp_key, sizeof(g_yp_key)); |
| /* write data */ |
| size_t written = fwrite(fw.component_data[i], sizeof(char), |
| fw.component_size[i], output_file); |
| if (written != fw.component_size[i]) |
| { |
| fprintf(stderr, "%s: error writing data to file. Written %ld bytes\n", |
| firmware_components[i], written); |
| die(SAMSUNG_WRITE_ERROR); |
| } |
| /* padding */ |
| if (i < (YPR0_COMPONENTS_COUNT-1)) |
| pad4byte('\0', output_file); |
| } |
| |
| /* free the big amount of memory and close handles */ |
| die(SAMSUNG_SUCCESS); |
| } |