MemProcFS icon indicating copy to clipboard operation
MemProcFS copied to clipboard

How to get similar results to ReadProcessMemory function?

Open FlashPlayer13 opened this issue 4 years ago • 15 comments

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?

FlashPlayer13 avatar Nov 02 '21 06:11 FlashPlayer13

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.

ufrisk avatar Nov 02 '21 18:11 ufrisk

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.

FlashPlayer13 avatar Nov 02 '21 19:11 FlashPlayer13

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.

ufrisk avatar Nov 02 '21 20:11 ufrisk

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?)

FlashPlayer13 avatar Nov 03 '21 06:11 FlashPlayer13

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?

ufrisk avatar Nov 03 '21 21:11 ufrisk

Ok, i got it. Thank you! I am using Win10 Pro 21H1.

FlashPlayer13 avatar Nov 04 '21 03:11 FlashPlayer13

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.

FlashPlayer13 avatar Nov 05 '21 09:11 FlashPlayer13

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.

ufrisk avatar Nov 06 '21 21:11 ufrisk

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?

FlashPlayer13 avatar Nov 10 '21 05:11 FlashPlayer13

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.

ufrisk avatar Nov 10 '21 22:11 ufrisk

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

Briland5 avatar Nov 27 '21 18:11 Briland5

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.

ufrisk avatar Nov 28 '21 22:11 ufrisk

Any update on this?

Briland5 avatar Jan 01 '22 17:01 Briland5

Up?)

FlashPlayer13 avatar Apr 19 '22 07:04 FlashPlayer13

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.

ufrisk avatar Apr 19 '22 21:04 ufrisk

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.

ufrisk avatar Apr 15 '23 18:04 ufrisk