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


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-73523774github.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)를 수정합니다.

당신은 단지 현재의 프로세스를 원하는 경우, 교체 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

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.