Установка размера массива TOKEN_PRIVILEGES.LUID_AND_ATTRIBUTES, возвращаемого GetTokenInformation - PullRequest
3 голосов
/ 03 декабря 2010

Я пытаюсь получить привилегии и их текущее состояние, связанное с токеном в C #, но я не могу понять, как настроить размер массива LUID_AND_ATTRIBUTES, который возвращается для соответствия фактическому количеству элементов.

С MSDN

Когда для MarshalAsAttribute.Value задано значение ByValArray, для параметра SizeConst должно быть указано количество элементов в массиве.

Мне удалось просмотреть свойство TOKEN_PRIVILEGES.PrivilegeCount после вызова GetTokenInformation и убедиться, что у токена, с которым я работал, было 24 из 35 привилегий, перечисленных на справочной странице Константы привилегий . Изменение SizeConst = 24 тогда дало бы мне возможность увидеть все из них, а не только первый (Я изначально установил SizeConst = 1, следуя примеру использования из PInvoke )

Есть ли способ указать глубину входного массива по мере его создания, или мне нужно будет узнать, сколько будет привилегий, прежде чем писать код?

Фрагмент кода

[DllImport("advapi32.dll", SetLastError = true)]
protected static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, ref int ReturnLength);

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)][return: MarshalAs(UnmanagedType.Bool)]
protected static extern bool LookupPrivilegeName(string lpSystemName, IntPtr lpLuid,System.Text.StringBuilder lpName, ref int cchName);

protected struct TOKEN_PRIVILEGES {
  public UInt32 PrivilegeCount;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
  public LUID_AND_ATTRIBUTES[] Privileges;
}//TOKEN_PRIVILEGES

[StructLayout(LayoutKind.Sequential)]
protected struct LUID_AND_ATTRIBUTES {
  public LUID Luid;
  public UInt32 Attributes;
}//LUID_AND_ATTRIBUTES

[StructLayout(LayoutKind.Sequential)]
protected struct LUID {
  public uint LowPart;
  public int HighPart;
}//LUID

int TokenInfLength = 0;
IntPtr ThisHandle = WindowsIdentity.GetCurrent().Token;
GetTokenInformation(ThisHandle, TOKEN_INFORMATION_CLASS.TokenPrivileges, IntPtr.Zero, TokenInfLength, ref TokenInfLength); //Get the TokenInformation length (returns false)
IntPtr TokenInformation = Marshal.AllocHGlobal(TokenInfLength);
if(GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenPrivileges, TokenInformation, TokenInfLength, ref TokenInfLength)){
  TOKEN_PRIVILEGES ThisPrivilegeSet = (TOKEN_PRIVILEGES)Marshal.PtrToStructure(TokenInformation, typeof(TOKEN_PRIVILEGES));
  //ThisPrivilegeSet now holds all of the LUID's i need to check out
  foreach(LUID_AND_ATTRIBUTES laa in ThisPrivilegeSet.Privileges){ //ThisPrivilegeSet.Privileges is only as deep as SizeConst will allow
    System.Text.StringBuilder StrBuilder = new System.Text.StringBuilder();
    int LuidNameLen = 0;
    IntPtr LuidPointer = Marshal.AllocHGlobal(Marshal.SizeOf(laa.Luid));
    Marshal.StructureToPtr(laa.Luid, LuidPointer, true);
    LookupPrivilegeName(null, LuidPointer, null, ref LuidNameLen); //Get the PrivilageName length (returns false)
    StrBuilder.EnsureCapacity(LuidNameLen + 1);
    if(LookupPrivilegeName(null, LuidPointer, StrBuilder, ref LuidNameLen)){ //StrBuilder gets the name this time
      Console.WriteLine("[{0}] : {1}", laa.Attributes.ToString(), StrBuilder.ToString());
    }//end if
    Marshal.FreeHGlobal(LuidPointer);
  }//next
}//end if

Это мой первый пост, так что извините, если я сделал это неправильно и TIA за помощь

Ответы [ 2 ]

2 голосов
/ 09 декабря 2010

Я хотел бы продолжить этот вопрос из-за того, что я узнал, перейдя по ссылке, предоставленной VVS.

Если вы похожи на меня и никогда не изучали или не использовали язык программирования, имеющий доступ к памятиНепосредственно вы также можете найти это интересным (кстати, я пометил ответ SwDevman81 как правильный, так как он отлично работает).

