1

.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。

4

3 回答 3

1

没有 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 更高效,但需要您知道如何解释更多结构。

于 2019-01-16T05:08:35.697 回答
1

克雷格几乎涵盖了所有内容。我想清除其中的一些。像克雷格一样,这里没有代码。

  1. 导航到与 $Secure 对应的节点号 9。
  2. 获取所有流并获取 $SDS 流的所有片段。
  3. 阅读内容并提取每个安全描述符。
  4. 使用IsValidSecurityDescriptor确保 SD 有效并在到达无效 SD 时停止。

请记住,$Secure 以自相关格式存储安全描述符。

于 2019-07-18T18:47:21.137 回答
0

你在使用 FSCTL_QUERY_FILE_LAYOUT 吗?我发现如何使用此功能的唯一真正来源是: https ://wimlib.net/git/?p=wimlib;a=blob;f=src/win32_capture.c;h=d62f7d07ef20c08c9bec93f261131033e39b159b;hb=HEAD

看起来他用这样的安全描述符解决了这个问题:他基本上从 MFT 中获取了有关文件的所有信息,但没有安全描述符。对于那些他从 MFT 获取字段 SecurityId 并在哈希表中查看他是否已经具有从该 ID 到 ACL 的映射。如果有,则直接返回,否则使用 NtQuerySecurityObject 并将其缓存在哈希表中。这应该会大大减少呼叫量。它假定安全描述符很少,并且 SecurityID 字段正确地表示描述符的单个实例

于 2020-06-01T10:40:08.123 回答