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]");
232 printf("f=%x", hdr
->flags
);
236 if(hdr
->opcode
== SB_INST_LOAD
)
238 struct sb_instruction_load_t
*load
= (struct sb_instruction_load_t
*)&buf
[pos
];
241 color(OFF
);printf(" | ");
243 printf("addr=0x%08x", load
->addr
);
244 color(OFF
);printf(" | ");
246 printf("len=0x%08x", load
->len
);
247 color(OFF
);printf(" | ");
249 printf("crc=0x%08x", load
->crc
);
250 /* data is padded to 16-byte boundary with random data and crc'ed with it */
251 uint32_t computed_crc
= crc(&buf
[pos
+ sizeof(struct sb_instruction_load_t
)],
252 ROUND_UP(load
->len
, 16));
254 if(load
->crc
== computed_crc
)
257 printf(" Failed (crc=0x%08x)\n", computed_crc
);
259 /* elf construction */
260 elf_add_load_section(&elf
, load
->addr
, load
->len
,
261 &buf
[pos
+ sizeof(struct sb_instruction_load_t
)]);
263 pos
+= load
->len
+ sizeof(struct sb_instruction_load_t
);
264 // unsure about rounding
265 pos
= ROUND_UP(pos
, 16);
267 else if(hdr
->opcode
== SB_INST_FILL
)
269 struct sb_instruction_fill_t
*fill
= (struct sb_instruction_fill_t
*)&buf
[pos
];
272 color(OFF
);printf(" | ");
274 printf("addr=0x%08x", fill
->addr
);
275 color(OFF
);printf(" | ");
277 printf("len=0x%08x", fill
->len
);
278 color(OFF
);printf(" | ");
280 printf("pattern=0x%08x\n", fill
->pattern
);
283 /* elf construction */
284 elf_add_fill_section(&elf
, fill
->addr
, fill
->len
, fill
->pattern
);
286 pos
+= sizeof(struct sb_instruction_fill_t
);
287 // fixme: useless as pos is a multiple of 16 and fill struct is 4-bytes wide ?
288 pos
= ROUND_UP(pos
, 16);
290 else if(hdr
->opcode
== SB_INST_CALL
||
291 hdr
->opcode
== SB_INST_JUMP
)
293 int is_call
= (hdr
->opcode
== SB_INST_CALL
);
294 struct sb_instruction_call_t
*call
= (struct sb_instruction_call_t
*)&buf
[pos
];
300 color(OFF
);printf(" | ");
302 printf("addr=0x%08x", call
->addr
);
303 color(OFF
);printf(" | ");
305 printf("arg=0x%08x\n", call
->arg
);
308 /* elf construction */
309 elf_set_start_addr(&elf
, call
->addr
);
310 extract_elf_section(&elf
, elf_count
++, filename
, indent
);
314 pos
+= sizeof(struct sb_instruction_call_t
);
315 // fixme: useless as pos is a multiple of 16 and call struct is 4-bytes wide ?
316 pos
= ROUND_UP(pos
, 16);
318 else if(hdr
->opcode
== SB_INST_MODE
)
320 struct sb_instruction_mode_t
*mode
= (struct sb_instruction_mode_t
*)hdr
;
323 color(OFF
);printf(" | ");
325 printf("mod=0x%08x\n", mode
->mode
);
327 pos
+= sizeof(struct sb_instruction_mode_t
);
332 printf("Unknown instruction %d at address 0x%08lx\n", hdr
->opcode
, (unsigned long)pos
);
337 if(!elf_is_empty(&elf
))
338 extract_elf_section(&elf
, elf_count
++, filename
, indent
);
342 static void fill_section_name(char name
[5], uint32_t identifier
)
344 name
[0] = (identifier
>> 24) & 0xff;
345 name
[1] = (identifier
>> 16) & 0xff;
346 name
[2] = (identifier
>> 8) & 0xff;
347 name
[3] = identifier
& 0xff;
348 for(int i
= 0; i
< 4; i
++)
349 if(!isprint(name
[i
]))
354 static uint16_t swap16(uint16_t t
)
356 return (t
<< 8) | (t
>> 8);
359 static void fix_version(struct sb_version_t
*ver
)
361 ver
->major
= swap16(ver
->major
);
362 ver
->minor
= swap16(ver
->minor
);
363 ver
->revision
= swap16(ver
->revision
);
366 static void extract(unsigned long filesize
)
368 struct sha_1_params_t sha_1_params
;
369 /* Basic header info */
370 struct sb_header_t
*sb_header
= (struct sb_header_t
*)g_buf
;
372 if(memcmp(sb_header
->signature
, "STMP", 4) != 0)
373 bugp("Bad signature");
374 if(sb_header
->image_size
* BLOCK_SIZE
!= filesize
)
375 bugp("File size mismatch");
376 if(sb_header
->header_size
* BLOCK_SIZE
!= sizeof(struct sb_header_t
))
377 bugp("Bad header size");
378 if(sb_header
->sec_hdr_size
* BLOCK_SIZE
!= sizeof(struct sb_section_header_t
))
379 bugp("Bad section header size");
382 printf("Basic info:\n");
384 printf(" SB version: ");
386 printf("%d.%d\n", sb_header
->major_ver
, sb_header
->minor_ver
);
388 printf(" Header SHA-1: ");
389 byte
*hdr_sha1
= sb_header
->sha1_header
;
391 print_hex(hdr_sha1
, 20, false);
393 byte computed_sha1
[20];
394 sha_1_init(&sha_1_params
);
395 sha_1_update(&sha_1_params
, &sb_header
->signature
[0],
396 sizeof(struct sb_header_t
) - sizeof(sb_header
->sha1_header
));
397 sha_1_finish(&sha_1_params
);
398 sha_1_output(&sha_1_params
, computed_sha1
);
400 if(memcmp(hdr_sha1
, computed_sha1
, 20) == 0)
407 printf("%x\n", sb_header
->flags
);
409 printf(" Total file size : ");
411 printf("%ld\n", filesize
);
413 /* Sizes and offsets */
415 printf("Sizes and offsets:\n");
417 printf(" # of encryption keys = ");
419 printf("%d\n", sb_header
->nr_keys
);
421 printf(" # of sections = ");
423 printf("%d\n", sb_header
->nr_sections
);
427 printf("Versions\n");
430 printf(" Random 1: ");
432 print_hex(sb_header
->rand_pad0
, sizeof(sb_header
->rand_pad0
), true);
434 printf(" Random 2: ");
436 print_hex(sb_header
->rand_pad1
, sizeof(sb_header
->rand_pad1
), true);
438 uint64_t micros
= sb_header
->timestamp
;
439 time_t seconds
= (micros
/ (uint64_t)1000000L);
440 struct tm tm_base
= {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL
}; /* 2000/1/1 0:00:00 */
441 seconds
+= mktime(&tm_base
);
442 struct tm
*time
= gmtime(&seconds
);
444 printf(" Creation date/time = ");
446 printf("%s", asctime(time
));
448 struct sb_version_t product_ver
= sb_header
->product_ver
;
449 fix_version(&product_ver
);
450 struct sb_version_t component_ver
= sb_header
->component_ver
;
451 fix_version(&component_ver
);
454 printf(" Product version = ");
456 printf("%X.%X.%X\n", product_ver
.major
, product_ver
.minor
, product_ver
.revision
);
458 printf(" Component version = ");
460 printf("%X.%X.%X\n", component_ver
.major
, component_ver
.minor
, component_ver
.revision
);
463 printf(" Drive tag = ");
465 printf("%x\n", sb_header
->drive_tag
);
467 printf(" First boot tag offset = ");
469 printf("%x\n", sb_header
->first_boot_tag_off
);
471 printf(" First boot section ID = ");
473 printf("0x%08x\n", sb_header
->first_boot_sec_id
);
475 /* encryption cbc-mac */
476 key_array_t keys
= NULL
; /* array of 16-bytes keys */
478 if(sb_header
->nr_keys
> 0)
480 keys
= read_keys(sb_header
->nr_keys
);
482 printf("Encryption data\n");
483 for(int i
= 0; i
< sb_header
->nr_keys
; i
++)
486 printf(" Key %d: ", i
);
487 print_hex(keys
[i
], 16, true);
489 printf(" CBC-MAC of headers: ");
491 uint32_t ofs
= sizeof(struct sb_header_t
)
492 + sizeof(struct sb_section_header_t
) * sb_header
->nr_sections
493 + sizeof(struct sb_key_dictionary_entry_t
) * i
;
494 struct sb_key_dictionary_entry_t
*dict_entry
=
495 (struct sb_key_dictionary_entry_t
*)&g_buf
[ofs
];
498 print_hex(dict_entry
->hdr_cbc_mac
, 16, false);
500 byte computed_cbc_mac
[16];
503 cbc_mac(g_buf
, NULL
, sb_header
->header_size
+ sb_header
->nr_sections
,
504 keys
[i
], zero
, &computed_cbc_mac
, 1);
506 if(memcmp(dict_entry
->hdr_cbc_mac
, computed_cbc_mac
, 16) == 0)
512 printf(" Encrypted key : ");
514 print_hex(dict_entry
->key
, 16, true);
517 byte decrypted_key
[16];
519 memcpy(iv
, g_buf
, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
520 cbc_mac(dict_entry
->key
, decrypted_key
, 1, keys
[i
], iv
, NULL
, 0);
521 printf(" Decrypted key : ");
523 print_hex(decrypted_key
, 16, false);
524 /* cross-check or copy */
526 memcpy(real_key
, decrypted_key
, 16);
527 else if(memcmp(real_key
, decrypted_key
, 16) == 0)
530 printf(" Cross-Check Ok");
535 printf(" Cross-Check Failed");
542 if(strcasecmp(s_getenv("SB_RAW_CMD"), "YES") != 0)
545 printf("Sections\n");
546 for(int i
= 0; i
< sb_header
->nr_sections
; i
++)
548 uint32_t ofs
= sb_header
->header_size
* BLOCK_SIZE
+ i
* sizeof(struct sb_section_header_t
);
549 struct sb_section_header_t
*sec_hdr
= (struct sb_section_header_t
*)&g_buf
[ofs
];
552 fill_section_name(name
, sec_hdr
->identifier
);
553 int pos
= sec_hdr
->offset
* BLOCK_SIZE
;
554 int size
= sec_hdr
->size
* BLOCK_SIZE
;
555 int data_sec
= !(sec_hdr
->flags
& SECTION_BOOTABLE
);
556 int encrypted
= !(sec_hdr
->flags
& SECTION_CLEARTEXT
) && sb_header
->nr_keys
> 0;
561 printf("'%s'\n", name
);
565 printf("%8x - %8x\n", pos
, pos
+size
);
569 printf("%8x\n", size
);
573 printf("%8x", sec_hdr
->flags
);
576 printf(" Data Section");
578 printf(" Boot Section");
580 printf(" (Encrypted)");
584 byte
*sec
= xmalloc(size
);
586 cbc_mac(g_buf
+ pos
, sec
, size
/ BLOCK_SIZE
, real_key
, g_buf
, NULL
, 0);
588 memcpy(sec
, g_buf
+ pos
, size
);
590 extract_section(data_sec
, name
, sec
, size
, " ");
596 /* advanced raw mode */
598 printf("Commands\n");
599 uint32_t offset
= sb_header
->first_boot_tag_off
* BLOCK_SIZE
;
601 memcpy(iv
, g_buf
, 16);
602 const char *indent
= " ";
606 if(sb_header
->nr_keys
> 0)
607 cbc_mac(g_buf
+ offset
, cmd
, 1, real_key
, iv
, &iv
, 0);
609 memcpy(cmd
, g_buf
+ offset
, BLOCK_SIZE
);
610 struct sb_instruction_header_t
*hdr
= (struct sb_instruction_header_t
*)cmd
;
611 printf("%s", indent
);
612 uint8_t checksum
= instruction_checksum(hdr
);
613 if(checksum
!= hdr
->checksum
)
616 printf("[Bad checksum]");
619 if(hdr
->opcode
== SB_INST_NOP
)
623 offset
+= BLOCK_SIZE
;
625 else if(hdr
->opcode
== SB_INST_TAG
)
627 struct sb_instruction_tag_t
*tag
= (struct sb_instruction_tag_t
*)hdr
;
630 color(OFF
);printf(" | ");
632 printf("sec=0x%08x", tag
->identifier
);
633 color(OFF
);printf(" | ");
635 printf("cnt=0x%08x", tag
->len
);
636 color(OFF
);printf(" | ");
638 printf("flg=0x%08x", tag
->flags
);
640 if(tag
->hdr
.flags
& SB_INST_LAST_TAG
)
644 printf(" Last section");
648 offset
+= sizeof(struct sb_instruction_tag_t
);
651 fill_section_name(name
, tag
->identifier
);
653 int size
= tag
->len
* BLOCK_SIZE
;
654 int data_sec
= !(tag
->flags
& SECTION_BOOTABLE
);
655 int encrypted
= !(tag
->flags
& SECTION_CLEARTEXT
) && sb_header
->nr_keys
> 0;
658 printf("%sSection ", indent
);
660 printf("'%s'\n", name
);
662 printf("%s pos = ", indent
);
664 printf("%8x - %8x\n", pos
, pos
+size
);
666 printf("%s len = ", indent
);
668 printf("%8x\n", size
);
670 printf("%s flags = ", indent
);
672 printf("%8x", tag
->flags
);
675 printf(" Data Section");
677 printf(" Boot Section");
679 printf(" (Encrypted)");
683 byte
*sec
= xmalloc(size
);
685 cbc_mac(g_buf
+ pos
, sec
, size
/ BLOCK_SIZE
, real_key
, g_buf
, NULL
, 0);
687 memcpy(sec
, g_buf
+ pos
, size
);
689 extract_section(data_sec
, name
, sec
, size
, " ");
693 if(tag
->hdr
.flags
& SB_INST_LAST_TAG
)
696 /* restart with IV */
697 memcpy(iv
, g_buf
, 16);
702 printf("Unknown instruction %d at address 0x%08lx\n", hdr
->opcode
, (long)offset
);
708 /* final signature */
710 printf("Final signature:\n");
711 byte decrypted_block
[32];
712 if(sb_header
->nr_keys
> 0)
715 printf(" Encrypted SHA-1:\n");
717 byte
*encrypted_block
= &g_buf
[filesize
- 32];
719 print_hex(encrypted_block
, 16, true);
721 print_hex(encrypted_block
+ 16, 16, true);
723 cbc_mac(encrypted_block
, decrypted_block
, 2, real_key
, g_buf
, NULL
, 0);
726 memcpy(decrypted_block
, &g_buf
[filesize
- 32], 32);
728 printf(" File SHA-1:\n ");
730 print_hex(decrypted_block
, 20, false);
732 sha_1_init(&sha_1_params
);
733 sha_1_update(&sha_1_params
, g_buf
, filesize
- 32);
734 sha_1_finish(&sha_1_params
);
735 sha_1_output(&sha_1_params
, computed_sha1
);
737 if(memcmp(decrypted_block
, computed_sha1
, 20) == 0)
743 int main(int argc
, const char **argv
)
747 if(argc
!= 3 && argc
!= 4)
749 printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv
);
750 printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n");
755 snprintf(out_prefix
, PREFIX_SIZE
, "%s", argv
[3]);
757 strcpy(out_prefix
, "");
759 if( (fd
= open(argv
[1], O_RDONLY
)) == -1 )
760 bugp("opening firmware failed");
764 if(fstat(fd
, &st
) == -1)
765 bugp("firmware stat() failed");
768 g_buf
= xmalloc(g_sz
);
769 if(read(fd
, g_buf
, g_sz
) != (ssize_t
)g_sz
) /* load the whole file into memory */
770 bugp("reading firmware");