内核句柄表与创建句柄Word文档格式.docx
《内核句柄表与创建句柄Word文档格式.docx》由会员分享,可在线阅读,更多相关《内核句柄表与创建句柄Word文档格式.docx(13页珍藏版)》请在冰豆网上搜索。
nt!
_HANDLE_TABLE
+0x000TableCode:
Uint4B//指向第一层局部表,并记录层数
+0x004QuotaProcess:
Ptr32_EPROCESS//指向进程_EPROCESS块
+0x008UniqueProcessId:
Ptr32Void//进程ID
+0x03cHandleCount:
Int4B//句柄计数,当前使用句柄个数
dt_EPROCESS//进程_EPROCESS块信息
_EPROCESS
+0x084UniqueProcessId:
Ptr32Void//进程ID
+0x0c4ObjectTable:
Ptr32_HANDLE_TABLE//指向_HANDLE_TABLE结构
2.句柄的数据结构
内核与SDK中定义句柄都为:
typedefvoid*HANDLE;
表明句柄是一个无符号整数,实际上有效句柄的值时有范围的,大家想想如果采用数组来存储句柄需要耗费很大的内存,Windows句柄表使用了稀疏数组.
2.1XP/2003句柄表项:
先看下句柄表中存放的是什么?
句柄表主要是存放的是对象的地址与属性信息,当然还要存放句柄表相关一些信息(审计,空闲项),每个句柄表项是由_HANDLE_TABLE_ENTRY描述的,_HANDLE_TABLE_ENTRY占8字节,定义如下:
dt_HANDLE_TABLE_ENTRY
_HANDLE_TABLE_ENTRY
+0x000Object:
Ptr32Void//对象指针
+0x000ObAttributes:
Uint4B
+0x000InfoTable:
Ptr32_HANDLE_TABLE_ENTRY_INFO
+0x000Value:
+0x004GrantedAccess:
+0x004GrantedAccessIndex:
Uint2B
+0x006CreatorBackTraceIndex:
+0x004NextFreeTableEntry:
Int4B
由于_HANDLE_TABLE_ENTRY有些联合体,不好理解,源码定义如下:
typedefstruct_HANDLE_TABLE_ENTRY{
union{
PVOIDObject;
//对象指针
ULONGObAttributes;
//对象属性
PHANDLE_TABLE_ENTRY_INFOInfoTable;
ULONG_PTRValue;
//值
};
union{
union{
ACCESS_MASKGrantedAccess;
//访问掩码
struct{
USHORTGrantedAccessIndex;
USHORTCreatorBackTraceIndex;
LONGNextFreeTableEntry;
//下一个空闲的句柄表项,空闲链表索引
};
}HANDLE_TABLE_ENTRY,*PHANDLE_TABLE_ENTRY;
表示的意义:
1.对象指针Object有效则第二个域为访问掩码GrantedAccess
2.第一个域为0,第二个域可能是NextFreeTableEntry,也可能为审计,后面会有相关算法用到这个域,要根据上下文来判断。
这里的Object并不是“真正”的对象指针,而是包括了对象的指针域对象的属性域,由于在内核中对象总是8字节对齐的,那么指向对象的指针最低3位总是0,微软把这3位也利用上,Object的最低3位做为对象的属性,看下面的一组宏定义:
#defineOBJ_HANDLE_ATTRIBUTES(OBJ_PROTECT_CLOSE|OBJ_INHERIT|OBJ_AUDIT_OBJECT_CLOSE)
第0位OBJ_PROTECT_CLOSE:
句柄表项是否被锁定,1锁定,0未锁定
第1位OBJ_INHERIT:
指向该进程所创建的子进程是否可以继承该句柄,既是否将该句柄项拷贝到它的句柄表中
第2位OBJ_AUDIT_OBJECT_CLOSE:
关闭该对象时是否产生一个审计事件
2.2XP/2003句柄表项:
Windows为了节省空间采用动态扩展结构,类似于页表结构,最大可扩展3层表._HANDLE_TABLE.TableCode存放了第一层局部表的基址指针和层数,微软在这里设计很精妙,由于效率32位地址都以4对齐,最低2位为0,微软把_HANDLE_TABLE.TableCode的最低两位作为句柄表层数的纪录,即00一层表,
01二层表10三层表.句柄表的结构图如下:
一层表:
两层表时:
三层表时:
有上图所示,最低层局部表都是是存放着_HANDLE_TABLE_ENTTY结构,中间层和最高层都是存放着页表指针,当句柄增加时,便会判断是否需要扩展。
2.3XP/2003句柄表表项计数:
句柄表是动态扩展,当引用资源足够多时,句柄的数目也在增加,当到一定数目时,句柄表便会扩展,扩展的标准是什么?
下面一系列宏给出了定义
(1)最低层存放句柄表项数:
每个最底层页表存放的是_HANDLE_TABLE_ENTRY结构,即4096/8=512,其中第一项做审计用,最多有511个有效项
#defineLOWLEVEL_COUNT(TABLE_PAGE_SIZE/sizeof(HANDLE_TABLE_ENTRY))
(2)中间层可以存放的项数
中间层存放的页表指针,最多有4028/4=1024
#defineMIDLEVEL_COUNT(PAGE_SIZE/sizeof(PHANDLE_TABLE_ENTRY))
(3)可分配的最大句柄值,不是我们想象的无符号整数最大值
#defineMAX_HANDLES(1<
<
24)//224
(4)最高层最大项数:
#defineHIGHLEVEL_COUNTMAX_HANDLES/(LOWLEVEL_COUNT*MIDLEVEL_COUNT)
即224/(1024*512)=25=32,在句柄表结构图已经说明3层表第一层表最大有32项
通过上面计算:
二级表最大可以存放511*1024=523264个对象引用,没有特殊情况一般来说已经够了,所以我们一般只能观察到一层,两层句柄表
3.nt!
PspCreateProcess中创建进程句柄表
3.1在创建进程时初始化进程对象并创建进程句柄表
创建进程时先创建进程对象,再创建进程句柄表,即nt!
PspCreateProcess->
ObInitProcess->
ExCreateHandleTable,创建句柄表的核心流程图如下:
分配进程句柄表例程步骤:
1.调用ExpAllocateHandleTable分配句柄表及_HANDLE_TABLE结构
2.插入到进程句柄表链表
函数描述:
;
RoutineDescription:
Thisfunctionallocateandinitializeanewnewhandletable
这个例程分配并初始化一个新的句柄表(_HANDLE_TABLE)
Arguments:
Process-Suppliesanoptionalpointertotheprocessagainstwhichquota
willbecharged.
提供一个将要记录相关信息(对象)的进程的指针
ReturnValue:
Ifahandletableissuccessfullycreated,thentheaddressofthe
handletableisreturnedasthefunctionvalue.Otherwise,avalue
NULLisreturned.
如果成功函数返回handletable的地址,负责返回0
_HANDLE_TABLE*__stdcallExCreateHandleTable(_EPROCESS*pProcess)
核心算法分析:
由于进程句柄表是一个双向链表结构,是系统很重要的数据结构,所以必须考虑同步问题,只有在加锁的情况下才能修改
通过ExpAllocateHandleTable分配进程句柄表:
push1;
DoInit
push[ebp+pProcess];
pProcess
call_ExpAllocateHandleTable@8;
创建句柄表例程
movebx,eax
testebx,ebx;
判断ExpAllocateHandleTable是否成功
jzshortALLOC_HANDLE_TABLE_UNSUCCESS
句柄表是进程句柄链表是内核重要结构,有同步问题存在,这里给句柄表上锁
moveax,0
系统句柄链表的改变必须要实现同步操作,所以要使用锁
movecx,offset_HandleTableListLock
lockbts[ecx],eax;
加锁
加入进程句柄表链表
movecx,_HandleTableListHead.Blink
leaeax,[ebx+_HANDLE_TABLE.HandleTableList.Flink
取_Handle_TABLE.HandleTableList的Flink指针
mov[eax+_LIST_ENTRY.Flink],ecx
_HANDLE_TABLE.HandleTable