ntfs
一如既往的叨叨
首先要对硬盘分区(MBR、GPT)和文件系统(NTFS、fat32等)有一定的认识,要知道MBR扇区以及DBR扇区的基本结构,如果后面遇到不清楚的地方可以参考上一篇文章https://blog.csdn.net/hilavergil/article/details/79270379,如果觉得这个文章不行的话,Emmm...还有Google呢。
接下来的代码目前只适用于MBR格式的分区,如果后面有时间的话再加上GPT的分区定位,实际上GPT的分区表更简洁明了一些。
我尽量少用windows的Api,从硬盘的MBR扇区(0扇区)开始逐步定位,确定每一个主分区和扩展分区的位置,如果是NTFS分区则定位到MFT,从根目录开始使用DFS进行遍历。
我们的目标是
由于硬盘的分区定位在上面那篇文章已经写过了,因此这篇文章的重点会放在ntfs文件系统的解析上。我们从一个硬盘的MBR扇区开始,定位到一个NTFS分区,然后从NTFS分区的第一个扇区(Boot扇区)开始,逐步分析并定位到该分区中的每个目录和文件。
好了开始写正文
前面那篇文章曾提到过,MBR扇区中的分区表只有四项,当分区数小于等于3的时候,所有的分区都属于主分区,安装操作系统的主分区也叫活动分区,这些在Windows的磁盘管理中都可以看到,MBR扇区中分区表的每一项直接指向该主分区的起始位置,也就是该主分区的DBR扇区。当分区数大于等于4的时候呢怎么办?一般来说这种情况下MBR扇区中分区表的第四项将会指向扩展分区,一个扩展分区可以包含多个逻辑分区,每个逻辑分区都有一个EBR扇区与之对应。而EBR扇区和MBR扇区的结构是一致的,但是在EBR扇区中仅用到了其分区表的前两项,其中第一项指向本逻辑分区的起始偏移(注意逻辑分区是存在于扩展分区内的,见下图),第二项指向下一个逻辑分区的EBR扇区。如此循环往复,你会发现实际上EBR扇区构成了一个逻辑分区的链表,链表的每一个节点都包含两项,第一项指向该EBR对应的逻辑分区,第二项指向下一个逻辑分区的EBR扇区。最后一个节点的第二项为零,表示此后不再有逻辑分区。
图1 名字可能不太对但结构应该没差.png
当找到一个NTFS文件系统的分区之后,接下来就可以开始着手遍历目录树和文件了。你可能要问为什么不是FAT32或者其他的分区,因为我只看了NTFS……
第一步:读取NTFS的DBR扇区
DBR扇区的结构在之前那片文章写过了,下面给个DBR的截图。
图2 DBR扇区
图中红色方框里面的数据是MFT的偏移(小端字节序),即0X 00 00 00 00 00 0C 00 00,单位是簇,即MFT偏移786432个簇(相对于该分区的起始位置而言),蓝色方框里是每簇的扇区数0X08,黑色方框里是每扇区字节数0X 02 00,即512个字节。有了这些就可以算出MFT偏移的扇区数:786432 乘 8 等于 6291456个扇区,我们转到该分区的第 6291456扇区,就是MFT文件的第一个扇区了。接下来该分析MFT了。
第二步:解析MFT
图3 ???
不好意思,进错片场了。
图4 MFT主文件表
实际上MFT也是一个文件,在winhex中可以看到它:
图5 WinHex中的MFT文件
也能看到MFT的偏移和我们之前计算的结果时一致的。MFT由一个个表项构成,每一个表项是一个文件记录,大小一般为1KB(两个扇区),记录着卷中每一个目录和文件的信息,每个文件记录的结构都是固定的,由文件记录头和若干属性构成。下面给一个截图:
图6 一个文件记录
其中,文件记录头的结构定义如下:
// 文件记录头
typedef struct _FILE_RECORD_HEADER
{
/*+0x00*/ BYTE Type[4]; // 固定值'FILE'
/*+0x04*/ UINT16 USNoffset; // 更新序列号偏移, 与操作系统有关
/*+0x06*/ UINT16 USNCount; // 固定列表大小Size in words of Update sequence Number & Array (S)
/*+0x08*/ UINT64 Lsn; // 日志文件序列号(LSN)
/*+0x10*/ UINT16 SequenceNumber; // 序列号(用于记录文件被反复使用的次数)
/*+0x12*/ UINT16 LinkCount; // 硬连接数
/*+0x14*/ UINT16 AttributeOffset; // 第一个属性偏移
/*+0x16*/ UINT16 Flags; // flags, 00表示删除文件,01表示正常文件,02表示删除目录,03表示正常目录
/*+0x18*/ UINT32 BytesInUse; // 文件记录实时大小(字节) 当前MFT表项长度,到FFFFFF的长度+4
/*+0x1C*/ UINT32 BytesAllocated; // 文件记录分配大小(字节)
/*+0x20*/ UINT64 BaseFileRecord; // = 0 基础文件记录 File reference to the base FILE record
/*+0x28*/ UINT16 NextAttributeNumber; // 下一个自由ID号
/*+0x2A*/ UINT16 Pading; // 边界
/*+0x2C*/ UINT32 MFTRecordNumber; // windows xp中使用,本MFT记录号
/*+0x30*/ UINT16 USN; // 更新序列号
/*+0x32*/ BYTE UpdateArray[0]; // 更新数组
} FILE_RECORD_HEADER, *pFILE_RECORD_HEADER;
文件记录头后面就是属性了,属性由属性头和属性体构成,有如下几种类型:
图7 属性类型
属性有常驻属性和非常驻属性之分,当一个属性的数据能够在1KB的文件记录中保存的时候,该属性为常驻属性;而当属性的数据无法在文件记录中存放,需要存放到MFT外的其他位置时,该属性为非常驻属性。常驻属性和非常驻属性的头部结构定义如下:
//常驻属性和非常驻属性的公用部分
typedef struct _CommonAttributeHeader {
UINT32 ATTR_Type; //属性类型
UINT32 ATTR_Size; //属性头和属性体的总长度
BYTE ATTR_ResFlag; //是否是常驻属性(0常驻 1非常驻)
BYTE ATTR_NamSz; //属性名的长度
UINT16 ATTR_NamOff; //属性名的偏移 相对于属性头
UINT16 ATTR_Flags; //标志(0x0001压缩 0x4000加密 0x8000稀疏)
UINT16 ATTR_Id; //属性唯一ID
}CommonAttributeHeader,*pCommonAttributeHeader;
//常驻属性 属性头
typedef struct _ResidentAttributeHeader {
CommonAttributeHeader ATTR_Common;
UINT32 ATTR_DatSz; //属性数据的长度
UINT16 ATTR_DatOff; //属性数据相对于属性头的偏移
BYTE ATTR_Indx; //索引
BYTE ATTR_Resvd; //保留
BYTE ATTR_AttrNam[0];//属性名,unicode,结尾无0
}ResidentAttributeHeader, *pResidentAttributeHeader;
//非常驻属性 属性头
typedef struct _NonResidentAttributeHeader {
CommonAttributeHeader ATTR_Common;
UINT64 ATTR_StartVCN; //本属性中数据流起始虚拟簇号
UINT64 ATTR_EndVCN; //本属性中数据流终止虚拟簇号
UINT16 ATTR_DatOff; //簇流列表相对于属性头的偏移
UINT16 ATTR_CmpSz; //压缩单位 2的n次方
UINT32 ATTR_Resvd;
UINT64 ATTR_AllocSz; //属性分配的大小
UINT64 ATTR_validSz; //属性的实际大小
UINT64 ATTR_InitedSz; //属性的初始大小
BYTE ATTR_AttrNam[0];
}NonResidentAttributeHeader, *pNonResidentAttributeHeader;
比较重要的几个属性如0X30文件名属性,其中记录着该目录或者文件的文件名;0X80数据属性记录着文件中的数据;0X90索引根属性,存放着该目录下的子目录和子文件的索引项;当某个目录下的内容比较多,从而导致0X90属性无法完全存放时,0XA0属性会指向一个索引区域,这个索引区域包含了该目录下所有剩余内容的索引项。
比较重要的几个属性的结构定义将在后面给出。
下面是一个90属性和A0属性的截图:
图8 90属性和A0属性
从图上大致也能看出来,90属性中包含了2个目录:Program Files (x86) 和 Users,剩下的其他目录就在A0的属性体所指向的索引区了。索引的具体含义将在后面给出。
前面说过,每一个文件记录都会对应一个目录或者文件,因此,如果我们按顺序读取每一个MFT表项,我们就能得到该卷中所有的文件和目录信息,其中还包括了部分被删除的文件和目录(被删除但未覆盖掉)。但我们的目的并不是目录和文件的简单罗列,我们要的是按照目录的树形结构去列出该卷的目录树,并且去定位某一个给定的文件,读出文件的数据。因此到这里还不够,继续向下。
由于所有的目录和文件都在MFT中有对应的记录,因此,一个卷中目录和文件的数量越多,MFT的大小就越大,$MFT文件的大小是动态增长的,NTFS默认给MFT分配了该卷的12.5%的存储空间。MFT的前16项(元数据文件)是固定的(现在第九项$Quota基本上不存在了):
图9 NTFS的元数据文件
有了前面这些基础,接下来我们就能去解析目录树,定位文件位置啦!
大致的思路如下:
首先,MFT的第五项是卷的根目录的文件记录,见上图的$Root项,这是我们遍历的起点。其次,通过根目录的文件记录的90属性和A0属性,可以定位根目录下所有内容的索引项,而这些索引项又指向了它自己的文件记录项(MFT中的一项),该文件记录的90和A0属性又指向了它的子目录的索引项。所以呢。写个递归呀,我们的目录树就出来啦。这个树形结构大致上是这样的:
图10 一棵树
接下来以E盘中的E:\dir1_0\dir2_0\dir3_1\新建文本文档.txt为例,一步步详细的写出遍历的步骤,并读取出这个文本文档中的数据。
第三步:得到根目录的文件记录
前面我们通过计算得到,MFT的偏移为6,291,456个扇区,而根目录的文件记录是MFT的第5项,一个MFT表项占2个扇区,所以根目录的文件记录的偏移为6,291,456 + 2 * 5 = 6,291,466个扇区。转到该扇区,可以看到根目录的文件记录如下:
图11 根目录的文件记录
其中,30属性的属性体结构定义如下(不包含属性头):
//FILE_NAME 0X30属性体
typedef struct _FILE_NAME {
UINT64 FN_parentFR; /*父目录的MFT记录的记录索引。
注意:该值的低6字节是MFT记录号,高2字节是该MFT记录的序列号*/
FILETIME FN_CreatTime;
FILETIME FN_AlterTime;
FILETIME FN_MFTChg;
FILETIME FN_ReadTime;
UINT64 FN_AllocSz;
UINT64 FN_ValidSz;//文件的真实尺寸
UINT32 FN_DOSAttr;//DOS文件属性
UINT32 FN_EA_Reparse;//扩展属性与链接
BYTE FN_NameSz;//文件名的字符数
BYTE FN_NamSpace;/*命名空间,该值可为以下值中的任意一个
0:POSIX 可以使用除NULL和分隔符“/”之外的所有UNICODE字符,最大可以使用255个字符。注意:“:”是合法字符,但Windows不允许使用。
1:Win32 Win32是POSIX的一个子集,不区分大小写,可以使用除““”、“*”、“?”、“:”、“/”、“<”、“>”、“/”、“|”之外的任意UNICODE字符,但名字不能以“.”或空格结尾。
2:DOS DOS命名空间是Win32的子集,只支持ASCII码大于空格的8BIT大写字符并且不支持以下字符““”、“*”、“?”、“:”、“/”、“<”、“>”、“/”、“|”、“+”、“,”、“;”、“=”;同时名字必须按以下格式命名:1~8个字符,然后是“.”,然后再是1~3个字符。
3:Win32&DOS 这个命名空间意味着Win32和DOS文件名都存放在同一个文件名属性中。*/
BYTE FN_FileName[0];
}FILE_NAME,*pFILE_NAME;
对照上图,可以得到根目录的文件名为 “ . ”。
第四步:计算根目录下索引项的偏移
90属性的属性体由3部分构成:索引根、索引头和索引项。但是有些情况下90属性中是不存在索引项的(上图的90属性不包含索引项,图8中的90属性包含2个索引项),这个时候该目录的索引项由A0属性中的data runs指出。90属性体的结构如下(不包含属性头):
typedef struct _INDEX_HEADER {
UINT32 IH_EntryOff;//第一个目录项的偏移
UINT32 IH_TalSzOfEntries;//目录项的总尺寸(包括索引头和下面的索引项)
UINT32 IH_AllocSize;//目录项分配的尺寸
BYTE IH_Flags;/*标志位,此值可能是以下和值之一:
0x00 小目录(数据存放在根节点的数据区中)
0x01 大目录(需要目录项存储区和索引项位图)*/
BYTE IH_Resvd[3];
}INDEX_HEADER,*pINDEX_HEADER;
//INDEX_ROOT 0X90属性体
typedef struct _INDEX_ROOT {
//索引根
UINT32 IR_AttrType;//属性的类型
UINT32 IR_ColRule;//整理规则
UINT32 IR_EntrySz;//目录项分配尺寸
BYTE IR_ClusPerRec;//每个目录项占用的簇数
BYTE IR_Resvd[3];
//索引头
INDEX_HEADER IH;
//索引项 可能不存在
BYTE IR_IndexEntry[0];
}INDEX_ROOT,*pINDEX_ROOT;
由于这里90属性没有索引项,我们直接看A0属性。
A0属性的属性体即为Data Runs,指向若干个索引区域的簇流(若干个物理上连续的簇称为一个簇流)。以上图的Data Runs为例:【11 01 2C 00 00 00 00 00】第一个字节【11】中的第二个1,表示接下来占用“1”个字节,用来存储该簇流占用簇的个数,即紧随其后的一个字节【01】,表示这个簇流占了0X01个簇的空间。第一个字节【11】中的第一个1,表示接下再占用“1”个字节,用来存储该簇流的偏移,即字节【2C】,表示偏移量为0X2C个簇。再往后一个字节为【00】,是结束标志。也就是说,该Data Runs只有一个簇流,而这个簇流包含一个簇,簇流的起始偏移为0X2C个簇,一个簇为8个扇区,即根目录所指向的索引区的偏移为44 * 8 = 352个扇区。
下面再给一个多簇流的data runs:
图12 Data Runs
十六进制的Data Runs 如下:31 05 F9 FF 0B 21 01 4E FF 11 01 12 31 01 12 CA F4 21 02 31 12 21 02 00 48 21 04 C9 0F 21 04 C9 59 31 04 87 11 01 21 08 57 10 00 02 A0 F8 FF FF。下面是对该Data Runs的解析:
图13 Data Runs解析
从上图可以看出,该Data Runs一共包含了10个簇流,其中第一个簇流占用了5个簇,起始偏移为0X0BFFF9,即786425个簇;第二个簇流占用1个簇,相对于第一个簇流偏移【-178】个簇,即第二个簇流起始偏移为786425 – 178 = 786247个簇。接下来的簇流的计算方法是一样的。
第五步:读取索引项
回到图11,我们计算出data runs指向的索引区的偏移为352个扇区,转到第352扇区,即索引区第一个扇区的位置,我们将看到如下数据(只截取了部分索引项):
图14 索引区域
索引区域占用了若干个簇,每一个簇都包含了两部分:一个标准索引头和若干个标准索引项。这两部分的结构定义如下:
//标准索引头的结构
typedef struct _STD_INDEX_HEADER {
BYTE SIH_Flag[4]; //固定值 "INDX"
UINT16 SIH_USNOffset;//更新序列号偏移
UINT16 SIH_USNSize;//更新序列号和更新数组大小
UINT64 SIH_Lsn; // 日志文件序列号(LSN)
UINT64 SIH_IndexcacheVCN;//本索引缓冲区在索引分配中的VCN
UINT32 SIH_IndexEntryOffset;//索引项的偏移 相对于当前位置
UINT32 SIH_IndexEntrySize;//索引项的大小
UINT32 SIH_IndexEntryAllocSize;//索引项分配的大小
UINT8 SIH_HasLeafNode;//置一 表示有子节点
BYTE SIH_Fill[3];//填充
UINT16 SIH_USN;//更新序列号
BYTE SIH_USNArray[0];//更新序列数组
}STD_INDEX_HEADER,*pSTD_INDEX_HEADER;
//标准索引项的结构
typedef struct _STD_INDEX_ENTRY {
UINT64 SIE_MFTReferNumber;//文件的MFT参考号
UINT16 SIE_IndexEntrySize;//索引项的大小
UINT16 SIE_FileNameAttriBodySize;//文件名属性体的大小
UINT16 SIE_IndexFlag;//索引标志
BYTE SIE_Fill[2];//填充
UINT64 SIE_FatherDirMFTReferNumber;//父目录MFT文件参考号
FILETIME SIE_CreatTime;//文件创建时间
FILETIME SIE_AlterTime;//文件最后修改时间
FILETIME SIE_MFTChgTime;//文件记录最后修改时间
FILETIME SIE_ReadTime;//文件最后访问时间
UINT64 SIE_FileAllocSize;//文件分配大小
UINT64 SIE_FileRealSize;//文件实际大小
UINT64 SIE_FileFlag;//文件标志
UINT8 SIE_FileNameSize;//文件名长度
UINT8 SIE_FileNamespace;//文件命名空间
BYTE SIE_FileNameAndFill[0];//文件名和填充
}STD_INDEX_ENTRY,*pSTD_INDEX_ENTRY;
在标准索引头中,几个比较重要的数据如下:
(1)索引项的偏移:即第一个标准索引项的偏移。在上图中为0X 00 00 00 40,这个偏移是相对于当前位置的偏移,即相对于字节【40】而言,偏移0X40个字节。
(2)索引项的大小:表示这个簇中,有效的索引项和索引头的总字节数。在上图中为0X 00 00 0A 80,即2688个字节,超出该范围的索引项为无效的索引项。
我们顺序读取每一个索引项,找到路径E:\dir1_0\dir2_0\dir3_1\新建文本文档.txt中目录dir1_0的索引项:
图15 目录dir1_0的索引项
标准索引项的结构已给出,其中几个重要的数据:
(1)文件的MFT参考号:低6字节是目录或者文件对应的文件记录的编号,由于MFT是顺序存储的,根据该编号可以定位到该文件记录在MFT中的位置。在上图中,目录dir1_0的MFT参考号为0X 00 00 00 00 00 2A,即dir1_0的文件记录是MFT的第0X2A,即第42项。之前已计算出MFT的偏移为6,291,456扇区,每一项占用2个扇区,因此dir1_0的文件记录的偏移为6,291,456 + 2 * 42 = 6291540扇区。
(2)索引项的长度:即本索引项占用的字节数,定义该索引项的边界。
第六步:现在可以递归啦
我们转到第6291540扇区,即dir1_0的文件记录,按照先前的步骤,去解析90属性和A0属性,就能进入下一层目录,再去定位索引项,越来越深,直到列出该目录的树形结构。OK,还是慢慢来,dir1_0的文件记录如下:
图16 dir1_0的文件记录
可以看到,30属性中的文件名为dir1_0,90属性中无索引项,A0属性的data runs为【11 01 2A 00 00 00 00 00】,计算得出dir1_0的索引区占用0X01个簇,偏移为0X2A个簇,即0X2A * 8 = 336扇区,转到336扇区,会看到如下索引数据:
图17 目录dir1_0下的索引项
找到路径E:\dir1_0\dir2_0\dir3_1\新建文本文档.txt中dir2_0的索引项,即上图的标准索引项1。得到dir2_0的文件记录的MFT编号为0X2D,可以计算出dir2_0的文件记录的偏移:MFT的起始偏移+MFT编号*2,即6,291,456 + 0X2D * 2 = 6291546扇区。读取该文件记录:
图18 dir2_0的文件记录
这个和以前有些不一样了,因为dir2_0只有两个子目录,90属性就够用了,因此没有A0属性。上面说过,90属性体由三部分构成:索引根、索引头和索引项。而90属性中的索引项和标准索引项的结构是一致的。接下来呢,我们找到路径E:\dir1_0\dir2_0\dir3_1\新建文本文档.txt中dir3_1的索引项,即上图中的索引项2,像以前一样计算出它的文件记录在MFT的位置并算出偏移扇区……
后面不再列举啦,一直找到新建文本文档.txt的文件记录,如下:
图19 新建文本文档.txt的文件记录
第七步:读取文件内容
对于文件呢,我们关注的是它的80属性,即数据属性。因为这个txt文件比较大,在MFT中无法存放其所有数据,因此这个文件的80属性为非常驻属性,属性体是一个data runs,指向存放该文件数据的簇。这里Data Runs的计算方法和前面是一致的,从上图可以看到,该data runs指向一个簇流,该簇流一共占用了0X 00 A9 89个簇,起始偏移为0X 4C C8 40个簇,即40256000扇区。我们转到该扇区,就可以读取这个txt中存储的数据了,截图如下:
图20 .txt中的数据
到这里我们已经读到了这个文本文档中的数据了。对于小文件而言,常驻的80属性就能够存放它的数据内容,比如下面这个文件:
图21 小文件的80属性
这个文本文档中只有一个字符串“sadfasdfasdf”,能够存放在常驻的80属性中,因此80属性的属性体并不是Data Runs,而是直接存放了文件内容。
嗯,到这里其实也差不多了,后面附上我写的测试代码吧。代码跳过了活动分区,因为活动分区比较活跃,最好是能够先打一个快照再去读取。
也传到github了:https://github.com/Hilaver/NtfsResolution/
如果后面想到了其他的东西再做补充。
下面是主程序的测试代码:
// consoleAPPlication.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "ntfs.h"
#include "fat32.h"
using namespace std;
//#pragma comment(lib, "Shlwapi.lib")
//#pragma comment(lib, "Kernel32.lib")
//#pragma comment(lib, "version.lib")
#pragma pack(1)
#pragma warning(disable : 4996)
typedef struct _PHY_INFO {
dword number;
vector<TCHAR> vols;
}PHY_INFO,*pPHY_INFO;
typedef struct _VCN_LCN_SIZE {
UINT64 VCN;
UINT64 LCN;
UINT64 SIZE;
_VCN_LCN_SIZE() {}
_VCN_LCN_SIZE(UINT64 vcn, UINT64 lcn, UINT64 size) {
this->VCN = vcn;
this->LCN = lcn;
this->SIZE = size;
}
~_VCN_LCN_SIZE() {}
}VCN_LCN_SIZE, *pVCN_LCN_SIZE;
FILE *fp;
//ERROR msg
void GetErrormessage(DWORD dwErrCode, DWORD dwLanguageId) {//dwLanguageId=0
DWORD dwRet = 0;
LPTSTR szResult = NULL;
setlocale(LC_ALL, "chs");
dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
dwErrCode, dwLanguageId, (LPTSTR)&szResult, 0, NULL);
if (dwRet == 0) { szResult = NULL; _tprintf(_T("No such errorCode\n")); }
else { _tprintf(_T("%s"), szResult); }
szResult = NULL;
return;
}
//char to WCHAR
WCHAR * charToWCHAR(char *s) {
int w_nlen = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0);
WCHAR *ret;
ret = (WCHAR*)malloc(sizeof(WCHAR)*w_nlen);
memset(ret, 0, sizeof(ret));
MultiByteToWideChar(CP_ACP, 0, s, -1, ret, w_nlen);
return ret;
}
//读取物理磁盘
//物理磁盘设备号 起始偏移(Byte) 读取长度(最小一个扇区) 输出缓冲
DWORD ReadDisk(DWORD physicalDriverNumber, UINT64 startOffset, DWORD size, PVOID ret) {
overlapPED over = { 0 };
over.Offset = startOffset & (0xFFFFFFFF);
over.OffsetHigh = (startOffset >> 32)&(0xFFFFFFFF);
CHAR PHYSICALDRIVE[MAX_PATH]; memset(PHYSICALDRIVE, 0, sizeof(PHYSICALDRIVE));
strcpy(PHYSICALDRIVE, "\\\\.\\PHYSICALDRIVE");
PHYSICALDRIVE[strlen(PHYSICALDRIVE)] = '0' + physicalDriverNumber;
LPCWSTR PD = charToWCHAR(PHYSICALDRIVE);
handle handle = CreateFile(PD, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE) return 0;
DWORD readsize;
if (ReadFile(handle, ret, size, &readsize, &over) == 0){
CloseHandle(handle);return 0;
}
CloseHandle(handle);
return readsize;
}
//根据逻辑分区获取其物理磁盘设备号
DWORD GetPhysicalDriveFromPartitionLetter(TCHAR letter)
{
HANDLE hDevice; // handle to the drive to be examined
BOOL result; // results flag
DWORD readed; // discard results
STORAGE_DEVICE_NUMBER number; //use this to get disk numbers
CHAR path[MAX_PATH];
sprintf(path, "\\\\.\\%c:", letter);
//printf("%s\n", path);
hDevice = CreateFile(charToWCHAR(path), // drive to open
GENERIC_READ | GENERIC_WRITE, // access to the drive
FILE_SHARE_READ | FILE_SHARE_WRITE, //share mode
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL); // do not copy file attribute
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
GetErrorMessage(GetLastError(), 0);
//fprintf(stderr, "CreateFile() Error: %ld\n", GetLastError());
return DWORD(-1);
}
result = deviceiocontrol(
hDevice, // handle to device
IOCTL_STORAGE_GET_DEVICE_NUMBER, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
&number, // output buffer
sizeof(number), // size of output buffer
&readed, // number of bytes returned
NULL // OVERLAPPED structure
);
if (!result) // fail
{
fprintf(stderr, "IOCTL_STORAGE_GET_DEVICE_NUMBER Error: %ld\n", GetLastError());
(void)CloseHandle(hDevice);
return (DWORD)-1;
}
//printf("DeviceType(设备类型) is %d, DeviceNumber(物理设备号) is %d, PartitionNumber(分区号) is %d\n", number.DeviceType, number.DeviceNumber, number.PartitionNumber);
(void)CloseHandle(hDevice);
return number.DeviceNumber;
}
//获取逻辑分区的信息如卷标、空间等
void getVolumeInfo(LPCWSTR volumeName) {
DWORD dwTotalclusters;//总的簇
DWORD dwFreeClusters;//可用的簇
DWORD dwSectPerClust;//每个簇有多少个扇区
DWORD dwBytesPerSect;//每个扇区有多少个字节
BOOL bResult = GetDiskFreeSpace((volumeName), &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters);
printf(("总簇数:%d\n可用簇数:%d\n簇内扇区数:%d\n扇区内字节数:%d\n"), dwTotalClusters, dwFreeClusters, dwSectPerClust, dwBytesPerSect);
//GetErrorMessage(GetLastError(),0);
}
//print buffer in byte
void printBuffer(PVOID buffer, __int64 size) {
BYTE *p = (BYTE*)buffer;
__int64 pos = 0;
while (pos < size) {
fprintf(fp,"%+02X ", *(p++));
//printf("%+02X ", *(p++));
if (++pos % 16 == 0) { fprintf(fp,"\n"); /*printf("\n");*/}
}
}
void printBuffer2(PVOID buffer, __int64 size) {
BYTE *p = (BYTE*)buffer;
__int64 pos = 0;
while (pos < size) {
/*fprintf(fp, "%+02X ", *(p++));*/
printf("%+02X ", *(p++));
if (++pos % 16 == 0) { /*fprintf(fp, "\n");*/ printf("\n"); }
}
}
//不固定字节数的number转为带符号的INT64
INT64 Bytes2Int64(BYTE *num,UINT8 bytesCnt) {
INT64 ret = 0; bool isNegative = false;
memcpy(&ret, num, bytesCnt);
if (ret&(1 << (bytesCnt * 8 - 1))) {
isNegative = true;
INT64 tmp = (INT64(0X01)) << bytesCnt * 8;
for (int i = 0; i < 64 - bytesCnt * 8; i++) {
ret |= (tmp);
tmp <<= 1;
}
}
return isNegative ? -(~(ret)+1) : ret;
}
//获取物理磁盘设备号
vector<PHY_INFO> getPhyDriverNumber() {
//这个地方应该有更好的实现方法
vector<TCHAR> phyvols[32];
DWORD dwSize = GetLogicalDriveStrings(0, NULL);
char* drivers = (char*)malloc(dwSize * 2);
DWORD dwRet = GetLogicalDriveStrings(dwSize, (LPWSTR)drivers);
wchar_t* lp = (wchar_t*)drivers;//所有逻辑驱动器的根驱动器路径 用0隔开
DWORD tmpNum = 0;
while (*lp) {
tmpNum = GetPhysicalDriveFromPartitionLetter(lp[0]);
phyvols[tmpNum].push_back(lp[0]);
lp += (wcslen(lp) + 1);//下一个根驱动器路径
}
vector<PHY_INFO> tmpPhyInfo;
for (int i = 0; i < 32; i++) {
if (phyvols[i].size() != 0) {
PHY_INFO tmp;
tmp.number = i;
tmp.vols = phyvols[i];
tmpPhyInfo.push_back(tmp);
}
}
return tmpPhyInfo;
}
void parseMFTEntry(PVOID MFTEntry, DWORD IndexEntrySize,
DWORD phyDriverNumber, UINT64 volByteOffset, UINT8 secPerCluster,
UINT64 mftOffset, WCHAR *filePath);
void dfsIndexEntry(PVOID IndexEntryBuf, DWORD IndexEntrySize,
DWORD phyDriverNumber, UINT64 volByteOffset, UINT8 secPerCluster,
UINT64 mftOffset, WCHAR *filePath);
//DFS 索引项
//索引项 物理磁盘设备号 每个簇的扇区数 卷的物理偏移(字节) MFT的相对偏移(相对于本分区)
void dfsIndexEntry(PVOID IndexEntryBuf, DWORD IndexEntrySize,
DWORD phyDriverNumber, UINT64 volByteOffset, UINT8 secPerCluster, UINT64 mftOffset, WCHAR *filePath) {
printf("dfsIndexEntry\n");
//getchar();
//printf("IndexEntryBuf:\n");
//printBuffer2(IndexEntryBuf, IndexEntrySize);
//printf("\n");
//getchar();
pSTD_INDEX_ENTRY ptrIndexEntry = (pSTD_INDEX_ENTRY)IndexEntryBuf;
//BYTE *ptrOfIndexEntry = (BYTE*)IndexEntryBuf;
//获取MFT编号
UINT64 mftReferNumber = (ptrIndexEntry->SIE_MFTReferNumber) & 0XFFFFFFFFFFFF;//取低六字节
printf("SIE_MFTReferNumber is 0X%X\n", mftReferNumber);
fprintf(fp,"SIE_MFTReferNumber is 0X%X\n", mftReferNumber);
//读取文件名
//ptrOfIndexEntry = ptrIndexEntry->SIE_FileNameAndFill;
//UINT32 fileNameBytes = (ptrIndexEntry->SIE_FileNameSize) * 2;
//WCHAR *fileName = (WCHAR *)malloc(fileNameBytes + 2);
//memset(fileName, 0, fileNameBytes + 2);
//memcpy(fileName, ptrIndexEntry->SIE_FileNameAndFill, fileNameBytes);
//printf("SIE_FileName is %ls\n", fileName);
//读取该索引项对应的MFT
UINT64 mftEntryByteOffset = mftReferNumber * MFTEntrySize + mftOffset + volByteOffset;
printf("mftOffset is %llu\n", mftOffset);
printf("volByteOffset is %llu\n", volByteOffset);
printf("mftEntryByteOffset is %llu\n", mftEntryByteOffset);
PVOID mftEntryBuf = malloc(MFTEntrySize);
ReadDisk(phyDriverNumber, mftEntryByteOffset, MFTEntrySize, mftEntryBuf);
//printf("mftEntryBuf:\n");
//printBuffer2(mftEntryBuf, MFTEntrySize);
//printf("\n");
//getchar();
//解析MFT的0X90 0XA0属性
parseMFTEntry(mftEntryBuf, MFTEntrySize, phyDriverNumber, volByteOffset, secPerCluster, mftOffset, filePath);
}
//解析MFT表项 获取0X90 0XA0属性
//MFT表项 物理设备号 卷物理偏移(字节) 每个簇的扇区数
void parseMFTEntry(PVOID MFTEntry, DWORD IndexEntrySize, DWORD phyDriverNumber,
UINT64 volByteOffset, UINT8 secPerCluster, UINT64 mftOffset, WCHAR *filePath) {
printf("parseMFTEntry\n");
//getchar();
//printf("MFTEntry:\n");
//printBuffer2(MFTEntry, MFTEntrySize);
//printf("\n");
//getchar();
pFILE_RECORD_HEADER MFTEntryHeader = (pFILE_RECORD_HEADER)malloc(sizeof(FILE_RECORD_HEADER));
memcpy(MFTEntryHeader, MFTEntry, sizeof(FILE_RECORD_HEADER));
fprintf(fp, "MFTEntry : BytesAllocated is %u\n", MFTEntryHeader->BytesAllocated);
fprintf(fp, "MFTEntry : BytesInUse is %u\n", MFTEntryHeader->BytesInUse);
fprintf(fp,"MFTEntry : MFTRecordNumber is 0X%0X\n", UINT32((MFTEntryHeader->MFTRecordNumber)));
////
printf("MFTEntry : BytesAllocated is %u\n", MFTEntryHeader->BytesAllocated);
printf("MFTEntry : BytesInUse is %u\n", MFTEntryHeader->BytesInUse);
printf("MFTEntry : MFTRecordNumber is 0X%X\n", UINT32((MFTEntryHeader->MFTRecordNumber)));
////
//UINT32 MFTEntryNumber = MFTEntryHeader->MFTRecordNumber;
//printBuffer2(MFTEntryHeader, sizeof(FILE_RECORD_HEADER));
UINT16 attriOffset = MFTEntryHeader->AttributeOffset;//第一个属性偏移
printf("MFTEntry : AttributeOffset is %hu\n", MFTEntryHeader->AttributeOffset);
UINT8 *pointerInMFTEntry;
pointerInMFTEntry = (UINT8*)MFTEntry;
pointerInMFTEntry += attriOffset;
BYTE *pindexofMFTEntry = (BYTE*)MFTEntry;
pIndexOfMFTEntry += attriOffset;//pIndexOfMFTEntry偏移MFT头部大小 指向第一个属性头
UINT32 attriType, attriLen;
//BYTE ATTR_ResFlagAttri;
//get attribute
pCommonAttributeHeader pComAttriHeader = (pCommonAttributeHeader)malloc(sizeof(CommonAttributeHeader));
//存放目录下所有索引项的vector
vector<pSTD_INDEX_ENTRY>indexEntryOfDir;
//一个set 删除重复索引项
map<UINT64, BOOL>visMftReferNum;
bool finishFlag = FALSE;
UINT32 attrCnt = 0;
//file path
WCHAR currentFilePath[2048] = { 0 };
//MFT项的类型 00表示删除文件,01表示正常文件,02表示删除目录,03表示正常目录
printf("isDirectoryOrFile[00删除文件,01正常文件,02删除目录,03正常目录]: %hu\n", MFTEntryHeader->Flags);
while (TRUE) {
//pIndexOfMFTEntry 现在指向属性头, 后面会加上这个属性的总长 指向下一个属性头
memcpy(&attriType, pIndexOfMFTEntry, 4);//attri type
if (attriType == 0xFFFFFFFF) { fprintf(fp, "\nATTR_Type is 0xFFFFFFFF, break\n"); break; }
fprintf(fp, "\nattrCnt : %u\n", attrCnt++);
fprintf(fp, "##### AttributeHeader #####\n");
memset(pComAttriHeader, 0, sizeof(CommonAttributeHeader));
//属性头的通用部分
memcpy(pComAttriHeader, pIndexOfMFTEntry, sizeof(CommonAttributeHeader));
fprintf(fp, "ATTR_Type is 0X%X ATTR_Size is %d\n", pComAttriHeader->ATTR_Type, pComAttriHeader->ATTR_Size);
//如果属性总长>1024 先break
if (pComAttriHeader->ATTR_Size > 0x400) { fprintf(fp, "\attriLen is more than 1024, break\n"); break; }
fprintf(fp, "ATTR_NamOff is %hu ATTR_NamSz is %d", pComAttriHeader->ATTR_NamOff, pComAttriHeader->ATTR_NamSz);
//如果当前指针偏移大于MFT已用字节数 break
if ((pIndexOfMFTEntry - MFTEntry) > MFTEntryHeader->BytesInUse) {
fprintf(fp, "\nreach end of BytesInUse, break\n");
break;
}
//resolve attribute header
UINT16 attriheadersize = 0;
bool isResidentAttri = false;
switch (pComAttriHeader->ATTR_ResFlag)//是否常驻属性
{
case BYTE(0x00): {
isResidentAttri = true;
//get attribute header
pResidentAttributeHeader residentAttriHeader = (pResidentAttributeHeader)malloc(sizeof(ResidentAttributeHeader));
memcpy(residentAttriHeader, pIndexOfMFTEntry, sizeof(ResidentAttributeHeader));
fprintf(fp, "\n\n常驻属性\n\n");
//fprintf(fp, "ATTR_Size is %u\n", residentAttriHeader->ATTR_Size);
fprintf(fp, "ATTR_DatOff[属性头长度] is %hu\n", residentAttriHeader->ATTR_DatOff);
attriHeaderSize = residentAttriHeader->ATTR_DatOff;
UINT16 ResidentAttributeHeaderSize = residentAttriHeader->ATTR_DatOff;
residentAttriHeader = (pResidentAttributeHeader)realloc(residentAttriHeader, ResidentAttributeHeaderSize);
memcpy(residentAttriHeader, pIndexOfMFTEntry, ResidentAttributeHeaderSize);
//fprintf(fp, "ATTR_AttrNam[属性名] is %ls\n", residentAttriHeader->ATTR_AttrNam);
fprintf(fp, "ATTR_DatSz[属性体长度] is %u\n", residentAttriHeader->ATTR_DatSz);
fprintf(fp, "ATTR_Indx[属性索引] is %u\n", residentAttriHeader->ATTR_Indx);
break;
}
case BYTE(0x01): {
isResidentAttri = false;
//get attribute header
fprintf(fp, "\n\n非常驻属性\n\n");
pNonResidentAttributeHeader nonResidentAttriHeader = (pNonResidentAttributeHeader)malloc(sizeof(NonResidentAttributeHeader));
memcpy(nonResidentAttriHeader, pIndexOfMFTEntry, sizeof(NonResidentAttributeHeader));
//fprintf(fp, "\n\n非常驻属性\nATTR_Type is 0x%X\n", nonResidentAttriHeader->ATTR_Type);
fprintf(fp, "ATTR_DatOff[属性头长度] is %hu\n", nonResidentAttriHeader->ATTR_DatOff);
attriHeaderSize = nonResidentAttriHeader->ATTR_DatOff;
UINT16 NonResidentAttributeHeaderSize = nonResidentAttriHeader->ATTR_DatOff;
nonResidentAttriHeader = (pNonResidentAttributeHeader)realloc(nonResidentAttriHeader, NonResidentAttributeHeaderSize);
memcpy(nonResidentAttriHeader, pIndexOfMFTEntry, NonResidentAttributeHeaderSize);
fprintf(fp, "ATTR_StartVCN[起始VCN] is %llu\n", nonResidentAttriHeader->ATTR_StartVCN);
fprintf(fp, "ATTR_EndVCN[终止VCN] is %llu\n", nonResidentAttriHeader->ATTR_EndVCN);
fprintf(fp, "ATTR_ValidSz[属性实际长度 is %llu\n", nonResidentAttriHeader->ATTR_ValidSz);
fprintf(fp, "ATTR_AllocSz[属性分配长度] is %llu\n", nonResidentAttriHeader->ATTR_AllocSz);
fprintf(fp, "ATTR_InitedSz[属性初始长度] is %llu\n", nonResidentAttriHeader->ATTR_InitedSz);
//fprintf(fp, "ATTR_AttrNam[属性名] is %ls\n", nonResidentAttriHeader->ATTR_AttrNam);
break;
}
default:
break;
}
fprintf(fp, "\n##### END of AttributeHeader #####\n");
//resolve attribute data
BYTE *tmpAttriDataIndex = pIndexOfMFTEntry;
//待修改
//tmpAttriDataIndex += (pComAttriHeader->ATTR_ResFlag == BYTE(0x00) ? sizeof(ResidentAttributeHeader) : sizeof(NonResidentAttributeHeader));
tmpAttriDataIndex += (attriHeaderSize);
//tmpAttriDataIndex指向属性体
switch (pComAttriHeader->ATTR_Type)
{
case 0x00000030: {
//文件名属性 可能多个
pFILE_NAME ptrFileName = (pFILE_NAME)malloc(sizeof(FILE_NAME));
memcpy(ptrFileName, tmpAttriDataIndex, sizeof(FILE_NAME));
if (ptrFileName->FN_NamSpace == 0X02) { break; }
fprintf(fp, "\n##### FILE_NAME #####\n");
printf("\n##### FILE_NAME #####\n");
fprintf(fp, "FN_NameSz is %d\n", ptrFileName->FN_NameSz);
printf("FN_NameSz is %d\n", ptrFileName->FN_NameSz);
fprintf(fp, "FN_NamSpace is %d\n", ptrFileName->FN_NamSpace);
printf("FN_NamSpace is %d\n", ptrFileName->FN_NamSpace);
//get file name
UINT32 fileNameLen = UINT32(0xFFFF & (ptrFileName->FN_NameSz) + 1) << 1;
WCHAR *fileName = (WCHAR*)malloc(fileNameLen);
memset(fileName, 0, fileNameLen);
memcpy(fileName, tmpAttriDataIndex + sizeof(FILE_NAME), fileNameLen - 2);
//printf("FILENAME[0X] is:\n");
//printBuffer2(fileName, fileNameLen);
//printf("\n");
fprintf(fp, "FILENAME is %ls\n", fileName);
printf("FILENAME is %ls\n", fileName);
memset(currentFilePath, 0, sizeof(currentFilePath));
wcscpy(currentFilePath, filePath);
wcscat(currentFilePath,L"\\");
wcscat(currentFilePath, fileName);
printf("\n\n------>\ncurrentFilePath is %ls\n", currentFilePath);
fprintf(fp, "---> currentFilePath is %ls\n", currentFilePath);
fprintf(fp, "\n##### END of FILE_NAME #####\n");
printf("\n##### END of FILE_NAME #####\n");
getchar();
break;
}
case 0x00000090: {//INDEX_ROOT 索引根
pINDEX_ROOT pIndexRoot = (INDEX_ROOT*)malloc(sizeof(INDEX_ROOT));
memcpy(pIndexRoot, tmpAttriDataIndex, sizeof(INDEX_ROOT));
fprintf(fp, "\n##### INDEX_ROOT #####\n");
fprintf(fp, "IR_EntrySz[目录项的大小,一般是一个簇] is %u\n", pIndexRoot->IR_EntrySz);
fprintf(fp, "IR_ClusPerRec[目录项占用的簇数,一般是一个] is %u\n", pIndexRoot->IR_ClusPerRec);
fprintf(fp, "IH_TalSzOfEntries[索引根和紧随其后的索引项的大小] is %u\n", pIndexRoot->IH.IH_TalSzOfEntries);
fprintf(fp, "IH_EntryOff[第一个索引项的偏移] is %u\n", pIndexRoot->IH.IH_EntryOff);
printf("\n##### INDEX_ROOT #####\n");
printf("IR_EntrySz[目录项的大小,一般是一个簇] is %u\n", pIndexRoot->IR_EntrySz);
printf("IR_ClusPerRec[目录项占用的簇数,一般是一个] is %u\n", pIndexRoot->IR_ClusPerRec);
printf("IH_TalSzOfEntries[索引根和紧随其后的索引项的大小] is %u\n", pIndexRoot->IH.IH_TalSzOfEntries);
printf("IH_EntryOff[第一个索引项的偏移] is %u\n", pIndexRoot->IH.IH_EntryOff);
//0X90属性的实际大小
UINT32 attri90Size = sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) + pIndexRoot->IH.IH_TalSzOfEntries;
pIndexRoot = (INDEX_ROOT*)realloc(pIndexRoot, attri90Size);
memcpy(pIndexRoot, tmpAttriDataIndex, attri90Size);
//获取90属性中的索引头
INDEX_HEADER IR_IH = pIndexRoot->IH;
UINT32 indexTotalSize = pIndexRoot->IH.IH_TalSzOfEntries;//索引头和接下来的索引项的总大小 注意可能没有索引项
//获取90属性中的索引项
BYTE *pIndexOfEntry, *ptrIndexHeaderStart;//索引项的指针 索引头的指针
pIndexOfEntry = pIndexRoot->IR_IndexEntry;
ptrIndexHeaderStart = (BYTE*)(&(pIndexRoot->IH));
UINT32 indexEntryIn90AttriCnt = 0;
while (TRUE) {
UINT64 isIndexEntryFinish = 0;
memcpy(&isIndexEntryFinish, pIndexOfEntry, 8);
if (isIndexEntryFinish == 0X00) {
//MFT号是0 break
break;
}
if (pIndexOfEntry - ptrIndexHeaderStart > indexTotalSize) {
//超出有效长度 break
break;
}
INDEX_ENTRY *pIndexEntry = (INDEX_ENTRY *)pIndexOfEntry;
//printf("IE_FileNameSize is %d\n", pIndexEntry->IE_FileNameSize);
UINT32 fileNameBytes = (pIndexEntry->IE_FileNameSize) * 2;
WCHAR *fileName = (WCHAR *)malloc(fileNameBytes + 2);
memset(fileName, 0, fileNameBytes + 2);
memcpy(fileName, pIndexEntry->IE_FileNameAndFill, fileNameBytes);
//printf("IE_FileName is %ls\n", fileName);
indexEntryIn90AttriCnt++;
//printBuffer2(pIndexEntry, pIndexEntry->IE_Size);
//printf("\n");
//getchar();
/*******************************/
if (visMftReferNum.find((pIndexEntry->IE_MftReferNumber) & 0XFFFFFFFFFFFF) == visMftReferNum.end() && ((((pIndexEntry->IE_MftReferNumber) >> (8 * 6)) & 0XFFFF) != 0X00)) {
// $ObjId的索引项正常 但其指向的MFT的90属性异常 其中该MFT号的高2位为0 90属性中的MFT引用号异常
//这里读到了索引项
printf("find index entry in 90 attribute, cnt is %d\n", indexEntryIn90AttriCnt);
fprintf(fp, "find index entry in 90 attribute, cnt is %d\n", indexEntryIn90AttriCnt);
indexEntryOfDir.push_back(pSTD_INDEX_ENTRY(pIndexEntry));
visMftReferNum.insert(pair<UINT64, BOOL>((pIndexEntry->IE_MftReferNumber) & 0XFFFFFFFFFFFF, TRUE));
}
//dfsIndexEntry((PVOID)pIndexEntry, pIndexEntry->IE_Size, phyDriverNumber, volByteOffset, secPerCluster, mftOffset);
/*******************************/
pIndexOfEntry += pIndexEntry->IE_Size;
//getchar();
}
printf("\n##### END of INDEX_ROOT #####\n");
break;
}
case 0x000000A0: {//INDEX_ALLOCATION
fprintf(fp, "\n##### INDEX_ALLOCATION #####\n");
printf("\n##### INDEX_ALLOCATION #####\n");
//A0属性体
//存放VCN LCN
vector<VCN_LCN_SIZE>dataRuns;
//data runs 起始指针
BYTE *dataRunsStartOffset = tmpAttriDataIndex;
//data runs 总字节数
UINT32 attriBodySize = (pIndexOfMFTEntry + pComAttriHeader->ATTR_Size) - tmpAttriDataIndex;
//printf("attriBodySize is %u\n", attriBodySize);
//getchar();
UINT64 vcnCnt = 0;
while ((*dataRunsStartOffset) != 0X00 && dataRunsStartOffset - tmpAttriDataIndex < attriBodySize) {
UINT8 bytesClustersOfStdIndex = (*dataRunsStartOffset) & 0X0F, bytesCluOffsetOfStdIndex = (*dataRunsStartOffset >> 4) & 0X0F;
UINT32 totalBytes = bytesClustersOfStdIndex + bytesCluOffsetOfStdIndex;
//VCN.push_back(vcnCnt++);
UINT64 clustersOfStdIndex = 0;
INT64 cluOffsetOfStdIndex = 0;
//BYTE *ptrInDataRuns = (BYTE *)(&dataRuns);
memcpy(&clustersOfStdIndex, dataRunsStartOffset + 1, bytesClustersOfStdIndex);
//memcpy(&cluOffsetOfStdIndex, dataRunsStartOffset + 1 + bytesClustersOfStdIndex, bytesCluOffsetOfStdIndex);
cluOffsetOfStdIndex = Bytes2Int64(dataRunsStartOffset + 1 + bytesClustersOfStdIndex, bytesCluOffsetOfStdIndex);
//printf("Bytes2Int64 is %lld\n",Bytes2Int64(dataRunsStartOffset + 1 + bytesClustersOfStdIndex, bytesCluOffsetOfStdIndex));
if (vcnCnt == 0) {
dataRuns.push_back(VCN_LCN_SIZE(vcnCnt, cluOffsetOfStdIndex, clustersOfStdIndex));
}
else {
dataRuns.push_back(VCN_LCN_SIZE(vcnCnt, dataRuns[vcnCnt-1].LCN + cluOffsetOfStdIndex, clustersOfStdIndex));
}
vcnCnt++;
dataRunsStartOffset += (totalBytes + 1);
}
printf("-->INDEX_ALLOCATION Cluster Info\n");
for (int i = 0; i < dataRuns.size(); i++) {
printf("VCN, LCN, SIZE: %llu, %llu, %llu\n",dataRuns[i].VCN, dataRuns[i].LCN, dataRuns[i].SIZE);
}
printf("-->End of INDEX_ALLOCATION Cluster Info\n");
getchar();
for (int i = 0; i < dataRuns.size(); i++) {
DWORD stdIndexSize = dataRuns[i].SIZE * secPerCluster*sectorSize;//标准索引占用的总字节数
UINT64 stdIndexByteOffset = volByteOffset + dataRuns[i].LCN * secPerCluster*SectorSize;//标准索引的物理偏移
//读取标准索引区的数据 该data run 的N个簇全部读取
PVOID pStdIndexBuffer = malloc(stdIndexSize);
ReadDisk(phyDriverNumber, stdIndexByteOffset, stdIndexSize, pStdIndexBuffer);
fprintf(fp, "->data run cnt: %d\n", i);
printf("->data run cnt: %d\n", i);
UINT32 indexClusterCnt = 0;
//逐个簇分析
UINT32 indexEntryInIndxArea = 0;
while (indexClusterCnt < dataRuns[i].SIZE) {
//
fprintf(fp, "->cluster cnt: %d\n", indexClusterCnt);
printf("->cluster cnt: %d\n", indexClusterCnt);
//读取标准索引的头部
BYTE *ptrOfStdIndexBuffer = (BYTE*)pStdIndexBuffer + (indexClusterCnt*secPerCluster*SectorSize);//标准索引的指针
indexClusterCnt++;
//ptrIndex指向该索引簇的起始位置
BYTE *ptrIndex = ptrOfStdIndexBuffer;
pSTD_INDEX_HEADER pStdIndexHeader = (pSTD_INDEX_HEADER)malloc(sizeof(STD_INDEX_HEADER));
memcpy(pStdIndexHeader, ptrOfStdIndexBuffer, sizeof(STD_INDEX_HEADER));
UINT32 SIH_Flag;
memcpy(&SIH_Flag, pStdIndexHeader->SIH_Flag, 4);
if (SIH_Flag == 0x00000000) { break; }
//标准索引头的大小=第一个索引项的偏移+24字节
UINT32 stdIndexHeaderSize = pStdIndexHeader->SIH_IndexEntryOffset + 8 * 3;
pStdIndexHeader = (pSTD_INDEX_HEADER)realloc(pStdIndexHeader, stdIndexHeaderSize);
memcpy(pStdIndexHeader, ptrOfStdIndexBuffer, stdIndexHeaderSize);
//print
fprintf(fp, "\n##### STD_INDEX_HEADER #####\n");
fprintf(fp, "SIH_IndexEntryOffset[索引项偏移,从此位置开始] is %u\n", pStdIndexHeader->SIH_IndexEntryOffset);
fprintf(fp, "SIH_IndexEntrySize[索引项总大小] is %u\n", pStdIndexHeader->SIH_IndexEntrySize);
printf("\n##### STD_INDEX_HEADER #####\n");
printf("SIH_IndexEntryOffset[索引项偏移,从此位置开始] is %u\n", pStdIndexHeader->SIH_IndexEntryOffset);
printf("SIH_IndexEntrySize[索引项总大小] is %u\n", pStdIndexHeader->SIH_IndexEntrySize);
UINT32 stdIndexTotalSize = pStdIndexHeader->SIH_IndexEntrySize;
printf("SIH_IndexEntryAllocSize[索引项总分配大小] is %u\n", pStdIndexHeader->SIH_IndexEntryAllocSize);
printf("\n##### END of STD_INDEX_HEADER #####\n");
fprintf(fp, "SIH_IndexEntryAllocSize[索引项总分配大小] is %u\n", pStdIndexHeader->SIH_IndexEntryAllocSize);
fprintf(fp, "\n##### END of STD_INDEX_HEADER #####\n");
//指针移动到索引项
ptrOfStdIndexBuffer += stdIndexHeaderSize;
//BYTE *ptrIndexEntryStartOffset = ptrOfStdIndexBuffer;
while (TRUE) {
//MFT编号为0 break
UINT64 isIndexEntryFinish = 0;
memcpy(&isIndexEntryFinish, ptrOfStdIndexBuffer, 8);
//超出有效长度 break
if (ptrOfStdIndexBuffer - ptrIndex > stdIndexTotalSize) {
fprintf(fp, "超出INDEX有效范围, break\n");
printf("超出INDEX有效范围, break\n");
break;
}
//if (isIndexEntryFinish == UINT64(0)) { break; }
if (isIndexEntryFinish == UINT64(0)) { fprintf(fp, "find mft refer number[00]\n"); }
if (isIndexEntryFinish == UINT64(0)) { printf("find mft refer number[00]\n"); }
//printf("ptrOfStdIndexBuffer - ptrIndexEntryStartOffset is %d\n", ptrOfStdIndexBuffer - ptrIndexEntryStartOffset);
//逐个读取索引项
pSTD_INDEX_ENTRY pStdIndexEntry = (pSTD_INDEX_ENTRY)malloc(sizeof(STD_INDEX_ENTRY));
memcpy(pStdIndexEntry, ptrOfStdIndexBuffer, sizeof(STD_INDEX_ENTRY));
UINT32 stdIndexEntrySize = pStdIndexEntry->SIE_IndexEntrySize;
pStdIndexEntry = (pSTD_INDEX_ENTRY)realloc(pStdIndexEntry, stdIndexEntrySize);
memcpy(pStdIndexEntry, ptrOfStdIndexBuffer, stdIndexEntrySize);
if (pStdIndexEntry->SIE_MFTReferNumber == UINT64(0)) { break; }
//printf("\n##### STD_INDEX_ENTRY #####\n");
//fprintf(fp, "\n");
//printBuffer(pStdIndexEntry, stdIndexEntrySize);
//fprintf(fp, "\n");
//printf("SIE_MFTReferNumber is %d\n", (pStdIndexEntry->SIE_MFTReferNumber) & 0XFFFFFFFFFFFF);
//printf("SIE_IndexEntrySize[索引项大小] is %u\n", (pStdIndexEntry->SIE_IndexEntrySize));
//printf("SIE_FileNameSize is %d\n", (pStdIndexEntry->SIE_FileNameSize));
//printf("SIE_FileAllocSize is %llu\n", (pStdIndexEntry->SIE_FileAllocSize));
//printf("SIE_FileRealSize is %llu\n", (pStdIndexEntry->SIE_FileRealSize));
//UINT8 fileNameBytes = (pStdIndexEntry->SIE_FileNameSize) * 2;
//WCHAR *fileName = (WCHAR *)malloc(fileNameBytes + 2);
//memcpy(fileName, pStdIndexEntry->SIE_FileNameAndFill, fileNameBytes);
//printf("SIE_FileName is %ls\n", fileName);
//printf("\n##### END of STD_INDEX_ENTRY #####\n");
//这里读到了索引项
/********************************/
if (visMftReferNum.find((pStdIndexEntry->SIE_MFTReferNumber) & 0XFFFFFFFFFFFF) == visMftReferNum.end() && ((((pStdIndexEntry->SIE_MFTReferNumber) >> (8 * 6)) & 0XFFFF) != 0X00)) {
printf("find index entry in INDX area, cnt is %d\n", indexEntryInIndxArea);
fprintf(fp, "find index entry in INDX area, cnt is %d\n", indexEntryInIndxArea);
indexEntryInIndxArea++;
indexEntryOfDir.push_back(pSTD_INDEX_ENTRY(pStdIndexEntry));
visMftReferNum.insert(pair<UINT64, BOOL>((pStdIndexEntry->SIE_MFTReferNumber) & 0XFFFFFFFFFFFF, TRUE));
}
//dfsIndexEntry((PVOID)pStdIndexEntry, stdIndexEntrySize, phyDriverNumber, volByteOffset, secPerCluster, mftOffset);
/********************************/
//ptrOfStdIndexBuffer指向下一个索引项
ptrOfStdIndexBuffer += stdIndexEntrySize;
//getchar();
}
//printBuffer2(pStdIndexBuffer, stdIndexSize);
//getchar();
//fprintf(fp, "\n##### END of INDEX_ALLOCATION #####\n");
//printf("\n##### END of INDEX_ALLOCATION #####\n");
}
}
fprintf(fp,"\n##### END of INDEX_ALLOCATION #####\n");
printf("\n##### END of INDEX_ALLOCATION #####\n");
break;
}
case 0x00000010: {
break;
}
case 0x00000020: {
break;
}
case 0x00000040: {
break;
}
case 0x00000050: {
break;
}
case 0x00000060: {
break;
}
case 0x00000070: {
break;
}
case 0x00000080: {
//文件数据属性
//80属性体长度
UINT32 attriBodySize = (pIndexOfMFTEntry + pComAttriHeader->ATTR_Size) - tmpAttriDataIndex;
//属性体
pDATA ptrData = (pDATA)malloc(attriBodySize);
memcpy(ptrData, tmpAttriDataIndex, attriBodySize);
//如果是常驻属性 80属性体就是文件内容
if (isResidentAttri) {
//80属性体中的文件内容
printf("content in 0X80[resident]:\n");
printBuffer2(ptrData, attriBodySize);
printf("\n");
}
//如果是非常驻属性 80属性体是data runs
else {
printf("content in 0X80[nonresident]:\n");
printBuffer2(ptrData, attriBodySize);
printf("\n");
//存放VCN LCN
vector<VCN_LCN_SIZE>dataRuns;
//data runs 起始指针
BYTE *dataRunsStartOffset = tmpAttriDataIndex;
//data runs 总字节数
UINT32 attriBodySize = (pIndexOfMFTEntry + pComAttriHeader->ATTR_Size) - tmpAttriDataIndex;
//printf("attriBodySize is %u\n", attriBodySize);
//getchar();
UINT64 vcnCnt = 0;
while ((*dataRunsStartOffset) != 0X00 && dataRunsStartOffset - tmpAttriDataIndex < attriBodySize) {
UINT8 bytesClustersOfStdIndex = (*dataRunsStartOffset) & 0X0F, bytesCluOffsetOfStdIndex = (*dataRunsStartOffset >> 4) & 0X0F;
UINT32 totalBytes = bytesClustersOfStdIndex + bytesCluOffsetOfStdIndex;
//VCN.push_back(vcnCnt++);
UINT64 clustersOfStdIndex = 0;
INT64 cluOffsetOfStdIndex = 0;
//BYTE *ptrInDataRuns = (BYTE *)(&dataRuns);
memcpy(&clustersOfStdIndex, dataRunsStartOffset + 1, bytesClustersOfStdIndex);
//memcpy(&cluOffsetOfStdIndex, dataRunsStartOffset + 1 + bytesClustersOfStdIndex, bytesCluOffsetOfStdIndex);
cluOffsetOfStdIndex = Bytes2Int64(dataRunsStartOffset + 1 + bytesClustersOfStdIndex, bytesCluOffsetOfStdIndex);
//printf("Bytes2Int64 is %lld\n",Bytes2Int64(dataRunsStartOffset + 1 + bytesClustersOfStdIndex, bytesCluOffsetOfStdIndex));
if (vcnCnt == 0) {
dataRuns.push_back(VCN_LCN_SIZE(vcnCnt, cluOffsetOfStdIndex, clustersOfStdIndex));
}
else {
dataRuns.push_back(VCN_LCN_SIZE(vcnCnt, dataRuns[vcnCnt - 1].LCN + cluOffsetOfStdIndex, clustersOfStdIndex));
}
vcnCnt++;
dataRunsStartOffset += (totalBytes + 1);
}
printf("-->DATA Cluster Info\n");
for (int i = 0; i < dataRuns.size(); i++) {
printf("VCN, LCN, SIZE: %llu, %llu, %llu\n", dataRuns[i].VCN, dataRuns[i].LCN, dataRuns[i].SIZE);
}
//拿到了文件每一块的LCN和对应的簇数
//能够直接读取文件内容了
printf("-->End of DATA Cluster Info\n");
getchar();
}
break;
}
case 0x000000B0: {
break;
}
case 0x000000C0: {
break;
}
case 0x000000D0: {
break;
}
case 0x000000E0: {
break;
}
case 0x000000F0: {
break;
}
case 0x00000100: {
break;
}
default: {
finishFlag = TRUE;
break;
}
}
pIndexOfMFTEntry += pComAttriHeader->ATTR_Size;
if (finishFlag) { break; }
}
for (int i = 0; i < indexEntryOfDir.size(); i++) {
//
fprintf(fp,"WATCH :: IndexEntryOfDir -> %d:\n", i);
printBuffer(indexEntryOfDir[i], indexEntryOfDir[i]->SIE_IndexEntrySize);
fprintf(fp,"\n");
//printf("WATCH :: IndexEntryOfDir -> %d:\n", i);
//printBuffer2(indexEntryOfDir[i], indexEntryOfDir[i]->SIE_IndexEntrySize);
//printf("\n");
//getchar();
//dfsIndexEntry((PVOID)(indexEntryOfDir[i]), indexEntryOfDir[i]->SIE_IndexEntrySize, phyDriverNumber, volByteOffset, secPerCluster, mftOffset);
}
for (int i = 0; i < indexEntryOfDir.size(); i++) {
//
//printf("indexEntryOfDir of root:\n");
//printBuffer2(indexEntryOfDir[i], indexEntryOfDir[i]->SIE_IndexEntrySize);
//printf("\n");
//getchar();
fprintf(fp,"begin DFS in Dir\n");
fprintf(fp,"Index Entry Buff:\n");
printBuffer(indexEntryOfDir[i], indexEntryOfDir[i]->SIE_IndexEntrySize);
fprintf(fp,"\n");
printf("begin DFS in Dir\n");
//printf("Index Entry Buff:\n");
//printBuffer2(indexEntryOfDir[i], indexEntryOfDir[i]->SIE_IndexEntrySize);
printf("\n");
if (UINT64((indexEntryOfDir[i]->SIE_MFTReferNumber) & 0XFFFFFFFFFFFF) < 16) {
fprintf(fp,"SIE_MFTReferNumber < 16, continue\n");
//printf("SIE_MFTReferNumber < 16, continue\n");
}
else {
fprintf(fp,"SIE_MFTReferNumber >= 16, begin search\n");
//printf("SIE_MFTReferNumber >= 16, begin search\n");
dfsIndexEntry((PVOID)(indexEntryOfDir[i]), indexEntryOfDir[i]->SIE_IndexEntrySize, phyDriverNumber, volByteOffset, secPerCluster, mftOffset, currentFilePath);
}
//dfsIndexEntry((PVOID)(indexEntryOfDir[i]), indexEntryOfDir[i]->SIE_IndexEntrySize, phyDriverNumber, volByteOffset, secPerCluster, mftOffset);
}
indexEntryOfDir.clear();
visMftReferNum.clear();
//getchar();
}
//解析MFT表项
void resolveMFTEntry(PVOID MFTEntry, DWORD phyDriverNumber, UINT64 volByteOffset, UINT8 secPerCluster, UINT64 mftOffset) {//MFT表项 物理设备号 卷物理偏移(字节) 每个簇的扇区数 mft相对于该分区的偏移
//printBuffer(MFTEntry, MFTEntrySize);
//get MFTEntryHeader
pFILE_RECORD_HEADER MFTEntryHeader = (pFILE_RECORD_HEADER)malloc(sizeof(FILE_RECORD_HEADER));
memcpy(MFTEntryHeader, MFTEntry, sizeof(FILE_RECORD_HEADER));
fprintf(fp, "MFTEntry : BytesAllocated is %u\n", MFTEntryHeader->BytesAllocated);
fprintf(fp, "MFTEntry : BytesInUse is %u\n", MFTEntryHeader->BytesInUse);
fprintf(fp, "MFTEntry : MFTRecordNumber is %u\n", MFTEntryHeader->MFTRecordNumber);
UINT32 MFTEntryNumber = MFTEntryHeader->MFTRecordNumber;
//printBuffer2(MFTEntryHeader, sizeof(FILE_RECORD_HEADER));
UINT16 attriOffset = MFTEntryHeader->AttributeOffset;//第一个属性偏移
UINT8 *pointerInMFTEntry;
pointerInMFTEntry = (UINT8*)MFTEntry;
pointerInMFTEntry += attriOffset;
BYTE *pIndexOfMFTEntry = (BYTE*)MFTEntry;
pIndexOfMFTEntry += attriOffset;//pIndexOfMFTEntry偏移MFT头部大小 指向第一个属性头
UINT32 attriType, attriLen;
//BYTE ATTR_ResFlagAttri;
//get attribute
pCommonAttributeHeader pComAttriHeader = (pCommonAttributeHeader)malloc(sizeof(CommonAttributeHeader));
bool finishFlag = FALSE;
UINT32 attrCnt = 0;
while (TRUE) {
//pIndexOfMFTEntry 现在指向属性头, 后面会加上这个属性的总长 指向下一个属性头
memcpy(&attriType, pIndexOfMFTEntry, 4);//attri type
if (attriType == 0xFFFFFFFF) { fprintf(fp, "\nATTR_Type is 0xFFFFFFFF, break\n"); break; }
fprintf(fp, "\nattrCnt : %u\n", attrCnt++);
fprintf(fp, "##### AttributeHeader #####\n");
memset(pComAttriHeader, 0, sizeof(CommonAttributeHeader));
//属性头的通用部分
memcpy(pComAttriHeader, pIndexOfMFTEntry, sizeof(CommonAttributeHeader));
fprintf(fp, "ATTR_Type is 0X%X ATTR_Size is %d\n", pComAttriHeader->ATTR_Type, pComAttriHeader->ATTR_Size);
//如果属性总长>1024 先break
if (pComAttriHeader->ATTR_Size > 0x400) { fprintf(fp, "\attriLen is more than 1024, break\n"); break; }
fprintf(fp, "ATTR_NamOff is %hu ATTR_NamSz is %d", pComAttriHeader->ATTR_NamOff, pComAttriHeader->ATTR_NamSz);
//如果当前指针偏移大于MFT已用字节数 break
if ((pIndexOfMFTEntry - MFTEntry) > MFTEntryHeader->BytesInUse) {
fprintf(fp, "\nreach end of BytesInUse, break\n");
break;
}
//resolve attribute header
UINT16 attriHeaderSize = 0;
switch (pComAttriHeader->ATTR_ResFlag)//是否常驻属性
{
case BYTE(0x00): {
//get attribute header
pResidentAttributeHeader residentAttriHeader = (pResidentAttributeHeader)malloc(sizeof(ResidentAttributeHeader));
memcpy(residentAttriHeader, pIndexOfMFTEntry, sizeof(ResidentAttributeHeader));
fprintf(fp, "\n\n常驻属性\n\n");
//fprintf(fp, "ATTR_Size is %u\n", residentAttriHeader->ATTR_Size);
fprintf(fp, "ATTR_DatOff[属性头长度] is %hu\n", residentAttriHeader->ATTR_DatOff);
attriHeaderSize = residentAttriHeader->ATTR_DatOff;
UINT16 ResidentAttributeHeaderSize = residentAttriHeader->ATTR_DatOff;
residentAttriHeader = (pResidentAttributeHeader)realloc(residentAttriHeader, ResidentAttributeHeaderSize);
memcpy(residentAttriHeader, pIndexOfMFTEntry, ResidentAttributeHeaderSize);
//fprintf(fp, "ATTR_AttrNam[属性名] is %ls\n", residentAttriHeader->ATTR_AttrNam);
fprintf(fp, "ATTR_DatSz[属性体长度] is %u\n", residentAttriHeader->ATTR_DatSz);
fprintf(fp, "ATTR_Indx[属性索引] is %u\n", residentAttriHeader->ATTR_Indx);
break;
}
case BYTE(0x01): {
//get attribute header
fprintf(fp, "\n\n非常驻属性\n\n");
pNonResidentAttributeHeader nonResidentAttriHeader = (pNonResidentAttributeHeader)malloc(sizeof(NonResidentAttributeHeader));
memcpy(nonResidentAttriHeader, pIndexOfMFTEntry, sizeof(NonResidentAttributeHeader));
//fprintf(fp, "\n\n非常驻属性\nATTR_Type is 0x%X\n", nonResidentAttriHeader->ATTR_Type);
fprintf(fp, "ATTR_DatOff[属性头长度] is %hu\n", nonResidentAttriHeader->ATTR_DatOff);
attriHeaderSize = nonResidentAttriHeader->ATTR_DatOff;
UINT16 NonResidentAttributeHeaderSize = nonResidentAttriHeader->ATTR_DatOff;
nonResidentAttriHeader = (pNonResidentAttributeHeader)realloc(nonResidentAttriHeader, NonResidentAttributeHeaderSize);
memcpy(nonResidentAttriHeader, pIndexOfMFTEntry, NonResidentAttributeHeaderSize);
fprintf(fp, "ATTR_StartVCN[起始VCN] is %llu\n", nonResidentAttriHeader->ATTR_StartVCN);
fprintf(fp, "ATTR_EndVCN[终止VCN] is %llu\n", nonResidentAttriHeader->ATTR_EndVCN);
fprintf(fp, "ATTR_ValidSz[属性实际长度 is %llu\n", nonResidentAttriHeader->ATTR_ValidSz);
fprintf(fp, "ATTR_AllocSz[属性分配长度] is %llu\n", nonResidentAttriHeader->ATTR_AllocSz);
fprintf(fp, "ATTR_InitedSz[属性初始长度] is %llu\n", nonResidentAttriHeader->ATTR_InitedSz);
//fprintf(fp, "ATTR_AttrNam[属性名] is %ls\n", nonResidentAttriHeader->ATTR_AttrNam);
break;
}
default:
break;
}
fprintf(fp, "\n##### END of AttributeHeader #####\n");
//resolve attribute data
BYTE *tmpAttriDataIndex = pIndexOfMFTEntry;
//指向属性体
tmpAttriDataIndex += (attriHeaderSize);
//tmpAttriDataIndex指向属性体
switch (pComAttriHeader->ATTR_Type)
{
case 0x00000010: {//STANDARD_INFORMATION 10属性
pSTANDARD_INFORMATION stdInfo = (pSTANDARD_INFORMATION)malloc(sizeof(STANDARD_INFORMATION));
memcpy(stdInfo, tmpAttriDataIndex, sizeof(STANDARD_INFORMATION));
SYSTEMTIME sysTime;
FileTimeToSystemTime(&(stdInfo->SI_CreatTime), &sysTime);
fprintf(fp, "\n##### STANDARD_INFORMATION #####\n");
//printBuffer(stdInfo, sizeof(STANDARD_INFORMATION));
fprintf(fp, "\n");
fprintf(fp, "SI_CreatTime-wYear is %hu\n", sysTime.wYear);
fprintf(fp, "SI_CreatTime-wMonth is %hu\n", sysTime.wMonth);
fprintf(fp, "SI_CreatTime-wDay is %hu\n", sysTime.wDay);
fprintf(fp, "SI_CreatTime-wHour is %hu\n", sysTime.wHour);
fprintf(fp, "SI_CreatTime-wMinute is %hu\n", sysTime.wMinute);
fprintf(fp, "SI_CreatTime-wSecond is %hu\n", sysTime.wSecond);
fprintf(fp, "SI_AlterTime is %lld\n", stdInfo->SI_AlterTime);
fprintf(fp, "SI_DOSAttr is %d\n", stdInfo->SI_DOSAttr);
fprintf(fp, "SI_MFTChgTime is %lld\n", stdInfo->SI_MFTChgTime);
fprintf(fp, "\n");
fprintf(fp, "\n#####END of STANDARD_INFORMATION#####\n\n");
break;
}
case 0x00000020: {//ATTRIBUTE_LIST 20属性
break;
}
case 0x00000030: {//FILE_NAME 可能不止一个
pFILE_NAME fileNameInfo = (pFILE_NAME)malloc(sizeof(FILE_NAME));
memcpy(fileNameInfo, tmpAttriDataIndex, sizeof(FILE_NAME));
fprintf(fp, "\n##### FILE_NAME #####\n");
//SYSTEMTIME sysTime;
//FileTimeToSystemTime(&(fileNameInfo->FN_AlterTime), &sysTime);
//fprintf(fp, "FN_AlterTime-wYear is %hu\n", sysTime.wYear);
//fprintf(fp, "FN_AlterTime-wMonth is %hu\n", sysTime.wMonth);
//fprintf(fp, "FN_AlterTime-wDay is %hu\n", sysTime.wDay);
//fprintf(fp, "FN_AlterTime-wHour is %hu\n", sysTime.wHour);
//fprintf(fp, "FN_AlterTime-wMinute is %hu\n", sysTime.wMinute);
//fprintf(fp, "FN_NameSz is %hu\n", 0xFFFF & (fileNameInfo->FN_NameSz));
//fprintf(fp, "FN_AllocSz is %llu\n", fileNameInfo->FN_AllocSz);
//fprintf(fp, "FN_ValidSz is %llu\n", fileNameInfo->FN_ValidSz);
//get file name
UINT32 fileNameLen = UINT32(0xFFFF & (fileNameInfo->FN_NameSz) + 1) << 1;
WCHAR *fileName = (WCHAR*)malloc(fileNameLen);
memset(fileName, 0, fileNameLen);
memcpy(fileName, tmpAttriDataIndex + sizeof(FILE_NAME), fileNameLen - 2);
fprintf(fp, "FILENAME is %ls\n", fileName);
fprintf(fp, "FN_NameSz is %d\n", fileNameInfo->FN_NameSz);
fprintf(fp, "FN_NamSpace is %d\n", fileNameInfo->FN_NamSpace);
fprintf(fp, "FILENAME is %ls\n", fileName);
fprintf(fp, "FN_ParentFR[父目录的MFT号] is %llu\n", (fileNameInfo->FN_ParentFR) & 0XFFFFFFFFFFFF);
//getchar();
fprintf(fp, "\n#####END of FILE_NAME#####\n\n");
break;
}
case 0x00000040: {//VOLUME_VERSION OBJECT_ID
break;
}
case 0x00000050: {//SECURITY_DESCRIPTOR
break;
}
case 0x00000060: {//VOLUME_NAME
break;
}
case 0x00000070: {//VOLUME_INFORMATION
break;
}
case 0x00000080: {//DATA
break;
}
case 0x00000090: {//INDEX_ROOT 索引根
//pINDEX_ROOT pIndexRoot = (INDEX_ROOT*)malloc(sizeof(INDEX_ROOT));
//memcpy(pIndexRoot, tmpAttriDataIndex, sizeof(INDEX_ROOT));
//fprintf(fp, "\n##### INDEX_ROOT #####\n");
//fprintf(fp, "IR_EntrySz[目录项的大小,一般是一个簇] is %u\n", pIndexRoot->IR_EntrySz);
//fprintf(fp, "IR_ClusPerRec[目录项占用的簇数,一般是一个] is %u\n", pIndexRoot->IR_ClusPerRec);
//fprintf(fp, "IH_TalSzOfEntries[索引根和紧随其后的索引项的大小] is %u\n", pIndexRoot->IH.IH_TalSzOfEntries);
//fprintf(fp, "IH_EntryOff[第一个索引项的偏移] is %u\n", pIndexRoot->IH.IH_EntryOff);
////0X90属性的实际大小
//UINT32 attri90Size = sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) + pIndexRoot->IH.IH_TalSzOfEntries;
//fprintf(fp, "\n##### END of INDEX_ROOT #####\n");
break;
}
case 0x000000A0: {//INDEX_ALLOCATION
//fprintf(fp, "\n##### INDEX_ALLOCATION #####\n");
////A0属性体
//pINDEX_ALLOCATION pIndexAlloc = (pINDEX_ALLOCATION)malloc(sizeof(INDEX_ALLOCATION));
//memcpy(pIndexAlloc, tmpAttriDataIndex, sizeof(INDEX_ALLOCATION));
//fprintf(fp, "\n##### END of INDEX_ALLOCATION #####\n");
break;
}
case 0x000000B0: {//BITMAP
break;
}
case 0x000000C0: {//symbol_LINK REPARSE_POINT
break;
}
case 0x000000D0: {//EA_INFORMATION
break;
}
case 0x000000E0: {//EA
break;
}
case 0x000000F0: {//PROPERTY_SET
break;
}
case 0x00000100: {//LOGGED_UNTILITY_STREAM
break;
}
default: {
finishFlag = TRUE;
break;
}
}
pIndexOfMFTEntry += pComAttriHeader->ATTR_Size;
if (finishFlag) { break; }
}
}
//解析ntfs DBR扇区
void resolveNTFSDBRSector(DWORD phyDriverNumber, UINT64 startSecOffset, pNTFSDBR DBRBuf) {//物理磁盘设备号,DBR物理偏移(Byte),DBR扇区数据
fprintf(fp, "bytePerSector is %hu\n", DBRBuf->bytePerSector);
fprintf(fp, "secPerCluster is %hu\n", DBRBuf->secPerCluster);
fprintf(fp, "totalSectors is %llu\n", DBRBuf->totalSectors);
fprintf(fp, "MFT offset(logical cluster number) is %llu\n", DBRBuf->MFT);
printf("MFT offset(logical cluster number) is %llu\n", DBRBuf->MFT);
//ntfs mft offset(byte)
UINT64 MFToffset = UINT64((DBRBuf->MFT)*(DBRBuf->secPerCluster)*(DBRBuf->bytePerSector)) + startSecOffset;
fprintf(fp, "MFTMirror offset(logical cluster number) is %llu\n", DBRBuf->MFTMirror);
fprintf(fp, "\n");
//直接读取MFT第五项 根目录项
UINT64 MFTEntryOffset = UINT64(5 * 1024 + MFToffset);
fprintf(fp, "MFTEntry[5] Offset is %llu\n", MFTEntryOffset);
PVOID tmpMFTEntryBuf = malloc((UINT)MFTEntrySize);
memset(tmpMFTEntryBuf, 0, (UINT)MFTEntrySize);
ReadDisk(phyDriverNumber, MFTEntryOffset, MFTEntrySize, tmpMFTEntryBuf);
//路径
WCHAR filePath[2048] = { 0 };
//这里开始深搜目录树
parseMFTEntry(tmpMFTEntryBuf, MFTEntrySize, phyDriverNumber, startSecOffset,
DBRBuf->secPerCluster, UINT64((DBRBuf->MFT)*(DBRBuf->secPerCluster)*(DBRBuf->bytePerSector)), filePath);
return;
//这里是顺序读取MFT 能读到被删的文件信息
//读取MFT表项
UINT64 MFTEntryCnt = 0;
UINT32 mftEntryFlag;
printf("Analyzing MFT......\n");
printf("MFTEntryCnt");
while (TRUE) {
//while (MFTEntryCnt<128) {
fprintf(fp, "\n\n########### MFT ENTRY ##########\n");
fprintf(fp, "MFTEntryCnt is %llu\n", MFTEntryCnt);
printf("%llu\t", MFTEntryCnt);
//PVOID tmpMFTEntryBuf = malloc((UINT)MFTEntrySize);
//get MFTEntry
UINT64 MFTEntryOffset = UINT64((MFTEntryCnt++) * 1024 + MFToffset);
fprintf(fp, "MFTEntryOffset is %llu\n", MFTEntryOffset);
PVOID tmpMFTEntryBuf = malloc((UINT)MFTEntrySize);
memset(tmpMFTEntryBuf, 0, (UINT)MFTEntrySize);
ReadDisk(phyDriverNumber, MFTEntryOffset, MFTEntrySize, tmpMFTEntryBuf);
//解析MFT表项
mftEntryFlag = 0X00;
memcpy(&mftEntryFlag, tmpMFTEntryBuf, (UINT)4);
if (mftEntryFlag != MFTEntryFlag) { fprintf(fp, "\nMiss MFTEntryFlag, break\n"); break; }
//printBuffer(tmpMFTEntryBuf, MFTEntrySize);
resolveMFTEntry(tmpMFTEntryBuf, phyDriverNumber, startSecOffset, DBRBuf->secPerCluster, UINT64((DBRBuf->MFT)*(DBRBuf->secPerCluster)*(DBRBuf->bytePerSector)));
fprintf(fp, "\n########### END MFT ENTRY ##########\n");
}
printf("\n");
}
void run() {
fp = fopen("output.txt", "w");
vector<PHY_INFO>driverInfos = getPhyDriverNumber();
pMBRSector MBRs[64];
short int MBRcnt = 0;
for (int i = 0; i < driverInfos.size(); i++) {
DWORD phyVolCnt = 0;
//phyVolCnt = 0;
fprintf(fp, "### NOW IN PHYDRIVER - %d ###\n", driverInfos[i].number);
printf("### NOW IN PHYDRIVER - %d ###\n", driverInfos[i].number);
//MBRs[MBRcnt] = (pMBRSector)malloc(sizeof(MBRSector));
//read MBR sector
PVOID tmpMBRBuf = malloc(UINT32(MBRSectorSize));
ReadDisk(driverInfos[i].number, 0, MBRSectorSize, tmpMBRBuf);
MBRs[MBRcnt] = (pMBRSector)tmpMBRBuf;
//for test
fprintf(fp, "MBR in physicalDriveNumber%lu:\n", driverInfos[i].number);
printf("MBR in physicalDriveNumber%lu:\n", driverInfos[i].number);
printBuffer(tmpMBRBuf, MBRSectorSize);
printBuffer2(tmpMBRBuf, MBRSectorSize);
fprintf(fp, "\n");
int PTEntryCnt = 0;
while (PTEntryCnt < 4) {
fprintf(fp, "PartitionTableEntry%d:\n", PTEntryCnt);
fprintf(fp, "bootSignature(引导标志) is %+02X\n", MBRs[MBRcnt]->ptEntrys[PTEntryCnt].bootSignature);
fprintf(fp, "systemSignature(分区类型标志) is %+02X\n", MBRs[MBRcnt]->ptEntrys[PTEntryCnt].systemSignature);
fprintf(fp, "startSectorNo is %+08X\n", MBRs[MBRcnt]->ptEntrys[PTEntryCnt].startSectorNo);
//printf("startSectorNo is %+08X\n", MBRs[MBRcnt - 1]->ptEntrys[PTEntryCnt].startSectorNo);
fprintf(fp, "totalSectorsNum is %+08X\n", MBRs[MBRcnt]->ptEntrys[PTEntryCnt].totalSectorsNum);
fprintf(fp, "\n");
//PTEntryCnt不足四个
if (MBRs[MBRcnt]->ptEntrys[PTEntryCnt].startSectorNo == 0x00) {
break;
}
//先跳过活动分区
if (MBRs[MBRcnt]->ptEntrys[PTEntryCnt].bootSignature == 0X80) {
printf("\n\n\nVolume letter is %c\n\n\n", driverInfos[i].vols[phyVolCnt]);
printf("\n\n活动分区, leap it\n");
fprintf(fp, "\n\n活动分区, leap it\n");
PTEntryCnt++;
phyVolCnt++;
getchar();
continue;
}
//read DBR or EBR sector
PVOID readBuf = malloc(UINT32(SectorSize));
UINT64 startSecOffset = UINT64(MBRs[MBRcnt]->ptEntrys[PTEntryCnt].startSectorNo);
startSecOffset *= UINT64(SectorSize);
fprintf(fp, "startSecOffset is %lld\n", startSecOffset);
ReadDisk(driverInfos[i].number, startSecOffset, SectorSize, readBuf);
//判断分区类型
switch (MBRs[MBRcnt]->ptEntrys[PTEntryCnt].systemSignature)
{
case BYTE(0x0C): {//FAT32
printf("\n\n\nVolume letter is %c\n\n\n", driverInfos[i].vols[phyVolCnt++]);
getchar();
fprintf(fp, "FAT32 DBR sector is\n");
//printf("FAT32 DBR sector, continue\n");
printBuffer(readBuf, SectorSize);
fprintf(fp, "\n");
pFAT32_DBR DBRBuf = (pFAT32_DBR)readBuf;
//sizeof(FAT32_DBR);
fprintf(fp, "Sectors_per_Cluster is %hu\n", DBRBuf->BPB.Sectors_per_Cluster);
fprintf(fp, "FATs is %hu\n", DBRBuf->BPB.FATs);
fprintf(fp, "FATs is %u\n", DBRBuf->BPB.Large_Sector);
fprintf(fp, "System_ID is %llu\n", DBRBuf->Extend_BPB.System_ID);
fprintf(fp, "\n");
printf("resolve fat32 volume\n");
//每扇区字节数
UINT16 bytesPerSector = DBRBuf->BPB.Bytes_per_Sector;
//每簇扇区数
UINT8 sectorsPerCluster = DBRBuf->BPB.Sectors_per_Cluster;
//保留扇区数
UINT16 reservedSectorNum = DBRBuf->BPB.Reserved_Sector;
//fat表占用的扇区数
UINT32 fat32Sectors = DBRBuf->BPB.Fat32_Sector.Sectors_per_FAT_FAT32;
//根目录簇号
UINT32 rootCluster = DBRBuf->BPB.Fat32_Sector.Root_Cluster_Number;
//定位根目录 保留扇区数+每个FAT表占用扇区数*2+(根目录簇号-2)*每簇扇区数
UINT64 rootSectorOffset = reservedSectorNum + fat32Sectors * 2 + (rootCluster - 2)*sectorsPerCluster;
printf("rootSectorOffset is %llu\n", rootSectorOffset);
getchar();
UINT64 rootSectorByteOffset = rootSectorOffset * bytesPerSector + startSecOffset;
PVOID tmpBuff = malloc(SectorSize);
ReadDisk(driverInfos[i].number, rootSectorByteOffset, SectorSize, tmpBuff);
printBuffer2(tmpBuff, SectorSize);
getchar();
break;
}
case BYTE(0x07): {//ntfs
printf("\n\n\nVolume letter is %c\n\n\n", driverInfos[i].vols[phyVolCnt++]);
getchar();
fprintf(fp, "ntfs DBR sector is\n");
printf("find ntfs DBR sector\n");
printBuffer(readBuf, SectorSize);
fprintf(fp, "\n");
pNTFSDBR DBRBuf = (pNTFSDBR)readBuf;
//解析ntfs dbr
resolveNTFSDBRSector(driverInfos[i].number, startSecOffset, DBRBuf);
break;
}
case BYTE(0x0F): {//Extended
fprintf(fp, "EBR sector is\n");
printBuffer(readBuf, SectorSize);
fprintf(fp, "\n");
pMBRSector EBRBuf = (pMBRSector)readBuf;
bool isEbrFinish = FALSE;
while (TRUE) {
if (!(EBRBuf->ptEntrys[1].totalSectorsNum)) { isEbrFinish = TRUE; }
printf("find EBR sector, continue\n");
fprintf(fp, "this volume : logical startSectorNo is %+08X\n", EBRBuf->ptEntrys[0].startSectorNo);
fprintf(fp, "this volume : totalSectorsNum is %+08X\n", EBRBuf->ptEntrys[0].totalSectorsNum);
fprintf(fp, "next volume : logical startSectorNo is %+08X\n", EBRBuf->ptEntrys[1].startSectorNo);
//本分区DBR的物理偏移
UINT64 thisVolPhyStartSecOffset = UINT64(MBRs[MBRcnt]->ptEntrys[PTEntryCnt].startSectorNo)
+ UINT64(EBRBuf->ptEntrys[0].startSectorNo);
thisVolPhyStartSecOffset *= UINT64(SectorSize);
//下一个EBR的物理偏移
UINT64 nextVolPhyStartSecOffset = UINT64(MBRs[MBRcnt]->ptEntrys[PTEntryCnt].startSectorNo)
+ UINT64(EBRBuf->ptEntrys[1].startSectorNo);
nextVolPhyStartSecOffset *= UINT64(SectorSize);
printf("nextVolPhyStartSecOffset is %llu\n", nextVolPhyStartSecOffset);
getchar();
//读取本分区的DBR
PVOID tempDBRBuf = malloc(int(DBRSectorSize));
ReadDisk(driverInfos[i].number, thisVolPhyStartSecOffset, DBRSectorSize, tempDBRBuf);
fprintf(fp, "\nDBR after EBR:\n");
printBuffer(tempDBRBuf, DBRSectorSize);
fprintf(fp, "\n");
switch (EBRBuf->ptEntrys[0].systemSignature)
{
case BYTE(0x07): {//ntfs
printf("\n\n\nVolume letter is %c\n\n\n", driverInfos[i].vols[phyVolCnt++]);
getchar();
printf("find ntfs DBR sector\n");
pNTFSDBR DBRBuf = (pNTFSDBR)tempDBRBuf;
//解析ntfs dbr
resolveNTFSDBRSector(driverInfos[i].number, thisVolPhyStartSecOffset, DBRBuf);
break;
}
case BYTE(0x0C): {//fat32
printf("\n\n\nVolume letter is %c\n\n\n", driverInfos[i].vols[phyVolCnt++]);
getchar();
printf("FAT32 DBR sector, continue\n");
break;
}
default:
break;
}
if (isEbrFinish) { break; }
//读取下一个EBR
PVOID tempEBRBuf = malloc(int(EBRSectorSize));
ReadDisk(driverInfos[i].number, nextVolPhyStartSecOffset, EBRSectorSize, tempEBRBuf);
EBRBuf = pMBRSector(tempEBRBuf);
fprintf(fp, "\nnext EBR sector is\n");
printBuffer(tempEBRBuf, EBRSectorSize);
fprintf(fp, "\n");
}
break;
}
default:
break;
}
PTEntryCnt++;
fprintf(fp, "\n");
}
MBRcnt++;
fprintf(fp, "\n");
}
fclose(fp);
}
//判断卷是否属于USB
bool isUsbDev(TCHAR volumePath[]) {
HANDLE deviceHandle = CreateFile(volumePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
STORAGE_PROPERTY_QUERY query;
memset(&query, 0, sizeof(query));
DWORD bytes;
STORAGE_DEVICE_DESCRIPTOR devd;
//STORAGE_BUS_TYPE用于记录结构,类型要初始化
STORAGE_BUS_TYPE busType = BusTypeUnknown;
if (DeviceIoControl(deviceHandle, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &devd, sizeof(devd), &bytes, NULL)) {
busType = devd.BusType;
}
CloseHandle(deviceHandle);
return busType == BusTypeUsb;
}
//发现USB设备
bool findUsbDev() {
bool ret = false;
DWORD dwSize = GetLogicalDriveStrings(0, NULL);
char* drivers = (char*)malloc(dwSize * 2);
DWORD dwRet = GetLogicalDriveStrings(dwSize, (LPWSTR)drivers);
wchar_t* lp = (wchar_t*)drivers;//所有逻辑驱动器的根驱动器路径 用0隔开
DWORD tmpNum = 0;
while (*lp) {
CHAR path[MAX_PATH];
sprintf(path, "\\\\.\\%c:", lp[0]);
if (isUsbDev(charToWCHAR(path))) {
//printf("find usb\n");
ret = true;
break;
}
lp += (wcslen(lp) + 1);//下一个根驱动器路径
}
return ret;
}
void test() {
}
int _tmain(int argc, TCHAR *argv[], TCHAR *env[]) {
setlocale(LC_ALL, "chs");
//test();
run();
system("pause");
return 0;
}
接下来是结构定义:
//ntfs.h
#pragma once
#pragma pack(1)
#pragma warning(disable : 4996)
#include "stdafx.h"
#define MBRlen 446
#define minReadSize 512
#define MFTEntrySize 1024
#define SectorSize 512
#define DBRSectorSize 512
#define EBRSectorSize 512
#define MBRSectorSize 512
#define MFTEntryFlag 0x454C4946 //FILE
//DPT表项
typedef struct _PartTableEntry {
BYTE bootSignature;//引导标志
BYTE startHead;//CHS寻址方式,起始磁头
BYTE startSector;//起始扇区,本字节低六位
BYTE startCylinder;//起始磁道(柱面),startSector高二位和本字节
BYTE systemSignature;//分区类型标志
BYTE endHead;//终止磁头
BYTE endSector;//终止扇区
BYTE endCylinder;//终止磁道
unsigned int startSectorNo;//LBA寻址,起始扇区号
unsigned int totalSectorsNum;//该分区扇区总数
}PartTableEntry, *pPartTableEntry;
//MBR扇区
typedef struct _MBRSector {
BYTE MBR[MBRlen];
PartTableEntry ptEntrys[4];
BYTE endSignature[2];
}MBRSector, *pMBRSector;
//NTFS DBR扇区
typedef struct _NTFSDBR {
BYTE JMP[3]; //跳转指令
BYTE FsID[8]; //文件系统ID
unsigned short int bytePerSector; //每扇区字节数
BYTE secPerCluster; //每簇扇区数
BYTE reservedBytes[2]; //2个保留字节
BYTE zeroBytes[3]; //三个0字节
BYTE unusedBytes1[2]; //2个未用字节
BYTE mediaType;//媒体类型
BYTE unusedBytes2[2]; //2个未用字节
unsigned short int secPerTrack; //每磁道扇区数
unsigned short int Heads; //磁头数
unsigned int 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]; //未用字节
BYTE volumeSerialID64[8]; //卷序列号
unsigned int checkSum; //校验和
BYTE bootCode[426]; //引导代码
BYTE endSignature[2]; //结束标志
}NTFSDBR, *pNTFSDBR;
//MFT表项的结构
// 文件记录头
typedef struct _FILE_RECORD_HEADER
{
/*+0x00*/ BYTE Type[4]; // 固定值'FILE'
/*+0x04*/ UINT16 USNOffset; // 更新序列号偏移, 与操作系统有关
/*+0x06*/ UINT16 USNCount; // 固定列表大小Size in words of Update Sequence Number & Array (S)
/*+0x08*/ UINT64 Lsn; // 日志文件序列号(LSN)
/*+0x10*/ UINT16 SequenceNumber; // 序列号(用于记录文件被反复使用的次数)
/*+0x12*/ UINT16 LinkCount; // 硬连接数
/*+0x14*/ UINT16 AttributeOffset; // 第一个属性偏移
/*+0x16*/ UINT16 Flags; // flags, 00表示删除文件,01表示正常文件,02表示删除目录,03表示正常目录
/*+0x18*/ UINT32 BytesInUse; // 文件记录实时大小(字节) 当前MFT表项长度,到FFFFFF的长度+4
/*+0x1C*/ UINT32 BytesAllocated; // 文件记录分配大小(字节)
/*+0x20*/ UINT64 BaseFileRecord; // = 0 基础文件记录 File reference to the base FILE record
/*+0x28*/ UINT16 NextAttributeNumber; // 下一个自由ID号
/*+0x2A*/ UINT16 Pading; // 边界
/*+0x2C*/ UINT32 MFTRecordNumber; // windows xp中使用,本MFT记录号
/*+0x30*/ UINT16 USN; // 更新序列号
/*+0x32*/ BYTE UpdateArray[0]; // 更新数组
} FILE_RECORD_HEADER, *pFILE_RECORD_HEADER;
//常驻属性和非常驻属性的公用部分
typedef struct _CommonAttributeHeader {
UINT32 ATTR_Type; //属性类型
UINT32 ATTR_Size; //属性头和属性体的总长度
BYTE ATTR_ResFlag; //是否是常驻属性(0常驻 1非常驻)
BYTE ATTR_NamSz; //属性名的长度
UINT16 ATTR_NamOff; //属性名的偏移 相对于属性头
UINT16 ATTR_Flags; //标志(0x0001压缩 0x4000加密 0x8000稀疏)
UINT16 ATTR_Id; //属性唯一ID
}CommonAttributeHeader,*pCommonAttributeHeader;
//常驻属性 属性头
typedef struct _ResidentAttributeHeader {
CommonAttributeHeader ATTR_Common;
UINT32 ATTR_DatSz; //属性数据的长度
UINT16 ATTR_DatOff; //属性数据相对于属性头的偏移
BYTE ATTR_Indx; //索引
BYTE ATTR_Resvd; //保留
BYTE ATTR_AttrNam[0];//属性名,Unicode,结尾无0
}ResidentAttributeHeader, *pResidentAttributeHeader;
//非常驻属性 属性头
typedef struct _NonResidentAttributeHeader {
CommonAttributeHeader ATTR_Common;
UINT64 ATTR_StartVCN; //本属性中数据流起始虚拟簇号
UINT64 ATTR_EndVCN; //本属性中数据流终止虚拟簇号
UINT16 ATTR_DatOff; //簇流列表相对于属性头的偏移
UINT16 ATTR_CmpSz; //压缩单位 2的N次方
UINT32 ATTR_Resvd;
UINT64 ATTR_AllocSz; //属性分配的大小
UINT64 ATTR_ValidSz; //属性的实际大小
UINT64 ATTR_InitedSz; //属性的初始大小
BYTE ATTR_AttrNam[0];
}NonResidentAttributeHeader, *pNonResidentAttributeHeader;
/*下面是索引结构的定义*/
//标准索引头的结构
typedef struct _STD_INDEX_HEADER {
BYTE SIH_Flag[4]; //固定值 "INDX"
UINT16 SIH_USNOffset;//更新序列号偏移
UINT16 SIH_USNSize;//更新序列号和更新数组大小
UINT64 SIH_Lsn; // 日志文件序列号(LSN)
UINT64 SIH_IndexCacheVCN;//本索引缓冲区在索引分配中的VCN
UINT32 SIH_IndexEntryOffset;//索引项的偏移 相对于当前位置
UINT32 SIH_IndexEntrySize;//索引项的大小
UINT32 SIH_IndexEntryAllocSize;//索引项分配的大小
UINT8 SIH_HasLeafNode;//置一 表示有子节点
BYTE SIH_Fill[3];//填充
UINT16 SIH_USN;//更新序列号
BYTE SIH_USNArray[0];//更新序列数组
}STD_INDEX_HEADER,*pSTD_INDEX_HEADER;
//标准索引项的结构
typedef struct _STD_INDEX_ENTRY {
UINT64 SIE_MFTReferNumber;//文件的MFT参考号
UINT16 SIE_IndexEntrySize;//索引项的大小
UINT16 SIE_FileNameAttriBodySize;//文件名属性体的大小
UINT16 SIE_IndexFlag;//索引标志
BYTE SIE_Fill[2];//填充
UINT64 SIE_FatherDirMFTReferNumber;//父目录MFT文件参考号
FILETIME SIE_CreatTime;//文件创建时间
FILETIME SIE_AlterTime;//文件最后修改时间
FILETIME SIE_MFTChgTime;//文件记录最后修改时间
FILETIME SIE_ReadTime;//文件最后访问时间
UINT64 SIE_FileAllocSize;//文件分配大小
UINT64 SIE_FileRealSize;//文件实际大小
UINT64 SIE_FileFlag;//文件标志
UINT8 SIE_FileNameSize;//文件名长度
UINT8 SIE_FileNamespace;//文件命名空间
BYTE SIE_FileNameAndFill[0];//文件名和填充
}STD_INDEX_ENTRY,*pSTD_INDEX_ENTRY;
/****下面定义的均是属性体的结构 不包括属性头****/
//STANDARD_INFORMATION 0X10属性体
/*
SI_DOSAttr取值:
0x0001 只读
0x0002 隐藏
0x0004 系统
0x0020 归档
0x0040 设备
0x0080 常规
0x0100 临时文件
0x0200 稀疏文件
0x0400 重解析点
0x0800 压缩
0x1000 离线
0x2000 无内容索引
0x4000 加密
*/
typedef struct _STANDARD_INFORMATION {
FILETIME SI_CreatTime;//创建时间
FILETIME SI_AlterTime;//最后修改时间
FILETIME SI_MFTChgTime;//文件的MFT修改的时间
FILETIME SI_ReadTime;//最后访问时间
UINT32 SI_DOSAttr;//DOS文件属性
UINT32 SI_MaxVer;//文件可用的最大版本号 0表示禁用
UINT32 SI_Ver;//文件版本号 若最大版本号为0 则值为0
UINT32 SI_ClassId;//??
//UINT64 SI_OwnerId;//文件拥有者ID
//UINT64 SI_SecurityId;//安全ID
//UINT64 SI_QuotaCharged;//文件最大可使用的空间配额 0表示无限制
//UINT64 SI_USN;//文件最后一次更新的记录号
#if 0
uint32 QuotaId;
uint32 SecurityId;
uint64 QuotaCharge;
USN Usn;
#endif
}STANDARD_INFORMATION,*pSTANDARD_INFORMATION;
//ATTRIBUTE_LIST 0X20属性体
typedef struct _ATTRIBUTE_LIST {
UINT32 AL_RD_Type;
UINT16 AL_RD_Len;
BYTE AL_RD_NamLen;
BYTE AL_RD_NamOff;
UINT64 AL_RD_StartVCN;//本属性中数据流开始的簇号
UINT64 AL_RD_BaseFRS;/*本属性记录所属的MFT记录的记录号
注意:该值的低6字节是MFT记录号,高2字节是该MFT记录的序列号*/
UINT16 AL_RD_AttrId;
//BYTE AL_RD_Name[0];
UINT16 AlignmentOrReserved[3];
}ATTRIBUTE_LIST,*pATTRIBUTE_LIST;
//FILE_NAME 0X30属性体
typedef struct _FILE_NAME {
UINT64 FN_ParentFR; /*父目录的MFT记录的记录索引。
注意:该值的低6字节是MFT记录号,高2字节是该MFT记录的序列号*/
FILETIME FN_CreatTime;
FILETIME FN_AlterTime;
FILETIME FN_MFTChg;
FILETIME FN_ReadTime;
UINT64 FN_AllocSz;
UINT64 FN_ValidSz;//文件的真实尺寸
UINT32 FN_DOSAttr;//DOS文件属性
UINT32 FN_EA_Reparse;//扩展属性与链接
BYTE FN_NameSz;//文件名的字符数
BYTE FN_NamSpace;/*命名空间,该值可为以下值中的任意一个
0:POSIX 可以使用除NULL和分隔符“/”之外的所有UNICODE字符,最大可以使用255个字符。注意:“:”是合法字符,但Windows不允许使用。
1:Win32 Win32是POSIX的一个子集,不区分大小写,可以使用除““”、“*”、“?”、“:”、“/”、“<”、“>”、“/”、“|”之外的任意UNICODE字符,但名字不能以“.”或空格结尾。
2:DOS DOS命名空间是Win32的子集,只支持ASCII码大于空格的8BIT大写字符并且不支持以下字符““”、“*”、“?”、“:”、“/”、“<”、“>”、“/”、“|”、“+”、“,”、“;”、“=”;同时名字必须按以下格式命名:1~8个字符,然后是“.”,然后再是1~3个字符。
3:Win32&DOS 这个命名空间意味着Win32和DOS文件名都存放在同一个文件名属性中。*/
BYTE FN_FileName[0];
}FILE_NAME,*pFILE_NAME;
//VOLUME_VERSION
typedef struct _VOLUME_VERSION {
//??
}VOLUME_VERSION,*pVOLUME_VERSION;
//OBJECT_ID 0X40属性体
typedef struct _OBJECT_ID {
BYTE OID_ObjID[16];//文件的GUID
BYTE OID_BirthVolID[16];//文件建立时所在卷的ID
BYTE OID_BirthID[16];//文件的原始ID
BYTE OID_DomainID[16];//对象所创建时所在域的ID
}OBJECT_ID, *pOBJECT_ID;
//SECRUITY_DESCRIPTOR 0X50属性体
typedef struct _SECRUITY_DESCRIPTOR {
//??
}SECRUITY_DESCRIPTOR,*pSECRUITY_DESCRIPTOR;
//VOLUME_NAME 0X60属性体
typedef struct _VOLUME_NAME {
BYTE VN_Name[0];
}VOLUME_NAME,*pVOLUME_NAME;
//VOLUME_INFORMATION 0X70属性体
typedef struct _VOLUME_INFORMATION{
UINT64 VI_Resvd;
BYTE VI_MajVer;//卷主版本号
BYTE VI_MinVer;//卷子版本号
UINT16 VI_Flags;/*标志位,可以是以下各值组合
0x0001 脏位,当该值被设置时Windows将会在下次启动时运行chkdsk/F命令。
0x0002 日志文件改变尺寸
0x0004 卷挂接时升级
0x0008 由Windows NT 4挂接
0x0010 启动时删除USN
0x0020 修复过的ID
0x8000 被chkdsk修改过*/
}VOLUME_INFORMATION,*pVOLUME_INFORMATION;
//DATA 0X80属性体
typedef struct _DATA {
//??
///*+0x10*/ UINT64 StartVcn; // LowVcn 起始VCN 起始簇号
///*+0x18*/ UINT64 LastVcn; // HighVcn 结束VCN 结束簇号
///*+0x20*/ UINT16 RunArrayOffset; // 数据运行的偏移
///*+0x22*/ UINT16 CompressionUnit; // 压缩引擎
///*+0x24*/ UINT32 Padding0; // 填充
///*+0x28*/ UINT32 IndexedFlag; // 为属性值分配大小(按分配的簇的字节数计算)
///*+0x30*/ UINT64 AllocatedSize; // 属性值实际大小
///*+0x38*/ UINT64 DataSize; // 属性值压缩大小
///*+0x40*/ UINT64 InitializedSize; // 实际数据大小
///*+0x48*/ UINT64 CompressedSize; // 压缩后大小
BYTE D_data[0];
}DATA,*pDATA;
typedef struct _INDEX_ENTRY {
UINT64 IE_MftReferNumber;/*该文件的MFT参考号。注意:该值的低6字节是MFT记录号,高2字节是该MFT记录的序列号*/
UINT16 IE_Size;//索引项的大小 相对于索引项开始的偏移量
UINT16 IE_FileNAmeAttriBodySize;//文件名属性体的大小
UINT16 IE_Flags;/*标志。该值可能是以下值之一:
0x00 普通文件项
0x01 有子项
0x02 当前项是最后一个目录项
在读取索引项数据时应该首先检查该成员的值以确定当前项的类型*/
UINT16 IE_Fill;//填充 无意义
UINT64 IE_FatherDirMftReferNumber;//父目录的MFT文件参考号
FILETIME IE_CreatTime;//文件创建时间
FILETIME IE_AlterTime;//文件最后修改时间
FILETIME IE_MFTChgTime;//文件记录最后修改时间
FILETIME IE_ReadTime;//文件最后访问时间
UINT64 IE_FileAllocSize;//文件分配大小
UINT64 IE_FileRealSize;//文件实际大小
UINT64 IE_FileFlag;//文件标志
UINT8 IE_FileNameSize;//文件名长度
UINT8 IE_FileNamespace;//文件命名空间
BYTE IE_FileNameAndFill[0];//文件名和填充
//BYTE IE_Stream[0];//目录项数据,结构与文件名属性的数据相同
//UINT64 IE_SubNodeFR;//子项的记录索引。该值的低6字节是MFT记录号,高2字节是该MFT记录的序列号
}INDEX_ENTRY,*pINDEX_ENTRY;
typedef struct _INDEX_HEADER {
UINT32 IH_EntryOff;//第一个目录项的偏移
UINT32 IH_TalSzOfEntries;//目录项的总尺寸(包括索引头和下面的索引项)
UINT32 IH_AllocSize;//目录项分配的尺寸
BYTE IH_Flags;/*标志位,此值可能是以下和值之一:
0x00 小目录(数据存放在根节点的数据区中)
0x01 大目录(需要目录项存储区和索引项位图)*/
BYTE IH_Resvd[3];
}INDEX_HEADER,*pINDEX_HEADER;
//INDEX_ROOT 0X90属性体
typedef struct _INDEX_ROOT {
//索引根
UINT32 IR_AttrType;//属性的类型
UINT32 IR_ColRule;//整理规则
UINT32 IR_EntrySz;//目录项分配尺寸
BYTE IR_ClusPerRec;//每个目录项占用的簇数
BYTE IR_Resvd[3];
//索引头
INDEX_HEADER IH;
//索引项 可能不存在
BYTE IR_IndexEntry[0];
}INDEX_ROOT,*pINDEX_ROOT;
//INDEX_ALLOCATION 0XA0属性体
typedef struct _INDEX_ALLOCATION {
//UINT64 IA_DataRuns;
BYTE IA_DataRuns[0];
}INDEX_ALLOCATION,*pINDEX_ALLOCATION;
//BITMAP
typedef struct _MFT_ATTR_BITMAP {
//??
}MFT_ATTR_BITMAP,*pMFT_ATTR_BITMAP;
//SYMBOL_LINK
typedef struct _SYMBOL_LINK {
//??
}SYMBOL_LINK,*pSYMBOL_LINK;
//REPARSE_POINT
typedef struct _REPARSE_POINT{
UINT32 RP_Type;/*重解析数据类型,该值可以是以下值之一
0x20000000 别名
0x40000000 最高等待时间
0x80000000 微软使用
0x68000005 NSS
0x68000006 NSS恢复
0x68000007 SIS
0x68000008 DFS
0x88000003 卷挂接点
0xA8000004 HSM
0xE8000000 硬连接*/
UINT16 RP_DatSz;//重解析数据尺寸
UINT16 RP_Resvd;//
BYTE RP_Data[0];// 重解析数据
}REPARSE_POINT,*pREPARSE_POINT;
//EA_INFORMATION
typedef struct _EA_INFORMATION {
UINT16 EI_PackedSz;// 压缩扩展属性尺寸
UINT16 EI_NumOfEA;//拥有NEED_EA记录的扩展属性个数
UINT32 EI_unpackedSz;//未压缩扩展属性尺寸
}EA_INFORMATION,*pEA_INFORMATION;
//EA
typedef struct _EA {
UINT32 EA_Next;//下一个扩展属性的偏移(本记录的尺寸)
BYTE EA_Flags;//标志位,值取0x80表示需要EA
BYTE EA_NamLen;//名字数据的长度(M)
UINT16 EA_ValLen;//值数据的长度
BYTE EA_NameVal[0];//名字数据和值数据
}EA,*pEA;
//PROPERTY_SET
typedef struct _PROPERTY_SET {
//??
}PROPERTY_SET,*pPROPERTY_SET;
//LOGGED_UNTILITY_STREAM
typedef struct _LOGGED_UNTILITY_STREAM {
//??
}LOGGED_UNTILITY_STREAM,*pLOGGED_UNTILITY_STREAM;
//fat32.h
#pragma once
#pragma pack(1)
#pragma warning(disable : 4996)
#include "stdafx.h"
/*
【FAT32分区的结构】
【[保留扇区,其中第一个扇区为DBR]||||[FAT1]||||[FAT2]||||[数据区]】
*/
//fat32相关
typedef struct _FAT32_Sector
{
UINT32 Sectors_per_FAT_FAT32; //FAT32中FAT表占用总扇区数
UINT16 Extend_Flag; //0-3位表示活动FAT数,7位:0表示在运行时FAT映射到所有FAT
//1表示只有一个FAT是活动的,其他位保留
UINT16 FS_Version; //文件系统版本,高字节表示主要修订号,低直接表示次要修订号
UINT32 Root_Cluster_Number; //根目录簇号,一般取值为2
UINT16 FS_Info_Sector; //文件系统扇区号,一般取1
UINT16 Backup_Sector; //备份引导扇区,一般取值为6
BYTE Reserved_Sector[12]; //保留扇区
}FAT32_Sector, *pFAT32_Sector;
typedef struct _Basic_BPB
{
UINT16 Bytes_per_Sector; //每个扇区字节数,可取minReadSize,1024,2048,4096,通常取minReadSize
BYTE Sectors_per_Cluster; //每簇扇区数,可取1,2,4,8,16,32,64,128,FAT32最多跟踪
//268,435,445个簇
UINT16 Reserved_Sector; //保留扇区,表示第一个FAT前的扇区数 【也就是FAT1的偏移】
BYTE FATs; //FAT表个数,通常取2
UINT16 RootEntry; //根目录项数,对FAT32,取值必为0
UINT16 SmallSector; //小扇区数,对FAT32,取值必为0
BYTE Media; //存储介质描述,F8表示硬盘,F0表示3.5软盘
UINT16 Sector_per_FAT_FAT16; //针对FAT12/16的每个FAT扇区数,对FAT32,取值为0
UINT16 Sector_per_Track; //每道扇区数,描述磁盘物理结构
UINT16 Heads; //磁头数
UINT32 hidden_Sector; //该块硬盘前用于存放引导代码及分区表的扇区数 【隐藏扇区】
UINT32 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识别
UINT32 Vol_Serial; //卷序列号,由格式化时随机获得
BYTE Vol_Label[11]; //卷标示
BYTE System_ID[8]; //系统ID,根据格式化的格式为FAT32,FAT16等
}FAT32_Extend_BPB, *pFAT32_Extend_BPB;
//FAT32 DBR扇区
typedef struct _FAT32_DBR
{
BYTE JumpInstrction[3]; //0x00,跳转指令,通常为EB 58 90,其中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;
//stdafx.h
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <stdarg.h>
#include <windows.h>
#include <map>
#include <vector>
#include <Setupapi.h>
//#include <winioctl.h>
//#include <tchar.h>
//#include <Shlwapi.h>
//#include <math.h>
//#include <time.h>
#include <string>
//#include <TlHelp32.h>
//#include <process.h>
//#include <iOStream>
//#include <VersionHelpers.h>
//#include <ShlObj.h>
//#include <assert.h>
//#include <WinBase.h>
//#include <fstream>
//#include <strsafe.h>
//#include <io.h>
//#include "md5.h"
//#include <unordered_map>
// TODO: 在此处引用程序需要的其他头文件
相关阅读
文件大小单位转换函数-getFileSize($bytes)
function getFileSize($bytes){ if ($bytes >= pow(2,40)) { # code... $return = round($bytes/pow(1024, 4),2); $suffi
三、Linux 文件权限首先来查看一下当前目录下的文件内容吧ls -l 查看当前目录下的文件列表 ls -l xxx.xxx (xxx.xxx是文件名) 查
TCode:SU01或SU3中可以看到用户参数文件(user profile)中的parameter :这个parameters可以通过函数 BAPI_USER_GET_DETAIL例子代
Android中使用file.createNewFile()无法创建文件的问
在写一个保存bitmap文件的方法的时候,遇到了题中问题。为了不出现问题,不要直接File f = new File(Environment.getExternalStorage
curl 模拟 GET\POST 请求,以及 curl post 上传文件
curl 模拟 GET\POST 请求,以及 curl post 上传文件 一般情况下,我们调试数据接口,都会使用一个 postman 的工具,但是这个工具还是有