ReadProcessMemory Read string until NULL

0

I'm trying to read a string "845120" from a process memory but I have some trouble...

I know "845120" is a numeric value, but in some cases it can be alphanumeric, that's why it's a string and not a 4 byte int.

Here is my Memory class, where I have all functions that deal with memory:

private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead);

public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
{
    var buffer = new byte[IntPtr.Size];
    foreach (int i in offsets)
    {
        ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);

        ptr = (IntPtr.Size == 4)
        ? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
        : ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
    }
    return ptr;
}

public static IntPtr GetModuleBaseAddress(Process proc, string modName)
{
    IntPtr addr = IntPtr.Zero;

    foreach (ProcessModule m in proc.Modules)
    {
        if (m.ModuleName == modName)
        {
            addr = m.BaseAddress;
            break;
        }
    }
    return addr;
}

public static string ReadStringUntilNULL(string EXENAME, int Address)
{
    string value = "";
    bool endOfString = false;
    int counter = 0;
    while (!endOfString)
    {
        if (ReadInt8(EXENAME, Address + counter) > (byte)0)
        {
            value += (char)ReadInt8(EXENAME, Address + counter);
        }
        else
        {
            return value;
        }
        counter++;
    }
    return value;
}

And here's the code that I'm using to invoke that functions:

Process process = null;

while(process == null)
{
    process = Process.GetProcessesByName("client_dx").FirstOrDefault();
}

var hProc = Memory.OpenProcess(0x00000010, false, process.Id);

var modBase = Memory.GetModuleBaseAddress(process, "client_dx.exe");

var addr = Memory.FindDMAAddy(hProc, (IntPtr)(modBase + 0x003393AC), new int[] { 0x30, 0x374, 0x2C, 0x0, 0x14, 0x48, 0x10 });

var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr);

Debug.WriteLine(acc);

It's working perfectly until this line:

var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr);

So var addr have the correct address but var acc it's not getting the expected results.

Here I'm getting this error: cannot convert from 'System.IntPtr' to 'int'

Ok, so it expects an integer where I'm giving a pointer... so I tested with ToInt32()

var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr.ToInt32());

The addr.ToInt32() operation returns 262959880 and as far as I know that's not even an address

I'm getting an empty string, the ReadStringUntilNULL function from Memory class it's only looping once..

Values are: addr 0x0fac7308 System.IntPtr and acc "" string

How can I read that string from memory? Or how can I pass the parameter correctly?

c#
memory
asked on Stack Overflow Nov 27, 2019 by kuhi

1 Answer

1

I finally wrote a class that lets me read strings until null:

public class NewMem
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll")]
    public static extern bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);

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

    public Process Process { get; set; }

    public static IntPtr GetModuleBaseAddress(Process proc, string modName)
    {
        IntPtr addr = IntPtr.Zero;

        foreach (ProcessModule m in proc.Modules)
        {
            if (m.ModuleName == modName)
            {
                addr = m.BaseAddress;
                break;
            }
        }
        return addr;
    }

    public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
    {
        var buffer = new byte[IntPtr.Size];
        foreach (int i in offsets)
        {
            ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);

            ptr = (IntPtr.Size == 4)
            ? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
            : ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
        }
        return ptr;
    }

    public string ReadStringASCII(IntPtr address)
    {
        var myString = "";

        for (int i = 1; i < 50; i++)
        {
            var bytes = ReadMemory(address, i);
            if (bytes[(i-1)] == 0)
            {                    
                return myString;
            }
            myString = Encoding.ASCII.GetString(bytes);
        }

        return myString;
    }

    public byte[] ReadMemory(IntPtr address, int size)
    {
        var buffer = new byte[size];
        var bytesRead = 0;

        ReadProcessMemory((int)Process.Handle, (int)address, buffer, buffer.Length, ref bytesRead);

        return buffer;

    }
}

This is my code:

NewMem MClass = new NewMem();

var client = Process.GetProcessesByName("client_dx").FirstOrDefault();

MClass.Process = client;

// Get handle to process
var hProc = NewMem.OpenProcess(0x00000010, false, client.Id);

// Get base module
var modBase = NewMem.GetModuleBaseAddress(client, "client_dx.exe");

// Get relative base address
var vBasePointer = NewMem.FindDMAAddy(hProc, (IntPtr)(modBase + 0x55F870), new int[] { 0 });

// Get string
if (vBasePointer != IntPtr.Zero)
{
    var vNameAddress = vBasePointer + 0x20;
    var vName = MClass.ReadStringASCII(vNameAddress);
}

It's stopping reading when finds a '0', but you can always set up some exceptions or tricks, I didn't find a cleaner way to do this but it's working :)

answered on Stack Overflow Dec 2, 2019 by kuhi

User contributions licensed under CC BY-SA 3.0