偶的博客: http://hi.baidu.com/hu3167343 大家支持下,谢谢了.
昨天新买了两本书, 看到了内存分页部分, 特此记录下, 没什么技术含量, 错误之处还请大牛指点.
大多数现代的操作系统都支持虚存, 这使得系统上的每个程序都拥有自己的地址空间. 每当程序读取内存时, 都必须指定一个地址. 对于每个进程, 该地址必须转换为实际的物理内存地址.
例如, 若我们的MzfHips.exe 程序需要的数据在虚拟内存地址的0x0041FF10处, 则实际的物理地址可能被映射为0x01EE2F10.
如下图:
图1: 虚拟地址转物理地址示意图 (图中的数据仅仅是为了演示)
内存地址的转换主要通过一个称为页表目录的特殊表来完成. Intel x86 CPU将页表目录的指针存储在特殊寄存器CR3中. 该寄存器指向一个包含1024个32位值的数组, 称为页目录. 每个数组元素称为页目录项, 它指定了页表在物理内存中的基地址, 还通过状态位指示该页表当前是否存在于内存中. 从页表中可以获得实际的物理地址.
图2: 在内存中寻找页面
下面我们来看下虚拟地址的组成:
由图可知, 虚拟地址的前10位用来定位页目录项, 中间10位用来定位页表项, 最后12位得到具体物理地址的偏移.
到了这里, 我们来总结下具体的步骤:
1. CPU查询CR3寄存器以找到页表目录的基地址
2. 操作系统根据所请求的虚拟地址的前10位(如图3), 来定位页目录项, 从而在内存中找到相应的页表.
3. 页表根据中间的10位定位该页相应的物理内存首地址
4. 根据虚拟地址的后12位得到具体的物理地址相对于首地址的偏移量.
5. 最后得到的物理地址即包含我们要请求的数据
知道了前面的知识, 下面我们来看下具体的页目录项和页表项中的内容.
由前面我们知道, CR3寄存器指向页目录的首地址, 而页目录是由最多1024个可能的页目录项组成.
下面我们看下页目录项的地址组成:
当访问页目录项时, 要检查U位(第2位), 若U位为0, 则意味着正在处理的页表只能用于内核.
还要检查W位(第1位), 若W位为0, 则内存是只读的.
页目录项指向整个页表, 即整个页面集合, 因此, 页目录项中的设置应用于整个内存页范围.
下面来看下页表项:
当访问页表项时, 仍然首先要检查U位(第2位), 若U位为0, 则只有内核模式的程序才能够访问该内存页.
还要检查W位(第1位), 以判断读写访问权限.
最后还要判断P位(第0位), 若它设置为0, 则当前内存页被换出在磁盘上. 若它设置为1, 则内存是常驻, 并且当前是可用的.
在将内存页换出后, 内存管理器在成功访问它之前必须将该页换入内存.
还有最后一个问题就是, 系统上的大多数可执行程序的其实地址都是0x00400000. 多个进程如何能使用同一个虚拟地址, 而不会在物理内存中发生冲突?那是因为系统上的每个进程都维护一个独立的页目录, 都拥有自己私有的CR3寄存器的值.
当线程发生切换时, 旧线程的状态会被保存起来. 若当前调度运行的线程不属于刚才的进程, 则当前进程的页目录地址会被加载到CR3寄存器中. 页目录地址可以在进程的KPROCESS结构中找到.
分析下MmIsAddressValid函数, 加深下对分页机制的了解.(参考combojiang大叔)
下面是ida 看到的ntoskrnl.exe中导出的MmIsAddressValid。
.text:0040C661 ; BOOLEAN __stdcall MmIsAddressValid(PVOID VirtualAddress)
.text:0040C661 public MmIsAddressValid
.text:0040C661 MmIsAddressValid proc near ; CODE XREF: sub_40D65E+Cp
.text:0040C661 ; sub_415459:loc_415470p ...
.text:0040C661
.text:0040C661 VirtualAddress = dword ptr 8
.text:0040C661
.text:0040C661 ; FUNCTION CHUNK AT .text:0041B84E SIZE 00000007 BYTES
.text:0040C661 ; FUNCTION CHUNK AT .text:0044A4F2 SIZE 00000019 BYTES
.text:0040C661
.text:0040C661 mov edi, edi
.text:0040C663 push ebp
.text:0040C664 mov ebp, esp
.text:0040C666 mov ecx, [ebp+VirtualAddress] ;取出虚拟地址
.text:0040C669 mov eax, ecx
.text:0040C66B shr eax, 14h ; 右移20位
.text:0040C66E mov edx, 0FFCh ; 取高10位
.text:0040C673 and eax, edx
.text:0040C675 sub eax, 3FD00000h ; 加上0xc0300000
.text:0040C675 ; PDE = ((VA >> 22) << 2 )& 0xffc + 0xc0300000
.text:0040C67A mov eax, [eax]
.text:0040C67C test al, 1 ; 页目录项的第0位, 即P位
.text:0040C67E jz loc_41B84E
.text:0040C684 test al, al
.text:0040C686 js short loc_40C6AC ; 判断page size位
.text:0040C688 shr ecx, 0Ah ; 右移10位
.text:0040C68B and ecx, 3FFFFCh
.text:0040C691 sub ecx, 40000000h
.text:0040C697 mov eax, ecx ; PTE = ((VA >> 12) << 2 ) & 0x3FFFC + 0xc0000000
.text:0040C699 mov ecx, [eax] ; ecx = PTE Context
.text:0040C69B test cl, 1 ; 判断present位
.text:0040C69E jz loc_41B84E
.text:0040C6A4 test cl, cl
.text:0040C6A6 js loc_44A4F2 ; 判断page size位
.text:0040C6AC
.text:0040C6AC loc_40C6AC: ; CODE XREF: MmIsAddressValid+25j
.text:0040C6AC ; MmIsAddressValid+3DE9Fj
.text:0040C6AC mov al, 1
.text:0040C6AE
.text:0040C6AE loc_40C6AE: ; CODE XREF: MmIsAddressValid+F1EFj
.text:0040C6AE pop ebp
.text:0040C6AF retn 4
.text:0040C6AF MmIsAddressValid endp
.text:0040C6AFPs:上面说的理论是在未开启PAE模式下的一般情况, 在开启了PAE的情况下, 可能会有所不同。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: