如何从GetTokenInformation()安全地为32位和64位拼接可变长度的结构数组? C#

我正在遵循
here提供的pinvoke代码,但稍微被可变长度数组的编组调整为size = 1,然后通过计算偏移而不是索引到数组来逐步执行它.有没有更好的方法?如果没有,我应该怎么做才能使它对32位和64位安全?

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

    [StructLayout(LayoutKind.Sequential)]
    public struct TOKEN_GROUPS
    {
        public int GroupCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public SID_AND_ATTRIBUTES[] Groups;
    };


public void SomeMethod()
{
    IntPtr tokenInformation;

    // ... 

    string retVal = string.Empty;
    TOKEN_GROUPS groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_GROUPS));
    int sidAndAttrSize = Marshal.SizeOf(new SID_AND_ATTRIBUTES());
    for (int i = 0; i < groups.GroupCount; i++)
    {
        // *** Scary line here: 
        SID_AND_ATTRIBUTES sidAndAttributes = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure(
              new IntPtr(tokenInformation.ToInt64() + i * sidAndAttrSize + IntPtr.Size), 
              typeof(SID_AND_ATTRIBUTES));

    // ... 
}

我看到here另一种声明阵列长度比它可能大得多的方法,但这似乎有其自身的问题.

作为一个附带问题:当我在调试器中单步调试上面的代码时,我无法评估tokenInformation.ToInt64()或ToInt32().我得到一个ArgumentOutOfRangeException.但是代码行执行得很好!?这里发生了什么?

最佳答案 我认为看起来没问题 – 无论如何,无论如何在无人管理的土地上进行任何探索都是好的.

但是,我想知道为什么start是tokenInformation.ToInt64()IntPtr.Size而不是tokenInformation.ToInt64()4(因为GroupCount字段类型是int而不是IntPtr).这是用于包装/对齐结构还是只是有点可疑?我不知道在这里.

使用tokenInformation.ToInt64()很重要,因为如果IntPtr值大于int可以存储的值,64位机器将爆炸(OverflowException).但是,CLR将在两种体系结构上处理很长时间,并且它不会更改从IntPtr中提取的实际值(因此将其放回到新的IntPtr(…)中).

想象一下这个(未经测试的)函数作为一个方便的包装器:

// unpacks an array of structures from unmanaged memory
// arr.Length is the number of items to unpack. don't overrun.
void PtrToStructureArray<T>(T[] arr, IntPtr start, int stride) {
   long ptr = start.ToInt64();
   for (int i = 0; i < arr.Length; i++, ptr += stride) {
       arr[i] = (T)Marshal.PtrToStructure(new IntPtr(ptr), typeof(T));
   }
}

var attributes = new SID_AND_ATTRIBUTES[groups.GroupCount];
PtrToStructureArray(attributes, new IntPtr(tokenInformation.ToInt64() + IntPtr.Size), sidAndAttrSize);

快乐的编码.

点赞