.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。
答案 0 :(得分:0)
没有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更具性能,但是需要您知道如何解释更多结构。
答案 1 :(得分:0)
克雷格(Craig)几乎涵盖了所有内容。我想清除其中一些。像Craig一样,这里没有代码。
请记住,$ Secure将安全描述符存储在self-relative format中。
答案 2 :(得分: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字段正确表示描述符的单个实例