1
0
Fork 0
forked from len0rd/rockbox

sbtoelf: fix to handle unencrypted files (minor tweak)

elftosb: properly generate sb file (encryption not implemented yet)

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29742 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Amaury Pouly 2011-04-17 22:30:09 +00:00
parent e3fe3956f6
commit b2c59541b4
5 changed files with 234 additions and 29 deletions

View file

@ -70,7 +70,12 @@ static uint32_t crc_table[256] = {
uint32_t crc(byte *data, int size)
{
uint32_t c = 0xffffffff;
return crc_continue(0xffffffff, data, size);
}
uint32_t crc_continue(uint32_t previous_crc, byte *data, int size)
{
uint32_t c = previous_crc;
/* normal CRC */
for(int i = 0; i < size; i++)
c = crc_table[data[i] ^ (c >> 24)] ^ (c << 8);

View file

@ -41,6 +41,7 @@ void cbc_mac(
/* crc.c */
uint32_t crc(byte *data, int size);
uint32_t crc_continue(uint32_t previous_crc, byte *data, int size);
/* sha1.c */
struct sha_1_params_t

View file

@ -42,10 +42,23 @@
bool g_debug = false;
#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
/**
* Misc
*/
void generate_random_data(void *buf, size_t sz)
{
static int rand_fd = -1;
if(rand_fd == -1)
rand_fd = open("/dev/urandom", O_RDONLY);
if(rand_fd == -1)
bugp("failed to open /dev/urandom");
if(read(rand_fd, buf, sz) != (ssize_t)sz)
bugp("failed to read /dev/urandom");
}
void *xmalloc(size_t s) /* malloc helper, used in elf.c */
{
void * r = malloc(s);
@ -316,6 +329,7 @@ static void next_lexem(char **ptr, char *end, struct lexem_t *lexem)
#undef ret_simple
}
#if 0
static void log_lexem(struct lexem_t *lexem)
{
switch(lexem->type)
@ -333,6 +347,7 @@ static void log_lexem(struct lexem_t *lexem)
default: printf("<unk>");
}
}
#endif
static struct cmd_source_t *find_source_by_id(struct cmd_file_t *cmd_file, const char *id)
{
@ -495,6 +510,9 @@ struct sb_inst_t
uint32_t pattern;
uint32_t addr;
// </union>
/* for production use */
uint32_t padding_size;
uint8_t *padding;
};
struct sb_section_t
@ -504,6 +522,7 @@ struct sb_section_t
struct sb_inst_t *insts;
/* for production use */
uint32_t file_offset; /* in blocks */
uint32_t sec_size; /* in blocks */
};
struct sb_file_t
@ -637,6 +656,24 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
* Sb file production
*/
static void fill_gaps(struct sb_file_t *sb)
{
for(int i = 0; i < sb->nr_sections; i++)
{
struct sb_section_t *sec = &sb->sections[i];
for(int j = 0; j < sec->nr_insts; j++)
{
struct sb_inst_t *inst = &sec->insts[j];
if(inst->inst != SB_INST_LOAD)
continue;
inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size;
/* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
inst->padding = xmalloc(15);
generate_random_data(inst->padding, 15);
}
}
}
static void compute_sb_offsets(struct sb_file_t *sb)
{
sb->image_size = 0;
@ -663,6 +700,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
printf("%s | addr=0x%08x | arg=0x%08x\n",
inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, 0);
sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
}
else if(inst->inst == SB_INST_FILL)
{
@ -670,6 +708,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
printf("FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
inst->addr, inst->size, inst->pattern);
sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
}
else if(inst->inst == SB_INST_LOAD)
{
@ -677,8 +716,10 @@ static void compute_sb_offsets(struct sb_file_t *sb)
printf("LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size);
/* load header */
sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
/* data + alignment */
sb->image_size += (inst->size + BLOCK_SIZE - 1) / BLOCK_SIZE;
sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
}
}
}
@ -686,8 +727,27 @@ static void compute_sb_offsets(struct sb_file_t *sb)
sb->image_size += 2;
}
static uint64_t generate_timestamp()
{
struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
time_t t = time(NULL) - mktime(&tm_base);
return (uint64_t)t * 1000000L;
}
void generate_version(struct sb_version_t *ver)
{
ver->major = 0x999;
ver->pad0 = 0;
ver->minor = 0x999;
ver->pad1 = 0;
ver->revision = 0x999;
ver->pad2 = 0;
}
static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr)
{
struct sha_1_params_t sha_1_params;
sb_hdr->signature[0] = 'S';
sb_hdr->signature[1] = 'T';
sb_hdr->signature[2] = 'M';
@ -696,6 +756,83 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr)
sb_hdr->minor_ver = IMAGE_MINOR_VERSION;
sb_hdr->flags = 0;
sb_hdr->image_size = sb->image_size;
sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE;
sb_hdr->first_boot_sec_id = sb->sections[0].identifier;
sb_hdr->nr_keys = g_nr_keys;
sb_hdr->nr_sections = sb->nr_sections;
sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE;
sb_hdr->key_dict_off = sb_hdr->header_size +
sb_hdr->sec_hdr_size * sb_hdr->nr_sections;
sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off +
sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE;
generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0));
generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1));
sb_hdr->timestamp = generate_timestamp();
generate_version(&sb_hdr->product_ver);
generate_version(&sb_hdr->component_ver);
sb_hdr->drive_tag = 0;
sha_1_init(&sha_1_params);
sha_1_update(&sha_1_params, &sb_hdr->signature[0],
sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header));
sha_1_finish(&sha_1_params);
sha_1_output(&sha_1_params, sb_hdr->sha1_header);
}
static void produce_sb_section_header(struct sb_section_t *sec,
struct sb_section_header_t *sec_hdr)
{
sec_hdr->identifier = sec->identifier;
sec_hdr->offset = sec->file_offset;
sec_hdr->size = sec->sec_size;
sec_hdr->flags = SECTION_BOOTABLE;
}
static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
{
uint8_t sum = 90;
byte *ptr = (byte *)hdr;
for(int i = 1; i < 16; i++)
sum += ptr[i];
return sum;
}
static void produce_section_tag_cmd(struct sb_section_t *sec,
struct sb_instruction_tag_t *tag, bool is_last)
{
tag->hdr.opcode = SB_INST_TAG;
tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0;
tag->identifier = sec->identifier;
tag->len = sec->sec_size;
tag->flags = SECTION_BOOTABLE;
tag->hdr.checksum = instruction_checksum(&tag->hdr);
}
void produce_sb_instruction(struct sb_inst_t *inst,
struct sb_instruction_common_t *cmd)
{
cmd->hdr.flags = 0;
cmd->hdr.opcode = inst->inst;
cmd->addr = inst->addr;
cmd->len = inst->size;
switch(inst->inst)
{
case SB_INST_CALL:
case SB_INST_JUMP:
cmd->len = 0;
cmd->data = 0;
break;
case SB_INST_FILL:
cmd->data = inst->pattern;
break;
case SB_INST_LOAD:
cmd->data = crc_continue(crc(inst->data, inst->size),
inst->padding, inst->padding_size);
break;
default:
break;
}
cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
}
static void produce_sb_file(struct sb_file_t *sb, const char *filename)
@ -705,25 +842,68 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
if(fd < 0)
bugp("cannot open output file");
byte real_key[16];
fill_gaps(sb);
compute_sb_offsets(sb);
generate_random_data(real_key, sizeof(real_key));
/* global SHA-1 */
struct sha_1_params_t file_sha1;
sha_1_init(&file_sha1);
/* produce and write header */
struct sb_header_t sb_hdr;
produce_sb_header(sb, &sb_hdr);
sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
write(fd, &sb_hdr, sizeof(sb_hdr));
/* produce and write section headers */
for(int i = 0; i < sb_hdr.nr_sections; i++)
{
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));
write(fd, &sb_sec_hdr, sizeof(sb_sec_hdr));
}
/* produce key dictionary */
/* produce sections data */
for(int i = 0; i< sb_hdr.nr_sections; i++)
{
/* produce tag command */
struct sb_instruction_tag_t tag_cmd;
produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
write(fd, &tag_cmd, sizeof(tag_cmd));
/* produce other commands */
for(int j = 0; j < sb->sections[i].nr_insts; j++)
{
struct sb_inst_t *inst = &sb->sections[i].insts[j];
/* command */
struct sb_instruction_common_t cmd;
produce_sb_instruction(inst, &cmd);
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
write(fd, &cmd, sizeof(cmd));
/* data */
if(inst->inst == SB_INST_LOAD)
{
sha_1_update(&file_sha1, inst->data, inst->size);
write(fd, inst->data, inst->size);
sha_1_update(&file_sha1, inst->padding, inst->padding_size);
write(fd, inst->padding, inst->padding_size);
}
}
}
/* write file SHA-1 */
byte final_sig[32];
sha_1_finish(&file_sha1);
sha_1_output(&file_sha1, final_sig);
generate_random_data(final_sig + 20, 12);
write(fd, final_sig, 32);
close(fd);
}
#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
{
uint8_t sum = 90;
byte *ptr = (byte *)hdr;
for(int i = 1; i < 16; i++)
sum += ptr[i];
return sum;
}
int main(int argc, const char **argv)
{
if(argc != 4)

View file

@ -99,6 +99,14 @@ struct sb_instruction_header_t
uint16_t flags;
} __attribute__((packed));
struct sb_instruction_common_t
{
struct sb_instruction_header_t hdr;
uint32_t addr;
uint32_t len;
uint32_t data;
} __attribute__((packed));
struct sb_instruction_load_t
{
struct sb_instruction_header_t hdr;

View file

@ -421,6 +421,14 @@ static void extract(unsigned long filesize)
printf(" Drive tag = ");
color(YELLOW);
printf("%x\n", sb_header->drive_tag);
color(GREEN);
printf(" First boot tag offset = ");
color(YELLOW);
printf("%x\n", sb_header->first_boot_tag_off);
color(GREEN);
printf(" First boot section ID = ");
color(YELLOW);
printf("0x%08x\n", sb_header->first_boot_sec_id);
/* encryption cbc-mac */
key_array_t keys = NULL; /* array of 16-bytes keys */
@ -504,7 +512,7 @@ static void extract(unsigned long filesize)
int pos = sec_hdr->offset * BLOCK_SIZE;
int size = sec_hdr->size * BLOCK_SIZE;
int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE);
int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT);
int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
color(GREEN);
printf(" Section ");
@ -547,9 +555,7 @@ static void extract(unsigned long filesize)
/* advanced raw mode */
color(BLUE);
printf("Commands\n");
uint32_t offset = sizeof(struct sb_header_t)
+ sizeof(struct sb_section_header_t) * sb_header->nr_sections
+ sizeof(struct sb_key_dictionary_entry_t) * sb_header->nr_keys;
uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE;
byte iv[16];
memcpy(iv, g_buf, 16);
const char *indent = " ";
@ -597,7 +603,7 @@ static void extract(unsigned long filesize)
int pos = offset;
int size = tag->len * BLOCK_SIZE;
int data_sec = !(tag->flags & SECTION_BOOTABLE);
int encrypted = !(tag->flags & SECTION_CLEARTEXT);
int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
color(GREEN);
printf("%sSection ", indent);
@ -653,19 +659,24 @@ static void extract(unsigned long filesize)
/* final signature */
color(BLUE);
printf("Final signature:\n");
color(GREEN);
printf(" Encrypted signature:\n");
color(YELLOW);
byte *encrypted_block = &g_buf[filesize - 32];
printf(" ");
print_hex(encrypted_block, 16, true);
printf(" ");
print_hex(encrypted_block + 16, 16, true);
/* decrypt it */
byte decrypted_block[32];
cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0);
if(sb_header->nr_keys > 0)
{
color(GREEN);
printf(" Encrypted SHA-1:\n");
color(YELLOW);
byte *encrypted_block = &g_buf[filesize - 32];
printf(" ");
print_hex(encrypted_block, 16, true);
printf(" ");
print_hex(encrypted_block + 16, 16, true);
/* decrypt it */
cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0);
}
else
memcpy(decrypted_block, &g_buf[filesize - 32], 32);
color(GREEN);
printf(" Decrypted SHA-1:\n ");
printf(" File SHA-1:\n ");
color(YELLOW);
print_hex(decrypted_block, 20, false);
/* check it */