Skip to content

Instantly share code, notes, and snippets.

@ceifa
Created January 30, 2020 20:46
Show Gist options
  • Save ceifa/cca8e968ea299774f07bea6bf47420bc to your computer and use it in GitHub Desktop.
Save ceifa/cca8e968ea299774f07bea6bf47420bc to your computer and use it in GitHub Desktop.
A perfect memory class
public class Memory
{
private const int ProcessVmOperation = 0x0008;
private const int ProcessVmRead = 0x0010;
private const int ProcessVmWrite = 0x0020;
private readonly Process _process;
private readonly IntPtr _processHandle;
private int _discard;
public Memory(string processName)
{
var processes = Process.GetProcessesByName(processName);
if (processes.Length == 0)
{
throw new InvalidOperationException($"{processName} must be running");
}
_process = processes[0];
_processHandle = OpenProcess(ProcessVmOperation | ProcessVmRead | ProcessVmWrite, false, _process.Id);
}
public int? GetModuleAddress(string moduleName)
{
if (!moduleName.EndsWith(".dll"))
{
moduleName = $"{moduleName}.dll";
}
foreach (ProcessModule module in _process.Modules)
{
if (moduleName == module.ModuleName)
{
return (int)module.BaseAddress;
}
}
return null;
}
public T Read<T>(int address) where T : struct
{
var byteSize = Marshal.SizeOf<T>();
var buffer = new byte[byteSize];
ReadProcessMemory(_processHandle, address, buffer, buffer.Length, ref _discard);
return ConvertToStructure<T>(buffer);
}
public T[] Read<T>(int address, int size) where T : struct
{
var byteSize = Marshal.SizeOf<T>();
var buffer = new byte[byteSize * size];
ReadProcessMemory(_processHandle, address, buffer, buffer.Length, ref _discard);
return ConvertToArray<T>(buffer, byteSize, size);
}
public void Write(int address, object value)
{
var buffer = ConvertToByteArray(value);
WriteProcessMemory(_processHandle, address, buffer, buffer.Length, out _);
}
private static T[] ConvertToArray<T>(byte[] bytes, int byteSize, int arraySize) where T : struct
{
if (bytes.Length % byteSize != 0)
throw new ArgumentException("Irregular size");
var arr = new T[arraySize];
for (var i = 0; i < arr.Length; i++)
arr[i] = ConvertToStructure<T>(bytes[(i * byteSize)..byteSize]);
return arr;
}
private static unsafe T ConvertToStructure<T>(byte[] bytes) where T : struct
{
fixed (byte* dataPtr = bytes)
return Marshal.PtrToStructure<T>(new IntPtr(dataPtr));
}
private static unsafe byte[] ConvertToByteArray(object obj)
{
var bytes = new byte[Marshal.SizeOf(obj)];
fixed (byte* ptr = bytes)
Marshal.StructureToPtr(obj, new IntPtr(ptr), true);
return bytes;
}
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
private static extern bool ReadProcessMemory(IntPtr hProcess, int lpBaseAddress, byte[] buffer, int size, ref int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
private static extern bool WriteProcessMemory(IntPtr hProcess, int lpBaseAddress, byte[] buffer, int size, out int lpNumberOfBytesWritten);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment