您当前的位置:首页 > 计算机 > 编程开发 > VC/VC++

C++ 读取硬盘分区NTFS格式的MFT信息

时间:07-06来源:作者:点击数:

C++ 读取硬盘分区NTFS格式的MFT信息

#include "ntfs.h"
#include <iostream>
#include <fstream>
#include <map>
#include <vector>
using namespace std;
//管理员权限运行
typedef struct {
	ULONGLONG index;
	ULONGLONG parent;
	WCHAR name[1024];
	int type; //0 file 1 dir
} FILE_INFO, *PFILE_INFO; 

//枚举盘符
void OpenNtfsVolume()
{
	WCHAR tDrivers[26*4+1] = {};
	GetLogicalDriveStrings(26*4+1,tDrivers);
	WCHAR fileSysBuf[8];
	DWORD dwDri; //0~25

	WCHAR szRootName[40];
	WCHAR szVolumeName[32];
	int iFilterRoot=0;
	for(WCHAR *p=tDrivers;*p!='\0';p+=4)
	{       
		if(*p>=L'a') *p-=32;//
		dwDri=*p-L'A';
		if(DRIVE_FIXED==GetDriveTypeW(p))
		{	
			DWORD dwMaxComLen,dwFileSysFlag;
			GetVolumeInformationW(p,szVolumeName,32,NULL,&dwMaxComLen,&dwFileSysFlag,fileSysBuf,8);
			if(fileSysBuf[0]==L'N' && fileSysBuf[1]==L'T' && fileSysBuf[2]==L'F' && fileSysBuf[3]==L'S')
			{
				swprintf(szRootName,L"%s (%c:)",szVolumeName,*p);
				WCHAR szVolumePath[10];
				swprintf(szVolumePath,L"\\\\.\\%c:",*p);
				wcout<<szVolumePath<<endl;
			}
		}
	}
}

