MmIsAddressValid分析

  1.之前有一次被问到了MmIsAddressValid的实现,当时只是大概猜了一下检测pte、pde的p标志位,今天来填一下坑。

  2.这次分析的环境是Win7 x32 PAE,也就是2-9-9-12分页,看一下PAE分页下intel文档说明:

  

       

    a)在任一时间的PAE分页模式下一个进程只能访问4GB的虚拟地址空间,尽管PAE模式支持大于4GB的物理内存

    b)PAE分页模式下,每个核维护了一组(4)PDPTE寄存器,因此每次进行地址翻译时并不会从CR3开始


  

       

    a)每个PDPTE控制1GB虚拟地址空间的访问

    b)在上图说明的4中情况会导致PDPTEs从CR3指向的地址中重新加载

    c)如果PDPTE的P标志位或者任何保留位被修改,则MOV To CR指令将会导致#GP异常,并且PDPTEs也不会重新加载 


       

        

    a)4K页面和2M页面的地址翻译过程如上

    b)详情见《IntelManual.Volume:System Programming Guide(4.4.2 Linear-Address Translation with PAE Paging)》


  3.接下来看一下IDA中的实现

   

  可以看到虚拟地址右移18位后与上了0x3FF8,这里可以看成虚拟地址右移21位然后左移3位(乘8,每个分页结构的大小都为8字节,低三位都为0),当时看到这里的有一些不理解,因为现在还剩下11位(也就是2 9 9 12分页的前两个偏移)。这里直接用这11位加上了0xC0600000,这里在Windbg中进行分析。

  

  在Windbg中可以看到0xC0600000指向的是PDPT0,并且每个PDPT都是相差0x1000的大小,因此上面的用11位直接加上0xC0600000就好理解了,前2位用来索引是哪个PDPTs,后9位用来确定PDE中的偏移。所以Windows应该会在0xC0600000地址翻译过程中的PTE构造一个PDPTs的表,这里可以用Windbg验证。

  

  在WIndbg中可以看到在翻译虚拟地址0xC0600000时,PTE中存放了一组PDPTs,和CR3中储存的值一致,因此(address >> 18) & 0x3FF8这个操作既起到了计算PDE偏移的作用,同时也计算了位于哪个PDPTs。因此可以知道:

/*
0xC0600000 pdpt0

0xC0601000 pdpt1

0xC0602000 pdpt2

0xC0603000 pdpt3
*/

  因此IDA中的MmIsAddressValid的代码就很清晰了,首先检测了虚拟地址对应的pde的p标志位是否置一,如过置一且pde.ps位置一,就说明这是个2m的大页,检查就完成了。如果不为1,那么将会继续检查PTE的p标志位是否置位。所以MmIsAddressValid只是简单的检查页面的p标志位,正如msdn中所说,如果这个地址指向的物理页没有被锁定或者不是非分页池分配的内存,那么这个函数返回的结果就不一定正确。

原文地址:https://www.cnblogs.com/DreamoneOnly/p/12240519.html