carlAlex
10/5/2016 - 11:40 AM

C# Accessing memory the manual way

C# Accessing memory the manual way

To write to a process' memory you'll need:
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(int hProcess, int lpBaseAddress, 
  byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesWritten);
  
You also need special permissions to do this:
const int PROCESS_VM_WRITE = 0x0020;
const int PROCESS_VM_OPERATION = 0x0008;

***FULL EXAMPLE***

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

public class MemoryRead
{
    const int PROCESS_VM_WRITE = 0x0020;
    const int PROCESS_VM_OPERATION = 0x0008;

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

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool WriteProcessMemory(int hProcess, int lpBaseAddress, 
      byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesWritten);

    public static void Main()
    {
        Process process = Process.GetProcessesByName("notepad")[0];
        IntPtr processHandle = OpenProcess(0x1F0FFF, false, process.Id); 

        int bytesWritten = 0;
        byte[] buffer = Encoding.Unicode.GetBytes("It works!\0");
        // '\0' marks the end of string

        // replace 0x0046A3B8 with your address
        WriteProcessMemory((int)processHandle, 0x0046A3B8, buffer, buffer.Length, ref bytesWritten);

        Console.ReadLine();
    }
}
We need to import 2 functions into C# from kernel32.dll (This is a good way to learn a part of WinAPI..)

[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);
  
To open a process for reading only, specify desired access by:
const int PROCESS_WM_READ = 0x0010;

***WHOLE EXAMPLE***

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

public class MemoryRead
{
    const int PROCESS_WM_READ = 0x0010;

    [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);

    public static void Main()
    {
        Process process = Process.GetProcessesByName("notepad")[0]; 
        IntPtr processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id); 

        int bytesRead = 0;
        byte[] buffer = new byte[24]; //'Hello World!' takes 12*2 bytes because of Unicode 


        // 0x0046A3B8 is the address where I found the string, replace it with what you found
        ReadProcessMemory((int)processHandle, 0x0046A3B8, buffer, buffer.Length, ref bytesRead);

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