设置PAGE_NOACCESS& Windows上的内存区域上的VirtualLock

时间:2018-02-13 12:55:32

标签: windows segmentation-fault kernel signals virtual-memory

在VirtualLock的documentation page上有以下注释:

typedef enum {
MGL_TRIANGLES,
MGL_QUADS
} MGLpoly_mode;

MGLpoly_mode mode; //mode 1

void mglBegin(MGLpoly_mode mode)
{
mode = mode;  //mode 1 = input parameter mode
}

有什么方法可以解决这个问题吗?这个专长可以在unix系统上实现,但是在windows上存在这种限制。目标是防止将内存分页到磁盘,同时防止对它进行任何访问。

1 个答案:

答案 0 :(得分:1)

当我们使用PAGE_NOACCESSPAGE_GUARD|*在锁定的内存区域调用ZwProtectVirtualMemory时,返回的状态为STATUS_WAS_UNLOCKED

  

{页面已解锁}

     

锁定页面的页面保护已更改为   “无权访问”,并且该页面已从内存和   过程。

此处重要的调用恰好是ZwProtectVirtualMemory而不是VirtualProtect[Ex],因为此win32 api不能区分不同的NT_SUCCESS值,只需对其中的任何一个返回 true 并删除原始状态。但是STATUS_WAS_UNLOCKED也被定义为0x40000017LNT_SUCCESS的值-因此,VirtualProtect[Ex]在这种情况下丢失了重要信息。

因此将PAGE_NOACCESSPAGE_GUARD|*设置为从内存中解锁页的副作用

但是在页面上设置PAGE_NOACCESS有什么意义?为防止外部有人从页面读取数据?但是如果此代理有权访问您的进程-他也可以并删除此PAGE_NOACCESS,如果没有访问权-则不需要执行保护。在两种情况下-无意义的集PAGE_NOACCESS-是否需要或可以将其删除。

防止页面交换到页面文件是有道理的,因为从理论上讲,可以在系统关闭后(如果此时在此位置)从其中读取它,但设置为No Access(从 PTE中删除有效位) 进入此页面)

只需测试代码

void PrintNtStatus(PCSTR prefix, NTSTATUS status)
{
    static HMODULE hmod = 0;

    if (!hmod)
    {
        hmod = GetModuleHandle(L"ntdll");
    }

    PWSTR msg;
    if (FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_ALLOCATE_BUFFER, hmod, status, 0, (PWSTR)&msg, 0, 0))
    {
        DbgPrint("%s = %x(%S)\n", prefix, status, msg);
        LocalFree(msg);
    }
}

void LockTest()
{
    if (PVOID pv = VirtualAlloc(0, 1, MEM_COMMIT, PAGE_READWRITE))
    {
        if (VirtualLock(pv, 1))
        {
            ULONG op;
            SIZE_T size = 1;
            PVOID BaseAddress = pv;
            //STATUS_WAS_UNLOCKED
            PrintNtStatus("ProtectVirtualMemory", 
                ZwProtectVirtualMemory(NtCurrentProcess(), &BaseAddress, &size, PAGE_NOACCESS, &op));
            PrintNtStatus("ProtectVirtualMemory", 
                ZwProtectVirtualMemory(NtCurrentProcess(), &BaseAddress, &size, op, &op));
            PrintNtStatus("VirtualUnlock", VirtualUnlock(pv, 1) ? STATUS_SUCCESS : RtlGetLastNtStatus());
        }
        VirtualFree(pv, 0, MEM_RELEASE);
    }
}