dt_overflow
dt_overflow

Reputation: 71

Can't read privileges from process access token

I'm trying to get the list of groups and privileges in a process access token and some info about them (name, flags and description).

To do this I'm using the GetTokenInfomation function and the TOKEN_GROUPS_AND_PRIVILEGES structure.

These are the structure definitions:

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;
        }

I can read the groups SIDs and get info on them fine but when I try to read the privileges I always get an Access violation.

This is the code that I use to read the privileges:

            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));
            }

The exception occurs when calling the GetPrivilegeName method which uses the function LookupPrivilegeNameW defined as follows:

        [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);

I tried different methods to read the data such as:

  1. Manually calculating the offset to the privileges array element from the start of the structure
  2. Declare the privileges field as an array and set a SizeConst to an obviously oversized value

Even those methods threw an Access violation exception.

I don't undestand what is the problem given that I use the same code to read the SIDs and it works normally.

Upvotes: 0

Views: 322

Answers (1)

Drake Wu
Drake Wu

Reputation: 7190

First, The second parameter of LookupPrivilegeNameW is A pointer to a LUID. You need to declare it as a reference type like ref Win32Structures.LUID LUID.

And then the TOKEN_GROUPS_AND_PRIVILEGES.Privileges is an array of the privileges. Your code does not retrieve all Privileges, but repeatedly reads the first Privilege every time. Here is the working sample:

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);

        }
    }
}

Upvotes: 2

Related Questions