C r e a t e P r o c e s s的b I n h e r i t H a n d l e s参数

时间:2022-08-02 01:55:35


使用对象句柄继承性时要执行的下一个步骤是让父进程生成子进程。这要使用C r e a t e
P r o c e s s函数来完成:


下一章将详细介绍这个函数的用法,不过现在我想要让你注意b I n h e r i t H a n d l e这个参数。一
般来说,当生成一个进程时,将为该参数传递FA L S E。该值告诉系统,不希望子进程继承父进
程的句柄表中的可继承句柄。
但是,如果为该参数传递T R U E,那么子进程就可以继承父进程的可继承句柄值。当传递
T R U E时,操作系统就创建该新子进程,但是不允许子进程立即开始执行它的代码。当然,系
统为子进程创建一个新的和空的句柄表,就像它为任何新进程创建句柄表那样。不过,由于将
T R U E传递给了C r e a t e P r o c e s s的b I n h e r i t H a n d l e s参数,因此系统要进行另一项操作,即它要遍历
父进程的句柄表,对于它找到的包含有效的可继承句柄的每个项目,系统会将该项目准确地拷
贝到子进程的句柄表中。该项目拷贝到子进程的句柄表中的位置将与父进程的句柄表中的位置
完全相同。这个情况非常重要,因为它意味着在父进程与子进程中,标识内核对象所用的句柄
值是相同的。
除了拷贝句柄表项目外,系统还要递增内核对象的使用计数,因为现在两个进程都使用该
对象。如果要撤消内核对象,那么父进程和子进程必须调用该对象上的C l o s e H a n d l e函数,也
可以终止进程的运行。子进程不必首先终止运行,但是父进程也不必首先终止运行。实际上,
C r e a t e P r o c e s s函数返回后,父进程可以立即关闭对象的句柄,而不影响子进程对该对象进行操
作的能力。
表3 - 3显示了子进程被允许运行前该进程的句柄表。可以看到,项目1和项目2尚未初始化,
因此是个无效句柄,子进程是无法使用的。但是,项目3确实标识了一个内核对象。实际上,
它标识的内核对象的地址是0 x F 0 0 0 0 0 1 0,这与父进程的句柄表中的对象地址相同。访问屏蔽与
父进程中的屏蔽相同,两者的标志也相同。这意味着如果该子进程要生成它自己的子进程(即
父进程的孙进程),该孙进程也将继承与该内核对象句柄相同的句柄值、同样的访问权和相同
的标志,同时,对象的使用计数再次被递增。
表3-3 继承父进程的可继承句柄后的子进程句柄表
索引内核对象内存块访问屏蔽标志
的指针(标志位的D W O R D) (标志位的D W O R D)
1 0 x 0 0 0 0 0 0 0 0 (无) (无)
2 0 x 0 0 0 0 0 0 0 0 (无) (无)
3 0 x F 0 0 0 0 0 1 0 0 x ? ? ? ? ? ? ? ? 0 x 0 0 0 0 0 0 0 1
应该知道,对象句柄的继承性只有在生成子进程的时候才能使用。如果父进程准备创建带
有可继承句柄的新内核对象,那么已经在运行的子进程将无法继承这些新句柄。
对象句柄的继承性有一个非常奇怪的特征,那就是当使用它时,子进程不知道它已经继承
了任何句柄。只有在另一个进程生成子进程时记录了这样一个情况,即它希望被赋予对内核对
象的访问权时,才能使用内核对象句柄的继承权。通常,父应用程序和子应用程序都是由同一
个公司编写的,但是,如果另一个公司记录了子应用程序期望的对象,那么该公司也能够编写
子应用程序。
子进程为了确定它期望的内核对象的句柄值,最常用的方法是将句柄值作为一个命令行参
数传递给子进程,该子进程的初始化代码对命令行进行分析(通常通过调用s s c a n f函数来进行
分析),并取出句柄值。一旦子进程拥有该句柄值,它就具有对该对象的无限访问权。请注意,
句柄继承权起作用的唯一原因是,父进程和子进程中的共享内核对象的句柄值是相同的,这就
是为什么父进程能够将句柄值作为命令行参数来传递的原因。