2.3 地址转换
运行在操作系统中的一般程序,并不都直接操作底层的物理地址空间,程序访问的地址一般是其系统提供的内存管理模型中的线性地址空间,采用的地址为线性地址。程序在计算机运行中,各种地址转换是由CPU和操作系统联合完成的。
内存取证中需要处理和分析的对象,一般都是对实际物理内存的映射和镜像,数据在文件中的偏移量与物理地址有对应关系。系统程序和用户应用代码引用的都是线性(虚拟)地址,这些地址都需要转化为物理地址才能真正进行访问,系统通过内存管理器实现这种转换。要进行内存分析,需要进行由线性地址到物理地址的转换。
在英特尔架构下,分段管理是强制性的,基本由处理器完成。本书讨论的操作系统,其实现隐藏了分段管理的细节。内存取证分析中,主要处理的是线性地址到物理地址部分的转换,大部分分析过程不具体涉及由逻辑地址到线性地址空间的转换。
在内存分析进行地址转换时,需要根据系统使用的不同分页模式,进行相应的地址转换。
2.3.1 32 bit分页
32 bit分页的页大小有两种情况:4 kB和4 MB。
4 kB下使用二级页表结构进行地址转换。一个32 bit的线性地址被划分成3个域,分别是页目录索引、页表索引和字节索引。
(1)Page Directory(页目录)——在线性地址中为最高10 bit,用于访问页目录表中的项。
(2)Page Table(页表)——在线性地址中为中间10 bit,用于访问页表中的项。
(3)Offset(偏移量)——最低12 bit,用于访问页内的某个存储单元。
进行转换时,使用内存中存储的页目录和页表,将线性地址转换为实际的物理地址。如图2-3所示。
图2-3 页大小4 kB的地址转换(32 bit)
线性地址的前10 bit是页目录索引,指向虚拟地址的页目录项(PDE,Page Directory Entry)。每个进程都有自己的页目录。系统进行进程环境切换时,硬件会得到当前进程的页目录地址,一般通过寄存器CR3保存这个物理地址。PDE中包含了内存中一个页面的物理地址页面帧编号(PFN,Page Frame Number)以及一些描述该页面的状态和属性的标志,通过PFN便可找到对应的页表地址。
接下来线性地址的10 bit是页表索引,定向到虚拟地址的页表项(PTE,Page Table Entry)。PTE的格式和PDE类似,页包含了一个页面物理地址的PFN和一些标志描述。根据PFN可以定位到目标页面。
查找到目标页面的物理地址之后,根据线性地址中最后12 bit的字节索引,便得到了最终需要的目标字节,这样就完成了虚拟地址到物理地址的转换。
4 MB的地址转换,只需要一个页目录项,如图2-4所示。
图2-4 页大小4 MB的地址转换(32 bit)
图2-3和图2-4中的线性地址都是结构化的地址,不同比特表示了地址转换中所需不同数据结构的值(如表2-1所示)。
表2-1 32 bit分页时结构化地址的格式
2.3.2 物理地址扩展分页
英特尔奔腾处理器引入了物理地址扩展(PAE,Physical Address Extension)内存映射模式,使X86处理器可以访问到64 GB的物理内存,X64处理器可以达到1024 GB。
PAE分页的页大小有4 kB和2 MB两种。
4 kB情况下,在采用了PAE模式之后,线性地址被内存管理单元(MMU)分为4个区块。与32 bit分页模式中的4 kB页相比,多了一项页目录指针(PDPT,Page Directory PointerTable),占2 bit。CPU通过CR3得到页目录指针区块的物理地址。之后的转换过程与之前提到的转换类似,不再重述。与默认映射模式不同的是,页目录项和页表项都由原来的32 bit改为64 bit,系统内部使用25 bit来定位物理地址,这样系统就可以支持128 GB的内存访问。地址转换如图2-5所示。
图2-5 页大小4 kB的地址转换(PAE)
PAE分页下,页大小2 MB的地址转换如图2-6所示。
图2-6 页大小2 MB的地址转换(PAE)
2.3.3 四级分页
Intel 64 bit架构处理器的计算机采用四级分页。内存取证涉及的Intel 64 bit架构知识与IA-32架构非常类似,但是也有一些不同。IA-32架构中涉及的寄存器,Intel 64 bit架构中仍然使用,只是由32 bit变为64 bit。最显著的变化是Intel 64 bit架构支持64 bit的线性地址,理论上可以支持264 byte的线性地址空间。目前的系统实现只使用了48 bit的线性地址,63:48 bit根据符号扩展设置为0或者1,即根据线性地址的第47 bit是0或者1来决定63:48 bit是0或者1。
四级分页(4-Level Paging)机制添加了一层分页结构PLM4(Page Map Level 4),支持3种固定大小的页(4 kB,2 MB,1 GB)。如果CPU相关寄存器中的分页标志位被设置,那么执行内存操作的机器指令时,CPU会自动根据相应转换结构(PML4,PDPT,PD,PT)中的信息,把虚拟地址转换成物理地址。图2-7显示了页大小4 kB的地址转换。
图2-7 页大小4 kB的地址转换(4-Level Paging)
2.3.4 地址转换实例
本节假定已知一些条件,举例讲如何进行从线性地址到物理地址的转换,在实际内存分析中,地址转换的具体算法将在第5章中详细介绍。
假设一个内存分析的情境,已知系统使用了IA-32分页,且分页大小为4 kB,在PID 1024的程序svchost.exe的虚拟地址空间中,引用了一个虚拟地址0x10036270,现在想知道这个地址的物理地址附近存在哪些数据,因此需要将虚拟地址0x10036270转化为物理地址。由图2-3可知,进行地址转换,还要知道相应的页目录基地址(寄存器CR3存储的值),已知这个值为0x7401000。下面是具体计算过程。
(1)将需要转换的虚拟地址0x10036270改写为二进制形式。
0001 0000 0000 0011 0110 0010 0111 0000
(2)计算PDE的物理地址,并获取PDE的值。
分割此二进制数的不同比特位,提取转换过程中需要的值(参照图2-3),见表2-2(IA-32分页模式下,各地址的位数以及表示的意义如表2-2所示,其他分页模式请参考Intel芯片架构的开发者手册)。
表2-2 虚拟地址位数
图2-3中页目录项(PDE,Page Directory Entry)的物理地址可以通过表2-2中页目录索引(Page Directory Index)的值乘上页目录项的大小(4 byte),再加上页目录基地址(已知的CR3保存的值0x7401000)得到。
PDE的物理地址=PDI×4+PDB(CR3)=0x40×4+0x7401000=0x7401100
知道了PDE的物理地址,可以获知该物理地址(内存物理镜像的偏移)中存储的值,这里假设PDE地址0x7401100处的值为0x28cf9067。需要注意的是此值一般存储为小头格式。
(3)计算PTE的物理地址,获取PTE的值
根据表2-2,页表索引(Page Table Index)由虚拟地址的12~21 bit,共10 bit构成,说明页表共有210=1024项。根据表2-1,由PDE值(0x28cf9067)的12~31 bit和虚拟地址(0x10016270)的12~21 bit,可以得到PTE(Page Table Entry)的物理地址。
PTE的物理地址=PTI×4+PDE物理地址的12~31 bit(11:0 bit填充0)=0x36×4+0x28cf9000=0x28cf9058
(4)计算转换后的物理地址
获取0x28cf9058处的值为0x182a7071。根据表2-1,可以根据PTE值0x0x182a7071的12~31 bit(0x28cf9000)和虚拟地址0x10036270的0~11 bit(偏移量,0x270)得到最后的物理地址。
物理地址=0x28cf9000+0x270=0x28cf9270
这样,最初的虚拟地址0x10016270就通过转换得到了物理地址0x28cf9270。