How to get similar results to ReadProcessMemory function?
Hi,
I am trying to find out how with MemProcFS get similar results to OpenProcess -> VirtualQueryEx -> ReadProcessMemory WinApi bundle. So i have a process and i can dump its memory with next C# code (using WinApi):
public static List<MemoryChunk> GetMemoryDump(Process process)
{
if (process == Process.GetCurrentProcess())
throw new Exception("Cannot dump the memory of this process");
GetSystemInfo(out var systemInfo);
var minimumAddress = systemInfo.minimumApplicationAddress;
var maximumAddress = systemInfo.maximumApplicationAddress;
var processHandle = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryRead, false, process.Id);
if (processHandle == IntPtr.Zero)
throw new Exception("Cannot get a handle to process");
var memoryChunkCollection = new List<MemoryChunk>();
while (minimumAddress.ToInt64() < maximumAddress.ToInt64())
{
VirtualQueryEx(processHandle, minimumAddress, out var memoryInformation, (uint) Marshal.SizeOf(typeof (MEMORY_BASIC_INFORMATION)));
// check if this chunk is accessible
if (memoryInformation.Protect == AllocationProtectEnum.PAGE_READWRITE && memoryInformation.State == StateEnum.MEM_COMMIT)
{
var byteArray = new byte[memoryInformation.RegionSize.ToInt64()];
ReadProcessMemory(processHandle, memoryInformation.BaseAddress, byteArray, memoryInformation.RegionSize.ToInt32(), out _);
var memoryChunk = new MemoryChunk();
memoryChunk.MemoryInformation = memoryInformation;
memoryChunk.ByteArray = byteArray;
memoryChunkCollection.Add(memoryChunk);
}
// move to the next chunk
try
{
minimumAddress = new IntPtr(minimumAddress.ToInt64() + memoryInformation.RegionSize.ToInt64());
}
catch (OverflowException)
{
break;
}
}
return memoryChunkCollection;
}
There is nothing interesting with this code, i just posted it for clarification.
Next i am trying to achive same results (same virtual memory data) with MemProcFS (using pmem driver):
LeechCoreWrap.vmm.Initialize("-printf", "-v", "-device", "pmem");
LeechCoreWrap.vmm.InitializePlugins();
LeechCoreWrap.vmm.PidGetFromName("MyProcess.exe", out var dwProcessPID);
LeechCoreWrap.vmm.MAP_VADENTRY[] mVad = LeechCoreWrap.vmm.Map_GetVad(dwProcessPID);
LeechCoreWrap.MEM_SCATTER[] MEMsPhysical = LeechCoreWrap.vmm.MemReadScatter(dwProcessPID, 0, someAddress); // ??? what address
Problem is that i can't find correspondence between addresses in memoryInformation structs and MAP_VADENTRY. In my case in first scenario (with WinApi) addresses start from 0x0000000000010000, but in MemProcFS results first vaStart is 0x10000000. Also in WinApi result bytes sum around x2 smaller that in MemProcFS (if i sum cbSize). Maybe it is related that in WinApi approach i am using filter for protection and state of memory chunks, but even with this knowledge i can't find proper way to get same results for two approaches.
Looks like i am comparing wrong things. Need some help to understand what i am doing wrong and how to achive same results in process memory dumping?
Unfortunately there is no absolute direct 1:1 mapping. The VADs are the way to go; but the VADs may contain a lot of unallocated non-committed memory as well.
If the VAD is small enough read the whole anyway; VMMDLL_MemReadEx with flag VMMDLL_FLAG_ZEROPAD_ON_FAIL is probably most convenient.
If using pmem driver everything is so fast so no real need to use the ReadScatter function to reduce the number of slow FPGA IO accesses.
If the VAD contains a larger region you can check the state of individual memory pages by querying VMMDLL_Map_GetVadEx - it's a bit complicated; but it basically tells whether the page is allocated or not and which kind of page it is and how it's backed in memory. You can check out the memmap/vad-v folder in the file system to see a bit how it looks like and what it does.
I wish I had a better answer; but it is how it is :\
As a side note I do have "minidump" file generation as well; but it's not well suited for live memory you wish to write to unfortunately. In that case your current approach is probably the way to go.
Thank you for answer. Any ideas, why WinApi results starts from smaller address than MemProcFS (0x0000000000010000 vs 0x10000000)? It was clear for me that MemProc extracts more memory than WinApi due to unallocated things, but in my case for some reason fist vad starts with bigger address than first winApi chunk of memory.
Please let me check into this. It seems odd that the MemProcFS value is exactly 0x1000 times larger than your value (i.e. one page). There may be some extra page bit shifts in my code. Please let me look into this. Probably this weekend.
Sure, thanks.
About that "VADs may contain a lot of unallocated non-committed memory as well".
In my WinApi example we can see this type of filtering:
if (memoryInformation.Protect == AllocationProtectEnum.PAGE_READWRITE && memoryInformation.State == StateEnum.MEM_COMMIT)
Is it enought to check vad.MemCommit == True in MAP_VADENTRY for similar State check in WinApi?
And for memoryInformation.Protect == AllocationProtectEnum.PAGE_READWRITE check i can use vad.Protection field in MAP_VADENTRY? Where can i find appropriate value of Protection field to AllocationProtectEnum in WinApi? Or just empirical?)
I haven't modeled this API after the WinAPI. I more modeled it after what exists in the VAD data structures in the kernel. It's similar but not exactly the same.
Also things have been changing around this (some bits in bitfields have moved a few positions and such) between WIndows versions. I have tried to make sure it should work amongst all of them; but I may have missed something somewhere so I'm not 100% sure it's bug free.
I have to look into the starting position difference in the weekend.
Which build number / version of Windows are you running this on?
Ok, i got it. Thank you! I am using Win10 Pro 21H1.
Have one more question. Is it possible to get process window handles through MemProcFS? And as result - extract window title and position? I found VMMDLL_Map_GetHandle function, but didn't find how to get window handle with it.
Window handles aren't supported right now; but it would be a really good idea to add them. I think I should place this on my todo list :)
I don't think they show up in the "handles" list (I'm not certain tho). Maybe they would exist as an object somehow M:\sys\objects - but I'd need to look into this.
I haven't modeled this API after the WinAPI. I more modeled it after what exists in the VAD data structures in the kernel. It's similar but not exactly the same.
Also things have been changing around this (some bits in bitfields have moved a few positions and such) between WIndows versions. I have tried to make sure it should work amongst all of them; but I may have missed something somewhere so I'm not 100% sure it's bug free.
I have to look into the starting position difference in the weekend.
Which build number / version of Windows are you running this on?
Hi,
Did you have a chance to check this issue?
sadly not, I got caught up coding a new subsystem that I hope to add soon; also I'll be away this weekend. I'll try to look into it next week.
Any update on this? I've been roughly trying to achieve the same functionality as FlashPlayer13.
I (ignorantly) expected all of the information returned by VirtualQueryEx to be a subset of what is stored in the VAD. I am getting rather different results from a local VirtualQueryEx and VMM_DLL_Map_GetVadU.
I am also using Win10 Pro 21H1 (build 19043. 1348)
Here are my results from a local call to VirtualQueryEx
Getting handle for pid 5736 'counter.exe'
BaseAddress AllocationBase RegionSize AProtect Protect Type State
0000000000000000 0000000000000000 65536 00000000 00000001 00000000 00010000
0000000000080000 0000000000080000 4096 00000002 00000002 00040000 00001000
0000000000088000 0000000000000000 32768 00000000 00000001 00000000 00010000
00000000000c8000 0000000000000000 32768 00000000 00000001 00000000 00010000
0000000000108000 0000000000100000 53248 00000004 00000004 00020000 00001000
0000000000170000 0000000000100000 589824 00000004 00000000 00020000 00002000
00000000005f0000 0000000000420000 172032 00000004 00000000 00020000 00002000
0000000000740000 0000000000000000 6160384 00000000 00000001 00000000 00010000
0000000003640000 0000000000000000 1574961152 00000000 00000001 00000000 00010000
00000000f2640000 0000000000000000 193265664 00000000 00000001 00000000 00010000
And my results from VMM_DLL_Map_GetVadU (with my attempt to format them like Virtual Query below)
leechOpenProcess: dwDesiredAccess=1fffff dwProcessId=5736
# ADRESS_RANGE KERNEL_ADDR TYPE PROT INFO
============================================================================
0000 0000000000010000-000000000001ffff [ffffe68c22c49200] Pf --rw-- HEAP-01
0001 0000000000020000-0000000000020fff [ffffe68c22c4da80] Pf --r---
0002 0000000000030000-000000000004cfff [ffffe68c22c48080] Pf --r---
0003 0000000000050000-0000000000053fff [ffffe68c22b52760] Pf --r---
0004 0000000000060000-0000000000061fff [ffffe68c22fd0800] p-rw--
0005 0000000000070000-0000000000070fff [ffffe68c22c4e520] Pf --r---
0006 0000000000080000-0000000000080fff [ffffe68c22c4dc60] Pf --r---
0007 0000000000090000-00000000000c1fff [ffffe68c22fd15c0] p-rw--
0008 00000000000d0000-00000000000d7fff [ffffe68c22b59060] Pf --r---
0009 0000000000100000-00000000001fffff [ffffe68c22fd0760] p-rw-- HEAP-02
000a 0000000000200000-00000000003fffff [ffffe68c22fccd90] p-rw--
000b 0000000000400000-000000000041afff [ffffe68c22c466e0] Image ---wxc \Dev\simple counter\counter.exe
000c 0000000000420000-000000000061ffff [ffffe68c22fceeb0] p-rw--
000d 0000000000620000-00000000006e8fff [ffffe68c22c486c0] File --r--- \Windows\System32\locale.nls
000e 0000000000d20000-0000000000d2ffff [ffffe68c22fcb0d0] p-rw-- HEAP-00
000f 0000000000d30000-0000000000d61fff [ffffe68c22fd1390] p-rw--
0010 0000000000d70000-0000000000f6ffff [ffffe68c22b4fe20] Pf --r---
0011 0000000000f70000-00000000010f0fff [ffffe68c19a94560] Pf --r---
0012 0000000001100000-0000000002500fff [ffffe68c19a947e0] Pf --r---
0013 0000000002510000-000000000260ffff [ffffe68c22fd12f0] p-rw-- HEAP-40
0014 0000000061440000-000000006145afff [ffffe68c22c4c540] Image ---wxc \Program Files\mingw-w64\x86_64-8.1.0-win32-seh-rt_v6-rev0\mingw64\bin\libgcc_s_seh-1.dll
0015 000000006fc40000-000000006fda3fff [ffffe68c22c4d260] Image ---wxc \Program Files\mingw-w64\x86_64-8.1.0-win32-seh-rt_v6-rev0\mingw64\bin\libstdc++-6.dll
0016 000000007ffe0000-000000007ffe0fff [ffffe68c22fcc930] p-r---
0017 000000007ffed000-000000007ffedfff [ffffe68c22fcc070] p-r---
0018 00007ff4fde90000-00007ff4fdf8ffff [ffffe68c22c48a80] Pf --r---
0019 00007ff4fdf90000-00007ff5fdfaffff [ffffe68c22fd0df0] p-rw--
001a 00007ff5fdfb0000-00007ff5fffb0fff [ffffe68c22fd0620] p-rw--
001b 00007ff5fffc0000-00007ff5fffc0fff [ffffe68c22c45a60] Pf --r---
001c 00007ff5fffd0000-00007ff5ffff2fff [ffffe68c22c46c80] Pf --r---
001d 00007ffed6870000-00007ffed696ffff [ffffe68c22c4e020] Image ---wxc \Windows\System32\ucrtbase.dll
001e 00007ffed6ca0000-00007ffed6cc1fff [ffffe68c22c4d300] Image ---wxc \Windows\System32\win32u.dll
001f 00007ffed6cd0000-00007ffed6f97fff [ffffe68c22c490c0] Image ---wxc \Windows\System32\KernelBase.dll
0020 00007ffed6ff0000-00007ffed70fafff [ffffe68c22c4dda0] Image ---wxc \Windows\System32\gdi32full.dll
0021 00007ffed7100000-00007ffed719cfff [ffffe68c22c4de40] Image ---wxc \Windows\System32\msvcp_win.dll
0022 00007ffed71a0000-00007ffed71cafff [ffffe68c22c4dee0] Image ---wxc \Windows\System32\gdi32.dll
0023 00007ffed7640000-00007ffed766ffff [ffffe68c22c4f100] Image ---wxc \Windows\System32\imm32.dll
0024 00007ffed8250000-00007ffed82edfff [ffffe68c22c460a0] Image ---wxc \Windows\System32\msvcrt.dll
0025 00007ffed88b0000-00007ffed8a50fff [ffffe68c22c4db20] Image ---wxc \Windows\System32\user32.dll
0026 00007ffed8ed0000-00007ffed8f8dfff [ffffe68c22c493e0] Image ---wxc \Windows\System32\kernel32.dll
0027 00007ffed9150000-00007ffed9344fff [ffffe68c22c46be0] Image ---wxc \Windows\System32\ntdll.dll
BaseAddress AllocationBase RegionSize AProtect Protect Type State
0000000000000000 0000000000000000 65536 00000000 00000001 00000000 00010000
0000000000010000 0000000000010000 65536 00000004 00000004 00040000 00002000
0000000000020000 0000000000020000 4096 00000002 00000002 00040000 00002000
0000000000021000 0000000000000000 61440 00000000 00000001 00000000 00010000
0000000000030000 0000000000030000 118784 00000002 00000002 00040000 00002000
000000000004d000 0000000000000000 12288 00000000 00000001 00000000 00010000
0000000000050000 0000000000050000 16384 00000002 00000002 00040000 00002000
0000000000054000 0000000000000000 49152 00000000 00000001 00000000 00010000
0000000000060000 0000000000060000 8192 00000004 00000004 00020000 00001000
0000000000062000 0000000000000000 57344 00000000 00000001 00000000 00010000
0000000000070000 0000000000070000 4096 00000002 00000002 00040000 00002000
0000000000071000 0000000000000000 61440 00000000 00000001 00000000 00010000
0000000000080000 0000000000080000 4096 00000002 00000002 00040000 00002000
0000000000081000 0000000000000000 61440 00000000 00000001 00000000 00010000
0000000000090000 0000000000090000 204800 00000004 00000004 00020000 00002000
00000000000c2000 0000000000000000 57344 00000000 00000001 00000000 00010000
00000000000d0000 00000000000d0000 32768 00000002 00000002 00040000 00002000
00000000000d8000 0000000000000000 163840 00000000 00000001 00000000 00010000
0000000000100000 0000000000100000 1159168 00000004 00000004 00020000 00002000
0000000000200000 0000000000200000 2097152 00000004 00000004 00020000 00002000
0000000000400000 0000000000400000 110592 00000080 00000080 01000000 00002000
000000000041b000 0000000000000000 20480 00000000 00000001 00000000 00010000
0000000000420000 0000000000420000 2097152 00000004 00000004 00020000 00002000
0000000000620000 0000000000620000 823296 00000002 00000002 00040000 00002000
00000000006e9000 0000000000000000 6516736 00000000 00000001 00000000 00010000
0000000000d20000 0000000000d20000 2162688 00000004 00000004 00020000 00002000
0000000000d70000 0000000000d70000 23072768 00000002 00000002 00040000 00002000
0000000001100000 0000000001100000 20975616 00000002 00000002 00040000 00002000
0000000002501000 0000000000000000 61440 00000000 00000001 00000000 00010000
0000000002510000 0000000002510000 1048576 00000004 00000004 00020000 00002000
0000000002610000 0000000000000000 1591934976 00000000 00000001 00000000 00010000
0000000061440000 0000000061440000 110592 00000080 00000080 01000000 00002000
000000006145b000 0000000000000000 243159040 00000000 00000001 00000000 00010000
000000006fc40000 000000006fc40000 1458176 00000080 00000080 01000000 00002000
000000006fda4000 0000000000000000 270778368 00000000 00000001 00000000 00010000
000000007ffe0000 000000007ffe0000 4096 00000002 00000002 00020000 00001000
000000007ffe1000 0000000000000000 49152 00000000 00000001 00000000 00010000
000000007ffed000 000000007ffed000 4096 00000002 00000002 00020000 00001000
000000007ffee000 0000000000000000 140688061243392 00000000 00000001 00000000 00010000
00007ff4fde90000 00007ff4fde90000 1048576 00000002 00000002 00040000 00002000
00007ff4fdf90000 00007ff4fdf90000 4295102464 00000004 00000004 00020000 00002000
00007ff5fdfb0000 00007ff5fdfb0000 33558528 00000004 00000004 00020000 00002000
00007ff5fffb1000 0000000000000000 61440 00000000 00000001 00000000 00010000
00007ff5fffc0000 00007ff5fffc0000 4096 00000002 00000002 00040000 00002000
00007ff5fffc1000 0000000000000000 61440 00000000 00000001 00000000 00010000
00007ff5fffd0000 00007ff5fffd0000 143360 00000002 00000002 00040000 00002000
00007ff5ffff3000 0000000000000000 37958963200 00000000 00000001 00000000 00010000
00007ffed6870000 00007ffed6870000 1048576 00000080 00000080 01000000 00002000
00007ffed6970000 0000000000000000 3342336 00000000 00000001 00000000 00010000
00007ffed6ca0000 00007ffed6ca0000 139264 00000080 00000080 01000000 00002000
00007ffed6cc2000 0000000000000000 57344 00000000 00000001 00000000 00010000
00007ffed6cd0000 00007ffed6cd0000 2916352 00000080 00000080 01000000 00002000
00007ffed6f98000 0000000000000000 360448 00000000 00000001 00000000 00010000
00007ffed6ff0000 00007ffed6ff0000 1093632 00000080 00000080 01000000 00002000
00007ffed70fb000 0000000000000000 20480 00000000 00000001 00000000 00010000
00007ffed7100000 00007ffed7100000 643072 00000080 00000080 01000000 00002000
00007ffed719d000 0000000000000000 12288 00000000 00000001 00000000 00010000
00007ffed71a0000 00007ffed71a0000 176128 00000080 00000080 01000000 00002000
00007ffed71cb000 0000000000000000 4673536 00000000 00000001 00000000 00010000
00007ffed7640000 00007ffed7640000 196608 00000080 00000080 01000000 00002000
00007ffed7670000 0000000000000000 12451840 00000000 00000001 00000000 00010000
00007ffed8250000 00007ffed8250000 647168 00000080 00000080 01000000 00002000
00007ffed82ee000 0000000000000000 6037504 00000000 00000001 00000000 00010000
00007ffed88b0000 00007ffed88b0000 1708032 00000080 00000080 01000000 00002000
00007ffed8a51000 0000000000000000 4714496 00000000 00000001 00000000 00010000
00007ffed8ed0000 00007ffed8ed0000 778240 00000080 00000080 01000000 00002000
I'm sorry, I haven't looked into this yet. I prioritized getting my new pool parsing feature finished and I've been busy elsewhere this weekend.
I'll try to look into it the coming week.
Any update on this?
Up?)
I think this would be pretty hard to get 1:1. For now the VAD map would be the closest thing. If checking the regions in the above example they are mostly the same.
I'm closing this issue due to old age. Like I mentioned in my last post the ranges would be pretty hard to get 1:1. For now the VAD map would be the closest thing. If checking the regions in the above example they are mostly the same.