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);
310 else if(hdr
->opcode
== SB_INST_MODE
)
312 struct sb_instruction_mode_t
*mode
= (struct sb_instruction_mode_t
*)hdr
;
315 color(OFF
);printf(" | ");
317 printf("mod=0x%08x\n", mode
->mode
);
319 pos
+= sizeof(struct sb_instruction_mode_t
);
324 printf("Unknown instruction %d at address 0x%08lx\n", hdr
->opcode
, (unsigned long)pos
);
329 if(!elf_is_empty(&elf
))
330 extract_elf_section(&elf
, elf_count
++, filename
, indent
);
334 void fill_section_name(char name
[5], uint32_t identifier
)
336 name
[0] = (identifier
>> 24) & 0xff;
337 name
[1] = (identifier
>> 16) & 0xff;
338 name
[2] = (identifier
>> 8) & 0xff;
339 name
[3] = identifier
& 0xff;
340 for(int i
= 0; i
< 4; i
++)
341 if(!isprint(name
[i
]))
346 static void extract(unsigned long filesize
)
348 struct sha_1_params_t sha_1_params
;
349 /* Basic header info */
350 struct sb_header_t
*sb_header
= (struct sb_header_t
*)g_buf
;
352 if(memcmp(sb_header
->signature
, "STMP", 4) != 0)
353 bugp("Bad signature");
354 if(sb_header
->image_size
* BLOCK_SIZE
!= filesize
)
355 bugp("File size mismatch");
356 if(sb_header
->header_size
* BLOCK_SIZE
!= sizeof(struct sb_header_t
))
357 bugp("Bad header size");
358 if((sb_header
->major_ver
!= IMAGE_MAJOR_VERSION
||
359 sb_header
->minor_ver
!= IMAGE_MINOR_VERSION
) && strcasecmp(s_getenv("SB_IGNORE_VER"), "YES"))
360 bugp("Bad file format version");
361 if(sb_header
->sec_hdr_size
* BLOCK_SIZE
!= sizeof(struct sb_section_header_t
))
362 bugp("Bad section header size");
365 printf("Basic info:\n");
367 printf(" Header SHA-1: ");
368 byte
*hdr_sha1
= sb_header
->sha1_header
;
370 print_hex(hdr_sha1
, 20, false);
372 byte computed_sha1
[20];
373 sha_1_init(&sha_1_params
);
374 sha_1_update(&sha_1_params
, &sb_header
->signature
[0],
375 sizeof(struct sb_header_t
) - sizeof(sb_header
->sha1_header
));
376 sha_1_finish(&sha_1_params
);
377 sha_1_output(&sha_1_params
, computed_sha1
);
379 if(memcmp(hdr_sha1
, computed_sha1
, 20) == 0)
386 printf("%x\n", sb_header
->flags
);
388 printf(" Total file size : ");
390 printf("%ld\n", filesize
);
392 /* Sizes and offsets */
394 printf("Sizes and offsets:\n");
396 printf(" # of encryption keys = ");
398 printf("%d\n", sb_header
->nr_keys
);
400 printf(" # of sections = ");
402 printf("%d\n", sb_header
->nr_sections
);
406 printf("Versions\n");
409 printf(" Random 1: ");
411 print_hex(sb_header
->rand_pad0
, sizeof(sb_header
->rand_pad0
), true);
413 printf(" Random 2: ");
415 print_hex(sb_header
->rand_pad1
, sizeof(sb_header
->rand_pad1
), true);
417 uint64_t micros
= sb_header
->timestamp
;
418 time_t seconds
= (micros
/ (uint64_t)1000000L);
419 struct tm tm_base
= {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL
}; /* 2000/1/1 0:00:00 */
420 seconds
+= mktime(&tm_base
);
421 struct tm
*time
= gmtime(&seconds
);
423 printf(" Creation date/time = ");
425 printf("%s", asctime(time
));
428 printf(" Product version = ");
430 printf("%X.%X.%X\n", sb_header
->product_ver
.major
,
431 sb_header
->product_ver
.minor
, sb_header
->product_ver
.revision
);
433 printf(" Component version = ");
435 printf("%X.%X.%X\n", sb_header
->component_ver
.major
,
436 sb_header
->component_ver
.minor
, sb_header
->component_ver
.revision
);
439 printf(" Drive tag = ");
441 printf("%x\n", sb_header
->drive_tag
);
443 printf(" First boot tag offset = ");
445 printf("%x\n", sb_header
->first_boot_tag_off
);
447 printf(" First boot section ID = ");
449 printf("0x%08x\n", sb_header
->first_boot_sec_id
);
451 /* encryption cbc-mac */
452 key_array_t keys
= NULL
; /* array of 16-bytes keys */
454 if(sb_header
->nr_keys
> 0)
456 keys
= read_keys(sb_header
->nr_keys
);
458 printf("Encryption data\n");
459 for(int i
= 0; i
< sb_header
->nr_keys
; i
++)
462 printf(" Key %d: ", i
);
463 print_hex(keys
[i
], 16, true);
465 printf(" CBC-MAC of headers: ");
467 uint32_t ofs
= sizeof(struct sb_header_t
)
468 + sizeof(struct sb_section_header_t
) * sb_header
->nr_sections
469 + sizeof(struct sb_key_dictionary_entry_t
) * i
;
470 struct sb_key_dictionary_entry_t
*dict_entry
=
471 (struct sb_key_dictionary_entry_t
*)&g_buf
[ofs
];
474 print_hex(dict_entry
->hdr_cbc_mac
, 16, false);
476 byte computed_cbc_mac
[16];
479 cbc_mac(g_buf
, NULL
, sb_header
->header_size
+ sb_header
->nr_sections
,
480 keys
[i
], zero
, &computed_cbc_mac
, 1);
482 if(memcmp(dict_entry
->hdr_cbc_mac
, computed_cbc_mac
, 16) == 0)
488 printf(" Encrypted key : ");
490 print_hex(dict_entry
->key
, 16, true);
493 byte decrypted_key
[16];
495 memcpy(iv
, g_buf
, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
496 cbc_mac(dict_entry
->key
, decrypted_key
, 1, keys
[i
], iv
, NULL
, 0);
497 printf(" Decrypted key : ");
499 print_hex(decrypted_key
, 16, false);
500 /* cross-check or copy */
502 memcpy(real_key
, decrypted_key
, 16);
503 else if(memcmp(real_key
, decrypted_key
, 16) == 0)
506 printf(" Cross-Check Ok");
511 printf(" Cross-Check Failed");
518 if(strcasecmp(s_getenv("SB_RAW_CMD"), "YES") != 0)
521 printf("Sections\n");
522 for(int i
= 0; i
< sb_header
->nr_sections
; i
++)
524 uint32_t ofs
= sb_header
->header_size
* BLOCK_SIZE
+ i
* sizeof(struct sb_section_header_t
);
525 struct sb_section_header_t
*sec_hdr
= (struct sb_section_header_t
*)&g_buf
[ofs
];
528 fill_section_name(name
, sec_hdr
->identifier
);
529 int pos
= sec_hdr
->offset
* BLOCK_SIZE
;
530 int size
= sec_hdr
->size
* BLOCK_SIZE
;
531 int data_sec
= !(sec_hdr
->flags
& SECTION_BOOTABLE
);
532 int encrypted
= !(sec_hdr
->flags
& SECTION_CLEARTEXT
) && sb_header
->nr_keys
> 0;
537 printf("'%s'\n", name
);
541 printf("%8x - %8x\n", pos
, pos
+size
);
545 printf("%8x\n", size
);
549 printf("%8x", sec_hdr
->flags
);
552 printf(" Data Section");
554 printf(" Boot Section");
556 printf(" (Encrypted)");
560 byte
*sec
= xmalloc(size
);
562 cbc_mac(g_buf
+ pos
, sec
, size
/ BLOCK_SIZE
, real_key
, g_buf
, NULL
, 0);
564 memcpy(sec
, g_buf
+ pos
, size
);
566 extract_section(data_sec
, name
, sec
, size
, " ");
572 /* advanced raw mode */
574 printf("Commands\n");
575 uint32_t offset
= sb_header
->first_boot_tag_off
* BLOCK_SIZE
;
577 memcpy(iv
, g_buf
, 16);
578 const char *indent
= " ";
582 if(sb_header
->nr_keys
> 0)
583 cbc_mac(g_buf
+ offset
, cmd
, 1, real_key
, iv
, &iv
, 0);
585 memcpy(cmd
, g_buf
+ offset
, BLOCK_SIZE
);
586 struct sb_instruction_header_t
*hdr
= (struct sb_instruction_header_t
*)cmd
;
587 printf("%s", indent
);
588 uint8_t checksum
= instruction_checksum(hdr
);
589 if(checksum
!= hdr
->checksum
)
592 printf("[Bad checksum]");
595 if(hdr
->opcode
== SB_INST_NOP
)
599 offset
+= BLOCK_SIZE
;
601 else if(hdr
->opcode
== SB_INST_TAG
)
603 struct sb_instruction_tag_t
*tag
= (struct sb_instruction_tag_t
*)hdr
;
606 color(OFF
);printf(" | ");
608 printf("sec=0x%08x", tag
->identifier
);
609 color(OFF
);printf(" | ");
611 printf("cnt=0x%08x", tag
->len
);
612 color(OFF
);printf(" | ");
614 printf("flg=0x%08x\n", tag
->flags
);
616 offset
+= sizeof(struct sb_instruction_tag_t
);
619 fill_section_name(name
, tag
->identifier
);
621 int size
= tag
->len
* BLOCK_SIZE
;
622 int data_sec
= !(tag
->flags
& SECTION_BOOTABLE
);
623 int encrypted
= !(tag
->flags
& SECTION_CLEARTEXT
) && sb_header
->nr_keys
> 0;
626 printf("%sSection ", indent
);
628 printf("'%s'\n", name
);
630 printf("%s pos = ", indent
);
632 printf("%8x - %8x\n", pos
, pos
+size
);
634 printf("%s len = ", indent
);
636 printf("%8x\n", size
);
638 printf("%s flags = ", indent
);
640 printf("%8x", tag
->flags
);
643 printf(" Data Section");
645 printf(" Boot Section");
647 printf(" (Encrypted)");
651 byte
*sec
= xmalloc(size
);
653 cbc_mac(g_buf
+ pos
, sec
, size
/ BLOCK_SIZE
, real_key
, g_buf
, NULL
, 0);
655 memcpy(sec
, g_buf
+ pos
, size
);
657 extract_section(data_sec
, name
, sec
, size
, " ");
661 if(tag
->hdr
.flags
& SB_INST_LAST_TAG
)
664 /* restart with IV */
665 memcpy(iv
, g_buf
, 16);
670 printf("Unknown instruction %d at address 0x%08lx\n", hdr
->opcode
, (long)offset
);
676 /* final signature */
678 printf("Final signature:\n");
679 byte decrypted_block
[32];
680 if(sb_header
->nr_keys
> 0)
683 printf(" Encrypted SHA-1:\n");
685 byte
*encrypted_block
= &g_buf
[filesize
- 32];
687 print_hex(encrypted_block
, 16, true);
689 print_hex(encrypted_block
+ 16, 16, true);
691 cbc_mac(encrypted_block
, decrypted_block
, 2, real_key
, g_buf
, NULL
, 0);
694 memcpy(decrypted_block
, &g_buf
[filesize
- 32], 32);
696 printf(" File SHA-1:\n ");
698 print_hex(decrypted_block
, 20, false);
700 sha_1_init(&sha_1_params
);
701 sha_1_update(&sha_1_params
, g_buf
, filesize
- 32);
702 sha_1_finish(&sha_1_params
);
703 sha_1_output(&sha_1_params
, computed_sha1
);
705 if(memcmp(decrypted_block
, computed_sha1
, 20) == 0)
711 int main(int argc
, const char **argv
)
715 if(argc
!= 3 && argc
!= 4)
717 printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv
);
718 printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n");
719 printf("To ignore the file version check, set environment variable SB_IGNORE_VER to YES\n");
724 snprintf(out_prefix
, PREFIX_SIZE
, "%s", argv
[3]);
726 strcpy(out_prefix
, "");
728 if( (fd
= open(argv
[1], O_RDONLY
)) == -1 )
729 bugp("opening firmware failed");
733 if(fstat(fd
, &st
) == -1)
734 bugp("firmware stat() failed");
737 g_buf
= xmalloc(g_sz
);
738 if(read(fd
, g_buf
, g_sz
) != (ssize_t
)g_sz
) /* load the whole file into memory */
739 bugp("reading firmware");