Windows 之 跨进程边界共享内核对象

跨进程边界共享内核对象

在很多情况下,我们需要跨进程边界共享内核对象。实现的方法有三种,继承对象句柄,给对象命名,复制对象句柄。

1.继承对象句柄

只有当进程具有父子关系时,才可以使用对象句柄的继承性。想要父进程生成一个子进程,并且赋予子进程对父进程内核对象的访问权,父进程必须完成以下几个操作:
当父进程创建内核对象时,必须向系统指明,它希望对象的句柄是个可继承的句柄,也就是 SECURITY_ATTRIBUTES的 bInheritHandle 置为 TRUE。并且创建子进程时,bInheritHandles参数同样只置为TRUE。这样,子进程在创建出来的时候,也会由一张空的句柄表,系统会遍历父进程的句柄表,将可继承的项拷贝进子进程句柄表的相同位置。这样同一个句柄值在父进程和子进程中就可以代表同一个内核对象了。
(这个操作满足上述内核对象的所有特性,相应的计数器会加1)。需要注意的是,继承的是句柄而不是对象。 若要改变内核对象句柄的继承标志,可以调用SetHandleInformation函数。

2.给对象命名

许多(虽然不是全部)内核对象都是可以命名的。名字的长度最多可以达到MAX_ PATH(定义为2 6 0)个字符。
起名字要带有特点,因为Windows下的内核对象没有命名的指导原则,也就是可能创建了一个内核对象的名字与已经存在的其他类型内核对象重复,这样就会出错。(名字与同一类型内核对象重复是可以的,这也是共享内核对象的方法)。
举个例子来说明,用命名对象的方法来共享内核对象的:
在进程A中调用函数创建一个内核对象并起名为 object。然后在B进程中调用函数创建同一个类型的内核对象并起名为 object。这时,系统首先要查看是否已经存在一个名字为 object的内核对象,由于确实存在一个名字为object的内核对象,因此内核要检查对象的类型,由于试图创建的对象与已有的对象为同一类型的对象,系统会执行一次安全检查,以确定调用者是否拥有对该对象的完整的访问权。如果拥有这种访问权,系统就在进程B的句柄表中找出一个空项目,并对该项目进行初始化,使该项目指向现有的内核对象,如果该对象类型不匹配,或者调用者被拒绝访问,创建对象的函数将运行失败(返回NULL)。
进程B如果创建成功实际上并不是真的创建了一个内核对象,只是被赋予了一个进程相关的句柄,用于标识内核中已有的名为object对象。这时内核对象的计数器会加1。
值得注意的是,当以这种方式创建成功内核对象时,创建对象函数的传入的安全属性将被忽略(因为在内核中生成该对象的时候已经确定了它的安全属性)。

除了调用函数(Create*)创建相同名字的内核对象以外,还有使用(Open*)函数来打开已有的内核对象。同样需要拥有相同类型和相同名字的的对象才可以成功被打开,否则返回NULL。
调用(Create )函数与调用(Open)函数之间的主要差别是,如果对象并不存在,那么(Create)函数将创建该对象,而(Open)函数则运行失败。**

3.复制对象句柄:

使用DuplicateHandle函数可以复制对象句柄。该函数取出一个进程的句柄表中的项目,并将该项目拷贝到另一个进程的句柄表中。先来看一下DuplicateHandle函数原型:

BOOL  DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
PHANDLE phTargetHandle,
DWORD dwDesiredAcess,
BOOL bInheritHandle,
DWOED dwOptions); 

当调用DuplicateHandle函数时,第一和第三个参数hSourceProcessHandle和hTargetProcessHandle是内核对象句柄。
这些句柄本身必须与调用DuplicateHandle函数的进程相关。这两个参数必须标识进程的内核对象,第二个参数hSourceHandle是任何类型的内核对象的句柄。
该句柄必须与hSourceProcessHandle句柄标识的进程相关。四个参数phTargetHandle是HANDLE变量的地址,它将接收获取源进程句柄信息拷贝的项目索引,返回的句柄值与hTargetProcessHandle标识的进程相关。也就是说,第一个参数为源进程的句柄,第二个参数为源进程中的源句柄,第三个参数为目标进程的句柄,第四个参数为目标进程中的目标句柄的地址,用来接收内容的。
DuplicateHandle的最后3个参数用于指明该目标进程的内核对象句柄表项目中使用的访问屏蔽值和继承性标志。
dwOptions参数可以是 0(零),也可以是下面两个标志的任何组合:
DUPLICATE _ SAME_ ACCESS和DU PLICATE_ CLOSE_ SOURCE。
如果设定了DUPLICATE _ SAME_ ACCESS标志,则告诉DuplicateHandle函数,你希望目标进程的句柄拥有与源进程句柄相同的访问屏蔽。使用该标志将使 DuplicateHandle忽略它的dwDesiredAcess参数。
如果设定了DU PLICATE_ CLOSE_ SOURCE标志,则可以关闭源进程中的句柄。该标志使得一个进程能够很容易地将内核对象传递给另一个进程。当使用该标志时,内核对象的使用计数不会受到影响。

猜你喜欢

转载自blog.csdn.net/weixin_45074185/article/details/105472765