Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make this Readprocessmemory code a lot more efficient

Tags:

c#

Introduction

Currently I am using someone's class to read bytes in memory (via pointers). The code I have so far works perfectly, I don't really want to change the way the class is setup if possible (because it works), but hopefully some minor tweaks can be made to the class and my code to make it highly efficient.

What I achieve at the moment:

  • Start off with a pointer address in memory, reads a byte at that address, adds the data to an array, adds 1 to the original address so we can now read the next address (eg original address is 24004, once the byte is stored, increment 1 and next address to read becomes 24005).

  • Reads the byte at the next address (24005), adds this to the same array, adds 1 to that address (next to read becomes 24006).

  • And so forth for a fixed number of iterations (approximately 10,000).

The problem:

Making 10,000 calls to readprocessmemory one after the other causes a system delay of 20 seconds whilst it goes about its business.

What I hope can be achieved:

Perform Readprocessmemory once only, specifying 10,000 bytes of data to be read (instead of just a byte at a time for 10,000 iterations), save this to the array in the same format as I had before with individual bytes (I am aware therefore that instead of array {0} (1) (2).. etc.. I will now just have array {0}, so I would imagine I would need an efficient means of splitting this very large number out into 10,000 numbers (in another array)) The data stored at each address are integers. So for 5 addresses: array {12345} becomes {1}{2}{3}{4}{5}. Where 1 2 3 4 or 5 could just as well be 1 200 40 43 or 20, for example.

So ideally, if I could wave my newbie wand, it would look something like this (class below as well as what I have so far):

Iteration code:

 private void label1_Click(object sender, EventArgs e)
    {
        int[] valuesSeperated[200];
        List<byte> PreArray = new List<byte>();
        Process[] test = Process.GetProcessesByName("MyProcess"); //Get process handle 
        int baseAddress = test[0].MainModule.BaseAddress.ToInt32(); //Get base address
        byte ReadX  = MyClass.ReadPointerByte("MyProcess", BaseAddress, new int[] { 0xc, 0x0, 0x2 }); //call memory reading function (including memory offsets)
        PreArray.Add(ReadX);
                byte[] PreArrayToInt = PreArray.ToArray();
                int[] MYConvertedBytes = PreArray ToInt.Select(x => (int)x).ToArray();
                foreach (int i in MYConvertedBytes)
{
valuesSeperated // (don't really know what to do here, if the read was successful I would have a long number at [0], so now need to separate these as if I had read each one in memory one at a time. 
}

//new array with 10,000 values created.
    }

Class:

[DllImport("kernel32", EntryPoint = "ReadProcessMemory")]
private static extern byte ReadProcessMemoryByte(int Handle, int Address, ref byte Value, int Size, ref int BytesRead);

public static byte ReadPointerByte(string EXENAME, int Pointer, int[] Offset)
{
    byte Value = 0;
    checked
    {
        try
        {
            Process[] Proc = Process.GetProcessesByName(EXENAME);
            if (Proc.Length != 0)
            {
                int Bytes = 0;
                int Handle = OpenProcess(PROCESS_ALL_ACCESS, 0, Proc[0].Id);
                if (Handle != 0)
                {
                    foreach (int i in Offset)
                    {
                        ReadProcessMemoryInteger((int)Handle, Pointer, ref Pointer, 4, ref Bytes);
                        Pointer += i;
                    }
                    ReadProcessMemoryByte((int)Handle, Pointer, ref Value, 2, ref Bytes);
                    CloseHandle(Handle);
                }
            }
        }
        catch
        { }
    }
    return Value;
}
like image 281
user1166981 Avatar asked Oct 23 '22 11:10

user1166981


1 Answers

Some advices:

  • Do not call OpenProcess / CloseHandle inside your "managed wrapper" (ReadPointerByte, or whatever...), you can use the Process.Handle property.

  • To avoid possible errors related with page's permissions, you might need to wrap calls to ReadProcessMemory with VirtualProtectEx (one to 'unprotect', allowing reads, and another to 'restore' the previous protection).

Some code:

// from http://www.pinvoke.net/default.aspx/kernel32.readprocessmemory
[DllImport("kernel32", EntryPoint = "ReadProcessMemory")]
private static extern bool ReadProcessMemory(IntPtr Handle, IntPtr Address, 
    [Out] byte[] Arr, int Size, out int BytesRead);

public static byte[] ReadBytes(IntPtr hnd, IntPtr Pointer, int Length)
{
    byte[] Arr = new byte[Length];
    int Bytes = 0;
    if(!ReadProcessMemory(hnd, Pointer, Arr, Length, out Bytes)){
        // Throw exception ...
    }
    // Check if Bytes == Length ...
    return Arr;
}

private void button1_Click(object sender, EventArgs e)
{
    //Get process handle
    Process[] test = Process.GetProcessesByName("notepad++");  

    //Get base address
    IntPtr baseAddress = test[0].MainModule.BaseAddress; 

    int bytesToRead = 16;
    int[] valuesSeparated = new int[bytesToRead / 4];
    byte[] ret = ReadBytes(test[0].Handle, baseAddress, bytesToRead);

    // Interpret ret as you like ...

    // Convert ret to int[]
    valuesSeparated = ....

}

[The iteration process]

You have two options here:

  1. Get a full snapshot of the target process's memory into a byte[], and perform your algorithm in this array
  2. You can exec a readprocessmemory for each iteration. I believe this is your best option.

Regardless of targe-process-memory-reading-technique, your algorithm is this (I'm having a real hard time translating your text into an implementation...):

Input: BaseAddress of process, Offsets

Output: byte[] Ret

Steps:

1: LastPtr = BaseAddress
2: IdxOffset = 0
3: Offset = Offsets[IdxOffset]
4: LastValue = Memory[LastPtr + Offset]
5: Ret.Add(LastValue)
6: IdxOffset++
7: LastPtr = LastValue // Is this it?????
8: If IdxOffset < Offsets.Length then return else goto 3
like image 119
5 revs Avatar answered Oct 26 '22 19:10

5 revs