【问题标题】:How to set memory region's protection in kernel mode under Windows 7Windows 7下如何在内核模式下设置内存区域的保护
【发布时间】:2016-07-29 23:22:20
【问题描述】:

基本上我正在寻找一个可以为内核模式做的函数,就像VirtualProtect 为用户模式做的那样。

我正在使用以下简化代码示例的逻辑分配内存。

    PMDL mdl = MmAllocatePagesForMdl    
    (
        LowAddress,
        HighAddress,
        SkipAddress,
        size
    );

    ULONG flags = NormalPagePriority | MdlMappingNoExecute | MdlMappingNoWrite;
    PVOID ptr = MmGetSystemAddressForMdlSafe
    (
        mdl, 
        flags
    );

MdlMappingNoExecuteMdlMappingNoWrite 标志仅对 Win8+ 有效。
此外,仅使用 MmGetSystemAddressForMdlSafe 我无法为内存区域分配例如 NoAccess 保护。

我可以使用任何其他或替代的 API 来修改分配内存的页面保护吗?
黑客也可以这样做,因为目前此功能不会在生产代码中使用。

【问题讨论】:

    标签: memory-management windows-kernel


    【解决方案1】:
    C:\Windows\System32>dumpbin /exports ntdll.dll | find "Protect"
            391  17E 0004C030 NtProtectVirtualMemory
           1077  42C 000CE8F0 RtlProtectHeap
           1638  65D 0004C030 ZwProtectVirtualMemory
    

    我认为您可以从内核模式调用Zw 函数,并且args 通常与对应的Nt 函数相同。虽然ZwProtectVirtualMemory 没有记录,但有一个记录在案的ZwAllocateVirtualMemory 接受保护标志。

    另一种方法可能是在用户模式下分配和保护虚拟内存,将缓冲区向下传递给驱动程序,然后在那里创建相应的 MDL。

    【讨论】:

    • 谢谢。您是否知道,这些 API 是否也可以应用于非分页和系统(非进程关联)内存?
    • ZwAllocateVirtualMemory 例程在指定进程的用户模式虚拟地址空间内保留、提交或同时保留、提交页面区域 - msdn.microsoft.com/en-us/library/windows/hardware/… While Your answer仍然有用,这个问题目前有点隐含地要求解决非分页内存,因为MmAllocatePagesForMdl 生成非分页内存分配 - msdn.microsoft.com/en-us/library/windows/hardware/…
    • 了解未记录的ZwProtectVirtualMemory API 是否能够在非分页内存上工作以及它与MmProtectMdlSystemAddress 有何不同仍然会很有趣?我想我知道NtProtectVirtualMemory 用于用户模式内存,并且会因指向系统内存范围的参数而失败。 ZwMm API 之间的区别很有趣,因为在互联网上可以找到各种黑客来调用 ZwProtectVirtualMemory API。如果不是为了某些优势......那么我认为这些黑客不会被制作?
    【解决方案2】:

    我目前最终使用的代码如下。
    所有使用的 API 都是官方的。
    在这里,我为分配的内存的 subrange 创建另一个 mdl 并更改该子范围的保护。

    如果你绊倒了使用下面这种方法保护的内存,那么:

    • IRQL < DISPATCH_LEVEL 你会得到PAGE_FAULT_IN_NONPAGED_AREA 错误(引用了无效的系统内存。这不能被try-except保护, 它必须受到探头的保护。通常,地址很糟糕,或者 指向释放的内存。)
    • IRQL == DISPATCH_LEVEL 你会得到 DRIVER_IRQL_NOT_LESS_OR_EQUAL fault (试图访问一个可分页(或完全无效)的地址 中断请求级别 (IRQL) 太高。这通常是 由司机使用不正确的地址造成的。)

    请注意,如果 子范围大页面 分配的一部分,则更改保护可能会失败。那么status 很可能是STATUS_NOT_SUPPORTED。 如果最初分配的内存区域的大小和对齐方式(取决于问题中的SkipAddress 变量)合适并且一些额外的先决条件是,
    大页面分配可能发生完成了我不熟悉的(可能从某些操作系统版本开始)。

            PMDL guard_mdl = IoAllocateMdl
            (
                NULL, 
                PAGE_SIZE * guardPageCount, 
                FALSE,           
                FALSE,  
                NULL        
            );
    
            if (guard_mdl)
            {
                IoBuildPartialMdl
                (
                    mdl,    
                    guard_mdl,  
                    (PVOID)(0),  // **offset** from the beginning of allocated memory ptr
                    PAGE_SIZE * guardPageCount
                );
    
                status = MmProtectMdlSystemAddress
                (
                    guard_mdl,
                    PAGE_NOACCESS
                );
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-12
      • 2013-06-05
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 2015-09-25
      • 1970-01-01
      相关资源
      最近更新 更多