상승 된 권한이 있거나없는 관리자로 실행 중인지 감지 하시겠습니까?


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

1
또한 계정이 기본 제공 관리자 인 경우 UAC는 기본적으로 상승하므로이 경우 IsProcessElevated는 false를 반환합니다 (IsUacEnabled가 true이고 상승 결과가 TokenElevationTypeDefault이므로). 사용자에게 메시지를 표시했습니다. 즉, 계정이 상승되고 프로세스가 기본 상승 유형으로 실행됩니다.
— Mister Cook

2
이 코드에는 다음 using 문이 필요합니다. using System.Diagnostics; System.Runtime.InteropServices 사용; System.Security.Principal 사용; 또한 여기에
— Scott Solmer 2014

이로 인해 Windows 8에서 예외가 발생했습니다 Marshal.SizeOf((int)elevationResult). 아직 이유가 확실하지 않습니다. 예외 메시지 : 메소드를 찾을 수 없습니다. 장소 :Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).
— CularBytes

TokenElevationTypeLimited는 어떻습니까? isProcessAdmin을 true로 설정하는 것을 고려하지 않아야합니까?
— Olivier MATROT

33

( 질문을받은 지 6 년 후 새로운 답변 )

면책 조항 : 이것은 특정 사용자의 특정 설정으로 특정 OS에서 작동하는 일입니다.

using System.Security.Principal;

// ...

    static bool IsElevated
    {
      get
      {
        return WindowsIdentity.GetCurrent().Owner
          .IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
      }
    }

따라서이 "관리자 권한으로 실행"을 실행하면 속성 get접근자가 true. 정상적으로 실행되면 (내 사용자가 "관리자"인 경우에도이 특정 응용 프로그램을 "관리자"로 "실행하지 않는 경우에도)을 반환합니다 false.

이것은 다른 많은 답변보다 훨씬 간단 해 보입니다.

이것이 실패하는 경우가 있는지 모르겠습니다.

추신! 이것도 괜찮아 보입니다.

    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)에서 이것을 사용했습니다.
— Lewis

알림을 '알림 표시 안함'으로 설정하면 true가 반환됩니다. 관리자로 소프트웨어를 실제로 실행해야하는 특정 시나리오에서는 잘못된 표시를 줄 수 있습니다.
— CularBytes

2
이것은 "semi-unlevated"프로세스와 적절하게 unlevated 프로세스를 구분하지 않습니다. IsElevatedfalse를 반환 할 수 있지만 프로세스가 여전히 높은 무결성 수준으로 실행될 수 있습니다. 진정으로 승격되지 않은 프로세스의 무결성 수준은 중간입니다. 이는 애플리케이션의 99 %와는 무관 할 수 있지만 Process Hacker와 같은 도구가 여전히 이러한 프로세스를 상승시킬 수 있다고 선언 할 수 있기 때문에 언급 할 가치가 있습니다. "semi-unlevated"프로세스는 일반적으로 볼 수있는 것이 아닙니다. 누군가가 권한없는 하위 프로세스를 올바르게 시작하지 못할 때 발생할 수 있습니다.
— Roman Starkov

"높은 무결성 수준으로 실행"이란 무엇입니까?
— StingyJack

@StingyJack은 댓글로 답하기에는 너무 큰 질문이지만 여기 와 여기를 참조 하십시오 .
— Roman Starkov

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 사용자로 실행 중인지 감지하려고합니까? "관리 상태"감지는 로컬 시스템과 로컬 서비스의 차이를 구분하는 데 작동하지 않으므로 프로세스를 실행중인 사용자를 직접 확인하여 테스트해야합니다.
— Scott Chamberlain

이로 인해 Windows 8에서 예외가 발생했습니다 Marshal.SizeOf((int)elevationResult). 아직 이유가 확실하지 않습니다. 예외 메시지 : 메소드를 찾을 수 없습니다. 장소 :Int32 System.Runtime.InteropServices.Marshal.SizeOf(!!0).
— CularBytes

@RageCompex 범용 앱 또는 Unity3d와 같은 제한된 플랫폼을 사용하고 있습니까?
— Scott Chamberlain

1
아, 이 오버로드 를 사용하려고하는데 4.5.1이 설치되어 있지 않기 때문에 4.5.1로 컴파일하고 있습니다. 로 대체하십시오 Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE)),
— 스콧의 전관

