/ 中存储网

NTFS文件系统数据恢复----解析MFT表

2017-09-13 14:46:12 来源:中存储网

开始先说下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. typedef struct _BIOS_PARAMETER_BLOCK {  
  7.   
  8.  /*+0x0B*/    uint16  BytesPerSector;    // 字节/扇区一般为0x0200 即512  
  9.  /*+0x0D*/    uchar   SectorsPerCluster; // 扇区/簇   
  10.  /*+0x0E*/    uint16  ReservedSectors;   // 保留扇区  
  11.  /*+0x0F*/    uchar   Fats;              //   
  12.  /*+0x11*/    uint16  RootEntries;       //   
  13.  /*+0x13*/    uint16  Sectors;           //   
  14.  /*+0x15*/    uchar   Media;             // 媒介描述  
  15.  /*+0x16*/    uint16  SectorsPerFat;     //   
  16.  /*+0x18*/    uint16  SectorsPerTrack;   // 扇区/磁轨  
  17.  /*+0x1A*/    uint16  Heads;             // 头  
  18.  /*+0x1C*/    uint32  HiddenSectors;     // 隐藏扇区  
  19.  /*+0x20*/    uint32  LargeSectors;      // checked when volume is mounted  
  20.   
  21. }BIOS_PARAMETER_BLOCK, *pBIOS_PARAMETER_BLOCK;  
  22.   
  23. typedef struct _NTFS_Boot_Sector{  
  24.  /*+0x00*/  uchar    JmpCode[3];        // 跳转指令  
  25.  /*+0x03*/  char     OemID[8];          // 文件系统ID  
  26.  /*+0x0B*/  BIOS_PARAMETER_BLOCK PackedBpb;   // BPB  
  27.  /*+0x24*/  uchar    Unused[4];           // 未使用,总是为  
  28.  /*+0x28*/  uint64   NumberSectors;       // 扇区总数  
  29.  /*+0x30*/  lcn      MftStartLcn;        // 开始C# $MFT  (簇) 乘以 BIOS_PARAMETER_BLOCK.SectorsPerCluster 值得到扇区号  
  30.  /*+0x38*/  lcn      Mft2StartLcn;       // 开始C# $MFTMirr (簇)  
  31.  /*+0x40*/  uchar    ClustersPerFileRecordSegment;  // 文件记录大小指示器  
  32.  /*+0x41*/  uchar   Reserved0[3];       // 未使用  
  33.  /*+0x44*/  uchar DefaultClustersPerIndexAllocationBuffer;     // 簇/索引块  
  34.  /*+0x45*/  uchar   Reserved1[3];       // 未使用  
  35.  /*+0x48*/  uint64  SerialNumber;       // 64位序列号  
  36.  /*+0x50*/  uint32  Checksum;           // 校验和  
  37.  /*+0x54*/  uchar   BootStrap[426];     // 启动代码  
  38.  /*+0x1FE*/ uint16  RecordEndSign;      // 0xAA55 结束标记  
  39. }NTFS_Boot_Sector, *pNTFS_Boot_Sector;  

在读取DBR的时候,一些数据以后经常会用到,那么需要根据DBR里面的信息保存以后会用到的信息,下面定义一个常用的保存信息结构:

  1. // 保存 NTFS 的基本信息  
  2. typedef struct _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.       
  12.     uint16 VolumeLabelLength;           //  卷名长度,卷名从MFT第4个项0x60属性得到(与0x30属性相似)  
  13.     wchar VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH];  // 卷名  
  14.       
  15.     uint16 vcnlen;  
  16.     uchar vcn[VCN_LENTH];  
  17. } 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. typedef struct _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. // 按簇读取数据,  
  11. // 传入 一个Partition_Stand_Post结构体指针,并指定buf,读取大小  
  12. // 结果返回读取的数据指针  
  13. PBYTE ReadClues(pPartition_Stand_Post post, PBYTE buf, DWORD lenth)  
  14. {  
  15.     DWORD dwbytes = 0;  
  16.     LARGE_INTEGER li = {0};  
  17.     li.QuadPart = post->CluNnum*post->BytesPerCluster;  
  18.     SetFilePointer(post->handle, li.LowPart, &li.HighPart, FILE_BEGIN);  
  19.     ReadFile(post->handle, buf, lenth, &dwbytes, NULL);  
  20.     if (lenth == dwbytes)  
  21.     {  
  22.         return buf;  
  23.     }  
  24.     return NULL;  
  25. }  

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