int main()
{
	//wcout.imbue(locale(locale(),"",LC_CTYPE));
	char szACP[16];  
	sprintf(szACP, ".%d", GetACP());  
	//setlocale(LC_CTYPE, szACP);
	wcout.imbue(locale(locale(),szACP,LC_CTYPE));
	OpenNtfsVolume();

	WCHAR driveletter[] = L"\\\\.\\D:";
	HANDLE hVol = CreateFile(driveletter, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
	NTFS_VOLUME_DATA_BUFFER ntfsVolData;
	DWORD dwWritten = 0;

	BOOL bDioControl = DeviceIoControl(hVol, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsVolData, sizeof(ntfsVolData), &dwWritten, NULL);
	if (!bDioControl) {wcout<<L"error"<<endl; return 1;}

	LARGE_INTEGER num;
	num.QuadPart = 1024;
	LONGLONG total_file_count = (ntfsVolData.MftValidDataLength.QuadPart/num.QuadPart);
	wcout<<L"total_file_count:"<<total_file_count<<endl;


	PNTFS_FILE_RECORD_OUTPUT_BUFFER ntfsFileRecordOutput = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)malloc(sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER)+ntfsVolData.BytesPerFileRecordSegment-1);
	for( LONGLONG i = 0; i < total_file_count && i < 10;i++)
	{
		NTFS_FILE_RECORD_INPUT_BUFFER mftRecordInput;
		mftRecordInput.FileReferenceNumber.QuadPart = i;
		memset(ntfsFileRecordOutput, 0, sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER)+ntfsVolData.BytesPerFileRecordSegment-1);
		DeviceIoControl(hVol, FSCTL_GET_NTFS_FILE_RECORD, &mftRecordInput, sizeof(mftRecordInput), ntfsFileRecordOutput, sizeof(NTFS_FILE_RECORD_OUTPUT_BUFFER)+ntfsVolData.BytesPerFileRecordSegment-1, &dwWritten, NULL);
		PFILE_RECORD_HEADER pfileRecordheader=(PFILE_RECORD_HEADER)ntfsFileRecordOutput->FileRecordBuffer;
		if(pfileRecordheader->Ntfs.Type != 'ELIF')
			continue;
		for(PATTRIBUTE pAttribute = (PATTRIBUTE)((PBYTE)pfileRecordheader +pfileRecordheader->AttributeOffset);pAttribute->AttributeType != -1;pAttribute=(PATTRIBUTE)((PBYTE)pAttribute +pAttribute->Length))
		{
			switch (pAttribute->AttributeType)
			{
			case AttributeFileName:
				{
					if((0x0002 & pfileRecordheader->Flags) && (0x0001 & pfileRecordheader->Flags));
					PFILENAME_ATTRIBUTE pFileNameAttr=PFILENAME_ATTRIBUTE((PBYTE)pAttribute+PRESIDENT_ATTRIBUTE(pAttribute)->ValueOffset);
				}
				break;
			case AttributeStandardInformation:
				break;
			case AttributeAttributeList:
				break;
			case AttributeObjectId:
				break;
			}
		}
	}
	free(ntfsFileRecordOutput);

	USN_JOURNAL_DATA journalData;
	READ_USN_JOURNAL_DATA readData = {0, 0xFFFFFFFF, FALSE, 0, 0};

	PUSN_RECORD usnRecord;
	DWORD dwBytes;
	DWORD dwRetBytes;
	char buffer[USN_PAGE_SIZE];
	bDioControl = DeviceIoControl(hVol, FSCTL_QUERY_USN_JOURNAL, NULL,0,&journalData,sizeof(journalData),&dwBytes,NULL);
	if (!bDioControl) {wcout<<L"error"<<endl; return 1;}
	readData.UsnJournalID = journalData.UsnJournalID;
	wprintf(L"Journal ID: %I64x\n", journalData.UsnJournalID );
	wprintf(L"FirstUsn: %I64x\n\n", journalData.FirstUsn );

	MFT_ENUM_DATA med;
	med.StartFileReferenceNumber = 0;
	med.LowUsn = 0;
	med.HighUsn = journalData.NextUsn;

	map<ULONGLONG,wstring> namemap;
	map<ULONGLONG,ULONGLONG> frnmap;
	vector<FILE_INFO> fileVect;
	for (;;)
	{
		memset(buffer, 0, sizeof(USN_PAGE_SIZE));
		//FSCTL_ENUM_USN_DATA FSCTL_READ_USN_JOURNAL
		//DeviceIoControl( hVol, FSCTL_READ_USN_JOURNAL, &readData,sizeof(readData),&buffer,USN_PAGE_SIZE,&dwBytes,NULL);
		bDioControl = DeviceIoControl( hVol, FSCTL_ENUM_USN_DATA, &med, sizeof(med),&buffer,USN_PAGE_SIZE,&dwBytes,NULL);
		if (!bDioControl) {wcout<<L"error"<<endl; break;}

		if(dwBytes<=sizeof(USN)) break;//结束!
		dwRetBytes = dwBytes - sizeof(USN);//跳过了1个USN,此USN是下一论查询起点
		usnRecord = (PUSN_RECORD)(((PUCHAR)buffer) + sizeof(USN));  
		while(dwRetBytes > 0)
		{
			FILE_INFO fi;
			fi.index = usnRecord->FileReferenceNumber;
			fi.parent = usnRecord->ParentFileReferenceNumber;

			//wprintf(L"USN: %I64x\n", usnRecord->Usn );
			//wprintf(L"File name: %.*s\n", (int)(usnRecord->FileNameLength/2),usnRecord->FileName );
			//wprintf(L"Reason: %x\n", usnRecord->Reason );

			memset(fi.name,0,sizeof(fi.name));
			swprintf(fi.name,L"%.*ws", (int)(usnRecord->FileNameLength/2),usnRecord->FileName);
			namemap[fi.index] = wstring(fi.name);
			fileVect.push_back(fi);
			frnmap[fi.index] = fi.parent;

			dwRetBytes -= usnRecord->RecordLength;
			usnRecord = (PUSN_RECORD)(((PCHAR)usnRecord) + usnRecord->RecordLength);    
		}
		med.StartFileReferenceNumber=*(DWORDLONG*)buffer;
		//readData.StartUsn = *(USN *)&buffer; 
	}
	wcout<<fileVect.size()<<endl;
	map<ULONGLONG,wstring>::iterator it;
	/*for ( it=namemap.begin() ; it != namemap.end(); it++ )
	{
	wcout << (*it).first << " => " << ((*it).second).c_str() <<"==>"<<namemap[(*it).first].c_str()<< endl;
	}*/

	//wofstream ofs(L"data.txt");
	for (LONGLONG i = 0; i < fileVect.size(); i++)
	{
		FILE_INFO fi = fileVect[i];
		wcout<<i<<": "<<fi.name<<"===>";
		ULONGLONG parent = fi.parent;
		while (namemap.find(parent) != namemap.end())
		{
			wstring dir = namemap[parent];
			wcout<<L"\\"<<dir.c_str();

			if (frnmap.find(parent) != frnmap.end())
			{
				parent = frnmap[parent];
			}
			else
			{
				break;
			}
		}
		wcout<<endl;
	}
	wcout<<"done"<<endl;
	CloseHandle(hVol);
	return 0;
}

/*typedef struct {

DWORD RecordLength;
WORD   MajorVersion;
WORD   MinorVersion;
DWORDLONG FileReferenceNumber;
DWORDLONG ParentFileReferenceNumber;
USN Usn;
LARGE_INTEGER TimeStamp;
DWORD Reason;
DWORD SourceInfo;
DWORD SecurityId;
DWORD FileAttributes;
WORD   FileNameLength;
WORD   FileNameOffset;
WCHAR FileName[1];

} USN_RECORD, *PUSN_RECORD;*/

