我目前使用的是 64 位 Windows 7,我正在使用 Windows 7。我正在玩一些 PSAPI (Process Status API) 函数来了解更多关于 Windows 如何管理内存的信息。
但是,我注意到 QueryWorkingSet
包括我无法阅读的条目(例如第 0 页,您无法阅读 0x00000000
)。在 64 位上尝试时,很明显为什么会出现这种情况:QueryWorkingSet
在 32 位上存在错误,因为地址被截断(因此出现多个第 0 页条目)。
不过,QueryWorkingSet
在 64 位上返回的一些条目也不可访问。 为什么这个明显不可访问的内存显示为可访问?这是 QueryWorkingSet
中的另一个错误吗? 此外,为什么没有任何加载的模块显示在结果中?他们不是工作集的一部分吗?是explicitly stated on MSDN他们是……
这是一个小示例程序,它使用 SEH 尝试读取页面,并在页面不可读时报告页面(而 QueryWorkingSet
告诉我它是):
#include <windows.h>
#include <psapi.h>
#include <stdio.h>
char z;
int main(int argc, char **argv) {
unsigned int counter;
HANDLE thisProcess = GetCurrentProcess();
SYSTEM_INFO si;
PSAPI_WORKING_SET_INFORMATION wsi_1, *wsi;
DWORD wsi_size;
GetSystemInfo(&si);
wsi_1.NumberOfEntries = 0;
QueryWorkingSet(thisProcess, (LPVOID)&wsi_1, sizeof(wsi));
#if !defined(_WIN64)
wsi_1.NumberOfEntries--;
#endif
wsi_size = sizeof(PSAPI_WORKING_SET_INFORMATION)
+ sizeof(PSAPI_WORKING_SET_BLOCK) * wsi_1.NumberOfEntries;
wsi = (PSAPI_WORKING_SET_INFORMATION*)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, wsi_size);
if (!QueryWorkingSet(thisProcess, (LPVOID)wsi, wsi_size)) {
printf("# Second QueryWorkingSet failed: %lu\n"
, GetLastError());
return 1;
}
for (counter = 0; counter < wsi->NumberOfEntries; counter++) {
unsigned long long page = (unsigned long long)wsi->WorkingSetInfo[counter].VirtualPage;
DWORD protection = (DWORD)wsi->WorkingSetInfo[counter].Protection;
__try {
if (*(char*)(page * si.dwPageSize) || TRUE) {
z = (protection & 5) ? '-' : 'T';
}
} __except(GetExceptionCode() == STATUS_ACCESS_VIOLATION) {
z = (protection & 5) ? 'F' : '-';
}
if (z == 'F') {
printf("%p %p : %c%c%c%c%c %c\n"
, (LPVOID)(page * si.dwPageSize)
, (LPVOID)((page + 1) * si.dwPageSize)
, protection & 16 ? 'G' : '-'
, protection & 8 ? 'V' : '-'
, protection & 4 ? 'w' : '-'
, protection & 2 ? 'x' : '-'
, protection & 1 ? 'r' : '-'
, z
);
}
}
return 0;
}
32 位版本提供以下输出:
7DBED000 7DBEE000 : --w-- F
7DBEE000 7DBEF000 : --w-- F
7DC00000 7DC01000 : --w-- F
80008000 80009000 : --w-- F
01080000 01081000 : --w-- F
01000000 01001000 : --w-- F
00000000 00001000 : --w-- F
7DA00000 7DA01000 : --w-- F
40001000 40002000 : --w-- F
003F7000 003F8000 : --w-- F
003FF000 00400000 : --w-- F
003BA000 003BB000 : --w-- F
00001000 00002000 : --w-- F
003B9000 003BA000 : --w-- F
40000000 40001000 : --w-- F
00006000 00007000 : --w-- F
00002000 00003000 : --w-- F
00000000 00001000 : --w-- F
0039A000 0039B000 : --w-- F
003A6000 003A7000 : --w-- F
003A8000 003A9000 : --w-- F
003AC000 003AD000 : --w-- F
00003000 00004000 : --w-- F
64 位版本给出了这个:
FFFFF6FB7DBED000 FFFFF6FB7DBEE000 : --w-- F
FFFFF6FB7DBEE000 FFFFF6FB7DBEF000 : --w-- F
FFFFF6FB7DC00000 FFFFF6FB7DC01000 : --w-- F
FFFFF6FB80008000 FFFFF6FB80009000 : --w-- F
FFFFF70001080000 FFFFF70001081000 : --w-- F
FFFFF70000000000 FFFFF70000001000 : --w-- F
FFFFF70001000000 FFFFF70001001000 : --w-- F
FFFFF7000107F000 FFFFF70001080000 : --w-- F
FFFFF6FB7DA0F000 FFFFF6FB7DA10000 : --w-- F
FFFFF6FB41FFF000 FFFFF6FB42000000 : --w-- F
FFFFF683FFFFF000 FFFFF68400000000 : --w-- F
FFFFF6FB40001000 FFFFF6FB40002000 : --w-- F
FFFFF680003FF000 FFFFF68000400000 : --w-- F
FFFFF6FB7DA00000 FFFFF6FB7DA01000 : --w-- F
FFFFF6FB40005000 FFFFF6FB40006000 : --w-- F
FFFFF68000A00000 FFFFF68000A01000 : --w-- F
FFFFF6FB40000000 FFFFF6FB40001000 : --w-- F
FFFFF68000000000 FFFFF68000001000 : --w-- F
FFFFF680003B9000 FFFFF680003BA000 : --w-- F
FFFFF68000001000 FFFFF68000002000 : --w-- F
FFFFF680003B6000 FFFFF680003B7000 : --w-- F
FFFFF680003B7000 FFFFF680003B8000 : --w-- F
FFFFF683FF7FA000 FFFFF683FF7FB000 : --w-- F
FFFFF683FF7EC000 FFFFF683FF7ED000 : --w-- F
FFFFF6FB41FFB000 FFFFF6FB41FFC000 : --w-- F
FFFFF680003F7000 FFFFF680003F8000 : --w-- F
FFFFF680003BA000 FFFFF680003BB000 : --w-- F
最佳答案
我假设这是由于 native API 的缺陷造成的。 K32QueryWorkingSet
非常天真地使用了 NtQueryVirtualMemory
,假设它可以将结果原样传递给调用者。根据this article ,违规结果涉及页表和工作集条目,它们可以从内核空间完全读取,但不能直接从用户空间访问。
一个快速修复方法是清理结果,以便在 MmSystemRangeStart
下面找到的地址被认为是有效的。该值只能在内核模式下读取,因此必须为用户模式应用程序“猜测”。对于 Windows 7 64 位,它是 0xFFFF080000000000
。对于 32 位版本有点棘手(由于 4GB 调整),但我不确定错误是否真的发生在那里。
关于windows - QueryWorkingSet 在其结果中包含无效页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8285506/