首页
社区
课程
招聘
[原创]解析NTFS(二)DBR\MFT部分
发表于: 2010-5-8 00:01 31429

[原创]解析NTFS(二)DBR\MFT部分

2010-5-8 00:01
31429
前面解析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

[课程]Linux pwn 探索篇!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (21)
雪    币: 492
活跃值: (53)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
2
又有新的内容了,进来学习~~~
2010-5-8 00:03
0
雪    币: 97
活跃值: (43)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
最近也在学习NTFS,所以先收藏了,等到了火候和楼主切磋一下
2010-5-9 16:34
0
雪    币: 392
活跃值: (89)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
4
有朋自远方来,不亦乐乎~这方面,会的牛人多,学习的人也多,但是学习的过程不明了,初学者很容易陷入困境;相互交流方法,共同进步
2010-5-9 16:51
0
雪    币: 133
活跃值: (113)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
5
写得很详细,借鉴一下,谢谢。期待第三,查找文件。
2010-5-11 07:00
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
不错,学习了,期待 解析NTFS(N)
2010-5-31 22:11
0
雪    币: 156
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
什么时候有更新?讲的很好啊。
2010-8-9 12:21
0
雪    币: 189
活跃值: (4810)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
收藏...........
2010-10-2 04:51
0
雪    币: 563
活跃值: (95)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
备用!
2010-10-6 09:28
0
雪    币: 14
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
非常期待续集啊,感谢楼主,让我受益匪浅
2011-4-5 21:04
0
雪    币: 123
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
MARK  %2凑字
2011-4-5 21:14
0
雪    币: 2323
活跃值: (4113)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
12
先标记一下,说不定以后用的着~~嘿嘿~~
2011-4-5 21:14
0
雪    币: 1149
活跃值: (833)
能力值: ( LV13,RANK:260 )
在线值:
发帖
回帖
粉丝
13
标记 要断电了。。。
2011-4-5 22:19
0
雪    币: 278
活跃值: (709)
能力值: ( LV15,RANK:520 )
在线值:
发帖
回帖
粉丝
14
顶起,谢谢了
2011-5-10 18:47
0
雪    币: 68
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
mark一下 以后学习
2011-5-11 14:41
0
雪    币: 76
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
楼主的代码风格画虎不成反类*, 非C非C++,非ring3非ring0.
2011-5-12 15:05
0
雪    币: 71
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
正在看其中一本书
感谢分享心得
2011-5-12 15:23
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
做个记号,谢谢楼主
2011-9-2 17:47
0
雪    币: 270
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
做个记号,期待楼主的解析NTFS(三)
2011-11-28 23:59
0
雪    币: 246
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
20
有没有兴趣一起做个NTFS  应用层得解析修复引擎?
2011-12-10 12:30
0
雪    币: 70
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
最近在看win 8 的启动流程,看到了bootmgr部分了,希望lz继续
2011-12-10 20:06
0
雪    币: 60
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
mark一下 以后学习
2012-4-17 08:25
0
游客
登录 | 注册 方可回帖
返回
//