NTFS lets a file have more than one $DATA attribute. The first one is unnamed and holds the file's main contents. Any additional $DATA attribute is named and acts as a parallel stream attached to the same file. These extra streams are Alternate Data Streams (ADS).
The syntax
You can read and write ADS from PowerShell or cmd:
echo hidden text > notes.txt:secret
type notes.txt:secret
notes.txt looks empty in Explorer and dir — its primary $DATA is zero bytes. But the named secret stream holds your text. From a user's perspective the file behaves normally; the alternate stream rides along.
Where you legitimately see ADS
Windows uses ADS for its own bookkeeping. The most common one is Zone.Identifier, attached to every file downloaded from the internet. It carries a short text block describing the origin URL and security zone. This is what triggers the "this file came from another computer" warning.
Other legitimate uses include:
$KSPfor keyboard layout filesOECustomPropertyfor Outlook attachments- Various thumbnail and search-index streams
Why attackers like ADS
Anything that lives off the main stream tends to be invisible to:
- Folder views that show only file sizes (sizes are reported for the unnamed stream)
- Antivirus engines that scan only the default stream
- Manual review by an analyst who has not asked for streams explicitly
A common pattern is dropping a payload into legit-document.docx:payload.exe and launching it via WMI. The file looks like a Word document and stays that way until you ask the right questions.
Detecting them
dir /R lists every stream on every file in a directory. The output shows the stream size next to the named stream:
1,234,567 legit-document.docx
45,056 legit-document.docx:payload.exe:$DATA
PowerShell offers the cleaner equivalent:
Get-Item legit-document.docx -Stream *
Why $MFT is the better lens
Individual file enumeration can miss streams that exist on files you did not think to scan. $MFT does not have this problem: every attribute is right there in the record. Walking the MFT and listing each entry's $DATA attributes — both named and unnamed — gives you a complete inventory of every stream on the volume in one pass.
For triage, that is the difference between "I'd better remember to check ADS" and "I already checked every one."