Detect if running as Administrator with or without elevated privileges?

Viewed 55109

I have an application that needs to detect whether or not it is running with elevated privileges or not. I currently have code set up like this:

static bool IsAdministrator()
{
    WindowsIdentity identity = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal(identity);
    return principal.IsInRole (WindowsBuiltInRole.Administrator);
}

This works to detect if a user is an administrator or not, but doesn't work if running as an administrator without elevation. (For example in vshost.exe).

How can I determine whether or not elevation is [already in force or] possible?

10 Answers

Try this out:

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;

public static class UacHelper
{
    private const string uacRegistryKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
    private const string uacRegistryValue = "EnableLUA";

    private static uint STANDARD_RIGHTS_READ = 0x00020000;
    private static uint TOKEN_QUERY = 0x0008;
    private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);

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

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);

    public enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin,
        TokenElevationType,
        TokenLinkedToken,
        TokenElevation,
        TokenHasRestrictions,
        TokenAccessInformation,
        TokenVirtualizationAllowed,
        TokenVirtualizationEnabled,
        TokenIntegrityLevel,
        TokenUIAccess,
        TokenMandatoryPolicy,
        TokenLogonSid,
        MaxTokenInfoClass
    }

    public enum TOKEN_ELEVATION_TYPE
    {
        TokenElevationTypeDefault = 1,
        TokenElevationTypeFull,
        TokenElevationTypeLimited
    }

    public static bool IsUacEnabled
    {
        get
        {
            RegistryKey uacKey = Registry.LocalMachine.OpenSubKey(uacRegistryKey, false);
            bool result = uacKey.GetValue(uacRegistryValue).Equals(1);
            return result;
        }
    }

    public static bool IsProcessElevated
    {
        get
        {
            if (IsUacEnabled)
            {
                IntPtr tokenHandle;
                if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_READ, out tokenHandle))
                {
                    throw new ApplicationException("Could not get process token.  Win32 Error Code: " + Marshal.GetLastWin32Error());
                }

                TOKEN_ELEVATION_TYPE elevationResult = TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;

                int elevationResultSize = Marshal.SizeOf((int)elevationResult);
                uint returnedSize = 0;
                IntPtr elevationTypePtr = Marshal.AllocHGlobal(elevationResultSize);

                bool success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenElevationType, elevationTypePtr, (uint)elevationResultSize, out returnedSize);
                if (success)
                {
                    elevationResult = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(elevationTypePtr);
                    bool isProcessAdmin = elevationResult == TOKEN_ELEVATION_TYPE.TokenElevationTypeFull;
                    return isProcessAdmin;
                }
                else
                {
                    throw new ApplicationException("Unable to determine the current elevation.");
                }
            }
            else
            {
                WindowsIdentity identity = WindowsIdentity.GetCurrent();
                WindowsPrincipal principal = new WindowsPrincipal(identity);
                bool result = principal.IsInRole(WindowsBuiltInRole.Administrator);
                return result;
            }
        }
    }
}

The CodePlex project UAChelper has code that checks on elevation in UserAccountControl.cpp UserAccountControl::IsUserAdmin, that checks if UAC is enabled and then checks if process is elevated.

bool UserAccountControl::IsCurrentProcessElevated::get()
{
    return GetProcessTokenElevationType() == TokenElevationTypeFull;    //elevated
}

from the function:

int UserAccountControl::GetProcessTokenElevationType()
{
    HANDLE hToken;
    try
    {
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
            throw gcnew Win32Exception(GetLastError());

        TOKEN_ELEVATION_TYPE elevationType;
        DWORD dwSize;
        if (!GetTokenInformation(hToken, TokenElevationType, &elevationType, sizeof(elevationType), &dwSize))
            throw gcnew Win32Exception(GetLastError());

        return elevationType;
    }
    finally
    {
        CloseHandle(hToken);
    }
}

Using TokenElevationType would work, but if you PInvoke CheckTokenMembership() against the admin group SID, your code would also work when UAC is off and on 2000/XP/2003 and will also handle deny SID's.

There is also a IsUserAnAdmin() function that does the CheckTokenMembership check for you, but MSDN says it might not be there forever

This Answer has a few problems. First, it doesn't get any System processes that run as Admin (for example under NT-Authority/SYSTEM). The code example below fixes all problems (detects, LocalAdmins, DomainAdmins, and LocalSystemAdmins)

If you just want the current Process, replace pHandle with Process.GetCurrentProcess().Handle

NOTE: You must have certain privileges to run it. (Every AdminProcess has them but needs to active them first, Services have them activated by default)

internal static bool IsProcessElevatedEx(this IntPtr pHandle) {

        var token = IntPtr.Zero;
        if (!OpenProcessToken(pHandle, MAXIMUM_ALLOWED, ref token))
                throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed");

        WindowsIdentity identity = new WindowsIdentity(token);
        WindowsPrincipal principal = new WindowsPrincipal(identity);
        bool result = principal.IsInRole(WindowsBuiltInRole.Administrator)
                   || principal.IsInRole(0x200); //Domain Administrator
        CloseHandle(token);
        return result;
}

Using UACHelper nuget package: https://www.nuget.org/packages/UACHelper/

if (UACHelper.IsElevated)
    // something
else
    // something else

There are a lot of other properties that can be used to detect if the user is, in fact, an administrator, or if the process is running under UAC virtualization, or if the desktop owner is the process owner. (Run as from limited account)

Check the read me for more information.

I am using this code and it works well:


bool runningAsAdmin = WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);

*Admin is part of the Build-In Administrators group.

"A user account for the system administrator. This account is the first account created during operating system installation. The account cannot be deleted or locked out. It is a member of the Administrators group and cannot be removed from that group." -- https://ss64.com/nt/syntax-security_groups.html

Related