Boot Record Dump
Here is a tool I wrote to dump information from boot records, the information normally stored in the first sector (boot sector) on a disk or partition. It attempts to automatically figure out if the record is a Master Boot Record (MBR) or a Volume Boot Record (VBR).
The boot record (file) can be extracted with the Unix "dd" tool, like so: 'dd bs=512 count=1 if=/dev/hda of=/tmp/br.dd'.
Here's an example of the information dumped from a MBR:
Master Boot Record (MBR) ------------------------ Serial: DCA41F6C Partition Table: Boot Type First LBA First C:H:S Last C:H:S Size * 0x04 0x0000003f 0000:001:01 -> 0002:254:63 (23 MB) 0x05 0x0000bc43 0003:000:01 -> 0123:254:63 (949 MB) 0x00 0x00000000 0000:000:00 -> 0000:000:00 --- 0x00 0x00000000 0000:000:00 -> 0000:000:00 --- Code: 0x0000: fa 33 c0 8e d0 bc 00 7c 8b f4 50 07 50 1f fb fc |.3.....|..P.P...| 0x0010: bf 00 06 b9 00 01 f2 a5 ea 1d 06 00 00 be be 07 |................| 0x0020: b3 04 80 3c 80 74 0e 80 3c 00 75 1c 83 c6 10 fe |...<.t..<.u.....| 0x0030: cb 75 ef cd 18 8b 14 8b 4c 02 8b ee 83 c6 10 fe |.u......L.......| 0x0040: cb 74 1a 80 3c 00 74 f4 be 8b 06 ac 3c 00 74 0b |.t..<.t.....<.t.| 0x0050: 56 bb 07 00 b4 0e cd 10 5e eb f0 eb fe bf 05 00 |V.......^.......| 0x0060: bb 00 7c b8 01 02 57 cd 13 5f 73 0c 33 c0 cd 13 |..|...W.._s.3...| 0x0070: 4f 75 ed be a3 06 eb d3 be c2 06 bf fe 7d 81 3d |Ou...........}.=| 0x0080: 55 aa 75 c7 8b f5 ea 00 7c 00 00 49 6e 76 61 6c |U.u.....|..Inval| 0x0090: 69 64 20 70 61 72 74 69 74 69 6f 6e 20 74 61 62 |id partition tab| 0x00a0: 6c 65 00 45 72 72 6f 72 20 6c 6f 61 64 69 6e 67 |le.Error loading| 0x00b0: 20 6f 70 65 72 61 74 69 6e 67 20 73 79 73 74 65 | operating syste| 0x00c0: 6d 00 4d 69 73 73 69 6e 67 20 6f 70 65 72 61 74 |m.Missing operat| 0x00d0: 69 6e 67 20 73 79 73 74 65 6d 00 00 00 00 00 00 |ing system......| 0x00e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x00f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x0190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x01a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0x01b0: 00 00 00 00 00 00 00 00 |................|
Here's an example of the information dumped from a VBR:
Volume Boot Record (VBR) ------------------------ Jump Code : 0xeb 0x3c 0x90 (jmp short 0x3E) OEM ID : 'MSWIN4.1' Volume Label : 'USER ' System ID : 'FAT16 ' Bytes per Sector : 512 Sectors per Cluster : 64 Sectors per FAT : 242 Sectors per Track : 63 No of FATs : 2 Reserved Sectors : 1 Hidden Sectors : 63 Small Sectors : 0 Large Sectors : 3951237 Root Entries : 512 Heads : 64 Current Head : 0 Media Descriptor : 0xF8 (Fixed Disk) Physical Drive Number: 0x80 Signature : 0x29 ID : E5165E0B Boot Code: 0x0030: 33 c9 |..............3.| 0x0040: 8e d1 bc fc 7b 16 07 bd 78 00 c5 76 00 1e 56 16 |....{...x..v..V.| 0x0050: 55 bf 22 05 89 7e 00 89 4e 02 b1 0b fc f3 a4 06 |U."..~..N.......| 0x0060: 1f bd 00 7c c6 45 fe 0f 38 4e 24 7d 20 8b c1 99 |...|.E..8N$} ...| 0x0070: e8 7e 01 83 eb 3a 66 a1 1c 7c 66 3b 07 8a 57 fc |.~...:f..|f;..W.| 0x0080: 75 06 80 ca 02 88 56 02 80 c3 10 73 ed 33 c9 fe |u.....V....s.3..| 0x0090: 06 d8 7d 8a 46 10 98 f7 66 16 03 46 1c 13 56 1e |..}.F...f..F..V.| 0x00a0: 03 46 0e 13 d1 8b 76 11 60 89 46 fc 89 56 fe b8 |.F....v.`.F..V..| 0x00b0: 20 00 f7 e6 8b 5e 0b 03 c3 48 f7 f3 01 46 fc 11 | ....^...H...F..| 0x00c0: 4e fe 61 bf 00 07 e8 28 01 72 3e 38 2d 74 17 60 |N.a....(.r>8-t.`| 0x00d0: b1 0b be d8 7d f3 a6 61 74 3d 4e 74 09 83 c7 20 |....}..at=Nt... | 0x00e0: 3b fb 72 e7 eb dd fe 0e d8 7d 7b a7 be 7f 7d ac |;.r......}{...}.| 0x00f0: 98 03 f0 ac 98 40 74 0c 48 74 13 b4 0e bb 07 00 |.....@t.Ht......| 0x0100: cd 10 eb ef be 82 7d eb e6 be 80 7d eb e1 cd 16 |......}....}....| 0x0110: 5e 1f 66 8f 04 cd 19 be 81 7d 8b 7d 1a 8d 45 fe |^.f......}.}..E.| 0x0120: 8a 4e 0d f7 e1 03 46 fc 13 56 fe b1 04 e8 c2 00 |.N....F..V......| 0x0130: 72 d7 ea 00 02 70 00 52 50 06 53 6a 01 6a 10 91 |r....p.RP.Sj.j..| 0x0140: 8b 46 18 a2 26 05 96 92 33 d2 f7 f6 91 f7 f6 42 |.F..&...3......B| 0x0150: 87 ca f7 76 1a 8a f2 8a e8 c0 cc 02 0a cc b8 01 |...v............| 0x0160: 02 80 7e 02 0e 75 04 b4 42 8b f4 8a 56 24 cd 13 |..~..u..B...V$..| 0x0170: 61 61 72 0a 40 75 01 42 03 5e 0b 49 75 77 c3 03 |aar.@u.B.^.Iuw..| 0x0180: 18 01 27 0d 0a 49 6e 76 61 6c 69 64 20 73 79 73 |..'..Invalid sys| 0x0190: 74 65 6d 20 64 69 73 6b ff 0d 0a 44 69 73 6b 20 |tem disk...Disk | 0x01a0: 49 2f 4f 20 65 72 72 6f 72 ff 0d 0a 52 65 70 6c |I/O error...Repl| 0x01b0: 61 63 65 20 74 68 65 20 64 69 73 6b 2c 20 61 6e |ace the disk, an| 0x01c0: 64 20 74 68 65 6e 20 70 72 65 73 73 20 61 6e 79 |d then press any| 0x01d0: 20 6b 65 79 0d 0a 00 00 49 4f 20 20 20 20 20 20 | key....IO | 0x01e0: 53 59 53 4d 53 44 4f 53 20 20 20 53 59 53 7f 01 |SYSMSDOS SYS..| 0x01f0: 00 41 bb 00 07 60 66 6a 00 e9 3b ff 00 00 |.A...`fj..;.....|
Here's the code:
#include <stdio.h> #include <stdint.h> #include <ctype.h> #include <arpa/inet.h> typedef struct partition_record_s { uint8_t bootable; uint8_t start_head; uint8_t start_cs_1; uint8_t start_cs_2; uint8_t type; uint8_t end_head; uint8_t end_cs_1; uint8_t end_cs_2; uint32_t start_lba; uint32_t no_of_sectors; } partition_record_t; #pragma pack(1) typedef struct mbr_s { uint8_t code[440]; uint32_t disk_signature; uint16_t reserved; partition_record_t partition[4]; uint16_t boot_record_signature; } mbr_t; #pragma pack() #pragma pack(1) typedef struct vbr_s { uint8_t jump_code[3]; char oem_id[8]; uint16_t bytes_per_sector; uint8_t sectors_per_cluster; uint16_t reserved_sectors; uint8_t no_of_fats; uint16_t root_entries; uint16_t small_sectors; uint8_t media_descriptor; uint16_t sectors_per_fat; uint16_t sectors_per_track; uint16_t heads; uint32_t hidden_sectors; uint32_t large_sectors; uint8_t physical_drive_number; uint8_t current_head; uint8_t signature; uint32_t id; char volume_label[11]; char system_id[8]; uint8_t boot_code[448]; uint16_t boot_record_signature; } vbr_t; #pragma pack() static void print_string(char *s, int len) { int i; for (i = 0; i < len; i++) { if (isprint(s[i])) fputc(s[i], stdout); else fputc('.', stdout); } } static void print_hex(uint8_t *data, int len, int offset_start) { int i, col, row; char buffer[16]; row = offset_start / 16; col = offset_start % 16; printf("0x%04x: ", row * 0x10); i = 0; while (col-- > 0) { printf(" "); buffer[i++] = 0x0; } col = offset_start % 16; for (i = 0; i < len; i++) { printf("%02x ", data[i]); buffer[col] = data[i]; col++; if (col == 16) { row++; col = 0; printf(" |"); print_string(buffer, 16); printf("|\n"); printf("0x%04x: ", row * 0x10); } } for (i = col; i < 16; i++) { printf(" "); buffer[i] = 0x0; } printf(" |"); if (col > 0) { print_string(buffer, 16); printf("|\n"); } else { printf("\n"); } } static void dump_mbr(mbr_t *mbr) { int i; int start_cylinder, start_sector, end_cylinder, end_sector; printf("Serial: %08X\n", htonl(mbr->disk_signature)); printf("Partition Table:\n"); printf(" Boot Type First LBA First C:H:S Last C:H:S Size\n"); for (i = 0; i < 4; i++) { start_sector = mbr->partition[i].start_cs_1 & 0x3F; start_cylinder = mbr->partition[i].start_cs_2; start_cylinder += (mbr->partition[i].start_cs_1 & 0xC0) << 2; end_sector = mbr->partition[i].end_cs_1 & 0x3F; end_cylinder = mbr->partition[i].end_cs_2; end_cylinder += (mbr->partition[i].end_cs_1 & 0xC0) << 2; printf(" %c ", (mbr->partition[i].bootable == 0x80) ? '*' : ' '); printf("0x%02x ", mbr->partition[i].type); printf("0x%08x ", mbr->partition[i].start_lba); printf("%04d:%03d:%02d -> ", start_cylinder, mbr->partition[i].start_head, start_sector); printf("%04d:%03d:%02d ", end_cylinder, mbr->partition[i].end_head, end_sector); if (mbr->partition[i].no_of_sectors == 0) { printf("---"); } else { /* NOTE: Assumes standard sector size of 512 bytes. */ printf("(%d MB)", mbr->partition[i].no_of_sectors / 2048); } printf("\n"); } printf("Code:\n"); print_hex(mbr->code, 440, 0x0); } static void dump_vbr(vbr_t *vbr) { char *s; printf("Jump Code : 0x%02x 0x%02x 0x%02x ", vbr->jump_code[0], vbr->jump_code[1], vbr->jump_code[2]); if (vbr->jump_code[0] == 0xEB) { printf("(jmp short 0x%02X)\n", vbr->jump_code[1] + 2); } else { printf("(?)\n"); } printf("OEM ID : '"); print_string(vbr->oem_id, 8); printf("'\n"); printf("Volume Label : '"); print_string(vbr->volume_label, 11); printf("'\n"); printf("System ID : '"); print_string(vbr->system_id, 8); printf("'\n"); printf("Bytes per Sector : %d\n", vbr->bytes_per_sector); printf("Sectors per Cluster : %d\n", vbr->sectors_per_cluster); printf("Sectors per FAT : %d\n", vbr->sectors_per_fat); printf("Sectors per Track : %d\n", vbr->sectors_per_track); printf("No of FATs : %d\n", vbr->no_of_fats); printf("Reserved Sectors : %d\n", vbr->reserved_sectors); printf("Hidden Sectors : %d\n", vbr->hidden_sectors); printf("Small Sectors : %d\n", vbr->small_sectors); printf("Large Sectors : %d\n", vbr->large_sectors); printf("Root Entries : %d\n", vbr->root_entries); printf("Heads : %d\n", vbr->heads); printf("Current Head : %d\n", vbr->current_head); switch (vbr->media_descriptor) { case 0xF0: case 0xF9: case 0xFC: case 0xFD: case 0xFE: case 0xFF: s = "Floppy Disk"; break; case 0xF8: s = "Fixed Disk"; break; default: s = "Unknown"; break; } printf("Media Descriptor : 0x%02X (%s)\n", vbr->media_descriptor, s); printf("Physical Drive Number: 0x%02X\n", vbr->physical_drive_number); printf("Signature : 0x%02X\n", vbr->signature); printf("ID : %08X\n", htonl(vbr->id)); printf("Boot Code:\n"); print_hex(vbr->boot_code, 448, 0x3E); } static int is_printable(char *s, int len) { int i; for (i = 0; i < len; i++) { if (! isprint(s[i])) return 0; } return 1; } int main(int argc, char *argv[]) { FILE *fh; int bytes; uint8_t sector[512]; if (argc != 2) { fprintf(stderr, "Usage: %s <boot record file>\n", argv[0]); return 1; } fh = fopen(argv[1], "rb"); if (fh == NULL) { fprintf(stderr, "Error: Unable to open file for reading.\n"); return 1; } bytes = fread(§or, sizeof(uint8_t), 512, fh); fclose(fh); if (bytes < 512) { fprintf(stderr, "Error: File is less than 512 bytes.\n"); return 1; } if (sector[510] != 0x55 || sector[511] != 0xAA) { fprintf(stderr, "Error: File is not a valid boot record.\n"); return 1; } if (is_printable(((vbr_t *)§or)->oem_id, 8)) { printf("Volume Boot Record (VBR)\n"); printf("------------------------\n"); dump_vbr((vbr_t *)§or); } else { printf("Master Boot Record (MBR)\n"); printf("------------------------\n"); dump_mbr((mbr_t *)§or); } return 0; }