← Back to blog

Resident data: tiny files that live inside the MFT

· 5 min read

Every NTFS file has a $DATA attribute (type 0x80) holding its contents. For most files, $DATA is non-resident: the attribute header carries a runlist pointing to cluster runs elsewhere on the volume. For small files, the bytes live inline in the MFT record itself. That second case is one of the most useful artifacts in NTFS forensics, and it is the one I keep watching analysts forget.

How small is small enough

An MFT record is 1,024 bytes. From that you subtract the 56-byte header, the fixup array, $STANDARD_INFORMATION (around 72 bytes), at least one $FILE_NAME (variable, around 90 bytes for a typical name), padding, and the attribute end sentinel. What is left is the usable budget for resident $DATA and any other resident attributes.

In practice the threshold is roughly 700 bytes of data. Some references say up to ~750 bytes for files with very short names and no other resident attributes; some go lower (~580 bytes) for files with longer names or additional attributes. The threshold is not a constant; it depends on what else is in the record.

Files that fit, and which I see constantly:

  • Small text files: notes, todo lists, scratch drafts.
  • Small configuration files: .ini, .cfg, small .json, small .xml.
  • PowerShell one-liners and short scripts.
  • Small .lnk shortcut files (most LNKs are small enough; see LNK forensics for what they encode).
  • Registry export snippets and .reg files.
  • Small .bat and .cmd files.
  • Certificate files in PEM format that are short.
  • Empty files and zero-byte placeholders. The "data" is zero bytes, and $DATA is trivially resident.
  • Many $INDEX_ROOT attributes for small directories.

Why this matters

A resident $DATA attribute can be recovered without reading the rest of the disk. If you have a copy of $MFT, you already have:

  • The full contents of small text files.
  • Lots of $INDEX_ROOT data for directories (the directory's entries, listed inline).
  • Short alternate data streams (named $DATA attributes with small content).
  • Reparse points and symlink targets (the target path lives in $REPARSE_POINT, which is also typically resident).

That is a surprising amount of evidence inside a single 200 MB to 2 GB MFT extract. For deleted small files, the resident bytes survive even after the data area has been overwritten, because the data area was never touched in the first place; the bytes lived in the MFT.

I have recovered:

  • A 320-byte PowerShell loader from a deleted record whose data clusters never existed.
  • A 480-byte .lnk pointing at the attacker's staging directory, deleted three weeks before acquisition.
  • A 700-byte .config from a service that had been uninstalled. The directory was gone; the MFT record sat at slot 412,000 untouched.

The MFT was the only place those files still existed.

Resident is not stable

When a resident file grows past the record's free space, NTFS converts it to non-resident. The data moves out to clusters and $DATA becomes a runlist. The conversion is logged in $LogFile as the change happens.

The reverse can happen, technically (a file shrunk back below the threshold could become resident again), but Windows rarely does it voluntarily. Once $DATA is non-resident it tends to stay that way. If you find a record with resident $DATA for a file that you know was once larger, that is unusual and worth investigating; it suggests either deliberate manipulation or an uncommon code path that shrank the file in place.

Detecting resident data while parsing

Every MFT parser exposes a "resident" flag on the $DATA attribute header. MFTECmd's CSV output has it as a boolean column. mft_dump's JSON has header.is_resident. libmft exposes it on the attribute object. Sleuth Kit's istat shows it as part of the attribute listing.

The browser parser on this site filters for IN_USE=0 with resident $DATA in two clicks. That filter is the one I run first on any extracted MFT where small-file recovery matters.

What the bytes look like

For a resident $DATA, the attribute header is followed by a 16-byte resident header (content size, content offset, indexed flag, padding) and then the raw bytes. The bytes are exactly what was on disk in the file: text in whatever encoding the file used, binary content in its native form. No transformation.

For a small text file in UTF-8, you can copy the bytes out and read the file in any editor. For binary content (a small PE, a compiled .pyc, a serialized object), the bytes are equally usable; treat them as a file extracted from the volume.

The limits

Most files are not resident. On a normal Windows install, well under 5% of user files are resident. The rest are everything Office, every browser cache file, every program in \Program Files\, every download. Resident recovery is a high-value niche, not the default mode.

The threshold is not exact. Do not assume "files under 700 bytes are recoverable". The actual threshold depends on the record's other attributes. Test on the specific MFT you are analyzing.

Resident does not survive compression or encryption to a sufficiently-large file. EFS-encrypted files use $LOGGED_UTILITY_STREAM for the encryption metadata and the $DATA is the ciphertext. If the ciphertext is small enough to be resident, you have the encrypted bytes; you still need the EFS key to read them.

A workflow that uses this

The next time you have a deleted-file recovery case and the file you care about is small:

  1. Acquire $MFT from the host (or a VSS snapshot, if you have a recent one).
  2. Parse it. Pull every record where IN_USE=0 and the primary $DATA is resident.
  3. Filter by $FILE_NAME regex if you know the filename. Filter by parent reference if you know the directory.
  4. Inspect the resident $DATA bytes inline. The file is right there.

Five minutes of work for a recovery that signature carving would have taken hours on (and likely failed for small fragmented files anyway).

Further reading

  • The linux-ntfs project's resident attribute notes. Clear explanation of the resident header layout.
  • Microsoft, NTFS allocation algorithm. Official reference for how the resident/non-resident decision is made.
  • Sleuth Kit's istat for inspecting individual records and seeing the resident flag in context.

External resources