As the OP mentioned you can do this with pinvoke and skip using blackmagic.
So for those that want full control without the extra DLL here is the pinvoke code to read and write memory in C#:
Code:
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(IntPtr hProcess);
public static void WriteMemory(Process p, int address, long v)
{
var hProc = OpenProcess(ProcessAccessFlags.All, false, p.Id);
var val = new[] {(byte) v};
int numWritten = 0;
WriteProcessMemory(hProc, new IntPtr(address), val, (UInt32) val.LongLength, out numWritten);
CloseHandle(hProc);
}
public static byte[] ReadMemory(Process p, int address, int numberOfBytes)
{
var hProc = OpenProcess(ProcessAccessFlags.All, false, p.Id);
byte[] buffer = new byte[numberOfBytes];
int bytesread;
ReadProcessMemory(hProc, new IntPtr(address), buffer, numberOfBytes, out bytesread);
return buffer;
}
Enjoy