Reading a processes memory

  • Thread starter Thread starter Matt Burland
  • Start date Start date
M

Matt Burland

I am trying to read the memory being used by a process but I can't
quite figure out how to do it (or if it's even possible). I can get a
reference to the process using Process.GetProcessesByName and I can get the
base address using Process.MainModule.BaseAddress (which returns a IntPtr).
I thought that by using IntPtr.ToPointer() and casting to a char* I would be
able to read the memory as a stream of chars but it doesn't work because it
always throws a NullReferenceException when I try and dereference the
pointer.
Can anybody help me out here?

Thanks


class Class1 { [STAThread] static unsafe void Main(string[] args) {
Process[] p = Process.GetProcessesByName("notepad"); ProcessModule pm =
p[0].MainModule; Console.WriteLine(pm.BaseAddress); char* ptr = (char*)
pm.BaseAddress.ToPointer(); char c = *ptr; // Throws
System.NullReferenceException Console.WriteLine(c);
Console.ReadLine(); } }
 
Hi Matt:

Every process in Win32 has it's own address space, and actually if you
check the BaseAddress for every process on the system you'll find many
of them are the same.

To pull this off you'll need to PInvoke OpenProcess and
ReadProcessMemory. Looking those API functions up in the SDK on MSDN
will get you started. ReadProcessMemory will copy bytes from the other
process into your address space.
 
Thanks for your help. I checked out the OpenProcess and ReadProcessMemory
and with a little fiddling managed to get it to read the memory. Great. Now
the problem is to see if I can alter it and write it back. I tried using
WriteProcessMemory, and I've set the DesiredAccess when opening the process
to PROCESS_VM_READ | PROCESS_VM_WRITE but it comes back with a system error
code for ERROR_ACCESS_DENIED?
Any ideas what I need to do to be able to write stuff back (if it's even
possible)? Here's my code now, it opens the process, reads 200 bytes,
displays it on the console and then tries to write the same 200 bytes back:

class Class1

{

[DllImport("Kernel32.dll")]

public static extern IntPtr OpenProcess(int dwDesiredAccess, bool
bInheritHandle, Int32 dwProcessId);

[DllImport("Kernel32.dll")]

public static extern unsafe bool ReadProcessMemory(IntPtr hProcess, IntPtr
lpBaseAddress, byte* lpBuffer, int nSize, int* lpNumberOfBytesRead);

[DllImport("Kernel32.dll")]

public static extern unsafe bool WriteProcessMemory(IntPtr hProcess, IntPtr
lpBaseAddress, byte* lpBuffer, int nSize, int* lpNumberOfBytesWritten);

[DllImport("Kernel32.dll")]

public static extern int GetLastError();

public static readonly int PROCESS_VM_READ = 0x0010;

public static readonly int PROCESS_VM_WRITE = 0x0020;



[STAThread]

static unsafe void Main(string[] args)

{

Process[] p = Process.GetProcessesByName("notepad");

ProcessModule pm = p[0].MainModule;

Console.WriteLine(pm.BaseAddress + ":" + p[0].Id);

byte[] buffer = new byte[200];

fixed(byte* cptr = &buffer[0])

{

int x = 0;

int* xptr = &x;

IntPtr hProcess = OpenProcess(PROCESS_VM_READ,false,p[0].Id);

Console.WriteLine(hProcess);

bool result = ReadProcessMemory(hProcess,pm.BaseAddress,cptr,200,xptr);

Console.WriteLine(result + ":" + x);

for (int i=0; i<200; i++)

{

byte b = *(cptr+i);

string s = b.ToString("x");

s = s.PadLeft(2,'0');

Console.Write(s + " ");

}

x = 0;

Console.WriteLine();


result = WriteProcessMemory(hProcess,pm.BaseAddress,cptr,200,xptr);

Console.WriteLine(result+":"+*xptr);

Console.WriteLine(GetLastError());


}

Console.ReadLine();

}

}


Scott Allen said:
Hi Matt:

Every process in Win32 has it's own address space, and actually if you
check the BaseAddress for every process on the system you'll find many
of them are the same.

To pull this off you'll need to PInvoke OpenProcess and
ReadProcessMemory. Looking those API functions up in the SDK on MSDN
will get you started. ReadProcessMemory will copy bytes from the other
process into your address space.

--
Scott
http://www.OdeToCode.com

I am trying to read the memory being used by a process but I can't
quite figure out how to do it (or if it's even possible). I can get a
reference to the process using Process.GetProcessesByName and I can get the
base address using Process.MainModule.BaseAddress (which returns a IntPtr).
I thought that by using IntPtr.ToPointer() and casting to a char* I would be
able to read the memory as a stream of chars but it doesn't work because it
always throws a NullReferenceException when I try and dereference the
pointer.
Can anybody help me out here?

Thanks


class Class1 { [STAThread] static unsafe void Main(string[] args) {
Process[] p = Process.GetProcessesByName("notepad"); ProcessModule pm =
p[0].MainModule; Console.WriteLine(pm.BaseAddress); char* ptr = (char*)
pm.BaseAddress.ToPointer(); char c = *ptr; // Throws
System.NullReferenceException Console.WriteLine(c);
Console.ReadLine(); } }
 
Actually I forgot to add the PROCESS_VM_WRITE in my sample and from looking
at the documentation I noticed I also need PROCESS_VM_OPERATION. When I set
both of those I get a different error: ERROR_NOACCESS.

Matt Burland said:
Thanks for your help. I checked out the OpenProcess and ReadProcessMemory
and with a little fiddling managed to get it to read the memory. Great. Now
the problem is to see if I can alter it and write it back. I tried using
WriteProcessMemory, and I've set the DesiredAccess when opening the process
to PROCESS_VM_READ | PROCESS_VM_WRITE but it comes back with a system error
code for ERROR_ACCESS_DENIED?
Any ideas what I need to do to be able to write stuff back (if it's even
possible)? Here's my code now, it opens the process, reads 200 bytes,
displays it on the console and then tries to write the same 200 bytes back:

class Class1

{

[DllImport("Kernel32.dll")]

public static extern IntPtr OpenProcess(int dwDesiredAccess, bool
bInheritHandle, Int32 dwProcessId);

[DllImport("Kernel32.dll")]

public static extern unsafe bool ReadProcessMemory(IntPtr hProcess, IntPtr
lpBaseAddress, byte* lpBuffer, int nSize, int* lpNumberOfBytesRead);

[DllImport("Kernel32.dll")]

public static extern unsafe bool WriteProcessMemory(IntPtr hProcess, IntPtr
lpBaseAddress, byte* lpBuffer, int nSize, int* lpNumberOfBytesWritten);

[DllImport("Kernel32.dll")]

public static extern int GetLastError();

public static readonly int PROCESS_VM_READ = 0x0010;

public static readonly int PROCESS_VM_WRITE = 0x0020;



[STAThread]

static unsafe void Main(string[] args)

{

Process[] p = Process.GetProcessesByName("notepad");

ProcessModule pm = p[0].MainModule;

Console.WriteLine(pm.BaseAddress + ":" + p[0].Id);

byte[] buffer = new byte[200];

fixed(byte* cptr = &buffer[0])

{

int x = 0;

int* xptr = &x;

IntPtr hProcess = OpenProcess(PROCESS_VM_READ,false,p[0].Id);

Console.WriteLine(hProcess);

bool result = ReadProcessMemory(hProcess,pm.BaseAddress,cptr,200,xptr);

Console.WriteLine(result + ":" + x);

for (int i=0; i<200; i++)

{

byte b = *(cptr+i);

string s = b.ToString("x");

s = s.PadLeft(2,'0');

Console.Write(s + " ");

}

x = 0;

Console.WriteLine();


result = WriteProcessMemory(hProcess,pm.BaseAddress,cptr,200,xptr);

Console.WriteLine(result+":"+*xptr);

Console.WriteLine(GetLastError());


}

Console.ReadLine();

}

}


Scott Allen said:
Hi Matt:

Every process in Win32 has it's own address space, and actually if you
check the BaseAddress for every process on the system you'll find many
of them are the same.

To pull this off you'll need to PInvoke OpenProcess and
ReadProcessMemory. Looking those API functions up in the SDK on MSDN
will get you started. ReadProcessMemory will copy bytes from the other
process into your address space.
would
because
it
always throws a NullReferenceException when I try and dereference the
pointer.
Can anybody help me out here?

Thanks


class Class1 { [STAThread] static unsafe void Main(string[] args) {
Process[] p = Process.GetProcessesByName("notepad"); ProcessModule pm =
p[0].MainModule; Console.WriteLine(pm.BaseAddress); char* ptr = (char*)
pm.BaseAddress.ToPointer(); char c = *ptr; // Throws
System.NullReferenceException Console.WriteLine(c);
Console.ReadLine(); } }
 
Hi Matt:

I'm afraid I have not worked with WriteProcessMemory much to know how
to troubleshoot this. I do know some pages will be marked as read only
pages - not sure if there is a guaranteed solution to unprotect
them... :/

--s
 
Back
Top