В системах семейства Windows NT есть малоизвестная функция, которая позволяет скрывать какую-либо информацию. Называется она альтернативные потоки данных NTFS (далее АПД). АПД позволяют добавить к любому файлу или папке информацию, которая будет не видна при обычном просмотре. Это обусловлено тем, что файл NTFS состоит из потоков данных и в обычных условиях вы видите только один, основной поток данных. При этом альтернативный поток невидим, хотя в нем может содержаться информация. В тоже время операционная система никак не оповещает пользователя, что в файле есть альтернативный поток. Некоторые программы используют эту возможность для хранения служебной информации, касающейся этого файла, а хакеры организовывают атаки.
Данные, записанные в альтернативный поток, влияют на размер файла, т.к. они записаны в файл. Логично. В Windows XP это хорошо видно в свойствах файла, но Vista и Windows 7 почему-то не показывают размер с учетом содержания двух потоков.
Чтобы лучше понять вышеописанное, давайте перейдем к практике. Сначала поработаем в консоли. Создайте текстовый файл (например example.txt) и введите в него какую-либо информацию. Запустите консоль… Вы должны находиться в этой же папке, где находится файл. Выполните следующую команду:
1 |
echo hello world > example.txt:hwstream |
С помощью команды echo и > вводим в файл запись «hello world», при этом через двоеточие даем название альтернативному потоку. В нашем случае поток называется hwstream.
Посмотреть что находится в потоке hwstream можно так:
1 |
more < example.txt:hwstream |
Таким образом записывается текстовая информация. Для того, чтобы записать другой тип данных, нужно использовать команду type:
1 |
type calc.exe > example.txt:calc |
После выполнения данной команды, в файле example.txt записан калькулятор, который можно запустить так:
1 |
start .\example.txt:calc |
Еще пример с записью видео файла и последующего его открытия:
1 |
"C:\Program Files\Windows Media Player\wmplayer.exe" "example.txt:Просто какое-то название" |
Теперь перейдем к C#. Стандартные функции библиотеки .NET не позволяют реализовать запись и чтение данных в альтернативном потоке. Для этого будем использовать функции WinApi – ReadFile, CreateFile и WriteFile.
Следующие два метода реализуют чтение и запись текста в альтернативный поток.
4 |
/// <param name="file">Имя файла</param> |
5 |
/// <param name="stream">Название потока</param> |
6 |
/// <returns>Данные потока</returns> |
7 |
public string ReadFromFile( string file, string stream) |
9 |
uint fHandle = CreateFile(file + ":" + stream, GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero); |
10 |
if (fHandle != uint .MaxValue) |
12 |
uint size = GetFileSize(fHandle, IntPtr.Zero); |
13 |
byte [] buffer = new byte [size]; |
14 |
uint read = uint .MinValue; |
16 |
uint result = ReadFile(fHandle, buffer, size, ref read, IntPtr.Zero); |
19 |
return System.Text.Encoding.Default.GetString(buffer); |
28 |
/// <param name="text">Текст, который нужно вставить</param> |
29 |
/// <param name="fileName">Имя файла</param> |
30 |
/// <param name="stream">Имя потока</param> |
31 |
/// <returns></returns> |
32 |
public uint WriteToFile( string text, string fileName, string stream) |
34 |
byte [] barData = System.Text.Encoding.Default.GetBytes(text); |
37 |
uint fHandle = CreateFile(fileName + ":" + stream, GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, CREATE_ALWAYS, 0, IntPtr.Zero); |
39 |
bool bOK = WriteFile(fHandle, barData, ( uint )barData.Length, ref nReturn, IntPtr.Zero); |
43 |
MessageBox.Show( "Не удалось записать в файл " + System.Runtime.InteropServices.Marshal.GetLastWin32Error()); |
Для статьи я создал тестовый проект, который наглядно показывает как это все дело можно реализовать с помощью C#.
Для выявления альтернативного потока в файле, существует ряд утилит, которые показывают что и где находится (от Sysinternals).