sbinfo: move more things to sb.h, rewrite code to use structures instead of hardcoded offsets

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29723 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Amaury Pouly 2011-04-16 18:22:42 +00:00
parent d9b050ee2b
commit e4dd514e6f
2 changed files with 97 additions and 123 deletions

View file

@ -23,6 +23,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#define BLOCK_SIZE 16
struct sb_version_t
{
uint16_t major;
@ -56,6 +58,23 @@ struct sb_header_t
uint8_t rand_pad1[6]; /* Random padding */
} __attribute__((packed));
struct sb_section_header_t
{
uint32_t identifier;
uint32_t offset; /* In blocks */
uint32_t size; /* In blocks */
uint32_t flags;
} __attribute__((packed));
struct sb_key_dictionary_entry_t
{
uint8_t hdr_cbc_mac[16]; /* CBC-MAC of the header */
uint8_t key[16]; /* Actual AES Key (encrypted by the global key) */
} __attribute__((packed));
#define ROM_SECTION_BOOTABLE (1 << 0)
#define ROM_SECTION_CLEARTEXT (1 << 1)
#define SB_INST_NOP 0x0
#define SB_INST_TAG 0x1
#define SB_INST_LOAD 0x2
@ -64,9 +83,6 @@ struct sb_header_t
#define SB_INST_CALL 0x5
#define SB_INST_MODE 0x6
#define ROM_SECTION_BOOTABLE (1 << 0)
#define ROM_SECTION_CLEARTEXT (1 << 1)
struct sb_instruction_header_t
{
uint8_t checksum;

View file

@ -62,11 +62,6 @@ char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
#define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
/* byte swapping */
#define get32le(a) ((uint32_t) \
( g_buf[a+3] << 24 | g_buf[a+2] << 16 | g_buf[a+1] << 8 | g_buf[a] ))
#define get16le(a) ((uint16_t)( g_buf[a+1] << 8 | g_buf[a] ))
/* all blocks are sized as a multiple of 0x1ff */
#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
@ -88,63 +83,12 @@ void *xmalloc(size_t s) /* malloc helper, used in elf.c */
return r;
}
static char getchr(int offset)
static void print_hex(byte *data, int len, bool newline)
{
char c;
c = g_buf[offset];
return isprint(c) ? c : '_';
}
static void getstrle(char string[], int offset)
{
int i;
for (i = 0; i < 4; i++)
string[i] = getchr(offset + 3 - i);
string[4] = 0;
}
static void getstrbe(char string[], int offset)
{
int i;
for (i = 0; i < 4; i++)
string[i] = getchr(offset + i);
string[4] = 0;
}
static void printhex(int offset, int len)
{
int i;
for (i = 0; i < len; i++)
printf("%02X ", g_buf[offset + i]);
printf("\n");
}
static void print_key(byte key[16])
{
for(int i = 0; i < 16; i++)
printf("%02X ", key[i]);
}
static void print_sha1(byte sha[20])
{
for(int i = 0; i < 20; i++)
printf("%02X ", sha[i]);
}
/* verify the firmware header */
static void check(unsigned long filesize)
{
/* check STMP marker */
char stmp[5];
getstrbe(stmp, 0x14);
assert(strcmp(stmp, "STMP") == 0);
color(GREEN);
/* get total size */
unsigned long totalsize = 16 * get32le(0x1C);
color(GREEN);
assert(filesize == totalsize);
for(int i = 0; i < len; i++)
printf("%02X ", data[i]);
if(newline)
printf("\n");
}
int convxdigit(char digit, byte *val)
@ -373,17 +317,31 @@ static void extract(unsigned long filesize)
{
struct sha_1_params_t sha_1_params;
/* Basic header info */
struct sb_header_t *sb_header = (struct sb_header_t *)g_buf;
if(memcmp(sb_header->signature, "STMP", 4) != 0)
bugp("Bad signature");
if(sb_header->image_size * BLOCK_SIZE != filesize)
bugp("File size mismatch");
if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
bugp("Bad header size");
if(sb_header->major_ver != 1 || sb_header->minor_ver != 1)
bugp("Bad file format version");
if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
bugp("Bad section header size");
color(BLUE);
printf("Basic info:\n");
color(GREEN);
printf(" Header SHA-1: ");
byte *hdr_sha1 = &g_buf[0];
byte *hdr_sha1 = sb_header->sha1_header;
color(YELLOW);
print_sha1(hdr_sha1);
print_hex(hdr_sha1, 20, false);
/* Check SHA1 sum */
byte computed_sha1[20];
sha_1_init(&sha_1_params);
sha_1_update(&sha_1_params, &g_buf[0x14], 0x4C);
sha_1_update(&sha_1_params, &sb_header->signature[0],
sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header));
sha_1_finish(&sha_1_params);
sha_1_output(&sha_1_params, computed_sha1);
color(RED);
@ -394,7 +352,7 @@ static void extract(unsigned long filesize)
color(GREEN);
printf(" Flags: ");
color(YELLOW);
printhex(0x18, 4);
printf("%x\n", sb_header->flags);
color(GREEN);
printf(" Total file size : ");
color(YELLOW);
@ -404,15 +362,13 @@ static void extract(unsigned long filesize)
color(BLUE);
printf("Sizes and offsets:\n");
color(GREEN);
int num_enc = get16le(0x28);
printf(" # of encryption keys = ");
color(YELLOW);
printf("%d\n", num_enc);
printf("%d\n", sb_header->nr_keys);
color(GREEN);
int num_chunks = get16le(0x2E);
printf(" # of chunk headers = ");
printf(" # of sections = ");
color(YELLOW);
printf("%d\n", num_chunks);
printf("%d\n", sb_header->nr_sections);
/* Versions */
color(BLUE);
@ -421,15 +377,13 @@ static void extract(unsigned long filesize)
printf(" Random 1: ");
color(YELLOW);
printhex(0x32, 6);
print_hex(sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true);
color(GREEN);
printf(" Random 2: ");
color(YELLOW);
printhex(0x5A, 6);
print_hex(sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true);
uint64_t micros_l = get32le(0x38);
uint64_t micros_h = get32le(0x3c);
uint64_t micros = ((uint64_t)micros_h << 32) | micros_l;
uint64_t micros = sb_header->timestamp;
time_t seconds = (micros / (uint64_t)1000000L);
seconds += 946684800; /* 2000/1/1 0:00:00 */
struct tm *time = gmtime(&seconds);
@ -438,69 +392,66 @@ static void extract(unsigned long filesize)
color(YELLOW);
printf("%s", asctime(time));
int p_maj = get32le(0x40);
int p_min = get32le(0x44);
int p_sub = get32le(0x48);
int c_maj = get32le(0x4C);
int c_min = get32le(0x50);
int c_sub = get32le(0x54);
color(GREEN);
printf(" Product version = ");
color(YELLOW);
printf("%X.%X.%X\n", p_maj, p_min, p_sub);
printf("%X.%X.%X\n", sb_header->product_ver.major,
sb_header->product_ver.minor, sb_header->product_ver.revision);
color(GREEN);
printf(" Component version = ");
color(YELLOW);
printf("%X.%X.%X\n", c_maj, c_min, c_sub);
printf("%X.%X.%X\n", sb_header->component_ver.major,
sb_header->component_ver.minor, sb_header->component_ver.revision);
/* encryption cbc-mac */
key_array_t keys = NULL; /* array of 16-bytes keys */
byte real_key[16];
if(num_enc > 0)
if(sb_header->nr_keys > 0)
{
keys = read_keys(num_enc);
keys = read_keys(sb_header->nr_keys);
color(BLUE);
printf("Encryption data\n");
for(int i = 0; i < num_enc; i++)
for(int i = 0; i < sb_header->nr_keys; i++)
{
color(RED);
printf(" Key %d: ", i);
print_key(keys[i]);
printf("\n");
print_hex(keys[i], 16, true);
color(GREEN);
printf(" CBC-MAC of headers: ");
/* copy the cbc mac */
byte hdr_cbc_mac[16];
memcpy(hdr_cbc_mac, &g_buf[0x60 + 16 * num_chunks + 32 * i], 16);
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 *)&g_buf[ofs];
/* cbc mac */
color(YELLOW);
print_key(hdr_cbc_mac);
print_hex(dict_entry->hdr_cbc_mac, 16, false);
/* check it */
byte computed_cbc_mac[16];
byte zero[16];
memset(zero, 0, 16);
cbc_mac(g_buf, NULL, 6 + num_chunks, keys[i], zero, &computed_cbc_mac, 1);
cbc_mac(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
keys[i], zero, &computed_cbc_mac, 1);
color(RED);
if(memcmp(hdr_cbc_mac, computed_cbc_mac, 16) == 0)
if(memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0)
printf(" Ok\n");
else
printf(" Failed\n");
color(GREEN);
printf(" Encrypted key : ");
byte (*encrypted_key)[16];
encrypted_key = (key_array_t)&g_buf[0x60 + 16 * num_chunks + 32 * i + 16];
color(YELLOW);
print_key(*encrypted_key);
printf("\n");
print_hex(dict_entry->key, 16, true);
color(GREEN);
/* decrypt */
byte decrypted_key[16];
byte iv[16];
memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
cbc_mac(*encrypted_key, decrypted_key, 1, keys[i], iv, NULL, 0);
cbc_mac(dict_entry->key, decrypted_key, 1, keys[i], iv, NULL, 0);
printf(" Decrypted key : ");
color(YELLOW);
print_key(decrypted_key);
print_hex(decrypted_key, 16, false);
/* cross-check or copy */
if(i == 0)
memcpy(real_key, decrypted_key, 16);
@ -518,20 +469,28 @@ static void extract(unsigned long filesize)
}
}
/* chunks */
/* sections */
color(BLUE);
printf("Chunks\n");
printf("Sections\n");
for (int i = 0; i < num_chunks; i++) {
uint32_t ofs = 0x60 + (i * 16);
for(int i = 0; i < sb_header->nr_sections; i++)
{
uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t);
struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&g_buf[ofs];
char name[5];
getstrle(name, ofs + 0);
int pos = 16 * get32le(ofs + 4);
int size = 16 * get32le(ofs + 8);
int flags = get32le(ofs + 12);
int data_sec = !(flags & ROM_SECTION_BOOTABLE);
int encrypted = !(flags & ROM_SECTION_CLEARTEXT);
name[0] = (sec_hdr->identifier >> 24) & 0xff;
name[1] = (sec_hdr->identifier >> 16) & 0xff;
name[2] = (sec_hdr->identifier >> 8) & 0xff;
name[3] = sec_hdr->identifier & 0xff;
for(int i = 0; i < 4; i++)
if(!isprint(name[i]))
name[i] = '_';
name[4] = 0;
int pos = sec_hdr->offset * BLOCK_SIZE;
int size = sec_hdr->size * BLOCK_SIZE;
int data_sec = !(sec_hdr->flags & ROM_SECTION_BOOTABLE);
int encrypted = !(sec_hdr->flags & ROM_SECTION_CLEARTEXT);
color(GREEN);
printf(" Chunk ");
@ -548,7 +507,7 @@ static void extract(unsigned long filesize)
color(GREEN);
printf(" flags = ");
color(YELLOW);
printf("%8x", flags);
printf("%8x", sec_hdr->flags);
color(RED);
if(data_sec)
printf(" Data Section");
@ -561,7 +520,7 @@ static void extract(unsigned long filesize)
/* save it */
byte *sec = xmalloc(size);
if(encrypted)
cbc_mac(g_buf + pos, sec, size / 16, real_key, g_buf, NULL, 0);
cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0);
else
memcpy(sec, g_buf + pos, size);
@ -575,18 +534,18 @@ static void extract(unsigned long filesize)
color(GREEN);
printf(" Encrypted signature:\n");
color(YELLOW);
printf(" ");
printhex(filesize - 32, 16);
printf(" ");
printhex(filesize - 16, 16);
/* decrypt it */
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);
color(GREEN);
printf(" Decrypted SHA-1:\n ");
color(YELLOW);
print_sha1(decrypted_block);
print_hex(decrypted_block, 20, false);
/* check it */
sha_1_init(&sha_1_params);
sha_1_update(&sha_1_params, g_buf, filesize - 32);
@ -626,8 +585,7 @@ int main(int argc, const char **argv)
close(fd);
check(st.st_size); /* verify header and checksums */
extract(st.st_size); /* split in blocks */
extract(st.st_size);
color(OFF);