windows下分页机制浅谈

引子:
 一直在研究恶意代码方向与逆向软件方向,面试聊了windows内核与保护模式相关知识,有很多没有回答上来,确实研究过相关资料,但是没有深入研究,加上长时间没有复习,有些遗忘了
 基本功不扎实,毕竟好久没写过驱动编程与复习内核/保护模式相关的知识,所以静下心来复习一下吧。

4GB的虚拟内存结构:

虚拟内存地址范围 描述
0x00000000~0x0000FFFF 64kb大小的空指针区域,当然就不可以访问了
0x00001000~0x7FFFFFFF 加上上述的空指针区域,低2GB的用户态空间
0x80000000~0xFFFFFFFF 高2GB的内核态空间

更多的详细划分请参考这篇博客:https://blog.csdn.net/wang010366/article/details/52730052

一个进程地址如何映射到物理地址的?

图片一:映射关系
                
 上述图片只是片面的阐释,一个虚拟内存地址通过页表转换,映射到物理内存地址,多个进程其实都是通过这种机制映射到物理内存。
图片二:地址映射过程

 图片二是虚拟地址映射,注意:缺少了分页的层级,页表中每一项都是一个分页。映射的物理地址过程如何实现的?先介绍Cr0系列的控制寄存器,面试的时候忘的一干二净,那就在学一遍:

寄存器名称 描述
CR0 包含处理器标志控制位,如PE,PG,WP等
CR1 保留
CR2 专门用于保存缺页异常时的线性地址
CR3 保存进程页目录地址
CR4 扩展功能(如判断物理地址扩展模式等),Pentium系列(包括486的后期版本)处理器中才实现

图片三:控制寄存器

➀什么是PE,PG,WP呢?
 1、PE:CR0寄存器的第0位,Protection Enable,启用保护标志。如果该位为1,开启了保护模式,反之关闭,当开启保护模式的时候PE\PG都会置位。
 2、PG:CR0寄存器的第31位,Paging,分页标志位。如果为1则开启分页机制,禁止分页的话线性地址等同于物理地址,若开启标志位意味着需要开启保护模式。
 3、WP:CR0寄存器的第16位,Write Proctect,写保护标志。WP==1的时候意味着只读页面不可执行写操作,wp==0的时候意味着只读页面可执行写操作。

➁CR3寄存器保存了每个进程的页目录地址,什么叫做页目录呢?
 Windows下开启保护模式与分页机制后,当前CR0寄存器的属性PE == 1 AND PG == 1,意味着进程中的虚拟地址将通过页表转换映射相对应的物理地址上,如图二所示,我们手工的获取来学习:
首先介绍一下分页机制其中一种记录方式:

非物理地址扩展模式 物理地址扩展模式
非PAE模式 PAE模式

 PAE模式:Physical address extension,物理扩展模式。能够在32位操作系统访问超过4GB寻址大小的模式,允许将最多64GB 的物理内存用作常规的4 KB 页面,并扩展内核能使用的位数以将物理内存地址从32扩展到36。
 非PAE模式:在非物理扩展模式下,32位最大只能4GB所以,即使你有8G的内存条,也是白费。
 那么在非PAE模式下,操作系统分页机制如何实现的?每个分页4kb,一共4GB的内存,4194304KB大小也就是一共1048576个分页,那么如何高效的管理这些分页呢?

 1024(PDT) × 1024(PTT) × 4096 = 4GB
 1024(PTT) × 1024(PTE) × 4 = 4MB
 1024(PDT) ×1024(PTE) = 1MB

如上述公式所示,就是通过这种方式来管理4GB的内存分页,PDT,PTT,PTE又是什么,如下所示

名称 描述
页目录索引表(PDT) 一级索引
页表索引表(PTT) 二级索引
页表项(PTE) 页表项 PDT(1024项PDE),PTT(1024项PTE)
图片四:地址解析

 需要配合图二一起理解,操作系统会通过CR3寄存器获取当前进程的页表目录地址,然后根据虚拟地址拆分为10,10,12比例,找到页目录,找到页表,然后找到分页加上对应的偏移(物理内存),为了方便理解,当然也是动手写个小程序,在windbg下一探究竟。

➀编写测试代码,如下所示:

