C# Scan for Memory Address Efficiently

0

I've written a memory editor class that can read and write memory, but what I need to do is to scan the program's memory, and find the list of memory addresses that contain the memory I'm searching for.

This is the memory editor class.

class MemoryEditor
{
    public const uint DELETE = 0x00010000;
    public const uint READ_CONTROL = 0x00020000;
    public const uint WRITE_DAC = 0x00040000;
    public const uint WRITE_OWNER = 0x00080000;
    public const uint SYNCHRONIZE = 0x00100000;
    public const uint END = 0xFFF;
    public const uint PROCESS_ALL_ACCESS = (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | END);

    public Process targetedProcess;

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

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

    [DllImport("kernel32.dll")]
    public static extern bool WriteProcessMemory(int hProcess, int lpBaseAddress, byte[] buffer, int size, int lpNumberOfBytesWritten);

    public Process targetProcess(string name, int index = 0)
    {
        return (targetedProcess = Process.GetProcessesByName(name)[index]);
    }

    public int getHandle(Process proc, uint access = PROCESS_ALL_ACCESS)
    {
        return OpenProcess(access, false, proc.Id);
    }

    public byte[] getBytesFromString(string str)
    {
        return Encoding.Unicode.GetBytes(str);
    }

    public string getStringFromBytes(byte[] byteArr)
    {
        return Encoding.Unicode.GetString(byteArr);
    }

    public int makeHex(string str)
    {
        return (int.Parse(str, System.Globalization.NumberStyles.HexNumber));
    }

    public byte[] ReadMemory(int address, int processSize)
    {
        byte[] buffer = new byte[processSize];
        ReadProcessMemory(getHandle(targetedProcess), address, buffer, processSize, 0);
        return buffer;
    }

    public List<int> GetAddress(byte[] memory, int index = 0)
    {
        List<int> buf = new List<int>();

        for (int i = 0; i < int.MaxValue; i++)
            if (ReadMemory(makeHex(i.ToString()), 1) == memory)
                buf.Add(i);

        return buf;
    }

    public void WriteMemory(int address, byte[] processBytes)
    {
        WriteProcessMemory(getHandle(targetedProcess), address, processBytes, processBytes.Length, 0);
    }

    public int GetObjectSize(object TestObject)
    {
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream ms = new MemoryStream();
        byte[] Array;
        bf.Serialize(ms, TestObject);
        Array = ms.ToArray();
        return Array.Length;
    }
}

And here is the function to try to find the memory addresses

    public List<int> GetAddress(byte[] memory, int index = 0)
    {
        List<int> buf = new List<int>();

        for (int i = 0; i < int.MaxValue; i++)
            if (ReadMemory(makeHex(i.ToString()), 1) == memory)
                buf.Add(i);

        return buf;
    }

It lags extremely badly, and I'm only targeting notepad. When I scan memory in Cheat Engine, it finds it immediately, without any lag. My program scans from 0, to the max value of an int, but Cheat Engine does it 0 to the max value of a long, so I don't know what I'm doing wrong.

Any way I can do this efficiently?

c#
memory
editor

1 Answer

2

There are several problems I see right away.

1. You're only reading one byte at a time:

ReadMemory(makeHex(i.ToString()), 1)

I'm not certain, but I would assume that a call to ReadProcessMemory requires a system call to execute, and doing this for every byte is certainly going to be one source of slowdown. Instead, you should read some size of "block" and then scan through that block in your process. (Doing one page at a time may be the most efficient.)

2. Why in the world are you doing all of the conversions back-and-forth to strings?!

public int makeHex(string str)
{
    return (int.Parse(str, System.Globalization.NumberStyles.HexNumber));
}

....

for (int i = 0; i < int.MaxValue; i++)
    if (ReadMemory(makeHex(i.ToString()), 1) == memory)

Every iteration of that loop, you're converting i to a string (the default, decimal - not hex), and then immediately passing it to makeHex which parses it (as hex, always) back to an integer. What's the point of this? Just pass the integer! These conversions can be very expensive.

<pedantic>By the way, the name "makeHex" doesn't make sense - it's going from hex, and making an integer.</pedantic>

answered on Stack Overflow Aug 1, 2013 by Jonathon Reinhart • edited Aug 1, 2013 by Jonathon Reinhart

User contributions licensed under CC BY-SA 3.0