检测是否以管理员身份运行,是否有提升的权限?

我有一个应用程序,它需要检测它是否以提升的权限运行。我目前的代码设置如下:

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

这样可以检测用户是否是管理员,但是如果作为管理员运行而没有升级,则无法检测用户是否是管理员。(例如在 vshost.exe 中)。

如何确定是否为 有可能[已经有效]提高

55740 次浏览

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

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

Here is a modified version of this answer to include things like the proper disposing of resources and handling of Domain Administrators.

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("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);


[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
{
using (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 = IntPtr.Zero;
if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_READ, out tokenHandle))
{
throw new ApplicationException("Could not get process token.  Win32 Error Code: " +
Marshal.GetLastWin32Error());
}


try
{
TOKEN_ELEVATION_TYPE elevationResult = TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;


int elevationResultSize = Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE));
uint returnedSize = 0;


IntPtr elevationTypePtr = Marshal.AllocHGlobal(elevationResultSize);
try
{
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.");
}
}
finally
{
if (elevationTypePtr != IntPtr.Zero)
Marshal.FreeHGlobal(elevationTypePtr);
}
}
finally
{
if (tokenHandle != IntPtr.Zero)
CloseHandle(tokenHandle);
}
}
else
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
bool result = principal.IsInRole(WindowsBuiltInRole.Administrator)
|| principal.IsInRole(0x200); //Domain Administrator
return result;
}
}
}
}

In .net Framwork 4.5 I found another method that works for me. In relation to the following script that can be found here here (in German)

 rem --- Admintest.bat ---
whoami /groups | find "S-1-5-32-544" > nul
if errorlevel 1 goto ende
echo Benutzer %username% ist lokaler Administrator.
:ende

In C# it looks like this:

    private bool IsAdmin
{
get
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
if (identity != null)
{
WindowsPrincipal principal = new WindowsPrincipal(identity);
List<Claim> list = new List<Claim>(principal.UserClaims);
Claim c = list.Find(p => p.Value.Contains("S-1-5-32-544"));
if (c != null)
return true;
}
return false;
}
}

But in .net < 4.5 the WindowsPrincipal class does not contain the UserClaims property and I found no way to get this information.

I think there is one more issue. I checked solutions provided by you and have to say that in the installation of Windows 7 and logged on as an admin the check does not work. Windows never returns information that process runs in an elevated mode. So the sequence:

if (IsUacEnabled)
return IsProcessInElevatedMode();
return IsUserAdmin();

does not returns true when logged as an Administrator but the process has all privileges to perform system operations (e.g. stop system services). The working sequence is:

if (IsUserAdmin())
return true;


if (IsUacEnabled)
return IsProcessInElevatedMode();


return false;

You should first check if the process is run in Administrator context. Additional info:

IsUacEnabled() - checks if the UAC has been enabled in the system (Windows)
IsProcessInElevatedMode() - checks if the process is run in an elevated mode
IsUserAdmin() - checks if the current user has an Administrtor role

All of that methods has been described in previous posts.

(new answer six years after the question was asked)

Disclaimer: This is just something that happened to work on my particular OS with my particular settings with my particular user:

using System.Security.Principal;


// ...


static bool IsElevated
{
get
{
return WindowsIdentity.GetCurrent().Owner
.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
}
}

So when I run this "Run as administrator", the property get accessor returns true. When running normally (even if my user "is" administrator, just not running this particular application "as administrator"), it returns false.

This seems much simpler than many other answers.

I have no idea if there are cases where this fails.

PS! This also seems OK:

    static bool IsElevated
{
get
{
var id = WindowsIdentity.GetCurrent();
return id.Owner != id.User;
}
}

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.

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

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