我使用 GetTokenInformation 作为确定当前线程是否以管理员身份运行的代码的一部分。

无论如何,我有一个 token 信息结构,如下所示:

Private Type TOKEN_GROUPS
   GroupCount As Long
   Groups(500) As SID_AND_ATTRIBUTES
End Type

然后,我像这样调用 GetTokenInformation:
res = GetTokenInformation(<Process Handle>, 2, <TOKEN_GROUPS>, _
                            <Token Info Length>, <Buffer Length)

第一次调用是获取缓冲区长度,然后我再次调用它以获取 token 信息。

无论如何,当运行应用程序的帐户连接到域时,应用程序会突然崩溃。显然,大小,
Groups(500) As SID.AND.ATTRIBUTES

不够,导致缓冲区溢出。我不知道为什么会这样(MSDN 说我应该提供 ANYSIZE_ARRAY 或 1)。将组的大小增加到 1000 可以解决此问题。

作为一个快速解决方案,并且由于我不知道如何获得适当大小的组,我计划在调用成功之前重新调整组的大小。

这是我的问题:
  • 我有一个 On Error 子句,但是当发生缓冲区溢出时,On Error 无法捕获它,我的应用程序突然崩溃。这是为什么?
  • 鉴于下面的代码
  • Private Type TOKEN_GROUPS
       GroupCount As Long
       Groups() As SID_AND_ATTRIBUTES 'FAILING
       'Groups(1000) As SID_AND_ATTRIBUTES DOES NOT FAIL
    End Type
    
    Dim X as TOKEN_GROUPS
    ReDim Preserve X.Groups(1000) As SID_AND_ATTRIBUTES 'FAILING
    
    res = GetTokenInformation(<Process Handle>, 2, <TOKEN_GROUPS>, <Token Info Length>, <Buffer Length)
    
    res = GetTokenInformation(<Process Handle>, 2, <TOKEN_GROUPS>, <Token Info Length>, <Buffer Length)
    

    为什么当我将 Groups 声明为 1000 时,GetTokenInformation 调用没有失败,但是当我声明一个“空”Groups() 并将其重新调整为 1000 时,它却失败了?

    最佳答案

    如果要为 Groups 使用动态大小的数组,则需要“自定义 API 调用编码(marshal)”代码。基本上是一对 CopyMemory 和一个数组调整大小

    Option Explicit
    
    '--- for OpenProcessToken
    Private Const TOKEN_READ                    As Long = &H20008
    
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pTo As Any, uFrom As Any, ByVal lSize As Long)
    Private Declare Function GetCurrentProcess Lib "kernel32" () As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
    Private Declare Function GetTokenInformation Lib "advapi32.dll" (ByVal TokenHandle As Long, ByVal TokenInformationClass As Long, TokenInformation As Any, ByVal TokenInformationLength As Long, ReturnLength As Long) As Long
    
    Private Type SID_AND_ATTRIBUTES
        Sid             As Long
        Attributes      As Long
    End Type
    
    Private Type VB_TOKEN_GROUPS
        GroupCount      As Long
        Groups()        As SID_AND_ATTRIBUTES
    End Type
    
    
    Private Sub Command1_Click()
        Dim hProcessID      As Long
        Dim hToken          As Long
        Dim lNeeded         As Long
        Dim baBuffer()      As Byte
        Dim uGroups         As VB_TOKEN_GROUPS
    
        hProcessID = GetCurrentProcess()
        If hProcessID <> 0 Then
            If OpenProcessToken(hProcessID, TOKEN_READ, hToken) = 1 Then
                Call GetTokenInformation(hToken, 2, ByVal 0, 0, lNeeded)
                ReDim baBuffer(0 To lNeeded)
                '--- enum TokenInformationClass { TokenUser = 1, TokenGroups = 2, ... }
                If GetTokenInformation(hToken, 2, baBuffer(0), UBound(baBuffer), lNeeded) = 1 Then
                    Call CopyMemory(uGroups.GroupCount, baBuffer(0), 4)
                    ReDim uGroups.Groups(0 To uGroups.GroupCount - 1)
                    Call CopyMemory(uGroups.Groups(0), baBuffer(4), uGroups.GroupCount * Len(uGroups.Groups(0)))
                End If
                Call CloseHandle(hToken)
            End If
            Call CloseHandle(hProcessID)
        End If
    End Sub
    

    关于winapi - 在 Visual Basic 6 中使用 GetTokenInformation 确定用户是否为管理员,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1847226/

    10-13 06:12