windows核心编程 第三章,跨越进程边界共享内核对象,对象句柄的继承性,改变句柄的标志,命名对象,终端服务器的名字空间,复制对象句柄

windows核心编程

3.3 跨越进程边界共享内核对象

3.3.1 对象句柄的继承性

3.3.2 改变句柄的标志

3.3.3命名对象

3.3.4终端服务器的名字空间

3.3.5 复制对象句柄


3.3 跨越进程边界共享内核对象

许多情况下,在不同进程中运行的线程需要共享内核对象。下面是为何需要共享的原因:·文件映射对象使你能够在同一台机器上运行的两个进程之间共享数据块。·邮箱和指定的管道使得应用程序能够在连网的不同机器上运行的进程之间发送数据块。·互斥对象、信标和事件使得不同进程中的线程能够同步它们的连续运行,这与一个应用程序在完成某项任务时需要将情况通知另一个应用程序的情况相同。
由于内核对象句柄与进程相关,因此这些任务的执行情况是不同的。不过,Microsoft公司有若干很好的理由将句柄设计成与进程相关的句柄。最重要的理由是要实现它的健壮性。如果内核对象句柄是系统范围的值,那么一个进程就能很容易获得另一个进程使用的对象的句柄,从而对该进程造成很大的破坏。另一个理由是安全性。内核对象是受安全性保护的,进程在试图操作一个对象之前,首先必须申请获得操作该对象的许可权。对象的创建人只需要拒绝向用户赋予许可权,就能防止未经授权的用户接触该对象。
在下面的各节中,将要介绍允许进程共享内核对象的 3个不同的机制。

3.3.1 对象句柄的继承性

只有当进程具有父子关系时,才能使用对象句柄的继承性。在这种情况下,父进程可以使用一个或多个内核对象句柄,并且该父进程可以决定生成一个子进程,为子进程赋予对父进程的内核对象的访问权。若要使这种类型的继承性能够实现,父进程必须执行若干个操作步骤。首先,当父进程创建内核对象时,必须向系统指明,它希望对象的句柄是个可继承的句柄
请记住,虽然内核对象句柄具有继承性,但是内核对象本身不具备继承性。若要创建能继承的句柄,父进程必须指定一个 SECURITY_ATTRIBUTES结构并对它进行初始化,然后将该结构的地址传递给特定的 Create函数。下面的代码用于创建一个互斥对象并将一个可继承的句柄返回给它:

SECURITY_ATTRIBUTES Sa;
sa.nLength=sizeof(sa);
sa.1pSecurityDescriptor=ULL:
sa.bInheritHandle =TRUE;// Make the returned handle inheritable.
HANDLE hMutex=CreateMutex(&Sa,FALSE, NULL);

该代码对一个SECURITY_ATTRIBUTES结构进行初始化,指明该对象应该使用默认安全性(在Windows98中该安全性被忽略)来创建,并且返回的句柄应该是可继承的。
Windows 98 尽管Windows 98不拥有完整的对安全性的支持,但是它却支持继承性,因此,Windows98能够正确地使用bInheritHandle成员的值。
现在介绍存放在进程句柄表项目中的标志。每个句柄表项目都有一个标志位,用来指明该句柄是否具有继承性。当创建一个内核对象时,如果传递NULL作为PSECURITY ATTRIBUTES的参数,那么返回的句柄是不能继承的,并且该标志位是0。如果将bInheritHandle成员置为TRUE,那么该标志位将被置为1。
表3-2显示了一个进程的句柄表。
在这里插入图片描述
表3-2表示该进程拥有对两个内核对象(句柄1和3)的访问权。句柄1是不可继承的,而句
柄3是可继承的。使用对象句柄继承性时要执行的下一个步骤是让父进程生成子进程。这要使用CreateProcess函数来完成:

B00L CreateProcess(
PCTSTR pszApplicationName.
PTSTR pszCommandLine,
PSECURITY_ATTRIBUTES psaProcess
PSECURITY_ATTRIBUTES pszThread,
B00L bInheritHandles.
DWORD dwCreationFiags.
PYOID DvEnvironment.
PCTSTR pszCurrentDirectory
LPSTARTUPINFO pStartupInfo.
PPROCESS_INFORMATION pProcessInformation);

下一章将详细介绍这个函数的用法,不过现在我想要让你注意 bInheritHande这个参数。般来说,当生成一个进程时,将为该参数传递 FALSE。该值告诉系统,不希望子进程继承父进程的句柄表中的可继承句柄。
但是,如果为该参数传递 TRUE,那么子进程就可以继承父进程的可继承句柄值。当传递TRUE时,操作系统就创建该新子进程,但是不允许子进程立即开始执行它的代码。当然,系统为子进程创建一个新的和空的句柄表,就像它为任何新进程创建句柄表那样。不过,由于将TRUE传递给了CreateProcess的bInheritHandles参数,因此系统要进行另一项操作,即它要遍历父进程的句柄表,对于它找到的包含有效的可继承句柄的每个项目,系统会将该项目准确地拷贝到子进程的句柄表中。该项目拷贝到子进程的句柄表中的位置将与父进程的句柄表中的位置完全相同。这个情况非常重要,因为它意味着在父进程与子进程中,标识内核对象所用的句柄值是相同的。
除了拷贝句柄表项目外,系统还要递增内核对象的使用计数,因为现在两个进程都使用该对象。如果要撤消内核对象,那么父进程和子进程必须调用该对象上的 CloseHandle函数,也可以终止进程的运行。子进程不必首先终止运行,但是父进程也不必首先终止运行。实际上,CreateProcess函数返回后,父进程可以立即关闭对象的句柄,而不影响子进程对该对象进行操
作的能力。表3-3显示了子进程被允许运行前该进程的句柄表。可以看到,项目1和项目2尚未初始化因此是个无效句柄,子进程是无法使用的。但是,项目 3确实标识了一个内核对象。实际上它标识的内核对象的地址是0xF0000010,这与父进程的句柄表中的对象地址相同。访问屏蔽与父进程中的屏蔽相同,两者的标志也相同。这意味着如果该子进程要生成它自己的子进程(即父进程的孙进程),该孙进程也将继承与该内核对象句柄相同的句柄值、同样的访问权和相同的标志,同时,对象的使用计数再次被递增。
在这里插入图片描述
应该知道,对象句柄的继承性只有在生成子进程的时候才能使用。如果父进程准备创建带有可继承句柄的新内核对象,那么已经在运行的子进程将无法继承这些新句柄。对象句柄的继承性有一个非常奇怪的特征,那就是当使用它时,子进程不知道它已经继承了任何句柄。只有在另一个进程生成子进程时记录了这样一个情况,即它希望被赋予对内核对象的访问权时,才能使用内核对象句柄的继承权。通常,父应用程序和子应用程序都是由同一个公司编写的,但是,如果另一个公司记录了子应用程序期望的对象,那么该公司也能够编写
子应用程序。子进程为了确定它期望的内核对象的句柄值,最常用的方法是将句柄值作为一个命令行参数传递给子进程,该子进程的初始化代码对命令行进行分析(通常通过调用 sscanf函数来进行分析),并取出句柄值。一旦子进程拥有该句柄值,它就具有对该对象的无限访问权。请注意句柄继承权起作用的唯一原因是,父进程和子进程中的共享内核对象的句柄值是相同的,这就是为什么父进程能够将句柄值作为命令行参数来传递的原因。
当然,可以使用其他形式的进程间通信,将已继承的内核对象句柄值从父进程传送给子进程方法之一是让父进程等待子进程完成初始化(使用第 9章介绍的WaitForInpu

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值