-
-
[原创]Windows内核学习笔记之内存管理
-
发表于: 2021-12-27 13:23 28272
-
Windows采用页式内存管理方案,在Intel x86处理器上,Windows不适用段来管理虚拟内存,但是,Intel x86处理器在访问内存时必须要通过段描述符,这意味着Windows将所有的段描述符都构造成了从基地址0开始,且段的大小根据段的用户和系统设置的不同,会设置为0x80000000,0xC0000000或0xFFFFFFFF。所以,Windows系统中的代码,包括操作系统本身的代码和应用程序的代码,所面对的地址空间都是线性地址空间。这种做法相当于屏蔽了处理器中的逻辑地址概念,段只被用于访问控制和内存保护。
Windows使用了两种特权级别:0和3,其中特权级0称为内核模式,特权级3称为用户模式。当处理器指向内核模式代码时,它们处于系统地址空间,位于0x80000000~0xFFFFFFFF,所有的进程共享此空间;当处理器执行用户模式代码时,它们处于进程地址空间,位于0x00000000~0x7FFFFFFF,这部分空间是进程私有的。用户模式代码只能访问进程自身的数据,而内核模式代码不仅可以访问当前进程的数据,也可也访问系统地址空间中的数据。所有的进程,一旦进入到内核模式,则共享同一的系统地址空间。
在Windows的每个地址空间中,虚拟地址的分配和回收都必须按照规定执行。Windows规定,应用程序在使用内存以前必须先申请,所以,操作系统内部可以根据应用程序的申请和释放操作来维护好整个虚拟地址空间的内存分配情况。而且,Windows也采用了按需分配的策略,也就是说,只有当一段虚拟地址空间真正被使用的时候,系统才会为它分配页表和物理页面。每个进程的虚拟地址空间的分配情况通过一组虚拟地址描述符(VAD)记录下来,这些描述符构成了有一颗平衡二叉树,以便于快速地定位到一个指定虚拟地址地描述符上。
在系统地址空间中,有些部分提供一些特殊模块使用,比如会话空间是由会话管理器和Windows子系统使用的;而换页内存池和非换页内存池则是提供给系统内核模块和设备驱动程序使用的。在换页内存池中分配的内存有可能在物理内存紧缺的情况瞎被换出到外存中;而非换页内存池中分配的内存总是处于物理内存中。为了实现这两种池,Windows使用了两层内存管理。下层是基于页面的内存管理,仅限于执行体内部使用;上层建立在下层的内存管理功能基础之上,对外提供各种粒度的内存服务。两层结果如下图所示
系统换页内存池和非换页内存池是Windows系统提供的最基本动态内存管理手段,它以页面为基本粒度来管理系统中划定的地址范围。
页面粒度对于一般的代码逻辑而言太大了。所以,为了适应各种内核组件对于内存管理的需要,Windows内核在系统的非换页内存池和换页内存池的基础上,实现了灵活的,可适应各种大小内存需求的内存池,这便是执行体内存池。
执行体内存对象是由数据结构POOL_DESCRIPTOR来描述的,定义如下:
以下是WRK中和内存管理有关的一部分全局变量:
ExpNumberOfNonPagePools代表非换页内存池数量,只有一个;而换页内存池的数量,即变量ExpNumberOfPagedPools,在单处理器系统上是3个,在多处理器系统上有5个。PoolVector是一个包含两个数组的元素,第一个元素PoolVector[0]指向非换页内存池,即NonPagedPoolDescriptor的地址;第二个元素PoolVector[1]指向换页内存池,即指向第一个换页内存池。数组ExpNonPagedPoolDescriptor仅用于有多个非换页内存池的情形;数组ExpPagedPoolDescriptor中的每个元素分别指向一个换页内存池。
执行体内存池对象的初始化是按照换页内存池和非换页内存池分开进行的,在Windows系统内核中通过一些列内核函数来使用内存池对象。
执行体内存池的初始化是在InitializePool函数中完成的,函数首先会判断要初始化的内存池是否是非分页内存池
如果要初始化非分页内存池,就会判断KeNumberNodes中的数据是否大于1,根据后面代码的内容可推测这个变量保存的是处理器的核数
如果大于1,就会修改全局变量ExpNumberOfNonPagedPools保存的数据
调用ExInitializePoolDescriptor来初始化非分页内存池对象,该内存池对象的地址则是全局变量NonPagedPoolDescriptor,且在初始化之前会将地址保存到PoolVector数组中的第一个元素
如果要初始化分页内存池,首先依然会判断KeNumberNodes中保存的数据是否大于1
如果大于1,则修改ExpNumberOfPagedPools中保存的数据
调用函数来申请一块内存,由于此时ebx等于0,所以申请的是非分页内存,而申请的内存的大小则是ExpNumberOfPagedPools的大小加1乘以0x1048的大小
这里申请的内存大小之所以要乘以0x1048,是因为要保存的结构体除了内存池对象的0x1028字节大小,还要申请FAST_MUTEX对象的0x20大小,该对象结构体如下:
将内存池对象地址赋给PoolVector数组下标为1的地址,将FAST_MUTEX对象地址赋给全局变量ExpPagedPoolMutex,并将参数PoolType修改为0,因为此时ebx等于0
将填充申请到的ExpNumberOfPagedPools+1个的内存池对象和FAST_MUTEX对象
因此,可以得出结论,分页内存池对象也是用非分页内存来保存的。而无论是初始化非分页内存对象还是初始化分页内存对象,都需要通过ExInitializePoolDescriptor函数来实现
ExInitializePoolDescriptor函数首先对对象中的前几个成员赋值
此时eax是内存池对象地址,加上0x28就会获得ListHeads成员的地址,而该成员是一个双向链表的数组,共有512个元素,所占内存大小为0x1000,所以接下来就是将ListHeads中的每一个双向链表都指向自己
为了管理内存的开销,每次通过执行体内存池分配的内存块有8字节大的POOL_HEADER结构体,该结构体定义如下:
这里的PreviousSize和BlockSize都是指实际大小除以8之后得到的值,并非原始值
POOL_DESCRIPTOR对象中的ListHeads成员维护了一组快表,这些快表包含了8字节倍数大小的空闲内存块链表。虽然ListHeads有512个成员,但是由于最小的内存块是8个字节,且POOL_HEADER也是8个字节,所以,实际使用的只有510项,分别对应于8,16,... ,4072和4080大小的空内存块。如果申请的内存块大小在4080到4096之间,就会使用整个页面,因为剩下的空间不足以容纳最小内存块(8字节)加上管理开销(8字节)。下图显示了执行体内存池对象的管理结构:
通常用户会使用ExAllocateTag或者ExAllocateTagEx来申请内存,但是真正申请内存的其实是函数ExAllocateTagEx,因为前者是通过调用后者来实现的
在函数ExAllocatePoolEx中,首先会通过PoolType从PoolVector中取出相应的内存池对象,局部变量则用来记录申请的情况
通过参数NumberOfBytes判断申请的内存大小是否是大于0xFF0的大页面,如果是大页面就会直接通过调用函数MiAllocatePoolPages来直接申请内存块,此时的内存地址按页对齐,也就是地址的低12位为0
如果不是大页面,判断NumberOfBytes为0,则假设为1字节,因为有些驱动在分配的时候会设置为0,根据要申请的内存NumberOfBytes计算在快表ListHeads数组中的索引,即ListNumber局部变量
对于申请分页内存情况,根据情况ListNumber是否是小于0x20的小页面内存来决定是要从处理器的后备链表中分配内存,还是通过全局变量ExpPagedPoolDescriptor保存的分页池对象分配内存
对于申请非分页内存情况,根据变量var_PoolType与NeedSize来决定是否要从处理器的后备链表中来分配内存,还是从全局变量ExpNonPagedPoolDescriptor中获取非分页内存对象来分配内存
如果是要在非分页内存对象中申请内存,最后会跳转到上面使用分页内存对象来申请内存时候的LABEL_17执行,而LABEL17则跳转到LABEL_18执行剩下的代码
剩下的代码就是先从链表中寻找内存块,如果没有找到可用的内存块,那么就会通过调用函数MiAllocatePoolPages来申请新的内存块,而多申请的内存块也会被加入到链表中,而内存块链接进链表的位置是POOL_HEADER以后的八字节,也就是说池对象头后就是用来链接进链表的双向链表,以下是WRK中关于这部分内容的部分代码:
因此,可得出ExAllocatePoolWithTag函数基本流程如下:
如果申请的是大页面,直接调用MiAllocatePoolPages分配池内存
如果请求小页面,尝试从当前处理器控制块后备链表分配
如果后备链表分配失败,在从PoolVector指向的池描述符512条链表中分配
如果池描述符链表分配也失败,在调用MiAllocatePoolPages分配
池内存的释放是通过ExFreePool来实现的,函数首先会判断要释放的池内存是否是大页面内存,由于大页面内存的地址是按页对齐的,低12位为0,所以此时如果与0xFFF与运算以后的结果为0,则说明是大页面池内存
对于大页面池内存,会通过MiFreePoolPages来释放
和申请池内存类似,如果释放的是小页面池内存,就会尝试将池内存交还给当前处理器控制块的后备链表
如果不是上面的两种情况,函数就会判断要释放的内存块的上一内存块和下一内存块是否在被使用中,如果没有被使用,就会将它们合并成为一个内存块。合并的内存块如果刚好一个页的大小,函数就会调用MiFreePoolPages释放内存,否则的话就会将其加入到链表中
相比于高2GB每个进程共享的内核内存空间,低2GB的用户内存空间则是每个进程独立拥有的内存空间。也就是说,这部分空间只能由进程自己访问,其他进程无法访问。Windows系统在进程切换的时候,通过更换页目录表基址,也就是CR3寄存器中的内容来实现每个进程独享其高2GB的内存空间。高2GB的内存空间还根据地址分成了不同的分区,如下是32位系统的不同地址的分区情况
对于进程地址空间,用户程序必须经过“保留(reserve)”和"提交(commit)"两个阶段才可以使用一段地址范围。“保留一段地址范围”的用意是,将这段地址范围保留起来,但并不真正使用,由于这段地址范围不占用任何物理内存或其他外存空间,所以并不会形成实质的开销。这对于有些需要连续地址空间的程序有意义,它们可用在初始时保留一段大地址范围,以后需要的时候陆续使用。提交地址范围是指这段地址终究要消耗物理内存,由于Windows支持物理内存和页面文件之间的交换,因此可提交的内存数量是,可用物理内存总量去除系统使用的物理内存数量后,在加上页面文件的大小
在已提交的地址范围中,当页面被访问时,一定要先映射到物理内存页面上。这些页面要么是一个进程私有的,不共享的,要么被映射到一个内存区的视图上。后者可被多个进程共享
在Windows提供的API中,VirtualAlloc或VirtualAllocEx被用来保留或提交地址范围,通过这两个API申请的内存就是私有内存,只有申请内存的进程可使用;之后可用通过VirtualFree或VirtualFreeEx函数来解除已提交的地址范围,或者完全释放此地址范围。解除提交是指回到保留状态。因此,对于进程地址空间中的任何一个页面的地址范围,它一定处于三种状态之一:空闲的,保留的,或已提交的
以VirtualAllloc函数为例,该函数的定义如下:
其中第三个参数flAllocationType指定了申请的进程内存地址是“保留“或是”提交“。当该参数是MEM_RESERVE的时候,申请的进程内存地址是”保留“的,当参数为MEM_COMMIT的时候,申请的进程内存地址就是”提交“的
共享内存是通过创建内存区对象来实现的,内存区对象是Windows平台上多个进程之间共享内存的一种常用方法,它可被映射到系统的页面文件或其他文件中。实际上,内存区对象代表了一种物理存储资源,它可能在物理内存中,也可能在系统页面文件中,或其他文件中
内存区对象有两种,一种建立在页面文件的基础上,称为页面文件支撑的内存区,另一种被映射到其他文件中,称为文件支撑的内存区,也称为文件对象
Windows提供的CreateFileMapping这个API就是用来创建内存区对象的,该函数定义如下:
当第一个参数传入INVALID_HANDLE_VALUE(宏定义,值为-1)的时候,就会创建一个页面文件支撑的内存区,最后一个参数则指定了内存区的名称。当其他进程想要使用该内存区的时候,就可使用如下定义的OpenFileMapping函数,通过第三个参数lpName来打开指定的内存区
获取指定内存区的句柄以后,就可通过MapViewOfFile函数来将物理地址映射到用户空间中
Windows的进程地址空间是通过VAD(虚拟地址描述符)来管理的。VAD对象描述了一段连续的地址范围。在整个地址空间中,保留的或提交的地址范围有可能是不连续的,所以,Windows使用一颗平衡二叉搜索树(称为AVL树)来管理VAD对象。在进程内核对象EPROCESS偏移0x11C处保存的VadRoot域指向的就是此树的根。该树的每一个节点的对象结构体是MMVAD,定义如下:
其中的MMVAD_FLAGS结构体定义如下:
以记事本进程为例,通过查看EPROCESS结构的VadRoot就可得到该进程VAD对象的二叉树的根节点地址,此时为0x81D14F48
根据VadRoot的地址就可找到相应的树的根,通过其左右子树就可遍历这颗二叉树
也可查看该VAD对象的内存属性
为了方便查看一个进程的内存使用情况,WinDbg提供了vad命令来解析这颗二叉树,如下就是对记事本进程的内存使用情况
在系统地址空间,有一个区域称为PFN数据库,用于管理系统的物理内存。PFN数据库是一个阵列,或者说是一个数组,每一项都描述了物理页面的状态。全局变量MnPfnDatabase是一个指向该数组的指针,以下是该全局变量的输出,可看到该数组的地址是0x80C00000
数组中的每一个元素都是一个MMPFN结构体,该结构体定义如下:
在WRK中的定义如下:
其中MMPFNENTRY结构定义如下:
数组中的每个元素都占0x1C字节的大小,因此要查看数组中的元素需要根据索引来乘以0x1C作为偏移,而索引值左移12位的地址就是数组中该元素所描述的物理页,比如以下查询的是索引为2的物理页面的状态,因此所查的物理页是0x200~0x2FFF页面的状态
当Intel x86处理器在执行一个执行流过程中,需要使用到地址页表项(PTE)来翻译一个虚拟地址引用,PTE结构如下图所示,其中的第0位(V位)代表了有效位,指定了该PTE是否是有效的
当有效位为0的时候,处理器会引发一个异常,也成为页面错误。Windows内核的陷阱处理器会把这一异常交给内存管理器的页面错误例程,由它来解决页面无效的问题。一般来说,只要这个页面错误是合理的,则页面错误处理例程将试图分配一个物理页面,并设置好PTE来消除虚拟地址引用错误,使得该地址引用能被正确地翻译成恰当地物理页面。由于异常是硬件触发地,而页面错误处理例程是操作系统提供的组件,所以这一页面分配并重映射的过程对于原始的指令流是完全透明的,最多只是时间上稍有停顿
如果一个PTE已经正确指向一个物理页面,则页面错误不会发生,虚拟地址翻译可快速进行。但是,随着进程使用越来越多的页面,最终系统的可用物理内存可能会消耗光。为了避免因内存消耗光而导致应用程序或系统的正常功能无法执行,现代操作系统提供了页面交换的能力,即把有些正在使用的页面中的内容存放到磁盘上,从而腾出这些物理页面以供使用。以后,当这些被换出到磁盘上的页面再次被引用时,页面错误处理例程在把它们换回内存中
Windows系统支持一个或多个页面文件(每个磁盘分区最多一个页面文件),用来存放被交换页面的内容。页面文件可被看做是物理内存的一种延伸。对于页面文件中的内容而言,页面文件域物理内存是同等的,只不过受页面调度的影响而在不同时刻位于不同的物理位置
当第0位(V位)为0的时候,此时的PTE就是一个无效PTE。此时,处理器引发页面错误异常,该异常的陷阱处理器把控制权交给页面处理例程,所以,PET其他位的含义由操作系统来解释。正是由于这一层灵活性,Windows才可以在这一的PTE中承载一些信息,以便实现页面管理功能。无效PTE有下图所示的4种情形:
情形一:如图中(a)所示,此时第10和11位为0,第1~4位指示了在哪个页面文件种,第12~31位共20位表示了该页面在页面文件中的偏移量,以页面单位(0x1000字节)为单位
情形二:如图中(b)所示,是第一种情形的特例,若1~4位和12~31位全为0,则表明这是一个待分配的页面,它需要一个填满零的页面
情形三:如图中(c)所示,第10位为1,说明这个页面尚在内存中,但正在换出过程中,位于系统的某个物理页面链表中。此时第12~31位指示了物理页帧编号,根据PFN数据库可用定位到该页面的实际状态
情形四:如图中(d)所示,是一个全零的PTE,此时该页面的状态无法确定,甚至该PTE对应的虚拟地址是否已被提交也不能确定,所以页面错误处理例程应检查VAD树中对应的节点,以确定页面的状态
当通过CreateFileMapping来创建内存区对象的时候,该函数的第三个参数flProtect指定了内存区对象的页面保护属性,可以是PAGE_READ, PAGE_READWRITE, PAGE_EXECUTE以及会产生写时复制的PAGE_WRITECOPY,该属性的含义是,如果一个进程要写这个页面,则生成器字节的私有拷贝,并且私有拷贝的保护属性为PAGE_READWRITE。而属性PAGE_READWRITE的含义是不管将来哪个进程读或者写这个页面,都始终只有一个页面,也就是说,完全共享这个页面
当一个进程使用内存区对象时,它必须映射一个视图,视图本身并不影响内存区对象的保护属性。然而,在视图所对应的VAD节点中包含了这一保护属性,代表该进程对于此内存区对象的操作类型。MMVAD结构中的u.VadFlags.Protection成员即为此目的。映像文件的视图,此值为MM_EXECUTE_WROTECPY,支持写时复制。而其他类型的视图,此值就会由函数MapVieOfFile来决定
通常将一个DLL文件装载进内存时所创建的内存区对象的属性就是写时复制,且相应的PTE的有效位也会是0,如下图是记事本进程的DLL内存区对象的属性
当程序对有写时复制属性的内存区进行写操作的时候,发现PTE是0,也就是无效PTE的时候,页面错误处理例程会检查其内存区对象属性。如果是写时复制属性,就会会这块内存在分配一块新的物理地址,这样对其写入的操作就会在这块物理地址中完成。这样做的好处就是,原来物理地址中的内容不会发生改变,就不会影响其他进程对该共享内存的使用
《Windows内核原理与实现》
《Windows内核设计思想》
kd> dt _POOL_DESCRIPTOR
nt!_POOL_DESCRIPTOR
+
0x000
PoolType : _POOL_TYPE
+
0x004
PoolIndex : Uint4B
+
0x008
RunningAllocs : Uint4B
+
0x00c
RunningDeAllocs : Uint4B
+
0x010
TotalPages : Uint4B
+
0x014
TotalBigPages : Uint4B
+
0x018
Threshold : Uint4B
+
0x01c
LockAddress : Ptr32 Void
+
0x020
PendingFrees : Ptr32 Void
+
0x024
PendingFreeDepth : Int4B
+
0x028
ListHeads : [
512
] _LIST_ENTRY
kd> dt _POOL_DESCRIPTOR
nt!_POOL_DESCRIPTOR
+
0x000
PoolType : _POOL_TYPE
+
0x004
PoolIndex : Uint4B
+
0x008
RunningAllocs : Uint4B
+
0x00c
RunningDeAllocs : Uint4B
+
0x010
TotalPages : Uint4B
+
0x014
TotalBigPages : Uint4B
+
0x018
Threshold : Uint4B
+
0x01c
LockAddress : Ptr32 Void
+
0x020
PendingFrees : Ptr32 Void
+
0x024
PendingFreeDepth : Int4B
+
0x028
ListHeads : [
512
] _LIST_ENTRY
偏移 | 名称 | 作用 |
---|---|---|
0x000 | PoolType | 枚举类型POOL_TYPE,其中的NonPagedPool代表了执行体非分页内存池,PagedPool代表执行体的分页内存池 |
0x004 | PoolIndex | 指当前对象在该类型的内存池数组中的索引,对于换页内存池,该域是它在ExpPagedPoolDescriptor数组中的下标值 |
0x028 | ListHeads | 执行体内存池对于小内存的分配和回收,是通过一组空间内存块链表实现的 |
#if defined(NT_UP)
#define NUMBER_OF_PAGED_POOLS 2
#else
#define NUMBER_OF_PAGED_POOLS 4
#endif
ULONG ExpNumberOfPagedPools
=
NUMBER_OF_PAGED_POOLS;
ULONG ExpNumberOfNonPagedPools
=
1
;
POOL_DESCRIPTOR NonPagedPoolDescriptor;
#define EXP_MAXIMUM_POOL_NODES 16
PPOOL_DESCRIPTOR ExpNonPagedPoolDescriptor[EXP_MAXIMUM_POOL_NODES];
#define NUMBER_OF_POOLS 2
PPOOL_DESCRIPTOR PoolVector[NUMBER_OF_POOLS];
PPOOL_DESCRIPTOR ExpPagedPoolDescriptor[EXP_MAXIMUM_POOL_NODES
+
1
];
volatile ULONG ExpPoolIndex
=
1
;
#if defined(NT_UP)
#define NUMBER_OF_PAGED_POOLS 2
#else
#define NUMBER_OF_PAGED_POOLS 4
#endif
ULONG ExpNumberOfPagedPools
=
NUMBER_OF_PAGED_POOLS;
ULONG ExpNumberOfNonPagedPools
=
1
;
POOL_DESCRIPTOR NonPagedPoolDescriptor;
#define EXP_MAXIMUM_POOL_NODES 16
PPOOL_DESCRIPTOR ExpNonPagedPoolDescriptor[EXP_MAXIMUM_POOL_NODES];
#define NUMBER_OF_POOLS 2
PPOOL_DESCRIPTOR PoolVector[NUMBER_OF_POOLS];
PPOOL_DESCRIPTOR ExpPagedPoolDescriptor[EXP_MAXIMUM_POOL_NODES
+
1
];
volatile ULONG ExpPoolIndex
=
1
;
INIT:
005EB2F9
;
int
__stdcall InitializePool(POOL_TYPE PoolType, ULONG Threshold)
INIT:
005EB2F9
_InitializePool@
8
proc near ; CODE XREF: MiInitMachineDependent(x)
-
1FE3
↑p
INIT:
005EB2F9
; MiBuildPagedPool()
+
276
↓p
INIT:
005EB2F9
INIT:
005EB2F9
PoolType
=
dword ptr
8
INIT:
005EB2F9
Threshold
=
dword ptr
0Ch
INIT:
005EB2F9
INIT:
005EB2F9
mov edi, edi
INIT:
005EB2FB
push ebp
INIT:
005EB2FC
mov ebp, esp
INIT:
005EB2FE
push ebx
INIT:
005EB2FF
xor ebx, ebx ; ebx清
0
INIT:
005EB301
cmp
[ebp
+
PoolType], ebx ; PoolTpe是否为NonPagedPool
INIT:
005EB304
push esi
INIT:
005EB305
push edi
INIT:
005EB306
jnz loc_5EB21C
INIT:
005EB2F9
;
int
__stdcall InitializePool(POOL_TYPE PoolType, ULONG Threshold)
INIT:
005EB2F9
_InitializePool@
8
proc near ; CODE XREF: MiInitMachineDependent(x)
-
1FE3
↑p
INIT:
005EB2F9
; MiBuildPagedPool()
+
276
↓p
INIT:
005EB2F9
INIT:
005EB2F9
PoolType
=
dword ptr
8
INIT:
005EB2F9
Threshold
=
dword ptr
0Ch
INIT:
005EB2F9
INIT:
005EB2F9
mov edi, edi
INIT:
005EB2FB
push ebp
INIT:
005EB2FC
mov ebp, esp
INIT:
005EB2FE
push ebx
INIT:
005EB2FF
xor ebx, ebx ; ebx清
0
INIT:
005EB301
cmp
[ebp
+
PoolType], ebx ; PoolTpe是否为NonPagedPool
INIT:
005EB304
push esi
INIT:
005EB305
push edi
INIT:
005EB306
jnz loc_5EB21C
INIT:
005EB319
loc_5EB319: ; CODE XREF: InitializePool(x,x)
+
10BB9
↓j
INIT:
005EB319
mov al, _KeNumberNodes
INIT:
005EB31E
cmp
al,
1
INIT:
005EB320
ja loc_5FBEB7 ; al是否大于
1
INIT:
005EB319
loc_5EB319: ; CODE XREF: InitializePool(x,x)
+
10BB9
↓j
INIT:
005EB319
mov al, _KeNumberNodes
INIT:
005EB31E
cmp
al,
1
INIT:
005EB320
ja loc_5FBEB7 ; al是否大于
1
INIT:
005FBEB7
loc_5FBEB7: ; CODE XREF: InitializePool(x,x)
+
27
↑j
INIT:
005FBEB7
movzx eax, al
INIT:
005FBEBA
cmp
eax,
7Fh
INIT:
005FBEBD
mov ds:_ExpNumberOfNonPagedPools, eax
INIT:
005FBEC2
jbe short loc_5FBECC
INIT:
005FBEC4
push
7Fh
INIT:
005FBEC6
pop eax
INIT:
005FBEC7
mov ds:_ExpNumberOfNonPagedPools, eax
INIT:
005FBECC
INIT:
005FBECC
loc_5FBECC: ; CODE XREF: InitializePool(x,x)
+
10BC9
↑j
INIT:
005FBECC
cmp
eax,
10h
INIT:
005FBECF
jbe short loc_5FBED9
INIT:
005FBED1
push
10h
INIT:
005FBED3
pop eax
INIT:
005FBED4
mov ds:_ExpNumberOfNonPagedPools, eax
INIT:
005FBEB7
loc_5FBEB7: ; CODE XREF: InitializePool(x,x)
+
27
↑j
INIT:
005FBEB7
movzx eax, al
INIT:
005FBEBA
cmp
eax,
7Fh
INIT:
005FBEBD
mov ds:_ExpNumberOfNonPagedPools, eax
INIT:
005FBEC2
jbe short loc_5FBECC
INIT:
005FBEC4
push
7Fh
INIT:
005FBEC6
pop eax
INIT:
005FBEC7
mov ds:_ExpNumberOfNonPagedPools, eax
INIT:
005FBECC
INIT:
005FBECC
loc_5FBECC: ; CODE XREF: InitializePool(x,x)
+
10BC9
↑j
INIT:
005FBECC
cmp
eax,
10h
INIT:
005FBECF
jbe short loc_5FBED9
INIT:
005FBED1
push
10h
INIT:
005FBED3
pop eax
INIT:
005FBED4
mov ds:_ExpNumberOfNonPagedPools, eax
INIT:
005EB326
loc_5EB326: ; CODE XREF: InitializePool(x,x)
+
10BE4
↓j
INIT:
005EB326
; InitializePool(x,x)
+
10C28
↓j
INIT:
005EB326
push offset _ExpTaggedPoolLock ; SpinLock
INIT:
005EB32B
call _KeInitializeSpinLock@
4
; KeInitializeSpinLock(x)
INIT:
005EB330
push ebx ; PoolLock
INIT:
005EB331
push [ebp
+
Threshold] ; Threshold
INIT:
005EB334
mov eax, offset _NonPagedPoolDescriptor ; 将NonPagedPoolDescriptor地址赋给eax
INIT:
005EB339
push ebx ; PoolIndex
INIT:
005EB33A
push ebx ; PoolType
INIT:
005EB33B
push eax ;
int
INIT:
005EB33C
mov _PoolVector, eax ; 将NonPagedPoolDescriptor赋给PoolVector[
0
]
INIT:
005EB341
call _ExInitializePoolDescriptor@
20
; ExInitializePoolDescriptor(x,x,x,x,x)
INIT:
005EB346
INIT:
005EB346
loc_5EB346: ; CODE XREF: InitializePool(x,x)
-
16
↑j
INIT:
005EB346
; InitializePool(x,x)
-
7
↑j ...
INIT:
005EB346
pop edi
INIT:
005EB347
pop esi
INIT:
005EB348
pop ebx
INIT:
005EB349
pop ebp
INIT:
005EB34A
retn
8
INIT:
005EB34A
_InitializePool@
8
endp
INIT:
005EB326
loc_5EB326: ; CODE XREF: InitializePool(x,x)
+
10BE4
↓j
INIT:
005EB326
; InitializePool(x,x)
+
10C28
↓j
INIT:
005EB326
push offset _ExpTaggedPoolLock ; SpinLock
INIT:
005EB32B
call _KeInitializeSpinLock@
4
; KeInitializeSpinLock(x)
INIT:
005EB330
push ebx ; PoolLock
INIT:
005EB331
push [ebp
+
Threshold] ; Threshold
INIT:
005EB334
mov eax, offset _NonPagedPoolDescriptor ; 将NonPagedPoolDescriptor地址赋给eax
INIT:
005EB339
push ebx ; PoolIndex
INIT:
005EB33A
push ebx ; PoolType
INIT:
005EB33B
push eax ;
int
INIT:
005EB33C
mov _PoolVector, eax ; 将NonPagedPoolDescriptor赋给PoolVector[
0
]
INIT:
005EB341
call _ExInitializePoolDescriptor@
20
; ExInitializePoolDescriptor(x,x,x,x,x)
INIT:
005EB346
INIT:
005EB346
loc_5EB346: ; CODE XREF: InitializePool(x,x)
-
16
↑j
INIT:
005EB346
; InitializePool(x,x)
-
7
↑j ...
INIT:
005EB346
pop edi
INIT:
005EB347
pop esi
INIT:
005EB348
pop ebx
INIT:
005EB349
pop ebp
INIT:
005EB34A
retn
8
INIT:
005EB34A
_InitializePool@
8
endp
INIT:
005EB21C
loc_5EB21C: ; CODE XREF: InitializePool(x,x)
+
D↓j
INIT:
005EB21C
mov cl, _KeNumberNodes
INIT:
005EB222
cmp
cl,
1
INIT:
005EB225
ja loc_5FBF3E ; KeNumberNodes是否大于
1
INIT:
005EB21C
loc_5EB21C: ; CODE XREF: InitializePool(x,x)
+
D↓j
INIT:
005EB21C
mov cl, _KeNumberNodes
INIT:
005EB222
cmp
cl,
1
INIT:
005EB225
ja loc_5FBF3E ; KeNumberNodes是否大于
1
INIT:
005FBF3E
loc_5FBF3E: ; CODE XREF: InitializePool(x,x)
-
D4↑j
INIT:
005FBF3E
movzx eax, cl
INIT:
005FBF41
cmp
eax,
7Fh
INIT:
005FBF44
mov ds:_ExpNumberOfPagedPools, eax
INIT:
005FBF49
jbe loc_5EB230
INIT:
005FBF4F
push
7Fh
INIT:
005FBF51
pop eax
INIT:
005FBF52
mov ds:_ExpNumberOfPagedPools, eax
INIT:
005FBF57
jmp loc_5EB230
INIT:
005FBF5C
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
INIT:
005FBF5C
INIT:
005FBF5C
loc_5FBF5C: ; CODE XREF: InitializePool(x,x)
-
C6↑j
INIT:
005FBF5C
push
10h
INIT:
005FBF5E
pop eax
INIT:
005FBF5F
mov ds:_ExpNumberOfPagedPools, eax
INIT:
005FBF64
jmp loc_5EB239
INIT:
005FBF3E
loc_5FBF3E: ; CODE XREF: InitializePool(x,x)
-
D4↑j
INIT:
005FBF3E
movzx eax, cl
INIT:
005FBF41
cmp
eax,
7Fh
INIT:
005FBF44
mov ds:_ExpNumberOfPagedPools, eax
INIT:
005FBF49
jbe loc_5EB230
INIT:
005FBF4F
push
7Fh
INIT:
005FBF51
pop eax
INIT:
005FBF52
mov ds:_ExpNumberOfPagedPools, eax
INIT:
005FBF57
jmp loc_5EB230
INIT:
005FBF5C
;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
INIT:
005FBF5C
INIT:
005FBF5C
loc_5FBF5C: ; CODE XREF: InitializePool(x,x)
-
C6↑j
INIT:
005FBF5C
push
10h
INIT:
005FBF5E
pop eax
INIT:
005FBF5F
mov ds:_ExpNumberOfPagedPools, eax
INIT:
005FBF64
jmp loc_5EB239
INIT:
005EB242
lea esi, [eax
+
1
]
INIT:
005EB245
imul esi,
1048h
INIT:
005EB24B
push
'looP'
; Tag
INIT:
005EB250
push esi ; NumberOfBytes
INIT:
005EB251
push ebx ; PoolType
INIT:
005EB252
call _ExAllocatePoolWithTag@
12
; ExAllocatePoolWithTag(x,x,x)
INIT:
005EB257
mov edi, eax ; 要获取的内存赋值赋给esi
INIT:
005EB259
cmp
edi, ebx
INIT:
005EB25B
jz loc_5FBFF2
INIT:
005EB242
lea esi, [eax
+
1
]
INIT:
005EB245
imul esi,
1048h
INIT:
005EB24B
push
'looP'
; Tag
INIT:
005EB250
push esi ; NumberOfBytes
INIT:
005EB251
push ebx ; PoolType
INIT:
005EB252
call _ExAllocatePoolWithTag@
12
; ExAllocatePoolWithTag(x,x,x)
INIT:
005EB257
mov edi, eax ; 要获取的内存赋值赋给esi
INIT:
005EB259
cmp
edi, ebx
INIT:
005EB25B
jz loc_5FBFF2
kd> dt _FAST_MUTEX
nt!_FAST_MUTEX
+
0x000
Count : Int4B
+
0x004
Owner : Ptr32 _KTHREAD
+
0x008
Contention : Uint4B
+
0x00c
Event : _KEVENT
+
0x01c
OldIrql : Uint4B
kd> dt _FAST_MUTEX
nt!_FAST_MUTEX
+
0x000
Count : Int4B
+
0x004
Owner : Ptr32 _KTHREAD
+
0x008
Contention : Uint4B
+
0x00c
Event : _KEVENT
+
0x01c
OldIrql : Uint4B
INIT:
005EB261
mov eax, _ExpNumberOfPagedPools
INIT:
005EB266
lea esi, [eax
+
1
]
INIT:
005EB269
imul esi,
1028h
; 计算内存池对象占用的内存大小
INIT:
005EB26F
add esi, edi ; 将esi指向FAST_MUTEXT对象地址
INIT:
005EB271
inc eax
INIT:
005EB272
mov _PoolVector
+
4
, edi
INIT:
005EB278
mov _ExpPagedPoolMutex, esi
INIT:
005EB27E
mov [ebp
+
PoolType], ebx ; 将PoolType赋值为
1
INIT:
005EB281
jz short loc_5EB2CD
INIT:
005EB261
mov eax, _ExpNumberOfPagedPools
INIT:
005EB266
lea esi, [eax
+
1
]
INIT:
005EB269
imul esi,
1028h
; 计算内存池对象占用的内存大小
INIT:
005EB26F
add esi, edi ; 将esi指向FAST_MUTEXT对象地址
INIT:
005EB271
inc eax
INIT:
005EB272
mov _PoolVector
+
4
, edi
INIT:
005EB278
mov _ExpPagedPoolMutex, esi
INIT:
005EB27E
mov [ebp
+
PoolType], ebx ; 将PoolType赋值为
1
INIT:
005EB281
jz short loc_5EB2CD
INIT:
005EB283
loc_5EB283: ; CODE XREF: InitializePool(x,x)
-
2E
↓j
INIT:
005EB283
xor ecx, ecx
INIT:
005EB285
inc ecx ; ecx
=
1
INIT:
005EB286
push esi ; PoolLock
INIT:
005EB287
push [ebp
+
Threshold] ; Threshold
INIT:
005EB28A
mov [esi
+
_FAST_MUTEX.Count], ecx
INIT:
005EB28C
mov [esi
+
_FAST_MUTEX.Owner], ebx
INIT:
005EB28F
mov [esi
+
_FAST_MUTEX.Contention], ebx
INIT:
005EB292
mov [esi
+
_FAST_MUTEX.Event.Header.
Type
], cl
INIT:
005EB295
mov [esi
+
_FAST_MUTEX.Event.Header.Size],
4
INIT:
005EB299
mov [esi
+
_FAST_MUTEX.Event.Header.SignalState], ebx
INIT:
005EB29C
lea eax, [esi
+
_FAST_MUTEX.Event.Header.WaitListHead]
INIT:
005EB29F
mov [esi
+
_FAST_MUTEX.Event.Header.WaitListHead.Blink], eax
INIT:
005EB2A2
mov [eax], eax
INIT:
005EB2A4
mov eax, [ebp
+
PoolType] ; PoolType赋给eax
INIT:
005EB2A7
push eax ; PoolIndex
INIT:
005EB2A8
push ecx ; PoolType
INIT:
005EB2A9
push edi ;
int
INIT:
005EB2AA
mov _ExpPagedPoolDescriptor[eax
*
4
], edi
INIT:
005EB2B1
call _ExInitializePoolDescriptor@
20
; ExInitializePoolDescriptor(x,x,x,x,x)
INIT:
005EB2B6
mov eax, _ExpNumberOfPagedPools ; ExpNumberOfPagedPools赋给eax
INIT:
005EB2BB
add edi,
1028h
; edi指向下一个内存池对象
INIT:
005EB2C1
add esi,
20h
; esi指向下一个FAST_MUTEX对象
INIT:
005EB2C4
inc [ebp
+
PoolType] ; PoolType加
1
INIT:
005EB2C7
inc eax
INIT:
005EB2C8
cmp
[ebp
+
PoolType], eax
INIT:
005EB2CB
jb short loc_5EB283 ; PoolType是否小于ExpNumberOfPagedPools
INIT:
005EB283
loc_5EB283: ; CODE XREF: InitializePool(x,x)
-
2E
↓j
INIT:
005EB283
xor ecx, ecx
INIT:
005EB285
inc ecx ; ecx
=
1
INIT:
005EB286
push esi ; PoolLock
INIT:
005EB287
push [ebp
+
Threshold] ; Threshold
INIT:
005EB28A
mov [esi
+
_FAST_MUTEX.Count], ecx
INIT:
005EB28C
mov [esi
+
_FAST_MUTEX.Owner], ebx
INIT:
005EB28F
mov [esi
+
_FAST_MUTEX.Contention], ebx
INIT:
005EB292
mov [esi
+
_FAST_MUTEX.Event.Header.
Type
], cl
INIT:
005EB295
mov [esi
+
_FAST_MUTEX.Event.Header.Size],
4
INIT:
005EB299
mov [esi
+
_FAST_MUTEX.Event.Header.SignalState], ebx
INIT:
005EB29C
lea eax, [esi
+
_FAST_MUTEX.Event.Header.WaitListHead]
INIT:
005EB29F
mov [esi
+
_FAST_MUTEX.Event.Header.WaitListHead.Blink], eax
INIT:
005EB2A2
mov [eax], eax
INIT:
005EB2A4
mov eax, [ebp
+
PoolType] ; PoolType赋给eax
INIT:
005EB2A7
push eax ; PoolIndex
INIT:
005EB2A8
push ecx ; PoolType
INIT:
005EB2A9
push edi ;
int
INIT:
005EB2AA
mov _ExpPagedPoolDescriptor[eax
*
4
], edi
INIT:
005EB2B1
call _ExInitializePoolDescriptor@
20
; ExInitializePoolDescriptor(x,x,x,x,x)
INIT:
005EB2B6
mov eax, _ExpNumberOfPagedPools ; ExpNumberOfPagedPools赋给eax
INIT:
005EB2BB
add edi,
1028h
; edi指向下一个内存池对象
INIT:
005EB2C1
add esi,
20h
; esi指向下一个FAST_MUTEX对象
INIT:
005EB2C4
inc [ebp
+
PoolType] ; PoolType加
1
INIT:
005EB2C7
inc eax
INIT:
005EB2C8
cmp
[ebp
+
PoolType], eax
INIT:
005EB2CB
jb short loc_5EB283 ; PoolType是否小于ExpNumberOfPagedPools
PAGE:
004E281B
;
int
__stdcall ExInitializePoolDescriptor(
int
, POOL_TYPE PoolType, ULONG PoolIndex, ULONG Threshold, PVOID PoolLock)
PAGE:
004E281B
_ExInitializePoolDescriptor@
20
proc near
PAGE:
004E281B
; CODE XREF: MiInitializeSessionPool()
+
45
↓p
PAGE:
004E281B
; InitializePool(x,x)
-
48
↓p ...
PAGE:
004E281B
PAGE:
004E281B
PoolDescriptor
=
dword ptr
8
PAGE:
004E281B
PoolType
=
dword ptr
0Ch
PAGE:
004E281B
PoolIndex
=
dword ptr
10h
PAGE:
004E281B
Threshold
=
dword ptr
14h
PAGE:
004E281B
PoolLock
=
dword ptr
18h
PAGE:
004E281B
PAGE:
004E281B
; FUNCTION CHUNK AT PAGE:
004E36F6
SIZE
0000001B
BYTES
PAGE:
004E281B
PAGE:
004E281B
mov edi, edi
PAGE:
004E281D
push ebp
PAGE:
004E281E
mov ebp, esp
PAGE:
004E2820
mov eax, [ebp
+
PoolDescriptor]
PAGE:
004E2823
mov ecx, [ebp
+
PoolIndex]
PAGE:
004E2826
mov edx, [ebp
+
Threshold]
PAGE:
004E2829
mov [eax
+
_POOL_DESCRIPTOR.Threshold], edx
PAGE:
004E282C
mov edx, [ebp
+
PoolLock]
PAGE:
004E282F
mov [eax
+
_POOL_DESCRIPTOR.PoolIndex], ecx
PAGE:
004E2832
xor ecx, ecx ; ecx清
0
PAGE:
004E2834
push esi
PAGE:
004E2835
mov esi, [ebp
+
PoolType] ; 将PoolType赋给esi
PAGE:
004E2838
mov [eax
+
_POOL_DESCRIPTOR.LockAddress], edx
PAGE:
004E283B
mov [eax
+
_POOL_DESCRIPTOR.PoolType], esi
PAGE:
004E283D
mov [eax
+
_POOL_DESCRIPTOR.RunningAllocs], ecx
PAGE:
004E2840
mov [eax
+
_POOL_DESCRIPTOR.RunningDeAllocs], ecx
PAGE:
004E2843
mov [eax
+
_POOL_DESCRIPTOR.TotalPages], ecx
PAGE:
004E2846
mov [eax
+
_POOL_DESCRIPTOR.TotalBigPages], ecx
PAGE:
004E2849
mov [eax
+
_POOL_DESCRIPTOR.PendingFrees], ecx
PAGE:
004E284C
mov [eax
+
_POOL_DESCRIPTOR.PendingFreeDepth], ecx
PAGE:
004E281B
;
int
__stdcall ExInitializePoolDescriptor(
int
, POOL_TYPE PoolType, ULONG PoolIndex, ULONG Threshold, PVOID PoolLock)
PAGE:
004E281B
_ExInitializePoolDescriptor@
20
proc near
PAGE:
004E281B
; CODE XREF: MiInitializeSessionPool()
+
45
↓p
PAGE:
004E281B
; InitializePool(x,x)
-
48
↓p ...
PAGE:
004E281B
PAGE:
004E281B
PoolDescriptor
=
dword ptr
8
PAGE:
004E281B
PoolType
=
dword ptr
0Ch
PAGE:
004E281B
PoolIndex
=
dword ptr
10h
PAGE:
004E281B
Threshold
=
dword ptr
14h
PAGE:
004E281B
PoolLock
=
dword ptr
18h
PAGE:
004E281B
PAGE:
004E281B
; FUNCTION CHUNK AT PAGE:
004E36F6
SIZE
0000001B
BYTES
PAGE:
004E281B
PAGE:
004E281B
mov edi, edi
PAGE:
004E281D
push ebp
PAGE:
004E281E
mov ebp, esp
PAGE:
004E2820
mov eax, [ebp
+
PoolDescriptor]
PAGE:
004E2823
mov ecx, [ebp
+
PoolIndex]
PAGE:
004E2826
mov edx, [ebp
+
Threshold]
PAGE:
004E2829
mov [eax
+
_POOL_DESCRIPTOR.Threshold], edx
PAGE:
004E282C
mov edx, [ebp
+
PoolLock]
PAGE:
004E282F
mov [eax
+
_POOL_DESCRIPTOR.PoolIndex], ecx
PAGE:
004E2832
xor ecx, ecx ; ecx清
0
PAGE:
004E2834
push esi
PAGE:
004E2835
mov esi, [ebp
+
PoolType] ; 将PoolType赋给esi
PAGE:
004E2838
mov [eax
+
_POOL_DESCRIPTOR.LockAddress], edx
PAGE:
004E283B
mov [eax
+
_POOL_DESCRIPTOR.PoolType], esi
PAGE:
004E283D
mov [eax
+
_POOL_DESCRIPTOR.RunningAllocs], ecx
PAGE:
004E2840
mov [eax
+
_POOL_DESCRIPTOR.RunningDeAllocs], ecx
PAGE:
004E2843
mov [eax
+
_POOL_DESCRIPTOR.TotalPages], ecx
PAGE:
004E2846
mov [eax
+
_POOL_DESCRIPTOR.TotalBigPages], ecx
PAGE:
004E2849
mov [eax
+
_POOL_DESCRIPTOR.PendingFrees], ecx
PAGE:
004E284C
mov [eax
+
_POOL_DESCRIPTOR.PendingFreeDepth], ecx
PAGE:
004E284F
add eax,
28h
; eax指向ListHeads
PAGE:
004E2852
lea edx, [eax
+
1000h
] ; edx指向ListHead成员中的最后一个元素
PAGE:
004E2858
PAGE:
004E2858
loc_4E2858: ; CODE XREF: ExInitializePoolDescriptor(x,x,x,x,x)
+
49
↓j
PAGE:
004E2858
cmp
eax, edx
PAGE:
004E285A
jnb short loc_4E2866 ; eax是否大于edx
PAGE:
004E285C
mov [eax
+
LIST_ENTRY.Blink], eax
PAGE:
004E285F
mov [eax
+
LIST_ENTRY.Flink], eax
PAGE:
004E2861
add eax,
8
; 获取数组下一元素地址
PAGE:
004E2864
jmp short loc_4E2858
PAGE:
004E284F
add eax,
28h
; eax指向ListHeads
PAGE:
004E2852
lea edx, [eax
+
1000h
] ; edx指向ListHead成员中的最后一个元素
PAGE:
004E2858
PAGE:
004E2858
loc_4E2858: ; CODE XREF: ExInitializePoolDescriptor(x,x,x,x,x)
+
49
↓j
PAGE:
004E2858
cmp
eax, edx
PAGE:
004E285A
jnb short loc_4E2866 ; eax是否大于edx
PAGE:
004E285C
mov [eax
+
LIST_ENTRY.Blink], eax
PAGE:
004E285F
mov [eax
+
LIST_ENTRY.Flink], eax
PAGE:
004E2861
add eax,
8
; 获取数组下一元素地址
PAGE:
004E2864
jmp short loc_4E2858
kd> dt _POOL_HEADER
nt!_POOL_HEADER
+
0x000
PreviousSize : Pos
0
,
9
Bits
+
0x000
PoolIndex : Pos
9
,
7
Bits
+
0x002
BlockSize : Pos
0
,
9
Bits
+
0x002
PoolType : Pos
9
,
7
Bits
+
0x000
Ulong1 : Uint4B
+
0x004
ProcessBilled : Ptr32 _EPROCESS
+
0x004
PoolTag : Uint4B
+
0x004
AllocatorBackTraceIndex : Uint2B
+
0x006
PoolTagHash : Uint2B
kd> dt _POOL_HEADER
nt!_POOL_HEADER
+
0x000
PreviousSize : Pos
0
,
9
Bits
+
0x000
PoolIndex : Pos
9
,
7
Bits
+
0x002
BlockSize : Pos
0
,
9
Bits
+
0x002
PoolType : Pos
9
,
7
Bits
+
0x000
Ulong1 : Uint4B
+
0x004
ProcessBilled : Ptr32 _EPROCESS
+
0x004
PoolTag : Uint4B
+
0x004
AllocatorBackTraceIndex : Uint2B
+
0x006
PoolTagHash : Uint2B
名称 | 作用 |
---|---|
PreviousSize | 记录了当前内存块前面的内存块的大小,依据此域可用找到同一页面前面的内存块 |
PoolIndex | 说明了当前内存块属于哪个执行体内存池 |
BlockSize | 记录了当前内存块的大小,依据此域可用找到同一页面后面的内存块 |
PoolType | 记录了当前内存块所在的内存池的类型,对于空闲内存块,该成员为0 |
PoolTag | 记录了当前被分配内存块的一个标记 |
PVOID
ExAllocatePool(
IN POOL_TYPE PoolType,
IN ULONG NumberOfBytes
)
{
return
ExAllocatePoolWithTag(PoolType, NumberOfBytes,
'enoN'
);
}
PVOID
ExAllocatePool(
IN POOL_TYPE PoolType,
IN ULONG NumberOfBytes
)
{
return
ExAllocatePoolWithTag(PoolType, NumberOfBytes,
'enoN'
);
}
CheckType
=
PoolType &
1
;
if
( PoolType &
0x20
)
{
var_PoolType
=
0
;
if
( CheckType )
PoolDesc
=
ExpSessionPoolDescriptor;
else
PoolDesc
=
PoolVector[
0
];
}
else
{
PoolDesc
=
PoolVector[CheckType];
var_PoolType
=
1
;
}
CheckType
=
PoolType &
1
;
if
( PoolType &
0x20
)
{
var_PoolType
=
0
;
if
( CheckType )
PoolDesc
=
ExpSessionPoolDescriptor;
else
PoolDesc
=
PoolVector[
0
];
}
else
{
PoolDesc
=
PoolVector[CheckType];
var_PoolType
=
1
;
}
if
( NumberOfBytes >
0xFF0
)
{
v63
=
0
;
while
(
1
)
{
if
(
*
(_BYTE
*
)PoolDesc &
1
)
{
ExAcquireFastMutex(
*
(PFAST_MUTEX
*
)(PoolDesc
+
28
));
}
else
if
( (_UNKNOWN
*
)PoolDesc
=
=
&NonPagedPoolDescriptor )
{
LockHandle.OldIrql
=
KeAcquireQueuedSpinLock(
6
);
}
else
{
KeAcquireInStackQueuedSpinLock(
*
(PKSPIN_LOCK
*
)(PoolDesc
+
28
), &LockHandle);
}
Entry
=
(_DWORD
*
*
)MiAllocatePoolPages(PoolType &
0x61
, NumberOfBytes, v59);
if
( Entry )
break
;
if
(
*
(_BYTE
*
)PoolDesc &
1
)
{
ExReleaseFastMutex(
*
(PFAST_MUTEX
*
)(PoolDesc
+
28
));
}
/
/
省略部分代码
}
return
Entry;
}
if
( NumberOfBytes >
0xFF0
)
{
v63
=
0
;
while
(
1
)
{
if
(
*
(_BYTE
*
)PoolDesc &
1
)
{
ExAcquireFastMutex(
*
(PFAST_MUTEX
*
)(PoolDesc
+
28
));
}
else
if
( (_UNKNOWN
*
)PoolDesc
=
=
&NonPagedPoolDescriptor )
{
LockHandle.OldIrql
=
KeAcquireQueuedSpinLock(
6
);
}
else
{
KeAcquireInStackQueuedSpinLock(
*
(PKSPIN_LOCK
*
)(PoolDesc
+
28
), &LockHandle);
}
Entry
=
(_DWORD
*
*
)MiAllocatePoolPages(PoolType &
0x61
, NumberOfBytes, v59);
if
( Entry )
break
;
if
(
*
(_BYTE
*
)PoolDesc &
1
)
{
ExReleaseFastMutex(
*
(PFAST_MUTEX
*
)(PoolDesc
+
28
));
}
/
/
省略部分代码
}
return
Entry;
}
if
( !NumberOfBytes )
NumberOfBytes
=
1
;
ListNumber
=
(NumberOfBytes
+
15
) >>
3
;
NeedSize
=
(NumberOfBytes
+
15
) >>
3
;
if
( !NumberOfBytes )
NumberOfBytes
=
1
;
ListNumber
=
(NumberOfBytes
+
15
) >>
3
;
NeedSize
=
(NumberOfBytes
+
15
) >>
3
;
if
( CheckType
=
=
1
)
{
if
( var_PoolType
=
=
1
)
{
if
( ListNumber <
=
0x20
)
{
var_KPRCB
=
KeGetPcr()
-
>Prcb;
/
/
从处理器后备链表中获取符合条件的链表
LookasideList
=
var_KPRCB
-
>PPNPagedLookasideList[ListNumber
+
31
].P;
+
+
*
((_DWORD
*
)LookasideList
+
3
);
NumberOfBytesb
=
(SIZE_T)var_KPRCB;
/
/
从链表中获取内存对象
v15
=
ExInterlockedPopEntrySList(LookasideList);
v16
=
v15;
/
/
省略部分代码,找到就返回
}
/
/
如果处理器个数大于
1
if
( (unsigned __int8)KeNumberNodes >
1u
)
{
v50
=
KeGetPcr()
-
>Prcb
-
>ParentNode
-
>Color;
var_ExpNumberOfPagedPools
=
ExpNumberOfPagedPools;
PoolIndex
=
v50;
if
( v50 < ExpNumberOfPagedPools )
{
PoolDesc
=
ExpPagedPoolDescriptor[v50
+
1
];
PoolIndex
=
v50
+
1
;
/
/
省略部分代码,找到就返回
}
}
else
{
/
/
处理器个数等于
1
var_ExpNumberOfPagedPools
=
ExpNumberOfPagedPools;
}
PoolIndex
=
1
;
if
( var_ExpNumberOfPagedPools !
=
1
)
{
PoolIndex
=
+
+
ExpPoolIndex;
if
( ExpPoolIndex > var_ExpNumberOfPagedPools )
{
PoolIndex
=
1
;
ExpPoolIndex
=
1
;
}
JUMPOUT(
*
*
(_DWORD
*
*
)(ExpPagedPoolDescriptor[PoolIndex]
+
28
),
1
, &loc_47AC36);
}
/
/
获取相应的内存池对象
PoolDesc
=
ExpPagedPoolDescriptor[PoolIndex];
LABEL_17:
ListNumber
=
NeedSize;
goto LABEL_18;
}
if
( CheckType
=
=
1
)
{
if
( var_PoolType
=
=
1
)
{
if
( ListNumber <
=
0x20
)
{
var_KPRCB
=
KeGetPcr()
-
>Prcb;
/
/
从处理器后备链表中获取符合条件的链表
LookasideList
=
var_KPRCB
-
>PPNPagedLookasideList[ListNumber
+
31
].P;
+
+
*
((_DWORD
*
)LookasideList
+
3
);
NumberOfBytesb
=
(SIZE_T)var_KPRCB;
/
/
从链表中获取内存对象
v15
=
ExInterlockedPopEntrySList(LookasideList);
v16
=
v15;
/
/
省略部分代码,找到就返回
}
/
/
如果处理器个数大于
1
if
( (unsigned __int8)KeNumberNodes >
1u
)
{
v50
=
KeGetPcr()
-
>Prcb
-
>ParentNode
-
>Color;
var_ExpNumberOfPagedPools
=
ExpNumberOfPagedPools;
PoolIndex
=
v50;
if
( v50 < ExpNumberOfPagedPools )
{
PoolDesc
=
ExpPagedPoolDescriptor[v50
+
1
];
PoolIndex
=
v50
+
1
;
/
/
省略部分代码,找到就返回
}
}
else
{
/
/
处理器个数等于
1
var_ExpNumberOfPagedPools
=
ExpNumberOfPagedPools;
}
PoolIndex
=
1
;
if
( var_ExpNumberOfPagedPools !
=
1
)
{
PoolIndex
=
+
+
ExpPoolIndex;
if
( ExpPoolIndex > var_ExpNumberOfPagedPools )
{
PoolIndex
=
1
;
ExpPoolIndex
=
1
;
}
JUMPOUT(
*
*
(_DWORD
*
*
)(ExpPagedPoolDescriptor[PoolIndex]
+
28
),
1
, &loc_47AC36);
}
/
/
获取相应的内存池对象
PoolDesc
=
ExpPagedPoolDescriptor[PoolIndex];
LABEL_17:
ListNumber
=
NeedSize;
goto LABEL_18;
}
else
{
if
( var_PoolType
=
=
1
&& NeedSize <
=
0x20
)
{
KPRCB
=
KeGetPcr()
-
>Prcb;
var_LookasideList
=
KPRCB
-
>PPLookasideList[NeedSize
+
15
].P;
+
+
*
((_DWORD
*
)var_LookasideList
+
3
);
NumberOfBytesa
=
(SIZE_T)KPRCB;
v8
=
ExInterlockedPopEntrySList(var_LookasideList);
v9
=
v8;
/
/
省略代码,找到则返回结果
}
if
( (unsigned
int
)ExpNumberOfNonPagedPools >
1
)
{
tmpPoolIndex
=
KeGetPcr()
-
>Prcb
-
>ParentNode
-
>Color;
PoolIndex
=
tmpPoolIndex;
if
( tmpPoolIndex >
=
ExpNumberOfNonPagedPools )
{
PoolIndex
=
ExpNumberOfNonPagedPools
-
1
;
tmpPoolIndex
=
ExpNumberOfNonPagedPools
-
1
;
}
/
/
获取非分页内存对象
PoolDesc
=
ExpNonPagedPoolDescriptor[tmpPoolIndex];
goto LABEL_17;
}
}
else
{
if
( var_PoolType
=
=
1
&& NeedSize <
=
0x20
)
{
KPRCB
=
KeGetPcr()
-
>Prcb;
var_LookasideList
=
KPRCB
-
>PPLookasideList[NeedSize
+
15
].P;
+
+
*
((_DWORD
*
)var_LookasideList
+
3
);
NumberOfBytesa
=
(SIZE_T)KPRCB;
v8
=
ExInterlockedPopEntrySList(var_LookasideList);
v9
=
v8;
/
/
省略代码,找到则返回结果
}
if
( (unsigned
int
)ExpNumberOfNonPagedPools >
1
)
{
tmpPoolIndex
=
KeGetPcr()
-
>Prcb
-
>ParentNode
-
>Color;
PoolIndex
=
tmpPoolIndex;
if
( tmpPoolIndex >
=
ExpNumberOfNonPagedPools )
{
PoolIndex
=
ExpNumberOfNonPagedPools
-
1
;
tmpPoolIndex
=
ExpNumberOfNonPagedPools
-
1
;
}
/
/
获取非分页内存对象
PoolDesc
=
ExpNonPagedPoolDescriptor[tmpPoolIndex];
goto LABEL_17;
}
}
ListHead
=
&PoolDesc
-
>ListHeads[ListNumber];
do {
/
/
检查链表中是否有可用的内存块, FALSE为有
if
(PrivateIsListEmpty (ListHead)
=
=
FALSE) {
/
/
获取内存块
Block
=
PrivateRemoveHeadList (ListHead);
/
/
指向POOL_HEADER,此处的POOL_OVERHEAD为
0x8
Entry
=
(PPOOL_HEADER)((PCHAR)Block
-
POOL_OVERHEAD);
/
/
内存块大小是和需要的内存大小不一致
if
(Entry
-
>BlockSize !
=
NeededSize) {
if
(Entry
-
>PreviousSize
=
=
0
) {
/
/
页面开始处,取前面一块作为返回结果的内存块,保存在Entry中
/
/
剩余部分保存在SplitEntry中
SplitEntry
=
(PPOOL_HEADER)((PPOOL_BLOCK)Entry
+
NeededSize);
SplitEntry
-
>BlockSize
=
(USHORT)(Entry
-
>BlockSize
-
NeededSize);
SplitEntry
-
>PreviousSize
=
(USHORT) NeededSize;
/
/
获取下一内存块
NextEntry
=
(PPOOL_HEADER)((PPOOL_BLOCK)SplitEntry
+
SplitEntry
-
>BlockSize);
if
(PAGE_END(NextEntry)
=
=
FALSE) {
NextEntry
-
>PreviousSize
=
SplitEntry
-
>BlockSize;
}
}
else
{
/
/
非页面开始处,取后面一块作为返回结果的内存块,保存在Entry中
/
/
剩余部分保存在SplitEntry中
SplitEntry
=
Entry;
Entry
-
>BlockSize
=
(USHORT)(Entry
-
>BlockSize
-
NeededSize);
Entry
=
(PPOOL_HEADER)((PPOOL_BLOCK)Entry
+
Entry
-
>BlockSize);
Entry
-
>PreviousSize
=
SplitEntry
-
>BlockSize;
NextEntry
=
(PPOOL_HEADER)((PPOOL_BLOCK)Entry
+
NeededSize);
if
(PAGE_END(NextEntry)
=
=
FALSE) {
NextEntry
-
>PreviousSize
=
(USHORT) NeededSize;
}
}
/
/
为内存块赋值
Entry
-
>BlockSize
=
(USHORT) NeededSize;
SplitEntry
-
>PoolType
=
0
;
Index
=
SplitEntry
-
>BlockSize;
if
((POOL_OVERHEAD !
=
POOL_SMALLEST_BLOCK) ||
(SplitEntry
-
>BlockSize !
=
1
)) {
/
/
将剩余内存块加入到链表中
PrivateInsertTailList(&PoolDesc
-
>ListHeads[Index
-
1
], ((PLIST_ENTRY)((PCHAR)SplitEntry
+
POOL_OVERHEAD)));
}
}
/
/
为申请的内存块的POOL_HEADER赋值
Entry
-
>PoolType
=
(UCHAR)(((PoolType & (BASE_POOL_TYPE_MASK | POOL_QUOTA_MASK | SESSION_POOL_MASK | POOL_VERIFIER_MASK))
+
1
) | POOL_IN_USE_MASK);
InterlockedIncrement ((PLONG)&PoolDesc
-
>RunningAllocs);
InterlockedExchangeAddSizeT (&PoolDesc
-
>TotalBytes,
Entry
-
>BlockSize << POOL_BLOCK_SHIFT);
Entry
-
>PoolTag
=
Tag;
((PULONGLONG)((PCHAR)Entry
+
CacheOverhead))[
0
]
=
0
;
/
/
将申请到的内存地址返回,此时的CacheOverhead为
0x8
,所以会略过POOL_HEADER
return
(PCHAR)Entry
+
CacheOverhead;
}
/
/
指向下一个链表
ListHead
+
=
1
;
/
/
是否是最后一个链表
}
while
(ListHead !
=
&PoolDesc
-
>ListHeads[POOL_LIST_HEADS]);
/
/
如果没有找到可用内存块,就通过MiAllocatePoolPages来申请一块内存
Entry
=
(PPOOL_HEADER) MiAllocatePoolPages (RequestType, PAGE_SIZE);
/
/
为申请的内存块赋值
Entry
-
>Ulong1
=
0
;
Entry
-
>PoolIndex
=
(UCHAR) PoolIndex;
Entry
-
>BlockSize
=
(USHORT) NeededSize;
Entry
-
>PoolType
=
(UCHAR)(((PoolType & (BASE_POOL_TYPE_MASK | POOL_QUOTA_MASK | SESSION_POOL_MASK | POOL_VERIFIER_MASK))
+
1
) | POOL_IN_USE_MASK);
/
/
指向剩余内存块
SplitEntry
=
(PPOOL_HEADER)((PPOOL_BLOCK)Entry
+
NeededSize);
SplitEntry
-
>Ulong1
=
0
;
Index
=
(PAGE_SIZE
/
sizeof(POOL_BLOCK))
-
NeededSize;
SplitEntry
-
>BlockSize
=
(USHORT) Index;
SplitEntry
-
>PreviousSize
=
(USHORT) NeededSize;
SplitEntry
-
>PoolIndex
=
(UCHAR) PoolIndex;
InterlockedIncrement ((PLONG)&PoolDesc
-
>TotalPages);
NeededSize <<
=
POOL_BLOCK_SHIFT;
InterlockedExchangeAddSizeT (&PoolDesc
-
>TotalBytes, NeededSize);
if
((POOL_OVERHEAD !
=
POOL_SMALLEST_BLOCK) ||
(SplitEntry
-
>BlockSize !
=
1
)) {
/
/
将剩余的内存块加入到链表中
PrivateInsertTailList(&PoolDesc
-
>ListHeads[Index
-
1
], ((PLIST_ENTRY)((PCHAR)SplitEntry
+
POOL_OVERHEAD)));
}
InterlockedIncrement ((PLONG)&PoolDesc
-
>RunningAllocs);
/
/
指向申请的内存块的内存地址,此时的CacheOverhead为
0x8
,所以会略过POOL_HEADER
Block
=
(PVOID) ((PCHAR)Entry
+
CacheOverhead);
Entry
-
>PoolTag
=
Tag;
return
Block;
ListHead
=
&PoolDesc
-
>ListHeads[ListNumber];
do {
/
/
检查链表中是否有可用的内存块, FALSE为有
if
(PrivateIsListEmpty (ListHead)
=
=
FALSE) {
/
/
获取内存块
Block
=
PrivateRemoveHeadList (ListHead);
/
/
指向POOL_HEADER,此处的POOL_OVERHEAD为
0x8
Entry
=
(PPOOL_HEADER)((PCHAR)Block
-
POOL_OVERHEAD);
/
/
内存块大小是和需要的内存大小不一致
if
(Entry
-
>BlockSize !
=
NeededSize) {
if
(Entry
-
>PreviousSize
=
=
0
) {
/
/
页面开始处,取前面一块作为返回结果的内存块,保存在Entry中
/
/
剩余部分保存在SplitEntry中
SplitEntry
=
(PPOOL_HEADER)((PPOOL_BLOCK)Entry
+
NeededSize);
SplitEntry
-
>BlockSize
=
(USHORT)(Entry
-
>BlockSize
-
NeededSize);
SplitEntry
-
>PreviousSize
=
(USHORT) NeededSize;
/
/
获取下一内存块
NextEntry
=
(PPOOL_HEADER)((PPOOL_BLOCK)SplitEntry
+
SplitEntry
-
>BlockSize);
if
(PAGE_END(NextEntry)
=
=
FALSE) {
NextEntry
-
>PreviousSize
=
SplitEntry
-
>BlockSize;
}
}
else
{
/
/
非页面开始处,取后面一块作为返回结果的内存块,保存在Entry中
/
/
剩余部分保存在SplitEntry中
SplitEntry
=
Entry;
Entry
-
>BlockSize
=
(USHORT)(Entry
-
>BlockSize
-
NeededSize);
Entry
=
(PPOOL_HEADER)((PPOOL_BLOCK)Entry
+
Entry
-
>BlockSize);
Entry
-
>PreviousSize
=
SplitEntry
-
>BlockSize;
NextEntry
=
(PPOOL_HEADER)((PPOOL_BLOCK)Entry
+
NeededSize);
if
(PAGE_END(NextEntry)
=
=
FALSE) {
NextEntry
-
>PreviousSize
=
(USHORT) NeededSize;
}
}
/
/
为内存块赋值
Entry
-
>BlockSize
=
(USHORT) NeededSize;
SplitEntry
-
>PoolType
=
0
;
Index
=
SplitEntry
-
>BlockSize;
if
((POOL_OVERHEAD !
=
POOL_SMALLEST_BLOCK) ||
(SplitEntry
-
>BlockSize !
=
1
)) {
/
/
将剩余内存块加入到链表中
PrivateInsertTailList(&PoolDesc
-
>ListHeads[Index
-
1
], ((PLIST_ENTRY)((PCHAR)SplitEntry
+
POOL_OVERHEAD)));
}
}
/
/
为申请的内存块的POOL_HEADER赋值
Entry
-
>PoolType
=
(UCHAR)(((PoolType & (BASE_POOL_TYPE_MASK | POOL_QUOTA_MASK | SESSION_POOL_MASK | POOL_VERIFIER_MASK))
+
1
) | POOL_IN_USE_MASK);
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]CVE-2022-21882提权漏洞学习笔记 16383
- [原创]CVE-2021-1732提权漏洞学习笔记 19489
- [原创]CVE-2014-1767提权漏洞学习笔记 15192
- [原创]CVE-2018-8453提权漏洞学习笔记 18526
- [原创]CVE-2020-1054提权漏洞学习笔记 13542