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
|
LD=gcc
|
||||||
CFLAGS=-g -std=c99 -W -Wall $(DEFINES) `pkg-config --cflags openssl`
|
CFLAGS=-g -std=c99 -W -Wall $(DEFINES) `pkg-config --cflags openssl`
|
||||||
LDFLAGS=`pkg-config --libs openssl`
|
LDFLAGS=`pkg-config --libs openssl`
|
||||||
BINS=fwdecrypt
|
BINS=fwdecrypt fwcrypt
|
||||||
|
|
||||||
all: $(BINS)
|
all: $(BINS)
|
||||||
|
|
||||||
|
@ -13,5 +13,8 @@ all: $(BINS)
|
||||||
fwdecrypt: fwdecrypt.o samsung.o
|
fwdecrypt: fwdecrypt.o samsung.o
|
||||||
$(LD) -o $@ $^ $(LDFLAGS)
|
$(LD) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
fwcrypt: fwcrypt.o samsung.o
|
||||||
|
$(LD) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr *.o $(BINS)
|
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;
|
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)
|
void samsung_free(struct samsung_firmware_t *fw)
|
||||||
{
|
{
|
||||||
if(fw)
|
if(fw)
|
||||||
|
|
|
@ -66,13 +66,17 @@ enum samsung_error_t
|
||||||
SAMSUNG_READ_ERROR = -1,
|
SAMSUNG_READ_ERROR = -1,
|
||||||
SAMSUNG_FORMAT_ERROR = -2,
|
SAMSUNG_FORMAT_ERROR = -2,
|
||||||
SAMSUNG_MD5_ERROR = -3,
|
SAMSUNG_MD5_ERROR = -3,
|
||||||
|
SAMSUNG_WRITE_ERROR = -4,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*samsung_read_t)(void *user, int offset, void *buffer, int size);
|
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, ...);
|
typedef void (*samsung_printf_t)(void *user, bool error, const char *fmt, ...);
|
||||||
|
|
||||||
struct samsung_firmware_t *samsung_read(samsung_read_t read,
|
struct samsung_firmware_t *samsung_read(samsung_read_t read,
|
||||||
samsung_printf_t printf, void *user, enum samsung_error_t *err);
|
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);
|
void samsung_free(struct samsung_firmware_t *fw);
|
||||||
|
|
||||||
#endif /* __SAMSUNG_H__ */
|
#endif /* __SAMSUNG_H__ */
|
||||||
|
|
Loading…
Reference in a new issue