Eye Describe Anatomy

NTFS Master File Table — Total Binary Dissection

Logical mapping of the 1024-byte FILE record, its attribute headers, and the four most forensically-loaded attributes: $STANDARD_INFORMATION, $FILE_NAME, $DATA, and $ATTRIBUTE_LIST.

Anatomy Component Map — How They Fit Together

The MFT Record — each file's current on-disk state
On-disk location: C:\$MFT · one fixed-size FILE record per file / directory
Holds: FILE Header, USA, $STANDARD_INFORMATION, $FILE_NAME, $DATA, end sentinel, slack.
Slot size1024 Bfixed

An MFT entry is always exactly 1024 bytes on standard NTFS volumes (4096 on large-cluster formats). The first 48 bytes are a kernel-managed FILE Record Header (NTFS 3.1) ending at 0x2F, followed by an Update Sequence Array (USA) at 0x300x37 (USN + 2 fixups + 2 B align). The first attribute begins at offset 0x38 (per the header's First Attribute Offset field) and a stream of typed, 8-byte-aligned attributes follows in canonical order: $STANDARD_INFORMATION$FILE_NAME$DATA → … until a 0xFFFFFFFF sentinel marks end-of-attributes. Everything past that point is record slack. The bar below maps that 1024 B slot — drawn to true byte proportions on a wide canvas so every band stays readable. Scroll horizontally to traverse the full record; click any band to jump to its byte-level tab.

OFFSET 0x000 FILE RECORD — full 1024 B, drawn to scale 0x400 (1024)
scroll horizontally to read every band — record slack is huge
FILE Header 48 B 0x00–0x2F
USA 8 B (USN + 2 fixups + align) 0x30–0x37
$STANDARD_INFORMATION (type 0x10) 24 hdr + 72 content = 96 B 0x38–0x97
$FILE_NAME (type 0x30) 24 hdr + 80 content ≈ 104 B 0x98–0xFF
$DATA resident (type 0x80) 24 hdr + inline content ≈ 40 B 0x100–0x127
END 0xFFFFFFFF 0x128–0x12B
Record Slack — tombstone residue ~724 B 0x12C–0x3FF
Drawn to actual byte proportions on a wide canvas so every band — even the 4 B END marker — stays fully readable. Scroll right to see all of the ~708 B record slack: most of every MFT record is leftover space from whatever file previously occupied the slot. Colours match the dissection map below.
FILE Header (blue — kernel bookkeeping)
USA (green — integrity fixup)
$SI (cyan — mutable timestamps)
$FN (amber — name + parent ref)
$DATA (green — file content / runlist)
END (purple — 0xFFFFFFFF sentinel)
Record Slack (tombstone residue)
Full Record
1024 bytes · mandatory
What: The entire FILE record — one fixed-size slot in the MFT for one file or directory.
WhyGives every NTFS object a predictable, addressable home. The MFT is just an array of these slots, indexed by record number.
WhenAlways — every file, directory, system file, even deleted entries (with the IN_USE bit cleared).
FILE Header
48 B + 8 B USA · mandatory
What: The fixed 48-byte slab at the top of every record. Carries "FILE" magic, sequence number, hardlink count, in-use / directory flags, and the offset of the first attribute.
WhyThe kernel needs a deterministic place to find "is this slot live?", "where do attributes start?", and "what record number am I?". The Update Sequence Array protects against torn writes.
WhenAlways at offset 0 of every record. Even a wiped slot keeps the magic if only the IN_USE flag was cleared.
$STANDARD_INFORMATION
96 B (24 hdr + 72 content) · mandatory
What: The four MAC(b) timestamps, the DOS-era file-attribute flags, and (NTFS 3.0+) the owner_id, security_id, quota, and USN.
WhyHolds the metadata Windows shows in Explorer's "Properties" dialog. This is the timestamp set that SetFileTime() writes to — and the one timestomping tools target.
WhenEvery base record. Always the first attribute (type 0x10).
$FILE_NAME
~104 B (24 hdr + 80 content) · can repeat
What: The filename (UTF-16LE), the parent directory's MFT reference, and a second independent set of four MAC(b) timestamps used by NTFS for index-key updates.
WhyThe parent directory keeps a B+tree index keyed by filename — it needs a copy of the name + size + timestamps right next to the entry. Updated only on rename / move, which is what makes it timestomping-resistant.
WhenEvery base record. Multiple copies exist for hard-linked files (one per link) and 8.3 short-name files (one Win32, one DOS).
$DATA (resident)
~24 B hdr + content · small files only
What: The actual file bytes, stored inside the MFT record next to the metadata.
WhyAvoids allocating a whole 4 KB cluster for tiny files. A single disk read fetches both the metadata and the content. Common for shortcut hashes, registry stub files, log fragments, named-pipe tokens.
WhenWhen the file content fits in the leftover ~700 B of the record after the other attributes. Triggered automatically by NTFS — user has no control.
$DATA (non-resident)
~64 B hdr + runlist · large files
What: A 64-byte non-resident header (allocated/real/initialized sizes + VCN range) followed by a compact cluster runlist — pairs of (length, LCN delta) telling the kernel where to find the file's bytes on disk.
WhyFiles larger than the record's spare bytes can't live inline. The runlist is extremely compact (a single contiguous file = one 8-byte run), so even multi-GB files have tiny $DATA attributes.
WhenMost files larger than ~700 B. Multiple $DATA attributes on one record = Alternate Data Streams (ADS), each named.
The MFT (above) and the USN Journal (below) are two separate files on the volume
Join key FileReferenceNumber 1 MFT record  :  N USN events
Pivot from any USN event back to the live MFT record (or its parent directory) by matching FRN

Companion Artifact — The USN Journal

The USN Journal — the history of every change that produced that state
On-disk location: C:\$Extend\$UsnJrnl:$J · one sparse stream for the whole volume
Holds: a continuous log of variable-length USN_RECORD_V2 entries (FRN, parent FRN, reason flags, FILETIME, filename).
Record sizevariable~60–120 B

This is a completely separate file from $MFT. The MFT box above shows you the current state of a file (what it looks like right now); this box shows you the history — every FILE_CREATE, rename, attribute write, and security change, with a precise FILETIME on each event. The two are joined on FRN: a BASIC_INFO_CHANGE reason always corresponds to a write into the $STANDARD_INFORMATION band above; RENAME_OLD_NAME / RENAME_NEW_NAME always corresponds to a rewrite of the $FILE_NAME band above.

USN Journal — companion change log (opens USN Anatomy →)
Lives in \$Extend\$UsnJrnl:$J · not inside the FILE record
What: A separate sparse stream of variable-length USN_RECORD_V2 entries that records every change made to the files described above. Where the MFT shows you the current state, the USN journal shows you the history of state transitions — with a precise FILETIME on every event.
WhyA FILE record can only carry the last values of its attributes. The USN journal preserves the full sequence — every FILE_CREATE, every rename, every BASIC_INFO_CHANGE (timestamp / attribute write), every SECURITY_CHANGE, every CLOSE — so investigators can reconstruct exactly how a file got into its current shape.
JoinEach USN_RECORD carries a FileReferenceNumber (the same MFT entry/sequence pair embedded in the FILE Header above) and a ParentFileReferenceNumber (the same pair stored inside $FILE_NAME). FRN is the universal pivot — one MFT record ↔ many USN events.
WhenDefault-on for the system volume since Windows Vista. Off by default for non-system NTFS volumes; can be enabled with fsutil usn createjournal. Older entries are continuously discarded as the sparse stream's allocated region wraps.
Full Record
FILE Header
$STANDARD_INFORMATION
$FILE_NAME
$DATA (Resident)
$DATA (Non-Resident)
Full FILE record overview (320-byte slice)
Live Byte Selection

Select any field in the map to reveal a deep forensic dive.

The Master File Table — NTFS's Family Tree

NTFS does not store files in a directory tree the way FAT does. Every file and every directory on an NTFS volume is just a row in a giant database called the Master File Table. Even the MFT itself is a row in the MFT (record 0, $MFT). Even the root directory is a row (record 5, "."). Even the volume label, the security descriptor pool, and the bad-cluster list are rows.

Each row is a 1024-byte FILE record beginning with the ASCII magic FILE. The record header is followed by a stream of attributes — small typed structures that describe one facet of the file each. Three attributes appear in nearly every record an investigator cares about: $STANDARD_INFORMATION (timestamps + flags), $FILE_NAME (the filename + parent reference + a second timestamp set), and $DATA (the actual file content, either resident inside the record or pointed at by runlist extents on disk).

When the attributes for one file no longer fit in 1024 bytes — large directories, files with hundreds of alternate data streams, or heavily fragmented files — NTFS spills them into extension records tracked by a fourth attribute, $ATTRIBUTE_LIST. Crow-Eye's MFT_Claw parser walks every record sequentially, dispatches by attribute type, and reconstructs full paths by chasing each $FILE_NAME entry's parent reference back to record 5.

How the MFT Works — Kernel-Level Bookkeeping

At volume format time, NTFS reserves an MFT Zone — by default about 12.5% of the volume — for the MFT to grow into without fragmenting. The first 16 records (0–15) are reserved for NTFS metadata files. Records 16 and beyond hold user files and directories.

The lifecycle of a single FILE record:

  1. Allocation. When a new file is created, NTFS finds a free record slot (tracked by the $Bitmap attribute on the MFT itself) and writes a fresh FILE header with the in-use flag set.
  2. Attribute population. The kernel writes $STANDARD_INFORMATION (four FILETIMEs, file-attribute flags) and $FILE_NAME (parent reference, name, second FILETIME set) immediately. If the file has data, a $DATA attribute follows — resident if the data fits in the remaining bytes of the record, non-resident (with cluster runlists) if it doesn't.
  3. Updates. Each metadata change increments the record's $LogFile Sequence Number (LSN) and updates the $SI "entry changed" timestamp. The on-disk update is fixed up at write time by the Update Sequence Array (USA) — a 2-byte signature is interleaved into every 512-byte sector so torn writes can be detected.
  4. Deletion. When the file is deleted, only the in-use flag (bit 0 of record flags) is cleared. The attributes, filename, timestamps, and parent pointer all remain intact. This is why MFT analysis recovers so much forensic value from deleted files — the record is essentially a tombstone with full metadata.
  5. Reuse. The next file created in that slot increments the record's sequence number and overwrites the attributes. Cross-checking the sequence number is how NTFS detects stale references.

Every $FILE_NAME attribute embeds its parent directory as an 8-byte MFT reference: the lower 48 bits are the parent's MFT entry number, the upper 16 bits are the parent's sequence number. By chasing parent references record-by-record back to entry 5 (the root), Crow-Eye reconstructs full paths even for deleted files whose parent directory still exists.

NTFS Version History — When Did the MFT Reach Its Current Form?

Unlike many Windows artifacts, the on-disk MFT format has changed surprisingly little since 2001. Crow-Eye's parser handles the current format (NTFS 3.1) which has been stable from Windows XP through Windows 11.

JULY 1993 · NTFS 1.0
Windows NT 3.1 — NTFS ships
NTFS debuts as the native filesystem for Windows NT 3.1, replacing the older HPFS / FAT-only model. The fundamental design — everything-is-a-file, every file lives in the MFT, attributes describe everything — is laid down. Each FILE record is 1024 bytes, beginning with the magic FILE.
MAY 1995 · NTFS 1.1
Windows NT 3.51 — refinements
Compressed attributes are added (the 0x0001 bit in the resident-attribute flags). FILE record layout is unchanged.
JULY 1996 · NTFS 1.2
Windows NT 4.0 — security descriptors
$SECURITY_DESCRIPTOR attribute is added as a per-file ACL container. This is the last revision sometimes called "NTFS 4" by old documentation; the on-disk version byte is still 1.2.
FEBRUARY 2000 · NTFS 3.0
Windows 2000 — the big rewrite
Major expansion. Adds $OBJECT_ID, $REPARSE_POINT (symlinks, mount points, dedup, AppExecLinks), $EA / $EA_INFORMATION (extended attributes), $LOGGED_UTILITY_STREAM (used by EFS), disk quotas, sparse files, and the USN Journal. $STANDARD_INFORMATION grows from 48 to 72 bytes to hold owner_id, security_id, quota_charged, and usn.
OCTOBER 2001 · NTFS 3.1 — CURRENT
Windows XP through Windows 11
A single tweak: the FILE record header is extended with a 4-byte field at offset 0x2C holding the record's own MFT number. This lets forensic tools validate a record's expected location even when reading raw clusters. The format has not changed since — Crow-Eye's parser targets this version. Modern Windows ships 1.2 PB max volume size, optional 4096-byte FILE records on huge volumes, and transparent compression / deduplication on top, but the on-disk MFT record layout remains v3.1.

Key MFT Facts

Record size
1024 B
Standard FILE record. 4096 B on volumes with very large clusters (rare).
Magic / Signature
"FILE"
ASCII 0x46 0x49 0x4C 0x45 at offset 0. Carving anchor.
MFT Zone
12.5%
Reserved at format time for MFT growth. Reduces fragmentation.
System records
0 – 15
Reserved for NTFS metadata files ($MFT, $LogFile, etc.).
Attribute types
17
Defined attribute types from 0x10 ($SI) to 0x100 ($LOGGED_UTILITY_STREAM).
Timestamps per file
8
Four in $SI + four in $FN. The pair is the key to detecting timestomping.
Parent reference
48 + 16 bit
Lower 48 bits = parent MFT entry; upper 16 bits = parent sequence number.
End marker
0xFFFFFFFF
Sentinel that terminates the attribute stream inside a FILE record.

The First 16 MFT Records (System Files)

Reserved by NTFS at format time. Every NTFS volume has these records, every time.

Rec #FilenameRole
0$MFTThe MFT itself — its own DATA attribute is the table.
1$MFTMirrMirror of the first 4 records — recovery insurance.
2$LogFileTransaction log used by NTFS recovery (LSN source).
3$VolumeVolume name, NTFS version, dirty bit.
4$AttrDefDefinitions of every attribute type known to this volume.
5. (root)Root directory. All path reconstruction terminates here.
6$BitmapCluster allocation bitmap for the whole volume.
7$BootMaps the boot sector(s) as a file. First-stage bootloader lives here.
8$BadClusSparse map of bad clusters marked by chkdsk.
9$SecureShared security descriptor pool (since NTFS 3.0).
10$UpCaseUnicode uppercase mapping table for case-insensitive lookup.
11$ExtendContainer directory for $Quota, $ObjId, $Reparse, $UsnJrnl.
12–15reservedReserved for future Microsoft use; usually zero / unused.

All 17 Attribute Types

Every attribute begins with a 4-byte type code. Green rows are deep-parsed by Crow-Eye (timestamps decoded, paths extracted, GUIDs formatted). The remaining rows are still recognised and counted, but their content is opaque.

TypeNamePurpose
0x10$STANDARD_INFORMATION4 timestamps, file-attr flags, owner_id, security_id, USN.
0x20$ATTRIBUTE_LISTPointer to extension records when attributes overflow.
0x30$FILE_NAMEFilename + parent ref + 2nd timestamp set. Can appear multiple times.
0x40$OBJECT_ID128-bit globally-unique ID assigned to the file. Persisted as data_type='ObjectID'.
0x50$SECURITY_DESCRIPTORPer-file ACL. Mostly replaced by $Secure shared pool in 3.0+.
0x60$VOLUME_NAMEOnly on record 3 ($Volume) — the volume label. Persisted as data_type='VolumeName'.
0x70$VOLUME_INFORMATIONNTFS version + dirty bit + flags. Persisted as data_type='VolumeInfo'.
0x80$DATAThe file content. Unnamed = default stream; named = ADS (now correctly distinguished).
0x90$INDEX_ROOTRoot B+tree node for directories. Persisted as data_type='IndexRoot'.
0xA0$INDEX_ALLOCATIONNon-resident B+tree leaf clusters for large directories.
0xB0$BITMAPAllocation bitmap for indexes / the MFT itself.
0xC0$REPARSE_POINTSymlinks, mount points, dedup, AppExecLinks. Tag + target path extracted. data_type='Reparse:<Type>'.
0xD0$EA_INFORMATIONLength info for OS/2-style extended attributes. data_type='EaInfo'.
0xE0$EAOS/2 extended attribute data, walked entry-by-entry. data_type='EA'.
0xF0$PROPERTY_SETObsolete; never used in modern Windows.
0x100$LOGGED_UTILITY_STREAMEFS ($EFS) and TxF ($TXF_DATA) streams. data_type='LoggedUtilStream'.

Persistence Conventions — mft_data_attributes

Rather than alter the database schema, the enhanced parser packs the newly-parsed NTFS attributes into the existing mft_data_attributes table using a typed data_type convention. Existing consumers that filter on data_type IN ('Default','ADS','Zone.Identifier',…) are unaffected; new analyses can pivot on the additional types below.

data_typeattribute_namesizeMeaning
Default'' (empty)stream bytesThe file's default unnamed $DATA stream.
ADSADS stream namestream bytesGeneric named $DATA (Alternate Data Stream).
Zone.IdentifierZone.Identifierstream bytesMark-of-the-Web ADS — proves origin URL of downloaded files.
Thumbnail / Encryptednamestream bytesOther well-known ADS variants.
ObjectIDGUID {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}16+Decoded $OBJECT_ID primary GUID.
Reparse:Symlinksubstitute pathtag (0xA000000C)$REPARSE_POINT tag 0xA000000C — Windows symbolic link.
Reparse:MountPointsubstitute pathtag (0xA0000003)NTFS junction or volume mount.
Reparse:AppExecLinktarget exe pathtag (0x8000001B)UWP execution alias (e.g. winget.exe in WindowsApps).
Reparse:Dedup(empty)tag (0x80000013)Data Deduplication chunk-store reference.
VolumeNamevolume labelbytesFrom record 3 ($Volume).
VolumeInfoNTFS 3.1 flags=0x...flag bitmaskNTFS major.minor version + dirty bit.
EaInfocount=N packed=X unpacked=Ypacked_ea_sizeSummary of OS/2 extended attributes attached to the file.
EAcomma-joined EA namesea countWalked $EA entry list. Common: $KERNEL.PURGE.*.
IndexRootindex stream name ($I30, $O, …)attr sizeDirectory B+tree root or other index. Multiple rows per record.
LoggedUtilStreamstream name ($EFS, $TXF_DATA)attr sizeEFS-encrypted files or transactional NTFS streams.
Hardlinkshardlinks=NNOnly emitted when hardlink count > 1 — surfaces hard-linked DLLs.
ExtensionOfbase_rec=NNThis record is an extension of base record N (via $ATTRIBUTE_LIST).

The schema is the same 4-table layout introduced with the original parser (mft_records, mft_standard_info, mft_file_names, mft_data_attributes). Existing databases gain richer rows on next parse; no migration needed.

Full Logical Dissection Reference

Offset Size Field Name Forensic Meaning & Value

$STANDARD_INFORMATION Flags (0x20)

MaskFlagForensic Meaning
0x0001Read-onlyCommon but trivially flippable; rarely indicative.
0x0002HiddenOften set on system / staged adversary payloads.
0x0004SystemCombined with Hidden = classic dropper hiding pattern.
0x0020ArchiveSet by writes; cleared by backup utilities.
0x0040DeviceInternal NTFS use.
0x0080Normal"No other attributes set" — mutually exclusive with everything.
0x0100TemporaryMarked for deletion at close; suspicious if persisting.
0x0200SparseSparse file (only allocated where non-zero).
0x0400Reparse PointFile has a $REPARSE_POINT attribute — symlink / mount / dedup.
0x0800CompressedNTFS LZ77 compression on the data stream.
0x1000OfflineStored remotely; HSM dehydration in progress.
0x2000Not IndexedExcluded from content indexing.
0x4000EncryptedEFS-encrypted data stream.

$FILE_NAME Namespaces (byte 0x41)

A single file can have multiple $FILE_NAME attributes — one per namespace. Crow-Eye prefers the non-DOS name when picking the primary filename.

ValueNamespaceDescription
0POSIXCase-sensitive, allows any Unicode except / and NUL.
1Win32Case-insensitive; the long filename most users see.
2DOS (8.3)Legacy short name (PROGRA~1 style). Auto-generated.
3Win32 & DOSSingle name compatible with both spaces (e.g. readme.txt).

Reparse Point Tags ($REPARSE_POINT 0xC0)

Crow-Eye recognises these explicitly. The tag is the first 4 bytes of the reparse data.

TagTypeInvestigative Note
0xA0000003Mount PointJunction or volume mount — expands to a different MFT.
0xA000000CSymbolic LinkTrue Windows symlink (admin-only creation by default).
0x80000013DedupData Deduplication chunk store reference.
0x8000001BAppExecLinkUWP app execution alias (e.g. winget.exe in WindowsApps).

FILE Record Flags (header offset 0x16)

BitMeaningForensic Use
0x0001IN_USESet when the record is allocated to a live file. Cleared on delete — the rest of the record persists.
0x0002IS_DIRECTORYRecord describes a directory (uses $INDEX_ROOT / $INDEX_ALLOCATION).
0x0004IS_EXTENSIONRecord is a continuation of another record's attribute list.
0x0008SPECIAL_INDEXSpecial index present (rare; view-index style).

Anti-Forensics & APT Techniques

How sophisticated adversaries try to defeat MFT-based evidence — and how an investigator catches each play:

TechniqueIndicator in the MFTCounter-detection
Timestomping ($SI only) The four $STANDARD_INFORMATION timestamps are rewritten to backdate a dropped binary, but the four $FILE_NAME timestamps still reflect creation reality. Cross-check $SI vs $FN. The kernel updates $FN only on rename/move — if $SI says "2019" but $FN says "yesterday", the file was timestomped. Crow-Eye exposes both sets in mft_standard_info and mft_file_names.
Alternate Data Stream payloads A binary blob hidden in a named $DATA stream on an innocent-looking host file (notes.txt:evil.exe). Default browsing tools never show ADS. Crow-Eye flags every record with has_ads = 1 and counts ADS in ads_count. The named streams are itemised in mft_data_attributes with data_type IN ('ADS','Zone.Identifier','ObjectID','Thumbnail').
FILE record zeroing An adversary wipes the entire 1024-byte record after deleting the file, removing the in-use flag and the metadata. Hard to defeat directly — but the parent directory's $INDEX_ROOT / $INDEX_ALLOCATION may still hold the filename. $MFTMirr (record 1) preserves the first 4 records even if $MFT is tampered with.
Slack-space residue The allocated MFT clusters are larger than the logical $MFT size — the trailing slack contains old FILE records from previous allocations. Crow-Eye's scan_slack_space_records() walks past the logical EOF and recovers every valid FILE-signature record in slack. These are flagged separately and can reveal deleted-then-overwritten activity.
Extension-record fragmentation Heavy ADS abuse or huge directories force the file's attributes to spill into extension records linked by $ATTRIBUTE_LIST. A naive parser sees only the base record and misses half the evidence. Crow-Eye's AttributeListParser reads every entry of $ATTRIBUTE_LIST, lists the extension record numbers, and records them in MFTRecord.extension_records so the analyst can follow the chain.
Sequence-number reuse An adversary deletes a file, then creates one in the same MFT slot — references to the old file (in $FILE_NAME parent pointers, USN journal, prefetch) now resolve to a totally different binary. The 16-bit sequence number in every MFT reference increments on reuse. Compare the sequence number in the reference against the live record's sequence number — a mismatch proves slot reuse.
USA / fixup forgery Attempts to forge a FILE record on disk fail to update the Update Sequence Array correctly — the 2-byte sector signatures at offsets 0x1FE, 0x3FE don't match the USN at the top of the USA. Validate the USA: the last 2 bytes of every 512-byte sector inside the record should equal the first 2 bytes of the USA (the USN). Mismatches are evidence of crafted records or torn writes.
From reading to doing

Parse the whole $MFT with Crow-Eye

Crow-Eye reads $MFT records across the volume — comparing $STANDARD_INFORMATION vs $FILE_NAME timestamps to flag timestomping, and recovering resident data, alternate data streams, and parent-child paths.

Download Crow-Eye