昇格された特権の有無にかかわらず、管理者として実行されているかどうかを検出しますか?


82

昇格された特権で実行されているかどうかを検出する必要があるアプリケーションがあります。私は現在、次のようにコードを設定しています。

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

これは、ユーザーが管理者であるかどうかを検出するために機能しますが、昇格なしで管理者として実行している場合は機能しません。(たとえば、vshost.exeで)。

仰角が[すでに有効であるか]可能かどうかをどのように判断できますか?

回答:


55

これを試してみてください:

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
アカウントをローカル管理者として実行する場合は機能しますが、ドメイン管理者を使用する場合、変数isProcessAdminはfalseを返します。しかし、UACは、特権を昇格するときにドメイン管理者を有効として受け入れます(Windowsでフォルダーを作成する、管理者として実行するなど)...その場合も考慮に入れるように関数を変更するにはどうすればよいですか?
VSP 2012

1
また、アカウントが組み込みの管理者である場合、UACはデフォルトで昇格されるため、プロセスが昇格モードで実行されていても、この場合はIsProcessElevatedがfalseを返すことを考慮する必要があります(IsUacEnabledがtrueでelevationResultがTokenElevationTypeDefaultであるため)。ユーザーにプロンプ​​トを表示しました。つまり、アカウントは昇格され、プロセスはデフォルトの昇格タイプで実行されます。
ミスタークック

2
このコードには、次のusingステートメントが必要です。usingSystem.Diagnostics; System.Runtime.InteropServicesを使用する; System.Security.Principalを使用します。ここにも反映されている
スコットソルマー2014

これにより、Windows 8で例外が発生しましたMarshal.SizeOf((int)elevationResult)。理由は、まだわかりません。例外メッセージは次のとおりです。メソッドが見つかりません。で:Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).
CularBytes 2016年

TokenElevationTypeLimitedはどうですか?isProcessAdminをtrueに設定することを考慮すべきではありませんか?
Olivier MATROT 2016

34

(質問から6年後の新しい回答)

免責事項:これは、特定のユーザーの特定の設定で、特定のOSでたまたま機能したものです。

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

1
これをありがとう!-これをPowerShellで使用しました[Security.Principal.WindowsIdentity] :: GetCurrent()。Owner.IsWellKnown([System.Security.Principal.WellKnownSidType] :: BuiltinAdministratorsSid)
ルイス

通知を「通知を表示しない」に設定した場合、これはtrueを返します。おそらく、管理者としてソフトウェアを実行する必要がある特定のシナリオでは、誤った表示をする可能性があります。
CularBytes 2016年

2
これは、「半昇格」プロセスと適切に昇格されていないプロセスを区別しません。falseIsElevatedを返す可能性がありますが、プロセスは高整合性レベルで実行されている可能性があります。真に昇格されていないプロセスの整合性レベルは中程度です。これはおそらくアプリケーションの99%には関係ありませんが、Process Hackerのようなツールはまだそのようなプロセスを昇格すると宣言する可能性があるため、言及する価値があります。「半上昇」プロセスは、通常見られるものではありません。誰かが昇格されていない子プロセスを正しく起動できなかった場合に発生する可能性があります。
ローマンスターコフ2016年

「高い整合性レベルで実行」とは何ですか?
stingyJack 2017年

@StingyJackは、コメントで答えるには大きすぎる質問ですが、ここここを参照ください
ローマンスターコフ2017年

19

これは、リソースの適切な廃棄やドメイン管理者の処理などを含むように、この回答を修正したものです。

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

それはすべて、サービスを実行しているユーザーによって異なります。サービスがローカルシステム、ローカルサービス、ネットワークサービス、またはWindowsユーザーとして実行されているかどうかを検出しようとしていますか?「管理ステータス」の検出は、ローカルシステムとローカルサービスの違いを区別するためには機能しません。プロセスを実行しているユーザーを直接確認して、そのことをテストする必要があります。
スコットチェンバレン

これにより、Windows 8で例外が発生しましたMarshal.SizeOf((int)elevationResult)。理由は、まだわかりません。例外メッセージは次のとおりです。メソッドが見つかりません。で:Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).
CularBytes 2016年

@RageCompexは、ユニバーサルアプリやUnity3dなどの制限されたプラットフォームを使用していますか?
スコットチェンバレン

1
ああ、このオーバーロードを使おうとしているのに4.5.1でコンパイルしていますが、ユーザーには4.5.1がインストールされていません。それを交換してみてくださいMarshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE))
スコット・チェンバレン

2
@ScottChamberlainint elevationResultSize = Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE))は、ArgumentException32ビットアプリケーション.NET 4.0をスローしますが、int elevationResultSize = Marshal.SizeOf((int)elevationResult)機能しました。
マーティンブラウン

16

CodePlexのプロジェクトUAChelperはUserAccountControl.cppの上昇にチェックするコード有し、UserAccountControl::IsUserAdminUACが有効になっているかどうかを確認すること、そして次にチェックは、プロセスが上昇する場合が。

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

10

.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プロパティが含まれておらず、この情報を取得する方法が見つかりませんでした。


参考:アカウントが管理者であるかどうかのみを判断し、アプリが昇格されているかどうかは判断しません
CularBytes 2016年

