Skip to main content

Command Palette

Search for a command to run...

NTFS Alternate Data Streams (ADS)

Updated
3 min read

1️⃣ 什麼是 ADS

  • ADS (Alternate Data Stream) 是 NTFS 檔案系統的功能,允許檔案擁有多個資料流(data stream)。

  • 每個檔案都有主資料流(默認內容),ADS 是附加的隱藏資料流。

  • 特性:

    • 普通檔案列表 (dirDirectory.GetFiles) 不會列出 ADS。

    • 檔案總管即使開啟「顯示隱藏檔案」也看不到 ADS

    • 需特定工具查看:

      • CMD: dir /r

      • PowerShell: 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.txt
    
  • Notepad 可以正確打開,證明資料存在。

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 內容。


總結

  1. ADS 是 NTFS 隱藏資料流,一般工具無法看到。

  2. 建立與查看

    • CMD: echo "內容" > file.txt:adsname

    • 查看: dir /r 或 PowerShell Get-Item -Stream *

  3. 讀取

    • 高階 API (File.ReadAllText) 無法讀取。

    • Notepad 可以打開。

    • C# 需使用 Windows API (CreateFile)。

  4. 列出資料夾所有 ADS

    • 使用 Windows API FindFirstStreamW / FindNextStreamW

    • 可搭配 FileStream 讀取內容。

More from this blog

Android Edge-to-Edge & View 類型筆記

1️⃣ enableEdgeToEdge() 作用:讓 Activity 畫面延伸到 狀態列 / 導覽列 底下。 預設行為: 狀態列透明。 導航列自動套用 scrim(半透明遮罩)確保對比度,API 29+ 支援自動亮暗判斷。 好處:畫面可以全螢幕顯示,UI 更現代化。 2️⃣ ViewCompat.setOnApplyWindowInsetsListener(...) 作用:監聽系統 WindowInsets(安全區域)。 用途:避免內容被狀態列 / 導覽列擋住。 範...

Aug 18, 20251 min read

公司 Proxy 下 npm install 的 SSL 問題解法

在公司網路有 Proxy 或自簽憑證 (self-signed cert) 的情況下,執行 npm install 可能會遇到 SSL 認證錯誤。 以下是常見的解法: 🔧 解法一:關閉 SSL 驗證 npm config set strict-ssl false 缺點:不安全,會允許不可信憑證。 🔧 解法二:指定公司憑證檔案 npm config set cafile <path-to-cert> 讓 npm 認得公司 CA,推薦這種做法(比完全關閉驗證安全)。 🔧 解法...

Aug 18, 20251 min read

Tech notes

5 posts