ReadProcessMemory (kernel32)
Last changed: -196.215.129.234

.
Summary

C# Signature:

[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)]
static extern bool ReadProcessMemory(
    IntPtr hProcess,
    IntPtr lpBaseAddress,
    [Out, MarshalAs(UnmanagedType.AsAny)] object lpBuffer,
    int dwSize,
    out IntPtr lpNumberOfBytesRead);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(
    IntPtr hProcess,
    IntPtr lpBaseAddress,
    IntPtr lpBuffer,
    int dwSize,
    out IntPtr lpNumberOfBytesRead);

VB.Net Signature:

<DllImport("kernel32.dll", SetLastError:=true)> _
Public Shared Function ReadProcessMemory( _
    ByVal hProcess As IntPtr, _
    ByVal lpBaseAddress As IntPtr, _
    <Out()> ByVal lpBuffer As Byte(), _
    ByVal dwSize as Integer, _
    ByRef lpNumberOfBytesRead as Integer) As Boolean
End Function

<DllImport("kernel32.dll", SetLastError:=true)> _
Public Shared Function ReadProcessMemory( _
    ByVal hProcess As IntPtr, _
    ByVal lpBaseAddress As IntPtr, _
    <Out(),MarshalAs(UnmanagedType.AsAny)> ByVal lpBuffer As object, _
    ByVal dwSize as Integer, _
    ByRef lpNumberOfBytesRead as Integer) As Boolean
End Function

<DllImport("kernel32.dll", SetLastError:=True)> _
Public Shared Function ReadProcessMemory( _
    ByVal hProcess As IntPtr, _
    ByVal lpBaseAddress As IntPtr, _
    ByVal lpBuffer As IntPtr, _
    ByVal iSize As Integer, _
    ByRef lpNumberOfBytesRead As Integer) As Boolean
End Function

Notes:

None.

Tips & Tricks:

Using VB.NET you may need to substitute ByVal for ByRef when declaring: "lpBuffer" and "lpNumberOfBytesRead" for the method to work.

To read primitive values without boxing pass in a byte array to read the content. Use methods in the BitConverter class to convert the data.

On 64-bit systems lpNumberOfBytesRead returned as the 64-bit value.

You can also make aliases of the signatures above to pass the variable receiving the data by reference. e.g

<DllImport("kernel32.dll", SetLastError=true, EntryPoint="ReadProcessMemory")> _
Public Shared Function ReadVMInteger(
    ByVal hProcess As IntPtr,
    ByVal lpBaseAddress As IntPtr,
    ByRef lpBuffer As Integer,
    ByVal dwSize as Integer,
    ByRef lpNumberOfBytesRead as Integer) As Boolean
End Function

Sample Code:

Assuming you're trying to readout an integer which is four bytes long:

As you can see I prove a handle, and an address.

I then create a new buffer the size of the address.

(Note that this example is an integer you could also do it with strings but then return encoding.default.ascii etc.. )

public int ReadInt32(IntPtr hProcess, uint dwAddress)
{
    byte[] buffer = new byte[4];
    int bytesread;

    Win32Api.ReadProcessMemory(hProcess, dwAddress, buffer, 4, out bytesread);
    return BitConverter.ToInt32(buffer, 0);
}

Generic RPM was missing here. (Also added WPM -> WriteProcessMemory example)

public T Rpm<T>(IntPtr lpBaseAddress) where T : struct
{
    T[] buffer = new T[Marshal.SizeOf<T>()];
    ReadProcessMemory(_gameProcess.Process.Handle, lpBaseAddress, buffer, Marshal.SizeOf<T>(), out var bytesread);
    return buffer.First(); // [0] would be faster, but First() is safer. E.g. of buffer[0] ?? default(T)
}

public T Rpm<T>(IntPtr lpBaseAddress, List<int> offsets) where T : struct
{
    IntPtr address = lpBaseAddress;

    var lastOffset = offsets.Last();
    offsets.RemoveAt(offsets.Count-1);

    foreach (var offset in offsets)
    {
       address = Rpm<IntPtr>(IntPtr.Add(address, offset));
    }

    return Rpm<T>(IntPtr.Add(address, lastOffset));
}

Alternative Managed API:

Do you know one? Please contribute it!

Documentation