2
@ScottChamberlain 은 32 비트 응용 프로그램 .NET 4.0을 int elevationResultSize = Marshal.SizeOf(typeof(TOKEN_ELEVATION_TYPE))던졌습니다 . ArgumentExceptionint elevationResultSize = Marshal.SizeOf((int)elevationResult)
— Martin Braun

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

사용자가 .Net <4.5에서 S-1-5-32-544 (관리자 그룹)의 구성원인지 확인하려면 원래 질문의 코드를 사용하면됩니다. 프린시 펄은 프로세스가 상승되고 사용자가 그룹에있는 경우에만 Administrators 그룹의 구성원이됩니다. 프로세스가 승격되지 않으면 주체가 그룹에 포함되지 않습니다.
— Adam

1
짧고 효율적인 좋은 답변입니다. +1을주었습니다. NB 내 코드 ( private bool IsAdmin{ get { ... } }) 에서 이것을 속성으로 만들었으므로을 호출하면 대괄호가 필요하지 않습니다 IsAdmin.
— Matt

4

을 사용 TokenElevationType하면 작동하지만 CheckTokenMembership()관리자 그룹 SID에 대해 PInvoke 를 수행하면 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을 확인하고 다음과 같이 끝낼 수 있습니다. bool is_or_can_elevate () {return process_is_elevated () || TokenElevationTypeLimited == get_current_token_elevation_type (); }. 또 다른 문제는 승격의 정의가 모든 곳에서 동일하지 않다는 것입니다. "관리자 :"접두사가있는 콘솔 창을 가질 수 있으며 동시에 높은 무결성 수준보다 낮을 수 있습니다! TokenElevation이 항상 TokenIntegrityLevel과 일치하는 것은 아닙니다.
— Anders

즐거운 시간. 사용자가 관리자인지 여부와는 별도로 승격 된 프로세스가 있는지 알고 싶습니다. 여기에 내가 끝났다. 잘못된 경우 어디로 가야하는지 알려주세요 -github.com/chocolatey/choco/issues/77#issuecomment-73523774 및 github.com/chocolatey/choco/commit/…
— ferventcoder

@ferventcoder is_processes_elevated () {Return CheckTokenMembership / IsInRole || TokenElevation / TokenIntegrityLevel> = 0x3000; } CheckTokenMembership 또는 IsInRole for <Vista and Vista + with UAC off. 정확한 고도 감지 방법에 따라 TokenElevation 또는 TokenIntegrityLevel> = 0x3000입니다. conhost.exe가 TokenElevation을 사용한다고 믿지만 IMHO가 깨졌고 실제 수준을 확인해야합니다 ... (TokenElevation을 속이는 토큰을 생성하려면 특수 도구가 필요합니다) 참조 : windowssucks.wordpress.com/2011/02/07 / uac-are-you-high / #
— Anders

... 그리고 그것은 일종의 잘못된 것입니다. 이론적으로는 관리자 그룹에 속하지 않고 상승 된 토큰을 가질 수 있습니다. 따라서 관리자 그룹의 사람 만 원하고 승격되었는지 확인하는 경우 CheckTokenMembership / IsInRole 확인을 수행 한 다음 Token * 확인이 실패해야합니다 (UAC 없음). 그렇지 않으면 값이 승격을 나타내야합니다. 실제로 액세스하려는 항목에 대해 시스템 / 관리자 권한이 필요하거나 권한이 상승해야 할 수도 있습니다. 이는 ACL에 따라 다릅니다.
— Anders

4

이 답변 에는 몇 가지 문제가 있습니다. 첫째, 관리자로 실행되는 시스템 프로세스 (예 : NT-Authority / SYSTEM에서)를 가져 오지 않습니다. 아래 코드 예제는 모든 문제 (detects, 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;
}

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

1

사용 UACHelper nuget 패키지 : https://www.nuget.org/packages/UACHelper/

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

사용자가 실제로 관리자인지, 프로세스가 UAC 가상화에서 실행 중인지 또는 데스크톱 소유자가 프로세스 소유자인지 감지하는 데 사용할 수있는 다른 속성이 많이 있습니다. (제한된 계정에서 실행)

자세한 내용은 읽어보기를 확인하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.