我正在尝试编写一个函数,可以通过一个进程的内存。我注意到ReadProcessMemory会在权限设置为PAGE_NOACCESS或PAGE_GUARD的区域上失败。我决定使用VirtualProtectEx临时更改这些页面上的权限,以便能够读取它们。在大多数情况下,这似乎都是可行的,但是总会有几种情况下,VirtualProtectEx会在ERROR_INVALID_PARAMETER上失败。我对所有参数进行了三次检查,它们似乎是正确的,我甚至添加了代码,在失败时再次调用VirtualQueryEx,以确保传递的参数仍然有效。是什么导致了这一切,我怎么才能摆脱它呢?我在下面添加了一些最小的(尽可能小的)代码来重现这个问题。
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;
}
发布于 2021-11-20 19:07:52
响应GuidedHacking为未来的人寻找正确的信息。
仍然可能会返回具有执行/读取保护的页面,并且需要更改为PAGE_EXECUTE_READWRITE进行写入。代码也错了。它有效地将MEM_COMMIT与受保护相比较。显然,没有人扫描一个进程来寻找有用的内存。
更正和简化:
if (state == MEM_COMMIT && !(protect & (PAGE_NOACCESS|PAGE_GUARD))
https://stackoverflow.com/questions/60857829
复制相似问题