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>
45 #if 1 /* ANSI colors */
47 # define color(a) printf("%s",a)
48 char OFF
[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
50 char GREY
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
51 char RED
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
52 char GREEN
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
53 char YELLOW
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
54 char BLUE
[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
61 #define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
62 #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
65 #define get32le(a) ((uint32_t) \
66 ( buf[a+3] << 24 | buf[a+2] << 16 | buf[a+1] << 8 | buf[a] ))
67 #define get16le(a) ((uint16_t)( buf[a+1] << 8 | buf[a] ))
69 /* all blocks are sized as a multiple of 0x1ff */
70 #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
72 /* If you find a firmware that breaks the known format ^^ */
73 #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)
77 size_t sz
; /* file size */
78 uint8_t *buf
; /* file content */
79 #define PREFIX_SIZE 128
80 char out_prefix
[PREFIX_SIZE
];
83 #define SB_INST_NOP 0x0
84 #define SB_INST_TAG 0x1
85 #define SB_INST_LOAD 0x2
86 #define SB_INST_FILL 0x3
87 #define SB_INST_JUMP 0x4
88 #define SB_INST_CALL 0x5
89 #define SB_INST_MODE 0x6
91 struct sb_instruction_header_t
95 uint16_t zero_except_for_tag
;
96 } __attribute__((packed
));
98 struct sb_instruction_load_t
100 struct sb_instruction_header_t hdr
;
104 } __attribute__((packed
));
106 struct sb_instruction_fill_t
108 struct sb_instruction_header_t hdr
;
112 } __attribute__((packed
));
114 struct sb_instruction_call_t
116 struct sb_instruction_header_t hdr
;
120 } __attribute__((packed
));
122 void *xmalloc(size_t s
) /* malloc helper, used in elf.c */
124 void * r
= malloc(s
);
125 if(!r
) bugp("malloc");
129 static char getchr(int offset
)
133 return isprint(c
) ? c
: '_';
136 static void getstrle(char string
[], int offset
)
139 for (i
= 0; i
< 4; i
++) {
140 string
[i
] = getchr(offset
+ 3 - i
);
145 static void getstrbe(char string
[], int offset
)
148 for (i
= 0; i
< 4; i
++) {
149 string
[i
] = getchr(offset
+ i
);
154 static void printhex(int offset
, int len
)
158 for (i
= 0; i
< len
; i
++) {
159 printf("%02X ", buf
[offset
+ i
]);
164 static void print_key(byte key
[16])
166 for(int i
= 0; i
< 16; i
++)
167 printf("%02X ", key
[i
]);
170 static void print_sha1(byte sha
[20])
172 for(int i
= 0; i
< 20; i
++)
173 printf("%02X ", sha
[i
]);
176 /* verify the firmware header */
177 static void check(unsigned long filesize
)
179 /* check STMP marker */
181 getstrbe(stmp
, 0x14);
182 assert(strcmp(stmp
, "STMP") == 0);
186 unsigned long totalsize
= 16 * get32le(0x1C);
188 assert(filesize
== totalsize
);
191 int convxdigit(char digit
, byte
*val
)
193 if(digit
>= '0' && digit
<= '9')
198 else if(digit
>= 'A' && digit
<= 'F')
200 *val
= digit
- 'A' + 10;
203 else if(digit
>= 'a' && digit
<= 'f')
205 *val
= digit
- 'a' + 10;
212 typedef byte (*key_array_t
)[16];
214 static key_array_t
read_keys(int num_keys
)
218 int fd
= open(key_file
,O_RDONLY
);
220 bugp("opening key file failed");
221 if(fstat(fd
,&st
) == -1)
222 bugp("key file stat() failed");
224 char *buf
= xmalloc(size
);
225 if(read(fd
,buf
,sz
)!=(ssize_t
)size
)
226 bugp("reading key file");
229 key_array_t keys
= xmalloc(sizeof(byte
[16]) * num_keys
);
231 for(int i
= 0; i
< num_keys
; i
++)
234 while(pos
< size
&& isspace(buf
[pos
]))
237 if((pos
+ 32) > size
)
238 bugp("invalid key file (not enough keys)");
239 for(int j
= 0; j
< 16; j
++)
242 if(convxdigit(buf
[pos
+ 2 * j
], &a
) || convxdigit(buf
[pos
+ 2 * j
+ 1], &b
))
243 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
244 keys
[i
][j
] = (a
<< 4) | b
;
253 #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
255 static uint8_t instruction_checksum(struct sb_instruction_header_t
*hdr
)
258 byte
*ptr
= (byte
*)hdr
;
259 for(int i
= 1; i
< 16; i
++)
264 static void elf_write(void *user
, uint32_t addr
, const void *buf
, size_t count
)
267 fseek(f
, addr
, SEEK_SET
);
268 fwrite(buf
, count
, 1, f
);
271 static void extract_elf_section(struct elf_params_t
*elf
, int count
, const char *prefix
)
273 char *filename
= xmalloc(strlen(prefix
) + 32);
274 sprintf(filename
, "%s.%d.elf", prefix
, count
);
275 printf("write %s\n", filename
);
277 FILE *fd
= fopen(filename
, "wb");
282 elf_output(elf
, elf_write
, fd
);
286 static void extract_section(int data_sec
, char name
[5], byte
*buf
, int size
, const char *indent
)
288 char filename
[PREFIX_SIZE
+ 32];
289 snprintf(filename
, sizeof filename
, "%s%s.bin", out_prefix
, name
);
290 FILE *fd
= fopen(filename
, "wb");
292 fwrite(buf
, size
, 1, fd
);
298 snprintf(filename
, sizeof filename
, "%s%s", out_prefix
, name
);
300 /* elf construction */
301 struct elf_params_t elf
;
304 /* Pretty print the content */
308 struct sb_instruction_header_t
*hdr
= (struct sb_instruction_header_t
*)&buf
[pos
];
309 printf("%s", indent
);
310 uint8_t checksum
= instruction_checksum(hdr
);
311 if(checksum
!= hdr
->checksum
)
314 printf("[Bad checksum]");
317 if(hdr
->opcode
== SB_INST_LOAD
)
319 struct sb_instruction_load_t
*load
= (struct sb_instruction_load_t
*)&buf
[pos
];
322 color(OFF
);printf(" | ");
324 printf("addr=0x%08x", load
->addr
);
325 color(OFF
);printf(" | ");
327 printf("len=0x%08x", load
->len
);
328 color(OFF
);printf(" | ");
330 printf("crc=0x%08x", load
->crc
);
331 /* data is padded to 16-byte boundary with random data and crc'ed with it */
332 uint32_t computed_crc
= crc(&buf
[pos
+ sizeof(struct sb_instruction_load_t
)],
333 ROUND_UP(load
->len
, 16));
335 if(load
->crc
== computed_crc
)
338 printf(" Failed (crc=0x%08x)\n", computed_crc
);
340 /* elf construction */
341 elf_add_load_section(&elf
, load
->addr
, load
->len
,
342 &buf
[pos
+ sizeof(struct sb_instruction_load_t
)]);
344 pos
+= load
->len
+ sizeof(struct sb_instruction_load_t
);
345 // unsure about rounding
346 pos
= ROUND_UP(pos
, 16);
348 else if(hdr
->opcode
== SB_INST_FILL
)
350 struct sb_instruction_fill_t
*fill
= (struct sb_instruction_fill_t
*)&buf
[pos
];
353 color(OFF
);printf(" | ");
355 printf("addr=0x%08x", fill
->addr
);
356 color(OFF
);printf(" | ");
358 printf("len=0x%08x", fill
->len
);
359 color(OFF
);printf(" | ");
361 printf("pattern=0x%08x\n", fill
->pattern
);
364 /* elf construction */
365 elf_add_fill_section(&elf
, fill
->addr
, fill
->len
, fill
->pattern
);
367 pos
+= sizeof(struct sb_instruction_fill_t
);
368 // fixme: useless as pos is a multiple of 16 and fill struct is 4-bytes wide ?
369 pos
= ROUND_UP(pos
, 16);
371 else if(hdr
->opcode
== SB_INST_CALL
||
372 hdr
->opcode
== SB_INST_JUMP
)
374 int is_call
= (hdr
->opcode
== SB_INST_CALL
);
375 struct sb_instruction_call_t
*call
= (struct sb_instruction_call_t
*)&buf
[pos
];
381 color(OFF
);printf(" | ");
383 printf("addr=0x%08x", call
->addr
);
384 color(OFF
);printf(" | ");
386 printf("arg=0x%08x\n", call
->arg
);
389 /* elf construction */
390 elf_set_start_addr(&elf
, call
->addr
);
391 extract_elf_section(&elf
, elf_count
++, filename
);
395 pos
+= sizeof(struct sb_instruction_call_t
);
396 // fixme: useless as pos is a multiple of 16 and call struct is 4-bytes wide ?
397 pos
= ROUND_UP(pos
, 16);
402 printf("Unknown instruction %d at address 0x%08lx\n", hdr
->opcode
, (unsigned long)pos
);
407 if(!elf_is_empty(&elf
))
408 extract_elf_section(&elf
, elf_count
++, filename
);
412 static void extract(unsigned long filesize
)
414 struct sha_1_params_t sha_1_params
;
415 /* Basic header info */
417 printf("Basic info:\n");
419 printf("\tHeader SHA-1: ");
420 byte
*hdr_sha1
= &buf
[0];
422 print_sha1(hdr_sha1
);
424 byte computed_sha1
[20];
425 sha_1_init(&sha_1_params
);
426 sha_1_update(&sha_1_params
, &buf
[0x14], 0x4C);
427 sha_1_finish(&sha_1_params
);
428 sha_1_output(&sha_1_params
, computed_sha1
);
430 if(memcmp(hdr_sha1
, computed_sha1
, 20) == 0)
437 printf("\tTotal file size : %ld\n", filesize
);
439 /* Sizes and offsets */
441 printf("Sizes and offsets:\n");
443 int num_enc
= get16le(0x28);
444 printf("\t# of encryption keys = %d\n", num_enc
);
445 int num_chunks
= get16le(0x2E);
446 printf("\t# of chunk headers = %d\n", num_chunks
);
450 printf("Versions\n");
453 printf("\tRandom 1: ");
455 printf("\tRandom 2: ");
458 uint64_t micros_l
= get32le(0x38);
459 uint64_t micros_h
= get32le(0x3c);
460 uint64_t micros
= ((uint64_t)micros_h
<< 32) | micros_l
;
461 time_t seconds
= (micros
/ (uint64_t)1000000L);
462 seconds
+= 946684800; /* 2000/1/1 0:00:00 */
463 struct tm
*time
= gmtime(&seconds
);
465 printf("\tCreation date/time = %s", asctime(time
));
467 int p_maj
= get32le(0x40);
468 int p_min
= get32le(0x44);
469 int p_sub
= get32le(0x48);
470 int c_maj
= get32le(0x4C);
471 int c_min
= get32le(0x50);
472 int c_sub
= get32le(0x54);
474 printf("\tProduct version = %X.%X.%X\n", p_maj
, p_min
, p_sub
);
475 printf("\tComponent version = %X.%X.%X\n", c_maj
, c_min
, c_sub
);
477 /* encryption cbc-mac */
478 key_array_t keys
= NULL
; /* array of 16-bytes keys */
482 keys
= read_keys(num_enc
);
484 printf("Encryption data\n");
485 for(int i
= 0; i
< num_enc
; i
++)
488 printf("\tKey %d: ", i
);
492 printf("\t\tCBC-MAC of headers: ");
493 /* copy the cbc mac */
494 byte hdr_cbc_mac
[16];
495 memcpy(hdr_cbc_mac
, &buf
[0x60 + 16 * num_chunks
+ 32 * i
], 16);
497 print_key(hdr_cbc_mac
);
499 byte computed_cbc_mac
[16];
502 cbc_mac(buf
, NULL
, 6 + num_chunks
, keys
[i
], zero
, &computed_cbc_mac
, 1);
504 if(memcmp(hdr_cbc_mac
, computed_cbc_mac
, 16) == 0)
510 printf("\t\tEncrypted key : ");
511 byte (*encrypted_key
)[16];
512 encrypted_key
= (key_array_t
)&buf
[0x60 + 16 * num_chunks
+ 32 * i
+ 16];
514 print_key(*encrypted_key
);
518 byte decrypted_key
[16];
520 memcpy(iv
, buf
, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
521 cbc_mac(*encrypted_key
, decrypted_key
, 1, keys
[i
], iv
, NULL
, 0);
522 printf("\t\tDecrypted key : ");
524 print_key(decrypted_key
);
525 /* cross-check or copy */
527 memcpy(real_key
, decrypted_key
, 16);
528 else if(memcmp(real_key
, decrypted_key
, 16) == 0)
531 printf(" Cross-Check Ok");
536 printf(" Cross-Check Failed");
546 for (int i
= 0; i
< num_chunks
; i
++) {
547 uint32_t ofs
= 0x60 + (i
* 16);
550 getstrle(name
, ofs
+ 0);
551 int pos
= 16 * get32le(ofs
+ 4);
552 int size
= 16 * get32le(ofs
+ 8);
553 int flags
= get32le(ofs
+ 12);
554 int data_sec
= (flags
== 2);
555 int encrypted
= !data_sec
&& (num_enc
> 0);
558 printf("\tChunk '%s'\n", name
);
559 printf("\t\tpos = %8x - %8x\n", pos
, pos
+size
);
560 printf("\t\tlen = %8x\n", size
);
561 printf("\t\tflags = %8x", flags
);
564 printf(" Data Section");
566 printf(" Boot Section");
568 printf(" (Encrypted)");
572 byte
*sec
= xmalloc(size
);
574 cbc_mac(buf
+ pos
, sec
, size
/ 16, real_key
, buf
, NULL
, 0);
576 memcpy(sec
, buf
+ pos
, size
);
578 extract_section(data_sec
, name
, sec
, size
, "\t\t\t");
582 /* final signature */
584 printf("Final signature:\n");
586 printf("\tEncrypted signature:\n");
589 printhex(filesize
- 32, 16);
591 printhex(filesize
- 16, 16);
593 byte
*encrypted_block
= &buf
[filesize
- 32];
594 byte decrypted_block
[32];
595 cbc_mac(encrypted_block
, decrypted_block
, 2, real_key
, buf
, NULL
, 0);
597 printf("\tDecrypted SHA-1:\n\t\t");
599 print_sha1(decrypted_block
);
601 sha_1_init(&sha_1_params
);
602 sha_1_update(&sha_1_params
, buf
, filesize
- 32);
603 sha_1_finish(&sha_1_params
);
604 sha_1_output(&sha_1_params
, computed_sha1
);
606 if(memcmp(decrypted_block
, computed_sha1
, 20) == 0)
612 int main(int argc
, const char **argv
)
616 if(argc
!= 3 && argc
!= 4)
617 bug("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv
);
620 snprintf(out_prefix
, PREFIX_SIZE
, "%s", argv
[3]);
622 strcpy(out_prefix
, "");
624 if( (fd
= open(argv
[1],O_RDONLY
)) == -1 )
625 bugp("opening firmware failed");
629 if(fstat(fd
,&st
) == -1)
630 bugp("firmware stat() failed");
634 if(read(fd
,buf
,sz
)!=(ssize_t
)sz
) /* load the whole file into memory */
635 bugp("reading firmware");
639 check(st
.st_size
); /* verify header and checksums */
640 extract(st
.st_size
); /* split in blocks */