windows - QueryWorkingSet 在其结果中包含无效页面

标签 windows winapi memory-management x86 access-violation

我目前使用的是 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/

相关文章:

java - 使用 Cmake 在 Windows x64 上构建 OpenCV for Java

c - 使用 C 查询自定义 DNS 服务器

c++ - 从 ListView 控件丢失 WM_NOTIFY

c++ - MessageBox() 在触摸屏上的 WM_ACTIVATEAPP 中没有响应

objective-c - ARC 子类上的 super dealloc

c++ - ReadFile Timeout 字节间延迟时间

windows - Windows Phone 中的 Azure Active Directory 身份验证失败

database - 使用不同操作系统将项目从开发部署到生产的良好做法?

c++ - MMGR 问题、代码使用和线程安全

c - malloc 错误处理