В сообщении блога, предоставленном VVS, автор говорит об использовании значения (адреса памяти) указателя, возвращаемого вызовом + размер объектов, возвращаемых для маршалинга возвращаемых данных в чанках для динамического получения переменного числа объектов.В этой ситуации, описанной в посте блога, мы извлекаем выгоду из первого возвращаемого значения, содержащего количество элементов в следующем массиве. У нас также есть целое число, возвращаемое функцией, сообщающей нам, насколько большой будет возвращенная структура, которая такжеиспользоваться, чтобы проверить, достигли ли мы конца нашей структуры, если у нас нет преимущества от значения, сообщающего нам количество элементов.

Я предоставляю приведенный ниже пример кода для всех, кто интересуется тем, как вышесообщение в блоге будет применено к этому сценарию.

Пример кода:

using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace MarshallingExample {
  class Program {

    protected struct TOKEN_PRIVILEGES {
      public UInt32 PrivilegeCount;
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
      public LUID_AND_ATTRIBUTES[] Privileges;
    }

    [StructLayout(LayoutKind.Sequential)]
    protected struct LUID_AND_ATTRIBUTES {
      public LUID Luid;
      public UInt32 Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    protected struct LUID {
      public uint LowPart;
      public int HighPart;
    }

    //This enum was huge, I cut it down to save space
    protected enum TOKEN_INFORMATION_CLASS {
      /// <summary>
      /// The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token.
      /// </summary>
      TokenPrivileges = 3
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    protected static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, ref int ReturnLength);

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool LookupPrivilegeName(string lpSystemName, IntPtr lpLuid, System.Text.StringBuilder lpName, ref int cchName);

    static void Main(string[] args) {
      //Check and print the privileges this token has
      CheckPrivileges(WindowsIdentity.GetCurrent().Token);
    }

    //test function to output privileges for an account
    private static bool CheckPrivileges(IntPtr thisHandle) {
      int iTokenInfLength = 0; //holds the length of the TOKEN_PRIVILEGES structure that will be returned by GetTokenInformation

      //First call to GetTokenInformation returns the length of the structure that will be returned on the next call
      GetTokenInformation(thisHandle, TOKEN_INFORMATION_CLASS.TokenPrivileges, IntPtr.Zero, iTokenInfLength, ref iTokenInfLength);

      //Allocate a block of memory large enough to hold the expected structure
      IntPtr ipTokenInformation = Marshal.AllocHGlobal(iTokenInfLength);
      //ipTokenInformation holds the starting location readable as an integer
      //you can view the memory location using Ctrl-Alt-M,1 or Debug->Windows->Memory->Memory1 in Visual Studio
      //and pasting the value of ipTokenInformation into the search box (it's still empty right now though)
      if(GetTokenInformation(thisHandle, TOKEN_INFORMATION_CLASS.TokenPrivileges, ipTokenInformation, iTokenInfLength, ref iTokenInfLength)) {
        //If GetTokenInformation doesn't return false then the structure should be sitting in the space reserved by ipTokenInformation
        //at this point

        //What was returned is a structure of type TOKEN_PRIVILEGES which has two values, a UInt32 followed by an array
        //of LUID_AND_ATTRIBUTES structures. Because we know what to expect and we know the order to expect it we can section
        //off the memory into marshalled structures and do some math to figure out where to start our next marshal

        uint uiPrivilegeCount = (uint)Marshal.PtrToStructure(ipTokenInformation, typeof(uint)); //Get the count

        //lets create the structure we should have had in the first place
        LUID_AND_ATTRIBUTES[] aLuidAa = new LUID_AND_ATTRIBUTES[uiPrivilegeCount]; //initialize an array to the right size
        LUID_AND_ATTRIBUTES cLuidAa = new LUID_AND_ATTRIBUTES();

        //ipPointer will hold our new location to read from by taking the last pointer plus the size of the last structure read
        IntPtr ipPointer = new IntPtr(ipTokenInformation.ToInt32() + sizeof(uint)); //first laa pointer
        cLuidAa = (LUID_AND_ATTRIBUTES)Marshal.PtrToStructure(ipPointer, typeof(LUID_AND_ATTRIBUTES)); //Read the memory location
        aLuidAa[0] = cLuidAa; //Add it to the array

        //After getting our first structure we can loop through the rest since they will all be the same
        for(int i = 1; i < uiPrivilegeCount; ++i) {
          ipPointer = new IntPtr(ipPointer.ToInt32() + Marshal.SizeOf(cLuidAa)); //Update the starting point in ipPointer
          cLuidAa = (LUID_AND_ATTRIBUTES)Marshal.PtrToStructure(ipPointer, typeof(LUID_AND_ATTRIBUTES)); //Read the memory location
          aLuidAa[i] = cLuidAa; //Add it to the array
        }//next

        TOKEN_PRIVILEGES cPrivilegeSet = new TOKEN_PRIVILEGES();
        cPrivilegeSet.PrivilegeCount = uiPrivilegeCount;
        cPrivilegeSet.Privileges = aLuidAa;
        //now we have what we should have had to begin with
        Console.WriteLine("Privilege Count: {0}", cPrivilegeSet.PrivilegeCount.ToString());


        //This loops through the LUID_AND_ATTRIBUTES array and resolves the LUID names with a
        //call to LookupPrivilegeName which requires us to first convert our managed structure into an unmanaged one
        //so we get to see what it looks like to do it backwards
        foreach(LUID_AND_ATTRIBUTES cLaa in cPrivilegeSet.Privileges) {
          System.Text.StringBuilder sb = new System.Text.StringBuilder();
          int iLuidNameLen = 0; //Holds the length of structure we will be receiving LookupPrivilagename
          IntPtr ipLuid = Marshal.AllocHGlobal(Marshal.SizeOf(cLaa.Luid)); //Allocate a block of memory large enough to hold the structure
          Marshal.StructureToPtr(cLaa.Luid, ipLuid, true); //Write the structure into the reserved space in unmanaged memory
          LookupPrivilegeName(null, ipLuid, null, ref iLuidNameLen); // call once to get the name length we will be receiving
          sb.EnsureCapacity(iLuidNameLen + 1); //Make sure there is enough room for it
          if(LookupPrivilegeName(null, ipLuid, sb, ref iLuidNameLen)) { // call again to get the name
            Console.WriteLine("[{0}] : {1}", cLaa.Attributes.ToString(), sb.ToString());
          }//end if
          Marshal.FreeHGlobal(ipLuid); //Free up the reserved space in unmanaged memory (Should be done any time AllocHGlobal is used)
        }//next
        Marshal.FreeHGlobal(ipTokenInformation);  //Free up the reserved space in unmanaged memory (Should be done any time AllocHGlobal is used)
      }//end if GetTokenInformation
      return true;
    }//CheckPrivileges
  }//Program
}//MarshallingExample
2 голосов
/ 04 декабря 2010

Вы не сможете изменить SizeConst во время выполнения, поэтому я думаю, что вам лучше всего выбрать как можно больше и использовать только те, которые вам нужны.Таким образом, вам не нужно будет менять код позже, если вам потребуется дополнительная информация.

Так, например, если максимальное количество возможных привилегий равно 35, установите SizeConst на 35.Затем измените цикл foreach на цикл for и перейдите от i = 0 к ThisPrivilegeSet.PrivilegeCount.

Вот пример (для этого я установил SizeConst на 8000):

  public void RunPrivileges()
  {
     int TokenInfLength = 0;
     IntPtr ThisHandle = WindowsIdentity.GetCurrent().Token;
     GetTokenInformation(ThisHandle, TOKEN_INFORMATION_CLASS.TokenPrivileges, IntPtr.Zero, TokenInfLength, ref TokenInfLength);
     IntPtr TokenInformation = Marshal.AllocHGlobal(TokenInfLength);
     if (GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenPrivileges, TokenInformation, TokenInfLength, ref TokenInfLength))
     {
        TOKEN_PRIVILEGES ThisPrivilegeSet = (TOKEN_PRIVILEGES)Marshal.PtrToStructure(TokenInformation, typeof(TOKEN_PRIVILEGES));
        for (int index = 0; index < ThisPrivilegeSet.PrivilegeCount; index++ )
        { 
           LUID_AND_ATTRIBUTES laa = ThisPrivilegeSet.Privileges[index];
           System.Text.StringBuilder StrBuilder = new System.Text.StringBuilder();
           int LuidNameLen = 0;
           IntPtr LuidPointer = Marshal.AllocHGlobal(Marshal.SizeOf(laa.Luid));
           Marshal.StructureToPtr(laa.Luid, LuidPointer, true);
           LookupPrivilegeName(null, LuidPointer, null, ref LuidNameLen);
           StrBuilder.EnsureCapacity(LuidNameLen + 1);
           if (LookupPrivilegeName(null, LuidPointer, StrBuilder, ref LuidNameLen))
           {
              Console.WriteLine("[{0}] : {1}", laa.Attributes.ToString(), StrBuilder.ToString());
           }
           Marshal.FreeHGlobal(LuidPointer);
        }
     }
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...