APICall GetTokenInformation возвращает значение ошибки - PullRequest
0 голосов
/ 13 июня 2019

Я использую следующий код C #:

enum TOKEN_INFORMATION_CLASS
{
    TokenUser = 1,
    TokenGroups,
    TokenPrivileges,
    TokenOwner,
    TokenPrimaryGroup,
    TokenDefaultDacl,
    TokenSource,
    TokenType,
    TokenImpersonationLevel,
    TokenStatistics,
    TokenRestrictedSids,
    TokenSessionId,
    TokenGroupsAndPrivileges,
    TokenSessionReference,
    TokenSandBoxInert,
    TokenAuditPolicy,
    TokenOrigin
}

[StructLayout(LayoutKind.Sequential)]
public struct SID_AND_ATTRIBUTES
{
    public IntPtr Sid;
    public UInt32 Attributes;
}

[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_GROUPS
{
    public UInt32 GroupCount;
    // Followed by this:
    [MarshalAs(UnmanagedType.ByValArray)]
    public SID_AND_ATTRIBUTES[] Groups;
}

internal class TokenInformationTools : ITokenInformationTools
{

    [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
    static extern int OpenProcessToken(System.IntPtr processHandle, int desiredAccess, ref IntPtr tokenHandle);
    const int OpenProcessTokenFail = 0;

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern int GetTokenInformation(IntPtr tokenHandle, TOKEN_INFORMATION_CLASS tokenInformationClass, IntPtr tokenInformation, int tokenInformationLength, out int returnLength);
    const int GetTokenInformationFail = 0;

    [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool ConvertSidToStringSid(IntPtr securityIdentifier, out string securityIdentifierName);

    [DllImport("kernel32.dll")]
    static extern uint GetLastError();

    public bool CheckForTokenGroup(string tokenGroupName)
    {
        var processHandle = Process.GetCurrentProcess().Handle;
        IntPtr tokenHandler = IntPtr.Zero;
        const int TOKEN_READ = 0x20008;
        if (OpenProcessToken(processHandle, TOKEN_READ, ref tokenHandler) != OpenProcessTokenFail)
        {
            int length = 0;
            var getTokenInformationReturnValue = GetTokenInformation(tokenHandler, TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero, 0, out length);
            if (getTokenInformationReturnValue != GetTokenInformationFail)
            {
                var tokenInfo = Marshal.AllocHGlobal(length);
                if (GetTokenInformation(tokenHandler, TOKEN_INFORMATION_CLASS.TokenGroups, tokenInfo, length, out length) != GetTokenInformationFail)
                {
                    int groupCount = Marshal.ReadInt32(tokenInfo);
                    const int sizeDword = 4;
                    var pSaa = tokenInfo + sizeDword;
                    for (int i = 0; i < groupCount; i++)
                    {
                        var groupInfo = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure((IntPtr)pSaa, typeof(SID_AND_ATTRIBUTES));
                        string sidAsString = string.Empty;
                        ConvertSidToStringSid(groupInfo.Sid, out sidAsString);
                        if (sidAsString == tokenGroupName)
                        {
                            Marshal.FreeHGlobal(tokenInfo);
                            return true;
                        }
                        pSaa += Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES));
                    }
                }
                else
                {
                    var error = GetLastError();
                }
                Marshal.FreeHGlobal(tokenInfo);
            }
            else
            {
                var error = GetLastError();
            }
        }
        return false;
    }
}

Проблема в том, что getTokenInformationReturnValue равен 0 при первом вызове.Итак, как описано здесь: https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-gettokeninformation это ошибка:

If the function succeeds, the return value is nonzero.

GetLastError возвращает 0, что означает « Операция успешно завершена. » в соответствии с этим: https://docs.microsoft.com/de-de/windows/desktop/Debug/system-error-codes--0-499-

Но функция все равно работает.Если я игнорирую getTokenInformationReturnValue (и возвращаемое значение следующего вызова GetTokenInformation), кажется, что все работает как задумано.

Этот код является копией следующего кода VBA, где возвращаемое значение GetTokenInformationFail не равно 0.

Enum TokenInformation
  TokenUser = 1
  TokenGroups = 2
End Enum

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 Const GetCurrentProcessFail As Long = 0

Private Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Const OpenProcessTokenFail As Long = 0
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 Const GetTokenInformationFail As Long = 0
Private Declare Function ConvertSidToStringSid Lib "advapi32.dll" Alias "ConvertSidToStringSidA" (ByVal lpSid As Long, lpString As Long) As Long
Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString 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 Const SizeDword As Long = 4

Public Function fn_checkForTokenGroup(ByVal par_UserGroupSid As String) As Boolean

  Dim dPseudoProcessHandle As Long
  Dim dTokenHandler As Long
  Dim dNeeded As Long
  Dim dReadBuffer() As Byte
  Dim dStringBuffer As String
  Dim dStringPointer As Long
  Dim dGroupData As VB_TOKEN_GROUPS

  On Error GoTo fn_checkForTokenGroup_error

  fn_checkForTokenGroup = False

  dPseudoProcessHandle = GetCurrentProcess()
  If dPseudoProcessHandle <> GetCurrentProcessFail Then
    If OpenProcessToken(dPseudoProcessHandle, TOKEN_READ, dTokenHandler) <> OpenProcessTokenFail Then
      Call GetTokenInformation(dTokenHandler, TokenInformation.TokenGroups, ByVal 0, 0, dNeeded)
      ReDim dReadBuffer(0 To dNeeded)
      If GetTokenInformation(dTokenHandler, TokenInformation.TokenGroups, dReadBuffer(0), UBound(dReadBuffer), dNeeded) <> GetTokenInformationFail Then
        Call CopyMemory(dGroupData.GroupCount, dReadBuffer(0), SizeDword)
        ReDim dGroupData.Groups(0 To dGroupData.GroupCount - 1)
        Call CopyMemory(dGroupData.Groups(0), dReadBuffer(SizeDword), dGroupData.GroupCount * Len(dGroupData.Groups(0)))

        Dim i As Long
        For i = 0 To dGroupData.GroupCount - 1
          If ConvertSidToStringSid(dGroupData.Groups(i).Sid, dStringPointer) Then
            dStringBuffer = Space(lstrlen(dStringPointer))
            Call CopyMemory(ByVal dStringBuffer, ByVal dStringPointer, Len(dStringBuffer))
            Call LocalFree(dStringPointer)
            If (dStringBuffer = par_UserGroupSid) Then
              fn_checkForTokenGroup = True
              GoTo fn_checkForTokenGroup_endeSchleife:
            End If
          End If
        Next
fn_checkForTokenGroup_endeSchleife:

      End If
      Call CloseHandle(dTokenHandler)
    End If
    Call CloseHandle(dPseudoProcessHandle)
  End If

fn_checkForTokenGroup_exit:

  Exit Function

fn_checkForTokenGroup_error:
  Call msg_error_norm(ModuleName, "CheckForTokenGroup")
  GoTo fn_checkForTokenGroup_exit:
End Function

Так в чем же проблема с моим кодом C #?Что-то не так с моими заявлениями?

1 Ответ

1 голос
/ 16 июня 2019

Вы не должны использовать GetLastError но

 int nLastWin32Error = Marshal.GetLastWin32Error();

когда возвращаемое значение равно 0 и проверить, если эта ошибка == ERROR_INSUFFICIENT_BUFFER (122), тогда вы можете позвонить Marshal.AllocHGlobal

...