diff options
Diffstat (limited to 'utils/sbtools/sb.c')
-rw-r--r-- | utils/sbtools/sb.c | 680 |
1 files changed, 677 insertions, 3 deletions
diff --git a/utils/sbtools/sb.c b/utils/sbtools/sb.c index 3921710a2d..99f953600d 100644 --- a/utils/sbtools/sb.c +++ b/utils/sbtools/sb.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <stdio.h> | 21 | #include <stdio.h> |
22 | #include <time.h> | 22 | #include <time.h> |
23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
24 | #include <ctype.h> | ||
24 | #include "misc.h" | 25 | #include "misc.h" |
25 | #include "crypto.h" | 26 | #include "crypto.h" |
26 | #include "sb.h" | 27 | #include "sb.h" |
@@ -64,6 +65,7 @@ static void compute_sb_offsets(struct sb_file_t *sb) | |||
64 | alignment /= BLOCK_SIZE; /* alignment in block sizes */ | 65 | alignment /= BLOCK_SIZE; /* alignment in block sizes */ |
65 | 66 | ||
66 | struct sb_section_t *sec = &sb->sections[i]; | 67 | struct sb_section_t *sec = &sb->sections[i]; |
68 | sec->sec_size = 0; | ||
67 | 69 | ||
68 | if(g_debug) | 70 | if(g_debug) |
69 | { | 71 | { |
@@ -203,7 +205,7 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) | |||
203 | sb_hdr->flags = 0; | 205 | sb_hdr->flags = 0; |
204 | sb_hdr->image_size = sb->image_size; | 206 | sb_hdr->image_size = sb->image_size; |
205 | sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; | 207 | sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; |
206 | sb_hdr->first_boot_sec_id = sb->sections[0].identifier; | 208 | sb_hdr->first_boot_sec_id = sb->first_boot_sec_id; |
207 | sb_hdr->nr_keys = g_nr_keys; | 209 | sb_hdr->nr_keys = g_nr_keys; |
208 | sb_hdr->nr_sections = sb->nr_sections; | 210 | sb_hdr->nr_sections = sb->nr_sections; |
209 | sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; | 211 | sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; |
@@ -213,12 +215,17 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) | |||
213 | sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE; | 215 | sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE; |
214 | generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0)); | 216 | generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0)); |
215 | generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1)); | 217 | generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1)); |
218 | /* Version 1.0 has 6 bytes of random padding, | ||
219 | * Version 1.1 requires the last 4 bytes to be 'sgtl' */ | ||
220 | if(sb->minor_version >= 1) | ||
221 | memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4); | ||
222 | |||
216 | sb_hdr->timestamp = generate_timestamp(); | 223 | sb_hdr->timestamp = generate_timestamp(); |
217 | sb_hdr->product_ver = sb->product_ver; | 224 | sb_hdr->product_ver = sb->product_ver; |
218 | fix_version(&sb_hdr->product_ver); | 225 | fix_version(&sb_hdr->product_ver); |
219 | sb_hdr->component_ver = sb->component_ver; | 226 | sb_hdr->component_ver = sb->component_ver; |
220 | fix_version(&sb_hdr->component_ver); | 227 | fix_version(&sb_hdr->component_ver); |
221 | sb_hdr->drive_tag = 0; | 228 | sb_hdr->drive_tag = sb->drive_tag; |
222 | 229 | ||
223 | sha_1_init(&sha_1_params); | 230 | sha_1_init(&sha_1_params); |
224 | sha_1_update(&sha_1_params, &sb_hdr->signature[0], | 231 | sha_1_update(&sha_1_params, &sb_hdr->signature[0], |
@@ -292,7 +299,7 @@ void produce_sb_instruction(struct sb_inst_t *inst, | |||
292 | cmd->hdr.checksum = instruction_checksum(&cmd->hdr); | 299 | cmd->hdr.checksum = instruction_checksum(&cmd->hdr); |
293 | } | 300 | } |
294 | 301 | ||
295 | void sb_produce_file(struct sb_file_t *sb, const char *filename) | 302 | void sb_write_file(struct sb_file_t *sb, const char *filename) |
296 | { | 303 | { |
297 | FILE *fd = fopen(filename, "wb"); | 304 | FILE *fd = fopen(filename, "wb"); |
298 | if(fd == NULL) | 305 | if(fd == NULL) |
@@ -424,3 +431,670 @@ void sb_produce_file(struct sb_file_t *sb, const char *filename) | |||
424 | 431 | ||
425 | fclose(fd); | 432 | fclose(fd); |
426 | } | 433 | } |
434 | |||
435 | static void *memdup(void *p, size_t len) | ||
436 | { | ||
437 | void *cpy = xmalloc(len); | ||
438 | memcpy(cpy, p, len); | ||
439 | return cpy; | ||
440 | } | ||
441 | |||
442 | static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf, | ||
443 | int size, const char *indent, void *u, sb_color_printf cprintf) | ||
444 | { | ||
445 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
446 | |||
447 | struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t)); | ||
448 | memset(sec, 0, sizeof(struct sb_section_t)); | ||
449 | sec->identifier = id; | ||
450 | sec->is_data = data_sec; | ||
451 | sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE; | ||
452 | |||
453 | if(data_sec) | ||
454 | { | ||
455 | sec->nr_insts = 1; | ||
456 | sec->insts = xmalloc(sizeof(struct sb_inst_t)); | ||
457 | memset(sec->insts, 0, sizeof(struct sb_inst_t)); | ||
458 | sec->insts->inst = SB_INST_DATA; | ||
459 | sec->insts->size = size; | ||
460 | sec->insts->data = memdup(buf, size); | ||
461 | return sec; | ||
462 | } | ||
463 | |||
464 | /* Pretty print the content */ | ||
465 | int pos = 0; | ||
466 | while(pos < size) | ||
467 | { | ||
468 | struct sb_inst_t inst; | ||
469 | memset(&inst, 0, sizeof(inst)); | ||
470 | |||
471 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos]; | ||
472 | inst.inst = hdr->opcode; | ||
473 | |||
474 | printf(OFF, "%s", indent); | ||
475 | uint8_t checksum = instruction_checksum(hdr); | ||
476 | if(checksum != hdr->checksum) | ||
477 | printf(GREY, "[Bad checksum]"); | ||
478 | if(hdr->flags != 0) | ||
479 | { | ||
480 | printf(GREY, "["); | ||
481 | printf(BLUE, "f=%x", hdr->flags); | ||
482 | printf(GREY, "] "); | ||
483 | } | ||
484 | if(hdr->opcode == SB_INST_LOAD) | ||
485 | { | ||
486 | struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos]; | ||
487 | inst.size = load->len; | ||
488 | inst.addr = load->addr; | ||
489 | inst.data = memdup(load + 1, load->len); | ||
490 | |||
491 | printf(RED, "LOAD"); | ||
492 | printf(OFF, " | "); | ||
493 | printf(BLUE, "addr=0x%08x", load->addr); | ||
494 | printf(OFF, " | "); | ||
495 | printf(GREEN, "len=0x%08x", load->len); | ||
496 | printf(OFF, " | "); | ||
497 | printf(YELLOW, "crc=0x%08x", load->crc); | ||
498 | /* data is padded to 16-byte boundary with random data and crc'ed with it */ | ||
499 | uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)], | ||
500 | ROUND_UP(load->len, 16)); | ||
501 | if(load->crc == computed_crc) | ||
502 | printf(RED, " Ok\n"); | ||
503 | else | ||
504 | printf(RED, " Failed (crc=0x%08x)\n", computed_crc); | ||
505 | |||
506 | pos += load->len + sizeof(struct sb_instruction_load_t); | ||
507 | } | ||
508 | else if(hdr->opcode == SB_INST_FILL) | ||
509 | { | ||
510 | struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos]; | ||
511 | inst.pattern = fill->pattern; | ||
512 | inst.size = fill->len; | ||
513 | inst.addr = fill->addr; | ||
514 | |||
515 | printf(RED, "FILL"); | ||
516 | printf(OFF, " | "); | ||
517 | printf(BLUE, "addr=0x%08x", fill->addr); | ||
518 | printf(OFF, " | "); | ||
519 | printf(GREEN, "len=0x%08x", fill->len); | ||
520 | printf(OFF, " | "); | ||
521 | printf(YELLOW, "pattern=0x%08x\n", fill->pattern); | ||
522 | |||
523 | pos += sizeof(struct sb_instruction_fill_t); | ||
524 | } | ||
525 | else if(hdr->opcode == SB_INST_CALL || | ||
526 | hdr->opcode == SB_INST_JUMP) | ||
527 | { | ||
528 | int is_call = (hdr->opcode == SB_INST_CALL); | ||
529 | struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos]; | ||
530 | inst.addr = call->addr; | ||
531 | inst.argument = call->arg; | ||
532 | |||
533 | if(is_call) | ||
534 | printf(RED, "CALL"); | ||
535 | else | ||
536 | printf(RED, "JUMP"); | ||
537 | printf(OFF, " | "); | ||
538 | printf(BLUE, "addr=0x%08x", call->addr); | ||
539 | printf(OFF, " | "); | ||
540 | printf(GREEN, "arg=0x%08x\n", call->arg); | ||
541 | |||
542 | pos += sizeof(struct sb_instruction_call_t); | ||
543 | } | ||
544 | else if(hdr->opcode == SB_INST_MODE) | ||
545 | { | ||
546 | struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr; | ||
547 | inst.argument = mode->mode; | ||
548 | |||
549 | printf(RED, "MODE"); | ||
550 | printf(OFF, " | "); | ||
551 | printf(BLUE, "mod=0x%08x\n", mode->mode); | ||
552 | |||
553 | pos += sizeof(struct sb_instruction_mode_t); | ||
554 | } | ||
555 | else if(hdr->opcode == SB_INST_NOP) | ||
556 | { | ||
557 | printf(RED, "NOOP\n"); | ||
558 | pos += sizeof(struct sb_instruction_mode_t); | ||
559 | } | ||
560 | else | ||
561 | { | ||
562 | printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos); | ||
563 | break; | ||
564 | } | ||
565 | |||
566 | sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1); | ||
567 | pos = ROUND_UP(pos, BLOCK_SIZE); | ||
568 | } | ||
569 | |||
570 | return sec; | ||
571 | #undef printf | ||
572 | } | ||
573 | |||
574 | static void fill_section_name(char name[5], uint32_t identifier) | ||
575 | { | ||
576 | name[0] = (identifier >> 24) & 0xff; | ||
577 | name[1] = (identifier >> 16) & 0xff; | ||
578 | name[2] = (identifier >> 8) & 0xff; | ||
579 | name[3] = identifier & 0xff; | ||
580 | for(int i = 0; i < 4; i++) | ||
581 | if(!isprint(name[i])) | ||
582 | name[i] = '_'; | ||
583 | name[4] = 0; | ||
584 | } | ||
585 | |||
586 | static uint32_t guess_alignment(uint32_t off) | ||
587 | { | ||
588 | /* find greatest power of two which divides the offset */ | ||
589 | if(off == 0) | ||
590 | return 1; | ||
591 | uint32_t a = 1; | ||
592 | while(off % (2 * a) == 0) | ||
593 | a *= 2; | ||
594 | return a; | ||
595 | } | ||
596 | |||
597 | struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, | ||
598 | sb_color_printf cprintf) | ||
599 | { | ||
600 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
601 | #define fatal(...) do { cprintf(u, true, GREY, __VA_ARGS__); return NULL; } while(0) | ||
602 | #define print_hex(c, p, len, nl) \ | ||
603 | do { printf(c, ""); print_hex(p, len, nl); } while(0) | ||
604 | |||
605 | FILE *f = fopen(filename, "rb"); | ||
606 | if(f == NULL) | ||
607 | fatal("Cannot open file for reading\n"); | ||
608 | fseek(f, 0, SEEK_END); | ||
609 | long filesize = ftell(f); | ||
610 | fseek(f, 0, SEEK_SET); | ||
611 | uint8_t *buf = xmalloc(filesize); | ||
612 | fread(buf, 1, filesize, f); | ||
613 | fclose(f); | ||
614 | |||
615 | struct sha_1_params_t sha_1_params; | ||
616 | struct sb_file_t *sb_file = xmalloc(sizeof(struct sb_file_t)); | ||
617 | memset(sb_file, 0, sizeof(struct sb_file_t)); | ||
618 | struct sb_header_t *sb_header = (struct sb_header_t *)buf; | ||
619 | |||
620 | sb_file->image_size = sb_header->image_size; | ||
621 | sb_file->minor_version = sb_header->minor_ver; | ||
622 | sb_file->flags = sb_header->flags; | ||
623 | sb_file->drive_tag = sb_header->drive_tag; | ||
624 | sb_file->first_boot_sec_id = sb_header->first_boot_sec_id; | ||
625 | |||
626 | if(memcmp(sb_header->signature, "STMP", 4) != 0) | ||
627 | fatal("Bad signature\n"); | ||
628 | if(sb_header->image_size * BLOCK_SIZE > filesize) | ||
629 | fatal("File too small mismatch"); | ||
630 | if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t)) | ||
631 | fatal("Bad header size"); | ||
632 | if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t)) | ||
633 | fatal("Bad section header size"); | ||
634 | |||
635 | if(filesize > sb_header->image_size * BLOCK_SIZE) | ||
636 | { | ||
637 | printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize, | ||
638 | sb_header->image_size * BLOCK_SIZE); | ||
639 | filesize = sb_header->image_size * BLOCK_SIZE; | ||
640 | } | ||
641 | |||
642 | printf(BLUE, "Basic info:\n"); | ||
643 | printf(GREEN, " SB version: "); | ||
644 | printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver); | ||
645 | printf(GREEN, " Header SHA-1: "); | ||
646 | byte *hdr_sha1 = sb_header->sha1_header; | ||
647 | print_hex(YELLOW, hdr_sha1, 20, false); | ||
648 | /* Check SHA1 sum */ | ||
649 | byte computed_sha1[20]; | ||
650 | sha_1_init(&sha_1_params); | ||
651 | sha_1_update(&sha_1_params, &sb_header->signature[0], | ||
652 | sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header)); | ||
653 | sha_1_finish(&sha_1_params); | ||
654 | sha_1_output(&sha_1_params, computed_sha1); | ||
655 | if(memcmp(hdr_sha1, computed_sha1, 20) == 0) | ||
656 | printf(RED, " Ok\n"); | ||
657 | else | ||
658 | printf(RED, " Failed\n"); | ||
659 | printf(GREEN, " Flags: "); | ||
660 | printf(YELLOW, "%x\n", sb_header->flags); | ||
661 | printf(GREEN, " Total file size : "); | ||
662 | printf(YELLOW, "%ld\n", filesize); | ||
663 | |||
664 | /* Sizes and offsets */ | ||
665 | printf(BLUE, "Sizes and offsets:\n"); | ||
666 | printf(GREEN, " # of encryption keys = "); | ||
667 | printf(YELLOW, "%d\n", sb_header->nr_keys); | ||
668 | printf(GREEN, " # of sections = "); | ||
669 | printf(YELLOW, "%d\n", sb_header->nr_sections); | ||
670 | |||
671 | /* Versions */ | ||
672 | printf(BLUE, "Versions\n"); | ||
673 | |||
674 | printf(GREEN, " Random 1: "); | ||
675 | print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true); | ||
676 | printf(GREEN, " Random 2: "); | ||
677 | print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true); | ||
678 | |||
679 | uint64_t micros = sb_header->timestamp; | ||
680 | time_t seconds = (micros / (uint64_t)1000000L); | ||
681 | struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ | ||
682 | seconds += mktime(&tm_base); | ||
683 | struct tm *time = gmtime(&seconds); | ||
684 | printf(GREEN, " Creation date/time = "); | ||
685 | printf(YELLOW, "%s", asctime(time)); | ||
686 | |||
687 | struct sb_version_t product_ver = sb_header->product_ver; | ||
688 | fix_version(&product_ver); | ||
689 | struct sb_version_t component_ver = sb_header->component_ver; | ||
690 | fix_version(&component_ver); | ||
691 | |||
692 | memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver)); | ||
693 | memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver)); | ||
694 | |||
695 | printf(GREEN, " Product version = "); | ||
696 | printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision); | ||
697 | printf(GREEN, " Component version = "); | ||
698 | printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision); | ||
699 | |||
700 | printf(GREEN, " Drive tag = "); | ||
701 | printf(YELLOW, "%x\n", sb_header->drive_tag); | ||
702 | printf(GREEN, " First boot tag offset = "); | ||
703 | printf(YELLOW, "%x\n", sb_header->first_boot_tag_off); | ||
704 | printf(GREEN, " First boot section ID = "); | ||
705 | printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id); | ||
706 | |||
707 | /* encryption cbc-mac */ | ||
708 | byte real_key[16]; | ||
709 | bool valid_key = false; /* false until a matching key was found */ | ||
710 | if(sb_header->nr_keys > 0) | ||
711 | { | ||
712 | if(sb_header->nr_keys > g_nr_keys) | ||
713 | { | ||
714 | fatal("SB file has %d keys but only %d were specified\n", | ||
715 | sb_header->nr_keys, g_nr_keys); | ||
716 | } | ||
717 | printf(BLUE, "Encryption data\n"); | ||
718 | for(int i = 0; i < sb_header->nr_keys; i++) | ||
719 | { | ||
720 | printf(RED, " Key %d: ", i); | ||
721 | printf(YELLOW, ""); | ||
722 | print_key(&g_key_array[i], true); | ||
723 | printf(GREEN, " CBC-MAC of headers: "); | ||
724 | |||
725 | uint32_t ofs = sizeof(struct sb_header_t) | ||
726 | + sizeof(struct sb_section_header_t) * sb_header->nr_sections | ||
727 | + sizeof(struct sb_key_dictionary_entry_t) * i; | ||
728 | struct sb_key_dictionary_entry_t *dict_entry = | ||
729 | (struct sb_key_dictionary_entry_t *)&buf[ofs]; | ||
730 | /* cbc mac */ | ||
731 | print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false); | ||
732 | /* check it */ | ||
733 | byte computed_cbc_mac[16]; | ||
734 | byte zero[16]; | ||
735 | memset(zero, 0, 16); | ||
736 | crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections, | ||
737 | &g_key_array[i], zero, &computed_cbc_mac, 1); | ||
738 | |||
739 | bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0; | ||
740 | if(ok) | ||
741 | { | ||
742 | valid_key = true; | ||
743 | printf(RED, " Ok\n"); | ||
744 | } | ||
745 | else | ||
746 | printf(RED, " Failed\n"); | ||
747 | |||
748 | printf(GREEN, " Encrypted key : "); | ||
749 | print_hex(YELLOW, dict_entry->key, 16, true); | ||
750 | /* decrypt */ | ||
751 | byte decrypted_key[16]; | ||
752 | byte iv[16]; | ||
753 | memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ | ||
754 | crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0); | ||
755 | printf(GREEN, " Decrypted key : "); | ||
756 | print_hex(YELLOW, decrypted_key, 16, false); | ||
757 | /* cross-check or copy */ | ||
758 | if(valid_key && ok) | ||
759 | memcpy(real_key, decrypted_key, 16); | ||
760 | else if(valid_key) | ||
761 | { | ||
762 | if(memcmp(real_key, decrypted_key, 16) == 0) | ||
763 | printf(RED, " Cross-Check Ok"); | ||
764 | else | ||
765 | printf(RED, " Cross-Check Failed"); | ||
766 | } | ||
767 | printf(OFF, "\n"); | ||
768 | } | ||
769 | } | ||
770 | |||
771 | if(getenv("SB_REAL_KEY") != 0) | ||
772 | { | ||
773 | struct crypto_key_t k; | ||
774 | char *env = getenv("SB_REAL_KEY"); | ||
775 | if(!parse_key(&env, &k) || *env) | ||
776 | bug("Invalid SB_REAL_KEY"); | ||
777 | memcpy(real_key, k.u.key, 16); | ||
778 | } | ||
779 | |||
780 | printf(RED, " Summary:\n"); | ||
781 | printf(GREEN, " Real key: "); | ||
782 | print_hex(YELLOW, real_key, 16, true); | ||
783 | printf(GREEN, " IV : "); | ||
784 | print_hex(YELLOW, buf, 16, true); | ||
785 | |||
786 | sb_file->real_key = xmalloc(16); | ||
787 | memcpy(*sb_file->real_key, real_key, 16); | ||
788 | sb_file->crypto_iv = xmalloc(16); | ||
789 | memcpy(*sb_file->crypto_iv, buf, 16); | ||
790 | |||
791 | /* sections */ | ||
792 | if(!raw_mode) | ||
793 | { | ||
794 | sb_file->nr_sections = sb_header->nr_sections; | ||
795 | sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t)); | ||
796 | memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t)); | ||
797 | printf(BLUE, "Sections\n"); | ||
798 | for(int i = 0; i < sb_header->nr_sections; i++) | ||
799 | { | ||
800 | uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t); | ||
801 | struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs]; | ||
802 | |||
803 | char name[5]; | ||
804 | fill_section_name(name, sec_hdr->identifier); | ||
805 | int pos = sec_hdr->offset * BLOCK_SIZE; | ||
806 | int size = sec_hdr->size * BLOCK_SIZE; | ||
807 | int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE); | ||
808 | int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
809 | |||
810 | printf(GREEN, " Section "); | ||
811 | printf(YELLOW, "'%s'\n", name); | ||
812 | printf(GREEN, " pos = "); | ||
813 | printf(YELLOW, "%8x - %8x\n", pos, pos+size); | ||
814 | printf(GREEN, " len = "); | ||
815 | printf(YELLOW, "%8x\n", size); | ||
816 | printf(GREEN, " flags = "); | ||
817 | printf(YELLOW, "%8x", sec_hdr->flags); | ||
818 | if(data_sec) | ||
819 | printf(RED, " Data Section"); | ||
820 | else | ||
821 | printf(RED, " Boot Section"); | ||
822 | if(encrypted) | ||
823 | printf(RED, " (Encrypted)"); | ||
824 | printf(OFF, "\n"); | ||
825 | |||
826 | /* save it */ | ||
827 | byte *sec = xmalloc(size); | ||
828 | if(encrypted) | ||
829 | cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); | ||
830 | else | ||
831 | memcpy(sec, buf + pos, size); | ||
832 | |||
833 | struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier, | ||
834 | sec, size, " ", u, cprintf); | ||
835 | if(s) | ||
836 | { | ||
837 | s->is_cleartext = !encrypted; | ||
838 | s->alignment = guess_alignment(pos); | ||
839 | memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t)); | ||
840 | free(s); | ||
841 | } | ||
842 | |||
843 | free(sec); | ||
844 | } | ||
845 | } | ||
846 | else | ||
847 | { | ||
848 | /* advanced raw mode */ | ||
849 | printf(BLUE, "Commands\n"); | ||
850 | uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE; | ||
851 | byte iv[16]; | ||
852 | const char *indent = " "; | ||
853 | while(true) | ||
854 | { | ||
855 | /* restart with IV */ | ||
856 | memcpy(iv, buf, 16); | ||
857 | byte cmd[BLOCK_SIZE]; | ||
858 | if(sb_header->nr_keys > 0) | ||
859 | cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0); | ||
860 | else | ||
861 | memcpy(cmd, buf + offset, BLOCK_SIZE); | ||
862 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd; | ||
863 | printf(OFF, "%s", indent); | ||
864 | uint8_t checksum = instruction_checksum(hdr); | ||
865 | if(checksum != hdr->checksum) | ||
866 | printf(GREY, "[Bad checksum']"); | ||
867 | |||
868 | if(hdr->opcode == SB_INST_NOP) | ||
869 | { | ||
870 | printf(RED, "NOOP\n"); | ||
871 | offset += BLOCK_SIZE; | ||
872 | } | ||
873 | else if(hdr->opcode == SB_INST_TAG) | ||
874 | { | ||
875 | struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr; | ||
876 | printf(RED, "BTAG"); | ||
877 | printf(OFF, " | "); | ||
878 | printf(BLUE, "sec=0x%08x", tag->identifier); | ||
879 | printf(OFF, " | "); | ||
880 | printf(GREEN, "cnt=0x%08x", tag->len); | ||
881 | printf(OFF, " | "); | ||
882 | printf(YELLOW, "flg=0x%08x", tag->flags); | ||
883 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
884 | { | ||
885 | printf(OFF, " | "); | ||
886 | printf(RED, " Last section"); | ||
887 | } | ||
888 | printf(OFF, "\n"); | ||
889 | offset += sizeof(struct sb_instruction_tag_t); | ||
890 | |||
891 | char name[5]; | ||
892 | fill_section_name(name, tag->identifier); | ||
893 | int pos = offset; | ||
894 | int size = tag->len * BLOCK_SIZE; | ||
895 | int data_sec = !(tag->flags & SECTION_BOOTABLE); | ||
896 | int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
897 | |||
898 | printf(GREEN, "%sSection ", indent); | ||
899 | printf(YELLOW, "'%s'\n", name); | ||
900 | printf(GREEN, "%s pos = ", indent); | ||
901 | printf(YELLOW, "%8x - %8x\n", pos, pos+size); | ||
902 | printf(GREEN, "%s len = ", indent); | ||
903 | printf(YELLOW, "%8x\n", size); | ||
904 | printf(GREEN, "%s flags = ", indent); | ||
905 | printf(YELLOW, "%8x", tag->flags); | ||
906 | if(data_sec) | ||
907 | printf(RED, " Data Section"); | ||
908 | else | ||
909 | printf(RED, " Boot Section"); | ||
910 | if(encrypted) | ||
911 | printf(RED, " (Encrypted)"); | ||
912 | printf(OFF, "\n"); | ||
913 | |||
914 | /* save it */ | ||
915 | byte *sec = xmalloc(size); | ||
916 | if(encrypted) | ||
917 | cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); | ||
918 | else | ||
919 | memcpy(sec, buf + pos, size); | ||
920 | |||
921 | struct sb_section_t *s = read_section(data_sec, tag->identifier, | ||
922 | sec, size, " ", u, cprintf); | ||
923 | if(s) | ||
924 | { | ||
925 | s->is_cleartext = !encrypted; | ||
926 | s->alignment = guess_alignment(pos); | ||
927 | sb_file->sections = augment_array(sb_file->sections, | ||
928 | sizeof(struct sb_section_t), sb_file->nr_sections++, | ||
929 | s, 1); | ||
930 | free(s); | ||
931 | } | ||
932 | free(sec); | ||
933 | |||
934 | /* last one ? */ | ||
935 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
936 | break; | ||
937 | offset += size; | ||
938 | } | ||
939 | else | ||
940 | { | ||
941 | printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset); | ||
942 | break; | ||
943 | } | ||
944 | } | ||
945 | } | ||
946 | |||
947 | /* final signature */ | ||
948 | printf(BLUE, "Final signature:\n"); | ||
949 | byte decrypted_block[32]; | ||
950 | if(sb_header->nr_keys > 0) | ||
951 | { | ||
952 | printf(GREEN, " Encrypted SHA-1:\n"); | ||
953 | byte *encrypted_block = &buf[filesize - 32]; | ||
954 | printf(OFF, " "); | ||
955 | print_hex(YELLOW, encrypted_block, 16, true); | ||
956 | printf(OFF, " "); | ||
957 | print_hex(YELLOW, encrypted_block + 16, 16, true); | ||
958 | /* decrypt it */ | ||
959 | cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0); | ||
960 | } | ||
961 | else | ||
962 | memcpy(decrypted_block, &buf[filesize - 32], 32); | ||
963 | printf(GREEN, " File SHA-1:\n "); | ||
964 | print_hex(YELLOW, decrypted_block, 20, false); | ||
965 | /* check it */ | ||
966 | sha_1_init(&sha_1_params); | ||
967 | sha_1_update(&sha_1_params, buf, filesize - 32); | ||
968 | sha_1_finish(&sha_1_params); | ||
969 | sha_1_output(&sha_1_params, computed_sha1); | ||
970 | if(memcmp(decrypted_block, computed_sha1, 20) == 0) | ||
971 | printf(RED, " Ok\n"); | ||
972 | else | ||
973 | printf(RED, " Failed\n"); | ||
974 | free(buf); | ||
975 | |||
976 | return sb_file; | ||
977 | #undef printf | ||
978 | #undef fatal | ||
979 | #undef print_hex | ||
980 | } | ||
981 | |||
982 | void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf) | ||
983 | { | ||
984 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
985 | #define print_hex(c, p, len, nl) \ | ||
986 | do { printf(c, ""); print_hex(p, len, nl); } while(0) | ||
987 | |||
988 | #define TREE RED | ||
989 | #define HEADER GREEN | ||
990 | #define TEXT YELLOW | ||
991 | #define TEXT2 BLUE | ||
992 | #define SEP OFF | ||
993 | |||
994 | printf(HEADER, "SB File\n"); | ||
995 | printf(TREE, "+-"); | ||
996 | printf(HEADER, "Version: "); | ||
997 | printf(TEXT, "1.%d\n", file->minor_version); | ||
998 | printf(TREE, "+-"); | ||
999 | printf(HEADER, "Flags: "); | ||
1000 | printf(TEXT, "%x\n", file->flags); | ||
1001 | printf(TREE, "+-"); | ||
1002 | printf(HEADER, "Drive Tag: "); | ||
1003 | printf(TEXT, "%x\n", file->drive_tag); | ||
1004 | printf(TREE, "+-"); | ||
1005 | printf(HEADER, "First Boot Section ID: "); | ||
1006 | char name[5]; | ||
1007 | fill_section_name(name, file->first_boot_sec_id); | ||
1008 | printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name); | ||
1009 | |||
1010 | if(file->real_key) | ||
1011 | { | ||
1012 | printf(TREE, "+-"); | ||
1013 | printf(HEADER, "Real key: "); | ||
1014 | print_hex(TEXT, *file->real_key, 16, true); | ||
1015 | } | ||
1016 | if(file->crypto_iv) | ||
1017 | { | ||
1018 | printf(TREE, "+-"); | ||
1019 | printf(HEADER, "IV : "); | ||
1020 | print_hex(TEXT, *file->crypto_iv, 16, true); | ||
1021 | } | ||
1022 | printf(TREE, "+-"); | ||
1023 | printf(HEADER, "Product Version: "); | ||
1024 | printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor, | ||
1025 | file->product_ver.revision); | ||
1026 | printf(TREE, "+-"); | ||
1027 | printf(HEADER, "Component Version: "); | ||
1028 | printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor, | ||
1029 | file->component_ver.revision); | ||
1030 | |||
1031 | for(int i = 0; i < file->nr_sections; i++) | ||
1032 | { | ||
1033 | struct sb_section_t *sec = &file->sections[i]; | ||
1034 | printf(TREE, "+-"); | ||
1035 | printf(HEADER, "Section\n"); | ||
1036 | printf(TREE,"| +-"); | ||
1037 | printf(HEADER, "Identifier: "); | ||
1038 | fill_section_name(name, sec->identifier); | ||
1039 | printf(TEXT, "%08x (%s)\n", sec->identifier, name); | ||
1040 | printf(TREE, "| +-"); | ||
1041 | printf(HEADER, "Type: "); | ||
1042 | printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section", | ||
1043 | sec->is_cleartext ? "Cleartext" : "Encrypted"); | ||
1044 | printf(TREE, "| +-"); | ||
1045 | printf(HEADER, "Alignment: "); | ||
1046 | printf(TEXT, "%d (bytes)\n", sec->alignment); | ||
1047 | printf(TREE, "| +-"); | ||
1048 | printf(HEADER, "Instructions\n"); | ||
1049 | for(int j = 0; j < sec->nr_insts; j++) | ||
1050 | { | ||
1051 | struct sb_inst_t *inst = &sec->insts[j]; | ||
1052 | printf(TREE, "| | +-"); | ||
1053 | switch(inst->inst) | ||
1054 | { | ||
1055 | case SB_INST_DATA: | ||
1056 | printf(HEADER, "DATA"); | ||
1057 | printf(SEP, " | "); | ||
1058 | printf(TEXT, "size=0x%08x\n", inst->size); | ||
1059 | break; | ||
1060 | case SB_INST_CALL: | ||
1061 | case SB_INST_JUMP: | ||
1062 | printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP"); | ||
1063 | printf(SEP, " | "); | ||
1064 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1065 | printf(SEP, " | "); | ||
1066 | printf(TEXT2, "arg=0x%08x\n", inst->argument); | ||
1067 | break; | ||
1068 | case SB_INST_LOAD: | ||
1069 | printf(HEADER, "LOAD"); | ||
1070 | printf(SEP, " | "); | ||
1071 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1072 | printf(SEP, " | "); | ||
1073 | printf(TEXT2, "len=0x%08x\n", inst->size); | ||
1074 | break; | ||
1075 | case SB_INST_FILL: | ||
1076 | printf(HEADER, "FILL"); | ||
1077 | printf(SEP, " | "); | ||
1078 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1079 | printf(SEP, " | "); | ||
1080 | printf(TEXT2, "len=0x%08x", inst->size); | ||
1081 | printf(SEP, " | "); | ||
1082 | printf(TEXT2, "pattern=0x%08x\n", inst->pattern); | ||
1083 | break; | ||
1084 | case SB_INST_MODE: | ||
1085 | printf(HEADER, "MODE"); | ||
1086 | printf(SEP, " | "); | ||
1087 | printf(TEXT, "mod=0x%08x\n", inst->addr); | ||
1088 | break; | ||
1089 | case SB_INST_NOP: | ||
1090 | printf(HEADER, "NOOP\n"); | ||
1091 | break; | ||
1092 | default: | ||
1093 | printf(GREY, "[Unknown instruction %x]\n", inst->inst); | ||
1094 | } | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | #undef printf | ||
1099 | #undef print_hex | ||
1100 | } | ||