在映射文件上调用 VirtualProtect

Posted

技术标签:

【中文标题】在映射文件上调用 VirtualProtect【英文标题】:Calling VirtualProtect on a mapped file 【发布时间】:2011-03-18 00:49:08 【问题描述】:

我正在使用 CreateFileMapping 和 MapViewOfFile 函数将文件映射到内存中。在某一点之后,我调用 VirtualProtect 将其保护从只读更改为读写。此调用失败,GetLastError 给出 ERROR_INVALID_PARAMETER。

这是我演示问题的代码的简化版本。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int main() 
    HANDLE fd, md;
    char *addr;
    DWORD old;
    BOOL ok;

    fd = CreateFile("filename", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    md = CreateFileMapping(fd, NULL, PAGE_READWRITE, 0, 100, NULL);
    addr = MapViewOfFile(md, FILE_MAP_READ, 0, 0, 100);
    ok = VirtualProtect(addr, 100, PAGE_READWRITE, &old);
    if (!ok) 
        // we fall into this if block
        DWORD err = GetLastError();
        // this outputs "error protecting: 87"
        printf("error protecting: %u\n", err);
        return 1;
    
    UnmapViewOfFile(addr);
    CloseHandle(md);
    CloseHandle(fd);
    return 0;

我在这里做错了什么?我是否不允许在包含映射文件的区域上调用 VirtualProtect?

【问题讨论】:

之前的函数是否返回了预期值?我意识到您只发布了一个 sn-p ...但请确保您测试来自 MapViewOfFile、CreateFileMapping、CreateFile、...的 ALL 返回值... 是的,我确信其他功能没有失败。为简单起见,我省略了其他错误检查。 【参考方案1】:

首先使用 FILE_MAP_READ | 创建视图FILE_MAP_WRITE 并使用 PAGE_READONLY 进行保护。现在您可以轻松地稍后将其设为 PAGE_READWRITE:

addr = MapViewOfFile(md, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 100);
ok = VirtualProtect(addr, 100, PAGE_READONLY, &old);
//...
ok = VirtualProtect(addr, 100, PAGE_READWRITE, &old);

【讨论】:

好的,所以我想以将来可能需要的最大访问权限调用 CreateFileMapping 和 MapViewOfFile。我要补充一点:如果我不是最初打开文件句柄的人,有没有办法找出该文件句柄上可用的最高访问级别? A FALSE return 和 GetLastError() 告诉你,同样的想法。 您是否建议我先尝试最高访问权限,然后再降低到不会给我错误的最低访问权限?我想这可能行得通,但似乎应该有更好的方法。 另外,在hostile environment :-) - 在尝试 VirtualProtect 之前,您可以调用 VirtualQuery 并查看原始内存保护选项(MEMORY_BASIC_INFORMATION 结构的 AllocationProtect 成员)【参考方案2】:

在您的代码中发生的情况是 VirtualProtectEx(由您的 VirtualProtect 调用)失败并出现错误 STATUS_SECTION_PROTECTION (0xC000004E) - “一个部分的视图指定了一个保护与初始视图的保护不兼容”,这似乎是您通过创建具有更多限制性保护 (FILE_MAP_READ) 的剖面视图所做的事情。

这个话题似乎没有足够的细节记录,所以我认为你最好按照汉斯的建议去做。

【讨论】:

【参考方案3】:

根据http://msdn.microsoft.com/en-us/library/aa366556(v=vs.85).aspx,这应该是合法的。根据 VirtualProtect 文档,新标志必须与“VirtualAlloc”标志兼容——如果这转移到“MapViewOfFile”标志,我怀疑你可以加强但不能放松保护。尝试将读写映射并将保护更改为只读。

【讨论】:

以上是关于在映射文件上调用 VirtualProtect的主要内容,如果未能解决你的问题,请参考以下文章

什么时候在ARM板上安装操作系统?调用端口的地址会映射到真实地址还是虚拟地址?

linux内核源码分析之虚拟内存映射

内存映射mmap 和 共享内存

在集合返回后调用集合上的映射与使用点链接映射

RestKit 对象映射 POST 响应,“CoreData:错误:在 NSManagedObject 类映射操作上调用指定初始化程序失败”

为啥我不能在 Laravel 上正确映射嵌套查询? “在 null 上调用成员函数 map()”显示为错误