How can I read memory from a selected process? I'm using the ReadProcessMemory function and I don't understand the 2nd parameter (lpBaseAddress). Could anyone help me with this, or tell me another way to read memory from a process?

This is my function for reading memory, which I pulled off of Google.

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

        ReadProcessMemory(hProcess, dwAddress, buffer, 4, out bytesread);

        return BitConverter.ToInt32(buffer, 0);
    }

Recommended Answers

All 4 Replies

The second parm is from the MEMORY_BASIC_INFORMATION structure. You must first call OpenProcess and then call GetSystemInfo The lpMinimumApplicationAddress is used as an input to VirtualQueryEx which returns the Memory_BASIC_INFORMATION structure which is used in your ReadProcessMemory function call. In very simple terms, lpBaseAddress is where the executable loads in memory.

commented: Nice :) +14

The second parm is from the MEMORY_BASIC_INFORMATION structure. You must first call OpenProcess and then call GetSystemInfo The lpMinimumApplicationAddress is used as an input to VirtualQueryEx which returns the Memory_BASIC_INFORMATION structure which is used in your ReadProcessMemory function call. In very simple terms, lpBaseAddress is where the executable loads in memory.

Thanks. I still have tons of errors, and I don't know why though. This is the class I made so far, and I get errors at ReadMemory function.

public SYSTEM_INFO GetInfo()
{
    SYSTEM_INFO sysinfo = new SYSTEM_INFO();
    GetSystemInfo(out sysinfo);
    return sysinfo;
}

public MEMORY_BASIC_INFORMATION GetBuffer(IntPtr ProcessHandle)
{
    MEMORY_BASIC_INFORMATION ret;
    VirtualQueryEx(ProcessHandle, GetInfo().lpMinimumApplicationAddress, out ret, (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)));
    return ret;
}

public string ReadMemory(Process Process, IntPtr ProcessHandle)
{
    byte[] buffer = new byte[Process.VirtualMemorySize64];
    ReadProcessMemory(ProcessHandle, GetBuffer(ProcessHandle), buffer, Process.VirtualMemorySize64, out 0);

    return "";
}

Well, it's a nice try but you really have to use Platform Invocation Services (Pinvoke). This allows managed code to call unmanaged methods. In order to call external unmanaged methods, in this case Win32 API, you must provide the Common Language Runtime (CLR) with a declaration of the unmanaged method, and a description of how to marshal the parameters and return value to and from the unmanaged code.

In the starting code below, I did the Open Process function which is as follows:

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

The method is static since we do not have to instantiate a class. Also, the extern keyword is used which informs the compiler that the method is external to the runtime.

Here is your starter code:

// How to test
// Start an instance of notepad.exe
// Execute this app with notepad on the command line

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;


class ReadTheProcessMemory
{
    private const uint PROCESS_ALL_ACCESS = 2035711;
    static int processHandle;
    static Process[] MyProcess;

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

    public static int Main(string[] args)
    {
        string ProcessName = args[0];
        MyProcess = Process.GetProcessesByName(ProcessName);
        try
        {
            processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, MyProcess[0].Id);
            if (processHandle != 0)
                Console.WriteLine("{0} is running, ProcessID: {1}", ProcessName,MyProcess[0].Id);
                else return 0;
        }
        catch (System.IndexOutOfRangeException e) 
        {
            Console.WriteLine("Process NOT running, Error Message: " + e.Message);
        }
        return 1;
    }
}



The above app needs the name of a running process entered on its command line.  You can start notepad.exe and the execute the app with notepad on the command line.

The next Win32 API to be converted is GetSystemInfo.

I have provided the following Win32 API ReadProcessMemory sample to use as a "roadmap" in writing your application. You'll have to convert all the unmanaged function calls to managed code:

#pragma comment(lib, "advapi32.lib")
#include <windows.h>
#include <stdio.h>

VOID DumpBuffer(const unsigned char* pBuffer, size_t sz)
{
    for (size_t i = 0; i < sz; ++i)
        printf("0x%x ", pBuffer[i]);
}

BOOL DumpProcessMemory(DWORD dwPid)
{
    HANDLE pHandle;
    SYSTEM_INFO si; 
    MEMORY_BASIC_INFORMATION mbi;
    LPVOID lpMem;
    DWORD dwReturn, dwTotalRead;

    pHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid);
    if (pHandle == NULL)
    {
        printf("OpenProcess failed for PID: %d\n",dwPid); 
        return FALSE;
    }
    GetSystemInfo(&si);
    lpMem = si.lpMinimumApplicationAddress;
    while (lpMem < si.lpMaximumApplicationAddress)
    {
        mbi.RegionSize = 0;
        dwReturn = VirtualQueryEx(pHandle, lpMem, &mbi, sizeof(mbi));
        if (dwReturn == sizeof(mbi)) {
            if ((mbi.Type == MEM_PRIVATE) && (mbi.State == MEM_COMMIT))
            { 
                if (mbi.RegionSize > 0)
                {
                    const BYTE* cbBuffer = (BYTE*)HeapAlloc(GetProcessHeap(), NULL, mbi.RegionSize);
                    if (cbBuffer == NULL) 
                    {
                        printf ("HeapAlloc failed\n");
                        return FALSE;
                    }
                    ReadProcessMemory(pHandle, mbi.BaseAddress, (LPVOID)cbBuffer, mbi.RegionSize, &dwTotalRead);
                    DumpBuffer(cbBuffer, mbi.RegionSize);
                    HeapFree(GetProcessHeap(), NULL, (LPVOID)cbBuffer);
                } 
            } 
            lpMem = (LPVOID)((DWORD)mbi.BaseAddress + mbi.RegionSize);
        } 
        else break;
    }
    CloseHandle(pHandle);
    return TRUE;
}

INT main(INT argc, CHAR **argv)
{
    DumpProcessMemory(atoi(argv[1]));
    return 0;
}

Sorry for that post, I can't edit it. Anyways, I'm doing this function right here that gets it but it returns 0 every time?

public int ReadInt32(IntPtr hProcess, IntPtr dwAddress)
{
    byte[] buffer = new byte[4];
    int bytesread;
    ReadProcessMemory(hProcess, dwAddress, buffer, 4, out bytesread);
    return BitConverter.ToInt32(buffer, 0);
}

And here's the way I'm using it

        textBox1.Text = me.ReadInt32(this.Handle, me.GetBuffer(this.Handle).BaseAddress).ToString();
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.