您的位置:首页 > 编程语言

Windows核心编程:(一)内核对象

2015-03-11 11:13 337 查看
一:何为内核对象

      每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问。这个内存块是一个数据结构,其成员维护着与对象相关的信息。

二:使用计数

     每个内核对象都包含一个使用计数,初次创建一个对象的时候,其使用计数被设为1.另一个进程获得对现有内核对象的访问后,使用计数就会递增;进程终止,操作系统内核自动递减打开的所有内核对象的使用计数。若使用计数变为0,则操作系统内核就会销毁该对象。

三:进程内核对象句柄表(一个指向内核对象的指针,一个访问掩码,一些标志)

      一个进程在初始化时,系统将为它分配一个句柄表。这个句柄表仅供内核对象使用,不适用于用户对象或GDI对象。一个进程首次初始化的时候,其句柄表为空。当进程的一个线程调用一个会创建内核对象的函数时,内核将为这个对象分配并初始化一个内存块,然后扫描进程的句柄表,查找一个空白的记录项,并对其初始化。(指针成员会被设置成内核对象的数据结构内部内存地址,访问掩码被设置成拥有完全访问权限,标志也会被设置)

      用于创建内核对象的任何函数都会返回一个与进程相关的句柄,这个句柄可由同一个进程中运行的所有线程使用。系统用索引来表示内核对象的信息保存在进程句柄表中的具体位置,要得到实际的索引值,句柄值实际应该除以4。由于句柄值实际是作为进程句柄表的索引来使用的,所以这些句柄是与当前这个进程相关的,无法供其他进程使用。

     调用函数创建一个内核对象时,若调用失败,那么返回的句柄值通常为0,即为第一个有效的句柄值为4.

四:关闭内核对象

      在CloseHandle函数返回之前,会清除进程句柄表中对应的记录项—这个句柄现在对我们的进程来说是无效的,无论内核对象是否销毁,这个清除过程都会发生。

      当进程终止时,系统能保证一切都被正确的清除,这适用于所有内核对象,资源以及内存块。进程终止时,系统会确保我们的进程不会留下任何东西。

五:进程共享内核对象

      (1)使用对象句柄继承:

        只有在进程之间有一个父子关系的时候,才可以使用对象句柄继承。父进程有一个或多个内核对象句柄可以使用,而且父进程决定生成一个子进程,并允许子进程访问父进程的内核对象。

        首先,当父进程创建一个内核对象时,父进程必须向系统指出它希望这个对象的句柄是可以继承的(可将对应记录项的是否继承的标志位置1);其次由父进程生成子进程,指定其中的一个参数bInheritHandles参数为TRUE,子进程就会继承父进程的“可继承的句柄”值。传递TRUE时,操作系统会创建新的子进程,但不允许子进程立即执行它的代码。系统为子进程创建一个新的,空白的进程句柄表;然后会遍历父进程的句柄表,对它的每一个记录进行检查,凡是包含一个有效的“可继承的句柄”的项,都会被完整地复制到子进程的句柄表。在子进程的句柄表中,复制项的位置与它在父进程句柄表中的位置是完全一样的,系统还会递增内核对象的使用计数。

       内核对象的内容被保存在内核地址空间中—系统上运行的所有进程都共享这个空间。对32位系统,是ox80000000到oxFFFFFFFF之间的内存空间,对64位系统,是0x00000400'00000000到0xFFFFFFFF'FFFFFFFF之间的内存空间。对象句柄的继承只会在生成子进程的时候发生。

      (2)为对象命名

        对象命名都共享同一个命名空间,即使它们的类型并不相同。

         

        HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("JeffObj"));

        HANDLE hSem = CreateSemaphore(NULL, 1, 1, TEXT("JeffObj"));

        第二个函数肯定会调用失败。

        以此种方式共享对象的方法:

 HANDLE hMutexProcessA = CreateMutex(NULL, FALSE, TEXT("JeffMutex"));   进程A创建一个新的互斥量内核对象,后来某个进程B(B不一定是A的子进程)执行以下代码:

 HANDLE hMutexProcess = CreateMutex(NULL, FALSE, TEXT("JeffMutex")); 系统查看是否存在一个名为“JeffMutex”的内核对象。若存在,内核接着检查对象的类型,若相同则接着执行一次安全检查,若肯定,系统就会在进程B的句柄表中查找一个空白的记录项,并将其初始化为指向现有的内核对象。若对象的类型不匹配,或拒绝访问,则会失败。

     (3)复制对象句柄

             使用DuplicateHandle函数,原型如下:

       

           BOOL DuplicateHandle(

                     HANDLE hSourceProcessHandle,

                     HANDLE hSourceHandle,

                     HANDLE hTargetProcessHandle,

                     HANDLE phTargetHandle,

                     DWORD dwDesiredAccess,

                     BOOL bInheritHandle,

                     DWORD dwOptions          

);

这个函数获得一个进程的句柄表中的一个记录项,然后在另一个进程的句柄表中创建这个记录项的一个副本。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: