如何使用C语言读取本地系统的主文件表(MFT)?
Reading NTFS MFT with C on Windows
Hey there! Reading the NTFS Master File Table (MFT) directly from C is a deep dive into low-level Windows system programming—let me walk you through the core steps, key concepts, and a working code example to get you started.
Prerequisites
- Admin privileges: Accessing physical disk devices or raw NTFS volumes requires elevated rights. Always run your program as an administrator.
- Windows-only: MFT is unique to NTFS, so this code will only work on Windows systems.
- Basic NTFS knowledge: Familiarity with terms like clusters, sectors, and MFT records will help you follow along.
Core Approach
To read the MFT, you’ll need to:
- Open a handle to the NTFS volume (either a physical drive or logical volume like
C:). - Read the NTFS boot sector to extract critical metadata (MFT start position, cluster size, etc.).
- Calculate the exact disk offset of the MFT.
- Read and parse individual MFT records.
Step-by-Step Code Example
Here’s a complete example that reads the MFT’s first record (which always represents the MFT itself) and prints basic metadata:
#include <windows.h> #include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> // Simplified NTFS Boot Sector structure (only key fields) typedef struct { uint8_t Jump[3]; uint8_t OEMID[8]; uint16_t BytesPerSector; uint8_t SectorsPerCluster; uint16_t ReservedSectors; uint8_t FATCount; uint16_t RootDirEntries; uint16_t TotalSectors16; uint8_t MediaType; uint16_t FATSize16; uint16_t SectorsPerTrack; uint16_t Heads; uint32_t HiddenSectors; uint32_t TotalSectors32; // NTFS-specific fields uint32_t SectorsPerFAT; uint16_t ExtFlags; uint16_t FSVersion; uint64_t MftStartCluster; uint64_t MftMirrorStartCluster; int8_t ClustersPerMftRecord; int8_t ClustersPerIndexRecord; uint64_t VolumeSerialNumber; uint32_t Checksum; } NTFS_BOOT_SECTOR; // Simplified MFT Record Header structure typedef struct { uint32_t Signature; // Should be "FILE" (0x454C4946 in little-endian) uint16_t UpdateSequenceOffset; uint16_t UpdateSequenceSize; uint64_t LogFileSequenceNumber; uint16_t SequenceNumber; uint16_t HardLinkCount; uint16_t FirstAttributeOffset; uint16_t Flags; uint32_t RecordSize; uint32_t AllocatedSize; uint64_t BaseRecord; uint16_t NextAttributeID; } MFT_RECORD_HEADER; int main() { // Open logical volume C: (use \\.\PhysicalDrive0 for the first physical disk) HANDLE hVolume = CreateFile( L"\\\\.\\C:", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, NULL ); if (hVolume == INVALID_HANDLE_VALUE) { printf("Failed to open volume. Error code: %lu\n", GetLastError()); return 1; } // Read the boot sector (first 512 bytes of the volume) NTFS_BOOT_SECTOR bootSector; DWORD bytesRead; if (!ReadFile(hVolume, &bootSector, sizeof(NTFS_BOOT_SECTOR), &bytesRead, NULL)) { printf("Failed to read boot sector. Error code: %lu\n", GetLastError()); CloseHandle(hVolume); return 1; } if (bytesRead != sizeof(NTFS_BOOT_SECTOR)) { printf("Incomplete boot sector read: %lu bytes received\n", bytesRead); CloseHandle(hVolume); return 1; } // Verify we're dealing with an NTFS volume if (memcmp(bootSector.OEMID, "NTFS ", 8) != 0) { printf("Target volume is not NTFS\n"); CloseHandle(hVolume); return 1; } // Calculate MFT start offset on disk uint64_t bytesPerCluster = (uint64_t)bootSector.BytesPerSector * bootSector.SectorsPerCluster; uint64_t mftOffset = bootSector.MftStartCluster * bytesPerCluster; // Seek to the MFT start position LARGE_INTEGER offset; offset.QuadPart = mftOffset; if (!SetFilePointerEx(hVolume, offset, NULL, FILE_BEGIN)) { printf("Failed to seek to MFT. Error code: %lu\n", GetLastError()); CloseHandle(hVolume); return 1; } // Calculate MFT record size (handles both positive cluster count and negative power-of-2 values) uint32_t mftRecordSize; if (bootSector.ClustersPerMftRecord > 0) { mftRecordSize = bootSector.ClustersPerMftRecord * bytesPerCluster; } else { mftRecordSize = 1 << (-bootSector.ClustersPerMftRecord); } // Allocate buffer for the MFT record uint8_t* mftRecord = malloc(mftRecordSize); if (!mftRecord) { printf("Failed to allocate memory for MFT record\n"); CloseHandle(hVolume); return 1; } // Read the first MFT record if (!ReadFile(hVolume, mftRecord, mftRecordSize, &bytesRead, NULL)) { printf("Failed to read MFT record. Error code: %lu\n", GetLastError()); free(mftRecord); CloseHandle(hVolume); return 1; } // Parse and validate the MFT record header MFT_RECORD_HEADER* header = (MFT_RECORD_HEADER*)mftRecord; if (header->Signature != 0x454C4946) { // "FILE" in little-endian byte order printf("Invalid MFT record signature\n"); free(mftRecord); CloseHandle(hVolume); return 1; } // Print basic MFT record info printf("MFT Record Signature: %.4s\n", (char*)&header->Signature); printf("Record Size: %u bytes\n", header->RecordSize); printf("Hard Link Count: %u\n", header->HardLinkCount); printf("First Attribute Offset: %u bytes\n", header->FirstAttributeOffset); // Cleanup resources free(mftRecord); CloseHandle(hVolume); return 0; }
Key Notes & Pitfalls
- File Flags:
FILE_FLAG_NO_BUFFERINGis critical to bypass Windows disk caching, which can interfere with raw reads. Ensure your buffer size aligns with the volume's sector size (checkbootSector.BytesPerSector). - MFT Record Size: The size is stored either as a positive number (clusters per record) or a negative power of 2 (e.g.,
-4means 16 sectors per record). Always handle both cases. - Access Denied: If you get error code
5, you didn’t run the program as an administrator—elevated rights are mandatory for raw disk access. - Attribute Parsing: This example only reads the MFT header. To get file names, sizes, or other metadata, you’ll need to parse the attribute records that follow the header (look up the
ATTRIBUTE_RECORDstructure for NTFS). - Safety Warning: Never write to the MFT unless you’re absolutely sure what you’re doing—incorrect modifications can corrupt your entire filesystem.
Alternatives for Non-Raw Access
If you only need basic file metadata (not deep NTFS analysis), use safer Win32 APIs like FindFirstFileExW or GetFileInformationByHandle instead. Direct MFT access is only necessary for forensic work, filesystem research, or advanced system tools.
内容的提问来源于stack exchange,提问作者Ori
相关产品推荐
相关产品推荐

