3

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

无论如何,我有一个 TOKEN INFORMATION 的结构,如下所示:

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)

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

无论如何,当运行应用程序的帐户连接到域时,应用程序会突然崩溃。显然,

Groups(500) As SID.AND.ATTRIBUTES

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

作为一种快速解决方法,由于我不知道如何获得适当大小的 Groups,我打算只重新调整 Groups 直到调用成功。

这是我的问题:

  1. 我有一个On Error子句,但是当缓冲区溢出时,On Error无法捕获它并且我的应用程序突然崩溃。这是为什么?

  2. 鉴于下面的代码

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 时,它失败了?

4

2 回答 2

3

如果要使用动态大小的数组,则Groups需要“自定义 API 调用编组”代码。基本上是几个 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
于 2009-12-04T22:20:34.810 回答
2

There is another question here that seems to have solved the GetTokenInformation call. Copied from the accepted answer:

Call GetTokenInformation(hToken, 1, ByVal 0, 0, lNeeded)
ReDim baBuffer(0 To lNeeded)
...
于 2009-12-04T21:26:33.340 回答