Reputation: 83
I am trying to write a function that will can through a process' memory. I noticed that ReadProcessMemory would fail on regions with permissions set to PAGE_NOACCESS or PAGE_GUARD. I decided that I would use VirtualProtectEx to temporarily change the permissions on these pages so I would be able to read them. This seemed to work in most cases, but there would always be a few cases in which VirtualProtectEx would fail with ERROR_INVALID_PARAMETER. I triple-checked all the parameters and they seem to be correct and I even added code which would call VirtualQueryEx again on failure to ensure the parameters passed were still valid. What is causing this and how can I get around it? I've added some minimal (as minimal as I could get it) code below that reproduces the problem.
int protect_test(DWORD pid) {
HANDLE phandle;
struct _MEMORY_BASIC_INFORMATION mbi;
SIZE_T mbi_size = sizeof(struct _MEMORY_BASIC_INFORMATION);
DWORD state;
SIZE_T regionsize;
int bytes_retrieved;
void* lpAddress;
void* lpBaseAddress;
void* lpAddress2;
int error;
struct _SYSTEM_INFO lpSystemInfo;
DWORD pagesize;
DWORD protect;
DWORD newprotect;
DWORD lpflOldProtect;
DWORD lpExitCode = 0;
// get the page size
GetSystemInfo(&lpSystemInfo);
pagesize = lpSystemInfo.dwPageSize;
// get handle to process
if ((phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)) == NULL) {
return(-1);
}
// main loop
lpAddress = 0;
while (!((bytes_retrieved = VirtualQueryEx(phandle, lpAddress, &mbi, mbi_size)) == 0 && (error = GetLastError()) == ERROR_INVALID_PARAMETER)) {
// Check for error -2
if (GetExitCodeProcess(phandle, &lpExitCode) && lpExitCode != 259) {
// process was closed abruptly
return -2;
}
// handle VirtualQueryEx fail
if (bytes_retrieved == 0) {
lpBaseAddress = lpAddress;
lpAddress2 = (unsigned long long) lpAddress + pagesize;
lpAddress = lpAddress2;
continue;
}
// set variables so we don't have to refernce mbi directly
lpBaseAddress = mbi.BaseAddress;
regionsize = mbi.RegionSize;
lpAddress2 = (unsigned long long)lpBaseAddress + regionsize;
state = mbi.State;
protect = mbi.Protect;
if ( state == MEM_COMMIT && ((protect & PAGE_NOACCESS) || (protect & PAGE_GUARD)) ) {
// some debug print
//printf(" State: 0x%x Protection: 0x%x Regionsize: 0x%llx %p - %p\n", state, protect, regionsize, lpBaseAddress, (unsigned long long)lpAddress2 - 1);
// The problematic VirtualProtectEx call
newprotect = PAGE_EXECUTE_READWRITE;
if (VirtualProtectEx(phandle, lpBaseAddress, regionsize, newprotect, &lpflOldProtect) == NULL) {
printf(" Failed to change region's protection to 0x%x. Base address: 0x%p Errorcode: 0x%x\n", newprotect, lpBaseAddress, GetLastError());
printf(" VirtualQuery returns %d. The base address returned was 0x%o. The regionsize returned is 0x%llx\n", VirtualQueryEx(phandle, lpBaseAddress, &mbi, mbi_size), mbi.BaseAddress, mbi.RegionSize);
return(1);
}
// set things back
if (VirtualProtectEx(phandle, lpBaseAddress, regionsize, lpflOldProtect, &lpflOldProtect) == 0) {
printf(" Failed to change region's protection back to its previous state\n", pid);
}
}
// update lpAddress
lpAddress = lpAddress2;
}
return 0;
}
Upvotes: 2
Views: 4622
Reputation:
In response to GuidedHacking for future people looking for correct info.
Pages with execute/read protection may still be returned and will need to change to e.g. PAGE_EXECUTE_READWRITE for writing. The code is also wrong. It's effectively comparing MEM_COMMIT together with protected. Obviously not what anyone scanning a process for useful memory would want to do.
Corrected and simplified:
if (state == MEM_COMMIT && !(protect & (PAGE_NOACCESS|PAGE_GUARD))
Upvotes: 0
Reputation: 3923
You can't change that page's permissions.
Using
if ( state == MEM_COMMIT && ((protect & PAGE_NOACCESS) || (protect & PAGE_GUARD)) )
to filter out bad memory is all you need to do, you do not need to change permissions to pages with other states and protections. "Hidden data" in other page types would be EXTREMELY rare like a 0.000001% chance, not even worth considering unless you have a reason to suspect it in the case of working on some very advanced protection mechanism.
Upvotes: 0