90 votes

Détecter si l'exécution se fait en tant qu'administrateur avec ou sans privilèges élevés ?

J'ai une application qui doit détecter si elle est exécutée avec des privilèges élevés ou non. Le code est actuellement configuré comme suit :

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

Cela fonctionne pour détecter si un utilisateur est un administrateur ou non, mais ne fonctionne pas si vous vous exécutez en tant qu'administrateur sans élévation. (Par exemple dans vshost.exe).

Comment puis-je déterminer si oui ou non l'élévation est [déjà en vigueur ou] possible ?

59voto

Steven Points 1637

Essayez ceci :

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

8 votes

Cela fonctionne si le compte à exécuter est un administrateur local, mais si vous utilisez l'administrateur de domaine, la variable isProcessAdmin renvoie false. Mais l'UAC accepte l'administrateur de domaine comme valide lors de l'élévation des privilèges (créer un dossier dans Windows, exécuter en tant qu'administrateur, etc)... Comment puis-je modifier votre fonction pour qu'elle prenne en compte ce cas aussi ?

1 votes

Vous pouvez également tenir compte du fait que si le compte est l'administrateur intégré, l'UAC est élevé par défaut. IsProcessElevated renverra donc false dans ce cas (parce que IsUacEnabled est true et elevationResult est TokenElevationTypeDefault), même si le processus s'exécute en mode élevé sans avoir invité l'utilisateur. En d'autres termes, le compte est élevé et le processus s'exécute dans le type d'élévation par défaut.

2 votes

Ce code nécessite les instructions suivantes : using System.Diagnostics ; using System.Runtime.InteropServices ; using System.Security.Principal ; Il semble également être en miroir. ici.

22voto

Scott Chamberlain Points 32782

Voici une version modifiée de cette réponse pour inclure des éléments tels que l'élimination correcte des ressources et la gestion des administrateurs de domaine.

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

0 votes

Tout dépend de l'utilisateur sous lequel vous exécutez le service. Essayez-vous de détecter si le service est exécuté en tant que Système Local, Service Local, Service Réseau, ou un utilisateur Windows ? La détection du "statut administratif" ne fonctionnera pas pour faire la différence entre le Système Local et le Service Local, vous devez tester cela en vérifiant directement quel utilisateur exécute le processus.

0 votes

Cela m'a valu une exception à Windows 8, à Marshal.SizeOf((int)elevationResult) Je ne sais pas encore pourquoi. Le message d'exception est : Méthode non trouvée. À : Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).

0 votes

@RageCompex Utilisez-vous une plateforme restreinte comme une application universelle ou Unity3d ?

16voto

Preet Sangha Points 39414

Le site Projet CodePlex UAChelper a un code qui vérifie l'élévation dans UserAccountControl.cpp UserAccountControl::IsUserAdmin qui vérifie si l'UAC est activé et ensuite vérifie si le processus est élevé.

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

de la fonction :

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

11voto

Rafael Points 108

Dans .net Framwork 4.5 j'ai trouvé une autre méthode qui fonctionne pour moi. En relation avec le script suivant qui se trouve ici ici (en allemand)

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

En C#, cela ressemble à ceci :

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

Mais dans .net < 4.5 le WindowsPrincipal ne contient pas la classe UserClaims propriété et je n'ai trouvé aucun moyen d'obtenir cette information.

2 votes

FYI : Détermine seulement si le compte est administrateur, pas si l'application est élevée.

0 votes

Pour vérifier si un utilisateur est membre de S-1-5-32-544 (groupe Administrateurs) en .Net < 4.5, vous pouvez simplement utiliser le code de la question originale. Le principal ne sera membre du groupe Administrateurs que si le processus est exécuté en élévation et que l'utilisateur est dans le groupe. Si le processus n'est pas élevé, le principal ne sera pas dans le groupe.

1 votes

Belle réponse, courte et efficace, je vous ai donné un +1 pour cela. N.B. J'en ai fait une propriété dans mon code ( private bool IsAdmin{ get { ... } } ), alors vous n'avez pas besoin des parenthèses si vous invoquez IsAdmin .

5voto

Anders Points 34448

Utilisation de TokenElevationType fonctionnerait, mais si vous PInvoke CheckTokenMembership() par rapport au SID du groupe admin, votre code fonctionnerait également lorsque l'UAC est désactivé et sur 2000/XP/2003 et traiterait également les SID refusés.

Il existe également un IsUserAnAdmin() qui fait le CheckTokenMembership vérifier pour vous, mais MSDN dit qu'il pourrait ne pas être là pour toujours

0 votes

J'ai trouvé CheckTokenMembership insuffisant lorsqu'il est soumis à l'UAC - github.com/chocolatey/choco/blob/ retourne faux. Vérifiez le code (je le remplace) et jetez un coup d'œil à la sortie de Win2012R2 - i.imgur.com/gX3JP0W.png

0 votes

@ferventcoder Cela dépend de ce que vous voulez vraiment savoir ; l'utilisateur est-il un administrateur élevé pour le moment ou peut-il s'élever si nécessaire. Vous pouvez par exemple vérifier TOKEN_ELEVATION_TYPE et obtenir quelque chose comme : bool is_or_can_elevate() { return process_is_elevated() || TokenElevationTypeLimited == get_current_token_elevation_type() ; }. Un autre problème est que la définition de "elevated" n'est pas la même partout, vous pouvez avoir une fenêtre de console avec le préfixe "Administrator : " et être en même temps sous le niveau d'intégrité High ! TokenElevation ne correspond pas toujours à TokenIntegrityLevel.

0 votes

Du bon temps. Je veux savoir si j'ai un processus élevé distinct du fait que l'utilisateur est un administrateur. Voici où j'ai abouti. Faites-moi savoir où je dois aller si c'est faux - github.com/chocolatey/choco/issues/77#issuecomment-73523774 et github.com/chocolatey/choco/commit/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X