3

I try to read all commited pages of a process (Win7-64). On most pages it works but it fails for a few pages. I cannot explain why. Here is my test programme (compiled x32, tested in Win7-64):

#include <windows.h>

void main()
{
    HANDLE hProc = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,FALSE,GetCurrentProcessId());

    SYSTEM_INFO si;
    ZeroMemory(&si,sizeof(SYSTEM_INFO));
    GetSystemInfo(&si);

    char* buf = new char[si.dwPageSize];

    for (unsigned i = 0; i < 0x7fff0; i++)
    {
        void* baseOffs = (void*) (i * si.dwPageSize);
        MEMORY_BASIC_INFORMATION mbi;
        ZeroMemory(&mbi,sizeof(MEMORY_BASIC_INFORMATION));

        if (VirtualQueryEx(hProc, baseOffs, &mbi, sizeof(MEMORY_BASIC_INFORMATION)) == 0)
        {
            MessageBox(NULL, TEXT("VirtualQueryEx failed"),TEXT(""),MB_OK);
        }

        if (mbi.State == MEM_COMMIT)
        {
            SIZE_T numByteWritten = 0;
            if(ReadProcessMemory(hProc, baseOffs,buf,si.dwPageSize,&numByteWritten) == FALSE)
                OutputDebugString(TEXT("bad\n")); //GetLastError()==ERROR_PARTIALLY_READ; numByteWritten == 0;
            else
                OutputDebugString(TEXT("good\n"));

        }
    }

    delete[] buf;
}

I tired to look into the MEMORY_BASIC_INFORMATION for the failing pages but I didn't find anything strange there. Also the number of failing pages varies from run to run (in average about 5). WHat prevents me from reading these pages? Do I need to adjust some privilges in the process token?

Arno Nühm
  • 93
  • 1
  • 9
  • I don't know, but what would happen if the target process unmapped the page while ReadProcessMemory was trying to copy it? After you get this error, is the page still committed? – arx Aug 25 '12 at 18:47
  • yes, if I run VirtualQuery dircetly after ReadProcessMemory failed it still returns State==MEM_COMMIT for that page. I also made another test with the whole program twice in a loop and in both runs the same pages fail. However I get different pages (also a different number) when I run the process multiple times. – Arno Nühm Aug 26 '12 at 12:39
  • It is a common error code on a 64-bit operating system. No idea why, I suspect the wow64 emulator has something to do with it. – Hans Passant Aug 27 '12 at 13:42
  • what happens if you explicitly set the page to readable via `VirtualProtect`? looking at how your program runs, you might be accessing pages that aren't resident in memory, and `ReadProcessMemory` doesn't trigger them to be paged in, try checking the memory info type of the failed pages. – Necrolis Aug 27 '12 at 14:04
  • FYI: "ERROR_PARTIAL_COPY 299 (0x12B) Only part of a ReadProcessMemory or WriteProcessMemory request was completed" – Ben Voigt Jul 03 '13 at 21:29

2 Answers2

6

A little bit of debugging and something interesting is identified: all pages that fail have protection bit PAGE_GUARD set (see MSDN doc). As I interpret the docs, it is by design that you cannot read these pages with ReadProcessMemory.

if(ReadProcessMemory(hProc, baseOffs,buf,si.dwPageSize,&numByteWritten) == FALSE) {
    assert(mbi.Protect & 0x100);
    OutputDebugString(TEXT("bad\n")); //GetLastError()==ERROR_PARTIALLY_READ; numByteWritten == 0; 
}
else {
    assert(!(mbi.Protect & 0x100));
    OutputDebugString(TEXT("good\n")); 
}
Werner Henze
  • 16,404
  • 12
  • 44
  • 69
  • 2
    However I thought, I have carfully checked for that, you are completely right. I added VirtualProtectEx to temporarely remove the flag and everything is fine. – Arno Nühm Aug 27 '12 at 15:09
  • How did you called VirtualProtectEx? I tried to overwrite it too for another process, but it doesn't change the flag. It says, that the old flag is always 0x1 (PAGE_NOACCESS). – StanE Oct 27 '21 at 15:56
3

The page size on 32-bit Windows is not the same as the page size on 64-bit Windows. Therefore, the page size is a per-process value. The page size for your process is not necessarily the same as the page size of the process you are reading from. Use the RegionSize member of the MEMORY_BASIC_INFORMATION instead. That is the actual size of the affected region.

Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
  • Thanks for that hint. I read about the difference of GetSystemInfo() and GetNativeSystemInfo(). However in my OS both sizes are the same. RegionSize usually contains multiple pages. But you are right, that it makes sense to process larger blocks at once. – Arno Nühm Aug 27 '12 at 19:19