int main()
{
    printf("虚拟地址:0x%X\n", "hello world");
    cout << "hello world" << endl;
    system("pause");
}

 ➁编译后拖入虚拟机,开启双击调试(测试环境win7 32位),运行测试程序(不要关闭回车),windbg下输入!process 0 0查看全部进程及各部分说明,如下所示:

图片五:双击调试

 ➂上述进程说明中我们看到DirBase地址,这个就是当前进程指向的页目录,我们看看到底对不对?需要明确的字段PROCESS 0x86ca5c18是EPROCESS的地址,输入指令dt 0x86ca5c18 _EPROCESS来看一看,如下所示:
图片六:EPROCESS

 ➃一个进程的页目录怎样找?在CreateProcess的第二个阶段,会初始化进程的执行体层EPROCESS数据结构与微内核层KPROCESS数据结构,系统DLL映像目标用户空间且初始化PEB操等等,来看_KPROCESS结构+0x18字段是什么?如下所示:
图片七:DirectoryTableBase

 ➄通过上述_KPROCESS获取了PDT的地址,与解析出来PDT数据一样的。每当CPU切片执行进程时候,CR3就会被系统切换,CR3是不是读取当前进程DirectoryTableBase字段作为切换数值有待研究,看一看PDT也就是页表转换的第一层结构,如下所示:
图片八:虚拟地址

 ➅解释两个dd,因为这个以前也总是被同学问起,dd怎么啥东西都找不到,在windbg命令下,d系列命令只能查看虚拟地址, 查看物理地址需要使用!d系列命令,PDT是物理地址,如下所示:

图片九:物理地址

 ➆根据上述一些理论性知识,如图九中所展示的每项便是页表地址(物理地址),根据虚拟地址,测试是否能通过页表转换找到映射的物理存储数据,所以第二步中没输出字符串虚拟地址(图是昨天的),重新来一下(已经关闭了随机基址),如下所示:
图片十:输出字符串在虚拟内存地址

➇根据图片四把上述的虚拟地址进行分割,如下所示:
图片十一:虚拟地址转换

 ➈对应的二进制换算16进制 (1 <--> 19 <--> B30),其中1代表是页目录表中的第一项,查看页目录表之前需要对地址页目录的PTE了解,如下所示:

 ➉如上图所示,低12位是属性,高位是地址, 然后页表索引是19,数组元素是保存的指针,需要乘以4字节,如下所示:

图片十二:页表查找

 ⑪怎么什么都没有,还记着我们上述说过,这一台记录方式PAE与非PAE,我们现在所处的环境究竟是怎样,我们打开cmd,利用bcdedit命令,先做了解如下所示:
图片十三:bcdedit

 ⑫修改当前pae模式以及nx模式,pae我们知道是物理扩展模式,nx是缓解机制,使某些内存区域不可执行,并使可执行区域不可写DEP,我们也要改为Always Off模式,如下所示:

修改指令如下:

名称 关闭指令 开启指令
PAE bcdedit /set pae ForceDisable bcdedir /set forceEnable
NX bcdedit /set nx AlwaysOff bcdedit /set nx OptIn

修改后属性如下:

图片十四:属性调整

⑬重启系统后,再次按照上述步骤查找具体的分页数据,如下所示:
图片十五:非PAE下目录表

 ⑭那么解析虚拟地址之后,如何通过也目录找到具体页表呢?我们需要了解一下页目录中的每一项PDE数据,也就是指针如何分解的,如下所示:

图片十六:页表地址解析

 ⑮通过上图所示,我们知道低位12位是属性,高位才是地址,意味着我们只需要BaseAddress + 第几项PTT × 4(指针大小)就可以找到相对的页表指针,如下所示:

图片十七:页表

 ⑯找到了具体的页表地址,也就是0x342f6025,加上具体的偏移(虚拟地址分解出的低12位)就可以找到映射的物理内存数据保存,当然地址还是要把地位属性去掉,用地址+偏移即可,如下所示:
图片十八:物理内存

 整个过程解析了虚拟地址将一个地址如何映射到物理内存,他们之间的存在的转换映射关系,当然省略很多机制内部机制。片面的理解保护模式下分页的重要性,我们跟多层面去学习研究虚拟内存与物理内存关系。

出处:https://blog.51cto.com/13352079/2368281

你可能感兴趣的:(windows下分页机制浅谈)