Files
2025-11-07 14:27:24 -05:00

543 lines
25 KiB
C#

/**
* BSD 3-Clause License
* Copyright (c) 2023-2024, SafeBreach Labs
* Copyright (c) 2025, Stroz Friedberg
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Runtime.InteropServices;
using static SharpParty.Enums;
namespace SharpParty
{
internal class Structs
{
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 8)]
public struct LARGE_INTEGER
{
[FieldOffset(0)]
public Int64 QuadPart;
[FieldOffset(0)]
public UInt32 LowPart;
[FieldOffset(4)]
public Int32 HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct _WORKER_FACTORY_BASIC_INFORMATION
{
public LARGE_INTEGER Timeout; // 8 bytes
public LARGE_INTEGER RetryTimeout; // 8 bytes
public LARGE_INTEGER IdleTimeout; // 8 bytes
public byte Paused; // 1 byte
public byte TimerSet; // 1 byte
public byte QueuedToExWorker; // 1 byte
public byte MayCreate; // 1 byte
public byte CreateInProgress; // 1 byte
public byte InsertedIntoQueue; // 1 byte
public byte Shutdown; // 1 byte
public uint BindingCount; // 8 bytes
public uint ThreadMinimum; // 8 bytes
public uint ThreadMaximum; // 8 bytes
public uint PendingWorkerCount; // 8 bytes
public uint WaitingWorkerCount; // 8 bytes
public uint TotalWorkerCount; // 8 bytes
public uint ReleaseCount; // 8 bytes
public long InfiniteWaitGoal; // 8 bytes
public IntPtr StartRoutine; // 8 bytes
public IntPtr StartParameter; // 8 bytes
public IntPtr ProcessId; // 8 bytes
public IntPtr StackReserve; // 8 bytes
public IntPtr StackCommit; // 8 bytes
public int LastThreadCreationStatus; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Pack = 1, CharSet = CharSet.Unicode)]
public unsafe struct PROCESS_HANDLE_TABLE_ENTRY_INFO
{
[FieldOffset(0)]
public IntPtr HandleValue; // c++ = HANDLE -> c# = IntPtr
[FieldOffset(8)]
public IntPtr HandleCount; // c++ = ULONG_PTR -> c# = IntPtr
[FieldOffset(16)]
public IntPtr PointerCount; // c++ = ULONG_PTR -> c# = IntPtr
[FieldOffset(24)]
public uint GrantedAccess; // c++ = ACCESS_MASK -> DWORD (Win32) -> c# = UInt32
[FieldOffset(28)]
public ulong ObjectTypeIndex; // c++ = ULONG -> c# = ulong
[FieldOffset(36)]
public ulong HandleAttributes; // c++ = ULONG -> c# = ulong
[FieldOffset(44)]
public ulong Reserved; // c++ = ULONG -> c# = ulong
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public unsafe struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION
{
[FieldOffset(0)]
public IntPtr NumberOfHandles; // c++ = ULONG_PTR -> c# = IntPtr
[FieldOffset(8)]
public IntPtr Reserved; // c++ = ULONG_PTR -> c# = IntPtr
[FieldOffset(16)]
public fixed byte Handles[1];
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_HANDLE_SNAPSHOT_INFORMATION
{
public IntPtr NumberOfHandles; // c++ = ULONG_PTR -> c# = IntPtr
public IntPtr Reserved; // c++ = ULONG_PTR -> c# = IntPtr
public PROCESS_HANDLE_TABLE_ENTRY_INFO[] Handles; // c++ = PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[ANYSIZE_ARRAY] -> c# = PROCESS_HANDLE_TABLE_ENTRY_INFO* Handles
}
// https://stackoverflow.com/questions/6838302/list-entry-and-unicode-string-pinvoke-c-sharp
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public unsafe 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, CharSet = CharSet.Unicode)]
public unsafe struct _PUBLIC_OBJECT_TYPE_INFORMATION
{
public UNICODE_STRING TypeName; // c++ = UNICODE_STRING (char *) -> c# = IntPtr
public fixed ulong Reserved[22]; // c++ = ULONG Reserved[22] -> c# = ulong*
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Explicit, Size = 4)]
public struct _TPP_REFCOUNT
{
[FieldOffset(0)] public volatile int Refcount; // 4 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)] // Union in C++: Overlapping multiple fields, value is dependent on how it's accessed. Each field is an IntPtr (8 bytes)
public struct CallbackUnion
{
[FieldOffset(0)] public IntPtr Callback;
[FieldOffset(0)] public IntPtr WorkCallback;
[FieldOffset(0)] public IntPtr SimpleCallback;
[FieldOffset(0)] public IntPtr TimerCallback;
[FieldOffset(0)] public IntPtr WaitCallback;
[FieldOffset(0)] public IntPtr IoCallback;
[FieldOffset(0)] public IntPtr AlpcCallback;
[FieldOffset(0)] public IntPtr AlpcCallbackEx;
[FieldOffset(0)] public IntPtr JobCallback;
}
[StructLayout(LayoutKind.Explicit, Size = 4)] // Union in C++ = Explicit Layout with each field at offset 0; uint/int = 4 bytes
public struct FlagUnion
{
[FieldOffset(0)] public volatile int Flags;
[FieldOffset(0)] public uint LongFunction;
[FieldOffset(0)] public uint Persistent;
[FieldOffset(0)] public uint UnusedPublic;
[FieldOffset(0)] public uint Released;
[FieldOffset(0)] public uint CleanupGroupReleased;
[FieldOffset(0)] public uint InCleanupGroupCleanupList;
[FieldOffset(0)] public uint UnusedPrivate;
}
[StructLayout(LayoutKind.Explicit, Size = 80)]
public struct _TP_CLEANUP_GROUP
{
[FieldOffset(0)] public _TPP_REFCOUNT Refcount; // 4 bytes
[FieldOffset(4)] public int Released; // 4 bytes
[FieldOffset(8)] public _RTL_SRWLOCK MemberLock; // 8 bytes
[FieldOffset(16)] public _LIST_ENTRY MemberList; // 16 bytes
[FieldOffset(32)] public _TPP_BARRIER Barrier; // 24 bytes
[FieldOffset(56)] public _RTL_SRWLOCK CleanupLock; // 8 bytes
[FieldOffset(64)] public _LIST_ENTRY CleanupList; // 16 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct _TPP_FLAGS_UNION
{
[FieldOffset(0)] public long Data; // 8 bytes
[FieldOffset(0)] public ulong Flags; // 8 bytes
[FieldOffset(0)] public ulong Count; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct _TPP_FLAGS_COUNT
{
[FieldOffset(0)] public _TPP_FLAGS_UNION Flags; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct _RTL_SRWLOCK
{
[FieldOffset(0)] public IntPtr Ptr; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public unsafe struct _TPP_ITE_WAITER
{
[FieldOffset(0)] public _TPP_ITE_WAITER* Next; // Ptr to struct; 8 bytes
[FieldOffset(8)] public IntPtr ThreadId; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public unsafe struct _TPP_ITE
{
[FieldOffset(0)] public _TPP_ITE_WAITER* First; // Ptr to struct; 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 24)]
public struct _TPP_BARRIER
{
[FieldOffset(0)] public _TPP_FLAGS_COUNT Ptr; // 8 bytes
[FieldOffset(8)] public _RTL_SRWLOCK WaitLock; // 8 bytes
[FieldOffset(16)] public _TPP_ITE WaitList; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public unsafe struct _GUID
{
[FieldOffset(0)] public int Data1; // 4 bytes
[FieldOffset(4)] public short Data2; // 2 bytes
[FieldOffset(6)] public short Data3; // 2 bytes
[FieldOffset(8)] public fixed byte Data4[8]; // 8 byte array = 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct _ALPC_WORK_ON_BEHALF_TICKET
{
[FieldOffset(0)] public uint ThreadId; // 4 bytes
[FieldOffset(4)] public uint ThreadCreationTimeLow; // 4 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct _TPP_POOL_QUEUE_STATE
{
[FieldOffset(0)] public long Exchange; // 8 bytes
[FieldOffset(0)] public _TPP_POOL_QUEUE_STATE_FIELDS Fields; // 8 bytes
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct _TPP_POOL_QUEUE_STATE_FIELDS
{
[FieldOffset(0)] public short RunningThreadGoal; // 2 bytes
[FieldOffset(2)] public ushort PendingReleaseGoal; // 2 bytes
[FieldOffset(4)] public uint QueueLength; // 4 bytes
}
}
[StructLayout(LayoutKind.Explicit, Size = 4)]
public struct _TPP_NUMA_NODE
{
[FieldOffset(0)] public int WorkerCount; // 4 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 24)]
public struct _TPP_QUEUE
{
[FieldOffset(0)] public _LIST_ENTRY Queue; // 16 bytes
[FieldOffset(16)] public _RTL_SRWLOCK Lock; // 8 bytes
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct _GROUP_AFFINITY
{
public UIntPtr Mask;
[MarshalAs(UnmanagedType.U2)] public ushort Group;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U2)] public ushort[] Reserved;
}
[StructLayout(LayoutKind.Explicit, Size = 40)]
public struct _TPP_PH_LINKS
{
[FieldOffset(0)] public _LIST_ENTRY Siblings; // 16 bytes
[FieldOffset(16)] public _LIST_ENTRY Children; // 16 bytes
[FieldOffset(32)] public long Key; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public unsafe struct _TPP_PH
{
[FieldOffset(0)] public _TPP_PH_LINKS* Root; // Ptr to struct; 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 120)]
public unsafe struct _TPP_TIMER_SUBQUEUE
{
[FieldOffset(0)] public long Expiration; // 8 bytes
[FieldOffset(8)] public _TPP_PH WindowStart; // 8 bytes
[FieldOffset(16)] public _TPP_PH WindowEnd; // 8 bytes
[FieldOffset(24)] public IntPtr Timer; // 8 bytes
[FieldOffset(32)] public IntPtr TimerPkt; // 8 bytes
[FieldOffset(40)] public _TP_DIRECT Direct; // 72 bytes
[FieldOffset(112)] public uint ExpirationWindow; // 4 bytes
[FieldOffset(116)] public fixed int PADDING[1]; // int = 4 bytes; array of 1 int = 4 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 256)]
public unsafe struct _TPP_TIMER_QUEUE
{
[FieldOffset(0)] public _RTL_SRWLOCK Lock; // 8 bytes
[FieldOffset(8)] public _TPP_TIMER_SUBQUEUE AbsoluteQueue; // 120 bytes
[FieldOffset(128)] public _TPP_TIMER_SUBQUEUE RelativeQueue; // 120 bytes
[FieldOffset(248)] public int AllocatedTimerCount; // 4 bytes
[FieldOffset(252)] public fixed int PADDING[1]; // int = 4 bytes; array of 1 int = 4 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 486)] // Should be 472
public unsafe struct FULL_TP_POOL
{
[FieldOffset(0)] public _TPP_REFCOUNT Refcount; // 4 bytes
[FieldOffset(4)] public int PADDING1; // 4 bytes
[FieldOffset(8)] public _TPP_POOL_QUEUE_STATE QueueState; // 8 bytes
[FieldOffset(16)][MarshalAs(UnmanagedType.LPArray, SizeConst = 3)] public _TPP_QUEUE* TaskQueue; // Ptr = 8 bytes; array of 3 pointers = 24 bytes
[FieldOffset(40)] public _TPP_NUMA_NODE* NumaNode; // Ptr to struct; 8 bytes
[FieldOffset(48)] public _GROUP_AFFINITY* ProximityInfo; // Ptr to struct; 8 bytes
[FieldOffset(56)] public IntPtr WorkerFactory; // 8 bytes
[FieldOffset(64)] public IntPtr CompletionPort; // 8 bytes
[FieldOffset(72)] public _RTL_SRWLOCK Lock; // 8 bytes
[FieldOffset(80)] public _LIST_ENTRY PoolObjectList; // 16 bytes
[FieldOffset(96)] public _LIST_ENTRY WorkerList; // 16 bytes
[FieldOffset(112)] public _TPP_TIMER_QUEUE TimerQueue; // 256 bytes
[FieldOffset(368)] public _RTL_SRWLOCK ShutdownLock; // 8 bytes
[FieldOffset(376)] public uint ShutdownInitiated; // 4 bytes
[FieldOffset(380)] public uint Released; // 4 bytes
[FieldOffset(384)] public ushort PoolFlags; // 2 bytes
[FieldOffset(386)] public int PADDING2; // 4 bytes
[FieldOffset(390)] public _LIST_ENTRY PoolLinks; // 16 bytes
[FieldOffset(406)] public _TPP_CALLER AllocCaller; // 8 bytes
[FieldOffset(414)] public _TPP_CALLER ReleaseCaller; // 8 bytes
[FieldOffset(422)] public volatile int AvailableWorkerCount; // 4 bytes
[FieldOffset(426)] public volatile int LongRunningWorkerCount; // 4 bytes
[FieldOffset(430)] public uint LastProcCount; // 4 bytes
[FieldOffset(434)] public volatile int NodeStatus; // 4 bytes
[FieldOffset(438)] public volatile int BindingCount; // 4 bytes
[FieldOffset(442)] public uint CallbackChecksDisabled; // 4 bytes
[FieldOffset(446)] public uint TrimTarget; // 4 bytes
[FieldOffset(450)] public uint TrimmedThrdCount; // 4 bytes
[FieldOffset(454)] public uint SelectedCpuSetCount; // 4 bytes
[FieldOffset(458)] public int PADDING3; // 4 bytes
[FieldOffset(462)] public IntPtr TrimComplete; // 8 bytes
[FieldOffset(470)] public _LIST_ENTRY TrimmedWorkerList; // 16 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct _TPP_CALLER
{
[FieldOffset(0)] public IntPtr ReturnAddress;
}
[StructLayout(LayoutKind.Explicit, Size = 200)]
public unsafe struct _TPP_CLEANUP_GROUP_MEMBER
{
[FieldOffset(0)] public _TPP_REFCOUNT Refcount; // size = 4; align = 4
[FieldOffset(4)] public int PADDING1; // size = 4 bytes (long in C++ PoC = 4 bytes)
[FieldOffset(8)] public IntPtr VFuncs; // Pointer to another struct; 8 bytes
[FieldOffset(16)] public _TP_CLEANUP_GROUP* CleanupGroup; // Pointer to another struct; 8 bytes
[FieldOffset(24)] public IntPtr CleanupGroupCancelCallback;// Void Pointer; 8 bytes
[FieldOffset(32)] public IntPtr FinalizationCallback;// Void Pointer; 8 bytes
[FieldOffset(40)] public _LIST_ENTRY CleanupGroupMemberLinks;// size = 16 bytes; align = 8 bytes
[FieldOffset(56)] public _TPP_BARRIER CallbackBarrier; // Size = 24 bytes; align = 8 bytes
[FieldOffset(80)] public CallbackUnion callbackUnion; // Size = 8 bytes
[FieldOffset(88)] public IntPtr Context; // Void Pointer; 8 Bytes
[FieldOffset(96)] public IntPtr ActivationContext; // Pointer to struct; 8 bytes
[FieldOffset(104)] public IntPtr SubProcessTag; // Void Pointer; 8 bytes
[FieldOffset(112)] public _GUID ActivityId; // Size = 16 bytes; align = 4 bytes
[FieldOffset(128)] public _ALPC_WORK_ON_BEHALF_TICKET WorkOnBehalfTicket; // Size = 8 bytes; align = 4 bytes
[FieldOffset(136)] public IntPtr RaceDll; // Void Pointer = 8 bytes
[FieldOffset(144)] public IntPtr Pool; // Pointer to another struct; 8 bytes
[FieldOffset(152)] public _LIST_ENTRY PoolObjectLinks; // Size = 16 bytes; align = 8 bytes
[FieldOffset(168)] public FlagUnion flagUnion; // Size = 4 bytes
[FieldOffset(172)] public int PADDING2; // size = 4 bytes (long in C++ PoC = 4 bytes)
[FieldOffset(176)] public _TPP_CALLER AllocCaller; // Size = 8; Align = 8
[FieldOffset(184)] public _TPP_CALLER ReleaseCaller; // Size = 8; Align = 8
[FieldOffset(192)] public _TP_CALLBACK_PRIORITY CallbackPriority; // Size = 4; Align = 4
[FieldOffset(196)] public fixed int PADDING3[1]; // Array of 1 int = 4 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct _TP_TASK_CALLBACKS
{
[FieldOffset(0)] public IntPtr ExecuteCallback; // 8 bytes
[FieldOffset(8)] public IntPtr Unposted; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct _LIST_ENTRY
{
[FieldOffset(0)] public IntPtr fLink; // 8 bytes
[FieldOffset(8)] public IntPtr bLink; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 32)]
public unsafe struct _TP_TASK
{
[FieldOffset(0)] public _TP_TASK_CALLBACKS* Callbacks; // Pointer to struct; 8 bytes
[FieldOffset(8)] public uint NumaNode; // 4 bytes
[FieldOffset(12)] public byte IdealProcessor; // 1 byte
[FieldOffset(13)] public fixed byte PADDING[3]; // 3 byte array = 3 bytes
[FieldOffset(16)] public _LIST_ENTRY ListEntry; // 16 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 72)]
public unsafe struct _TP_DIRECT
{
[FieldOffset(0)] public _TP_TASK Task; // 32 bytes
[FieldOffset(32)] public ulong Lock; // 8 bytes
[FieldOffset(40)] public _LIST_ENTRY IoCompletionInformationList; // 16 bytes
[FieldOffset(56)] public IntPtr Callback; // 8 bytes
[FieldOffset(64)] public uint NumaNode; // 4 bytes
[FieldOffset(68)] public byte IdealProcessor; // 1 byte
[FieldOffset(69)] public fixed byte PADDING[3]; // byte = 1 byte; array of 3 bytes = 3 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 288)]
public unsafe struct FULL_TP_IO
{
[FieldOffset(0)] public _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; // 200 bytes
[FieldOffset(200)] public _TP_DIRECT Direct; // 72 bytes
[FieldOffset(272)] public IntPtr File; // 8 bytes
[FieldOffset(280)] public volatile int PendingIrpCount; // 4 bytes
[FieldOffset(284)] public fixed int PADDING[1]; // array of one int; int is 4 bytes; size is 4 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct _FULL_TP_JOB_UNION
{
[FieldOffset(0)] public long CompletionState;
[FieldOffset(0)] public long Rundown;
[FieldOffset(0)] public long CompletionCount;
}
[StructLayout(LayoutKind.Explicit, Size = 296)]
public unsafe struct FULL_TP_JOB
{
[FieldOffset(0)] public _TP_DIRECT Direct; // 72 bytes
[FieldOffset(72)] public _TPP_CLEANUP_GROUP_MEMBER CleanupGroupMember; // 200 bytes
[FieldOffset(272)] public IntPtr JobHandle; // 8 bytes
[FieldOffset(280)] public _FULL_TP_JOB_UNION JobUnion; // 8 Bytes
[FieldOffset(288)] public _RTL_SRWLOCK RundownLock; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public unsafe struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT
{
[FieldOffset(0)] public IntPtr CompletionKey;
[FieldOffset(8)] public IntPtr CompletionPort;
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct IO_STATUS_UNION
{
[FieldOffset(0)] public uint Status; // 4 bytes
[FieldOffset(0)] public IntPtr Pointer; // 8 bytes; union stores at same address so size = 8
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct IO_STATUS_BLOCK
{
[FieldOffset(0)] public IO_STATUS_UNION StatusUnion; // 8 bytes
[FieldOffset(8)] public IntPtr Information; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct FILE_COMPLETION_INFORMATION
{
[FieldOffset(0)] public IntPtr Port; // 8 bytes
[FieldOffset(8)] public IntPtr Key; // 8 bytes
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct TP_CALLBACK_INSTANCE
{
[FieldOffset(0)] public IntPtr instance;
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct TP_IO
{
[FieldOffset(0)] public IntPtr instance;
}
[StructLayout(LayoutKind.Explicit, Size = 48)]
public unsafe struct TP_WIN32_IO_CALLBACK
{
[FieldOffset(0)] public TP_CALLBACK_INSTANCE* Instance; // Ptr to struct; 8 bytes
[FieldOffset(8)] public IntPtr Context; // 8 bytes
[FieldOffset(16)] public IntPtr Overlapped; // 8 bytes
[FieldOffset(24)] public ulong IoResult; // 8 bytes
[FieldOffset(32)] public IntPtr NumberOfBytesTransferred; // 8 bytes
[FieldOffset(40)] public TP_IO* Io; // 8 bytes
}
}
}