解析NTFS(二)DBR\MFT部分

前面解析MBR,得到每个分区的起始扇区号,以及每个分区的大小;至于该分区的详细信息,则取决于该分区卷加载的文件系统。比如:簇大小,扇区大小,文件系统类型,该分区使用情况,介质描述,隐含扇区,扇区总数……
  解析完MBR,跳转到引导分区的第一个扇区,即DBR;然后从DBR中的BPB中得到改卷的基本参数信息,定位MFT起始簇,进而定位到文件系统元数据文件位置,对该分区上的所有文件和目录进行遍历解析。

下面分步说明:

  DBR的作用
  简单的来说,计算机启动时执行完BOIS的启动代码,检查各硬件设备正常后,JMP到MBR的引导代码进行执行;然后由MBR引导至活动分区的DBR,再由DBR引导操作系统。如:DBR调用NTLDR,再由NTLDR调用系统内核。

  一.FAT32 DBR 和NTFS $BOOT 的统一

  每个分区第0号扇区,也就是系统引导扇区DBR(DOS BOOT RECORDER)。不管是FAT32文件系统,还是NTFS文件系统,第一个扇区内容都是DBR。很多做文件系统过滤驱动的开发人员强调,如果是FAT32系统,那么分区开始的第一个扇区是DBR;如果是NTFS系统,那么分区开始的第一个扇区是$BOOT文件。其实,这个说法是基于文件系统特征的,虽然没有错,但也混淆了视听。事实上,在NTFS系统上,$BOOT位于分区开始的2个簇上,也就是16个扇区,8K大小(假设每簇大小占8扇区)。在这16个扇区上,第一个扇区仍然是DBR。所以,从分区卷扇区级上来说,NTFS分区的第一个扇区仍然是DBR。这样就统一了说法,也便于理解了~

  二.读取DBR,进行解析:
  为什么要读DBR呢,因为DBR存放着关于文件系统的重要参数信息以及系统引导代码。读DBR扇区的数据,并进行解析;由前面的分析,至少有两种方法可以定位到DBR的位置。
  关于解析DBR,声明两个重载的函数:
  void AnalyseDBR(ULONG ulSector);  //参数为扇区号
void AnalyseDBR(wchar_t* szVolumeLink);  //参数为分区符号链接

A. 解析MBR,根据分区表的信息,定位到指定分区的起始扇区,读取该扇区,按照DBR格式进行解析,上一节已经解析了MBR,分区信息存储在链表结构里,直接定位到第一个分区,读取DBR,伪代码如下:
  //
  //  定位到第一个卷,即C盘
  //
  {
    NextEntry = RemoveHeadList(&NtfsData.Partitions);
    
    PtItem= (PPARTITION_ITEM)CONTAINING_RECORD(NextEntry,PARTITION_ITEM,ForPtChain.ListEntry);
    
    cout<<"\nthe test volume's start sector:"<<PtItem->StartSector<<endl;
    ulDbrSector = PtItem->StartSector;

  }
  // 利用解析MBR的分区表信息,定位到分区开始扇区,解析DBR
  AnalyseDBR(ulDbrSector);
  详细代码见toysNtfs工程。

B. 根据分区符号链接,如:_T("\\\\.\\C:"),直接打开分区,进行读写;相比解析MBR的方式,这种方法明显直接而简单,打开分区以后,第一个扇区就是DBR。解析MBR虽然麻烦,但是灵活;将整个磁盘与分区都联系起来,更容易理解磁盘结构;甚至经过深入学习,自己开发一个小型的磁盘分区工具,划分一小块空间,用来存储自己的秘密文件,该卷的解析方式只有你自己知道(有意不让windows识别),岂不快哉~

  伪代码如下:(假设打开C:盘)
  // 利用分区符号链接,打开分区,进行解析
  AnalyseDBR(_T("\\\\.\\C:"));

  前后两种方法解析的结果如下:

 
  (相同的结果)

C.  DBR在磁盘上的格式和各字段的含义,在FAT文件系统上的DBR和NTFS上的DBR有所不同,下面以NTFS为例:
大概分以下几个部分:
跳转指令;
文件系统标志, Oem;
BPB,25字节;
其后类似于扩展BPB的一些字段;
大小为[0x200-0x044]的引导代码;
结束标志:55AA

