Как получить двоичное значение SDDL ПРИГОДНОЕ ДЛЯ ЗАПИСИ В РЕЕСТР?
Пытаюсь получить дескриптор безопасности службы в двоичном виде, чтобы записать его в поле Security другой службы в реестре. Однако способы, представленные в интернете (с помощью PowerShell и C#) все как один возвращают не то двоичное значение, которое записано в реестре в поле Security соответствующей службы.
Например, есть некая служба, к которой в реестре уже записано поле Security. Я с помощью sc sdshow <имя_службы> получаю её дескриптор безопасности в строковом формате. Создаю из этой строки объект класса RawSecurityDescriptor в C#, после чего использую метод GetBinaryForm, возвращающий (по идее) как раз то, что мне нужно, а именно – тот же дескриптор в двоичном виде. Сравниваю полученный результат с тем, что записано в поле Security для рассматриваемой службы. И значения не совпадают! Если быть совсем уж точным, они совпадают частично, но не полностью.
Код того, что я делал:
var rawSd = new RawSecurityDescriptor("D:(A;;CCLCSWRPLOCRRC;;;WD)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLORC;;;IU)(A;;CCLCSWLOCRRC;;;SU)");
_bytes = new byte[rawSd.BinaryLength];
rawSd.GetBinaryForm(_bytes, 0);
В переменной _bytes получается значение байтов (16ичные) типа:
0x01 0x00 0x04 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x14 0x00 0x00 0x00 0x02 0x00 0x70 ...
и так далее, их много.
В реестре же записаны значения с другим началом (48 значениий) и другим концом (24 значения), но такой же серединой (всего значений около 200).
После тщательного рассмотрения записей в реестре выяснил, что концовка у всех значений поля Security (у разных служб) одинаковая. Для каждой службы одни и те же 24 байта. (все не проверял, но по крайней мере для многих это точно актуально).
Что ещё интереснее, в таком коде
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.AccessControl;
using Microsoft.Win32;
namespace TryingServicePermissions
{
class Program
{
static void Main(string[] args)
{
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\services\audiosrv\Security");
byte[] registryBytes = (byte[])key.GetValue("Security");
RawSecurityDescriptor registryDecriptor = new RawSecurityDescriptor(registryBytes, 0);
string registrySddl = registryDecriptor.GetSddlForm(AccessControlSections.All);
Console.WriteLine($"SSDL from registry: {registrySddl}");
RawSecurityDescriptor stringDecriptor = new RawSecurityDescriptor(registrySddl);
byte[] _bytes = new byte[stringDecriptor.BinaryLength];
stringDecriptor.GetBinaryForm(_bytes, 0);
Console.WriteLine(string.Join("", _bytes.Select(b => b.ToString("X2"))));
}
}
}
после его выполнения значения переменных registryBytes и _bytes не равны! Хотя, логически рассуждая, я просто сделал из байтов строку и обратно.
И ещё одно добавление: если представленный выше блок кода дополнить таким строками
RawSecurityDescriptor byteDecriptor = new RawSecurityDescriptor(_bytes, 0);
if (registrySddl == byteDecriptor.GetSddlForm(AccessControlSections.All))
Console.WriteLine("Equal!");
оно-таки выдаёт Equal!. То есть, не смотря на различные байтовые значения, строка разрешений всё же остаётся неизменной.
Вопрос: почему происходит вышеописанное и как всё-таки получить корректное двоичное представление дескриптора безопасности?