ユーザーが.Net <4.5のS-1-5-32-544(Administratorsグループ)のメンバーであるかどうかを確認するには、元の質問のコードを使用するだけです。プリンシパルは、プロセスが昇格して実行されており、ユーザーがグループに属している場合にのみ、Administratorsグループのメンバーになります。プロセスが昇格されていない場合、プリンシパルはグループに含まれません。
アダム

1
いい答えです、短くて効率的です、私はあなたにそれのために+1を与えました。注意:これをコード(private bool IsAdmin{ get { ... } })でプロパティにしたので、を呼び出す場合は括弧は必要ありませんIsAdmin
マット

4

を使用しても機能しますが、管理グループSIDに対してTokenElevationTypePInvokeを実行するCheckTokenMembership()と、UACがオフおよびオンの2000 / XP / 2003でもコードが機能し、拒否SIDも処理されます。

あなたのためIsUserAnAdmin()CheckTokenMembershipチェックをする機能もありますが、MSDNはそれが永遠にそこにないかもしれないと言います


UACの対象となる場合、CheckTokenMembershipが不十分であることがわかりました-github.com/chocolatey/choco/blob/…はfalseを返します。コードを確認してください(私はそれを交換しています)とWin2012R2からの出力を見てみましょう- i.imgur.com/gX3JP0W.png
ferventcoder

@ferventcoderそれはあなたが本当に知りたいことによります。現在、昇格した管理者のユーザーですか、必要に応じて昇格できますか。たとえば、TOKEN_ELEVATION_TYPEを確認すると、次のようになります。boolis_or_can_elevate(){return process_is_elevated()|| TokenElevationTypeLimited == get_current_token_elevation_type(); }。もう1つの問題は、昇格の定義がどこでも同じではないことです。「Administrator:」プレフィックスが付いたコンソールウィンドウを作成すると同時に、高整合性レベルを下回ることができます。TokenElevationは、TokenIntegrityLevelと常に一致するとは限りません。
アンダース

楽しい時間。ユーザーが管理者であるかどうかとは別に、昇格されたプロセスがあるかどうかを知りたいです。これが私が終わったところです。-それは間違っている場合、私は行くべき場所を私に教えてくださいgithub.com/chocolatey/choco/issues/77#issuecomment-73523774github.com/chocolatey/choco/commit/...
ferventcoder

@ferventcoder is_processes_elevated(){return CheckTokenMembership / IsInRole || TokenElevation / TokenIntegrityLevel> = 0x3000; } CheckTokenMembershipまたはIsInRolefor <VistaおよびVista +、UACがオフ。標高を正確に検出する方法に応じて、TokenElevationまたはTokenIntegrityLevel> = 0x3000。:私も参照してください(あなたががトークンその愚か者のTokenElevationを生成するための特別なツールを必要とする)... conhost.exe用途にTokenElevationを信じていますが、IMHO壊れていると、あなたが実際のレベルをチェックする必要がありますwindowssucks.wordpress.com/2011/02/07 / uac-are-you-high /#
アンダース

...そしてそれでも一種の間違いですが、理論的には、昇格されたトークンを持ち、管理者グループに属していない可能性があります。したがって、管理者グループのユーザーのみが必要で、昇格されていることを確認する場合は、CheckTokenMembership / IsInRoleチェックを実行してから、Token *チェックが失敗するか(UACなし)その値が昇格を示す必要があります...これはもちろん異なります実際にアクセスしたいものについて。ACLによって異なりますが、システム/管理者で昇格する必要がある場合もあれば、昇格する必要がある場合もあります。
アンダース

4

この回答にはいくつかの問題があります。まず、管理者として実行されるシステムプロセスを取得しません(たとえば、NT-Authority / SYSTEMの下で)。以下のコード例は、すべての問題(detects、LocalAdmins、DomainAdmins、およびLocalSystemAdmins)を修正します。

あなただけの現在のプロセスが必要な場合は、交換するpHandleProcess.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;
}

1

もう一つ問題があると思います。私はあなたから提供された解決策をチェックしましたが、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

その方法はすべて、以前の投稿で説明されています。


1
これは答えではありませんが、間違いなく別の投稿への解説です
MickyD 2015年

1

UACHelper nugetパッケージの使用:https://www.nuget.org/packages/UACHelper/

if (UACHelper.IsElevated)
    // something
else
    // something else

ユーザーが実際に管理者であるかどうか、プロセスがUAC仮想化で実行されているかどうか、またはデスクトップ所有者がプロセス所有者であるかどうかを検出するために使用できるプロパティは他にもたくさんあります。(限定アカウントから実行)

詳細については、私を読んでください。


1

私はこのコードを使用していますが、うまく機能します。


bool runningAsAdmin = WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);

* AdminはBuild-InAdministratorsグループの一部です。

「システム管理者のユーザーアカウント。このアカウントは、オペレーティングシステムのインストール中に作成された最初のアカウントです。アカウントを削除またはロックアウトすることはできません。Administratorsグループのメンバーであり、そのグループから削除することはできません。」- https://ss64.com/nt/syntax-security_groups.html

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.