demo:https://github.com/Hilaver/NtfsResolution/
先看一張硬盤圖片(一個盤面):
MBR
主引導記錄(MBR,Main Boot Record)是位於磁盤最前邊的一段引導(Loader)代碼。它負責磁盤操作系統(DOS)對磁盤進行讀寫時分區合法性的判別、分區引導信息的定位,它由磁盤操作系統(DOS)在對硬盤進行初始化時產生的。 --摘自百度百科
MBR扇區位於物理硬盤的0柱面,0磁頭,1扇區,也就是整個硬盤的第一個扇區(偏移量爲0),共佔512個字節(即一個扇區),每個物理硬盤只有一個MBR扇區。
MBR扇區由三部分構成:第一部分是446字節的引導代碼,也就是上面提到的MBR;第二部分是DPT(Disk Partition Table,硬盤分區表),包含4個表項,每個表項16字節,共佔用64字節;第三部分是2個字節的結束標誌,0x55AA。其結構如下圖:
DBR
分區引導扇區也稱DBR(DOS BOOT RECORD),是由FORMAT高級格式化命令寫到該扇區的內容,DBR是由硬盤的MBR裝載的程序段。DBR裝入內存後,即開始執行該引導程序段,其主要功能是完成操作系統的自舉並將控制權交給操作系統。每個分區都有引導扇區,但只有被設爲活動分區纔會被MBR裝的DBR入內存運行。 --摘自百度百科
在對硬盤分區之後,每一個分區均有一個DBR與之對應。DBR位於每個分區的第一個扇區,大小爲512字節。
DBR的結構與分區格式有關,NTFS與FAT32的DBR格式是不同的。
EBR
EBR(Extended Boot Record)是與MBR相對應的一個概念。前邊已經講過,MBR裏有一個DPT(Disk Partition Table,磁盤分區表)的區域,它一共是64字節,按每16個字節作爲一個分區表項,它最多隻能容納4個分區。能夠在MBR的DPT裏進行說明的分區稱爲主分區。如果我們想分區多於4個的時候,MBR的DPT裏就會容納不下來,於是微軟就想出了另一個解決方案,在MBR裏,只放不多於三個主分區,剩下的分區,則由與MBR結構很相像的另一種分區結構(EBR,也就是擴展分區引導記錄)進行說明。一個EBR不夠用時,可以增加另一個EBR,如此像一根鏈條一樣地接下去,直到夠用爲止。 --又摘自百度百科
實際上,EBR中有用的部分僅爲其DPT的前兩個表項,第一個表項記錄了擴展分區中該EBR對應的邏輯分區(邏輯驅動器)的偏移地址和扇區個數,第二個表項記錄了下一個邏輯分區的必要信息,本質上是一個鏈表的結點。
實例分析
下面給出我的一個Windows7虛擬機的分區結構圖(所有的分區文件系統格式均爲NTFS):
在Winhex下讀取到的硬盤信息如下:
其中MBR、DBR和EBR的位置如下圖:
從上圖可以看到,整個物理硬盤被分成了6個分區,其中C、E和F是主分區,G、H和I是邏輯分區。寫代碼獲得各個分區的信息如下:
MBR扇區數據分析
讀取MBR如下(在硬盤偏移量爲0處讀取512個字節),找到其中64個字節的DPT數據:
提取出來如下:
80 20 21 00 07 FE FF FF 00 08 00 00 00 F0 3F 06
00 FE FF FF 07 FE FF FF 00 F8 3F 06 00 F8 7F 02
00 FE FF FF 07 FE FF FF 00 F0 BF 08 00 00 40 02
00 FE FF FF 0F FE FF FF 00 F0 FF 0A 00 08 40 00
上面四個表項分別指向分區C、E、F和G。
剛剛已經提到,DPT中最多包含4個表項,每個表項16字節,每個表項的結構如下:
//DPT表項
typedefstruct_PartTableEntry {
BYTE bootSignature;//引導標誌
BYTE startHead;//CHS尋址方式,起始磁頭
BYTE startSector;//起始扇區,本字節低六位
BYTE startCylinder;//起始磁道(柱面),startSector高二位和本字節
BYTE systemSignature;//文件系統類型標誌
BYTE endHead;//終止磁頭
BYTE endSector;//終止扇區
BYTE endCylinder;//終止磁道
unsignedint startSectorNo;//LBA尋址,起始扇區號
unsignedint totalSectorsNum;//該分區扇區總數
}PartTableEntry,*pPartTableEntry;
先看第一個表項:
80 20 21 00 07 FE FF FF 00 08 00 00 00 F0 3F 06
第一個字節爲引導標誌,0x80表示活動分區,0x00表示非活動分區。接下來三個字節用來表示CHS尋址方式的起始地址,具體含義已經在上面結構體中給出。接下來一個字節表示分區文件系統的類型,0x07表示NTFS(參考最後的附表)。接下來的三個字節表示CHS尋址方式的終止地址(0xFEFFFF表示該字段無效,因爲3個字節最大的尋址能力爲2^(3*8)個扇區,即8GB。當分區大小超過8GB時該字段無效)。再後面的四個字節表示LBA(Logical Block Address)尋址方式的起始扇區(可以計算出最大支持2TB的硬盤),要注意小端字節序(數據存儲時低字節在前),也就是說C盤的起始扇區爲00 00 08 00。最後四個字節表示該分區的扇區數量,同樣是小端模式,即C盤共0x063FF000個扇區。
接下來讓我們跳轉到C盤的起始扇區(00 00 08 00),讀取該處512字節的數據如下:
你會看到熟悉的結束標誌0x55AA,實際上這是C盤的DBR扇區。DBR扇區各個字段的含義在後面展開。
EBR扇區分析
MBR扇區的硬盤分區表的第二和第三個表項與第一個類似,這裏不再展開,我們主要來看一下第四個表項:
00 FE FF FF 0F FE FF FF 00 F0 FF 0A 00 08 40 00
第一個字節表示非活動分區,CHS尋址無效,第五個字節分區類型爲0x0F,表示擴展分區。LBA尋址的起始扇區爲0x0AFFF000,包含扇區個數爲0x00400800。跳轉到該擴展分區的起始扇區0x0AFFF000處讀取512字節數據:
最後兩個字節是結束標誌0x55AA,這512字節實際上是一個EBR扇區,其結構與MBR扇區相同,但有用的部分僅爲DPT的前兩個表項,數據如下:
00 FE FF FF 07 FE FF FF 00 08 00 00 00 90 21 00
00 FE FF FF 05 FE FF FF 00 98 21 00 00 70 1E 00
第一個表項表示本該EBR對應的邏輯分區G的起始地址和扇區數量,其中LBA尋址的起始扇區爲00 00 08 00,但是該地址爲相對偏移,實際的起始扇區爲本扇區的實際地址加上相對偏移量,即0x0AFFF000 + 0x00000800 = 0x0AFFF800。讀取0x0AFFF800扇區的數據如下:
這個扇區實際上是邏輯分區G的DBR扇區,記錄了G盤的基本信息。
第二個表項記錄了下一個邏輯分區 H 的EBR扇區的起始地址和扇區總數量。其中,EBR扇區的起始地址爲00 21 98 00,同樣是一個相對地址,實際扇區爲0x0AFFF000 + 0x00219800 = 0x0B218800,讀取0x0B218800扇區的數據如下:
這512字節是邏輯分區H的EBR扇區,同樣提取DPT的前兩個表項:
00 FE FF FF 07 FE FF FF 00 08 00 00 00 B8 0B 00
00 FE FF FF 05 FE FF FF 00 58 2D 00 00 B0 12 00
與上一個EBR扇區類似,第一個表項的LBA尋址的起始扇區(00 00 08 00)仍是一個相對偏移,指向該EBR所對應的邏輯分區的起始地址,其實際扇區爲:0x0B218800 + 0x00000800 = 0x0B219000,實際字節偏移爲0x0B219000 *512字節每扇區 = 0x1643200000,從該字節處讀取512字節數據可以得到分區H的DBR扇區,這裏就不再截圖。第二個表項的LBA尋址起始扇區(00 2D 58 00)同樣是一個相對偏移,指向下一個邏輯分區(I:)的EBR扇區,其實際扇區爲MBR扇區DPT第四個表項的起始扇區加上該相對偏移,即0x0AFFF000 + 0x002D5800 = 0x0B2D4800。該扇區的數據爲:
在該EBR扇區中,DPT的第一個表項仍使用相對偏移指出本邏輯分區(I:)的起始扇區,這個扇區就是分區I:的DBR扇區。第二個表項全0,表示該邏輯分區即是最後一個邏輯分區。
總結一下,在Windows系統下如果採用MBR的引導方式,當分區個數大於等於4的時候,一般情況下系統會將前三個分區設爲主分區,第四個作爲擴展分區(擴展分區中包含若干個邏輯分區)。MBR扇區的DPT中前三個表項可以直接定位前三個主分區的DBR扇區,第四個表項指向第一個邏輯分區的EBR扇區,根據EBR中的DPT前兩個表項分別可以定位本邏輯分區的DBR扇區和下一個邏輯分區的EBR扇區,由此邏輯分區鏈接成一條鏈進行管理。
DBR扇區分析
下面給出NTFS和FAT32的DBR扇區格式,注意一點:NTFS下的備份DBR在分區的最後一個扇區,FAT32下的備份DBR一般在第六個扇區。
//NTFS DBR扇區
typedefstruct_NTFSDBR {
BYTE JMP[3]; //跳轉指令
BYTE FsID[8]; //文件系統ID
unsignedshortint bytePerSector; //每扇區字節數
BYTE secPerCluster; //每簇扇區數
BYTE reservedBytes[2]; //2個保留字節
BYTE zeroBytes[3]; //三個0字節
BYTE unusedBytes1[2]; //2個未用字節
BYTE mediaType;//媒體類型
BYTE unusedBytes2[2]; //2個未用字節
unsignedshortint secPerTrack; //每磁道扇區數
unsignedshortint Heads; //磁頭數
unsignedint hideSectors; //隱藏扇區數
BYTE unusedBytes3[4]; //4個未用字節
BYTE usedBytes[4]; //4個固定字節
unsigned__int64 totalSectors; //總扇區數
unsigned__int64 MFT; //MFT文件起始簇號
unsigned__int64 MFTMirror; //MFTMirror文件起始簇號
char fileRecord; //文件記錄
BYTE unusedBytes4[3]; //3個未用字節
char indexSize; //索引緩衝區大小
BYTE unusedBytes5[3]; //未用字節
BYTEvolumeSerialID64[8]; //卷序列號
unsignedint checkSum; //校驗和
BYTE bootCode[426]; //引導代碼
BYTE endSignature[2]; //結束標誌
}NTFSDBR,*pNTFSDBR;
typedefstruct_FAT32_Sector{
unsignedint Sectors_per_FAT_FAT32; //FAT32每個FAT表佔用扇區數
unsignedshortint Extend_Flag; //0-3位表示活動FAT數,7位:0表示在運行時FAT映射到所有FAT 1表示只有一個FAT是活動的,其他位保留
unsignedshortint FS_Version; //文件系統版本,高字節表示主要修訂號,低直接表示次要修訂號
unsignedint Root_Cluster_Number; //根目錄簇號,一般取值爲2
unsignedshortint FS_Info_Sector; //文件系統扇區號,一般取1
unsignedshortint Backup_Sector; //備份引導扇區,一般取值爲6
BYTE Reserved_Sector[12]; //保留扇區
}FAT32_Sector, *pFAT32_Sector;
typedefstruct_Basic_BPB{
unsignedshortint Bytes_per_Sector; //每個扇區字節數,可取512,1024,2048,4096,通常取512
BYTE Sectors_per_Cluster; //每簇扇區數,可取1,2,4,8,16,32,64,128,FAT32最多跟蹤268,435,445個簇
unsignedshortint Reserved_Sector; //保留扇區,表示第一個FAT前的扇區數,通常取32
BYTE FATs; //FAT表個數,通常取2
unsignedshortint RootEntry; //根目錄項數,對FAT32,取值必爲0
unsignedshortint SmallSector; //小扇區數,對FAT32,取值必爲0
BYTE Media; //存儲介質描述,F8表示硬盤,F0表示3.5軟盤
unsignedshortint Sector_per_FAT_FAT16; //針對FAT12/16的每個FAT扇區數,對FAT32,取值爲0
unsignedshortint Sector_per_Track; //每道扇區數,描述磁盤物理結構
unsignedshortint Heads; //磁頭數
unsignedint Hidden_Sector; //該塊硬盤前用於存放引導代碼及分區表的扇區數
unsignedint Large_Sector; //總扇區數,若SmallSector爲0,此處表示分區上扇區總數
//可用扇區數 = 總扇區數-保留扇區-FAT表佔用扇區
_FAT32_Sector Fat32_Sector; //FAT32文件系統扇區信息
}Basic_BPB, *pBasic_BPB;
typedef struct_FAT32_Extend_BPB{
BYTE Physical_Drive; //物理驅動器號,0x80表示物理硬盤,0x00表示軟盤驅動器
BYTE Reserved; //保留
BYTE Extend_Singure; //0x28或0x29以供Windows NT識別
unsignedint Vol_Serial; //卷序列號,由格式化時隨機獲得
BYTE Vol_Label[11]; //卷標示
BYTE System_ID[8]; //系統ID,根據格式化的格式爲FAT32,FAT16等
}FAT32_Extend_BPB, *pFAT32_Extend_BPB;
//FAT32 DBR扇區
typedefstruct_FAT32_DBR{
BYTE JumpInstrction[3]; //0x00,跳轉指令,通常爲EB5890,其中58指示了,跳轉位置,在X86中,58+2就代表跳轉到5A處
BYTE OEMID[8]; //0x03,廠商標示和OS版本信息
_Basic_BPB BPB; //0x0B
_FAT32_Extend_BPB Extend_BPB; //0x40
BYTE Boot_Strap[420]; //文件系統引導代碼 //0x5A,引導區代碼
BYTE endSignature[2]; //0x01FE,結束標示
}FAT32_DBR, *pFAT32_DBR;
下面是一個FAT32分區的DBR扇區數據,具體含義在上述結構體中已做聲明,這裏就不再展開:
下面是一張以前的FAT32分區DBR扇區的數據,部分字段含義做了解釋:
附-磁盤分區類型標誌表: