How to use ReadProcessMemory

Celmos picture Celmos · Sep 26, 2017 · Viewed 10.8k times · Source

So I have been trying to read variables with ReadProcessMemory and finding the adresses in cheat engine worked perfectly, but as soon as I got to programming I encountered some problems. I searched for the ammo and health addresses in cheat engine and the health was a one level pointer and the ammo was a three level pointer. I tried reading the health, but everytime I read it, it returns 0.

namespace AssaultCubeTrainer

{

public partial class MainWindow : Window
{

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool ReadProcessMemory(IntPtr pHandle, IntPtr Address, byte[] Buffer, int Size, IntPtr NumberofBytesRead);

    public static Process myProc;

    public static Player p1;

    public MainWindow()
    {
        InitializeComponent();

        p1  = new Player();

        MessageBox.Show("Please press the attach button as soon as the game has started", " Information",MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);



    }

    private void AttachProcButton_Click(object sender, RoutedEventArgs e)
    {

        try
        {
            myProc = Process.GetProcessesByName("ac_client")[0];


            if (myProc.Handle != null)
            {
                MessageBox.Show("Process successfully attached", "Success", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
            }
        }

        catch
        {
            MessageBox.Show("The process was not found","Error", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
        }

    }

    private void ButtonTest_Click(object sender, RoutedEventArgs e)
    {

            lbHealthInfo.Content = p1.GetHealthInfo();

    }
}

}

namespace AssaultCubeTrainer
{
    public class Player
{

    private byte[] buffer;

    public bool ReadSuccess;

    public int HealthAddress;
    public int HealthOffset;

    public int AmmoAddress;
    public int AmmoOffset;

    public int Health;
    public int Ammo;

    public IntPtr bytesRead;

    public Player()
    {
        HealthAddress = 0x00509B74;
        HealthOffset = 0xF8;

        AmmoAddress = 0x00509B74;
        AmmoOffset = 0x374;

        Health = HealthAddress + HealthOffset;
        Ammo = AmmoAddress + AmmoOffset;

    }


//Here I have the problem when reading variable
public int GetHealthInfo()
        {
            **buffer = new byte[4];
            ReadSuccess = MainWindow.ReadProcessMemory(MainWindow.myProc.Handle, (IntPtr)Health, buffer, buffer.Length, bytesRead);
            return BitConverter.ToInt32(buffer, 0);**


    }
}

}

Heres the links to the addresses in cheat engine Couldnt upload them here :P

http://prntscr.com/gp1ko0

http://prntscr.com/gp1ksu

How do I use pointers and offsets from cheat engine properly in my code and how do I implement multi-level pointers into my code? Please excuse my shitty english.

Answer

Xiaoy312 picture Xiaoy312 · Sep 26, 2017

ReadProcessMemory(MainWindow.myProc.Handle, ...)

hProcess [in]
A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process.

To get this handle, you need to use OpenProcess:

[DllImport("kernel32", SetLastError = true)]
public static extern IntPtr OpenProcess(
            int dwDesiredAccess,
            IntPtr bInheritHandle,
            IntPtr dwProcessId
            );
public const int PROCESS_VM_READ = 0x10;

var handle = OpenProcess(PROCESS_VM_READ, IntPtr.Zero, new IntPtr(MainWindow.myProc.Id)); // note: use the id
ReadProcessMemory(handle, ...);

EDIT: Also make sure your application runs on elevated privileges, which means you should start VStudio or your application with Run as Admin.

EDIT2: You should use ref for the lpBuffer to avoid stepping into unsafe territory:

    [DllImport("kernel32", SetLastError = true)]
    public static extern int ReadProcessMemory(
        IntPtr hProcess,
        int lpBase,
        ref int lpBuffer,
        int nSize,
        int lpNumberOfBytesRead
        );

As for multi-level pointers, you read the value of base address, and add the offset and read again and again.

ReadProcessMemory(handle, BaseAddress, ref value, sizeof(int), 0);
ReadProcessMemory(handle, value + 0x508, ref value, sizeof(int), 0);
ReadProcessMemory(handle, value + 0xF8, ref value, sizeof(int), 0);

Or, you could use my Pointer class in Xy.DataAnalysis. Usage example can be found in Xy.PerfectWorld.Models: https://github.com/Xiaoy312/Xy.PerfectWorld/tree/master/Xy.DataAnalysis