2013年12月10日 星期二

Manipulating NTFS alternate data streams in C# with the CodeFluent Runtime Client

Have you already heard about NTFS alternate streams? Also known as named streams or ADS (Alternate Data Streams).
Well it is a useful feature in NTFS storage systems. It expands the concept of file and data streams.
Alternate Data Streams
Alternate Data Streams
When working with NTFS files, the main data stream (or unnamed stream) is the central element of the file. When you create a file, a main stream is created. When you create an alternate stream and the main stream does not exist it is created, if you delete the main stream the whole file is deleted (so the existing alternate streams).
When you read a file or you write in to a file you are working with the main stream by default.
Alternate streams follows the syntax: “filename.ext:alternateName”
You can store any kind of data in an ADS (as you can do it with the unnamed stream), so you can store binary data, text data, an image, a video and even an executable file.
Let’s make quick test.
Open a command line console (cmd.exe).
Create a text file and write some content in it:
Writing in to the main data stream
Writing in to the main data stream
Let’s read the content:
Reading the main stream
Reading the main stream
Nothing extraordinary, we get the main data stream from our file.
Now let’s try to write in to an alternate data stream (this will create the alternate stream if it does not exist).
Writing in to an Alternate Data Stream
Writing in to an Alternate Data Stream
You have created an alternate data stream called “hide” right on our file “test.txt”, this will not have any incidence with your main data stream.
To ensure that our alternate data stream “hide” has been correctly created we will try to read it.
Reading an Alternate Data Stream content
Reading an Alternate Data Stream content
And to prove that our main data stream is still there, let’s read the main stream.
Reading the main stream
Reading the main stream
We have made some tests only with “text” streams but a stream can be also an image, an executable file and all other kind of stream a file container can host.
What about manipulating Alternate Data Streams with C#? 
Well, this feature is unfortunately not available in .NET, we would need to call native methods if we want to manipulate alternate data streams.
So we can build some nice native method wrappers in order to manipulate alternate data streams or we can use the CodeFluent Entities Runtime Client.
CodeFluent Runtime Client is a free library that provides very useful and powerful helpers like:
  • XML utilities
  • IO utilities
  • Type conversion helpers
  • JSON utilities
  • … and many other
You can easily install the CodeFluent Runtime Client from Nugget.
PM> Install-package CodeFluentRuntimeClient
Using the CodeFluent Entities Client Runtime to manipulate alternate data streams is as easy as manipulate all well-known file streams.
We will use the NtfsAlternateStream class which is located in theCodeFluent.Runtime.BinaryServices namespace, it provides some static helper methods to manipulate alternate streams as they were “regular” streams (open, create, read, write, enumerate, delete…).
Let’s take a look to some useful methods to manipulate alternate data streams (ADS):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Create a stream supporting ADS syntax
FileStream stream = NtfsAlternateStream.Open("test.txt:hide", FileAccess.Write, FileMode.OpenOrCreate, FileShare.None);
stream.Close();
 
//Writing in to an ADS
NtfsAlternateStream.WriteAllText("test.txt:hide", "Secret content");
 
//Reading data from an ADS
string text = NtfsAlternateStream.ReadAllText("test.txt:hide");
 
//Enumerating all the ADS in test.txt
IEnumerable adsStreams = NtfsAlternateStream.EnumerateStreams("test.txt");
foreach (NtfsAlternateStream ads in adsStreams)
{
    Console.WriteLine(ads.Name);
}
 
//This will not delete the test.txt file
NtfsAlternateStream.Delete("test.txt:hide");
A concrete example of how ADS are used in Windows is when you download a file from the Internet. When I open a file downloaded from the Internet with Word (2013) I receive a warning telling me that the file might not be secure.
Word Protected View
Word Protected View
How does Word know that I downloaded the file from the Internet? Well, every time you download a file, Windows set an ADS called “:Zone.Identifier” containing some data related to the origin of the file. Let’s confirm that.
1
2
3
string altFileName = @"C:\Users\pablo\Downloads\someDoc.docx:Zone.Identifier";
string content = NtfsAlternateStream.ReadAllText(altFileName);
Console.WriteLine(content);
What we get is:
ZoneTransfer ZoneId
ZoneTransfer ZoneId
This value “ZoneId=3” means that the file has “Internet” as origin.
If we delete the “:Zone.Identifier” ADS from the file:
1
2
3
string altFileName = @"C:\Users\pablo\Downloads\someDoc.docx:Zone.Identifier";
//this will not delete the file
NtfsAlternateStream.Delete(altFileName);
Now we don’t receive a warning when trying to open the file, Word has no information from the file origin.
Alternate data streams are nice but they have some limitations. As we have said, ADS are only supported in NTFS file storage systems so what happen if you copy a file containing ADSs to another file system (FAT file system, USB drive, CD/DVD, network transfer…)? Well, you will lose all your ADS!
Avoid writing important or critical data to alternate data streams. ADS are not supported in not NTFS file systems.
Some ideas where ADS might be useful:
  • If you are writing a program to edit images it will be nice to keep the original image (or even all the modification history) so the user can undo some changes. Instead of keeping separate files you can write all the image versions in the same file using ADS, e.g.image.jpg:original, image.jpg:v1
  • You can store thumbnails for graphical files.
  • Imagine you wrote a “reader” application, you can keep some information like: font size, current page, background color… in the file itself.
I am sure you can image other practical and fun uses for Alternate Data Streams, it would be great if you share it with us Winking smile.
Regards.
Pablo Fernandez Duran

沒有留言:

張貼留言