Обнаруживать, если он работает как администратор с повышенными привилегиями или без них?

У меня есть приложение, которое должно определить, работает ли оно с повышенными привилегиями или нет. В настоящее время у меня есть код, подобный этому:

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

Все эти методы описаны в предыдущих сообщениях.