用代码结构表示如下:同样,只记录需要关心的若干字段,便于解析NTFS其他部分。
  typedef struct _PACKED_BOOT_SECTOR {

    UCHAR Jump[3];                                
    UCHAR Oem[8];                                 
    BIOS_PARAMETER_BLOCK PackedBpb;    //BPB          
    UCHAR Unused[4];                              
    LONGLONG NumberSectors;   //扇区总数        
    LCN MftStartLcn;    //MFT开始簇                  
    LCN Mft2StartLcn;                             
    CHAR ClustersPerFileRecordSegment;            
    UCHAR Reserved0[3];
    CHAR DefaultClustersPerIndexAllocationBuffer; 
    UCHAR Reserved1[3];
    LONGLONG SerialNumber;                        
    ULONG Checksum;                               
    UCHAR BootStrap[0x200-0x044];    //引导代码    

} PACKED_BOOT_SECTOR;                             

typedef PACKED_BOOT_SECTOR *PPACKED_BOOT_SECTOR;

  DBR中的BPB结构如下:

  typedef struct BIOS_PARAMETER_BLOCK {


    USHORT BytesPerSector;
    UCHAR  SectorsPerCluster;
    USHORT ReservedSectors;
    UCHAR  Fats;
    USHORT RootEntries;
    USHORT Sectors;
    UCHAR  Media;
    USHORT SectorsPerFat;
    USHORT SectorsPerTrack;
    USHORT Heads;
    ULONG  HiddenSectors;
    ULONG  LargeSectors;

} BIOS_PARAMETER_BLOCK;

typedef BIOS_PARAMETER_BLOCK *PBIOS_PARAMETER_BLOCK;

   大概能见名知意。BPB(bois parameter block) 是一段描述能够使可执行引导代码找到相关参数的信息。主要描述磁盘结构的细节,包括每扇区的字节数BytesPerSector,每簇的扇区数SectorsPerCluster;磁盘介质;每磁道扇区数,磁头数等,均为后续引导代码提供参数。
关于文件系统的信息,其实在扩展BPB中,也就是BPB之后的若干字段。这些字段中的数据使得NTLDR能够在启动时找到主文件表$MFT,进而定位到其他数据文件。


  至此,DBR解析完毕,得到该卷上的MFT起始簇,备份MFT起始簇,每簇扇区数,每扇区字节数,介质等信息。经过简单的计算就能知道起始MFT的扇区号。

  三.解析MFT

    由于用扇区来描述磁盘空间粒度比较小,处理量比较大,所以引进簇的概念。簇一般是2的倍数,一般NTFS中一个簇占8个连续扇区。基本上所有文件系统用簇来描述分区。
  LCN(logical cluster number)逻辑簇号,对卷的第1个簇到最后一个簇进行编号。只要知道LCN号和簇的大小以及NTFS卷在物理磁盘中的绝对扇区就可以对簇进行扇区定位。
  VCN(virtual cluster number)虚拟簇号,VCN对特定文件的簇从头到尾进行编号,表示文件内部的相对位置,方便系统对文件中的数据进行引用。假如一个文件占用m个簇,那么这些簇的VCN就是从0到(m-1)。

     NTFS文件系统用文件来记录所有信息;文件由属性组成;所以对NTFS文件的读写,实际上是对NTFS属性的读写。一个文件对应一条MFT记录(即文件记录块),一个文件记录块固定大小为1K,占两个扇区;所有文件的MFT记录都有一个文件来管理,就是$MFT,也就是0号MFT记录所指向的文件。
  由前面解析DBR知道MFT起始扇区,那么读取该扇区内容,就是$MFT文件的文件记录了。
  解析之前,先说说元文件,对文件系统有一个全局的认识。
  NTFS文件系统由DBR(本身也是$BOOT的内容)和元文件组成,其他文件和目录通过文件系统管理。