下面是ntfs.h的内容,编译使用UNICODE编码

#include <Windows.h> 
#include <WinIoCtl.h>

typedef struct { 
	ULONG Type;  //4B  'ELIF','XDNI','DAAB','ELOH','DKHC'  
	USHORT UsaOffset;  //2B 更新序列号数组偏移,校验值地址 
	USHORT UsaCount;  //1+n 1为校验值个数 n为待替换值个数  fixup 
	USN Usn; //8B 每次记录被修改 USN都变化 
} NTFS_RECORD_HEADER, *PNTFS_RECORD_HEADER;

typedef struct { //sizeof(FILE_RECORD_HEADER)==48 
	NTFS_RECORD_HEADER Ntfs;  //16B Ntfs.Type总是'ELIF' 
	USHORT SequenceNumber; //File Reference Number的高16位  i是低48位 0~total_file_count-1
	//用于记录主文件表记录被重复使用的次数 
	USHORT LinkCount; //记录硬连接的数目,只出现在基本文件记录中 
	USHORT AttributeOffset; //第一个属性的偏移 
	USHORT Flags;       // 0x0001 = InUse, 0x0002 = Directory 
	ULONG BytesInUse;  //记录头和属性的总长度,即文件记录的实际长度文件,即记录在磁盘上实际占用的字节空间。 
	ULONG BytesAllocated; //总共分配给记录的长度 
	ULONGLONG BaseFileRecord; //基本文件记录中的文件索引号, 
	//对于基本文件记录,其值为0,如果不为0,则是一个主文件表的文件索引号, 
	//指向所属的基本文件记录中的文件记录号, 
	//在基本文件记录中包含有扩展文件记录的信息,存储在“属性列表ATTRIBUTE_LIST”属性中。 
	USHORT NextAttributeNumber; //下一属性ID 
} FILE_RECORD_HEADER, *PFILE_RECORD_HEADER;


//文件记录中按属性非降序(因为有时连续多个相同的属性)排列, 
//属性的值即为 字节流 
typedef enum { 
	//诸如只读、存档等文件属性; 
	//时间戳:文件创建时、最后一次修改时; 
	//多少目录指向该文件(硬链接计数hard link count) 
	AttributeStandardInformation = 0x10, //Resident_Attributes 常驻属性

	//????????????????????????????????? 
	//当一个文件要求多个MFT文件记录时 会有该属性 
	//属性列表,包括构成该文件的这些属性,以及每个属性所在的MFT文件记录的文件引用 
	//????????????????????????????????? 
	AttributeAttributeList = 0x20,//由于属性值可能会增长,可能是非驻留属性

	//文件名属性可以有多个: 
	//1.长文件名自动为其短文件名(以便MS-DOS和16位程序访问) 
	//2.当该文件存在硬链接时 
	AttributeFileName = 0x30, //常驻

	//一个文件或目录的64字节标识符,其中低16字节对于该卷来说是唯一的 
	//链接-跟踪服务将对象ID分配给外壳快捷方式和OLE链接源文件。 
	//NTFS提供了相应的API,因为文件和目录可以通过其对象ID,而不是通过其文件名打开 
	AttributeObjectId = 0x40, //常驻

	//为与NTFS以前版本保持向后兼容 
	//所有具有相同安全描述符的文件或目录共享同样的安全描述 
	//以前版本的NTFS将私有的安全描述符信息与每个文件和目录存储在一起 
	AttributeSecurityDescriptor = 0x50,//出现于$Secure元数据文件中

	//保存了该卷的版本和label信息 
	AttributeVolumeName = 0x60, //仅出现于$Volume元数据文件中 
	AttributeVolumeInformation = 0x70,//仅出现于$Volume元数据文件中

	//文件内容,一个文件仅有一个未命名的数据属性,但可有额外多个命名数据属性 
	//即一个文件可以有多个数据流,目录没有默认的数据属性,但可有多个可选的命名的数据属性 
	AttributeData = 0x80,//由于属性值可能会增长,可能是非驻留属性

	//以下三个用于实现大目录的文件名分配和位图索引 
	AttributeIndexRoot = 0x90,//常驻 
	AttributeIndexAllocation = 0xA0, 
	AttributeBitmap = 0xB0,

	//存储了一个文件的重解析点数据,NTFS的交接(junction)和挂载点包含此属性 
	AttributeReparsePoint = 0xC0,

	//以下两个为扩展属性,现已不再被主动使用,之所以提供是为与OS/2程序保持向后兼容 
	AttributeEAInformation = 0xD0, 
	AttributeEA = 0xE0,

	AttributePropertySet = 0xF0, 
	AttributeLoggedUtilityStream = 0x100, 
	AttributeEnd=0xFFFFFFFF 
} ATTRIBUTE_TYPE, *PATTRIBUTE_TYPE;

