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;
}