Определить, работает ли от имени администратора с повышенными привилегиями или без них?
У меня есть приложение, которое должно определить, работает ли оно с повышенными привилегиями или нет. В настоящее время у меня есть код, настроенный так:
static bool IsAdministrator()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole (WindowsBuiltInRole.Administrator);
}
Это работает, чтобы определить, является ли пользователь администратором или нет, но не работает, если работает от имени администратора без повышения прав. (Например в vshost.exe).
Как я могу определить, возможно ли повышение [уже в силе или] возможно?
8 ответов
Попробуйте это:
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;
}
}
}
}
(новый ответ через шесть лет после того, как вопрос был задан)
Отказ от ответственности: это просто то, что произошло на моей конкретной ОС с моими конкретными настройками с моим конкретным пользователем:
using System.Security.Principal;
// ...
static bool IsElevated
{
get
{
return WindowsIdentity.GetCurrent().Owner
.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
}
}
Поэтому, когда я запускаю этот "Запуск от имени администратора", свойство get
возврат доступа true
, При работе в обычном режиме (даже если мой пользователь "является" администратором, но не запускает данное приложение "как администратор"), он возвращает false
,
Это кажется намного проще, чем многие другие ответы.
Я понятия не имею, есть ли случаи, когда это не удается.
PS! Это также кажется нормальным:
static bool IsElevated
{
get
{
var id = WindowsIdentity.GetCurrent();
return id.Owner != id.User;
}
}
Вот модифицированная версия этого ответа, включающая такие вещи, как правильное размещение ресурсов и обработка администраторов домена.
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;
}
}
}
}
В проекте CodePlex UAChelper есть код, который проверяет высоту в UserAccountControl.cpp UserAccountControl::IsUserAdmin
, который проверяет, включен ли UAC, а затем проверяет, повышен ли процесс.
bool UserAccountControl::IsCurrentProcessElevated::get()
{
return GetProcessTokenElevationType() == TokenElevationTypeFull; //elevated
}
из функции:
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);
}
}
В.net Framwork 4.5 я нашел другой метод, который работает для меня. В отношении следующего сценария, который можно найти здесь (на немецком языке)
rem --- Admintest.bat ---
whoami /groups | find "S-1-5-32-544" > nul
if errorlevel 1 goto ende
echo Benutzer %username% ist lokaler Administrator.
:ende
В C# это выглядит так:
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;
}
}
Но в.net < 4.5 WindowsPrincipal
класс не содержит UserClaims
собственности, и я не нашел способа получить эту информацию.
С помощью TokenElevationType
будет работать, но если вы PInvoke CheckTokenMembership()
в отношении SID группы администраторов ваш код также будет работать при отключенном UAC и в 2000/XP/2003, а также обрабатывать SID, запрещающие работу.
Также есть IsUserAnAdmin()
функция, которая делает CheckTokenMembership
проверить вас, но MSDN говорит, что он не может быть там навсегда
Этот ответ имеет несколько проблем. Во-первых, он не получает никаких системных процессов, которые запускаются от имени администратора (например, в NT-Authority/SYSTEM). Пример кода ниже устраняет все проблемы (обнаруживает, LocalAdmins, DomainAdmins и LocalSystemAdmins)
Если вы просто хотите текущий процесс, замените pHandle
с Process.GetCurrentProcess().Handle
ПРИМЕЧАНИЕ. Для его запуска у вас должны быть определенные права. (Каждый AdminProcess имеет их, но сначала их нужно активировать, Сервисы активируют их по умолчанию)
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;
}
Я думаю, что есть еще одна проблема. Я проверил предоставленные вами решения и должен сказать, что при установке Windows 7 и вошел в систему как администратор, проверка не работает. Windows никогда не возвращает информацию о том, что процесс выполняется в режиме с повышенными правами. Итак, последовательность:
if (IsUacEnabled)
return IsProcessInElevatedMode();
return IsUserAdmin();
не возвращает true, если зарегистрирован как администратор, но у процесса есть все привилегии для выполнения системных операций (например, остановка системных служб). Рабочая последовательность:
if (IsUserAdmin())
return true;
if (IsUacEnabled)
return IsProcessInElevatedMode();
return false;
Сначала вы должны проверить, запущен ли процесс в контексте администратора. Дополнительная информация:
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
Все эти методы были описаны в предыдущих постах.
Используя пакет nuget UACHelper: https://www.nuget.org/packages/UACHelper/
if (UACHelper.IsElevated)
// something
else
// something else
Существует множество других свойств, которые можно использовать для определения того, является ли пользователь на самом деле администратором, или процесс выполняется под виртуализацией UAC, или владелец рабочего стола является владельцем процесса. (Запускать как с ограниченной учетной записи)
Проверьте прочитайте меня для получения дополнительной информации.
Я использую этот код, и он хорошо работает:
bool runningAsAdmin = WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
*Admin является частью группы встроенных администраторов.
"Учетная запись пользователя для системного администратора. Эта учетная запись - первая учетная запись, созданная во время установки операционной системы. Учетная запись не может быть удалена или заблокирована. Она является членом группы администраторов и не может быть удалена из этой группы". - https://ss64.com/nt/syntax-security_groups.html