在Visual Basic 6中使用GetTokenInformation来确定用户是否是管理员

时间:2009-12-04 14:18:49

标签: winapi vb6 windows-security

我使用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)

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

无论如何,当运行应用程序的帐户连接到域时,应用程序将突然崩溃。显然,组(500)As SID.AND.ATTRIBUTES的大小是不够的,并导致缓冲区溢出。我不知道为什么会这样(MSDN说我应该提供一个ANYSIZE_ARRAY或1)。将组的大小增加到1000可以解决问题。

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

这是我的问题:

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

  2. 鉴于以下代码

    私人类型TOKEN_GROUPS    GroupCount As Long    Groups()作为SID_AND_ATTRIBUTES'失败    '组(1000)因为SID_AND_ATTRIBUTES没有失败 结束类型

    Dim X为TOKEN_GROUPS ReDim保留X.Groups(1000)作为SID_AND_ATTRIBUTES'失败

    res = GetTokenInformation(,2 ,,,

    res = GetTokenInformation(,2 ,,,

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

    谢谢!

2 个答案:

答案 0 :(得分:2)

如果要为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

答案 1 :(得分:1)

还有另一个问题here似乎解决了GetTokenInformation调用问题。 从接受的答案复制:

Call GetTokenInformation(hToken, 1, ByVal 0, 0, lNeeded)
ReDim baBuffer(0 To lNeeded)
...