🔒 Locked
Determining Process Memory Area
Advertisement
Original Post
How can I determine the area of a processes memory? I've been looking into ReadProcessMemory and I want to scan a processes memory for a particular value, however it's going to take forever to scan from 0x0000000 to 0xFFFFFF and from what I've seen the process doesn't store memory in all these locations (maybe I'm wrong) but is there a way to determine where the memory area begins and ends?
Stack or heap? You may be able to just use the stack pointer ESP...
In most cases process memory above 0x7FFFFFFF belongs to the kernel, so you don't have to scan the entire 4gb - you won't be able to scan the kernel portion anyway, at least not without some complicated hacks. Virtual memory is also allocated in 64 kb chunks. You can confirm that for yourself via GetSystemInfo and the allocation granularity. That means you don't have to scan every single byte, just every 64 kb chunk between 0 and 0x80000000, which works out to 0x8000 chunks. Really, the word I should use isn't scan, but simply query, using VirtualQueryEx. That way you can pass on scanning unused allocations. You might want to start with a program that scans it's own virtual memory before moving on to scanning another process.
So, would each memory address be a single byte of data? Also I'm not to sure what the last argument of VirtualQueryEx is and how I use it.
Here is my declaration of it from the Win32 API.
And the following is how I use it.
For the last argument I don't know what to put. I think the STATE of the BASIC_MEMORY_INFORMATION is what you were referring to in order to decide whether or not the memory address is worth reading.
Here is my declaration of it from the Win32 API.
// typedef struct _MEMORY_BASIC_INFORMATION{ // PVOID BaseAddress; // PVOID AllocationBase; // DWORD AllocationProtect; // SIZE_T RegionSize; // DWORD State; // DWORD Protect; // DWORD Type; // } MEMORY_BASIC_INFORMATION, // *PMEMORY_BASIC_INFORMATION; [StructLayout(LayoutKind.Sequential)] public struct MEMORY_BASIC_INFORMATION { public IntPtr BaseAddress; public IntPtr AllocationBase; public uint AllocationProtect; public uint RegionSize; public uint State; public uint Protect; public uint Type; } // SIZE_T VirtualQueryEx( // HANDLE hProcess, // LPCVOID lpAddress, // PMEMORY_BASIC_INFORMATION lpBuffer, // SIZE_T dwLength // ); [DllImport("Kernel32.dll", EntryPoint = "VirtualQueryEx")] public static extern long VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, MEMORY_BASIC_INFORMATION lpBuffer, long dwLength);And the following is how I use it.
public uint GetMemoryState(IntPtr MemoryAddress) { ProcessMemoryReaderApi.MEMORY_BASIC_INFORMATION memInfo = new ProcessMemoryReaderApi.MEMORY_BASIC_INFORMATION(); ProcessMemoryReaderApi.VirtualQueryEx(m_hProcess, MemoryAddress, memInfo, memInfo.RegionSize, /*What goes here?*/); return memInfo.State; }For the last argument I don't know what to put. I think the STATE of the BASIC_MEMORY_INFORMATION is what you were referring to in order to decide whether or not the memory address is worth reading.
Quote:
Original post by Zmurf
So, would each memory address be a single byte of data? Also I'm not to sure what the last argument of VirtualQueryEx is and how I use it.
On a 32 bit system, it takes 32 bits to hold a memory address. That's four bytes. Each address points to a single byte of memory but the general conception is that it points to the first byte of a block of memory.
Here is a simple C program that scans the virtual memory of the current process.
#include <windows.h>#include <stdio.h>int main(void){ MEMORY_BASIC_INFORMATION membasic; printf(" address | BaseAddress, AllocationBase, AllocationProtect, RegionSize, State, Protect\n"); for (DWORD address = 0; address < 0x80000000; address += 0x10000UL) { VirtualQuery((DWORD*)address, &membasic, sizeof(membasic)); if ( MEM_COMMIT == membasic.State ) { // scan me further printf("%08X | %08X, %08X, %08X, %08d, %08X, %08X, %08X\n", address, membasic.BaseAddress, membasic.AllocationBase, membasic.AllocationProtect, membasic.RegionSize, membasic.State, membasic.Protect, membasic.Type); } } return 0;}Quote:
Original post by Anonymous Poster
I'm not exactly sure what you mean by your declaration... You can just include the required header and you're set to use VirtualQueryEx().
Declaring it like this seems to be the only way I can use the functions in C#, from the articles I've read. But I've only been able to find articles on how to open a process and read a known memory location.
I've modified my query function to this:
public uint GetMemoryState(IntPtr MemoryAddress) { ProcessMemoryReaderApi.MEMORY_BASIC_INFORMATION memInfo; ProcessMemoryReaderApi.VirtualQueryEx(m_hProcess, MemoryAddress, &memInfo, sizeof(memInfo)); return memInfo.State; }But it's giving me the following errors:
Quote:
Error 1 Pointers and fixed size buffers may only be used in an unsafe context
Error 2 The type or namespace name 'memInfo' could not be found (are you missing a using directive or an assembly reference?)
Error 3 The best overloaded method match for 'MemoryEdit.ProcessMemoryReaderApi.VirtualQueryEx(System.IntPtr, System.IntPtr, MemoryEdit.ProcessMemoryReaderApi.MEMORY_BASIC_INFORMATION, long)' has some invalid arguments
Error 4 Argument '3': cannot convert from 'MemoryEdit.ProcessMemoryReaderApi.MEMORY_BASIC_INFORMATION*' to 'MemoryEdit.ProcessMemoryReaderApi.MEMORY_BASIC_INFORMATION'
The messages are there to tell you that this sort of hackery is best done in a lower level language than C#. as for the error messages, use google.
I don't see how hacks are required, it's just read-only virtual memory. You can even write to it after you call VirtualProtect I believe(though not a good idea).
Quote:
In most cases process memory above 0x7FFFFFFF belongs to the kernel, so you don't have to scan the entire 4gb - you won't be able to scan the kernel portion anyway, at least not without some complicated hacks
I don't see how hacks are required, it's just read-only virtual memory. You can even write to it after you call VirtualProtect I believe(though not a good idea).
Quote:
Original post by LessBread
In most cases process memory above 0x7FFFFFFF belongs to the kernel...
I thought that was always the case.
LessBread's approach is great if you want to scan the entire process's address-space, but generally, if you're looking for 'a variable', you don't need to look so far.
You may want to have a look at the PSAPI library. In particular, QueryWorkingSetEx could save you some time. Also, if you have the means to call from within the process's address-space, GetProcessHeaps could come in handy.
Admiral
Quote:
Original post by DaBookshah
The messages are there to tell you that this sort of hackery is best done in a lower level language than C#. as for the error messages, use google.Quote:
In most cases process memory above 0x7FFFFFFF belongs to the kernel, so you don't have to scan the entire 4gb - you won't be able to scan the kernel portion anyway, at least not without some complicated hacks
I don't see how hacks are required, it's just read-only virtual memory. You can even write to it after you call VirtualProtect I believe(though not a good idea).
My understanding is that attempts to touch addresses above 0x80000000 will produce an access violation exception. Most of the mapping above that address is the same across every process so I'm at a loss as to why it would be so easy to write to that range in another process and not within the current process.
@TheAdmiral - Here's the exception to the 2gb rule:
The /3GB switch allocates 3 GB of virtual address space to an application that uses IMAGE_FILE_LARGE_ADDRESS_AWARE in the process header. This switch allows applications to address 1 GB of additional virtual address space above 2 GB. [1]. In the past when I've talked about the 2gb user address space without qualifying it, a stickler would always point this out, so I've taken to qualifying the assertion with phrases like "in most cases" in order to preclude such remarks.
QueryWorkingSetEx and GetProcessHeaps are more direct approaches. And like DaBookshah said, these investigations are better done in a lower level language than C#.
Quote:
Original post by LessBread
My understanding is that attempts to touch addresses above 0x80000000 will produce an access violation exception. Most of the mapping above that address is the same across every process so I'm at a loss as to why it would be so easy to write to that range in another process and not within the current process.
Wrong. Ollydbg marks those pages as readable, and anyway, kernel32/ntdll api calls will sometimes read data in this location, so obviously they can be read. Not so sure about the writing bit, but still, with VirtualProtect I think you can.
Then Ollydbg likely uses a device driver to read those addresses or it's a 16 bit app that runs at an extremely low level similar to SoftIce. K32 and NTDLL don't read data in kernel land from user land. They pass addresses from user space to kernel space through interrupt 2E. The eventual handler locks those addresses into ram so they don't page fault (page faults in kernel mode cause bsods), then if there is kernel data to be transfered back to user land, it's copied to the locked user land address, the userland memory is unlocked, the interupt handler returns passing execution back over to userland. That's the short of it at least.
Olly is not a 16-bit app....It's a ring 3 debugger, and I don't think it has any ring-0 components. And I am talking about under XP. In any case, that you can run olly and view this memory while NOT running as administrator rules out use of a device-driver(you need to be Administrator), I think. Bah, I'll just check when I get home.
wow, I actually understood all of that!
Seems theres some confusion, I don't think that happens either.
EDIT: Admiral is the expert, but I would read his post as saying that kernel32/ntdll are loaded above 0x80000000.
Quote:
Then Ollydbg likely uses a device driver to read those addresses or it's a 16 bit app that runs at an extremely low level similar to SoftIce. K32 and NTDLL don't read data in kernel land from user land. They pass addresses from user space to kernel space through interrupt 2E. The eventual handler locks those addresses into ram so they don't page fault (page faults in kernel mode cause bsods), then if there is kernel data to be transfered back to user land, it's copied to the locked user land address, the userland memory is unlocked, the interupt handler returns passing execution back over to userland. That's the short of it at least.
wow, I actually understood all of that!
Quote:
K32 and NTDLL don't read data in kernel land from user land
Seems theres some confusion, I don't think that happens either.
EDIT: Admiral is the expert, but I would read his post as saying that kernel32/ntdll are loaded above 0x80000000.
Quote:
Original post by DaBookshah
Olly is not a 16-bit app....It's a ring 3 debugger, and I don't think it has any ring-0 components. And I am talking about under XP. In any case, that you can run olly and view this memory while NOT running as administrator rules out use of a device-driver(you need to be Administrator), I think. Bah, I'll just check when I get home.
Ok, if it's a 32 bit app then it most likely uses a driver to read kernel addresses. That's how the sysinternals utilities do it. Some native routines can be called too, but that can get tricky. A user mode app isn't not supposed to be able to read kernel mode addresses directly. The os supplies a couple of interfaces for accessing kernel side information - psapi, toolhelp, wmi - but these wrap the switch to kernel mode.
Quote:
Original post by DaBookshah Quote:
Then Ollydbg likely uses a device driver to read those addresses or it's a 16 bit app that runs at an extremely low level similar to SoftIce. K32 and NTDLL don't read data in kernel land from user land. They pass addresses from user space to kernel space through interrupt 2E. The eventual handler locks those addresses into ram so they don't page fault (page faults in kernel mode cause bsods), then if there is kernel data to be transfered back to user land, it's copied to the locked user land address, the userland memory is unlocked, the interupt handler returns passing execution back over to userland. That's the short of it at least.
wow, I actually understood all of that!
Check out the sections in the IA32 manual about call gates and interrupt gates. And here's another reference: Interfacing the the Native API in Windows 2000.
Quote:
Original post by DaBookshah Quote:
K32 and NTDLL don't read data in kernel land from user land
Seems theres some confusion, I don't think that happens either.
EDIT: Admiral is the expert, but I would read his post as saying that kernel32/ntdll are loaded above 0x80000000.
Which post was that? On the version of XP SP2 running on the machine I'm using right now, the preferred load address for K32 is 0x7C800000 and for NTDLL is 0x7C900000.
@DaBookshah, here's a description of one approach to accessing kernel addresses from user mode: Entering the kernel without a driver and getting interrupt information from APIC. This approach uses some inline assembler and NtMapViewOfSection and NtUnMapViewOfSection from NTDLL to start with. It's not a very robust approach so it wouldn't be good to use with a debugger. A driver or some microsoft supplied approach would be the way to go.
*Gives up and agrees with LessBread*
I was confusing 0x80000000 with 0x7c800000. Guess I never noticed that locations past 0x80000000 are never used.
Guess I learned something.
EDIT: Interesting links btw.
I was confusing 0x80000000 with 0x7c800000. Guess I never noticed that locations past 0x80000000 are never used.
Guess I learned something.
EDIT: Interesting links btw.
You're welcome. I think the subject is interesting so I've looked into it quite a bit. Here are three more links. Dependency Walker 2.2. This is the software that I used to determine the preferred load address of those two dlls. PEBrowse Professional. In the past I've used this to examine ntoskrnl.exe (that's the grandaddy of the windows operating system). Best of all, both of these programs are free! (And their usefulness goes beyond snooping around in kernelland). And lastly, a white paper from Microsoft: Memory Management: What Every Driver Writer Needs to Know.
Ok, I've changed my code and now it's compiling properly (well, at least not giving me errors)
But its giving me the following runtime error:
I'm stumped as to how to fix this, I've been link chasing all over MSDN with no luck.
public uint GetMemoryState(IntPtr MemoryAddress) { ProcessMemoryReaderApi.MEMORY_BASIC_INFORMATION memInfo = new ProcessMemoryReaderApi.MEMORY_BASIC_INFORMATION(); ProcessMemoryReaderApi.VirtualQueryEx( m_hProcess, MemoryAddress, memInfo, System.Runtime.InteropServices.Marshal.SizeOf((memInfo)) ); return memInfo.State; }But its giving me the following runtime error:
Quote:
PInvokeStackImbalance was detected
Message: A call to PInvoke function 'MemoryEdit!MemoryEdit.ProcessMemoryReaderApi::VirtualQueryEx' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
I'm stumped as to how to fix this, I've been link chasing all over MSDN with no luck.
I don't know enough about C# to help resolve that runtime error, but my understanding is that C# is best used for building guis and not for exploring the nooks and crannies of the operating system. Like the AP said, C/C++ would be a better choice. You might consider using a DLL to isolate the low level stuff from the GUI.
VirtualQueryEx uses the standard calling convention (aka __stdcall).
I found this via google. Maybe it will help.
C# Signature:
[DllImport("kernel32.dll")]
static extern uint VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress,
out MEMORY_BASIC_INFORMATION lpBuffer, UIntPtr dwLength);
This article, Minesweeper, Behind the scenes, appears to do what you're trying to do.
VirtualQueryEx uses the standard calling convention (aka __stdcall).
I found this via google. Maybe it will help.
C# Signature:
[DllImport("kernel32.dll")]
static extern uint VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress,
out MEMORY_BASIC_INFORMATION lpBuffer, UIntPtr dwLength);
This article, Minesweeper, Behind the scenes, appears to do what you're trying to do.
Yea, I've looked into that thanks. I think the best method will be the use of a DLL written in C/C++ like you said. I've never done any DLL's before ... sounds, sorta ... laughable - that I'd be querying about a problem like this without even looking into DLL's but ... yea, all apart of the learning process. Suppose it will get easier when I get to Uni and I can speak face to face with someone who knows something about programming ... my high school teachers are hopeless.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement