首页 > 解决方案 > 如何在 C# 中以编程方式读取 Windows NTFS $Secure 文件(和/或 $SDS 流)

问题描述

.NET 平台的 DirectorySecurity 命名空间中的方法(例如 GetAccessRules())对于我的目的来说太慢了。相反,我希望直接查询 NTFS $Secure 元文件(或者,$SDS 流),以便检索每个文件系统对象的本地帐户列表及其相关权限。

我的计划是首先读取 $MFT 元文件(我已经知道如何去做) - 然后,对于其中的每个条目,在元文件(或流)中查找适当的安全描述符。

理想的代码块如下所示:

//I've already successfully written code for MFTReader:
var mftReader = new MFTReader(driveToAnalyze, RetrieveMode.All);
IEnumerable<INode> nodes = mftReader.GetNodes(driveToAnalyze.Name);

foreach (NodeWrapper node in nodes)
{
    //Now I wish to return security information for each file system object
    //WITHOUT needing to traverse the directory tree.
    //This is where I need help:
    var securityInfo = GetSecurityInfoFromMetafile(node.FullName, node.SecurityID);
    yield return Tuple.Create(node.FullName, securityInfo.PrincipalName, DecodeAccessMask(securityInfo.AccessMask));
}

我希望我的输出看起来像这样:

c:\Folder1\File1.txt    jane_smith  Read, Write, Execute
c:\Folder1\File1.txt    bill_jones  Read, Execute
c:\Folder1\File2.txt    john_brown  Full Control
etc.

我在 Windows 10 上运行 .NET 版本 4.7.1。

标签: c#windowssecurityntfsntfs-mft

解决方案


没有 API 可以直接从 $Secure 读取,就像没有 API 可以直接从 $MFT 读取一样。(有 FSCTL_QUERY_FILE_LAYOUT 但这只是为您提供了对 MFT 内容的抽象解释。)

既然你说你可以读取 $MFT,听起来你必须使用卷句柄直接从卷中读取,就像 chkdsk 和类似工具一样。只要您知道如何解释磁盘结构,就可以阅读您想要的任何内容。因此,您的问题归结为如何正确解释 $Secure 文件。

我不会给你代码片段或确切的数据结构,但我会给你一些非常好的提示。实际上有两种可能的方法。

第一种方法是您可以在 $SDS 中向前扫描。所有安全描述符都在那里,按 SecurityId 顺序排列。您会发现有各种 16 字节对齐的偏移量,将有一个 20 字节的标头,其中包括 SecurityId 以及其他信息,然后是序列化形式的安全描述符。SecurityId 值将按升序显示在 $SDS 中。此外,$SDS 中的每个备用 256K 区域都是前一个 256K 区域的镜像。要将工作减半,只需考虑 0..256K-1、512K..768K-1 等区域。

第二种方法是利用 $SII 索引,它也是 $Secure 文件的一部分。它的结构是一个 B 树,与 NTFS 中目录的结构非常相似。$SII 中的索引条目将 SecurityId 作为查找的索引,还包含您可以在 $SDS 中查找相应标头和安全描述符的字节偏移量。这种方法将比扫描 $SDS 更高效,但需要您知道如何解释更多结构。


推荐阅读