Code:
public class Memory
{
public nint wowProc { get; set; }
public Memory(nint wowProc)
{
this.wowProc = wowProc;
}
[Flags]
public enum SnapshotFlags : uint
{
HeapList = 0x00000001,
Process = 0x00000002,
Thread = 0x00000004,
Module = 0x00000008,
Module32 = 0x00000010,
All = (HeapList | Process | Thread | Module),
Inherit = 0x80000000,
NoHeaps = 0x40000000
}
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
uint processAccess,
bool bInheritHandle,
uint processId
);
[StructLayout(LayoutKind.Sequential)]
public struct PROCESSENTRY32
{
public uint dwSize;
public uint cntUsage;
public uint th32ProcessID;
public IntPtr th32DefaultHeapID;
public uint th32ModuleID;
public uint cntThreads;
public uint th32ParentProcessID;
public int pcPriClassBase;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExeFile;
};
[StructLayout(LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct MODULEENTRY32
{
internal uint dwSize;
internal uint th32ModuleID;
internal uint th32ProcessID;
internal uint GlblcntUsage;
internal uint ProccntUsage;
internal IntPtr modBaseAddr;
internal uint modBaseSize;
internal IntPtr hModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
internal string szModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
internal string szExePath;
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
int dwSize,
out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[MarshalAs(UnmanagedType.AsAny)] object lpBuffer,
Int32 nSize,
out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport("kernel32.dll")]
static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport("kernel32.dll")]
static extern bool Module32First(IntPtr hSnapshot, ref MODULEENTRY32 lpme);
[DllImport("kernel32.dll")]
static extern bool Module32Next(IntPtr hSnapshot, ref MODULEENTRY32 lpme);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hHandle);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateToolhelp32Snapshot(SnapshotFlags dwFlags, int th32ProcessID);
public static IntPtr GetModuleBaseAddress(System.Diagnostics.Process proc, string modName)
{
IntPtr addr = IntPtr.Zero;
foreach (ProcessModule m in proc.Modules)
{
if (m.ModuleName == modName)
{
addr = m.BaseAddress;
break;
}
}
return addr;
}
const int INVALID_HANDLE_VALUE = -1;
public static IntPtr GetModuleBaseAddress(int procId, string modName)
{
IntPtr modBaseAddress = IntPtr.Zero;
IntPtr hSnap = CreateToolhelp32Snapshot(SnapshotFlags.Module | SnapshotFlags.Module32, procId);
if (hSnap.ToInt64() != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry = new MODULEENTRY32();
modEntry.dwSize = (uint)Marshal.SizeOf(typeof(MODULEENTRY32));
if (Module32First(hSnap, ref modEntry))
{
do
{
if (modEntry.szModule.Equals(modName))
{
modBaseAddress = modEntry.modBaseAddr;
break;
}
} while (Module32Next(hSnap, ref modEntry));
}
}
CloseHandle(hSnap);
return modBaseAddress;
}
public IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
{
var buffer = new byte[IntPtr.Size];
foreach (var i in offsets)
{
ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);
var test = read;
;
ptr = (IntPtr.Size == 4)
? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
: ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
}
return ptr;
}
public string ReadString(IntPtr address)
{
const int maxBufferSize = 4096; // Set a reasonable maximum buffer size to prevent infinite loops
List<byte> bufferList = new List<byte>();
byte[] tempBuffer = new byte[maxBufferSize];
int bytesRead = 0;
while (bufferList.Count < maxBufferSize)
{
if (ReadProcessMemory(wowProc, address, tempBuffer, tempBuffer.Length, out IntPtr read))
{
bytesRead = read.ToInt32();
if (bytesRead == 0)
break;
int nullTerminatorIndex = Array.IndexOf(tempBuffer, (byte)0, 0, bytesRead);
if (nullTerminatorIndex != -1)
{
bufferList.AddRange(tempBuffer.Take(nullTerminatorIndex));
break;
}
bufferList.AddRange(tempBuffer.Take(bytesRead));
address += bytesRead;
}
}
string result = Encoding.UTF8.GetString(bufferList.ToArray());
return result;
}
public T Read<T>(IntPtr address) where T : struct
{
int dataSize = Marshal.SizeOf<T>(); // Size of the data type in bytes
byte[] buffer = new byte[dataSize];
IntPtr bytesRead;
if (ReadProcessMemory(wowProc, address, buffer, dataSize, out bytesRead) && bytesRead.ToInt32() == dataSize)
{
T result = ByteArrayToStructure<T>(buffer);
return result;
}
else
{
throw new Exception("Failed to read data from memory.");
}
}
private static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
return Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
}
finally
{
handle.Free();
}
}
}