我正在尝试检索与C#中的令牌相关联的特权及其当前状态,但我不知道如何调整返回的LUID_AND_ATTRIBUTES数组的大小以适应实际的元素数量。
来自MSDN
当MarshalAsAttribute.Value设置为ByValArray时,必须将SizeConst设置为指示数组中的元素数。
在调用TOKEN_PRIVILEGES.PrivilegeCount之后,我能够查看GetTokenInformation属性,并看到我正在使用的令牌拥有特权常数参考页面中列出的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向我寻求帮助。
发布于 2010-12-03 21:19:05
您将无法在运行时更改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);
}
}
}发布于 2010-12-09 14:33:31
我想跟进这个问题,因为我从VVS提供的链接中学到了什么。
如果您和我一样,从未学习或使用过必须直接访问内存的编程语言,您可能也会发现这也很有趣(BTW,我已经将SwDevman81 81的答案标记为正确的答案,因为它工作得非常好)。
在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
}//MarshallingExamplehttps://stackoverflow.com/questions/4349743
复制相似问题