内存管理
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
内存管理
1. 线性地址管理
1)VadRoot _EPROCESS+0x11c
每个进程的_EPROCESS+0x11c位置,都存在一个二叉树,VadRoot,之前我们有过介绍。
该VadRoot中以二叉树的形式记录了当前线程中所申请的全部内存,以__MVD的形式保存。
windbg中使用 !vad addr 可以遍历该内存的各种VAD属性。
2)__MVAD
//0x28
bytes (sizeof) struct _MMVAD {
ULONG StartingVpn; //0x0 开始的内存页地址
ULONG EndingVpn; //0x4 结束的内存页地址
struct _MMVAD* Parent; //0x8
struct _MMVAD* LeftChild; //0xc
struct _MMVAD* RightChild; //0x10
union {
ULONG LongFlags; //0x14
struct _MMVAD_FLAGS VadFlags; //0x14 访问属性
} u; //0x14
struct _CONTROL_AREA* ControlArea; //0x18
struct _MMPTE* FirstPrototypePte; //0x1c
struct _MMPTE* LastContiguousPte; //0x20
union {
ULONG LongFlags2; //0x24
struct _MMVAD_FLAGS2 VadFlags2; //0x24
} u2; //0x24
};
① 二叉树链表,指向父节点,左子树与右子树。
② StartingVpn EndingVpn:表示页的起始地址和结束地址,以4KB为单位,所获取结果直接乘以0x1000获取线性地址。
③ ControlArea - 该页映射的具体内容
如果该值为NULL,则说明该页是物理内存;如果指向FILE_OBJECT,则说明指向文件的映射。
一个是VirtualAlloc申请的,一个是Map映射的内存,通过这个可以区分。
④ VadFlags - 指明当前内存页的属性,可读可写可访问之类的,通过 __MMVAD_FLAGS可以详细查看有关位的标识。
3)总结:
该部分是管理线性地址,而不是物理地址的,因此获取的地址(VPN)是线性地址而不是物理地址,这个很简单的道理你需要明确。
2. PrivateMemory
前面讲过内存存在两类,一类是PrivateMemory,一类是MappedMemory内存。
PrivateMemory是通过VirtualAlloc分配内存,其第一个参数是线性地址执行的,必须在VadRoot中StartingVpn没有被占用的,这个你要明确。
1)VirtualAlloc
该函数的本质就是申请PrivateMemory内存,申请一块__MMVAD结构块,然后挂到有关进程的_VAD链表中。
因此该地址的lpAddress就是对应的__MMVAD.StartVpn,如果被占用则会重新分配地址,因此这个参数不确保一定会申请出来。
2)malloc 与 new 内存:
① new 内存
② malloc的底层实现 HeapAlloc,从堆内存中申请内存,HeapAlloc没有进零环,
③ 所谓堆内存,是创建进程时操作系统提前为我们使用VirtualAlloc分配好的一块大内存,因此HeapAlloc并没有进零环,因为直接拿去分配好的内存。
3. MappedMemory
1)文件映射
① CreateFileMapping 该函数关联物理页与对应的文件。
② MapViewOfFile 将物理页与对应进程的线性地址关联,可以在相关进程的Vad中搜索到该内存。
2)DLL映射
LoadLibrary的底层是CreateFileMapping,底层实现映射。
其将属性设置为写拷贝,当修改时,其会自动创建一个物理页拷贝过去,而不修改原始文件。
4. 物理内存的管理 MmPfnDataBase 物理页数据库
1)查看当前物理页的数量
MmNumberOfPhysicalPages 全局变量,里面存储着当前物理页的个数。
其中一页为4KB,转换为可以得到相应的物理内存。
2)物理地址如何管理
其存储在一个全局数组中,_MMPFN *MmPfnDataBase,其数组长度就是 MmNumberOfPhysicalPages。
其数组中的成员结构为 __MMPFN,其成员很好理解。
3)线性地址与物理地址如何查找管理
注意:__MMVAD没有一个指针指向__MMPFN结构,根据数组计算。
比如一个__MMVAD.StartingVpn为X,如果要找对应的物理页索引,即 MmPfnDataBase[x],__MMPFN其大小为0x1c,因此这样很容易计算得出。
4)物理页的属性及六个链表 物理地址属性 __MMPFN.u3
u3中存在一个 __MMPFNENTRY,里面描述了有关该页所处的状态(空闲状态,零化状态,未分配状态·····)。
其根据物理页的状态,制作不同的链表,将相同属性的物理页串联在一起,如下六个全局变量:
① MmZeroedPageListHead
② MmFreePageListHead
③ MmStandbyPageListHead
④ MmModifiedPageListHead
⑤ MmModifiednoWritePageListHead
⑥ MmBadPageListHead
4)总结:
物理页管理如下图,由一个MmPfnDataBase[]数组来管理索引的,注意_MMPFN的Flink与Blink,并不是指向前后链表,其是一个索引。
MmPfnDataBase是一个数组,因此很容易就可以从前面找到后面的,其Flink与Blink是相同属性的物理页索引(上面介绍的四个数组)。
5. 缺页异常
PTE结构中如果P位为0,如果访问该位,则会产生缺页异常。
1)为什么会产生缺页异常?
如果一个物理页长时间不被使用或者物理页紧缺,会将当前物理页拿出来,存放要硬盘上,这成为虚拟内存。
2)COMMIT、RESERVED属性区别