Search code examples
windowswinapiprocesssystem32advapi32

Check if another process has admin privileges


I have wrote a code to check is a process running on the same machine has administrator privileges or not. But it always returns false.

Can you tell me what's wrong with it.

private static bool HasAdminPrivileges(int processId)
{
    var hProcess = WinApi.OpenProcess(ProcessAccessFlags.QueryInformation, false, processId);
    var opened = WinApi.OpenProcessToken(hProcess, WinApi.TOKEN_QUERY, out IntPtr hToken);
    if (opened)
    {
        var token = new IntPtr(hProcess.ToInt64() + hToken.ToInt64()); // 64 bit machine only

        WinApi.CreateWellKnownSid(WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid, IntPtr.Zero, IntPtr.Zero, out uint cbSidUint);
        var cbSid = new IntPtr(cbSidUint);

        var succeed = WinApi.CheckTokenMembership(token, cbSid, out bool isMember);

        return succeed && isMember;
    }
    return false;
}

public class WinApi
{
    public const int TOKEN_QUERY = 0X00000008;

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);    

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType, IntPtr DomainSid, IntPtr pSid, out uint cbSid);    

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool CheckTokenMembership(IntPtr TokenHandle, IntPtr SidToCheck, out bool IsMember);
}

public enum ProcessAccessFlags : uint
{
    QueryInformation = 0x00000400
}

public enum WELL_KNOWN_SID_TYPE
{
    WinBuiltinAdministratorsSid = 26
}

Solution

  • You cannot add handles together (new IntPtr(hProcess.ToInt64() + hToken.ToInt64()); ), that makes no sense.

    You need the process handle to get the process token handle, then pass the token handle to CheckTokenMembership.

    You also need to close these handles with CloseHandle.

    using System;
    using System.Runtime.InteropServices;
    ...
    public class WinApi
    {
        public const int TOKEN_DUPLICATE = 0x0002;
        public const int TOKEN_QUERY = 0x00000008;
        public const int SecurityImpersonation = 2;
        public const int TokenImpersonation = 2;
    
        [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);
        [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool DuplicateTokenEx(IntPtr hTok, UInt32 DesiredAccess, IntPtr SecAttPtr, int ImpLvl, int TokType, out IntPtr TokenHandle);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
    
        [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType, IntPtr DomainSid, IntPtr pSid, ref uint cbSid);
    
        [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CheckTokenMembership(IntPtr TokenHandle, IntPtr SidToCheck, out bool IsMember);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int GetCurrentProcessId();
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int CloseHandle(IntPtr h);
    }
    
    public enum ProcessAccessFlags : uint
    {
        QueryInformation = 0x00000400,
        QueryLimitedInformation = 0x1000
    }
    
    public enum WELL_KNOWN_SID_TYPE
    {
        WinBuiltinAdministratorsSid = 26
    }
    
    private static bool IsAdminGroupMember(int processId)
    {
        IntPtr hPriToken = IntPtr.Zero, hImpToken = IntPtr.Zero;
        var hProcess = WinApi.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, processId);
        if (hProcess == IntPtr.Zero) hProcess = WinApi.OpenProcess(ProcessAccessFlags.QueryInformation, false, processId); // < Vista
        var haveToken = WinApi.OpenProcessToken(hProcess, WinApi.TOKEN_DUPLICATE, out hPriToken);
        if (haveToken) 
        {
            haveToken = WinApi.DuplicateTokenEx(hPriToken, WinApi.TOKEN_QUERY, IntPtr.Zero, WinApi.SecurityImpersonation, WinApi.TokenImpersonation, out hImpToken);
            WinApi.CloseHandle(hPriToken);
        }
        if (hProcess != IntPtr.Zero) WinApi.CloseHandle(hProcess);
        if (haveToken)
        {
            uint cbSid = 0;
            bool isMember = false;
            WinApi.CreateWellKnownSid(WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid, IntPtr.Zero, IntPtr.Zero, ref cbSid);
            IntPtr pSid = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
            var succeed = pSid != IntPtr.Zero && WinApi.CreateWellKnownSid(WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid, IntPtr.Zero, pSid, ref cbSid);
            succeed = succeed && WinApi.CheckTokenMembership(hImpToken, pSid, out isMember);
            Marshal.FreeCoTaskMem(pSid);
            WinApi.CloseHandle(hImpToken);
            return succeed && isMember;
        }
        return false;
    }
    
    
    [STAThread]static void Main(/*string[] args*/) 
    {
    
        bool admin = IsAdminGroupMember(WinApi.GetCurrentProcessId());
        Console.WriteLine(string.Format("IsAdminGroupMember={0}", admin));
    }