Не удается прочитать привилегии из токена доступа к процессу

#c# #.net #winapi

#c# #.net #winapi

Вопрос:

Я пытаюсь получить список групп и привилегий в токене доступа к процессу и некоторую информацию о них (имя, флаги и описание).

Для этого я использую функцию GetTokenInfomation и структуру TOKEN_GROUPS_AND_PRIVILEGES .

Это определения структуры:

TOKEN_GROUPS_AND_PRIVILEGES

         [StructLayout(LayoutKind.Sequential)]
        public struct TOKEN_GROUPS_AND_PRIVILEGES
        {
            public uint SidCount;

            public uint SidLength;

            public IntPtr Sids;

            public uint RestrictedSidCount;

            public uint RestrictedSidLength;

            public IntPtr RestrictedSids;

            public uint PrivilegeCount;

            public uint PrivilegeLength;

            public IntPtr Privileges;

            public LUID AuthenticationID;
        }
 

LUID_AND_ATTRIBUTES

         [StructLayout(LayoutKind.Sequential)]
        public struct LUID_AND_ATTRIBUTES
        {
            public LUID Luid;

            public uint Attributes;
        }
 

LUID

         [StructLayout(LayoutKind.Sequential)]
        public struct LUID
        {
            public uint LowPart;

            public int HighPart;
        }
 

Я могу читать SID групп и получать информацию о них нормально, но когда я пытаюсь прочитать привилегии, я всегда получаю нарушение доступа.

Это код, который я использую для чтения привилегий:

             for (int i = 0; i < GroupsAndPrivilegesInfo.PrivilegeCount; i  )
            {
                Privilege = (Win32Structures.LUID_AND_ATTRIBUTES)Marshal.PtrToStructure(GroupsAndPrivilegesInfo.Privileges, typeof(Win32Structures.LUID_AND_ATTRIBUTES));
                PrivilegeName = GetPrivilegeName(Privilege.Luid) ?? "Non disponibile";
                PrivilegeStatus = GetPrivilegeFlags((Win32Enumerations.PrivilegeLUIDAttribute)Privilege.Attributes) ?? "Non disponibile";
                PrivilegeDescription = GetPrivilegeDescription(PrivilegeName) ?? "Non disponibile";
                Privileges.Add(new TokenPrivilegeInfo(PrivilegeName, PrivilegeStatus, PrivilegeDescription));
                GroupsAndPrivilegesInfo.Privileges  = Marshal.SizeOf(typeof(Win32Structures.LUID_AND_ATTRIBUTES));
            }
 

Исключение возникает при вызове метода GetPrivilegeName, который использует функцию LookupPrivilegeNameW, определенную следующим образом:

         [DllImport("Advapi32.dll", EntryPoint = "LookupPrivilegeNameW", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool LookupPrivilegeName(string SystemName, Win32Structures.LUID LUID, StringBuilder PrivilegeName, ref uint NameLength);
 

Я пробовал разные методы для чтения данных, такие как:

  1. Вручную вычисление смещения к элементу массива привилегий с начала структуры
  2. Объявите поле привилегий как массив и установите SizeConst на явно завышенное значение

Даже эти методы вызвали исключение нарушения доступа.

Я не понимаю, в чем проблема, учитывая, что я использую тот же код для чтения SID, и он работает нормально.

Комментарии:

1. Второй параметр LookupPrivilegeNameW — это указатель на a LUID . Вы должны объявить его как ссылочный тип ref Win32Structures.LUID LUID .

2. Спасибо @DrakeWu-MSFT, теперь это работает, я не могу поверить, что это было что-то настолько простое.

Ответ №1:

Во-первых, второй параметр LookupPrivilegeNameW — это указатель на LUID. Вам нужно объявить его как ссылочный тип, например ref Win32Structures.LUID LUID .

И тогда TOKEN_GROUPS_AND_PRIVILEGES.Privileges это массив привилегий. Ваш код не извлекает все привилегии, но каждый раз повторно считывает первую привилегию. Вот рабочий пример:

 namespace ConsoleApp2
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct TOKEN_GROUPS_AND_PRIVILEGES
        {
            public uint SidCount;
            public uint SidLength;
            public IntPtr Sids;
            public uint RestrictedSidCount;
            public uint RestrictedSidLength;
            public IntPtr RestrictedSids;
            public uint PrivilegeCount;
            public uint PrivilegeLength;
            public IntPtr Privileges;
            public LUID AuthenticationID;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct LUID_AND_ATTRIBUTES
        {
            public LUID Luid;
            public uint Attributes;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct LUID
        {
            public uint LowPart;
            public int HighPart;
        }
        public enum TOKEN_INFORMATION_CLASS
        {
            TokenUser = 1,
            TokenGroups,
            TokenPrivileges,
            TokenOwner,
            TokenPrimaryGroup,
            TokenDefaultDacl,
            TokenSource,
            TokenType,
            TokenImpersonationLevel,
            TokenStatistics,
            TokenRestrictedSids,
            TokenSessionId,
            TokenGroupsAndPrivileges,
            TokenSessionReference,
            TokenSandBoxInert,
            TokenAuditPolicy,
            TokenOrigin
        }
        [DllImport("Advapi32.dll", EntryPoint = "LookupPrivilegeNameW", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool LookupPrivilegeName(string SystemName, ref LUID LUID, StringBuilder PrivilegeName, ref uint NameLength);
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool OpenProcessToken(IntPtr ProcessHandle,
    UInt32 DesiredAccess, out IntPtr TokenHandle);
        [DllImport("kernel32.dll")]
        public static extern IntPtr GetCurrentProcess();
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool GetTokenInformation(IntPtr TokenHandle, 
            TOKEN_INFORMATION_CLASS TokenInformationClass, 
            IntPtr TokenInformation,
            Int32 TokenInformationLength,
            out Int32 ReturnLength);

        public static UInt32 TOKEN_QUERY = 0x0008;
        static void Main(string[] args)
        {
            bool ret = false;
            IntPtr token;
            ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out token);
            Int32 ReturnLength;
            ret = GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenGroupsAndPrivileges, IntPtr.Zero, 0, out ReturnLength);
            IntPtr pGroupsAndPrivilegesInfo = Marshal.AllocHGlobal(ReturnLength);
            ret = GetTokenInformation(token, TOKEN_INFORMATION_CLASS.TokenGroupsAndPrivileges, pGroupsAndPrivilegesInfo, ReturnLength, out ReturnLength);
            TOKEN_GROUPS_AND_PRIVILEGES GroupsAndPrivilegesInfo = (TOKEN_GROUPS_AND_PRIVILEGES)Marshal.PtrToStructure(pGroupsAndPrivilegesInfo, typeof(TOKEN_GROUPS_AND_PRIVILEGES));
            

            for (int i = 0; i < GroupsAndPrivilegesInfo.PrivilegeCount; i  )
            {
                //IntPtr ptr = GroupsAndPrivilegesInfo.Privileges   i * Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES));
                LUID_AND_ATTRIBUTES Privilege = (LUID_AND_ATTRIBUTES)Marshal.PtrToStructure(GroupsAndPrivilegesInfo.Privileges   i * Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES)), typeof(LUID_AND_ATTRIBUTES));
                StringBuilder name = new StringBuilder(50);
                uint cchName = 50; 
                ret = LookupPrivilegeName(null, ref Privilege.Luid, name, ref cchName);
                Console.WriteLine(name);
            }
            Marshal.FreeHGlobal(pGroupsAndPrivilegesInfo);

        }
    }
}