Обнаруживать, если он работает как администратор с повышенными привилегиями или без них?
У меня есть приложение, которое должно определить, работает ли оно с повышенными привилегиями или нет. В настоящее время у меня есть код, подобный этому:
static bool IsAdministrator()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole (WindowsBuiltInRole.Administrator);
}
Это работает, чтобы определить, является ли пользователь администратором или нет, но не работает, если он работает как администратор без повышения. (Например, в vshost.exe).
Как я могу определить, возможно ли повышение [уже в силе или] возможно?
Ответы
Ответ 1
Попробуйте следующее:
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;
}
}
}
}
Ответ 2
(новый ответ через шесть лет после того, как был задан вопрос)
Отказ от ответственности. Это то, что случилось с моей конкретной ОС с моими настройками с моим конкретным пользователем:
using System.Security.Principal;
// ...
static bool IsElevated
{
get
{
return WindowsIdentity.GetCurrent().Owner
.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
}
}
Поэтому, когда я запускаю этот "Запуск от имени администратора", свойство get
accessor возвращает true
. При нормальной работе (даже если мой пользователь "является" администратором, просто не запуская это конкретное приложение "как администратор" ), он возвращает false
.
Это кажется намного проще, чем многие другие ответы.
Я не знаю, есть ли случаи, когда это не удается.
PS! Это также кажется ОК:
static bool IsElevated
{
get
{
var id = WindowsIdentity.GetCurrent();
return id.Owner != id.User;
}
}
Ответ 3
Проект 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);
}
}
Ответ 4
Вот измененная версия этого ответа, чтобы включить такие вещи, как правильное распределение ресурсов и обработка Администраторов домена.
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;
}
}
}
}
Ответ 5
В .net Framwork 4.5 я нашел другой метод, который работает для меня.
В отношении следующего script, который можно найти здесь здесь (на немецком языке)
rem --- Admintest.bat ---
whoami /groups | find "S-1-5-32-544" > nul
if errorlevel 1 goto ende
echo Benutzer %username% ist lokaler Administrator.
:ende
В С# он выглядит так:
private bool IsAdmin()
{
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
и я не нашел способа получить эту информацию.
Ответ 6
Использование TokenElevationType
будет работать, но если вы используете PInvoke CheckTokenMembership()
для SID группы администратора, ваш код также будет работать, когда UAC выключен, и на 2000/XP/2003, а также будет обрабатывать идентификаторы SID.
Существует также функция IsUserAnAdmin()
, которая выполняет проверку CheckTokenMembership
для вас, но MSDN говорит, что она может быть не навсегда
Ответ 7
Я думаю, что есть еще одна проблема. Я проверил решения, предоставленные вами, и должен сказать, что при установке 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
Все эти методы описаны в предыдущих сообщениях.