进程句柄表与创建句柄表
我们编写Windows程序中经常使用到内核对象,特别是句柄这个概念,通过句柄可以对内核对象进行访问,那句柄到底是什么?本文将会从内核来说明这个概念。
Windows采取了面向对象设计,内核中有一个的模块来管理内核对象,有很多资料都是说是“对象管理器”,本文也采用这个概念。对象管理器用来管理内核对象信息和记录内核对象的使用情况,包括引用计数。
每个进程都要创建一个句柄列表,这些句柄指向各种系统资源,比如信号量,线程,和文件等,进程中的所有线程都可以访问这些资源性),如下图所示,进程和资源:
1.进程与句柄表数据关系
在用户模式下如果调用CloseHanele( )表示不再使用这个对象,在内核中进程便会删除句柄(释放对象引用);对象管理器也会将内核对象的引用计数也会减一,当对象的句柄引用为0时,对象管理器便会释放这个对象。
句柄表最基本作用就是句柄与目标对象之间的映射表,下图是进程与句柄的简化模型图(有些数据域要经过处理):
_HANDLE_TABLE是句柄表的信息的结构体,在内核中句柄是句柄表中表项的索引,在这里可以简单的理解,由索引(句柄)在句柄表中查找到进程引用的内核对象.
在Windbg中查看_HANDLE_TABLE(这里例出部分有意义的项)
kd> dt _HANDLE_TABLE
nt!_HANDLE_TABLE
+0x000 TableCode : Uint4B //指向第一层局部表,并记录层数
+0x004 QuotaProcess : Ptr32 _EPROCESS //指向进程_EPROCESS块
+0x008 UniqueProcessId : Ptr32 Void //进程ID
+0x03c HandleCount : Int4B //句柄计数,当前使用句柄个数
kd> dt _EPROCESS //进程_EPROCESS块信息
nt!_EPROCESS
+0x084 UniqueProcessId : Ptr32 Void //进程ID
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE //指向_HANDLE_TABLE结构
2.句柄的数据结构
内核与SDK中定义句柄都为: typedef void *HANDLE; 表明句柄是一个无符号整数,实际上有效句柄的值时有范围的,大家想想如果采用数组来存储句柄需要耗费很大的内存,Windows句柄表使用了稀疏数组.
2.1XP/2003句柄表项:
先看下句柄表中存放的是什么?句柄表主要是存放的是对象的地址与属性信息,当然还要存放句柄表相关一些信息(审计,空闲项),每个句柄表项是由_HANDLE_TABLE_ENTRY 描述的,_HANDLE_TABLE_ENTRY占8字节,定义如下:
kd> dt _HANDLE_TABLE_ENTRY
nt!_HANDLE_TABLE_ENTRY
+0x000 Object : Ptr32 Void //对象指针
+0x000 ObAttributes : Uint4B
+0x000 InfoTable : Ptr32 _HANDLE_TABLE_ENTRY_INFO
+0x000 Value : Uint4B
+0x004 GrantedAccess : Uint4B
+0x004 GrantedAccessIndex : Uint2B
+0x006 CreatorBackTraceIndex : Uint2B
+0x004 NextFreeTableEntry : Int4B
由于_HANDLE_TABLE_ENTRY有些联合体,不好理解,源码定义如下:
typedef struct _HANDLE_TABLE_ENTRY {
union {
PVOID Object; //对象指针
ULONG ObAttributes; //对象属性
PHANDLE_TABLE_ENTRY_INFO InfoTable;
ULONG_PTR Value; //值
};
union {
union {
ACCESS_MASK GrantedAccess; //访问掩码
struct {
USHORT GrantedAccessIndex;
USHORT CreatorBackTraceIndex;
};
};
LONG NextFreeTableEntry;//下一个空闲的句柄表项,空闲链表索引
};
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
push 1 ; DoInit
push [ebp+pProcess] ; pProcess
call _ExpAllocateHandleTable@8 ; 创建句柄表例程
mov ebx, eax
test ebx, ebx ; 判断ExpAllocateHandleTable是否成功
jz short ALLOC_HANDLE_TABLE_UNSUCCESS
mov eax, 0
; 系统句柄链表的改变必须要实现同步操作,所以要使用锁
mov ecx, offset _HandleTableListLock
lock bts [ecx], eax ; 加锁
mov ecx, _HandleTableListHead.Blink
lea eax, [ebx+_HANDLE_TABLE.HandleTableList.Flink
;取_Handle_TABLE.HandleTableList的Flink指针
mov [eax+_LIST_ENTRY.Flink], ecx
;_HANDLE_TABLE.HandleTableList.Flink= HADLETABLELIST.BLINK
mov dword ptr [eax], offset _HandleTableListHead.Flink HandleTalbeListHead
; 取得句柄表链表头节点的头指针地址
mov [ecx], eax
mov _HandleTableListHead.Blink, eax
;设置,HandleTableListHead.BLink =_HANDLE_TABLE.HandleTableList.Flink
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!