根据NTFS - File - Search思路:Qt/C++中了解NTFS文件系统全解析系列
整个列系列是基于开源项目NTFS-File-分区获得所有文件/目录列表的想法。
细节如下:
QT/C ++了解NTFS文件系统,了解MFT(文件表)主文件表(1)
介绍NTFS文件系统,通过MFT(文件表)主文件表比较数据的优点和缺点,简要介绍了NTFS-File-开源项目,并了解NTFS系统中引用的所有文章。 QT/C ++了解NTFS文件系统,分析磁盘的数据以指导扇区数据以获取MFT(文件表)主文件表偏移地址
阅读$ boot指南分区扇区数据,获取单个群集大小(4096字节),$ mft元数据大小(1024字节)和$ mft元数据的启动群集编号,计算磁盘磁盘上的$ mft元数据拍摄地址。 QT/C ++了解NTFS文件系统,获取第一个MFT表数据,分析文件的内容以查找第一个属性偏移地址
分析$ MFT元数据结构,并根据$ MFT元数据文件的记录标头获取属性的偏移地址。它用于以后分析0x80 $数据属性。居民属性和非常居民的属性
简要介绍$ MFT元数据.qt/c ++中的居民属性和非常居民的属性结构,了解NTFS文件系统,分析0x80 $数据属性并获得运行列表数据列表
根据0x80 $数据属性,查找间隔列表(运行列表数据列表)以存储所有$ MFT元数据数据。
根据前面获得的运行列表数据列表,
遍历所有运行列表数据列表读取所有$ mft元数据,并分析$属性的实际大小和$属性获取文件或目录,名称,磁盘分布大小,记录号,文件属性和其他信息
目录指南
前言
根据第一个MFT(文件表)的第一个MFT(文件表),获得的偏移地址,
获取第一个MFT(文件表)主文件表数据,分析文件记录标头的内容数据,然后获取第一个属性的偏移地址。
用于查找所有属性,直到找到$数据(0x80)属性并获取数据列表。
NTFS文件系统中的每个文件或目录都由一个或多个MFT(文件表)主文件表保存
数据列表是指所有MFT(文件表)主文件表位于区域磁盘的文件目录中的偏移地址列表
设置偏移地址,读取(1024)的数据字节,
参考ntfs-file-
//! 设置偏移量读取数据
DWORD ReadBytes(HANDLE m_hVolume,PVOID pBuffer, DWORD cbReadSize, UINT64 ullAbsoluteOffset)
{
DWORD dwNumberOfBytesRead=0;
BOOL bSuccess;
if (ullAbsoluteOffset != UINT64_MAX)
{
LARGE_INTEGER liPosition;
liPosition.QuadPart = ullAbsoluteOffset;
LARGE_INTEGER liUpdatedPosition;
if (SetFilePointerEx(m_hVolume, liPosition, &liUpdatedPosition, FILE_BEGIN))
m_ullCurrentOffset = liUpdatedPosition.QuadPart;
else
return 0;
}
bSuccess = ReadFile(m_hVolume, pBuffer, cbReadSize, &dwNumberOfBytesRead, NULL);
if (bSuccess) {
m_ullCurrentOffset += cbReadSize;
}
return dwNumberOfBytesRead;
}
//! 开始读取首个MFT表
PBYTE pbMFTBuffer = new BYTE[m_ullRecordSize];
UINT64 MFT_LCN= (UINT64)(m_BootRecord.MFT_LCN * m_BootRecord.BytesPerSector * m_BootRecord.SectorsPerCluster);
if (m_ullRecordSize != ReadBytes(m_hVolume,pbMFTBuffer, (INT64)m_ullRecordSize, MFT_LCN))
goto out;
qDebug()<<"输出...";
for(int i=0;i<m_ullRecordSize;i++)
{
Val+=QString("%1 ").arg(pbMFTBuffer[i],2,16,QLatin1Char('0')).toUpper();
if((i+1)%16==0)
{
qDebug()<<Val;
Val="";
}
}
/*输出...
"46 49 4C 45 30 00 03 00 EC F3 01 ED 15 00 00 00 "
"01 00 01 00 38 00 01 00 B8 01 00 00 00 04 00 00 "
"00 00 00 00 00 00 00 00 17 00 00 00 00 00 00 00 "
"D6 03 00 00 00 00 00 00 10 00 00 00 60 00 00 00 "
"00 00 18 00 00 00 00 00 48 00 00 00 18 00 00 00 "
"A0 73 73 A7 99 E8 D7 01 A0 73 73 A7 99 E8 D7 01 "
"A0 73 73 A7 99 E8 D7 01 A0 73 73 A7 99 E8 D7 01 "
....
....
*/
在工具中,第一个MFT(文件表)主文件表是指导该扇区后的第16个扇区。
MFT(文件表)主文件表的分析
了解MFT(文件表)的结构对于了解NTFS文件系统的操作至关重要。以下是对MFT结构的详细说明:
MFT记录:
MFT由一系列固定尺寸记录组成,每个记录对应于文件,目录或元数据文件。
MFT记录包括文件或目录的元数据信息,例如文件属性,数据位置,文件名等。
MFT记录号:
每个MFT记录都有一个唯一的标识符,称为MFT记录号。
MFT记录号用于在MFT中找到和识别特定文件或目录。
摘要来自:MFT(文件表,主文件表)是操作系统中NTFS(新文件,新技术文件系统)的关键组件,用于存储文件和目录的元数据信息。 MFT与UNIX和Linux系统中的Inode相似,但实现却不同。
MFT是一组文件记录。卷中的每个文件都由一个或多个文件记录完全描述。用UNIX术语,文件记录等效于索引节点。给定文件描述的第一个文件记录称为基本文件记录,其他记录称为扩展文件记录。
文件记录由标题,几个可变长度属性和一个终端标签组成(简单)。
来自:file- $ mft(0)
-文件
以第一个MFT(文件表)主文件表作为一个示例来分析数据结构
MFT(文件表)主文件表以File0字符串开始。
分析文件记录标题布局($ MFT文件)
MFT表中的前48个字节是文件记录标头的内容。数据的数据结构获得了数据记录标头数据的属性。数据结构是:
字节大小描述
0x00
4个字节
(魔术'文件')
固定值必须是“文件”
0x04
2个字节
(到)
更新序列号的偏移
0x06
2个字节
(用(s)的单词大小
更新序列号并更新单词中的数组
0x08
8个字节
$(LSN)
日志序列编号(每个记录都经过修改,将使序列为Plus 1)
0x10
2个字节
序列号(用于记录文件记录的次数重复使用的次数,在删除文件时添加1,并跳过0个值。如果是0,则将其保留为0)
0x12
2个字节
硬链路计数
硬链数仅出现在基本文件记录中,目录中包含的项目数必须用于他
0x14
2个字节
到第一个
第一个属性流的偏移位置
0x16
2个字节
标志
按字节标记,1表示在记录期间,2表示记录是目录
0x18
4个字节
文件的实际尺寸
文件记录的实际大小(填写8个字节,即8个字节8个字节)
0x1c
4个字节
文件的大小
文件记录分布大小(填充到8个字节,即8个字节8个字节)
0x20
8个字节
文件到基本文件
相应基本文件记录的文件参考号(在扩展文件记录中使用,基本文件记录中的0,基本文件记录0x20属性存储相关信息的属性列表的属性列表)
0x28
2个字节
下一个ID
下一个免费ID号,添加新属性时,将值分配给新属性,然后值增加。如果重复使用IFT记录,请将其设置为0,第一个实例始终为0
0x2a
2个字节
XP
与4个字节保持一致
边框,在XP中使用,即此记录中使用的两个扇区的最后两个字节的值
0x2c
4个字节
XP
这个MFT
在XP中使用此MFT记录号
价值描述
0x01
表示正在使用记录
0x02
记录是目录(存在文件名索引)
0x04
是扩展名($目录中的记录设置)
0x08
有特殊的索引(对于包含索引的非注销记录设置:objid,配额,配额,配额,)
分配大小是磁盘上占据的空间。这应该是集群大小的倍数,并且可能等于MFT文件记录的大小。实际大小是记录中使用的字节数。
注意:实际尺寸将填充到8字节边界中。
参考:NTFS文件系统的详细说明(3)NTFS元素文件分析
-文件
定义一个48字节结构,对数据结构转换的对齐字节,例如NTFS-File-中的ER结构:
/*
* $MFT File Record Header Layout - 文件记录头布局 标准属性标题,
* MFT是一组文件记录。卷中的每个文件都由一个或多个这样的文件记录完整地描述。
* 在Unix术语中,文件记录相当于索引节点。描述给定文件的第一个文件记录称为基本文件记录,其他记录称为扩展文件记录。
* 文件记录由一个标题、几个可变长度属性和一个结束标记(简单地说就是0xFFFFFFFF)组成。
* https://flatcap.github.io/linux-ntfs/ntfs/concepts/file_record.html
*/
typedef struct MFT_FILE_RECORD_HEADER
{
//!字节4 固定值 一定是"FILE"
DWORD Magic; // "FILE" (0x454C4946)
//!字节2 更新序列号的偏移
WORD UpdateSequenceOffset; // Update Sequence offset - 偏移到更新序列
//!字节2 更新序列号与更新数组以字为单位(s)
WORD SizeOfUpdateSequence; // Size in words of Update Sequence - 更新序列的字数
//!字节8 日志序列号(每次记录被修改,都将导致该序列加1)
ULONGLONG LogSequenceNumber; // $LogFile Sequence Number (LSN) - $日志文件序列号(LSN)
//!字节2 序列号(用于记录本文件记录被重复使用的次数,每次文件删除时加1,跳过0值,如果为0,则保持为0)
WORD SequenceNumber; // Sequence number - 序列号
//!字节2 硬链接数 只出现在基本文件记录中,目录所含项数要使用到他
WORD HardLinkCount; // Hard link count - 硬链接计数
//!字节2 第一个属性流的偏移位置
WORD FirstAttributeOffset; // First attribute offset - 到第一个属性的偏移量
//!字节2 标志字节,1表示记录使用中,2表示该记录为目录
WORD Flags;
//!字节4 文件记录实际大小(填充到8字节,即以8字节为边界)
DWORD RealSize; // Real size of the FILE record - FILE记录的实际大小
//!字节4 文件记录分配大小(填充到8字节,即以8字节为边界)
DWORD AllocatedSize; // Allocated size of the FILE record - 文件记录的分配大小
//!字节8 所对应的基本文件记录的文件参考号(扩展文件记录中使用,基本文件记录中为0,在基本文件记录的属性列表0x20属性存储中扩展文件记录的相关信息)
ULONGLONG FileReference; // File reference to the base FILE record - 对基本文件记录的文件引用
//!字节2 下一个自由ID号,当增加新的属性时,将该值分配给新属性,然后该值增加,如果IFT记录重新使用,则将它置0,第一个实例总是0
WORD NextAttributeId; // 下一个属性Id
//!字节2 边界, WINDOWS XP 中使用,也就是本记录使用的两个扇区的最后两个字节的值
WORD Align; // 对齐4字节边界
//!字节4 WINDOWS XP中使用,本MFT记录号
DWORD RecordNumber; // MFT Record Number - MFT记录号
}*PMFT_FILE_RECORD_HEADER;
PMFT_FILE_RECORD_HEADER header=(PMFT_FILE_RECORD_HEADER)pbMFTBuffer;
qDebug()<<"FirstAttributeOffset: "<<QString::number(header->FirstAttributeOffset,16).toUpper()<<" -> "<<QString::number(header->FirstAttributeOffset,10);
qDebug()<<"LogSequenceNumber: "<<QString::number(header->LogSequenceNumber,16).toUpper()<<" -> "<<QString::number(header->LogSequenceNumber,10);
qDebug()<<"Flags: "<<QString::number(header->Flags,16).toUpper()<<" -> "<<QString::number(header->Flags,10);
qDebug()<<"RealSize: "<<QString::number(header->RealSize,16).toUpper()<<" -> "<<QString::number(header->RealSize,10);
qDebug()<<"AllocatedSize: "<<QString::number(header->AllocatedSize,16).toUpper()<<" -> "<<QString::number(header->AllocatedSize,10);
/*
FirstAttributeOffset: "38" -> "56"
LogSequenceNumber: "15ED01F3EC" -> "94170641388"
Flags: "1" -> "1"
RealSize: "1B8" -> "440"
AllocatedSize: "400" -> "1024"
*/
获取第一个属性偏移地址()从56个字节开始
如下所示: