sbtools: rename to imxtools, move imx_hid_recovery to imxtools/sbloader, fix tools to correctly handle/free memory, properly return error codes
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30907 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
33d6bd61b5
commit
5827937270
20 changed files with 392 additions and 198 deletions
|
@ -1,15 +0,0 @@
|
|||
CC=gcc
|
||||
LD=gcc
|
||||
|
||||
all: imx_hid_recovery
|
||||
|
||||
imx_hid_recovery.o: imx_hid_recovery.c
|
||||
$(CC) -c -Wall -O2 -std=c99 `pkg-config --cflags libusb-1.0` -o $@ $<
|
||||
|
||||
imx_hid_recovery: imx_hid_recovery.o
|
||||
$(LD) -o $@ $< `pkg-config --libs libusb-1.0`
|
||||
|
||||
clean:
|
||||
rm -rf imx_hid_recovery.o
|
||||
|
||||
|
|
@ -3,8 +3,9 @@ CC=gcc
|
|||
LD=gcc
|
||||
CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
|
||||
LDFLAGS=`pkg-config --libs libusb-1.0`
|
||||
BINS=elftosb sbtoelf sbloader
|
||||
|
||||
all: elftosb sbtoelf
|
||||
all: $(BINS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
@ -15,8 +16,11 @@ sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o
|
|||
elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
sbloader: sbloader.o
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -fr *.o
|
||||
|
||||
veryclean:
|
||||
rm -rf sbtoelf elftosb
|
||||
rm -rf $(BINS)
|
|
@ -63,6 +63,7 @@ void crypto_setup(enum crypto_method_t method, void *param);
|
|||
#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */
|
||||
#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */
|
||||
#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
|
||||
#define CRYPTO_NUM_ERRORS 8
|
||||
/* return 0 on success, <0 on error */
|
||||
int crypto_apply(
|
||||
byte *in_data, /* Input data */
|
|
@ -19,6 +19,7 @@
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L /* for strdup */
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
|
@ -48,6 +49,7 @@ enum lexem_type_t
|
|||
struct lexem_t
|
||||
{
|
||||
enum lexem_type_t type;
|
||||
/* if str is not NULL, it must be a malloc'd pointer */
|
||||
char *str;
|
||||
uint32_t num;
|
||||
int line;
|
||||
|
@ -390,8 +392,15 @@ struct lex_ctx_t
|
|||
struct lexem_t lexem;
|
||||
};
|
||||
|
||||
static inline void next(struct lex_ctx_t *ctx)
|
||||
/* When lexems hold strings (like identifier), it might be useful to steal
|
||||
* the pointer and don't clean the lexem but in other case, one don't want
|
||||
* to keep the pointer to the string and just want to release the memory.
|
||||
* Thus clean_lexem should be true except when one keeps a pointer */
|
||||
static inline void next(struct lex_ctx_t *ctx, bool clean_lexem)
|
||||
{
|
||||
if(clean_lexem)
|
||||
free(ctx->lexem.str);
|
||||
memset(&ctx->lexem, 0, sizeof(struct lexem_t));
|
||||
next_lexem(&ctx->ctx, &ctx->lexem);
|
||||
}
|
||||
|
||||
|
@ -411,7 +420,7 @@ static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *cons
|
|||
}
|
||||
else
|
||||
parse_error(ctx->lexem, "Number or constant identifier expected\n");
|
||||
next(ctx);
|
||||
next(ctx, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -420,7 +429,7 @@ static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *con
|
|||
uint32_t v = parse_term_expr(ctx, const_list);
|
||||
while(ctx->lexem.type == LEX_LSHIFT)
|
||||
{
|
||||
next(ctx);
|
||||
next(ctx, true);
|
||||
v <<= parse_term_expr(ctx, const_list);
|
||||
}
|
||||
return v;
|
||||
|
@ -431,7 +440,7 @@ static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_
|
|||
uint32_t v = parse_shift_expr(ctx, const_list);
|
||||
while(ctx->lexem.type == LEX_OR)
|
||||
{
|
||||
next(ctx);
|
||||
next(ctx, true);
|
||||
v |= parse_shift_expr(ctx, const_list);
|
||||
}
|
||||
return v;
|
||||
|
@ -470,7 +479,7 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
{
|
||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||
opt->name = init_const_name[i];
|
||||
opt->name = strdup(init_const_name[i]);
|
||||
opt->is_string = false;
|
||||
opt->val = init_const_value[i];
|
||||
opt->next = cmd_file->constant_list;
|
||||
|
@ -483,14 +492,14 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
lctx.ctx.begin = buf;
|
||||
lctx.ctx.ptr = buf;
|
||||
lctx.ctx.end = buf + size;
|
||||
#define next() next(&lctx)
|
||||
#define next(clean_lexem) next(&lctx, clean_lexem)
|
||||
#define lexem lctx.lexem
|
||||
/* init lexer */
|
||||
next();
|
||||
next(false); /* don't clean init lexem because it doesn't exist */
|
||||
/* constants ? */
|
||||
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
|
||||
{
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type != LEX_LBRACE)
|
||||
parse_error(lexem, "'{' expected after 'constants'\n");
|
||||
|
||||
|
@ -498,16 +507,16 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
{
|
||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type == LEX_RBRACE)
|
||||
break;
|
||||
if(lexem.type != LEX_IDENTIFIER)
|
||||
parse_error(lexem, "Identifier expected in constants\n");
|
||||
opt->name = lexem.str;
|
||||
next();
|
||||
next(false); /* lexem string is kept as option name */
|
||||
if(lexem.type != LEX_EQUAL)
|
||||
parse_error(lexem, "'=' expected after identifier\n");
|
||||
next();
|
||||
next(true);
|
||||
opt->is_string = false;
|
||||
opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||
opt->next = cmd_file->constant_list;
|
||||
|
@ -515,34 +524,34 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
if(lexem.type != LEX_SEMICOLON)
|
||||
parse_error(lexem, "';' expected after string\n");
|
||||
}
|
||||
next();
|
||||
next(true);
|
||||
}
|
||||
/* options ? */
|
||||
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
|
||||
{
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type != LEX_LBRACE)
|
||||
parse_error(lexem, "'{' expected after 'options'\n");
|
||||
|
||||
while(true)
|
||||
{
|
||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type == LEX_RBRACE)
|
||||
break;
|
||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||
if(lexem.type != LEX_IDENTIFIER)
|
||||
parse_error(lexem, "Identifier expected in options\n");
|
||||
opt->name = lexem.str;
|
||||
next();
|
||||
next(false); /* lexem string is kept as option name */
|
||||
if(lexem.type != LEX_EQUAL)
|
||||
parse_error(lexem, "'=' expected after identifier\n");
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type == LEX_STRING)
|
||||
{
|
||||
opt->is_string = true;
|
||||
opt->str = lexem.str;
|
||||
next();
|
||||
next(false); /* lexem string is kept as option name */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -554,18 +563,18 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
if(lexem.type != LEX_SEMICOLON)
|
||||
parse_error(lexem, "';' expected after string\n");
|
||||
}
|
||||
next();
|
||||
next(true);
|
||||
}
|
||||
/* sources */
|
||||
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
|
||||
parse_error(lexem, "'sources' expected\n");
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type != LEX_LBRACE)
|
||||
parse_error(lexem, "'{' expected after 'sources'\n");
|
||||
|
||||
while(true)
|
||||
{
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type == LEX_RBRACE)
|
||||
break;
|
||||
struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
|
||||
|
@ -573,28 +582,28 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
if(lexem.type != LEX_IDENTIFIER)
|
||||
parse_error(lexem, "identifier expected in sources\n");
|
||||
src->identifier = lexem.str;
|
||||
next();
|
||||
next(false); /* lexem string is kept as source name */
|
||||
if(lexem.type != LEX_EQUAL)
|
||||
parse_error(lexem, "'=' expected after identifier\n");
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type == LEX_STRING)
|
||||
{
|
||||
src->is_extern = false;
|
||||
src->filename = lexem.str;
|
||||
next();
|
||||
next(false); /* lexem string is kept as file name */
|
||||
}
|
||||
else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
|
||||
{
|
||||
src->is_extern = true;
|
||||
src->filename = "<extern>";
|
||||
next();
|
||||
src->filename = strdup("<extern>"); /* duplicate because it will be free'd */
|
||||
next(true);
|
||||
if(lexem.type != LEX_LPAREN)
|
||||
parse_error(lexem, "'(' expected after 'extern'\n");
|
||||
next();
|
||||
next(true);
|
||||
src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||
if(lexem.type != LEX_RPAREN)
|
||||
parse_error(lexem, "')' expected\n");
|
||||
next();
|
||||
next(true);
|
||||
}
|
||||
else
|
||||
parse_error(lexem, "String or 'extern' expected after '='\n");
|
||||
|
@ -612,18 +621,18 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
struct cmd_section_t *end_sec = NULL;
|
||||
while(true)
|
||||
{
|
||||
next(true);
|
||||
if(lexem.type == LEX_EOF)
|
||||
break;
|
||||
struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
|
||||
struct cmd_inst_t *end_list = NULL;
|
||||
memset(sec, 0, sizeof(struct cmd_section_t));
|
||||
next();
|
||||
if(lexem.type == LEX_EOF)
|
||||
break;
|
||||
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
|
||||
parse_error(lexem, "'section' expected\n");
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type != LEX_LPAREN)
|
||||
parse_error(lexem, "'(' expected after 'section'\n");
|
||||
next();
|
||||
next(true);
|
||||
/* can be any number */
|
||||
sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||
/* options ? */
|
||||
|
@ -631,21 +640,21 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
{
|
||||
do
|
||||
{
|
||||
next();
|
||||
next(true);
|
||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||
if(lexem.type != LEX_IDENTIFIER)
|
||||
parse_error(lexem, "Identifier expected for section option\n");
|
||||
opt->name = lexem.str;
|
||||
next();
|
||||
next(false); /* lexem string is kept as option name */
|
||||
if(lexem.type != LEX_EQUAL)
|
||||
parse_error(lexem, "'=' expected after option identifier\n");
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type == LEX_STRING)
|
||||
{
|
||||
opt->is_string = true;
|
||||
opt->str = lexem.str;
|
||||
next();
|
||||
next(false); /* lexem string is kept as option string */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -658,18 +667,18 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
}
|
||||
if(lexem.type != LEX_RPAREN)
|
||||
parse_error(lexem, "')' expected after section identifier\n");
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type == LEX_LBRACE)
|
||||
{
|
||||
sec->is_data = false;
|
||||
/* commands */
|
||||
while(true)
|
||||
{
|
||||
struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
|
||||
memset(inst, 0, sizeof(struct cmd_inst_t));
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type == LEX_RBRACE)
|
||||
break;
|
||||
struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
|
||||
memset(inst, 0, sizeof(struct cmd_inst_t));
|
||||
if(lexem.type != LEX_IDENTIFIER)
|
||||
parse_error(lexem, "Instruction expected in section\n");
|
||||
if(strcmp(lexem.str, "load") == 0)
|
||||
|
@ -682,7 +691,7 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
inst->type = CMD_MODE;
|
||||
else
|
||||
parse_error(lexem, "Instruction expected in section\n");
|
||||
next();
|
||||
next(true);
|
||||
|
||||
if(inst->type == CMD_LOAD)
|
||||
{
|
||||
|
@ -691,12 +700,12 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
inst->identifier = lexem.str;
|
||||
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
|
||||
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
|
||||
next();
|
||||
next(false); /* lexem string kept as identifier */
|
||||
if(lexem.type == LEX_RANGLE)
|
||||
{
|
||||
// load at
|
||||
inst->type = CMD_LOAD_AT;
|
||||
next();
|
||||
next(true);
|
||||
inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||
}
|
||||
if(lexem.type != LEX_SEMICOLON)
|
||||
|
@ -709,7 +718,7 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
inst->identifier = lexem.str;
|
||||
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
|
||||
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
|
||||
next();
|
||||
next(false); /* lexem string kept as identifier */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -719,11 +728,11 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
|
||||
if(lexem.type == LEX_LPAREN)
|
||||
{
|
||||
next();
|
||||
next(true);
|
||||
inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||
if(lexem.type != LEX_RPAREN)
|
||||
parse_error(lexem, "Expected closing brace\n");
|
||||
next();
|
||||
next(true);
|
||||
}
|
||||
if(lexem.type != LEX_SEMICOLON)
|
||||
parse_error(lexem, "';' expected after command\n");
|
||||
|
@ -751,11 +760,11 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
else if(lexem.type == LEX_LE)
|
||||
{
|
||||
sec->is_data = true;
|
||||
next();
|
||||
next(true);
|
||||
if(lexem.type != LEX_IDENTIFIER)
|
||||
parse_error(lexem, "Identifier expected after '<='\n");
|
||||
sec->source_id = lexem.str;
|
||||
next();
|
||||
next(false); /* lexem string is kept as source id */
|
||||
if(lexem.type != LEX_SEMICOLON)
|
||||
parse_error(lexem, "';' expected after identifier\n");
|
||||
}
|
||||
|
@ -776,6 +785,7 @@ struct cmd_file_t *db_parse_file(const char *file)
|
|||
#undef lexem
|
||||
#undef next
|
||||
|
||||
free(buf);
|
||||
return cmd_file;
|
||||
}
|
||||
|
||||
|
@ -783,3 +793,57 @@ void db_generate_default_sb_version(struct sb_version_t *ver)
|
|||
{
|
||||
ver->major = ver->minor = ver->revision = 0x999;
|
||||
}
|
||||
|
||||
void db_free_option_list(struct cmd_option_t *opt_list)
|
||||
{
|
||||
while(opt_list)
|
||||
{
|
||||
struct cmd_option_t *next = opt_list->next;
|
||||
fflush(stdout);
|
||||
free(opt_list->name);
|
||||
free(opt_list->str);
|
||||
free(opt_list);
|
||||
opt_list = next;
|
||||
}
|
||||
}
|
||||
|
||||
void db_free(struct cmd_file_t *file)
|
||||
{
|
||||
db_free_option_list(file->opt_list);
|
||||
db_free_option_list(file->constant_list);
|
||||
struct cmd_source_t *src = file->source_list;
|
||||
while(src)
|
||||
{
|
||||
struct cmd_source_t *next = src->next;
|
||||
free(src->identifier);
|
||||
fflush(stdout);
|
||||
free(src->filename);
|
||||
if(src->loaded)
|
||||
{
|
||||
if(src->type == CMD_SRC_BIN)
|
||||
free(src->bin.data);
|
||||
if(src->type == CMD_SRC_ELF)
|
||||
elf_release(&src->elf);
|
||||
}
|
||||
free(src);
|
||||
src = next;
|
||||
}
|
||||
struct cmd_section_t *sec = file->section_list;
|
||||
while(sec)
|
||||
{
|
||||
struct cmd_section_t *next = sec->next;
|
||||
db_free_option_list(sec->opt_list);
|
||||
free(sec->source_id);
|
||||
struct cmd_inst_t *inst = sec->inst_list;
|
||||
while(inst)
|
||||
{
|
||||
struct cmd_inst_t *next = inst->next;
|
||||
free(inst->identifier);
|
||||
free(inst);
|
||||
inst = next;
|
||||
}
|
||||
free(sec);
|
||||
sec = next;
|
||||
}
|
||||
free(file);
|
||||
}
|
|
@ -102,7 +102,7 @@ struct cmd_section_t
|
|||
struct cmd_file_t
|
||||
{
|
||||
struct cmd_option_t *opt_list;
|
||||
struct cmd_option_t *constant_list; /* constant all always integers */
|
||||
struct cmd_option_t *constant_list; /* constant are always integers */
|
||||
struct cmd_source_t *source_list;
|
||||
struct cmd_section_t *section_list;
|
||||
};
|
||||
|
@ -112,5 +112,7 @@ struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *
|
|||
bool db_parse_sb_version(struct sb_version_t *ver, char *str);
|
||||
void db_generate_default_sb_version(struct sb_version_t *ver);
|
||||
struct cmd_file_t *db_parse_file(const char *file);
|
||||
void db_free_option_list(struct cmd_option_t *opt_list);
|
||||
void db_free(struct cmd_file_t *file);
|
||||
|
||||
#endif /* __DBPARSER__ */
|
|
@ -153,10 +153,7 @@ typedef struct
|
|||
|
||||
void elf_init(struct elf_params_t *params)
|
||||
{
|
||||
params->has_start_addr = false;
|
||||
params->start_addr = 0;
|
||||
params->first_section = NULL;
|
||||
params->last_section = NULL;
|
||||
memset(params, 0, sizeof(struct elf_params_t));
|
||||
}
|
||||
|
||||
extern void *xmalloc(size_t s);
|
||||
|
@ -463,6 +460,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
|
|||
if(!read(user, shdr.sh_offset, data, shdr.sh_size))
|
||||
error_printf("error read self section data\n");
|
||||
elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data);
|
||||
free(data);
|
||||
|
||||
if(strtab)
|
||||
printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]);
|
||||
|
@ -480,6 +478,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
|
|||
}
|
||||
|
||||
}
|
||||
free(strtab);
|
||||
/* run through segments */
|
||||
for(int i = 1; i < ehdr.e_phnum; i++)
|
||||
{
|
||||
|
@ -557,16 +556,20 @@ int elf_get_nr_sections(struct elf_params_t *params)
|
|||
|
||||
void elf_release(struct elf_params_t *params)
|
||||
{
|
||||
struct elf_section_t *sec, *next_sec;
|
||||
sec = params->first_section;
|
||||
struct elf_section_t *sec = params->first_section;
|
||||
while(sec)
|
||||
{
|
||||
next_sec = sec->next;
|
||||
struct elf_section_t *next_sec = sec->next;
|
||||
if(sec->type == EST_LOAD)
|
||||
free(sec->section);
|
||||
free(sec);
|
||||
sec = next_sec;
|
||||
}
|
||||
params->first_section = NULL;
|
||||
params->last_section = NULL;
|
||||
struct elf_segment_t *seg = params->first_segment;
|
||||
while(seg)
|
||||
{
|
||||
struct elf_segment_t *next_seg = seg->next;
|
||||
free(seg);
|
||||
seg = next_seg;
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
****************************************************************************/
|
||||
|
||||
#define _ISOC99_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L /* for strdup */
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -77,7 +78,9 @@ static void resolve_extern(struct cmd_source_t *src)
|
|||
src->is_extern = false;
|
||||
if(src->extern_nr < 0 || src->extern_nr >= g_extern_count)
|
||||
bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr);
|
||||
src->filename = g_extern[src->extern_nr];
|
||||
/* first free the old src->filename content */
|
||||
free(src->filename);
|
||||
src->filename = strdup(g_extern[src->extern_nr]);
|
||||
}
|
||||
|
||||
static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
|
||||
|
@ -206,7 +209,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
|
|||
|
||||
sec->insts[0].inst = SB_INST_DATA;
|
||||
sec->insts[0].size = bin->size;
|
||||
sec->insts[0].data = bin->data;
|
||||
sec->insts[0].data = memdup(bin->data, bin->size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -266,7 +269,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
|
|||
sec->insts[idx].inst = SB_INST_LOAD;
|
||||
sec->insts[idx].addr = esec->addr;
|
||||
sec->insts[idx].size = esec->size;
|
||||
sec->insts[idx++].data = esec->section;
|
||||
sec->insts[idx++].data = memdup(esec->section, esec->size);
|
||||
}
|
||||
else if(esec->type == EST_FILL)
|
||||
{
|
||||
|
@ -296,7 +299,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
|
|||
struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin;
|
||||
sec->insts[idx].inst = SB_INST_LOAD;
|
||||
sec->insts[idx].addr = cinst->addr;
|
||||
sec->insts[idx].data = bin->data;
|
||||
sec->insts[idx].data = memdup(bin->data, bin->size);
|
||||
sec->insts[idx++].size = bin->size;
|
||||
}
|
||||
else if(cinst->type == CMD_MODE)
|
||||
|
@ -431,11 +434,18 @@ int main(int argc, char **argv)
|
|||
|
||||
struct cmd_file_t *cmd_file = db_parse_file(cmd_filename);
|
||||
struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
|
||||
db_free(cmd_file);
|
||||
|
||||
if(real_key.method == CRYPTO_KEY)
|
||||
sb_file->real_key = &real_key.u.key;
|
||||
{
|
||||
sb_file->override_real_key = true;
|
||||
memcpy(sb_file->real_key, real_key.u.key, 16);
|
||||
}
|
||||
if(crypto_iv.method == CRYPTO_KEY)
|
||||
sb_file->crypto_iv = &crypto_iv.u.key;
|
||||
{
|
||||
sb_file->override_crypto_iv = true;
|
||||
memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16);
|
||||
}
|
||||
|
||||
/* fill with default parameters since there is no command file support for them */
|
||||
sb_file->drive_tag = 0;
|
||||
|
@ -444,6 +454,8 @@ int main(int argc, char **argv)
|
|||
sb_file->minor_version = 1;
|
||||
|
||||
sb_write_file(sb_file, output_filename);
|
||||
sb_free(sb_file);
|
||||
clear_keys();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -29,6 +29,14 @@ bool g_debug = false;
|
|||
/**
|
||||
* Misc
|
||||
*/
|
||||
|
||||
void *memdup(void *p, size_t len)
|
||||
{
|
||||
void *cpy = xmalloc(len);
|
||||
memcpy(cpy, p, len);
|
||||
return cpy;
|
||||
}
|
||||
|
||||
void generate_random_data(void *buf, size_t sz)
|
||||
{
|
||||
FILE *rand_fd = fopen("/dev/urandom", "rb");
|
||||
|
@ -144,6 +152,12 @@ void add_keys(key_array_t ka, int kac)
|
|||
g_nr_keys += kac;
|
||||
}
|
||||
|
||||
void clear_keys()
|
||||
{
|
||||
free(g_key_array);
|
||||
g_nr_keys = 0;
|
||||
}
|
||||
|
||||
void add_keys_from_file(const char *key_file)
|
||||
{
|
||||
int size;
|
|
@ -38,6 +38,7 @@ typedef struct crypto_key_t *key_array_t;
|
|||
int g_nr_keys;
|
||||
key_array_t g_key_array;
|
||||
|
||||
void *memdup(void *p, size_t len);
|
||||
void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt);
|
||||
void generate_random_data(void *buf, size_t sz);
|
||||
void *xmalloc(size_t s);
|
||||
|
@ -47,6 +48,7 @@ void add_keys(key_array_t ka, int kac);
|
|||
bool parse_key(char **str, struct crypto_key_t *key);
|
||||
void add_keys_from_file(const char *key_file);
|
||||
void print_key(struct crypto_key_t *key, bool newline);
|
||||
void clear_keys();
|
||||
|
||||
typedef char color_t[];
|
||||
|
|
@ -138,7 +138,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
|
|||
if(sb->sections[i].is_data)
|
||||
{
|
||||
nr_aug_insts = 1;
|
||||
aug_insts = malloc(sizeof(struct sb_inst_t));
|
||||
aug_insts = xmalloc(sizeof(struct sb_inst_t));
|
||||
memset(aug_insts, 0, sizeof(struct sb_inst_t));
|
||||
aug_insts[0].inst = SB_INST_DATA;
|
||||
aug_insts[0].size = missing_sz * BLOCK_SIZE;
|
||||
|
@ -150,7 +150,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
|
|||
else
|
||||
{
|
||||
nr_aug_insts = missing_sz;
|
||||
aug_insts = malloc(sizeof(struct sb_inst_t) * nr_aug_insts);
|
||||
aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts);
|
||||
memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
|
||||
for(int j = 0; j < nr_aug_insts; j++)
|
||||
{
|
||||
|
@ -163,6 +163,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
|
|||
sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
|
||||
sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
|
||||
sb->sections[i].nr_insts += nr_aug_insts;
|
||||
free(aug_insts);
|
||||
|
||||
/* augment image and section size */
|
||||
sb->image_size += missing_sz;
|
||||
|
@ -299,12 +300,8 @@ void produce_sb_instruction(struct sb_inst_t *inst,
|
|||
cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
|
||||
}
|
||||
|
||||
void sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||
enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||
{
|
||||
FILE *fd = fopen(filename, "wb");
|
||||
if(fd == NULL)
|
||||
bugp("cannot open output file");
|
||||
|
||||
struct crypto_key_t real_key;
|
||||
real_key.method = CRYPTO_KEY;
|
||||
byte crypto_iv[16];
|
||||
|
@ -324,8 +321,13 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
|||
/* produce and write header */
|
||||
struct sb_header_t sb_hdr;
|
||||
produce_sb_header(sb, &sb_hdr);
|
||||
/* allocate image */
|
||||
byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE);
|
||||
byte *buf_p = buf;
|
||||
#define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0)
|
||||
|
||||
sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
|
||||
fwrite(&sb_hdr, 1, sizeof(sb_hdr), fd);
|
||||
write(&sb_hdr, sizeof(sb_hdr));
|
||||
|
||||
memcpy(crypto_iv, &sb_hdr, 16);
|
||||
|
||||
|
@ -340,7 +342,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
|||
struct sb_section_header_t sb_sec_hdr;
|
||||
produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
|
||||
sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
|
||||
fwrite(&sb_sec_hdr, 1, sizeof(sb_sec_hdr), fd);
|
||||
write(&sb_sec_hdr, sizeof(sb_sec_hdr));
|
||||
/* update CBC-MACs */
|
||||
for(int j = 0; j < g_nr_keys; j++)
|
||||
crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
|
||||
|
@ -354,16 +356,18 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
|||
crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
|
||||
crypto_iv, NULL, 1);
|
||||
|
||||
fwrite(&entry, 1, sizeof(entry), fd);
|
||||
write(&entry, sizeof(entry));
|
||||
sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
|
||||
}
|
||||
|
||||
free(cbc_macs);
|
||||
|
||||
/* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
|
||||
/* Image crafting, don't use it unless you understand what you do */
|
||||
if(sb->real_key != NULL)
|
||||
memcpy(real_key.u.key, *sb->real_key, 16);
|
||||
if(sb->crypto_iv != NULL)
|
||||
memcpy(crypto_iv, *sb->crypto_iv, 16);
|
||||
if(sb->override_real_key)
|
||||
memcpy(real_key.u.key, sb->real_key, 16);
|
||||
if(sb->override_crypto_iv)
|
||||
memcpy(crypto_iv, sb->crypto_iv, 16);
|
||||
/* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
|
||||
if(g_debug)
|
||||
{
|
||||
|
@ -386,7 +390,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
|||
crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
|
||||
&real_key, crypto_iv, NULL, 1);
|
||||
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
|
||||
fwrite(&tag_cmd, 1, sizeof(tag_cmd), fd);
|
||||
write(&tag_cmd, sizeof(tag_cmd));
|
||||
/* produce other commands */
|
||||
byte cur_cbc_mac[16];
|
||||
memcpy(cur_cbc_mac, crypto_iv, 16);
|
||||
|
@ -402,7 +406,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
|||
crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
|
||||
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
||||
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
|
||||
fwrite(&cmd, 1, sizeof(cmd), fd);
|
||||
write(&cmd, sizeof(cmd));
|
||||
}
|
||||
/* data */
|
||||
if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
|
||||
|
@ -415,7 +419,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
|||
crypto_cbc(data, data, sz / BLOCK_SIZE,
|
||||
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
||||
sha_1_update(&file_sha1, data, sz);
|
||||
fwrite(data, 1, sz, fd);
|
||||
write(data, sz);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
@ -427,22 +431,35 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
|||
generate_random_data(final_sig + 20, 12);
|
||||
if(g_nr_keys > 0)
|
||||
crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
|
||||
fwrite(final_sig, 1, 32, fd);
|
||||
write(final_sig, 32);
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
|
||||
bug("SB image buffer was not entirely filled !");
|
||||
|
||||
static void *memdup(void *p, size_t len)
|
||||
FILE *fd = fopen(filename, "wb");
|
||||
if(fd == NULL)
|
||||
return SB_OPEN_ERROR;
|
||||
if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
|
||||
{
|
||||
void *cpy = xmalloc(len);
|
||||
memcpy(cpy, p, len);
|
||||
return cpy;
|
||||
free(buf);
|
||||
return SB_WRITE_ERROR;
|
||||
}
|
||||
fclose(fd);
|
||||
free(buf);
|
||||
|
||||
return SB_SUCCESS;
|
||||
}
|
||||
|
||||
static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
||||
int size, const char *indent, void *u, sb_color_printf cprintf)
|
||||
int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err)
|
||||
{
|
||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||
#define fatal(e, ...) \
|
||||
do { if(err) *err = e; \
|
||||
cprintf(u, true, GREY, __VA_ARGS__); \
|
||||
sb_free_section(*sec); \
|
||||
free(sec); \
|
||||
return NULL; } while(0)
|
||||
|
||||
struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
|
||||
memset(sec, 0, sizeof(struct sb_section_t));
|
||||
|
@ -474,7 +491,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
|||
printf(OFF, "%s", indent);
|
||||
uint8_t checksum = instruction_checksum(hdr);
|
||||
if(checksum != hdr->checksum)
|
||||
printf(GREY, "[Bad checksum]");
|
||||
fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum");
|
||||
if(hdr->flags != 0)
|
||||
{
|
||||
printf(GREY, "[");
|
||||
|
@ -501,7 +518,10 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
|||
if(load->crc == computed_crc)
|
||||
printf(RED, " Ok\n");
|
||||
else
|
||||
{
|
||||
printf(RED, " Failed (crc=0x%08x)\n", computed_crc);
|
||||
fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n");
|
||||
}
|
||||
|
||||
pos += load->len + sizeof(struct sb_instruction_load_t);
|
||||
}
|
||||
|
@ -559,7 +579,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
|||
}
|
||||
else
|
||||
{
|
||||
printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
|
||||
fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -569,6 +589,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
|||
|
||||
return sec;
|
||||
#undef printf
|
||||
#undef fatal
|
||||
}
|
||||
|
||||
void sb_fill_section_name(char name[5], uint32_t identifier)
|
||||
|
@ -595,25 +616,37 @@ static uint32_t guess_alignment(uint32_t off)
|
|||
}
|
||||
|
||||
struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||
sb_color_printf cprintf)
|
||||
sb_color_printf cprintf, enum sb_error_t *err)
|
||||
{
|
||||
uint8_t *buf = NULL;
|
||||
struct sb_file_t *sb_file = NULL;
|
||||
|
||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||
#define fatal(...) do { cprintf(u, true, GREY, __VA_ARGS__); return NULL; } while(0)
|
||||
#define fatal(e, ...) \
|
||||
do { if(err) *err = e; \
|
||||
cprintf(u, true, GREY, __VA_ARGS__); \
|
||||
free(buf); \
|
||||
sb_free(sb_file); \
|
||||
return NULL; } while(0)
|
||||
#define print_hex(c, p, len, nl) \
|
||||
do { printf(c, ""); print_hex(p, len, nl); } while(0)
|
||||
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if(f == NULL)
|
||||
fatal("Cannot open file for reading\n");
|
||||
fatal(SB_OPEN_ERROR, "Cannot open file for reading\n");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long filesize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
uint8_t *buf = xmalloc(filesize);
|
||||
fread(buf, 1, filesize, f);
|
||||
buf = xmalloc(filesize);
|
||||
if(fread(buf, filesize, 1, f) != 1)
|
||||
{
|
||||
fclose(f);
|
||||
fatal(SB_READ_ERROR, "Cannot read file\n");
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
struct sha_1_params_t sha_1_params;
|
||||
struct sb_file_t *sb_file = xmalloc(sizeof(struct sb_file_t));
|
||||
sb_file = xmalloc(sizeof(struct sb_file_t));
|
||||
memset(sb_file, 0, sizeof(struct sb_file_t));
|
||||
struct sb_header_t *sb_header = (struct sb_header_t *)buf;
|
||||
|
||||
|
@ -624,13 +657,13 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
|
||||
|
||||
if(memcmp(sb_header->signature, "STMP", 4) != 0)
|
||||
fatal("Bad signature\n");
|
||||
fatal(SB_FORMAT_ERROR, "Bad signature\n");
|
||||
if(sb_header->image_size * BLOCK_SIZE > filesize)
|
||||
fatal("File too small mismatch");
|
||||
fatal(SB_FORMAT_ERROR, "File too small");
|
||||
if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
|
||||
fatal("Bad header size");
|
||||
fatal(SB_FORMAT_ERROR, "Bad header size");
|
||||
if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
|
||||
fatal("Bad section header size");
|
||||
fatal(SB_FORMAT_ERROR, "Bad section header size");
|
||||
|
||||
if(filesize > sb_header->image_size * BLOCK_SIZE)
|
||||
{
|
||||
|
@ -707,67 +740,86 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
/* encryption cbc-mac */
|
||||
byte real_key[16];
|
||||
bool valid_key = false; /* false until a matching key was found */
|
||||
|
||||
if(sb_header->nr_keys > 0)
|
||||
{
|
||||
if(sb_header->nr_keys > g_nr_keys)
|
||||
{
|
||||
fatal("SB file has %d keys but only %d were specified\n",
|
||||
sb_header->nr_keys, g_nr_keys);
|
||||
}
|
||||
printf(BLUE, "Encryption data\n");
|
||||
for(int i = 0; i < sb_header->nr_keys; i++)
|
||||
byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
|
||||
printf(BLUE, "Encryption keys\n");
|
||||
for(int i = 0; i < g_nr_keys; i++)
|
||||
{
|
||||
printf(RED, " Key %d: ", i);
|
||||
printf(YELLOW, "");
|
||||
print_key(&g_key_array[i], true);
|
||||
printf(GREEN, " CBC-MAC of headers: ");
|
||||
printf(GREEN, " CBC-MAC: ");
|
||||
/* check it */
|
||||
byte zero[16];
|
||||
memset(zero, 0, 16);
|
||||
int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
|
||||
&g_key_array[i], zero, &cbcmacs[i], 1);
|
||||
if(ret != CRYPTO_ERROR_SUCCESS)
|
||||
{
|
||||
free(cbcmacs);
|
||||
fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret);
|
||||
}
|
||||
print_hex(YELLOW, cbcmacs[i], 16, true);
|
||||
}
|
||||
|
||||
printf(BLUE, "DEK\n");
|
||||
for(int i = 0; i < sb_header->nr_keys; i++)
|
||||
{
|
||||
printf(RED, " Entry %d\n", i);
|
||||
uint32_t ofs = sizeof(struct sb_header_t)
|
||||
+ sizeof(struct sb_section_header_t) * sb_header->nr_sections
|
||||
+ sizeof(struct sb_key_dictionary_entry_t) * i;
|
||||
struct sb_key_dictionary_entry_t *dict_entry =
|
||||
(struct sb_key_dictionary_entry_t *)&buf[ofs];
|
||||
/* cbc mac */
|
||||
print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
|
||||
/* check it */
|
||||
byte computed_cbc_mac[16];
|
||||
byte zero[16];
|
||||
memset(zero, 0, 16);
|
||||
crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
|
||||
&g_key_array[i], zero, &computed_cbc_mac, 1);
|
||||
|
||||
bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0;
|
||||
if(ok)
|
||||
{
|
||||
valid_key = true;
|
||||
printf(RED, " Ok\n");
|
||||
}
|
||||
else
|
||||
printf(RED, " Failed\n");
|
||||
|
||||
printf(GREEN, " Encrypted key: ");
|
||||
print_hex(YELLOW, dict_entry->key, 16, true);
|
||||
printf(GREEN, " CBC-MAC : ");
|
||||
print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
|
||||
/* check it */
|
||||
int idx = 0;
|
||||
while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0)
|
||||
idx++;
|
||||
if(idx != g_nr_keys)
|
||||
{
|
||||
printf(RED, " Match\n");
|
||||
/* decrypt */
|
||||
byte decrypted_key[16];
|
||||
byte iv[16];
|
||||
memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
|
||||
crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0);
|
||||
int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0);
|
||||
if(ret != CRYPTO_ERROR_SUCCESS)
|
||||
{
|
||||
free(cbcmacs);
|
||||
fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret);
|
||||
}
|
||||
printf(GREEN, " Decrypted key: ");
|
||||
print_hex(YELLOW, decrypted_key, 16, false);
|
||||
/* cross-check or copy */
|
||||
if(valid_key && ok)
|
||||
memcpy(real_key, decrypted_key, 16);
|
||||
else if(valid_key)
|
||||
if(valid_key)
|
||||
{
|
||||
if(memcmp(real_key, decrypted_key, 16) == 0)
|
||||
printf(RED, " Cross-Check Ok");
|
||||
else
|
||||
printf(RED, " Cross-Check Failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(real_key, decrypted_key, 16);
|
||||
valid_key = true;
|
||||
}
|
||||
printf(OFF, "\n");
|
||||
}
|
||||
else
|
||||
printf(RED, " Don't Match\n");
|
||||
}
|
||||
|
||||
free(cbcmacs);
|
||||
|
||||
if(!valid_key)
|
||||
fatal(SB_NO_VALID_KEY, "No valid key found\n");
|
||||
|
||||
if(getenv("SB_REAL_KEY") != 0)
|
||||
{
|
||||
struct crypto_key_t k;
|
||||
|
@ -783,10 +835,11 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
printf(GREEN, " IV : ");
|
||||
print_hex(YELLOW, buf, 16, true);
|
||||
|
||||
sb_file->real_key = xmalloc(16);
|
||||
memcpy(*sb_file->real_key, real_key, 16);
|
||||
sb_file->crypto_iv = xmalloc(16);
|
||||
memcpy(*sb_file->crypto_iv, buf, 16);
|
||||
sb_file->override_real_key = true;
|
||||
memcpy(sb_file->real_key, real_key, 16);
|
||||
sb_file->override_crypto_iv = true;
|
||||
memcpy(sb_file->crypto_iv, buf, 16);
|
||||
}
|
||||
|
||||
/* sections */
|
||||
if(!raw_mode)
|
||||
|
@ -831,7 +884,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
memcpy(sec, buf + pos, size);
|
||||
|
||||
struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
|
||||
sec, size, " ", u, cprintf);
|
||||
sec, size, " ", u, cprintf, err);
|
||||
if(s)
|
||||
{
|
||||
s->is_cleartext = !encrypted;
|
||||
|
@ -839,6 +892,8 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
fatal(*err, "Error reading section\n");
|
||||
|
||||
free(sec);
|
||||
}
|
||||
|
@ -919,7 +974,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
memcpy(sec, buf + pos, size);
|
||||
|
||||
struct sb_section_t *s = read_section(data_sec, tag->identifier,
|
||||
sec, size, " ", u, cprintf);
|
||||
sec, size, " ", u, cprintf, err);
|
||||
if(s)
|
||||
{
|
||||
s->is_cleartext = !encrypted;
|
||||
|
@ -929,6 +984,8 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
s, 1);
|
||||
free(s);
|
||||
}
|
||||
else
|
||||
fatal(*err, "Error reading section\n");
|
||||
free(sec);
|
||||
|
||||
/* last one ? */
|
||||
|
@ -938,7 +995,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
}
|
||||
else
|
||||
{
|
||||
printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
|
||||
fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -970,7 +1027,10 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
if(memcmp(decrypted_block, computed_sha1, 20) == 0)
|
||||
printf(RED, " Ok\n");
|
||||
else
|
||||
{
|
||||
printf(RED, " Failed\n");
|
||||
fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
|
||||
}
|
||||
free(buf);
|
||||
|
||||
return sb_file;
|
||||
|
@ -979,6 +1039,27 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
|||
#undef print_hex
|
||||
}
|
||||
|
||||
void sb_free_section(struct sb_section_t sec)
|
||||
{
|
||||
for(int j = 0; j < sec.nr_insts; j++)
|
||||
{
|
||||
free(sec.insts[j].padding);
|
||||
free(sec.insts[j].data);
|
||||
}
|
||||
free(sec.insts);
|
||||
}
|
||||
|
||||
void sb_free(struct sb_file_t *file)
|
||||
{
|
||||
if(!file) return;
|
||||
|
||||
for(int i = 0; i < file->nr_sections; i++)
|
||||
sb_free_section(file->sections[i]);
|
||||
|
||||
free(file->sections);
|
||||
free(file);
|
||||
}
|
||||
|
||||
void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
|
||||
{
|
||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||
|
@ -1007,17 +1088,17 @@ void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
|
|||
sb_fill_section_name(name, file->first_boot_sec_id);
|
||||
printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
|
||||
|
||||
if(file->real_key)
|
||||
if(file->override_real_key)
|
||||
{
|
||||
printf(TREE, "+-");
|
||||
printf(HEADER, "Real key: ");
|
||||
print_hex(TEXT, *file->real_key, 16, true);
|
||||
print_hex(TEXT, file->real_key, 16, true);
|
||||
}
|
||||
if(file->crypto_iv)
|
||||
if(file->override_crypto_iv)
|
||||
{
|
||||
printf(TREE, "+-");
|
||||
printf(HEADER, "IV : ");
|
||||
print_hex(TEXT, *file->crypto_iv, 16, true);
|
||||
print_hex(TEXT, file->crypto_iv, 16, true);
|
||||
}
|
||||
printf(TREE, "+-");
|
||||
printf(HEADER, "Product Version: ");
|
|
@ -191,9 +191,11 @@ struct sb_section_t
|
|||
struct sb_file_t
|
||||
{
|
||||
/* override real, otherwise it is randomly generated */
|
||||
uint8_t (*real_key)[16];
|
||||
bool override_real_key;
|
||||
uint8_t real_key[16];
|
||||
/* override crypto IV, use with caution ! Use NULL to generate it */
|
||||
uint8_t (*crypto_iv)[16];
|
||||
bool override_crypto_iv;
|
||||
uint8_t crypto_iv[16];
|
||||
|
||||
int nr_sections;
|
||||
uint16_t drive_tag;
|
||||
|
@ -207,13 +209,29 @@ struct sb_file_t
|
|||
uint32_t image_size; /* in blocks */
|
||||
};
|
||||
|
||||
void sb_write_file(struct sb_file_t *sb, const char *filename);
|
||||
enum sb_error_t
|
||||
{
|
||||
SB_SUCCESS = 0,
|
||||
SB_ERROR = -1,
|
||||
SB_OPEN_ERROR = -2,
|
||||
SB_READ_ERROR = -3,
|
||||
SB_WRITE_ERROR = -4,
|
||||
SB_FORMAT_ERROR = -5,
|
||||
SB_CHECKSUM_ERROR = -6,
|
||||
SB_NO_VALID_KEY = -7,
|
||||
SB_FIRST_CRYPTO_ERROR = -8,
|
||||
SB_LAST_CRYPTO_ERROR = SB_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
|
||||
};
|
||||
|
||||
enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename);
|
||||
|
||||
typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...);
|
||||
struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||
sb_color_printf printf);
|
||||
sb_color_printf printf, enum sb_error_t *err);
|
||||
|
||||
void sb_fill_section_name(char name[5], uint32_t identifier);
|
||||
void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf);
|
||||
void sb_free_section(struct sb_section_t file);
|
||||
void sb_free(struct sb_file_t *file);
|
||||
|
||||
#endif /* __SB_H__ */
|
|
@ -268,7 +268,15 @@ int main(int argc, char **argv)
|
|||
|
||||
const char *sb_filename = argv[optind];
|
||||
|
||||
struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf);
|
||||
enum sb_error_t err;
|
||||
struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
|
||||
if(file == NULL)
|
||||
{
|
||||
color(OFF);
|
||||
printf("SB read failed: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
color(OFF);
|
||||
if(g_out_prefix)
|
||||
extract_sb_file(file);
|
||||
|
@ -283,12 +291,12 @@ int main(int argc, char **argv)
|
|||
/* sb_read_file will fill real key and IV but we don't want to override
|
||||
* them when looping back otherwise the output will be inconsistent and
|
||||
* garbage */
|
||||
free(file->real_key);
|
||||
file->real_key = NULL;
|
||||
free(file->crypto_iv);
|
||||
file->crypto_iv = NULL;
|
||||
file->override_real_key = false;
|
||||
file->override_crypto_iv = false;
|
||||
sb_write_file(file, loopback);
|
||||
}
|
||||
sb_free(file);
|
||||
clear_keys();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue