1. 程式人生 > >NTFS檔案系統資料恢復----解析MFT表

NTFS檔案系統資料恢復----解析MFT表

http://blog.csdn.net/jha334201553/article/details/9089119

開始先說下DBR, DBR是繼MBR 之後最先訪問的地方,MBR利用int 13h 讀取MBR並將之載入到實體地址0x7c00的地方. 然後將段地址:程式碼地址入棧後retf跳過去執行.
        MBR利用BIOS中斷int 13h讀取資料載入到記憶體指定位置..傳統的int 13h呼叫最多隻能識別1024個磁頭:
前面MBR講解MBR的時候,有結構如下
/*+0x01*/   uchar    StartHead;         // 分割槽起始磁頭號  (1磁頭 = 63 扇區,取值 0~255 之間)  


/*+0x02*/   uint16   StartSector:10;    // 啟始柱面號 10位 (1柱面 = 255 磁頭,取值 0~1023 之間)  
/*+0x02*/   uint16   StartCylinder:6;   // 啟始扇區號 6位 (取值 1 到 63 之間) 
        此結構可容納最大值為FF FF FF (現在這個值基本都寫成FE FF FF, 而廢棄不用), 即最大能定址的就是255柱面, 1023磁頭, 63扇區,計算扇區個數為:
1023*255*63+255*63+63 = 16450623
        再按每扇區 512 位元組算, 那麼它容量為  8 GB  ≈  512*16450623 B = 7.84 GB 

        傳統的int 13h中斷就受限於8G的限制, Microsoft等多家公司制定了int 13h擴充套件標準,讓int 13h讀寫磁碟中斷可以突破8G限制. 現在的計算機BIOS都是按擴充套件int 13h標準編寫的程式碼.(具體詳細內容可參考"擴充套件 int 13h規範").
        按MBR分割槽表裡面的 SectionPrecedingPartition 邏輯扇區偏移(注意,這個邏輯扇區偏移是從0開始算的,讀取出來值為63,而物理扇區是從1開始計算的,邏輯扇區轉換物理扇區的時候必須+1才是正確的) 可以找到DBR的位置.可以看看winhex的顯示


        以下就偷懶不從MBR定址分割槽的DBR了,而是直接開啟碟符讀取 (這樣開啟的第一個扇區就是DBR),這樣做有個缺點,就是你用這個handle值將不能進行記憶體對映,只能一次多讀取幾個扇區來加快分析磁碟的速度(當前用的是一次讀取20M資料然後分析)。

  1. HANDLE  handle = CreateFile ( TEXT("\\\\.\\C:") ,  
  2.                           GENERIC_READ,  
  3.                           FILE_SHARE_READ|FILE_SHARE_WRITE,  
  4.                           NULL,  
  5.                           OPEN_EXISTING,  
  6.                           FILE_ATTRIBUTE_NORMAL,  
  7.                           NULL);  

        DBR結構定義為(對照winhex模板資訊檢視):


  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  NTFS 的DBR 資料結構
  4. //
  5. ////////////////////////////////////////////////////////////////////////////
  6. typedefstruct _BIOS_PARAMETER_BLOCK {  
  7.  /*+0x0B*/    uint16  BytesPerSector;    // 位元組/扇區一般為0x0200 即512
  8.  /*+0x0D*/    uchar   SectorsPerCluster; // 扇區/簇 
  9.  /*+0x0E*/    uint16  ReservedSectors;   // 保留扇區
  10.  /*+0x0F*/    uchar   Fats;              // 
  11.  /*+0x11*/    uint16  RootEntries;       // 
  12.  /*+0x13*/    uint16  Sectors;           // 
  13.  /*+0x15*/    uchar   Media;             // 媒介描述
  14.  /*+0x16*/    uint16  SectorsPerFat;     // 
  15.  /*+0x18*/    uint16  SectorsPerTrack;   // 扇區/磁軌
  16.  /*+0x1A*/    uint16  Heads;             // 頭
  17.  /*+0x1C*/    uint32  HiddenSectors;     // 隱藏扇區
  18.  /*+0x20*/    uint32  LargeSectors;      // checked when volume is mounted
  19. }BIOS_PARAMETER_BLOCK, *pBIOS_PARAMETER_BLOCK;  
  20. typedefstruct _NTFS_Boot_Sector{  
  21.  /*+0x00*/  uchar    JmpCode[3];        // 跳轉指令
  22.  /*+0x03*/char     OemID[8];          // 檔案系統ID
  23.  /*+0x0B*/  BIOS_PARAMETER_BLOCK PackedBpb;   // BPB
  24.  /*+0x24*/  uchar    Unused[4];           // 未使用,總是為
  25.  /*+0x28*/  uint64   NumberSectors;       // 扇區總數
  26.  /*+0x30*/  lcn      MftStartLcn;        // 開始C# $MFT  (簇) 乘以 BIOS_PARAMETER_BLOCK.SectorsPerCluster 值得到扇區號
  27.  /*+0x38*/  lcn      Mft2StartLcn;       // 開始C# $MFTMirr (簇)
  28.  /*+0x40*/  uchar    ClustersPerFileRecordSegment;  // 檔案記錄大小指示器
  29.  /*+0x41*/  uchar   Reserved0[3];       // 未使用
  30.  /*+0x44*/  uchar DefaultClustersPerIndexAllocationBuffer;     // 簇/索引塊
  31.  /*+0x45*/  uchar   Reserved1[3];       // 未使用
  32.  /*+0x48*/  uint64  SerialNumber;       // 64位序列號
  33.  /*+0x50*/  uint32  Checksum;           // 校驗和
  34.  /*+0x54*/  uchar   BootStrap[426];     // 啟動程式碼
  35.  /*+0x1FE*/ uint16  RecordEndSign;      // 0xAA55 結束標記
  36. }NTFS_Boot_Sector, *pNTFS_Boot_Sector;  
        在讀取DBR的時候,一些資料以後經常會用到,那麼需要根據DBR裡面的資訊儲存以後會用到的資訊,下面定義一個常用的儲存資訊結構:
  1. // 儲存 NTFS 的基本資訊
  2. typedefstruct _NTFS_INFO  
  3. {  
  4.     uint32 BytesPerSector;              // 每扇區的位元組數
  5.     uint32 SectorsPerCluster;           // 每簇的扇區數
  6.     uint32 BytesPerCluster;             // 每簇的位元組數
  7.     uint64 SectorCount;                 // 扇區總數
  8.     uint64 MftStart;                    // MFT表開始簇
  9.     uint64 MftMirrStart;                // MFT備份表開始簇
  10.     uint32 BytesPerFileRecord;          // 每個檔案記錄的位元組數一般為512*2
  11.     uint16 VolumeLabelLength;           //  卷名長度,卷名從MFT第4個項0x60屬性得到(與0x30屬性相似)
  12.     wchar VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH];  // 卷名
  13.     uint16 vcnlen;  
  14.     uchar vcn[VCN_LENTH];  
  15. } NTFS_INFO, *PNTFS_INFO;  
其中 MAXIMUM_VOLUE_LABEL_LENGTH定義為
  1. #define MAXIMUM_VOLUME_LABEL_LENGTH (32*sizeof(wchar))
        NTFS_Boot_Sector .MftStartLcn*NTFS_Boot_Sector. PackedBpb .SectorsPerCluster得到MFT所在扇區號,這裡為 786432*8 = 6291456扇區(位元組偏移為 6291456*512= 3221225472 ( 十六進位制0xC0000000))。然後MFT表裡面的內容是根據簇號來讀取資料的,那麼可以定義一個根據簇號,讀取資料的函式,如下形式:
  1. typedefstruct _Partition_Stand_Post  
  2. {  
  3.     HANDLE handle;  // 分割槽控制代碼
  4.     uint64 CluNnum; // 簇號
  5.     uint32 BytesPerCluster; // 每簇位元組
  6.     uint64 CluCount;  // 簇數量
  7.     PNTFS_INFO NtfsInfo; // 指向NTFS_INFO 結構
  8. }Partition_Stand_Post, *pPartition_Stand_Post;  
  9. // 按簇讀取資料,
  10. // 傳入 一個Partition_Stand_Post結構體指標,並指定buf,讀取大小
  11. // 結果返回讀取的資料指標
  12. PBYTE ReadClues(pPartition_Stand_Post post, PBYTE buf, DWORD lenth)  
  13. {  
  14.     DWORD dwbytes = 0;  
  15.     LARGE_INTEGER li = {0};  
  16.     li.QuadPart = post->CluNnum*post->BytesPerCluster;  
  17.     SetFilePointer(post->handle, li.LowPart, &li.HighPart, FILE_BEGIN);  
  18.     ReadFile(post->handle, buf, lenth, &dwbytes, NULL);  
  19.     if (lenth == dwbytes)  
  20.     {  
  21.         return buf;  
  22.     }  
  23.     return NULL;  
  24. }  
下面先說MFT表的結構:

首先,看到的是頭部,標記為"FILE", 結構體如下定義:

  1. // 檔案記錄頭
  2. typedefstruct _FILE_RECORD_HEADER  
  3. {  
  4.  /*+0x00*/  uint32 Type;            // 固定值'FILE'
  5.  /*+0x04*/  uint16 UsaOffset;       // 更新序列號偏移, 與作業系統有關
  6.  /*+0x06*/  uint16 UsaCount;        // 固定列表大小Size in words of Update Sequence Number & Array (S)