元数据文件记录了一些非常重要的文件系统数据,包括用于文件定位和恢复的数据结构、引导程序数据以及整个卷的分配位图等信息。这些数据被NTFS文件系统理解为文件,并以文件的方式进行管理,统一了思想。
元文件对于用户是不能直接访问的,MFT将开头的16个文件记录块保留用于这些元数据文件,除此之外的文件记录块才用于普通的用户文件和目录。
文件系统16个元文件列表:
  0    $MFT    //mft本身
  1  $MftMirr    //mft 元数据文件的镜像,用于备份恢复
  2  $LogFile    //文件操作历史记录文件
  3  $Volume    //文件卷信息文件
  4  $AttrDef    //属性定义文件
  5  $Root(\)    //根目录文件
  其它的元文件参照其他资料,不例举了。
  
  MFT结构

     每个文件都有一条MFT记录,通过读取该文件的MFT记录,就可以知道该文件有哪些属性,各属性的内容是多少,是否有加密,是否有隐藏存档属性,是否有命名的数据流等。
  MFT文件记录由记录头和属性部分组成;一个文件可以有多个属性,这些属性又分为属性头和属性内容。这些属性的标准信息由$AttrDef元文件定义。
  
  属性又分为常驻属性(Resident Attr)和非常驻属性(NonResident Attr)。当文件的属性内容大于大约700字节时,就要使用非常驻属性。将属性内容外挂到磁盘的其他位置,这些位置由runs片来描述。
  不同属性相同的地方在于属性头,即要么是常驻属性头,要么是非常驻属性头;不同属性的属性内容各不相同,在磁盘上的分布结构也不同,作用也不同;特别说明,这些属性是可以扩充的。对各个属性的解析,则比较繁琐。

  那么解析MFT文件记录块的基本框架如下:
  

ReadSector( MFT索引号, 长度)
{
  解析MFT记录头;(大小0x38字节)
  解析属性部分
  {
    Switch(属性类型)
    {
      Case: 对不同的属性做处处理,读取或修改,break;
      Default:
    }

  }

}
  指定一个MFT,解析属性列表:
  
  关于MFT的详细结构,请参考文献资料,解析过程见代码。
  
  无法说的太详细,因为NTFS内容很多,结构却一点也不复杂;展开全部细节,却又不是只言片语就能说完的,亦属力所不能及;说的太概念化,又恐读之无物。那,权当抛砖引玉吧。
  程序代码写的只是一个框架,在这个框架上就可以填充各个属性的详细分析过程。这样的解析未免不太科学,但是作为学习了解文件系统在磁盘上的底层结构,却是很简单有效的。如果要理解NTFS文件系统工作的原理,须跟踪文件系统IO处理流程,了解IO管理器,磁盘驱动,缓存cache管理等相关知识。
  
           顺着这个路径,熟悉文件的各个属性,属性之间的相互作用;用nt4.Src.cntfs代码,参考部分解析过程。
  
  PS:程序代码只是为了学习方便而写的简单测试框架;本节主要是分析DBR,获取MFT的起始簇,获取分区卷的必要参数信息;对指定的一条MFT文件记录进行定位和解析;如此就可以从MFT中读取文件的所有内容,包括:文件只读、隐藏、存档属性,创建时间,修改时间,对象ID,数据内容,命名数据流,重解析点等信息。
  那么,遗留的问题是,如何获得MFT索引号?MFT号其实是文件引用号(64位)的低48位,那么如何获取文件引用号?这里方法就不一了,比如:递归解析$Root跟目录文件,获取每个索引项的文件引用号,取低48位作为MFT索引号去MFT表中读取文件数据;第二种方法是,遍历MFT在磁盘上分布的区域大小,计算出总的MFT记录数量,然后发送控制码FSCTL_GET_NTFS_FILE_RECORD来获取文件引用号。
  
关于解析:首先要明确目的,才能在解析过程中对关心的文件属性信息作特殊处理;如果作为学习,那么选择一个清晰明了的框架还是比较合理的。等熟悉了基本结构,在去深入学习NTFS驱动源码,调试,在实际应用中开发项目,合理应用,使产品更高效;举个例子,NTFS文件系统中,遍历磁盘上的所有文件,并获取文件在磁盘上的数据存储信息。如果是普通的递归遍历法,即FindFirstFile,,FindNextFile,那么遍历速度将比直接遍历MFT慢25倍左右。

  下节具体解析文件的若干属性(数据属性,$IndexRoot根目录属性);给定文件名通过$ROOT文件查找文件引用号。


参考资料:
《数据恢复技术》 戴士剑、涂彦晖;
  《数据重现,文件系统原理精解》 马林
  《windows internal》,4th,Mark E.Russinovich
  《windows 内核情景分析》毛德操
相关代码:
ToysNtfs2.rar

posted on 2013-02-24 12:50  紫 陌  阅读(10952)  评论(0编辑  收藏  举报

导航