NTFS Alternate Data Streams (ADS)
1️⃣ 什麼是 ADS
ADS (Alternate Data Stream) 是 NTFS 檔案系統的功能,允許檔案擁有多個資料流(data stream)。
每個檔案都有主資料流(默認內容),ADS 是附加的隱藏資料流。
特性:
普通檔案列表 (
dir或Directory.GetFiles) 不會列出 ADS。檔案總管即使開啟「顯示隱藏檔案」也看不到 ADS。
需特定工具查看:
CMD:
dir /rPowerShell:
Get-Item -Stream *
2️⃣ 建立 ADS
CMD 建立範例:
echo "這是 ADS 內容" > C:\Test\a.txt:hidden.txt
查看 ADS:
dir /r C:\Test
輸出示例:
a.txt
a.txt:hidden.txt:$DATA
3️⃣ 嘗試讀取 ADS
3.1 CMD 嘗試用 type 讀取
type C:\Test\a.txt:hidden.txt
- 一定會失敗,一般命令行工具不支援 ADS。
3.2 C# 嘗試用高階 API 讀取
string content = File.ReadAllText(@"C:\Test\a.txt:hidden.txt");
會失敗,可能拋出:
System.NotSupportedException: 不支援指定的路徑格式或
路徑中有不合法的字元
原因:.NET 高階 API 對 ADS 支援不完全。
4️⃣ 用 Notepad / Windows API 讀取 ADS
4.1 用 Notepad 打開
打開 Notepad,輸入完整路徑:
C:\Test\a.txt:hidden.txtNotepad 可以正確打開,證明資料存在。
4.2 C# + Windows API CreateFile 讀取 ADS
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
const uint GENERIC_READ = 0x80000000;
const uint OPEN_EXISTING = 3;
const uint FILE_SHARE_READ = 0x00000001;
const uint FILE_SHARE_WRITE = 0x00000002;
static void Main()
{
string adsPath = @"C:\Test\a.txt:hidden.txt";
SafeFileHandle handle = CreateFile(
adsPath,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
0,
IntPtr.Zero);
if (handle.IsInvalid)
{
Console.WriteLine("無法打開 ADS,錯誤碼: " + Marshal.GetLastWin32Error());
return;
}
using (FileStream fs = new FileStream(handle, FileAccess.Read))
using (StreamReader reader = new StreamReader(fs))
{
string content = reader.ReadToEnd();
Console.WriteLine("ADS 內容: " + content);
}
}
}
說明:
ADS 路徑格式:
檔案完整路徑:ADS名稱(不要加:$DATA)。需要 NTFS 檔案系統。
這種方式可以完整讀取 ADS。
5️⃣ 列出資料夾中所有檔案及其 ADS
Windows API FindFirstStreamW / FindNextStreamW 範例
using System;
using System.IO;
using System.Runtime.InteropServices;
class Program
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct WIN32_FIND_STREAM_DATA
{
public long StreamSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 296)]
public string cStreamName;
}
enum STREAM_INFO_LEVELS
{
FindStreamInfoStandard = 0
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindFirstStreamW(
string lpFileName,
STREAM_INFO_LEVELS InfoLevel,
out WIN32_FIND_STREAM_DATA lpFindStreamData,
uint dwFlags);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern bool FindNextStreamW(
IntPtr hFindStream,
out WIN32_FIND_STREAM_DATA lpFindStreamData);
[DllImport("kernel32.dll")]
static extern bool FindClose(IntPtr hFindStream);
static void Main()
{
string folder = @"C:\Test";
foreach (var file in Directory.GetFiles(folder))
{
Console.WriteLine("檔案: " + file);
WIN32_FIND_STREAM_DATA streamData;
IntPtr hFind = FindFirstStreamW(file, STREAM_INFO_LEVELS.FindStreamInfoStandard, out streamData, 0);
if (hFind != IntPtr.Zero)
{
do
{
Console.WriteLine(" ADS: " + streamData.cStreamName + " (" + streamData.StreamSize + " bytes)");
} while (FindNextStreamW(hFind, out streamData));
FindClose(hFind);
}
}
}
}
說明:
專門用於列出檔案的 ADS。
可列出整個資料夾下每個檔案的所有 ADS(類似
dir /r)。可結合前面 Windows API 讀取方式,讀出 ADS 內容。
✅ 總結
ADS 是 NTFS 隱藏資料流,一般工具無法看到。
建立與查看:
CMD:
echo "內容" > file.txt:adsname查看:
dir /r或 PowerShellGet-Item -Stream *
讀取:
高階 API (
File.ReadAllText) 無法讀取。Notepad 可以打開。
C# 需使用 Windows API (
CreateFile)。
列出資料夾所有 ADS:
使用 Windows API
FindFirstStreamW/FindNextStreamW。可搭配
FileStream讀取內容。
