操作系统内核是指大多数操作系统的核心部分。它由操作系统中用于管理存储器、文件、外设和系统资源的那些部分组成。操作系统内核通常运行进程,并提供进程间的通信。
内核对象
每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问。这个内存块是一个数据结构,其成员维护着与对象相关的信息。少数成员(安全描述符和使用计数器等)是所有对象都有的,但其他大多数成员都是不同类型的对象特有的。
使用计数
操作系统内核知道当前有多少个进程正在使用一个特定的内核对象,因为每个对象都包含一个使用计数(usage count)。初次创建一个对象的时候,其使用计数被设为1,另一个进程获得对现有内核对象的访问后,使用计数就会递增。进程终止运行后,操作系统内核将自动递减此进程仍然打开的所有内核对象的使用计数,如果一旦对象的使用计数变成0,操作系统内核就会销毁该对象。
内核对象的安全性
内核对象可以用一个安全描述符(security descriptor,SD)来保护。安全描述符描述了谁拥有对象,哪些组和用户被允许访问或使用对象,哪些组和用户被拒绝访问此对象。用于创建内核对象的所有函数几乎都有指向SECURITY_ATTTRIBUTES结构的指针作为参数,大多数应用程序只是为了这个参数传入NULL,这样创建的内核对象具有默认的安全性,具体包括哪些默认的安全性,要取决于当前进程的安全令牌(security token)。
创建一个内核对象
一个进程在初始化时,系统将为它分配一个句柄表(handle table)。这个句柄表仅供内核对象使用。
索引 | 指向内核对象内存块的指针 | 访问掩码 | 标志 |
1 | 0x???????? | 0x???????? | 0x???????? |
2 | 0x???????? | 0x???????? | 0x???????? |
... |
一个进程首次初始化的时候,其句柄表为空。当进程内的一个线程调用一个会创建内核对象的函数时,内核将为这个对象分配并初始化一个内存块。然后内核扫描进程的句柄表,查找一个空白的记录项,对其进行初始化。具体地说,指针成员会被设置成内核对象的数据结构的内部内存地址,访问掩码将被设置成拥有完全访问权限,标志也会设置。
用于创建内核对象的任何函数都会返回一个与进程相关的句柄,这个句柄可由同一个进程中运行的所有线程使用。系统用索引来表示内核对象的信息保存在进程句柄表中的具体位置,要得到实际的索引值,句柄值实际应该除以4(或右移两位,以忽略windows操作系统内部使用的最后两位)。
调用一个函数时,如果它接受一个内核对象句柄作为参数,就必须把Create*函数返回的值传给它。在内部,这个函数会查找进程的句柄表,获得目标内核对象的地址,然后以一种恰当的方式来操纵对象的数据结构。
关闭内核对象
无论以什么方式创建内核对象,我们都要调用CloseHandle向系统表明我们已经结束使用对象,如下
BOOL CloseHandle(HANDLE hobject);
在内部,该函数首先检查主调进程的句柄表,验证“传给函数的句柄值”标识的是“进程确实有权访问的一个对象”。如果句柄是有效的,系统就将获得内核对象的数据结构的地址,并将结构中的“使用计数”成员递减。如果使用计数变成0,内存对象将被销毁,并从内存中去除。