构造一个简单的MBR分区表

上篇文章讲述了MBR分区表的分析过程,这篇我们开始讲一下如何构造一个MBR分区表。


首先从最简单的没有扩展分区的分区表开始构建:



typedef struct tagMBR_PTITEM
{
/*00*/	UCHAR	byState;				//分区状态, 0 = 未激活, 0x80 = 激活 
/*01*/	UCHAR	byBeginHead;			//分区起始磁头号
/*02*/	USHORT	wBeginSC;				//分区起始扇区和柱面号, 底字节的低6位为扇区号, 高2位为柱面号的第 9,10 位, 高字节为柱面号的低 8 位
/*04*/	UCHAR	byFSID;					//分区类型, 如 0x0B = FAT32, 0x83 = Linux 等, 00 表示此项未用
/*05*/	UCHAR	byEndHead;				//分区结束磁头号
/*06*/	USHORT	wEndSC;					//分区结束扇区和柱面号
/*08*/	ULONG	dwBeginSector;			//在线性寻址方式下的分区相对扇区地址
/*012*/	ULONG	dwSectors;				//分区大小 (总扇区数)
/*16*/
} MBR_PTITEM,FAR * LPMBR_PTITEM;		//磁盘的分区信息


#define GETSC_C(SC) ((((SC) & 0xc0) << 2) + ((SC) & 0xff)

#define GETSC_S(SC) (SC & 0x3f)
#define MAKE_SC(s, c) ((WORD)((s & 0x3F) | ((WORD)(LOBYTE(c) << 8)) | ((HIBYTE(c) & 3) << 6)))


我们通过上篇文章知道没有扩展分区表的MBR分区表最多只有4个分区,在硬盘的第0扇区,字节偏移是446,从446往后64个字节每16个是一个分区信息,总共4个分区,然后是0x55,0xAA,我们现在要分区,所要做的就是讲这4个分区信息填上,重点就是这些信息怎么填写。

假设我们的硬盘大小是100GB,如果厂商比较实诚的话扇区数应该是100*1024*1024*1024/512=209715200(不过没有这么实诚的,商家做硬盘为了节省成本,一般都不是1024进制,都是1000,就这样还要在少一些),假设我们要分两个分区,第一个40G,第二个60G,那么我们需要将0-83886079扇区分为第一个分区,83886080-209715200分为第二个分区,如果我们直接将这个偏移写进去是不行的,比如0扇区保存的是分区表信息,因此它不属于任何一个分区,一般情况下前面需要预留出一些扇区,最极端的情况下是从第1扇区开始,但是这样的话有些Linux系统可能无法安装,因为有些系统需要分区是4K对齐的,什么叫做4K对齐呢?就是分区的起始扇区是8的倍数,因为每8个扇区是4K,所以叫4K对齐,NTFS文件系统默认每簇大小是4K,因此为了提高扇区使用率,分区大小最好也是8的倍数, 绝大多数分区软件预留的是64扇区,新的分区软件也许会预留2048扇区,分区与分区之间也不是全部连续的,每两个分区之间也会预留一些扇区,叫分区间隙,分区间隙的大小也最好是8的倍数,一般跟前面保留的一样就好了,磁盘最后也要预留一部分扇区,但是这些其实不是必须的。

假设我们每处预留扇区都是64,因此第一个分区的区间就是64-83886079,第二个分区的区间是83886144-209715135,我们将该区间信息写入分区表,此时我们可以确定分区的信息为:在线性寻址方式下的分区相对扇区地址和分区大小。说到这里说一下分区的另一种表示方法,之前我们所说的扇区偏移都是线性地址(逻辑地址,Ligical Block Address,LBA),而很早之前使用的是C/H/S地址,所谓硬盘的CHS,即Cylinder(柱面)、Head(磁头)、Sector(扇区)。知道了一个扇区的LBA地址就可以计算出CHS地址:

//S = LBA % 每个磁头的扇区数
//H = LBA / 每个磁头的扇区数 % 每个柱面的磁头数
//C = LBA / 每个磁头的扇区数 / 每个柱面的磁头数
//每个磁头的扇区数、每个柱面的磁头数是磁盘的基本信息,可以通过IOCTL获取
void CalcChs(IN LPDISK_BASEINFO lpDiskInfo,
				 IN DWORD		dwSectOffset,
				 OUT LPWORD		lpwSector,
				 OUT LPWORD		lpwHead,
				 OUT LPDWORD	lpdwCylinder)
{
	*lpwSector =  (WORD)((dwSectOffset % lpDiskInfo->dwSectorsPerTrack) + 1);
	*lpwHead   = (WORD)((dwSectOffset / lpDiskInfo->dwSectorsPerTrack) % lpDiskInfo->dwTracksPerCylinder);
	*lpdwCylinder   = (DWORD)((dwSectOffset / lpDiskInfo->dwSectorsPerTrack) / lpDiskInfo->dwTracksPerCylinder);
}

到此为止我们还有两个成员没有确定:是否是活动分区和分区类型。接下来我们来了解一下这两项的作用,活动分区,也可以叫启动分区,就是说这个分区是否是启动分区,这个标志主要是可以让BIOS知道这个硬盘是否可以作为引导盘(我猜的,不过是在想不出它还有什么用),每个MBR分区的磁盘仅可以设置一个活动分区,而且这个分区只能是主分区,不能是扩展分区。一般这个分区就是操作系统的引导文件所在的分区,但是操作系统现在都有自己的MBR代码,然后加载运行他们自己的PBR,并不一定要依赖这个;分区类型,就是文件系统类型,这个值只要不是0其他都随便,没什么卵用,因为在操作系统中还是可以修改文件系统类型的,他也就是可以作为操作系统格式化分区的时候的一个默认值,比如你设置该值为0x0B,在格式化这个分区的时候,选择文件系统那个下拉默认选中FAT。

我们所有的数据都已经确定完后,因为个MBR分区表有4项,我们只有两个分区,剩下的两项就全部清为0,然后将最后两个字节设置为0x55,0xAA,一定要设置,不然BIOS不认,最后将我们构造的分区表写入硬盘的第0扇区,分区就结束了。


你可能感兴趣的:(构造一个简单的MBR分区表)