/*************************************************************************** * __________ __ ___. * 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 #include #include #include #include #include #include #include "common.h" static char* output_dir = NULL; static FILE* input_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 (input_file != NULL) fclose(input_file); free(output_dir); cleanup(); exit(error); } int main(int argc, char **argv) { FILE* component_handle = NULL; FILE* rev_info_file = NULL; char* tmp_path = malloc(MAX_PATH); int error = 0; bool md5sum_error = false; memset(&fw, 0, sizeof(fw)); if (argc < 2) { printf("Decrypts Samsung YP-R0/YP-R1 ROM file format\n" "Usage: fwdecrypt 2) { strcpy(output_dir, argv[2]); } /* open the output file for write */ input_file = fopen(argv[1], "rb"); if (input_file == NULL) { fprintf(stderr, "Cannot open file for reading: %m\n"); die(SAMSUNG_READ_ERROR); } /* read some generic information */ join_path(tmp_path, output_dir, "RevisionInfo.txt"); rev_info_file = fopen(tmp_path, "w"); for (int i = 0; i < 5; i++) { char info[MAX_HEADER_LEN]; error += fgets(info, MAX_HEADER_LEN, input_file) == NULL; printf("%s", info); if (rev_info_file != NULL) fprintf(rev_info_file, "%s", info); } if (rev_info_file != NULL) fclose(rev_info_file); if (error != 0) { fprintf(stderr, "Cannot write generic header\n"); die(SAMSUNG_WRITE_ERROR); } /* read metadata */ for (int i = 0; i < YPR0_COMPONENTS_COUNT; i++) { char metadata[MAX_HEADER_LEN]; error += fgets(metadata, MAX_HEADER_LEN, input_file) == NULL; error += sscanf(metadata, "%*s : size(%ld),checksum(%s)", &fw.component_size[i], fw.component_checksum[i]) != 2; /* strip last ")" */ fw.component_checksum[i][strlen(fw.component_checksum[i])-1] = '\0'; printf("%s: %ld bytes -- MD5 %s\n", firmware_components[i], fw.component_size[i], fw.component_checksum[i]); } /* We start from the end because ROM header could have a different * line count or extra new-lines (noticed in some hacked ROMs) */ size_t current_pos = get_filesize(input_file); for (int i = YPR0_COMPONENTS_COUNT-1; i >= 0; i--) { fw.component_data[i] = malloc(fw.component_size[i]); current_pos -= fw.component_size[i]; fseek(input_file, current_pos, SEEK_SET); size_t bread = fread(fw.component_data[i], 1, fw.component_size[i], input_file); if (bread != fw.component_size[i]) fprintf(stderr, "%s: Read size mismatch: read %ld bytes, expected %ld bytes\n", firmware_components[i], bread, fw.component_size[i]); /* decrypt data */ cyclic_xor(fw.component_data[i], fw.component_size[i], g_yp_key, sizeof(g_yp_key)); /* unpatch bootloader */ if (strcmp("MBoot", firmware_components[i]) == 0) { memset(fw.component_data[i] + MBOOT_CHECKSUM_OFFSET, 0, MBOOT_CHECKSUM_LENGTH); } char md5sum_decrypted[MD5_DIGEST_LENGTH*2+1]; md5sum(md5sum_decrypted, fw.component_data[i], fw.component_size[i]); if (strcmp(md5sum_decrypted, fw.component_checksum[i]) != 0) { printf("%s: FAIL (md5sum doesn't match)\n", firmware_components[i]); md5sum_error = true; } join_path(tmp_path, output_dir, firmware_filenames[i]); component_handle = fopen(tmp_path, "wb"); if (component_handle == NULL) { fprintf(stderr, "Error opening file for writing. Is the directory valid and writeable?\n"); die(SAMSUNG_WRITE_ERROR); } fwrite(fw.component_data[i], 1, fw.component_size[i], component_handle); fclose(component_handle); } if (md5sum_error) die(SAMSUNG_MD5_ERROR); die(SAMSUNG_SUCCESS); }