Search code examples
c#access-deniedreadprocessmemory

64bit ReadProcessMemory access denied


I've tried running this with Process.EnterDebugMode(), but it also doesn't work.

I want to read out the Notepad-memory but I don't know how to access it, or if the 64bit system is doing troubles.

This is what I've done:

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

public class MemoryRead
{

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

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

    [DllImport("kernel32.dll")]
    static extern bool CloseHandle(IntPtr hObject);

    static void Main(string[] args)
    {
        var pid = 10956; //notepad.exe
        var processHandle = OpenProcess(0x10, false, pid);

        byte[] buffer = new byte[24];
        int bytesRead = 0;
        ReadProcessMemory((int)processHandle, 0x21106B35770, buffer, buffer.Length, ref bytesRead); //0x21106B35770 is the address where "hello world" is written in notepad

        Console.WriteLine(Encoding.Unicode.GetString(buffer) +
           " (" + bytesRead.ToString() + "bytes)");
        Console.ReadLine();
        CloseHandle(processHandle);

        Console.ReadLine();
    }
}

Solution

  • Your PInvoke declaration of ReadProcessMemory is incorrect (though it should work on a 32 bit system).

    As can be seen from the native declaration of this function

    BOOL WINAPI ReadProcessMemory(
      _In_  HANDLE  hProcess,
      _In_  LPCVOID lpBaseAddress,
      _Out_ LPVOID  lpBuffer,
      _In_  SIZE_T  nSize,
      _Out_ SIZE_T  *lpNumberOfBytesRead
    );
    

    its first parameter is HANDLE, and it is a PVOID:

    A pointer to any type.

    This type is declared in WinNT.h as follows:

    typedef void *PVOID;

    And pointer to anything in 64-bit process is a 64-bit value - IntPtr.

    Basically the same goes to the size and lpNumberOfBytesRead parameters - they are 64 bit as well in a 64 bit process.

    Thus your declaration should be something like:

    [[DllImport("kernel32.dll", SetLastError = true)]]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern Boolean ReadProcessMemory(
      [In]  IntPtr  hProcess,
      [In]  IntPtr lpBaseAddress,
      [Out] Byte[] lpBuffer,
      [In]  UIntPtr  nSize,
      [Out] out UIntPtr lpNumberOfBytesRead
    );
    

    P.S.: And a bit of shameless self-promotion - if you ever have to work a lot with PInvoke, then there are a few good recommendations I've learned a hard way.