对象与句柄
句柄的定义
每个进程都有一个表,这个表中的每一项保存着需要访问的内核对象信息,系统为用户态应用程序提供一个“句柄”值,这个句柄值实际上是这个表的某种索引,通过这个值,可以在表中定位到具体需要访问的内核对象信息。用户态程序通过API创建或打开一个内核对象时,这个表中的信息会增加一项,用来描述这个内核对象的信息,并产生一个相应的句柄值,用户态程序把这个句柄传递到相应API,API进入内核后,通过这个句柄值定位到需要操作的内核对象,对内核对象进行相应的操作。
typedef void *HANDLE; |
内核对象的引用计数
每个内核对象存在两个计数,一个称为“句柄计数”,另一个称为“指针计数”,句柄计数是指这个内核对象被多少个句柄值所指向,如在用户态中创建一个命名的EVENT对象,获取到一个句柄,那么这个EVENT的句柄计数就是1,当其他程序通过该EVENT名字打开该EVENT时,会获取到另外一个句柄,这时候,句柄计数等于2。指针计数是在句柄计数基础上递增的计数,在刚才所提的例子中,句柄计数等于2,指针计数也等于2,句柄计数的增加,会相应导致指针计数增加,同理,句柄计数的减少,会相应导致指针计数减少,但指针计数可以独立增加与减少而不影响句柄计数。当一个对象的指针计数等于0的时候,这个对象会被系统释放。请注意,不同操作系统,系统对引用计数值的管理稍有不同。
句柄操作CODE
CODE
|
逻辑分析
ZwCreateEvent成功后,句柄会保存在hCreateEvent变量中,这个句柄是一个内核句柄。接着代码中调用ObReferenceObåjectByHandle函数,获取hCreateEvent句柄对应的EVENT对象指针。
例子代码在调用ObReferenceObjectByHandle函数成功后,使用ZwOpenEvent函数再次打开刚才创建的EVENT并获取一个句柄,保存在hOpenEvent变量中;接着通过hOpenEvent的值,使用ObReferenceObjectByHandle获取EVENT的对象指针,保存在pOpenEventObject变量中。
所以最后会产生两个句柄以及两个对象指针。代码通过DbgPrint函数把这些信息输出:
Create Handle : FFFFFFFF80000B90, Create Pointer = FFFFD1898059C260 |
ZwCreateEvent 函数
ZwCreateEvent 函数创建对象 EVENT 对象
NASTATUS ZwCreateEvent( |
EventHandle 参数用于保存EVENT的句柄;
DesiredAccess 参数 表示EVENT的权限;
ObjectAttributes 参数表示创建EVENT的属性信息;
EventType 参数表示EVENT的类型,取值为SynchronizationEvent或者NotificationEvent,分别表示同步类型EVENT以及通告类型的EVENT;
InitialState 参数 表示EVENT的初始状态,TRUE表示EVENT被创建后的状态为“有信号”,否则为“无信号”。
注意 :ObjectAttributes参数的用法最为重要,ObjectAttributes描述了需要打开或创建的内核对象属性,大部分涉及打开或创建内核对象的API都会有ObjectAttributes参数。
OBJECT_ATTRIBUTES 结构体
OBJECT_ATTRIBUTES 结构描述内核对象的属性;属性包括对象的名字,根目录
的句柄,对象的安全描述。
typedef struct _OBJECT_ATTRIBUTES |
Length 成员表示结构体的大小,一般等于sizeof(OBJECT_ATTRIBUTES),RootDirectory 表示对象的根目录句柄,可以为NULL。
ObjectName 是一个UNICODE_STRING的指针,表示对象的路径或名字,RootDirectory 与 ObjectName 共同组成了一个完整的对象全路径名字。Attributes 表示对象打开或创建时的具体属性,常见的有:
- OBJ_INHERIT 表示内核对象的句柄可以被继承
- OBJ_CASE_INSENSITIVE 表示内核对象的名字不区分大小写。
- OBJ_KERNEL_HANDLE 表示使用内核句柄,即句柄存在于系统句柄表中。
- SecurityDescriptor以及SecurityQualityOfService与安全性相关,可以暂设置成NULL。
ObReferenceObjectByHandle 函数
ObReferenceObjectByHandle 函数用于获取句柄对应的对象的指针。
ObReferenceObjectByHandle 函数成功则返回STATUS_SUCCESS,失败则返回错误码。函数原型如下:
NTSTATUS ObReferenceObjectByHandle( |
Handle 参数表示句柄值。
DesiredAccess 参数表示需要获取此对象的权限,针对不同类型的对象,这个权限的值不同,对于本例的EVENT对象来说,这个值可以传递EVENT_ALL_ACCESS,表示EVENT的所有权限。
ObjectType 参数 表示对象的类型,不同的对象用不同的“对象类型”来表示,
AccessMode 参数表示访问模式,可以是KernelMode或UserMode,分别表示用户态与内核态。如果参数Handle是内核句柄,则应该传递KernelMode。参数Object是返回参数,若函数执行成功则该参数保存对象的指针。HandleInformation 参数暂时没用,可以设置为NULL。