using System; using System.IO; using System.Runtime.InteropServices; using System.Text; namespace SharpHellsGate.Module { /// /// Used to manipulate and extract information from a memory stream. /// In this case the memory stream is the NTDLL module. /// public class MemoryUtil : IDisposable { /// /// The memory stream representation of the NTDLL module. /// protected Stream ModuleStream { get; set; } /// /// Dispose the memory stream when no longer needed. /// ~MemoryUtil() => Dispose(); /// /// Dispose the memory stream when no longer needed. /// public void Dispose() { this.ModuleStream.Dispose(); this.ModuleStream.Close(); GC.SuppressFinalize(this); } /// /// Extract a structure from the memory stream. /// /// The Type of the structure to extract. /// The offset in the memory stream where the structure is located. /// The structure populated or the default structure. protected T GetStructureFromBlob(Int64 offset) where T : struct { Span bytes = this.GetStructureBytesFromOffset(offset); if (Marshal.SizeOf() != bytes.Length) return default; IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); Marshal.Copy(bytes.ToArray(), 0, ptr, bytes.Length); T s = Marshal.PtrToStructure(ptr); Marshal.FreeHGlobal(ptr); return s; } /// /// Extract the code from a native Windows function. /// /// The location of the function in the memory stream. /// The 24 bytes representing the code of the function. protected Span GetFunctionOpCode(Int64 offset) { Span s = stackalloc byte[24]; this.ModuleStream.Seek(offset, SeekOrigin.Begin); this.ModuleStream.Read(s); return s.ToArray(); } /// /// Extract a DWORD value from the memory stream. /// /// The location of the DWORD in the memory stream. /// The value of the DWORD. protected UInt32 ReadPtr32(Int64 offset) { Span s = stackalloc byte[4]; this.ModuleStream.Seek(offset, SeekOrigin.Begin); this.ModuleStream.Read(s); return BitConverter.ToUInt32(s); } /// /// Extract a QWORD value from the memory stream. /// /// The location of the QWORD in the memory stream. /// The value of the QWORD. protected UInt64 ReadPtr64(Int64 offset) { Span s = stackalloc byte[8]; this.ModuleStream.Seek(offset, SeekOrigin.Begin); this.ModuleStream.Read(s); return BitConverter.ToUInt64(s); } /// /// Extract a WORD value from the memory stream. /// /// The location of the WORD in the memory stream. /// The value of the WORD. protected UInt16 ReadUShort(Int64 offset) { Span s = stackalloc byte[2]; this.ModuleStream.Seek(offset, SeekOrigin.Begin); this.ModuleStream.Read(s); return BitConverter.ToUInt16(s); } /// /// Extract an ASCII string from the memory stream. /// /// The location of the ASCII string in the memory stream. /// The ASCII string. protected string ReadAscii(Int64 offset) { int length = 0; this.ModuleStream.Seek(offset, SeekOrigin.Begin); while (this.ModuleStream.ReadByte() != 0x00) length++; Span s = length <= 1024 ? stackalloc byte[length] : new byte[length]; this.ModuleStream.Seek(offset, SeekOrigin.Begin); this.ModuleStream.Read(s); return Encoding.ASCII.GetString(s); } /// /// Extract the byte representation of a structure from the memory stream. /// /// The Type of the structure to extract from the memory stream. /// The location of the structure in the memory stream. /// The structure as byte span. protected Span GetStructureBytesFromOffset(Int64 offset) where T : struct { Span s = stackalloc byte[Marshal.SizeOf()]; this.ModuleStream.Seek(offset, SeekOrigin.Begin); this.ModuleStream.Read(s); return s.ToArray(); } /// /// Get a specific amount of bytes at a specific location in the memory stream. /// /// The location of the bytes to extract from the memory stream. /// The number of bytes to extract from the memory stream at a give location. /// The desired bytes as a byte span. protected Span GetBytesFromOffset(Int64 offset, int size) { Span s = size >= 1024 ? new byte[size] : stackalloc byte[size]; this.ModuleStream.Seek(offset, SeekOrigin.Begin); this.ModuleStream.Read(s); return s.ToArray(); } } }