Fun With NTFS Alternate Data Streams

Are you familiar with the feature of NTFS called Alternate Data Streams? Our typical usage of files is pretty simple. We double click it and it opens. But  by default we are only accessing the “default” data stream. We can write to multiple data streams, effectively storing multiple files in a single file. These alternate streams are generally hidden, but we can see them and even write to them. I’ll show  you how to do it from the command line and from C#.

Even if you have never heard of this feature, you have probably used it. On Windows, when you download a file the OS automatically writes the Internet Zone that the file came from to an alternate stream. This is what you manipulate with the “Unblock” checkbox:


You can view the details of the stream with a simple dir command that shows the stream name and number of bytes it contains:

dir /R

zoneid And, you can view the data with notepad by specifying the file name with its Alternate Data Stream:

notepad "DotNetCore.1.0.0-VS2015Tools.Preview2.exe:Zone.Identifier"


Writing text to an Alternate Data Stream is pretty simple. The command line supports this, all you have to do is provide the name you want to give the stream:

echo I'm writing a new stream ! > someExistingFile.txt:YourNameChoiceHere

That’s pretty interesting in itself, but we are not limited to writing text. We can write any data. The following C# program will write text to the default stream, an image to one alternate stream and finally a PDF to another. Unfortunately C# doesn’t have native support for this so we have to p/Invoke a bit:

using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace AlternateDataStreams
class Program
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
IntPtr lpSecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
static void Main(string[] args)
string basePath = @"c:\Users\tekhe\temp\";
string baseFile = "funwithfiles.txt";
//First create a vanilla text file
File.WriteAllText(Path.Combine(basePath, baseFile), "This is the normal, unnamed data stream.");
//Write an image to the ADS
CreateFileWithAlternateDataStream(basePath, baseFile, ":TheKitten", "kitten.jpg");
//Write a PDF to the ADS
CreateFileWithAlternateDataStream(basePath, baseFile, ":PDFSample", "pentest.pdf");
static void CreateFileWithAlternateDataStream(string basePath, string baseFile, string streamName, string fileToWrite)
var sfh = CreateFile(basePath + baseFile + streamName,
EFileAccess.GenericRead | EFileAccess.GenericWrite,
if (sfh.IsInvalid)
using (FileStream fs = new FileStream(sfh, FileAccess.Write))
byte[] filebytes = File.ReadAllBytes(Path.Combine(basePath, fileToWrite));
fs.Write(filebytes, 0, filebytes.Length);
enum EFileAccess : uint
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000
public enum EFileShare : uint
None = 0x00000000,
Read = 0x00000001,
Write = 0x00000002,
Delete = 0x00000004
public enum ECreationDisposition : uint
New = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5
public enum EFileAttributes : uint
Normal = 0x00000080

After running the program (be sure to edit you paths and files appropriately), the following 3 commands ….

c:\Users\tekhe\temp>"C:\Program Files (x86)\Foxit Software\Foxit Reader\FoxitReader.exe" funwithfiles.txt:PDFSample

c:\Users\tekhe\temp>notepad funwithfiles.txt

c:\Users\tekhe\temp>mspaint funwithfiles.txt:TheKitten

… open the following files, read from the default and Alternate Data Streams:



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s