ReadProcessMemory on a 64 bit proces always returns Error 299

Menna picture Menna · Nov 19, 2013 · Viewed 7.1k times · Source

I'm having some trouble with ReadProcessMemory My code is 64 bit I can read the memory of any 32 bit process , but ReadProcessMemory always fails with error code 299 (Partial read) returning 0 bytes read.

Done my research and most answers were relate to privilges , but I have Debugging token enabled and running as admin , The address i read the the ImageBase in the PE optional header

I tried to check the page status using VirtualQueryEx and got access denied!

Note : The code runs perfectly on any 32 bit process.

Any Ideas what maybe be causing this ?

HANDLE hProcess;
DWORD pid;
EnableDebugPriv();
pid=GetProcessByName("winmine.exe"); //32 bit apps work
//pid=GetProcessByName("notepad.exe"); //64 bit apps dont
hProcess = OpenProcess(PROCESS_ALL_ACCESS ,0, pid);
if(!hProcess)
{
    printf("failed to acquire handle , Error %d \n" , GetLastError());
    return FAILED;
}


//DEBUGGING
//DWORD address =   0x100000000; //64 notepad
DWORD address =  0x1000000; // 32 bit minsweeper
DWORD oldProtect=0;
printf("DEBUG pid %d - last err :%d \n" , GetProcessId(hProcess) , GetLastError() );
if(VirtualProtectEx(hProcess , (LPVOID)address,4096 /*pagesize for test*/ , PAGE_EXECUTE_READWRITE , &oldProtect))
{
    cout <<"vp done \n";
}
else cout << " vp err :" << GetLastError() << endl;
PMEMORY_BASIC_INFORMATION pmbi = new MEMORY_BASIC_INFORMATION;
if(VirtualQueryEx(hProcess,(LPVOID)address,pmbi,sizeof(MEMORY_BASIC_INFORMATION)))
{
    cout << "protection :" << pmbi->AllocationProtect << endl;
}
char value = 0;
SIZE_T * pbytes = new SIZE_T ;
ReadProcessMemory(hProcess,(LPCVOID)address ,&value,sizeof(value),pbytes);
cout << value << endl;
printf("Read status : %d ; bytes read %d  \n",GetLastError() , *pbytes );
CloseHandle(hProcess);

Answer

Frerich Raabe picture Frerich Raabe · Nov 19, 2013

Just using MEMORY_BASIC_INFORMATION like that is incorrect. You should use either use MEMORY_BASIC_INFORMATION32 or MEMORY_BASIC_INFORMATION64 (as described in the remarks section in the MSDN) depending on whether the remote process is 32bit or 64bit.

The size and layout of the structure will be different depending on whether it's a 32bit or a 64bit process. By just using MEMORY_BASIC_INFORMATION you expect that the remote process uses whatever layout your current process uses.

In order to test whether the remote process is 32bit or 64bit you can use the IsWow64Process function like this:

bool is64BitProcess(HANDLE hProcess)
{
    const bool is64BitOS = sizeof(void *) == 8 || IsWow64Process(GetCurrentProcess());
    return is64BitOS ? IsWow64Process(hProcess)
                     : false;
}