Reputation: 939
So I've been fighting through issue after issue with external process memory reading (reading the memory of processes I don't have access to.) My understanding of several things has changed, but there is one thing which I simply cannot get my head around.
The win32api function ReadProcessMemory() accepts several arguments, as seen here:
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
[In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
I'm passing those arguments like this:
public byte[] ReadBytes(IntPtr Handle, Int64 Address, uint BytesToRead)
{
IntPtr ptrBytesRead;
byte[] buffer = new byte[BytesToRead];
ReadProcessMemory(Handle, new IntPtr(Address), buffer, BytesToRead, out ptrBytesRead);
return buffer;
}
It was, until recently, my understanding that the Address listed here was the only thing really important to reading the memory, and that was what found me the correct value in memory. Unfortunately, that appears to be a load of tosh, and it seems that actually the handle controls which window I am interacting with. For example:
I am running 2 versions of the Process "Notepad.exe".
Each instance of the process has an integer in it, the first one contains the number 12345, the second contains 54321.
I'm looking to read that integer, and let's say (though I haven't confirmed this, so it may be untrue) memory address within that programs memory space is 0x1000.
If I run for example:
ReadProcessMemory(NP.Handle, NP.MainModule.BaseAddress + 0x1000, buffer, 32, bread);
That will read the process with that handle, at that base address added to that offset. However this code will read exactly the same value:
ReadProcessMemory(NP.Handle, NP2.MainModule.BaseAddress + 0x1000, buffer, 32, bread);
Note that NP2 is supposed to be the second notepad window, and NP is the first. On top of the above, this will read a different value (in spite of the address we're reading being the same as the first example):
ReadProcessMemory(NP2.Handle, NP.MainModule.BaseAddress + 0x1000, buffer, 32, bread);
Surely this means that the handle is controlling where the memory is read, and not the address, and that in fact the address is completely irrelevant to what I'm actually trying to do? Can anyone explain to me why that would be the case?
Apologies if this question is excessively specific, but this issue has been racking my brain for a long time now, and although I speak to numerous programmers on a daily basis, none of them have been able to (or perhaps it's more that they haven't been willing to) help me.
I am fully aware that this will only work for 2 running instances of the same exe, so it won't work if you're gonna read Firefox and Notepad (I think). I'm just wondering why it is the handle that makes this change, and not the address.
Thanks
Upvotes: 0
Views: 406
Reputation: 108995
It was, until recently, my understanding that the Address listed here was the only thing really important to reading the memory, and that was what found me the correct value in memory. Unfortunately, that appears to be a load of tosh, and it seems that actually the handle controls which window I am interacting with.
In this paragraph there are multiple miss-understandings about what you are doing that I'm not really sure where to begin.
But here goes (assume this is incomplete):
reading the memory of processes I don't have access to
You can't.
If you do not have sufficient access to the target process Windows security will prevent you getting a handle to that process with the necessary rights. (If this were not the case there would be no security.)
However we'll assume the reading process is running with Debug or equivalent privilege that gives sufficient access (this is why, in part, such are known as "God Privileges" allowing holders to bypass security).
handle controls which window
You need a process handle, not a window handle: they're completely different things. Use OpenProcess
to get a process handle from a process id, to read memory include PROCESS_VM_READ
in the requested access rights.
They you need to make use of knowledge of the (virtual) memory layout of Windows processes to work out what addresses you'll need to read from. Remember that ASLR and 32 vs 64bit processes will change that memory layout. Additional the allocated address space is unlikely to be contiguous, so you cannot just read memory sequentially.
This is an advanced topic. And in the end there is almost always a better approaches (proper APIs, making use of SendMessage
to request the content of controls, …) than directly reading process memory (remember a minor change to one DLL—eg. from a security patch—will shift things around).
Summary: find another, better, way.
EDIT: A few resources to understand memory in Windows:
Mysteries of Memory Management Revealed,with Mark Russinovich (Part 2 of 2)
A two part talk (part 1: virtual memory, part 2: physical) that will also introduce some very useful tools for looking at memory and how it is organised.
Read Windows Internals, Mark Russinovich et al. (not all will be relevant, but you will need to understand security in Win32 as well).
Read Advanced Windows, Jeffrey Richter. I think this is out of print (my 3rd edition covers Win95/NT4) but is the only serious coverage of the information you will need to know to read process memory and interpret the results.
Upvotes: 2