gpt4 book ai didi

c - 如何用C读取主文件表(MFT)?

转载 作者:行者123 更新时间:2023-11-30 19:59:45 33 4
gpt4 key购买 nike

我想使用 C 读取本地系统的 MFT。我在互联网上寻找解决方案,但没有找到。我希望有人为我提供一个教程,或者通过代码示例提供有关如何执行此操作的良好解释。提前致谢。

最佳答案

首先,我们需要使用 FILE_READ_DATA 权限打开卷句柄。

然后我们需要用NTFS_VOLUME_DATA_BUFFER控制代码来查询FSCTL_GET_NTFS_VOLUME_DATA

从这里我们得到了单个 MFT 记录的大小 - BytesPerFileRecordSegmentMFT 的总大小 - MftValidDataLength.因此最大记录数为(MftValidDataLength.QuadPart/BytesPerFileRecordSegment)

正确的方法(与 NTFS 同步)是通过 FSCTL_GET_NTFS_FILE_RECORD 读取单个记录。

如果您想一次读取多条记录 - 当然可以直接从卷中读取。我们有 MFT 的起始 LCN - MftStartLcn。但是MFT可以有几个不连续的片段。所以如果我们想获取所有片段位置,我们需要使用FSCTL_GET_RETRIEVAL_POINTERS。要将LCN转换为卷偏移量,我们需要将其乘以BytesPerCluster

演示代码:

void ReadMft(PCWSTR szVolume)
{
HANDLE hVolume = CreateFileW(szVolume, FILE_READ_DATA, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_OPEN_FOR_BACKUP_INTENT, 0);

if (hVolume != INVALID_HANDLE_VALUE)
{
NTFS_VOLUME_DATA_BUFFER nvdb;

OVERLAPPED ov = {};

if (DeviceIoControl(hVolume, FSCTL_GET_NTFS_VOLUME_DATA, 0, 0, &nvdb, sizeof(nvdb), 0, &ov))
{
NTFS_FILE_RECORD_INPUT_BUFFER nfrib;

nfrib.FileReferenceNumber.QuadPart = nvdb.MftValidDataLength.QuadPart / nvdb.BytesPerFileRecordSegment - 1;

ULONG cb = __builtin_offsetof(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer[nvdb.BytesPerFileRecordSegment]);

PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)alloca(cb);

do
{
if (!DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD,
&nfrib, sizeof(nfrib), pnfrob, cb, 0, &ov))
{
break;
}

// pnfrob->FileRecordBuffer :
// here pnfrob->FileReferenceNumber FileRecord

} while (0 <= (nfrib.FileReferenceNumber.QuadPart = pnfrob->FileReferenceNumber.QuadPart - 1));

ReadMft2(szVolume, hVolume, &nvdb);
}

CloseHandle(hVolume);
}
}

void ReadMft2(PCWSTR szVolume, HANDLE hVolume, PNTFS_VOLUME_DATA_BUFFER nvdb)
{
static PCWSTR MFT = L"\\$MFT";

static STARTING_VCN_INPUT_BUFFER vcn {};

static volatile UCHAR guz;

PVOID stack = alloca(guz);

union {
PVOID buf;
PWSTR lpFileName;
PRETRIEVAL_POINTERS_BUFFER rpb;
};

buf = alloca(wcslen(szVolume) * sizeof(WCHAR) + sizeof(MFT));

wcscat(wcscpy(lpFileName, szVolume), MFT);

HANDLE hFile = CreateFileW(lpFileName, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_OPEN_FOR_BACKUP_INTENT, 0);

if (hFile != INVALID_HANDLE_VALUE)
{
OVERLAPPED ov{};

ULONG cb = RtlPointerToOffset(buf, stack), rcb, ExtentCount = 2;

do
{
rcb = __builtin_offsetof(RETRIEVAL_POINTERS_BUFFER, Extents[ExtentCount]);

if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}

if (DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS, &vcn, sizeof(vcn), buf, cb, 0, &ov))
{
if (rpb->Extents->Lcn.QuadPart != nvdb->MftStartLcn.QuadPart)
{
__debugbreak();
}

if (ExtentCount = rpb->ExtentCount)
{
auto Extents = rpb->Extents;

ULONG BytesPerCluster = nvdb->BytesPerCluster;
ULONG BytesPerFileRecordSegment = nvdb->BytesPerFileRecordSegment;

LONGLONG StartingVcn = rpb->StartingVcn.QuadPart, NextVcn, len;

PVOID FileRecordBuffer = alloca(BytesPerFileRecordSegment);

do
{
NextVcn = Extents->NextVcn.QuadPart;
len = NextVcn - StartingVcn, StartingVcn = NextVcn;

DbgPrint("%I64x %I64x\n", Extents->Lcn.QuadPart, len);

if (Extents->Lcn.QuadPart != -1)
{
Extents->Lcn.QuadPart *= BytesPerCluster;
ov.Offset = Extents->Lcn.LowPart;
ov.OffsetHigh = Extents->Lcn.HighPart;

// read 1 record
ReadFile(hVolume, FileRecordBuffer, BytesPerFileRecordSegment, 0, &ov);
}

} while (Extents++, --ExtentCount);
}
break;
}

ExtentCount <<= 1;

} while (GetLastError() == ERROR_MORE_DATA);

CloseHandle(hFile);
}
}

关于c - 如何用C读取主文件表(MFT)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54606760/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com