Search code examples
c#winapipinvoke

LIST_ENTRY and UNICODE_STRING pinvoke C#


I'm trying to recreate a struct in C# which will be used with Win API, this is the struct:

typedef struct _LDR_MODULE {
  LIST_ENTRY              InLoadOrderModuleList;
  LIST_ENTRY              InMemoryOrderModuleList;
  LIST_ENTRY              InInitializationOrderModuleList;
  PVOID                   BaseAddress;
  PVOID                   EntryPoint;
  ULONG                   SizeOfImage;
  UNICODE_STRING          FullDllName;
  UNICODE_STRING          BaseDllName;
  ULONG                   Flags;
  SHORT                   LoadCount;
  SHORT                   TlsIndex;
  LIST_ENTRY              HashTableEntry;
  ULONG                   TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;

The two members I'm not sure about are LIST_ENTRY and UNICODE_STRING, how would I mimic these in C#?


Solution

  • I'm coming way late to the party, but I just had to do this for a personal "curiosity project" - the signatures end up looking like:

        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct LIST_ENTRY
        {
            public IntPtr Flink;
            public IntPtr Blink;
    
            public ListEntryWrapper Fwd
            {
                get
                {
                    var fwdAddr = Flink.ToInt32();
                    return new ListEntryWrapper()
                    {
                        Header = Flink.ReadMemory<LIST_ENTRY>(),
                            Body = new IntPtr(fwdAddr + Marshal.SizeOf(typeof(LIST_ENTRY))).ReadMemory<LDR_MODULE>()
                    };
                }               
            }
            public ListEntryWrapper Back
            {
                get
                {
                    var fwdAddr = Blink.ToInt32();
                    return new ListEntryWrapper()
                    {
                        Header = Flink.ReadMemory<LIST_ENTRY>(),
                        Body = new IntPtr(fwdAddr + Marshal.SizeOf(typeof(LIST_ENTRY))).ReadMemory<LDR_MODULE>()
                    };
                }
            }
        }
    
        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct ListEntryWrapper
        {
            public LIST_ENTRY Header;
            public LDR_MODULE Body;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct UNICODE_STRING : IDisposable
        {
            public ushort Length;
            public ushort MaximumLength;
            private IntPtr buffer;
    
            public UNICODE_STRING(string s)
            {
                Length = (ushort)(s.Length * 2);
                MaximumLength = (ushort)(Length + 2);
                buffer = Marshal.StringToHGlobalUni(s);
            }
    
            public void Dispose()
            {
                Marshal.FreeHGlobal(buffer);
                buffer = IntPtr.Zero;
            }
    
            public override string ToString()
            {
                return Marshal.PtrToStringUni(buffer);
            }
        }
    
        [StructLayout(LayoutKind.Sequential, Pack = 0)]
        public struct PEB_LDR_DATA
        {
            public int Length;
            public int Initialized;
            public int SsHandle;
            public IntPtr InLoadOrderModuleListPtr;
            public IntPtr InMemoryOrderModuleListPtr;
            public IntPtr InInitOrderModuleListPtr;
            public int EntryInProgress;
            public ListEntryWrapper InLoadOrderModuleList { get { return InLoadOrderModuleListPtr.ReadMemory<ListEntryWrapper>(); } }
            public ListEntryWrapper InMemoryOrderModuleList { get { return InLoadOrderModuleListPtr.ReadMemory<ListEntryWrapper>(); } }
            public ListEntryWrapper InInitOrderModuleList { get { return InLoadOrderModuleListPtr.ReadMemory<ListEntryWrapper>(); } }
        }
    

    Where IntPtr.ReadMemory is just an extension method:

        public static T ReadMemory<T>(this IntPtr atAddress)
        {
            var ret = (T)Marshal.PtrToStructure(atAddress, typeof (T));
            return ret;
        }