内核对象是内核分配的一个内存块,并且只能由内核访问。
该内存块是一种数据结构,它的成员负责维护该对象的各种信息。
内核对象的数据结构只能由内核访问,因此应用程序无法在内存中找到这些数据结构并改变它们的内容。
如何操作内核对象呢:
Windows提供了一组函数,以便用定义得很好的方法来对这些结构进行操作。
内核对象始终都通过这些函数进行访问。
当调用一个用于创建内核对象的函数时,该函数就返回一个用于标识该对象的句柄,该句柄可以被视为一个不透明值,你的进程中的任何线程都可以使用这个值。将这个句柄传递给Windows的各个函数,这样系统就能知道你想操作哪个内核对象。
内核对象的所有权:
内核对象由内核所有,而不是进程所有。
即:如果进程调用创建内核对象的函数,然后进程终止运行,但是内核对象不一定被撤销。
大多数情况下会被撤销,但是如果另一个进程正在使用你的进程创建的内核对象,那么内核知道,另一个进程停止使用该内核对象前不要撤销该对象,所以,内核对象的存在时间可以比创建该对象的进程长。
内核对象的使用计数:
内核知道有多少进程正在使用某个内核对象,因为每个对象包含一个使用计数。
当一个对象刚刚创建时,使用计数被置为1,当另一个进程访问现有内核对象时,计数递增1,当进程终止运行时,内核就自动确定该进程仍然打开的所有内核对象的使用计数。如果计数降为0,内核就撤销该对象。
这样可以确保没有进程引用该对象时系统中不保留任何对象。
内核对象的安全性:
内核对象能够得到安全描述符的保护。
安全描述符用于描述谁创建了对象,谁能够访问或使用该对象,谁无权访问对象。
通常在编写服务器应用程序时使用,如果编写客户端应用程序,则可以忽略内核对象这个特性。
用于创建内核对象的函数几乎都有一个指向 SECURITY_ATTRIBUTES 结构的指针作为其参数。大多数应用程序只是为该参数传递 NULL,这样就可以创建一个带有默认安全性的内核对象。默认安全性意味着:对象的管理小组的任何成员和对象的创建者都拥有该对象的全部访问权,而其他人均无权访问该对象。
但是,可以指定一个SECURITY_ATTRIBUTES结构,对它进行初始化,并为该参数传递该结构的地址。
如何区分内核对象与非内核对象:
除了内核对象之外,应用程序也可以使用其他类型的对象,例如:窗口、菜单、鼠标光标、刷子、字体等,这些对象属于用户对象或图形设备接口(GDI)对象,而不是内核对象。
要确定一个对象是否属于内核对象,最容易的方法是观察创建该对象所用的函数。创建内核对象的所有函数几乎都有这样一个参数,你可以用来设定安全属性信息。用于创建用户对象或GDI图形设备接口对象的函数都没有PSECURITY_ATTRIBUTES 参数。
有关进程的内核对象句柄表:
当一个进程被初始化时,系统就要为它分配一个句柄表,该句柄表只用于内核对象,而不用于用户对象或GDI对象。
一个称职的Windows程序员,必须懂得如何管理进程的句柄表。
创建内核对象:
当进程初次被初始化时,它的句柄表是空的。进程中的线程调用创建内核对象的函数时,内核就为该对象分配一个内存块,并对它初始化。此时内核对进程的句柄表进行扫描,找出一个空项,该指针成员将被设置为内核对象的数据结构的内存地址,访问屏蔽设置为全部访问权,同时,各个标志也做了设置。
用于创建内核对象的所有函数均返回与进程相关的句柄,这些句柄可以被在相同进程中运行的任何或所有线程成功地加以使用。该句柄的值实际上是放入进程的句柄表中的索引,它用于标识内核对象的信息存放的位置。
关闭内核对象:
无论怎样创建内核对象,都要向系统指明通过调用 CloseHandle 来结束对该对象的操作。
该函数首先检查调用进程的句柄表,以确保传递给它的索引(句柄)用于标识一个进程实际上无权访问的对象。如果该索引是有效的,那么系统可以获得内核对象的数据结构的地址,并可确定该结构中的使用计数成员。如果计数是0,该内核便从内存中撤销该内核对象。
当调用 CloseHandle 函数之后,将不再拥有内核对象的访问权,不过如果该对象的使用计数没有递减为0,那么该对象未撤销。
当进程终止运行时,操作系统能够确保该进程使用的任何资源或全部资源均被释放,这是有保证的。
对于内核对象来说,系统将自动扫描进程的句柄表。如果该表拥有任何无效项目(即终止进程运行前没有关闭的对象),系统将关闭这些对象的句柄。如果这些对象中的任何对象的使用计数降为0,那么内核便撤销该对象。
应用程序在运行时有可能泄露内核对象,但是当进程终止运行时,系统能确保所有内容均被正确地清除。这个情况适用于所有的对象,资源和内存块。
如何跨越进程边界共享内核对象:
许多情况下,在不同进程中运行的线程需要共享内核对象。下面是为何需要共享的原因:
- 文件映射对象使你能够在同一台机器上运行的两个进程之间共享数据块。
- 邮箱和指定的管道使得应用程序能够在连网的不同机器上运行的进程之间发送数据块。
- 互斥对象、信标和事件使得不同进程中的线程能够同步它们的连续运行,这与一个应用程序在完成某项任务时需要将情况通知另一个应用程序的情况相同。
允许进程共享内核对象的3个不同的机制:
- 对象句柄的继承性: 只有当进程具有父子关系时,才能使用对象句柄的继承性。在这种情况下,父进程可以使用一个或多个内核对象句柄,并且该父进程可以决定生成一个子进程,为子进程赋予父进程的内核访问权。
- 命名对象: 许多内核对象都是可以命名的,它们都有一个共同的参数pszName,当该参数传递为NULL时,就向系统指明了想创建的一个未命名的内核对象(匿名内核对象)。如果没有传递NULL值,则应传递一个以0结尾的字符串名字的地址,则可以创建一个命名的内核对象。
- 复制对象句柄: 使用DuplicateHandle函数,该函数取出一个进程句柄表中的项目,并将该项目拷贝到另一个进程的句柄表中。
先暂记于此,慢慢学习吧…