Skip to content

Instantly share code, notes, and snippets.

@ikkentim
Last active July 14, 2022 18:27
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ikkentim/7851466 to your computer and use it in GitHub Desktop.
Save ikkentim/7851466 to your computer and use it in GitHub Desktop.
(C#) Memory class capable of reading memory of a certain process.
public struct ProcessMemory
{
#region Constructors
private ProcessMemory(Process process, int address) : this()
{
Process = process;
Address = address;
}
private ProcessMemory(Process process) : this()
{
Process = process;
}
#endregion
#region Factories
public static ProcessMemory ForProcess(Process process)
{
if (process == null)
throw new ArgumentNullException("process");
return new ProcessMemory(process);
}
#endregion
#region Properties
public int Address { get; set; }
public Process Process { get; private set; }
public ProcessMemory this[int offset]
{
get { return AtOffset(offset); }
}
public ProcessMemory this[string module]
{
get { return GetModule(module); }
}
#endregion
#region Reading methods
public ProcessMemory AsPointer()
{
return new ProcessMemory(Process, AsInteger());
}
public int AsInteger()
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
return BitConverter.ToInt32(Read(Process, Address, 4), 0);
}
public float AsFloat()
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
return BitConverter.ToSingle(Read(Process, Address, 4), 0);
}
public byte AsByte()
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
return Read(Process, Address, 1)[0];
}
public byte[] AsBytes(int count)
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
return Read(Process, Address, count);
}
public short AsShort()
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
return BitConverter.ToInt16(Read(Process, Address, 2), 0);
}
public string AsString(int length)
{
return AsString(length, Encoding.ASCII);
}
public string AsString(int length, Encoding encoding)
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
var value = Read(Process, Address, length);
var stringLength = value.ToList().FindIndex(b => b == 0);
if (stringLength == 0)
return String.Empty;
Array.Resize(ref value, stringLength + 1);
return encoding.GetString(value);
}
public void Set(int value)
{
Set(BitConverter.GetBytes(value));
}
public void Set(float value)
{
Debug.WriteLine("Setting {0} to {1}", Address, value);
Set(BitConverter.GetBytes(value));
}
public void Set(byte value)
{
Set(BitConverter.GetBytes(value));
}
public void Set(byte[] value)
{
Write(Process, Address, value);
}
public void Set(short value)
{
Set(BitConverter.GetBytes(value));
}
public void Set(bool value)
{
Set(BitConverter.GetBytes(value));
}
public void Set(string value, Encoding encoding)
{
Set(encoding.GetBytes(value));
}
public void Set(string value)
{
Set(value, Encoding.ASCII);
}
public void Set(string value, Encoding encoding, int length)
{
var data = new byte[length];
var bytes = encoding.GetBytes(value);
Array.Copy(bytes, data, bytes.Length);
Set(data);
}
public void Set(string value, int length)
{
Set(value, Encoding.ASCII, length);
}
#endregion
#region Cast operators
public static implicit operator int(ProcessMemory memory)
{
return memory.AsInteger();
}
public static implicit operator short(ProcessMemory memory)
{
return memory.AsShort();
}
public static implicit operator byte(ProcessMemory memory)
{
return memory.AsByte();
}
public static implicit operator float(ProcessMemory memory)
{
return memory.AsFloat();
}
public static implicit operator string(ProcessMemory memory)
{
return memory.AsString(256);
}
public static implicit operator ProcessMemory(Process process)
{
return ForProcess(process);
}
#endregion
#region Operators
public static ProcessMemory operator ~(ProcessMemory memory)
{
return memory.AsPointer();
}
public static ProcessMemory operator +(ProcessMemory memory, int offset)
{
return memory.AtOffset(offset);
}
public static ProcessMemory operator -(ProcessMemory memory, int offset)
{
return memory.AtOffset(-offset);
}
public static ProcessMemory operator |(ProcessMemory memory, int value)
{
memory.Set(value);
return memory;
}
public static ProcessMemory operator |(ProcessMemory memory, short value)
{
memory.Set(value);
return memory;
}
public static ProcessMemory operator |(ProcessMemory memory, byte value)
{
memory.Set(value);
return memory;
}
public static ProcessMemory operator |(ProcessMemory memory, byte[] value)
{
memory.Set(value);
return memory;
}
public static ProcessMemory operator |(ProcessMemory memory, float value)
{
memory.Set(value);
return memory;
}
public static ProcessMemory operator |(ProcessMemory memory, string value)
{
memory.Set(value);
return memory;
}
public static bool operator false(ProcessMemory memory)
{
return memory.Equals(default(ProcessMemory)) || memory.Process == null || memory.Process.HasExited;
}
public static bool operator true(ProcessMemory memory)
{
return !memory.Equals(default(ProcessMemory)) && memory.Process != null && !memory.Process.HasExited;
}
#endregion
#region Methods
public ProcessMemory AtAddress(int address)
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
return new ProcessMemory(Process, address);
}
public ProcessMemory AtOffset(int offset)
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
return new ProcessMemory(Process, Address + offset);
}
public ProcessMemory GetModule(string moduleName)
{
if (Process.HasExited)
throw new InvalidOperationException("The process has exited.");
var process = Process;
return
process.Modules.Cast<ProcessModule>()
.Where(
module =>
String.Compare(module.ModuleName, moduleName, StringComparison.OrdinalIgnoreCase) == 0)
.Select(module => new ProcessMemory(process, (int) module.BaseAddress))
.FirstOrDefault();
}
public bool Equals(ProcessMemory other)
{
return Address == other.Address && Equals(Process, other.Process);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is ProcessMemory && Equals((ProcessMemory) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Address * 397) ^ (Process != null ? Process.GetHashCode() : 0);
}
}
public override string ToString()
{
return string.Format("{0}@{1}", Process.ProcessName, Address);
}
#endregion
#region Private methods
[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)]
private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer,
int dwSize, out int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
private static extern Int32 CloseHandle(IntPtr hProcess);
private static byte[] Read(Process process, int address, int numOfBytes, out int bytesRead)
{
IntPtr hProc = OpenProcess(ProcessAccessFlags.All, false, process.Id);
byte[] buffer = new byte[numOfBytes];
ReadProcessMemory(hProc, new IntPtr(address), buffer, numOfBytes, out bytesRead);
CloseHandle(hProc);
return buffer;
}
private static byte[] Read(Process process, int address, int numOfBytes)
{
int bytesRead;
return Read(process, address, numOfBytes, out bytesRead);
}
private static void Write(Process process, int address, byte[] bytes)
{
IntPtr hProc = OpenProcess(ProcessAccessFlags.All, false, process.Id);
int numOfBytes;
WriteProcessMemory(hProc, new IntPtr(address), bytes, (UInt32)bytes.LongLength, out numOfBytes);
CloseHandle(hProc);
}
#endregion
#region ProcessAccessFlags
private enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment