首页 技术 正文
技术 2022年11月9日
0 收藏 695 点赞 3,449 浏览 3633 个字

Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html

Windows内存布局 / MmPfnDataBase页帧数据库

1. Windows操作系统在X86下的内存布局如下图所示

  存储物理页属性的PFN数据库存储物理页属性的PFN数据库

 

2. 进程工作集 (Hyperspace and process working set list)

 如上图所示,在c0400000地址处存在一个进程工作集,其在EProcess+0x1f8 vm 表示,其是一个 _SUPPORT结构。

  存储物理页属性的PFN数据库

3. nt!MmNumberOfPhysicalPages 查看存在多少物理页
  这是一个全局变量,表明操作系统当前可用的物理页个数,我们在10-10-12分页模式下一个页以4KB为单位,我们查看该变量:

  dd nt!MmNumberOfPhysicalPages 0001ff6c

  我们从任务管理器中查看其可用的内存

  存储物理页属性的PFN数据库

   很容易发现满足关系 0001ff6c*4 =  523696,因此可以验证我们的说法:该变量代表当前进程中可用的物理页数。

4. 页帧数据库 PfnDataBase

  1) mmpfndatabase 全局变量

    该全局变量以数组形式存储对应的__MMPFN数据结构,整个可以看做 __MMPFN[x],x表示第x个物理页,这是数组一次排序。

    其__MPFN数据结构如下(其中涉及大量的Union类型),其单个长度 0x14。(注意,其长度不确定,具体看详细版本的长度)

    存储物理页属性的PFN数据库

   2) 物理页的八种状态(实际只有六个,其存在各自的链表)

    物理页本来应该存在八种状态,但其中只有六个可用,其存储在 __MMPFN.u3

    u3中存在一个 __MMPFNENTRY,里面描述了有关该页所处的状态(空闲状态,零化状态,未分配状态·····)。

    其根据物理页的状态,制作不同的链表,将相同属性的物理页串联在一起,如下六个全局变量:

    ① MmZeroedPageListHead  // 可以使用并清零的内存

    ② MmFreePageListHead // 被释放的内存,定期会检测是否有数据,如果有就清空并且挂到第一个链表中

    ③ MmStandbyPageListHead  // 分页内存,备份到虚拟文件中,如果①②用完其才会用到这个,紧急使用

    ④ MmModifiedPageListHead // 修改过属性的页

    ⑤ MmModifiednoWritePageListHead // 修改但是没有写出的链表

    ⑥ MmBadPageListHead // 坏页的链表

   具体的存储在 MmPageLocationList 这个数组中,我们在WRK中可以看到该数组的定义,我们可以看到,八个中确实只用到了六个。

    存储物理页属性的PFN数据库

    typedef enum _MMLISTS {
        ZeroedPageList,
        FreePageList,
        StandbyPageList,  //this list and before make up available pages.
        ModifiedPageList,
        ModifiedNoWritePageList,
        BadPageList,
        ActiveAndValid,
        TransitionPage
    } MMLISTS;

  3)__MMPFN的中存在 FlinkBlink 两个成员,但其并不是指针而是ULONG类型,前面说过内存物理页是依次排列的,那么这两个成员有什么用呢?

    前面我们说过其存在六个链表,虽然物理页的前后是确定的,但是相同属性的物理页却是通过 Flink 与 Blink 连接起来的,其并不是连接而是在页帧数据库中的位置,这个很好理解。

    存储物理页属性的PFN数据库

    而 MmPageLocationList数组中存储的各个属性物理页头部的地址,这样整个页帧数据库体系就很容易搭建起来了。

  4)Windbg 遍历pfn 单个 __MMPFN数据结构

  使用windbg的 !pfn x 命令可以查看其存在多少对应的PFN对应的物理页的属性:

  存储物理页属性的PFN数据库

5. 驱动遍历某一链表

  结合我们上面所讲,其Pfn在内存中的布局如下,如果上面都看懂了,这部分应该很好理解,但其中MmPageLocationList与MmPfnDataBase并不是导出变量,我们通过IDA特征码定位即可。

  存储物理页属性的PFN数据库

#include <ntifs.h>
#include <ntimage.h>
#include <intrin.h>
#include "tools.h"typedef struct _MMPFN {
ULONG Flink; // 前一个节点索引
ULONG PteAddress; // 对应的pte地址
ULONG Blink; // 后一个节点索引
ULONG u3[3]; // 占位,总共0x14个字节
}MMPFN,*PMMPFN;typedef enum _MMLISTS {
ZeroedPageList,
FreePageList,
StandbyPageList, //this list and before make up available pages.
ModifiedPageList,
ModifiedNoWritePageList,
BadPageList,
ActiveAndValid,
TransitionPage
} MMLISTS;typedef struct _MMPFNLIST {
PFN_NUMBER Total;
MMLISTS ListName;
PFN_NUMBER Flink;
PFN_NUMBER Blink;
} MMPFNLIST, *PMMPFNLIST;PULONG MmPageLocationList; //
PULONG MmPfnDataBase; // 页帧数据库VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("卸载完成\n");
}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegsiterPath)
{ pDriverObject->DriverUnload = DriverUnload; // 定位 MmPageLocationList
FindCode findcodes[1] = { 0 };
initFindCodeStruct(&findcodes[0],
"8B******8B48*FF088B56*894D*8B0E83**894D*0F*****8B*****8D0C498954**8B5D*8B4D*",
0, 0);
PUCHAR f = (PUCHAR)FindAddressByCode(findcodes, 1);
MmPageLocationList = *(PULONG) ((PUCHAR)f + 3); // 定位 MmPfnDataBase
FindCode findcodes2[1] = { 0 };
initFindCodeStruct(&findcodes2[0],
"8B*****8D044956578D34C28B7E*A1****C1**83**85C0895D*894D*0F*****83******0F*****8B46*",
0, 0);
f = (PUCHAR)FindAddressByCode(findcodes2, 1);
PULONG MmPfnDataBase = *(PULONG)(*(PULONG)((PUCHAR)f + 2)); // 查询空闲链表数据成员
MMLISTS PfnIndex = FreePageList;
PMMPFNLIST ZeroedPageList = MmPageLocationList[PfnIndex];
DbgPrint("零化链表的总数为:%x,前一个节点为:%x,后一个节点为:%x\r\n", ZeroedPageList->Total,ZeroedPageList->Flink,ZeroedPageList->Blink); // 开始遍历PfnDataBase页帧数据库
//DbgPrint("MmPfnDataBase地址为:%p\r\n", MmPfnDataBase);
ULONG index = ZeroedPageList->Flink; // 获取第一个节点索引
PMMPFN p;
for (ULONG i = 0; i < ZeroedPageList->Total; i++) {
p = (PMMPFN)((PUCHAR)MmPfnDataBase + sizeof(MMPFN) * index); // 获取结点
DbgPrint("Current PteAddress:%x\r\n", p->PteAddress);
index = p->Flink; // 更新下一个结点
}
return STATUS_SUCCESS;
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,493
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,495
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,133
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,297