169 lines
5.2 KiB
C
169 lines
5.2 KiB
C
|
/***************************************************************************
|
||
|
* __________ __ ___.
|
||
|
* 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 <stdbool.h>
|
||
|
#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 <ROM file path\n"
|
||
|
);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
output_dir = malloc(MAX_PATH);
|
||
|
output_dir[0] = '\0';
|
||
|
if (argc > 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);
|
||
|
}
|