1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2010 Bertrik Sikken
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * .sb file parser and chunk extractor
25 * Based on amsinfo, which is
26 * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com>
29 #define _ISOC99_SOURCE /* snprintf() */
31 #include <sys/types.h>
47 #if 1 /* ANSI colors */
49 # define color(a) printf("%s",a)
50 char OFF
[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
52 char GREY
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
53 char RED
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
54 char GREEN
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
55 char YELLOW
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
56 char BLUE
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
63 #define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
64 #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
66 /* all blocks are sized as a multiple of 0x1ff */
67 #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
69 /* If you find a firmware that breaks the known format ^^ */
70 #define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0)
74 size_t g_sz
; /* file size */
75 uint8_t *g_buf
; /* file content */
76 #define PREFIX_SIZE 128
77 char out_prefix
[PREFIX_SIZE
];
80 char *s_getenv(const char *name
)
82 char *s
= getenv(name
);
86 void *xmalloc(size_t s
) /* malloc helper, used in elf.c */
89 if(!r
) bugp("malloc");
93 static void print_hex(byte
*data
, int len
, bool newline
)
95 for(int i
= 0; i
< len
; i
++)
96 printf("%02X ", data
[i
]);
101 static int convxdigit(char digit
, byte
*val
)
103 if(digit
>= '0' && digit
<= '9')
108 else if(digit
>= 'A' && digit
<= 'F')
110 *val
= digit
- 'A' + 10;
113 else if(digit
>= 'a' && digit
<= 'f')
115 *val
= digit
- 'a' + 10;
122 typedef byte (*key_array_t
)[16];
124 static key_array_t
read_keys(int num_keys
)
128 int fd
= open(key_file
,O_RDONLY
);
130 bugp("opening key file failed");
131 if(fstat(fd
,&st
) == -1)
132 bugp("key file stat() failed");
134 char *buf
= xmalloc(size
);
135 if(read(fd
, buf
, size
) != (ssize_t
)size
)
136 bugp("reading key file");
139 key_array_t keys
= xmalloc(sizeof(byte
[16]) * num_keys
);
141 for(int i
= 0; i
< num_keys
; i
++)
144 while(pos
< size
&& isspace(buf
[pos
]))
147 if((pos
+ 32) > size
)
148 bugp("invalid key file (not enough keys)");
149 for(int j
= 0; j
< 16; j
++)
152 if(convxdigit(buf
[pos
+ 2 * j
], &a
) || convxdigit(buf
[pos
+ 2 * j
+ 1], &b
))
153 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
154 keys
[i
][j
] = (a
<< 4) | b
;
163 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
165 static uint8_t instruction_checksum(struct sb_instruction_header_t
*hdr
)
168 byte
*ptr
= (byte
*)hdr
;
169 for(int i
= 1; i
< 16; i
++)
174 static void elf_write(void *user
, uint32_t addr
, const void *buf
, size_t count
)
177 fseek(f
, addr
, SEEK_SET
);
178 fwrite(buf
, count
, 1, f
);
181 static void extract_elf_section(struct elf_params_t
*elf
, int count
, const char *prefix
,
184 char *filename
= xmalloc(strlen(prefix
) + 32);
185 sprintf(filename
, "%s.%d.elf", prefix
, count
);
186 printf("%swrite %s\n", indent
, filename
);
188 FILE *fd
= fopen(filename
, "wb");
193 elf_write_file(elf
, elf_write
, fd
);
197 static void extract_section(int data_sec
, char name
[5], byte
*buf
, int size
, const char *indent
)
199 char filename
[PREFIX_SIZE
+ 32];
200 snprintf(filename
, sizeof filename
, "%s%s.bin", out_prefix
, name
);
201 FILE *fd
= fopen(filename
, "wb");
203 fwrite(buf
, size
, 1, fd
);
209 snprintf(filename
, sizeof filename
, "%s%s", out_prefix
, name
);
211 /* elf construction */
212 struct elf_params_t elf
;
215 /* Pretty print the content */
219 struct sb_instruction_header_t
*hdr
= (struct sb_instruction_header_t
*)&buf
[pos
];
220 printf("%s", indent
);
221 uint8_t checksum
= instruction_checksum(hdr
);
222 if(checksum
!= hdr
->checksum
)
225 printf("[Bad checksum]");
228 if(hdr
->opcode
== SB_INST_LOAD
)
230 struct sb_instruction_load_t
*load
= (struct sb_instruction_load_t
*)&buf
[pos
];
233 color(OFF
);printf(" | ");
235 printf("addr=0x%08x", load
->addr
);
236 color(OFF
);printf(" | ");
238 printf("len=0x%08x", load
->len
);
239 color(OFF
);printf(" | ");
241 printf("crc=0x%08x", load
->crc
);
242 /* data is padded to 16-byte boundary with random data and crc'ed with it */
243 uint32_t computed_crc
= crc(&buf
[pos
+ sizeof(struct sb_instruction_load_t
)],
244 ROUND_UP(load
->len
, 16));
246 if(load
->crc
== computed_crc
)
249 printf(" Failed (crc=0x%08x)\n", computed_crc
);
251 /* elf construction */
252 elf_add_load_section(&elf
, load
->addr
, load
->len
,
253 &buf
[pos
+ sizeof(struct sb_instruction_load_t
)]);
255 pos
+= load
->len
+ sizeof(struct sb_instruction_load_t
);
256 // unsure about rounding
257 pos
= ROUND_UP(pos
, 16);
259 else if(hdr
->opcode
== SB_INST_FILL
)
261 struct sb_instruction_fill_t
*fill
= (struct sb_instruction_fill_t
*)&buf
[pos
];
264 color(OFF
);printf(" | ");
266 printf("addr=0x%08x", fill
->addr
);
267 color(OFF
);printf(" | ");
269 printf("len=0x%08x", fill
->len
);
270 color(OFF
);printf(" | ");
272 printf("pattern=0x%08x\n", fill
->pattern
);
275 /* elf construction */
276 elf_add_fill_section(&elf
, fill
->addr
, fill
->len
, fill
->pattern
);
278 pos
+= sizeof(struct sb_instruction_fill_t
);
279 // fixme: useless as pos is a multiple of 16 and fill struct is 4-bytes wide ?
280 pos
= ROUND_UP(pos
, 16);
282 else if(hdr
->opcode
== SB_INST_CALL
||
283 hdr
->opcode
== SB_INST_JUMP
)
285 int is_call
= (hdr
->opcode
== SB_INST_CALL
);
286 struct sb_instruction_call_t
*call
= (struct sb_instruction_call_t
*)&buf
[pos
];
292 color(OFF
);printf(" | ");
294 printf("addr=0x%08x", call
->addr
);
295 color(OFF
);printf(" | ");
297 printf("arg=0x%08x\n", call
->arg
);
300 /* elf construction */
301 elf_set_start_addr(&elf
, call
->addr
);
302 extract_elf_section(&elf
, elf_count
++, filename
, indent
);
306 pos
+= sizeof(struct sb_instruction_call_t
);
307 // fixme: useless as pos is a multiple of 16 and call struct is 4-bytes wide ?
308 pos
= ROUND_UP(pos
, 16);
313 printf("Unknown instruction %d at address 0x%08lx\n", hdr
->opcode
, (unsigned long)pos
);
318 if(!elf_is_empty(&elf
))
319 extract_elf_section(&elf
, elf_count
++, filename
, indent
);
323 void fill_section_name(char name
[5], uint32_t identifier
)
325 name
[0] = (identifier
>> 24) & 0xff;
326 name
[1] = (identifier
>> 16) & 0xff;
327 name
[2] = (identifier
>> 8) & 0xff;
328 name
[3] = identifier
& 0xff;
329 for(int i
= 0; i
< 4; i
++)
330 if(!isprint(name
[i
]))
335 static void extract(unsigned long filesize
)
337 struct sha_1_params_t sha_1_params
;
338 /* Basic header info */
339 struct sb_header_t
*sb_header
= (struct sb_header_t
*)g_buf
;
341 if(memcmp(sb_header
->signature
, "STMP", 4) != 0)
342 bugp("Bad signature");
343 if(sb_header
->image_size
* BLOCK_SIZE
!= filesize
)
344 bugp("File size mismatch");
345 if(sb_header
->header_size
* BLOCK_SIZE
!= sizeof(struct sb_header_t
))
346 bugp("Bad header size");
347 if((sb_header
->major_ver
!= IMAGE_MAJOR_VERSION
||
348 sb_header
->minor_ver
!= IMAGE_MINOR_VERSION
) && strcasecmp(s_getenv("SB_IGNORE_VER"), "YES"))
349 bugp("Bad file format version");
350 if(sb_header
->sec_hdr_size
* BLOCK_SIZE
!= sizeof(struct sb_section_header_t
))
351 bugp("Bad section header size");
354 printf("Basic info:\n");
356 printf(" Header SHA-1: ");
357 byte
*hdr_sha1
= sb_header
->sha1_header
;
359 print_hex(hdr_sha1
, 20, false);
361 byte computed_sha1
[20];
362 sha_1_init(&sha_1_params
);
363 sha_1_update(&sha_1_params
, &sb_header
->signature
[0],
364 sizeof(struct sb_header_t
) - sizeof(sb_header
->sha1_header
));
365 sha_1_finish(&sha_1_params
);
366 sha_1_output(&sha_1_params
, computed_sha1
);
368 if(memcmp(hdr_sha1
, computed_sha1
, 20) == 0)
375 printf("%x\n", sb_header
->flags
);
377 printf(" Total file size : ");
379 printf("%ld\n", filesize
);
381 /* Sizes and offsets */
383 printf("Sizes and offsets:\n");
385 printf(" # of encryption keys = ");
387 printf("%d\n", sb_header
->nr_keys
);
389 printf(" # of sections = ");
391 printf("%d\n", sb_header
->nr_sections
);
395 printf("Versions\n");
398 printf(" Random 1: ");
400 print_hex(sb_header
->rand_pad0
, sizeof(sb_header
->rand_pad0
), true);
402 printf(" Random 2: ");
404 print_hex(sb_header
->rand_pad1
, sizeof(sb_header
->rand_pad1
), true);
406 uint64_t micros
= sb_header
->timestamp
;
407 time_t seconds
= (micros
/ (uint64_t)1000000L);
408 struct tm tm_base
= {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL
}; /* 2000/1/1 0:00:00 */
409 seconds
+= mktime(&tm_base
);
410 struct tm
*time
= gmtime(&seconds
);
412 printf(" Creation date/time = ");
414 printf("%s", asctime(time
));
417 printf(" Product version = ");
419 printf("%X.%X.%X\n", sb_header
->product_ver
.major
,
420 sb_header
->product_ver
.minor
, sb_header
->product_ver
.revision
);
422 printf(" Component version = ");
424 printf("%X.%X.%X\n", sb_header
->component_ver
.major
,
425 sb_header
->component_ver
.minor
, sb_header
->component_ver
.revision
);
428 printf(" Drive tag = ");
430 printf("%x\n", sb_header
->drive_tag
);
432 printf(" First boot tag offset = ");
434 printf("%x\n", sb_header
->first_boot_tag_off
);
436 printf(" First boot section ID = ");
438 printf("0x%08x\n", sb_header
->first_boot_sec_id
);
440 /* encryption cbc-mac */
441 key_array_t keys
= NULL
; /* array of 16-bytes keys */
443 if(sb_header
->nr_keys
> 0)
445 keys
= read_keys(sb_header
->nr_keys
);
447 printf("Encryption data\n");
448 for(int i
= 0; i
< sb_header
->nr_keys
; i
++)
451 printf(" Key %d: ", i
);
452 print_hex(keys
[i
], 16, true);
454 printf(" CBC-MAC of headers: ");
456 uint32_t ofs
= sizeof(struct sb_header_t
)
457 + sizeof(struct sb_section_header_t
) * sb_header
->nr_sections
458 + sizeof(struct sb_key_dictionary_entry_t
) * i
;
459 struct sb_key_dictionary_entry_t
*dict_entry
=
460 (struct sb_key_dictionary_entry_t
*)&g_buf
[ofs
];
463 print_hex(dict_entry
->hdr_cbc_mac
, 16, false);
465 byte computed_cbc_mac
[16];
468 cbc_mac(g_buf
, NULL
, sb_header
->header_size
+ sb_header
->nr_sections
,
469 keys
[i
], zero
, &computed_cbc_mac
, 1);
471 if(memcmp(dict_entry
->hdr_cbc_mac
, computed_cbc_mac
, 16) == 0)
477 printf(" Encrypted key : ");
479 print_hex(dict_entry
->key
, 16, true);
482 byte decrypted_key
[16];
484 memcpy(iv
, g_buf
, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
485 cbc_mac(dict_entry
->key
, decrypted_key
, 1, keys
[i
], iv
, NULL
, 0);
486 printf(" Decrypted key : ");
488 print_hex(decrypted_key
, 16, false);
489 /* cross-check or copy */
491 memcpy(real_key
, decrypted_key
, 16);
492 else if(memcmp(real_key
, decrypted_key
, 16) == 0)
495 printf(" Cross-Check Ok");
500 printf(" Cross-Check Failed");
507 if(strcasecmp(s_getenv("SB_RAW_CMD"), "YES") != 0)
510 printf("Sections\n");
511 for(int i
= 0; i
< sb_header
->nr_sections
; i
++)
513 uint32_t ofs
= sb_header
->header_size
* BLOCK_SIZE
+ i
* sizeof(struct sb_section_header_t
);
514 struct sb_section_header_t
*sec_hdr
= (struct sb_section_header_t
*)&g_buf
[ofs
];
517 fill_section_name(name
, sec_hdr
->identifier
);
518 int pos
= sec_hdr
->offset
* BLOCK_SIZE
;
519 int size
= sec_hdr
->size
* BLOCK_SIZE
;
520 int data_sec
= !(sec_hdr
->flags
& SECTION_BOOTABLE
);
521 int encrypted
= !(sec_hdr
->flags
& SECTION_CLEARTEXT
) && sb_header
->nr_keys
> 0;
526 printf("'%s'\n", name
);
530 printf("%8x - %8x\n", pos
, pos
+size
);
534 printf("%8x\n", size
);
538 printf("%8x", sec_hdr
->flags
);
541 printf(" Data Section");
543 printf(" Boot Section");
545 printf(" (Encrypted)");
549 byte
*sec
= xmalloc(size
);
551 cbc_mac(g_buf
+ pos
, sec
, size
/ BLOCK_SIZE
, real_key
, g_buf
, NULL
, 0);
553 memcpy(sec
, g_buf
+ pos
, size
);
555 extract_section(data_sec
, name
, sec
, size
, " ");
561 /* advanced raw mode */
563 printf("Commands\n");
564 uint32_t offset
= sb_header
->first_boot_tag_off
* BLOCK_SIZE
;
566 memcpy(iv
, g_buf
, 16);
567 const char *indent
= " ";
571 if(sb_header
->nr_keys
> 0)
572 cbc_mac(g_buf
+ offset
, cmd
, 1, real_key
, iv
, &iv
, 0);
574 memcpy(cmd
, g_buf
+ offset
, BLOCK_SIZE
);
575 struct sb_instruction_header_t
*hdr
= (struct sb_instruction_header_t
*)cmd
;
576 printf("%s", indent
);
577 uint8_t checksum
= instruction_checksum(hdr
);
578 if(checksum
!= hdr
->checksum
)
581 printf("[Bad checksum]");
584 if(hdr
->opcode
== SB_INST_NOP
)
588 offset
+= BLOCK_SIZE
;
590 else if(hdr
->opcode
== SB_INST_TAG
)
592 struct sb_instruction_tag_t
*tag
= (struct sb_instruction_tag_t
*)hdr
;
595 color(OFF
);printf(" | ");
597 printf("sec=0x%08x", tag
->identifier
);
598 color(OFF
);printf(" | ");
600 printf("cnt=0x%08x", tag
->len
);
601 color(OFF
);printf(" | ");
603 printf("flg=0x%08x\n", tag
->flags
);
605 offset
+= sizeof(struct sb_instruction_tag_t
);
608 fill_section_name(name
, tag
->identifier
);
610 int size
= tag
->len
* BLOCK_SIZE
;
611 int data_sec
= !(tag
->flags
& SECTION_BOOTABLE
);
612 int encrypted
= !(tag
->flags
& SECTION_CLEARTEXT
) && sb_header
->nr_keys
> 0;
615 printf("%sSection ", indent
);
617 printf("'%s'\n", name
);
619 printf("%s pos = ", indent
);
621 printf("%8x - %8x\n", pos
, pos
+size
);
623 printf("%s len = ", indent
);
625 printf("%8x\n", size
);
627 printf("%s flags = ", indent
);
629 printf("%8x", tag
->flags
);
632 printf(" Data Section");
634 printf(" Boot Section");
636 printf(" (Encrypted)");
640 byte
*sec
= xmalloc(size
);
642 cbc_mac(g_buf
+ pos
, sec
, size
/ BLOCK_SIZE
, real_key
, g_buf
, NULL
, 0);
644 memcpy(sec
, g_buf
+ pos
, size
);
646 extract_section(data_sec
, name
, sec
, size
, " ");
650 if(tag
->hdr
.flags
& SB_INST_LAST_TAG
)
653 /* restart with IV */
654 memcpy(iv
, g_buf
, 16);
659 printf("Unknown instruction %d at address 0x%08lx\n", hdr
->opcode
, (long)offset
);
665 /* final signature */
667 printf("Final signature:\n");
668 byte decrypted_block
[32];
669 if(sb_header
->nr_keys
> 0)
672 printf(" Encrypted SHA-1:\n");
674 byte
*encrypted_block
= &g_buf
[filesize
- 32];
676 print_hex(encrypted_block
, 16, true);
678 print_hex(encrypted_block
+ 16, 16, true);
680 cbc_mac(encrypted_block
, decrypted_block
, 2, real_key
, g_buf
, NULL
, 0);
683 memcpy(decrypted_block
, &g_buf
[filesize
- 32], 32);
685 printf(" File SHA-1:\n ");
687 print_hex(decrypted_block
, 20, false);
689 sha_1_init(&sha_1_params
);
690 sha_1_update(&sha_1_params
, g_buf
, filesize
- 32);
691 sha_1_finish(&sha_1_params
);
692 sha_1_output(&sha_1_params
, computed_sha1
);
694 if(memcmp(decrypted_block
, computed_sha1
, 20) == 0)
700 int main(int argc
, const char **argv
)
704 if(argc
!= 3 && argc
!= 4)
706 printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv
);
707 printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n");
712 snprintf(out_prefix
, PREFIX_SIZE
, "%s", argv
[3]);
714 strcpy(out_prefix
, "");
716 if( (fd
= open(argv
[1], O_RDONLY
)) == -1 )
717 bugp("opening firmware failed");
721 if(fstat(fd
, &st
) == -1)
722 bugp("firmware stat() failed");
725 g_buf
= xmalloc(g_sz
);
726 if(read(fd
, g_buf
, g_sz
) != (ssize_t
)g_sz
) /* load the whole file into memory */
727 bugp("reading firmware");