Как программно прочитать файл $ Secure Windows NTFS (и / или поток $SDS) в C#
Методы в пространстве имен DirectorySecurity платформы.NET (например, 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.
Я использую.NET версии 4.7.1 в Windows 10.
1 ответ
Нет API для чтения напрямую из $Secure, точно так же, как нет API для чтения напрямую из $MFT. (Есть FSCTL_QUERY_FILE_LAYOUT, но это просто дает вам абстрактную интерпретацию содержимого MFT.)
Поскольку вы сказали, что можете читать $MFT, похоже, что вы используете дескриптор тома для чтения непосредственно с тома, как chkdsk и подобные инструменты. Это позволяет вам читать все, что вы хотите, при условии, что вы знаете, как интерпретировать структуры на диске. Таким образом, ваш вопрос сводится к тому, как правильно интерпретировать файл $ Secure.
Я не буду давать вам фрагменты кода или точные структуры данных, но я дам вам несколько очень полезных советов. На самом деле возможны два подхода.
Первый подход заключается в том, что вы можете сканировать вперед в $SDS. Все дескрипторы безопасности находятся в порядке SecurityId. Вы обнаружите, что в различных 16-байтовых выровненных смещениях будет 20-байтовый заголовок, который включает в себя SecurityId среди другой информации, и после этого есть дескриптор безопасности в сериализованной форме. Значения SecurityId будут отображаться в порядке возрастания в $SDS. Также каждая альтернативная область 256 КБ в $ SDS является зеркалом предыдущей области 256 КБ. Чтобы сократить работу пополам, рассмотрим только регионы 0..256K-1, 512K..768K-1 и т. Д.
Второй подход заключается в использовании индекса $SII, также являющегося частью файла $ Secure. Структура этого B-дерева очень похожа на структуру каталогов в NTFS. Записи индекса в $SII имеют SecurityId в качестве индекса для поиска, а также содержат смещение байтов, к которому вы можете перейти в $ SDS, чтобы найти соответствующий заголовок и дескриптор безопасности. Этот подход будет более производительным, чем сканирование $ SDS, но требует, чтобы вы знали, как интерпретировать гораздо больше структур.
Крейг почти все рассказал. Я хотел бы очистить некоторые из них. Как и Крейг, здесь нет кода.
- Перейдите к узлу номер 9, который соответствует $Secure.
- Получить все потоки и получить все фрагменты потока $SDS.
- Прочтите содержимое и извлеките каждый дескриптор безопасности.
- Используйте IsValidSecurityDescriptor, чтобы убедиться, что SD действительна, и остановитесь, когда вы достигнете недопустимой SD.
Помните, что $Secure хранит дескрипторы безопасности в относительном формате.
Вы используете FSCTL_QUERY_FILE_LAYOUT? Единственный реальный источник того, как использовать эту функцию, который я нашел, находится здесь:https://wimlib.net/git/?p=wimlib;a=blob;f=src/win32_capture.c;h=d62f7d07ef20c08c9bec93f261131033e39b159b;hb=HEAD
Похоже, он решает проблему с дескрипторами безопасности следующим образом: он получает практически всю информацию о файлах из MFT, но не дескрипторы безопасности. Для них он получает поле SecurityId из MFT и смотрит в хэш-таблицу, есть ли у него уже отображение этого идентификатора в ACL. Если есть, он просто возвращает его, в противном случае он использует NtQuerySecurityObject и кэширует его в хеш-таблице. Это должно резко сократить количество звонков. Предполагается, что дескрипторов безопасности мало и что поле SecurityID правильно представляет единичный экземпляр дескрипторов.