diff options
author | Amaury Pouly <pamaury@rockbox.org> | 2011-11-01 11:23:43 +0000 |
---|---|---|
committer | Amaury Pouly <pamaury@rockbox.org> | 2011-11-01 11:23:43 +0000 |
commit | e36471df9cfb3fa7aaa2216d9b5c79cb775bf9da (patch) | |
tree | d8c03ad24a339928a379dd864d235a3f1a02aaad /utils/sbtools/sbtoelf.c | |
parent | 591ec0349b424e94eaaaa1c9bf486f769ff34732 (diff) | |
download | rockbox-e36471df9cfb3fa7aaa2216d9b5c79cb775bf9da.tar.gz rockbox-e36471df9cfb3fa7aaa2216d9b5c79cb775bf9da.zip |
sbtools: move sb reading from sbtoelf.c to sb.c with a proper interface, fix sb production bug, fix ugly code, add sb dump code and sbtoelf loopback facility
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30881 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/sbtools/sbtoelf.c')
-rw-r--r-- | utils/sbtools/sbtoelf.c | 673 |
1 files changed, 46 insertions, 627 deletions
diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c index 24417dc88e..0199ffb4f5 100644 --- a/utils/sbtools/sbtoelf.c +++ b/utils/sbtools/sbtoelf.c | |||
@@ -56,19 +56,7 @@ | |||
56 | 56 | ||
57 | /* globals */ | 57 | /* globals */ |
58 | 58 | ||
59 | uint8_t *g_buf; /* file content */ | ||
60 | char *g_out_prefix; | 59 | char *g_out_prefix; |
61 | bool g_debug; | ||
62 | bool g_raw_mode; | ||
63 | |||
64 | static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) | ||
65 | { | ||
66 | uint8_t sum = 90; | ||
67 | byte *ptr = (byte *)hdr; | ||
68 | for(int i = 1; i < 16; i++) | ||
69 | sum += ptr[i]; | ||
70 | return sum; | ||
71 | } | ||
72 | 60 | ||
73 | static void elf_printf(void *user, bool error, const char *fmt, ...) | 61 | static void elf_printf(void *user, bool error, const char *fmt, ...) |
74 | { | 62 | { |
@@ -104,614 +92,34 @@ static void extract_elf_section(struct elf_params_t *elf, int count, const char | |||
104 | fclose(fd); | 92 | fclose(fd); |
105 | } | 93 | } |
106 | 94 | ||
107 | static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent) | 95 | static void usage(void) |
108 | { | ||
109 | char *filename = xmalloc(strlen(g_out_prefix) + strlen(name) + 5); | ||
110 | if(g_out_prefix) | ||
111 | { | ||
112 | sprintf(filename, "%s%s.bin", g_out_prefix, name); | ||
113 | FILE *fd = fopen(filename, "wb"); | ||
114 | if (fd != NULL) | ||
115 | { | ||
116 | fwrite(buf, size, 1, fd); | ||
117 | fclose(fd); | ||
118 | } | ||
119 | } | ||
120 | if(data_sec) | ||
121 | return; | ||
122 | |||
123 | sprintf(filename, "%s%s", g_out_prefix, name); | ||
124 | |||
125 | /* elf construction */ | ||
126 | struct elf_params_t elf; | ||
127 | elf_init(&elf); | ||
128 | int elf_count = 0; | ||
129 | /* Pretty print the content */ | ||
130 | int pos = 0; | ||
131 | while(pos < size) | ||
132 | { | ||
133 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos]; | ||
134 | printf("%s", indent); | ||
135 | uint8_t checksum = instruction_checksum(hdr); | ||
136 | if(checksum != hdr->checksum) | ||
137 | { | ||
138 | color(GREY); | ||
139 | printf("[Bad checksum]"); | ||
140 | } | ||
141 | if(hdr->flags != 0) | ||
142 | { | ||
143 | color(GREY); | ||
144 | printf("["); | ||
145 | color(BLUE); | ||
146 | printf("f=%x", hdr->flags); | ||
147 | color(GREY); | ||
148 | printf("] "); | ||
149 | } | ||
150 | if(hdr->opcode == SB_INST_LOAD) | ||
151 | { | ||
152 | struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos]; | ||
153 | color(RED); | ||
154 | printf("LOAD"); | ||
155 | color(OFF);printf(" | "); | ||
156 | color(BLUE); | ||
157 | printf("addr=0x%08x", load->addr); | ||
158 | color(OFF);printf(" | "); | ||
159 | color(GREEN); | ||
160 | printf("len=0x%08x", load->len); | ||
161 | color(OFF);printf(" | "); | ||
162 | color(YELLOW); | ||
163 | printf("crc=0x%08x", load->crc); | ||
164 | /* data is padded to 16-byte boundary with random data and crc'ed with it */ | ||
165 | uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)], | ||
166 | ROUND_UP(load->len, 16)); | ||
167 | color(RED); | ||
168 | if(load->crc == computed_crc) | ||
169 | printf(" Ok\n"); | ||
170 | else | ||
171 | printf(" Failed (crc=0x%08x)\n", computed_crc); | ||
172 | |||
173 | /* elf construction */ | ||
174 | elf_add_load_section(&elf, load->addr, load->len, | ||
175 | &buf[pos + sizeof(struct sb_instruction_load_t)]); | ||
176 | |||
177 | pos += load->len + sizeof(struct sb_instruction_load_t); | ||
178 | } | ||
179 | else if(hdr->opcode == SB_INST_FILL) | ||
180 | { | ||
181 | struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos]; | ||
182 | color(RED); | ||
183 | printf("FILL"); | ||
184 | color(OFF);printf(" | "); | ||
185 | color(BLUE); | ||
186 | printf("addr=0x%08x", fill->addr); | ||
187 | color(OFF);printf(" | "); | ||
188 | color(GREEN); | ||
189 | printf("len=0x%08x", fill->len); | ||
190 | color(OFF);printf(" | "); | ||
191 | color(YELLOW); | ||
192 | printf("pattern=0x%08x\n", fill->pattern); | ||
193 | color(OFF); | ||
194 | |||
195 | /* elf construction */ | ||
196 | elf_add_fill_section(&elf, fill->addr, fill->len, fill->pattern); | ||
197 | |||
198 | pos += sizeof(struct sb_instruction_fill_t); | ||
199 | } | ||
200 | else if(hdr->opcode == SB_INST_CALL || | ||
201 | hdr->opcode == SB_INST_JUMP) | ||
202 | { | ||
203 | int is_call = (hdr->opcode == SB_INST_CALL); | ||
204 | struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos]; | ||
205 | color(RED); | ||
206 | if(is_call) | ||
207 | printf("CALL"); | ||
208 | else | ||
209 | printf("JUMP"); | ||
210 | color(OFF);printf(" | "); | ||
211 | color(BLUE); | ||
212 | printf("addr=0x%08x", call->addr); | ||
213 | color(OFF);printf(" | "); | ||
214 | color(GREEN); | ||
215 | printf("arg=0x%08x\n", call->arg); | ||
216 | color(OFF); | ||
217 | |||
218 | /* elf construction */ | ||
219 | elf_set_start_addr(&elf, call->addr); | ||
220 | extract_elf_section(&elf, elf_count++, filename, indent); | ||
221 | elf_release(&elf); | ||
222 | elf_init(&elf); | ||
223 | |||
224 | pos += sizeof(struct sb_instruction_call_t); | ||
225 | } | ||
226 | else if(hdr->opcode == SB_INST_MODE) | ||
227 | { | ||
228 | struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr; | ||
229 | color(RED); | ||
230 | printf("MODE"); | ||
231 | color(OFF);printf(" | "); | ||
232 | color(BLUE); | ||
233 | printf("mod=0x%08x\n", mode->mode); | ||
234 | color(OFF); | ||
235 | pos += sizeof(struct sb_instruction_mode_t); | ||
236 | } | ||
237 | else if(hdr->opcode == SB_INST_NOP) | ||
238 | { | ||
239 | color(RED); | ||
240 | printf("NOOP\n"); | ||
241 | pos += sizeof(struct sb_instruction_mode_t); | ||
242 | } | ||
243 | else | ||
244 | { | ||
245 | color(RED); | ||
246 | printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos); | ||
247 | break; | ||
248 | } | ||
249 | |||
250 | pos = ROUND_UP(pos, BLOCK_SIZE); | ||
251 | } | ||
252 | |||
253 | if(!elf_is_empty(&elf)) | ||
254 | extract_elf_section(&elf, elf_count++, filename, indent); | ||
255 | elf_release(&elf); | ||
256 | } | ||
257 | |||
258 | static void fill_section_name(char name[5], uint32_t identifier) | ||
259 | { | ||
260 | name[0] = (identifier >> 24) & 0xff; | ||
261 | name[1] = (identifier >> 16) & 0xff; | ||
262 | name[2] = (identifier >> 8) & 0xff; | ||
263 | name[3] = identifier & 0xff; | ||
264 | for(int i = 0; i < 4; i++) | ||
265 | if(!isprint(name[i])) | ||
266 | name[i] = '_'; | ||
267 | name[4] = 0; | ||
268 | } | ||
269 | |||
270 | static uint16_t swap16(uint16_t t) | ||
271 | { | ||
272 | return (t << 8) | (t >> 8); | ||
273 | } | ||
274 | |||
275 | static void fix_version(struct sb_version_t *ver) | ||
276 | { | ||
277 | ver->major = swap16(ver->major); | ||
278 | ver->minor = swap16(ver->minor); | ||
279 | ver->revision = swap16(ver->revision); | ||
280 | } | ||
281 | |||
282 | static void extract(unsigned long filesize) | ||
283 | { | ||
284 | struct sha_1_params_t sha_1_params; | ||
285 | /* Basic header info */ | ||
286 | struct sb_header_t *sb_header = (struct sb_header_t *)g_buf; | ||
287 | |||
288 | if(memcmp(sb_header->signature, "STMP", 4) != 0) | ||
289 | bugp("Bad signature"); | ||
290 | /* | ||
291 | if(sb_header->image_size * BLOCK_SIZE > filesize) | ||
292 | bugp("File size mismatch"); | ||
293 | */ | ||
294 | if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t)) | ||
295 | bugp("Bad header size"); | ||
296 | if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t)) | ||
297 | bugp("Bad section header size"); | ||
298 | |||
299 | if(filesize > sb_header->image_size * BLOCK_SIZE) | ||
300 | { | ||
301 | color(GREY); | ||
302 | printf("[Restrict file size from %lu to %d bytes]\n", filesize, | ||
303 | sb_header->image_size * BLOCK_SIZE); | ||
304 | filesize = sb_header->image_size * BLOCK_SIZE; | ||
305 | } | ||
306 | |||
307 | color(BLUE); | ||
308 | printf("Basic info:\n"); | ||
309 | color(GREEN); | ||
310 | printf(" SB version: "); | ||
311 | color(YELLOW); | ||
312 | printf("%d.%d\n", sb_header->major_ver, sb_header->minor_ver); | ||
313 | color(GREEN); | ||
314 | printf(" Header SHA-1: "); | ||
315 | byte *hdr_sha1 = sb_header->sha1_header; | ||
316 | color(YELLOW); | ||
317 | print_hex(hdr_sha1, 20, false); | ||
318 | /* Check SHA1 sum */ | ||
319 | byte computed_sha1[20]; | ||
320 | sha_1_init(&sha_1_params); | ||
321 | sha_1_update(&sha_1_params, &sb_header->signature[0], | ||
322 | sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header)); | ||
323 | sha_1_finish(&sha_1_params); | ||
324 | sha_1_output(&sha_1_params, computed_sha1); | ||
325 | color(RED); | ||
326 | if(memcmp(hdr_sha1, computed_sha1, 20) == 0) | ||
327 | printf(" Ok\n"); | ||
328 | else | ||
329 | printf(" Failed\n"); | ||
330 | color(GREEN); | ||
331 | printf(" Flags: "); | ||
332 | color(YELLOW); | ||
333 | printf("%x\n", sb_header->flags); | ||
334 | color(GREEN); | ||
335 | printf(" Total file size : "); | ||
336 | color(YELLOW); | ||
337 | printf("%ld\n", filesize); | ||
338 | |||
339 | /* Sizes and offsets */ | ||
340 | color(BLUE); | ||
341 | printf("Sizes and offsets:\n"); | ||
342 | color(GREEN); | ||
343 | printf(" # of encryption keys = "); | ||
344 | color(YELLOW); | ||
345 | printf("%d\n", sb_header->nr_keys); | ||
346 | color(GREEN); | ||
347 | printf(" # of sections = "); | ||
348 | color(YELLOW); | ||
349 | printf("%d\n", sb_header->nr_sections); | ||
350 | |||
351 | /* Versions */ | ||
352 | color(BLUE); | ||
353 | printf("Versions\n"); | ||
354 | color(GREEN); | ||
355 | |||
356 | printf(" Random 1: "); | ||
357 | color(YELLOW); | ||
358 | print_hex(sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true); | ||
359 | color(GREEN); | ||
360 | printf(" Random 2: "); | ||
361 | color(YELLOW); | ||
362 | print_hex(sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true); | ||
363 | |||
364 | uint64_t micros = sb_header->timestamp; | ||
365 | time_t seconds = (micros / (uint64_t)1000000L); | ||
366 | struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ | ||
367 | seconds += mktime(&tm_base); | ||
368 | struct tm *time = gmtime(&seconds); | ||
369 | color(GREEN); | ||
370 | printf(" Creation date/time = "); | ||
371 | color(YELLOW); | ||
372 | printf("%s", asctime(time)); | ||
373 | |||
374 | struct sb_version_t product_ver = sb_header->product_ver; | ||
375 | fix_version(&product_ver); | ||
376 | struct sb_version_t component_ver = sb_header->component_ver; | ||
377 | fix_version(&component_ver); | ||
378 | |||
379 | color(GREEN); | ||
380 | printf(" Product version = "); | ||
381 | color(YELLOW); | ||
382 | printf("%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision); | ||
383 | color(GREEN); | ||
384 | printf(" Component version = "); | ||
385 | color(YELLOW); | ||
386 | printf("%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision); | ||
387 | |||
388 | color(GREEN); | ||
389 | printf(" Drive tag = "); | ||
390 | color(YELLOW); | ||
391 | printf("%x\n", sb_header->drive_tag); | ||
392 | color(GREEN); | ||
393 | printf(" First boot tag offset = "); | ||
394 | color(YELLOW); | ||
395 | printf("%x\n", sb_header->first_boot_tag_off); | ||
396 | color(GREEN); | ||
397 | printf(" First boot section ID = "); | ||
398 | color(YELLOW); | ||
399 | printf("0x%08x\n", sb_header->first_boot_sec_id); | ||
400 | |||
401 | /* encryption cbc-mac */ | ||
402 | byte real_key[16]; | ||
403 | bool valid_key = false; /* false until a matching key was found */ | ||
404 | if(sb_header->nr_keys > 0) | ||
405 | { | ||
406 | if(sb_header->nr_keys > g_nr_keys) | ||
407 | { | ||
408 | color(GREY); | ||
409 | bug("SB file has %d keys but only %d were specified on command line\n", | ||
410 | sb_header->nr_keys, g_nr_keys); | ||
411 | } | ||
412 | color(BLUE); | ||
413 | printf("Encryption data\n"); | ||
414 | for(int i = 0; i < sb_header->nr_keys; i++) | ||
415 | { | ||
416 | color(RED); | ||
417 | printf(" Key %d: ", i); | ||
418 | print_key(&g_key_array[i], true); | ||
419 | color(GREEN); | ||
420 | printf(" CBC-MAC of headers: "); | ||
421 | |||
422 | uint32_t ofs = sizeof(struct sb_header_t) | ||
423 | + sizeof(struct sb_section_header_t) * sb_header->nr_sections | ||
424 | + sizeof(struct sb_key_dictionary_entry_t) * i; | ||
425 | struct sb_key_dictionary_entry_t *dict_entry = | ||
426 | (struct sb_key_dictionary_entry_t *)&g_buf[ofs]; | ||
427 | /* cbc mac */ | ||
428 | color(YELLOW); | ||
429 | print_hex(dict_entry->hdr_cbc_mac, 16, false); | ||
430 | /* check it */ | ||
431 | byte computed_cbc_mac[16]; | ||
432 | byte zero[16]; | ||
433 | memset(zero, 0, 16); | ||
434 | crypto_cbc(g_buf, NULL, sb_header->header_size + sb_header->nr_sections, | ||
435 | &g_key_array[i], zero, &computed_cbc_mac, 1); | ||
436 | color(RED); | ||
437 | bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0; | ||
438 | if(ok) | ||
439 | { | ||
440 | valid_key = true; | ||
441 | printf(" Ok\n"); | ||
442 | } | ||
443 | else | ||
444 | printf(" Failed\n"); | ||
445 | color(GREEN); | ||
446 | |||
447 | printf(" Encrypted key : "); | ||
448 | color(YELLOW); | ||
449 | print_hex(dict_entry->key, 16, true); | ||
450 | color(GREEN); | ||
451 | /* decrypt */ | ||
452 | byte decrypted_key[16]; | ||
453 | byte iv[16]; | ||
454 | memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ | ||
455 | crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0); | ||
456 | printf(" Decrypted key : "); | ||
457 | color(YELLOW); | ||
458 | print_hex(decrypted_key, 16, false); | ||
459 | /* cross-check or copy */ | ||
460 | if(valid_key && ok) | ||
461 | memcpy(real_key, decrypted_key, 16); | ||
462 | else if(valid_key) | ||
463 | { | ||
464 | if(memcmp(real_key, decrypted_key, 16) == 0) | ||
465 | { | ||
466 | color(RED); | ||
467 | printf(" Cross-Check Ok"); | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | color(RED); | ||
472 | printf(" Cross-Check Failed"); | ||
473 | } | ||
474 | } | ||
475 | printf("\n"); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | if(getenv("SB_REAL_KEY") != 0) | ||
480 | { | ||
481 | struct crypto_key_t k; | ||
482 | char *env = getenv("SB_REAL_KEY"); | ||
483 | if(!parse_key(&env, &k) || *env) | ||
484 | bug("Invalid SB_REAL_KEY"); | ||
485 | memcpy(real_key, k.u.key, 16); | ||
486 | } | ||
487 | |||
488 | color(RED); | ||
489 | printf(" Summary:\n"); | ||
490 | color(GREEN); | ||
491 | printf(" Real key: "); | ||
492 | color(YELLOW); | ||
493 | print_hex(real_key, 16, true); | ||
494 | color(GREEN); | ||
495 | printf(" IV : "); | ||
496 | color(YELLOW); | ||
497 | print_hex(g_buf, 16, true); | ||
498 | |||
499 | /* sections */ | ||
500 | if(!g_raw_mode) | ||
501 | { | ||
502 | color(BLUE); | ||
503 | printf("Sections\n"); | ||
504 | for(int i = 0; i < sb_header->nr_sections; i++) | ||
505 | { | ||
506 | uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t); | ||
507 | struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&g_buf[ofs]; | ||
508 | |||
509 | char name[5]; | ||
510 | fill_section_name(name, sec_hdr->identifier); | ||
511 | int pos = sec_hdr->offset * BLOCK_SIZE; | ||
512 | int size = sec_hdr->size * BLOCK_SIZE; | ||
513 | int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE); | ||
514 | int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
515 | |||
516 | color(GREEN); | ||
517 | printf(" Section "); | ||
518 | color(YELLOW); | ||
519 | printf("'%s'\n", name); | ||
520 | color(GREEN); | ||
521 | printf(" pos = "); | ||
522 | color(YELLOW); | ||
523 | printf("%8x - %8x\n", pos, pos+size); | ||
524 | color(GREEN); | ||
525 | printf(" len = "); | ||
526 | color(YELLOW); | ||
527 | printf("%8x\n", size); | ||
528 | color(GREEN); | ||
529 | printf(" flags = "); | ||
530 | color(YELLOW); | ||
531 | printf("%8x", sec_hdr->flags); | ||
532 | color(RED); | ||
533 | if(data_sec) | ||
534 | printf(" Data Section"); | ||
535 | else | ||
536 | printf(" Boot Section"); | ||
537 | if(encrypted) | ||
538 | printf(" (Encrypted)"); | ||
539 | printf("\n"); | ||
540 | |||
541 | /* save it */ | ||
542 | byte *sec = xmalloc(size); | ||
543 | if(encrypted) | ||
544 | cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0); | ||
545 | else | ||
546 | memcpy(sec, g_buf + pos, size); | ||
547 | |||
548 | extract_section(data_sec, name, sec, size, " "); | ||
549 | free(sec); | ||
550 | } | ||
551 | } | ||
552 | else | ||
553 | { | ||
554 | /* advanced raw mode */ | ||
555 | color(BLUE); | ||
556 | printf("Commands\n"); | ||
557 | uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE; | ||
558 | byte iv[16]; | ||
559 | const char *indent = " "; | ||
560 | while(true) | ||
561 | { | ||
562 | /* restart with IV */ | ||
563 | memcpy(iv, g_buf, 16); | ||
564 | byte cmd[BLOCK_SIZE]; | ||
565 | if(sb_header->nr_keys > 0) | ||
566 | cbc_mac(g_buf + offset, cmd, 1, real_key, iv, &iv, 0); | ||
567 | else | ||
568 | memcpy(cmd, g_buf + offset, BLOCK_SIZE); | ||
569 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd; | ||
570 | printf("%s", indent); | ||
571 | uint8_t checksum = instruction_checksum(hdr); | ||
572 | if(checksum != hdr->checksum) | ||
573 | { | ||
574 | color(GREY); | ||
575 | printf("[Bad checksum']"); | ||
576 | } | ||
577 | |||
578 | if(hdr->opcode == SB_INST_NOP) | ||
579 | { | ||
580 | color(RED); | ||
581 | printf("NOOP\n"); | ||
582 | offset += BLOCK_SIZE; | ||
583 | } | ||
584 | else if(hdr->opcode == SB_INST_TAG) | ||
585 | { | ||
586 | struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr; | ||
587 | color(RED); | ||
588 | printf("BTAG"); | ||
589 | color(OFF);printf(" | "); | ||
590 | color(BLUE); | ||
591 | printf("sec=0x%08x", tag->identifier); | ||
592 | color(OFF);printf(" | "); | ||
593 | color(GREEN); | ||
594 | printf("cnt=0x%08x", tag->len); | ||
595 | color(OFF);printf(" | "); | ||
596 | color(YELLOW); | ||
597 | printf("flg=0x%08x", tag->flags); | ||
598 | color(OFF); | ||
599 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
600 | { | ||
601 | printf(" | "); | ||
602 | color(RED); | ||
603 | printf(" Last section"); | ||
604 | color(OFF); | ||
605 | } | ||
606 | printf("\n"); | ||
607 | offset += sizeof(struct sb_instruction_tag_t); | ||
608 | |||
609 | char name[5]; | ||
610 | fill_section_name(name, tag->identifier); | ||
611 | int pos = offset; | ||
612 | int size = tag->len * BLOCK_SIZE; | ||
613 | int data_sec = !(tag->flags & SECTION_BOOTABLE); | ||
614 | int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
615 | |||
616 | color(GREEN); | ||
617 | printf("%sSection ", indent); | ||
618 | color(YELLOW); | ||
619 | printf("'%s'\n", name); | ||
620 | color(GREEN); | ||
621 | printf("%s pos = ", indent); | ||
622 | color(YELLOW); | ||
623 | printf("%8x - %8x\n", pos, pos+size); | ||
624 | color(GREEN); | ||
625 | printf("%s len = ", indent); | ||
626 | color(YELLOW); | ||
627 | printf("%8x\n", size); | ||
628 | color(GREEN); | ||
629 | printf("%s flags = ", indent); | ||
630 | color(YELLOW); | ||
631 | printf("%8x", tag->flags); | ||
632 | color(RED); | ||
633 | if(data_sec) | ||
634 | printf(" Data Section"); | ||
635 | else | ||
636 | printf(" Boot Section"); | ||
637 | if(encrypted) | ||
638 | printf(" (Encrypted)"); | ||
639 | printf("\n"); | ||
640 | |||
641 | /* save it */ | ||
642 | byte *sec = xmalloc(size); | ||
643 | if(encrypted) | ||
644 | cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0); | ||
645 | else | ||
646 | memcpy(sec, g_buf + pos, size); | ||
647 | |||
648 | extract_section(data_sec, name, sec, size, " "); | ||
649 | free(sec); | ||
650 | |||
651 | /* last one ? */ | ||
652 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
653 | break; | ||
654 | offset += size; | ||
655 | } | ||
656 | else | ||
657 | { | ||
658 | color(RED); | ||
659 | printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset); | ||
660 | break; | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | |||
665 | /* final signature */ | ||
666 | color(BLUE); | ||
667 | printf("Final signature:\n"); | ||
668 | byte decrypted_block[32]; | ||
669 | if(sb_header->nr_keys > 0) | ||
670 | { | ||
671 | color(GREEN); | ||
672 | printf(" Encrypted SHA-1:\n"); | ||
673 | color(YELLOW); | ||
674 | byte *encrypted_block = &g_buf[filesize - 32]; | ||
675 | printf(" "); | ||
676 | print_hex(encrypted_block, 16, true); | ||
677 | printf(" "); | ||
678 | print_hex(encrypted_block + 16, 16, true); | ||
679 | /* decrypt it */ | ||
680 | cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0); | ||
681 | } | ||
682 | else | ||
683 | memcpy(decrypted_block, &g_buf[filesize - 32], 32); | ||
684 | color(GREEN); | ||
685 | printf(" File SHA-1:\n "); | ||
686 | color(YELLOW); | ||
687 | print_hex(decrypted_block, 20, false); | ||
688 | /* check it */ | ||
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); | ||
693 | color(RED); | ||
694 | if(memcmp(decrypted_block, computed_sha1, 20) == 0) | ||
695 | printf(" Ok\n"); | ||
696 | else | ||
697 | printf(" Failed\n"); | ||
698 | } | ||
699 | |||
700 | void usage(void) | ||
701 | { | 96 | { |
702 | printf("Usage: sbtoelf [options] sb-file\n"); | 97 | printf("Usage: sbtoelf [options] sb-file\n"); |
703 | printf("Options:\n"); | 98 | printf("Options:\n"); |
704 | printf(" -?/--help\tDisplay this message\n"); | 99 | printf(" -?/--help\tDisplay this message\n"); |
705 | printf(" -o <file>\tSet output prefix\n"); | 100 | printf(" -o <file>\tSet output prefix\n"); |
706 | printf(" -d/--debug\tEnable debug output\n"); | 101 | printf(" -d/--debug\tEnable debug output*\n"); |
707 | printf(" -k <file>\tAdd key file\n"); | 102 | printf(" -k <file>\tAdd key file\n"); |
708 | printf(" -z\t\tAdd zero key\n"); | 103 | printf(" -z\t\tAdd zero key\n"); |
709 | printf(" -r\t\tUse raw command mode\n"); | 104 | printf(" -r\t\tUse raw command mode\n"); |
710 | printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n"); | 105 | printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n"); |
711 | printf(" -n/--no-color\tDisable output colors\n"); | 106 | printf(" -n/--no-color\tDisable output colors\n"); |
107 | printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n"); | ||
108 | printf("Options marked with a * are for debug purpose only\n"); | ||
712 | exit(1); | 109 | exit(1); |
713 | } | 110 | } |
714 | 111 | ||
112 | static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...) | ||
113 | { | ||
114 | (void) user; | ||
115 | (void) error; | ||
116 | va_list args; | ||
117 | va_start(args, fmt); | ||
118 | color(c); | ||
119 | vprintf(fmt, args); | ||
120 | va_end(args); | ||
121 | } | ||
122 | |||
715 | static struct crypto_key_t g_zero_key = | 123 | static struct crypto_key_t g_zero_key = |
716 | { | 124 | { |
717 | .method = CRYPTO_KEY, | 125 | .method = CRYPTO_KEY, |
@@ -720,6 +128,9 @@ static struct crypto_key_t g_zero_key = | |||
720 | 128 | ||
721 | int main(int argc, char **argv) | 129 | int main(int argc, char **argv) |
722 | { | 130 | { |
131 | bool raw_mode = false; | ||
132 | const char *loopback = NULL; | ||
133 | |||
723 | while(1) | 134 | while(1) |
724 | { | 135 | { |
725 | static struct option long_options[] = | 136 | static struct option long_options[] = |
@@ -728,16 +139,22 @@ int main(int argc, char **argv) | |||
728 | {"debug", no_argument, 0, 'd'}, | 139 | {"debug", no_argument, 0, 'd'}, |
729 | {"add-key", required_argument, 0, 'a'}, | 140 | {"add-key", required_argument, 0, 'a'}, |
730 | {"no-color", no_argument, 0, 'n'}, | 141 | {"no-color", no_argument, 0, 'n'}, |
142 | {"loopback", required_argument, 0, 'l'}, | ||
731 | {0, 0, 0, 0} | 143 | {0, 0, 0, 0} |
732 | }; | 144 | }; |
733 | 145 | ||
734 | int c = getopt_long(argc, argv, "?do:k:zra:n", long_options, NULL); | 146 | int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL); |
735 | if(c == -1) | 147 | if(c == -1) |
736 | break; | 148 | break; |
737 | switch(c) | 149 | switch(c) |
738 | { | 150 | { |
739 | case -1: | 151 | case -1: |
740 | break; | 152 | break; |
153 | case 'l': | ||
154 | if(loopback) | ||
155 | bug("Only one loopback file can be specified !\n"); | ||
156 | loopback = optarg; | ||
157 | break; | ||
741 | case 'n': | 158 | case 'n': |
742 | enable_color(false); | 159 | enable_color(false); |
743 | break; | 160 | break; |
@@ -761,7 +178,7 @@ int main(int argc, char **argv) | |||
761 | break; | 178 | break; |
762 | } | 179 | } |
763 | case 'r': | 180 | case 'r': |
764 | g_raw_mode = true; | 181 | raw_mode = true; |
765 | break; | 182 | break; |
766 | case 'a': | 183 | case 'a': |
767 | { | 184 | { |
@@ -788,24 +205,26 @@ int main(int argc, char **argv) | |||
788 | return 1; | 205 | return 1; |
789 | } | 206 | } |
790 | 207 | ||
791 | const char *sb_file = argv[optind]; | 208 | const char *sb_filename = argv[optind]; |
792 | FILE *fd = fopen(sb_file, "rb"); | ||
793 | if(fd == NULL) | ||
794 | bug("Cannot open input file\n"); | ||
795 | fseek(fd, 0, SEEK_END); | ||
796 | size_t size = ftell(fd); | ||
797 | fseek(fd, 0, SEEK_SET); | ||
798 | |||
799 | g_buf = xmalloc(size); | ||
800 | if(fread(g_buf, 1, size, fd) != size) /* load the whole file into memory */ | ||
801 | bugp("reading firmware"); | ||
802 | |||
803 | fclose(fd); | ||
804 | |||
805 | extract(size); | ||
806 | 209 | ||
807 | color(OFF); | 210 | struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf); |
808 | 211 | if(g_debug) | |
809 | free(g_buf); | 212 | { |
213 | color(GREY); | ||
214 | printf("[Debug output]\n"); | ||
215 | sb_dump(file, NULL, sb_printf); | ||
216 | } | ||
217 | if(loopback) | ||
218 | { | ||
219 | /* sb_read_file will fill real key and IV but we don't want to override | ||
220 | * them when looping back otherwise the output will be inconsistent and | ||
221 | * garbage */ | ||
222 | free(file->real_key); | ||
223 | file->real_key = NULL; | ||
224 | free(file->crypto_iv); | ||
225 | file->crypto_iv = NULL; | ||
226 | sb_write_file(file, loopback); | ||
227 | } | ||
228 | |||
810 | return 0; | 229 | return 0; |
811 | } | 230 | } |