【问题标题】:How can I detect if my process is running UAC-elevated or not?如何检测我的进程是否正在运行 UAC 提升?
【发布时间】:2010-09-10 21:19:19
【问题描述】:

我的 Vista 应用程序需要知道用户是以“管理员”身份(提升)还是以标准用户(非提升)启动它。如何在运行时检测到它?

【问题讨论】:

标签: windows-7 windows-vista uac elevation


【解决方案1】:

这是一个检查(当前)进程是否被提升的 VB6 实现

Option Explicit

'--- for OpenProcessToken
Private Const TOKEN_QUERY                   As Long = &H8
Private Const TokenElevation                As Long = 20

Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
Private Declare Function OpenProcessToken Lib "advapi32" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Declare Function GetTokenInformation Lib "advapi32" (ByVal TokenHandle As Long, ByVal TokenInformationClass As Long, TokenInformation As Any, ByVal TokenInformationLength As Long, ReturnLength As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long


Public Function IsElevated(Optional ByVal hProcess As Long) As Boolean
    Dim hToken          As Long
    Dim dwIsElevated    As Long
    Dim dwLength        As Long

    If hProcess = 0 Then
        hProcess = GetCurrentProcess()
    End If
    If OpenProcessToken(hProcess, TOKEN_QUERY, hToken) <> 0 Then
        If GetTokenInformation(hToken, TokenElevation, dwIsElevated, 4, dwLength) <> 0 Then
            IsElevated = (dwIsElevated <> 0)
        End If
        Call CloseHandle(hToken)
    End If
End Function

【讨论】:

    【解决方案2】:

    我不认为海拔类型是您想要的答案。您只想知道它是否升高。调用 GetTokenInformation 时使用 TokenElevation 而不是 TokenElevationType。如果结构返回正值,则用户是管理员。如果为零,则用户是正常海拔。

    这是一个 Delphi 解决方案:

    function TMyAppInfo.RunningAsAdmin: boolean;
    var
      hToken, hProcess: THandle;
      pTokenInformation: pointer;
      ReturnLength: DWord;
      TokenInformation: TTokenElevation;
    begin
      hProcess := GetCurrentProcess;
      try
        if OpenProcessToken(hProcess, TOKEN_QUERY, hToken) then try
          TokenInformation.TokenIsElevated := 0;
          pTokenInformation := @TokenInformation;
          GetTokenInformation(hToken, TokenElevation, pTokenInformation, sizeof(TokenInformation), ReturnLength);
          result := (TokenInformation.TokenIsElevated > 0);
        finally
          CloseHandle(hToken);
        end;
      except
       result := false;
      end;
    end;
    

    【讨论】:

      【解决方案3】:

      以下 C++ 函数可以做到这一点:

      HRESULT GetElevationType( __out TOKEN_ELEVATION_TYPE * ptet );
      
      /*
      Parameters:
      
      ptet
          [out] Pointer to a variable that receives the elevation type of the current process.
      
          The possible values are:
      
          TokenElevationTypeDefault - This value indicates that either UAC is disabled, 
              or the process is started by a standard user (not a member of the Administrators group).
      
          The following two values can be returned only if both the UAC is enabled
          and the user is a member of the Administrator's group:
      
          TokenElevationTypeFull - the process is running elevated. 
      
          TokenElevationTypeLimited - the process is not running elevated.
      
      Return Values:
      
          If the function succeeds, the return value is S_OK. 
          If the function fails, the return value is E_FAIL. To get extended error information, call GetLastError().
      
      Implementation:
      */
      
      HRESULT GetElevationType( __out TOKEN_ELEVATION_TYPE * ptet )
      {
          if ( !IsVista() )
              return E_FAIL;
      
          HRESULT hResult = E_FAIL; // assume an error occurred
          HANDLE hToken   = NULL;
      
          if ( !::OpenProcessToken( 
                      ::GetCurrentProcess(), 
                      TOKEN_QUERY, 
                      &hToken ) )
          {
              return hResult;
          }
      
          DWORD dwReturnLength = 0;
      
          if ( ::GetTokenInformation(
                      hToken,
                      TokenElevationType,
                      ptet,
                      sizeof( *ptet ),
                      &dwReturnLength ) )
          {
                  ASSERT( dwReturnLength == sizeof( *ptet ) );
                  hResult = S_OK;
          }
      
          ::CloseHandle( hToken );
      
          return hResult;
      }
      

      【讨论】:

      【解决方案4】:

      对于我们这些使用 C# 的人,在 Windows SDK 中有一个“UACDemo”应用程序作为“交叉技术示例”的一部分。他们使用这种方法查找当前用户是否是管理员:

      private bool IsAdministrator
      {
          get
          {
              WindowsIdentity wi = WindowsIdentity.GetCurrent();
              WindowsPrincipal wp = new WindowsPrincipal(wi);
      
              return wp.IsInRole(WindowsBuiltInRole.Administrator);
          }
      }
      

      (注意:我将原始代码重构为属性,而不是“if”语句)

      【讨论】:

      • 问题,这会做域安全吗? (MYDOMAIN\Administrators) 或者这只是本地安全?
      • 如果您的域帐户是该机器的本地管理员或域管理员 - 默认情况下它将在该本地组中,afaik。
      • 问题是用户可能是管理员,但仍可能在非管理员模式下运行应用程序(默认情况下不是)。 WindowsBuildInRole.Administrator 可以捕捉到吗?
      • @David Brunelle - 它在程序运行时工作,但请注意从 VS 中调试时结果可能无法预测。我遇到了这个问题,直到我发现调试器仍在以非提升用户身份运行程序,即使 IsInRole(WindowsBuiltInRole.Administrator) 返回 true。在调试器之外就像一个魅力。
      • +1 用于引用代码的原始源。我到处都看到过这些行,但这是唯一提供参考的帖子。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      • 2012-06-16
      • 2015-10-28
      • 1970-01-01
      • 2020-12-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多