2.3XP/2003句柄表表项计数:
句柄表是动态扩展,当引用资源足够多时,句柄的数目也在增加,当到一定数目时,句柄表便会扩展,扩展的标准是什么?下面一系列宏给出了定义
(1)最低层存放句柄表项数:
每个最底层页表存放的是_HANDLE_TABLE_ENTRY结构, 即4096/8 = 512,其中第一项做审计用,最多有511个有效项
#define LOWLEVEL_COUNT (TABLE_PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY))
(2)中间层可以存放的项数
中间层存放的页表指针,最多有4028 / 4 =1024
#define MIDLEVEL_COUNT (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY))
(3)可分配的最大句柄值,不是我们想象的无符号整数最大值
#define MAX_HANDLES (1<<24) //224
(4)最高层最大项数:
#define HIGHLEVEL_COUNT MAX_HANDLES / (LOWLEVEL_COUNT * MIDLEVEL_COUNT)
即224/(1024*512) = 25 =32,在句柄表结构图已经说明3层表第一层表最大有32项
通过上面计算:二级表最大可以存放511 * 1024 = 523264个对象引用,没有特殊情况一般来说已经够了,所以我们一般只能观察到一层,两层句柄表
3. nt!PspCreateProcess中创建进程句柄表
3.1在创建进程时初始化进程对象并创建进程句柄表
创建进程时先创建进程对象,再创建进程句柄表,即nt!PspCreateProcess->nt!ObInitProcess->nt!ExCreateHandleTable,创建句柄表的核心流程图如下:
分配进程句柄表例程步骤:
1.调用ExpAllocateHandleTable分配句柄表及_HANDLE_TABLE结构
2.插入到进程句柄表链表
函数描述:
; Routine Description:
; This function allocate and initialize a new new handle table
; 这个例程分配并初始化一个新的句柄表(_HANDLE_TABLE)
; Arguments:
; Process - Supplies an optional pointer to the process against which quota
; will be charged.
; 提供一个将要记录相关信息(对象)的进程的指针
; Return Value:
; If a handle table is successfully created, then the address of the
; handle table is returned as the function value. Otherwise, a value
; NULL is returned.
; 如果成功函数返回handle table的地址,负责返回0
_HANDLE_TABLE *__stdcall ExCreateHandleTable(_EPROCESS *pProcess)
nt!ExpAllocateHandleTable的核心流程:
ExpAllocateHandleTable例程:
1.分配_HANDLE_TABLE内存池与分配一页内存池作为第一层句柄表
2.初始化句柄表
3.建立进程与句柄表的映射关系
函数描述:
; Routine Description:
;
; This worker routine will allocate and initialize a new handle table
; structure. The new structure consists of the basic handle table
; struct plus the first allocation needed to store handles. This is
; really one page divided up into the top level node, the first mid
; level node, and one bottom level node.
; 例程分配并初始化一个新的句柄表结构,加入一些存储句柄的必要的基本结构信息
; 到新分配的句柄表结构中.这里准备一个页内存分割给高层节点,第一个中间层节点和一个
; 低层节点
; Arguments:
; Process - Optionally supplies the process to charge quota for the
; handle table
; 提供审计配额信息的进程(并不是指当前进程)的指针
; DoInit - If FALSE then we are being called by duplicate and we don't need
; the free list built for the caller
; 如果FALSE(copy)时同样会被调用,并且调用者不需要释放创建建的表
; Return Value:
; A pointer to the new handle table or NULL if unsuccessful at getting
; pool.
; 一个指向句柄表(HANDLE_TABLE)的指针,如果NULL表示获取内核内存池失败
; _HANDLE_TABLE *__stdcall ExpAllocateHandleTable(_EPROCESS *pProcess, char DoInit)
核心算法分析:
分配_HANDLE_TABLE结构内存池: