设置GetTokenInformation返回的TOKEN_PRIVILEGES.LUID_AND_ATTRIBUTES数组的大小

时间:2010-12-03 20:51:17

标签: c# windows-xp marshalling impersonation privileges

我正在尝试检索与C#中的令牌关联的权限及其当前状态,但我无法弄清楚如何调整返回的LUID_AND_ATTRIBUTES数组的大小以适合实际的数量元件。

来自MSDN

  

当MarshalAsAttribute.Value设置为ByValArray时,必须设置SizeConst以指示数组中元素的数量。

在调用TOKEN_PRIVILEGES.PrivilegeCount之后,我能够看到GetTokenInformation属性,并看到我正在使用的令牌拥有Privilege Constants参考页上列出的35个特权中的24个。改变SizeConst = 24会让我能够看到所有这些而不仅仅是第一个 (我最初根据PInvoke)的使用示例设置了SizeConst = 1

有没有办法在创建传入数组时指定传入数组的深度,或者我需要知道在编写代码之前会有多少权限?

代码段

[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 个答案:

答案 0 :(得分:2)

您将无法在运行时更改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);
        }
     }
  }

答案 1 :(得分:2)

我想通过关注VVS提供的链接来了解这个问题。

如果你像我一样并且从未学习或使用过必须直接访问内存的编程语言,那么你也可能会觉得这很有趣(顺便说一句,我已经将SwDevman81的答案标记为正确的,因为它运行得非常好)。

在VVS提供的博客文章中,作者讨论了使用调用返回的指针的值(内存地址)+返回的对象的大小来编组chuncks中返回的数据以动态检索变量的数量对象。在这种情况和博客文章中概述的情况下,我们受益于返回的第一个值包含以下数组中的元素数量,我们还有一个从函数返回的整数,告诉我们返回的结构有多大也可以用于检查我们是否已达到结构的末尾,如果我们没有价值的好处告诉我们元素的数量。

我正在为有兴趣了解上述博客文章如何应用于此方案的任何人提供以下代码示例。

代码示例:

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