samsungtool: allow firmware creation
The new tool fwcrypt can create a firmware image with a specified model, version, region and so on. Change-Id: I0e90e9ab905398a3e7ae3f4fb8b8bbfb2d12d703
This commit is contained in:
parent
8666e83aaa
commit
fb43a137e7
4 changed files with 229 additions and 1 deletions
|
@ -3,7 +3,7 @@ CC=gcc
|
|||
LD=gcc
|
||||
CFLAGS=-g -std=c99 -W -Wall $(DEFINES) `pkg-config --cflags openssl`
|
||||
LDFLAGS=`pkg-config --libs openssl`
|
||||
BINS=fwdecrypt
|
||||
BINS=fwdecrypt fwcrypt
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
|
@ -13,5 +13,8 @@ all: $(BINS)
|
|||
fwdecrypt: fwdecrypt.o samsung.o
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
fwcrypt: fwcrypt.o samsung.o
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -fr *.o $(BINS)
|
||||
|
|
170
utils/samsungtools/fwcrypt.c
Normal file
170
utils/samsungtools/fwcrypt.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Amaury Pouly
|
||||
*
|
||||
* 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 "samsung.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
|
||||
static bool g_debug = false;
|
||||
static char *g_out_prefix = NULL;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: fwcrypt [options] content\n");
|
||||
printf("Options:\n");
|
||||
printf(" -o <prefix>\tSet output file\n");
|
||||
printf(" -m/--model <model>\tSet model\n");
|
||||
printf(" -v/--version <ver>\tSet version\n");
|
||||
printf(" -r/--region <region>\tSet region\n");
|
||||
printf(" -e/--extra <extra>\tSet extra\n");
|
||||
printf(" -?/--help\tDisplay this message\n");
|
||||
printf(" -d/--debug\tDisplay debug messages\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int s_write(void *user, int offset, void *buf, int size)
|
||||
{
|
||||
FILE *f = user;
|
||||
if(fseek(f, offset, SEEK_SET) != 0)
|
||||
return 0;
|
||||
return fwrite(buf, 1, size, f);
|
||||
}
|
||||
|
||||
static void s_printf(void *user, bool error, const char *fmt, ...)
|
||||
{
|
||||
if(!g_debug && !error)
|
||||
return;
|
||||
(void) user;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct samsung_firmware_t *fw = malloc(sizeof(struct samsung_firmware_t));
|
||||
memset(fw, 0, sizeof(struct samsung_firmware_t));
|
||||
|
||||
if(argc <= 1)
|
||||
usage();
|
||||
|
||||
while(1)
|
||||
{
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, 0, '?'},
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"model", required_argument, 0, 'm'},
|
||||
{"version", required_argument, 0, 'v'},
|
||||
{"region", required_argument, 0, 'r'},
|
||||
{"extra", required_argument, 0, 'e'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int c = getopt_long(argc, argv, "?do:m:v:r:e:", long_options, NULL);
|
||||
if(c == -1)
|
||||
break;
|
||||
switch(c)
|
||||
{
|
||||
case -1:
|
||||
break;
|
||||
case 'd':
|
||||
g_debug = true;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
break;
|
||||
case 'o':
|
||||
g_out_prefix = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
strncpy(fw->model, optarg, sizeof(fw->model));
|
||||
if(strlen(optarg) > sizeof(fw->model))
|
||||
printf("Warning: truncate model string\n");
|
||||
break;
|
||||
case 'r':
|
||||
strncpy(fw->region, optarg, sizeof(fw->region));
|
||||
if(strlen(optarg) > sizeof(fw->region))
|
||||
printf("Warning: truncate region string\n");
|
||||
break;
|
||||
case 'v':
|
||||
strncpy(fw->version, optarg, sizeof(fw->version));
|
||||
if(strlen(optarg) > sizeof(fw->version))
|
||||
printf("Warning: truncate vesion string\n");
|
||||
break;
|
||||
case 'e':
|
||||
strncpy(fw->extra, optarg, sizeof(fw->extra));
|
||||
if(strlen(optarg) > sizeof(fw->extra))
|
||||
printf("Warning: truncate extra string\n");
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if(optind != argc - 1)
|
||||
usage();
|
||||
|
||||
FILE *fin = fopen(argv[optind], "rb");
|
||||
if(fin == NULL)
|
||||
{
|
||||
printf("Cannot open file for reading: %m\n");
|
||||
samsung_free(fw);
|
||||
return 1;
|
||||
}
|
||||
fseek(fin, 0, SEEK_END);
|
||||
fw->data_size = ftell(fin);
|
||||
fseek(fin, 0, SEEK_SET);
|
||||
fw->data = malloc(fw->data_size);
|
||||
if((int)fread(fw->data, 1, fw->data_size, fin) != fw->data_size)
|
||||
{
|
||||
printf("Cannot read input file: %m\n");
|
||||
samsung_free(fw);
|
||||
return 2;
|
||||
}
|
||||
fclose(fin);
|
||||
|
||||
if(g_out_prefix)
|
||||
{
|
||||
FILE *f = fopen(g_out_prefix, "wb");
|
||||
if(f == NULL)
|
||||
{
|
||||
printf("Cannot open file for writing: %m\n");
|
||||
samsung_free(fw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum samsung_error_t err = samsung_write(s_write, s_printf, f, fw);
|
||||
if(err != SAMSUNG_SUCCESS)
|
||||
{
|
||||
printf("Error writing firmware: %d\n", err);
|
||||
samsung_free(fw);
|
||||
return 3;
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
samsung_free(fw);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -117,6 +117,57 @@ struct samsung_firmware_t *samsung_read(samsung_read_t read,
|
|||
return fw;
|
||||
}
|
||||
|
||||
enum samsung_error_t samsung_write(samsung_write_t write, samsung_printf_t printf,
|
||||
void *user, struct samsung_firmware_t *fw)
|
||||
{
|
||||
struct yp_header_t yp_hdr;
|
||||
struct yp_md5_t yp_md5;
|
||||
|
||||
// write header
|
||||
strncpy(yp_hdr.signature, YP_SIGNATURE, sizeof(yp_hdr.signature));
|
||||
strncpy(yp_hdr.version, fw->version, sizeof(yp_hdr.version));
|
||||
strncpy(yp_hdr.region, fw->region, sizeof(yp_hdr.region));
|
||||
strncpy(yp_hdr.extra, fw->extra, sizeof(yp_hdr.extra));
|
||||
strncpy(yp_hdr.model, fw->model, sizeof(yp_hdr.model));
|
||||
yp_hdr.datasize = fw->data_size;
|
||||
|
||||
printf(user, false, "Model: %s\n", yp_hdr.model);
|
||||
printf(user, false, "Version: %s %s %s\n", yp_hdr.version, yp_hdr.region, yp_hdr.extra);
|
||||
|
||||
if(write(user, 0, &yp_hdr, sizeof(yp_hdr)) != sizeof(yp_hdr))
|
||||
{
|
||||
printf(user, true, "Cannot write header\n");
|
||||
return SAMSUNG_WRITE_ERROR;
|
||||
}
|
||||
|
||||
// encrypt data
|
||||
cyclic_xor(fw->data, fw->data_size, g_yp_key, sizeof(g_yp_key));
|
||||
// compute MD5
|
||||
MD5_CTX c;
|
||||
MD5_Init(&c);
|
||||
MD5_Update(&c, fw->data, fw->data_size);
|
||||
MD5_Final(yp_md5.md5, &c);
|
||||
|
||||
// write data
|
||||
if(write(user, sizeof(yp_hdr), fw->data, fw->data_size) != fw->data_size)
|
||||
{
|
||||
// decrypt data so that the firmware data is the same after the call
|
||||
cyclic_xor(fw->data, fw->data_size, g_yp_key, sizeof(g_yp_key));
|
||||
printf(user, true, "Cannot write data\n");
|
||||
return SAMSUNG_WRITE_ERROR;
|
||||
}
|
||||
// decrypt data so that the firmware data is the same after the call
|
||||
cyclic_xor(fw->data, fw->data_size, g_yp_key, sizeof(g_yp_key));
|
||||
// write md5
|
||||
if(write(user, sizeof(yp_hdr) + fw->data_size, &yp_md5, sizeof(yp_md5)) != sizeof(yp_md5))
|
||||
{
|
||||
printf(user, true, "Cannot write md5\n");
|
||||
return SAMSUNG_WRITE_ERROR;
|
||||
}
|
||||
|
||||
return SAMSUNG_SUCCESS;
|
||||
}
|
||||
|
||||
void samsung_free(struct samsung_firmware_t *fw)
|
||||
{
|
||||
if(fw)
|
||||
|
|
|
@ -66,13 +66,17 @@ enum samsung_error_t
|
|||
SAMSUNG_READ_ERROR = -1,
|
||||
SAMSUNG_FORMAT_ERROR = -2,
|
||||
SAMSUNG_MD5_ERROR = -3,
|
||||
SAMSUNG_WRITE_ERROR = -4,
|
||||
};
|
||||
|
||||
typedef int (*samsung_read_t)(void *user, int offset, void *buffer, int size);
|
||||
typedef int (*samsung_write_t)(void *user, int offset, void *buffer, int size);
|
||||
typedef void (*samsung_printf_t)(void *user, bool error, const char *fmt, ...);
|
||||
|
||||
struct samsung_firmware_t *samsung_read(samsung_read_t read,
|
||||
samsung_printf_t printf, void *user, enum samsung_error_t *err);
|
||||
enum samsung_error_t samsung_write(samsung_write_t write, samsung_printf_t printf,
|
||||
void *user, struct samsung_firmware_t *fw);
|
||||
void samsung_free(struct samsung_firmware_t *fw);
|
||||
|
||||
#endif /* __SAMSUNG_H__ */
|
||||
|
|
Loading…
Reference in a new issue