Created
January 30, 2020 20:46
-
-
Save ceifa/cca8e968ea299774f07bea6bf47420bc to your computer and use it in GitHub Desktop.
A perfect memory class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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