主引导记录(Master Boot Record,缩写:MBR),又叫做主引导扇区,是计算机开机后访问硬盘时所必须要读取的首个扇区,它在硬盘上的三维地址为(柱面,磁头,扇区)=(0,0,1)。在深入讨论主引导扇区内部结构的时候,有时也将其开头的446字节内容特指为“主引导记录”(MBR),其后是4个16字节的“磁盘分区表”(DPT),以及2字节的结束标志(55AA)。因此,在使用“主引导记录”(MBR)这个术语的时候,需要根据具体情况判断其到底是指整个主引导扇区,还是主引导扇区的前446字节。
主引导扇区记录着硬盘本身的相关信息以及硬盘各个分区的大小及位置信息,是数据信息的重要入口。如果它受到破坏,硬盘上的基本数据结构信息将会丢失,需要用繁琐的方式试探性的重建数据结构信息后才可能重新访问原先的数据。主引导扇区内的信息可以通过任何一种基于某种操作系统的分区工具软件写入,但和某种操作系统没有特定的关系,即只要创建了有效的主引导记录就可以引导任意一种操作系统(操作系统是创建在高级格式化的硬盘分区之上,是和一定的文件系统相联系的)。
主引导记录的组成
|=======================|
|地址 描述 长度 |
|-----------------------------------------|
|0x00 代码区 440 |
|-----------------------------------------|
|0x01B8 选用磁盘标志 4 |
|---------------------------------------- |
|0x01BC 一般为空值 2 |
|---------------------------------------- |
|0x01BE 标准MBR分区表 64 |
| 4个16B的主分区表 |
|----------------------------------------- |
|0xFE MBR Magic 0x55AA |
| Number |
|========================|
硬盘分区结构表:
上图中的0x01BE开始的64个字节是4个主分区表,一个分区表的结构为:
|=============================|
|offset len info |
|---------------------------------------------------|
|0x00 1 此分区状态 |
|---------------------------------------------------|
|0x1 1 此分区起始磁头号 |
|---------------------------------------------------|
|0x2 1 此分区起始扇区号 |
|---------------------------------------------------|
|0x3 1 此分区起始磁柱号 |
|---------------------------------------------------|
|0x4 1 文件系统标志位 |
|---------------------------------------------------|
|0x5 1 此分区结束磁头号 |
|---------------------------------------------------|
|0x6 1 此分区结束扇区号 |
|---------------------------------------------------|
|0x7 1 此分区结束磁柱号 |
|---------------------------------------------------|
|0x8 4 分区起始相对扇区号 |
|---------------------------------------------------|
|0xC 4 分区总的扇区数 |
|=============================|
如何读取MBR分区的内容:
首先,需要打开硬盘设备,然后再从设备中读取第1个扇区的内容,即是MBR的内容,
HANDLE handle;
DISK_GEOMETRY dsk;
BOOL bResult;
DWORD junk;
//如果只是进行读的操作,在打开设备的时候,使用GENERIC_READ权限进行读的操作权限的设置;
/*
handle = CreateFileA(path, GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0, 0 );
*/
//若需要进行读写、执行的操作,在打开设备的时候,使用GENERIC_ALL权限字进行打开
handle = CreateFileA(path, GENERIC_ALL,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0, 0 );
if(handle == INVALID_HANDLE_VALUE)
{
return handle;
}
//获取设备的一个扇区的字节数,一般均为512Byte
bResult = DeviceIoControl(handle, // device we are querying
IOCTL_DISK_GET_DRIVE_GEOMETRY, // operation to perform
NULL, 0, // no input buffer, so pass zero
&dsk, sizeof(dsk), // output buffer
&junk, // discard count of bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O
if((!bResult) || (dsk.BytesPerSector < SECTOR_SIZE))
*sect_size = SECTOR_SIZE;
else
//dsk.BytesPerSector是当前硬盘设备的扇区大小
*sect_size = dsk.BytesPerSector;
再使用read_disk读取一个扇区的数据。
//hnd为设备的句柄,ptr为存储第一个扇区数据的存储空间指针,sector是从第几个扇区开始,nsects表示取几个扇区,
sectorsize为扇区的大小
int read_disk(FileHandle hnd, void *ptr, lloff_t sector, int nsects, int sectorsize)
{
lloff_t offset;
DWORD rd, len;
DWORD low;
LONG high;
BOOL ret;
//得到读取的数据在设备中的偏移字节数;
offset = sector * sectorsize;
low = (DWORD)(offset & 0xFFFFFFFF);
high = (DWORD)((offset >> 32)& 0xFFFFFFFF);
//设置当前设备句柄的读取位置
low = SetFilePointer(hnd, low, &high, FILE_BEGIN);
//要读取的扇区的总长度
len = nsects * sectorsize;
//从设备句柄hnd中读取长度为len的数据到ptr指向的存储空间中;其中rd为读取到的数据的长度
ret = ReadFile(hnd, ptr, len, &rd, NULL);
if(!ret)
return -1;
return rd;
}