内核句柄表与创建句柄.docx

上传人:b****2 文档编号:1989630 上传时间:2022-10-25 格式:DOCX 页数:13 大小:335.99KB
下载 相关 举报
内核句柄表与创建句柄.docx_第1页
第1页 / 共13页
内核句柄表与创建句柄.docx_第2页
第2页 / 共13页
内核句柄表与创建句柄.docx_第3页
第3页 / 共13页
内核句柄表与创建句柄.docx_第4页
第4页 / 共13页
内核句柄表与创建句柄.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

内核句柄表与创建句柄.docx

《内核句柄表与创建句柄.docx》由会员分享,可在线阅读,更多相关《内核句柄表与创建句柄.docx(13页珍藏版)》请在冰豆网上搜索。

内核句柄表与创建句柄.docx

内核句柄表与创建句柄

进程句柄表与创建句柄表

我们编写Windows程序中经常使用到内核对象,特别是句柄这个概念,通过句柄可以对内核对象进行访问,那句柄到底是什么?

本文将会从内核来说明这个概念。

Windows采取了面向对象设计,内核中有一个的模块来管理内核对象,有很多资料都是说是“对象管理器”,本文也采用这个概念。

对象管理器用来管理内核对象信息和记录内核对象的使用情况,包括引用计数。

每个进程都要创建一个句柄列表,这些句柄指向各种系统资源,比如信号量,线程,和文件等,进程中的所有线程都可以访问这些资源性),如下图所示,进程和资源:

 

1.进程与句柄表数据关系

在用户模式下如果调用CloseHanele()表示不再使用这个对象,在内核中进程便会删除句柄(释放对象引用);对象管理器也会将内核对象的引用计数也会减一,当对象的句柄引用为0时,对象管理器便会释放这个对象。

句柄表最基本作用就是句柄与目标对象之间的映射表,下图是进程与句柄的简化模型图(有些数据域要经过处理):

_HANDLE_TABLE是句柄表的信息的结构体,在内核中句柄是句柄表中表项的索引,在这里可以简单的理解,由索引(句柄)在句柄表中查找到进程引用的内核对象.

在Windbg中查看_HANDLE_TABLE(这里例出部分有意义的项)

kd>dt_HANDLE_TABLE

nt!

_HANDLE_TABLE

+0x000TableCode:

Uint4B//指向第一层局部表,并记录层数

+0x004QuotaProcess:

Ptr32_EPROCESS//指向进程_EPROCESS块

+0x008UniqueProcessId:

Ptr32Void//进程ID

+0x03cHandleCount:

Int4B//句柄计数,当前使用句柄个数

kd>dt_EPROCESS//进程_EPROCESS块信息

nt!

_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字节,定义如下:

kd>dt_HANDLE_TABLE_ENTRY

nt!

_HANDLE_TABLE_ENTRY

+0x000Object:

Ptr32Void//对象指针

+0x000ObAttributes:

Uint4B

+0x000InfoTable:

Ptr32_HANDLE_TABLE_ENTRY_INFO

+0x000Value:

Uint4B

+0x004GrantedAccess:

Uint4B

+0x004GrantedAccessIndex:

Uint2B

+0x006CreatorBackTraceIndex:

Uint2B

+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_ENTRY

 

_HANDLE_TABLE_ENTRY

两层表时:

_HANDLE_TABLE_ENTRY

_HANDLE_TABLE_ENTRY

三层表时:

_HANDLE_TABLE_ENTRY

_HANDLE_TABLE_ENTRY

有上图所示,最低层局部表都是是存放着_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->nt!

ObInitProcess->nt!

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1