内核对象
1、何为内核对象
每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问。这个内存块是一个数据结构,其成员维护着与对象相关的信息。少数成员(安全描述符和使用计数等)是所有对象都有的,但其他大多数成员都是不同类型的对象特有的。
应用程序通过Windows提供的一组函数来操作内核对象。调用一个会创建内核对象的函数后,函数会返回一个句柄(handle),它标识了所创建的对象。可以将句柄想象为一个不透明(opaque)的值,为了增强操作系统的可靠性,这些句柄值是与进程相关的。
1)使用计数
内核对象的所有者是操作系统内核,而非进程。内核对象的生命周期可能会长于创建它的那个进程。
每个内核对象都有一个使用计数(usage count),操作系统内核通过使用计数可以知道当前有多少个进程正在使用该对象。初次创建一个对象的时候,其使用计数被设计为1,其他的进程对该对象进行访问时,使用计数就会递增,进程中止时,操作系统内核会自动递减该对象的使用计数,如果一旦对象的使用计数变为0,操作系统内核就会销毁该对象。
2)内核对象的安全性
内核对象可以用一个安全描述符(security descriptor,SD)来保护。安全描述符描述了谁(通常是对象的创建着)拥有对象;哪些组和用户被允许访问或使用此对象;那些组和用户被拒绝访问此对象。
security descriptor
A structure and associated data that contains the security information for a securable object. A security descriptor identifies the object's owner and primary group. It can also contain a DACL that controls access to the object, and a SACL that controls the logging of attempts to access the object.
access-control list
(ACL) A list of security protections that applies to an object. (An object can be a file, process, event, or anything else having a security descriptor.) An entry in an access-control list (ACL) is an accesscontrol entry (ACE). There are two types of access-control list, discretionary and system.
typedef struct _SECURITY_ATTRIBUTES { DWORD nLength; LPVOID lpSecurityDescriptor; BOOL bInheritHandle; } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;
要想判断一个对象是不是内核对象,最简单的方式是查看创建这个对象的函数。几乎所有创建内核对象的函数都有一个允许我们指定安全属性信息的参数。
2、进程内核对象句柄表
一个进程在初始化时,系统将为它分配一个句柄表(handle table)。这个句柄表仅供内核对象使用,不适用于用户对象或GDI对象。句柄表只是一个由数据结构组成的数据,每个结构都包括一个内核对象的指针、一个访问掩码(access mask)和一些标志(flag)。
1)创建一个内核对象
当进程内的一个线程调用一个会创建内核对象的函数时,内核将为这个对象分配并初始化一个内存块。然后,内核扫描进程的句柄表,查找一个空白的记录项(empty entry)。系统用索引来表示内核对象的信息保存在进程句柄表中的具体位置,要得到实际的索引值,句柄值实际应该除以4(或右移两位)。
2)关闭内核对象
无论以何种方式创建内核对象,我们都应该调用CloseHandle向系统表明我们已经结束使用对象。如果句柄是有效的,系统就将获得内核对象的数据结构的地址,并将结构中的“使用计数”成员递减。如果使用计数变成0,内核对象将被销毁,其所占内存将被释放。
如果忘了调用CloseHandle,在应用程序运行时,可能会发生内核对象泄露的情况;但当进程终止运行,操作系统会确保此进程所使用的所有资源都被释放,这适用于所有内核对象(当使用计数变为0,内核会销毁该对象)、资源(包括GDI对象在内)以及内存块。
3、跨进程边界共享内核对象