EPROCESS中
+0x11c VadRoot : Void
这就是个入口点,从这个入口点开始是一个搜索二叉树,这个二叉树里面每个结点都记录了一块被占用的线性地址空间,结点类型是_MMVD
类型是 _MMVD,如下:
接下来探索一下:
因为它是根节点,所以呢?父节点也就为null
左右子树都是_MMVD,往下继续找即可。左右子树的父节点一定是上一个点。
为什么采用二叉树的方式管理线性地址空间呢?
最主要的原因是使用二叉树查询的性能会更好(涉及数据结构)
这个StartingVpn和这个EndingVpn是以页为单位也就是(4KB)0x1000
在StartingVpn这个地址后添加3个0,也就是这个结点描述的线性地址的起始地址
EndingVpn这个地址后添加3个0,也就是这个结点描述的线性地址的结束地址,也就是说这块线性地址已经被占用了
(如果想知道整个用户空间低2G的线性地址哪些地方没有被占用的话,需要遍历这棵二叉树,然后去找哪些未在起始地址和结束地址中的线性地址,也就没有被占用)
FilePointer
如果想知道这块线性地址到底是被谁占用的呢?可以通过ControlArea
看到这个结构体后,再去看看这个结构体中的一个FilePointer值
如果FilePointer的值是NULL,那就说明这块线性地址对应的是真正的物理页(这个内存是使用VirtualAlloc 来分配的)
再来看看其它情况
近一步看到FilePointer值不为空,再来近一步查看FilePointer指向的地方
它是一个Map内存,通过文件映射的内存(这块内存通过文件映射得到的)
遍历搜索链表操作:
!vad 根节点的地址(即vadRoot值)
结点中如何查看属性
这里的_MMVAD_FLAGS(是+0x014中结构体的成员)
dt _MMVAD_FLAGS
+0x000 CommitCharge
+0x000 PhysicalMapping
+0x000 ImageMap //1.镜像文件 0其他
+0x000 UserPhysicalPages
+0x000 Nochange
+0x000 WriteWatch
+0x000 Protection
//1.READONLY 2.EXECUTE 3.EXECUTE_READ 4.READWITER
//5.WRITECOPY 6.EXECUTE_READWITER 7.EXECUTE_WRITECOPY
+0x000 LargePages
+0x000 MemCommit
+0x000 PrivateMemory
//1.PrivateMemory 2.Map
内存分为两类:
1.VirtualAlloc分配的普通内存
2.map文件映射内存