科锐第三阶段项目-CreateProcess分析之MmInitializeProcessAddressSpace() 分析
函数原型:
NTSTATUS
MmInitializeProcessAddressSpace (
IN PEPROCESS ProcessToInitialize,
IN PEPROCESS ProcessToClone OPTIONAL,
IN PVOID SectionToMap OPTIONAL,
IN OUT PULONG CreateFlags,
OUT POBJECT_NAME_INFORMATION *AuditName OPTIONAL
);
函数主要功能:
此函数的主要功能如函数名,初始化新进程的地址空间,主要有两部分操作:
1. 初始化新进程 EPROCESS对象有关变量
2. 对新进程的可执行映像文件在地址空间的映射,或者在拷贝父进程地址空间。
函数参数:
ProcessToInitialize,即为要初始化的目标进程。
ProcessToClone,可选参数,表示新进程的地址空间可以从该进程拷贝获得。
SectionToMap,可选参数,一个内存区对象,表示在新进程地址空间中映射此对象。
CreateFlags, 传入传出参数,表示各种与进程创建相关的标志,与内存管理有关的标志是PROCESS_CREATE_FLAGS_ALL_LARGE_PAGE_FLAGS,其传出值表示是否成功地以大页面的方式来映射进程的映像文件。
AuditName,可选参数,输出参数,是一个对象名称信息指针。
一些相关的名词解释:
PDE:Page Directory Entry, 页目录项
PTE:Page Table Entry, 页表项
超空间:一个用于映射进程工作集列表的特殊区域,在执行一些操作时它也被临时用于映射其他的物理页面,这样的操作有零化空闲列表上的页面、使其他页表中的页表项无效,以及创建进程。
系统页表项:系统PTE池,其中的PTE被用于映射系统页面,比如I/O空间、内核栈,以及内存描述符列表。通过检查性能工具中的“Memory: Free System Page Table Entries”计数器的值,你可以知道有多少系统PTE是可以使用的。
换页内存池:可换页的系统内存堆。
非换页内存池:不可换页的系统内存堆,通常有两部分在系统空间的低端和高端各有一部分。
PFN数据库:页帧数据库(Page Frame Number Database),是一个阵列或一个数组,每一个页面对应有一个PFN项,记录了该页面的使用情况,包括它的状态、对应页表项的地址等信息。
自旋锁:是一种在内核定义,只能在内核态下使用的同步机制。自旋锁用来保护共享数据或者资源,使得并发执行的程序或者在高优先级IRQL的对称多处理器的程序能够正确访问这些数据。
工作集:是指一个进程当前正在使用的物理页面的集合。
VAD:Virtual Address Descriptor,虚拟地址描述符。Windows的进程地址空间是通过VAD来管理的,VAD对象描述了一些连续的地址范围,在整个地址空间中,保留的或提交的地址范围有可能是不连续的,所以,Windows使用一棵平衡二叉搜索树(称为AVL树)来管理VAD对象。VadRoot的类型为MM_AVL_TABLE,VAD树中的各节点类型为MMADDRESS_NODE,当使用AVL树来管理虚拟地址空间中的VAD时,树中节点的真正类型为MMVAD。需要说明的一点是,由于VadRoot的BalancedRoot域是一个内嵌结构体它无法从MMADDRESS_NODE适应MMVAD,所以,虚拟地址空间VAD树的真正根节点是VadRoot.BalancedRoot.RightChild,VadRoot.BalancedRoot.LeftChild并未使用。VadRoot.BalancedRoot.RightChild的静态类型是MMADDRESS_NODE,但其实际的对象类型是MMVAD。从这两种类型的定义可以看出,MMVAD是MMADDRESS_NODE的一个扩展,它增加了几个数据成员。
函数调用时机:
此函数是在创建进程时,由父进程在NtCreateProcessEx() 中, 在初始化完新进程对象的进程页目录和超空间的页帧号,以及新进程的句柄表之后调用的。
调用此函数初始进程空间有四种可能性:
1. Boot Process,系统引导时调用,无父进程。
2. System Process,系统进程的初始化,无父进程,无文件区域对象。
3. User Process (Cloned Address Space),根据父进程克隆地址空间。
4. User Process (New Image Address Space),根据指定文件区域对象映射地址空间
函数具体分析:
一个新进程在创建时,父进程调用此函数属于第四种,以下用上述所说第四种的执行过
程来分析此函数的具体功能。在第四种情况调用时,进入函数之前,在NtCreateProcessEx()函数中已调用了MmCreateProcessAddressSpace() 函数创建了进程地址空间,而且在新进程地址空间中,系统空间部分的页目录项已经被拷贝到页目录中,系统空间已经映射好,新进程的超空间也已初始化,但新进程的用户空间部分,即0x00000000~0x7fffffff,还是一片空白,此函数就是对用户空间部分的初始化。
调用函数具体流程如下:
1. 得到当前线程内核线程块KTHREAD结构体指针
注意:上传附件及图片大小不得大于30M。
⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。