typedef struct { 
	ATTRIBUTE_TYPE AttributeType; 
	ULONG Length; //本属性长度(包含属性值) 
	BOOLEAN Nonresident; //本属性不是 驻留 属性么? 
	UCHAR NameLength; //属性名的名称长度 
	USHORT NameOffset;//属性名偏移 
	USHORT Flags; // 0x0001 压缩 0x4000 加密 0x8000稀疏文件 
	USHORT AttributeNumber; 
} ATTRIBUTE, *PATTRIBUTE;

typedef struct { 
	ATTRIBUTE Attribute; 
	ULONG ValueLength; //属性值长度 
	USHORT ValueOffset; //属性值偏移 
	USHORT Flags; // 索引标志 0x0001 = Indexed 
} RESIDENT_ATTRIBUTE, *PRESIDENT_ATTRIBUTE;

typedef struct { 
	ATTRIBUTE Attribute; 
	ULONGLONG LowVcn; 
	ULONGLONG HighVcn; 
	USHORT RunArrayOffset; 
	UCHAR CompressionUnit; 
	UCHAR AlignmentOrReserved[5]; 
	ULONGLONG AllocatedSize; 
	ULONGLONG DataSize; 
	ULONGLONG InitializedSize; 
	ULONGLONG CompressedSize;    // Only when compressed 
} NONRESIDENT_ATTRIBUTE, *PNONRESIDENT_ATTRIBUTE;

typedef struct { //文件名属性的值区域 
	ULONGLONG DirectoryFileReferenceNumber; //父目录的FRN 
	ULONGLONG CreationTime; 
	ULONGLONG ChangeTime; 
	ULONGLONG LastWriteTime; // 最后一次MFT更新时间 
	ULONGLONG LastAccessTime; 
	ULONGLONG AllocatedSize; // 未明 
	ULONGLONG DataSize; // 偶尔与文件大小GetFileSize不同 
	ULONG FileAttributes; 
	ULONG AlignmentOrReserved; 
	UCHAR NameLength; 
	UCHAR NameType; //POSIX 0x0  WIN32 0x01  DOS 0x02  WIN32&DOS 0x3 
	WCHAR Name[1]; 
} FILENAME_ATTRIBUTE, *PFILENAME_ATTRIBUTE;

typedef struct { 
	ATTRIBUTE_TYPE AttributeType;   //属性类型 
	USHORT Length;                  //本记录长度 
	UCHAR NameLength;               //属性名长度 
	UCHAR NameOffset;               //属性名偏移 
	ULONGLONG LowVcn;               //起始VCN 
	ULONGLONG FileReferenceNumber;  //属性的文件参考号 
	USHORT AttributeNumber;         //标识 
	WCHAR Name[1]; 
} ATTRIBUTE_LIST, *PATTRIBUTE_LIST;

#pragma pack(push,1) 
typedef struct { //512B 
	UCHAR Jump[3];//跳过3个字节 
	UCHAR Format[8]; //‘N’'T' 'F' 'S' 0x20 0x20 0x20 0x20 
	USHORT BytesPerSector;//每扇区有多少字节 一般为512B 0x200 
	UCHAR SectorsPerCluster;//每簇有多少个扇区 
	USHORT BootSectors;// 
	UCHAR Mbz1;//保留0 
	USHORT Mbz2;//保留0 
	USHORT Reserved1;//保留0 
	UCHAR MediaType;//介质描述符,硬盘为0xf8 
	USHORT Mbz3;//总为0 
	USHORT SectorsPerTrack;//每道扇区数,一般为0x3f 
	USHORT NumberOfHeads;//磁头数 
	ULONG PartitionOffset;//该分区的便宜(即该分区前的隐含扇区数 一般为磁道扇区数0x3f 63) 
	ULONG Reserved2[2]; 
	ULONGLONG TotalSectors;//该分区总扇区数 
	ULONGLONG MftStartLcn;//MFT表的起始簇号LCN 
	ULONGLONG Mft2StartLcn;//MFT备份表的起始簇号LCN 
	ULONG ClustersPerFileRecord;//每个MFT记录包含几个簇  记录的字节不一定为:ClustersPerFileRecord*SectorsPerCluster*BytesPerSector
	ULONG ClustersPerIndexBlock;//每个索引块的簇数 
	ULONGLONG VolumeSerialNumber;//卷序列号 
	UCHAR Code[0x1AE]; 
	USHORT BootSignature; 
} BOOT_BLOCK, *PBOOT_BLOCK; 
#pragma pack(pop)
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