Fun with NTFS alternate data streams

| 3 minutes


NTFS (and also recent versions of ReFS) contains a feature called alternate data streams, which as the name implies allows you to associate multiple data streams with one filename. Nowadays this feature is mostly used for marking files downloaded from the internet, but there really is no restriction to what you can store in an alternate stream. So why don’t we use this feature to hide music “inside” a text file?

Creating the magical file

To create a new stream in a file (the file does not have to exist beforehand), use the below PowerShell snippet:

Add-Content 'path to file' -Stream 'stream name' -AsByteStream (Get-Content 'path to other file' -AsByteStream -ReadCount 0)

To list all the streams of a file, use the below PowerShell snippet:

Get-Item 'file' -Stream *

To get a specific stream, just substitute the asterisk with your desired stream name. If you ran the Add-Content snippet correctly, you should see the default stream with an empty name, as well as one with the name of your newly added one.

Accessing the hidden music

Accessing the hidden data is the most difficult part. In theory, it is as simple as using the filename:stream syntax, but in practise, most programs including Windows Explorer and the open dialog only use the default data stream and will not let you open any alternate ones. Luckily, for our desired usecase the solution is quite simple: m3u playlists. They are dead simple to write by hand and programmatically. For example, assuming you wish to use a stream called magic, all you need to write in a playlist file is the following line:

[full path to file]:magic

Note that relative paths cannot be used for this based on my testing.

Fruits of our labor

foobar2000 showing our album hidden in alternate data streams The text file looks normal on first glance, but opening our m3u playlist in foobar2000 reveals that we have an entire hidden album that is fully playable using our playlist file! The only clue the average user has is the size on disk being much larger in Explorer, as it only reads the default stream for the size measurement: Properties showing size on disk being massively larger than the size The size on disk value shows that our “4 byte” file is in reality taking 570 MB on disk!

Conclusion

While alternate data streams are quite neat, ultimately they really shouldn’t be used this way for serious purposes. You risk data loss if you move a file with them to an unsupported filesystem or use a program that might discard them either intentionally or unintentionally.

Bonus scripts!

While it’s certainly not the most robust thing in the world, this script allows you to add new streams in a much friendlier way. It also includes code for automatically generating a playlist if the PlaylistName option is specified.

param (
    [Parameter(Position=0,mandatory)]
    [string] $File = "",
    [Parameter(Position=1,mandatory)]
    [string] $FileToAdd = "",
    [Parameter(Position=2,mandatory)]
    [string] $Stream = "",
    [Parameter(Position=3)]
    [string] $PlaylistName = ""
)

Add-Content $File -Stream $Stream -AsByteStream (Get-Content $FileToAdd -AsByteStream -ReadCount 0)

if ($PlaylistName -ne "") {
    # default stream should be skipped as we are not interested in it
    $streams = (Get-Item $File -Stream * | Where-Object {$_.Stream -ne ':$DATA'}).Stream
    $streams | ForEach-Object {
        "$PWD\${File}:$PSItem"
    } | Out-File "$PlaylistName.m3u"
}

I used the below one-liner to add a whole album as alternate streams (assumes above script is saved as Add-Ads.ps1 in PATH):

Get-ChildItem 'path of album' | ForEach-Object { Add-Ads -File 'file name' -FileToAdd $PSItem -Stream $PSItem.Name -PlaylistName 'playlist name' }