看流星社区

 找回密码
 注册账号
查看: 2375|回复: 0

内核篇---跨进程边界共享内核对象

[复制链接]

该用户从未签到

发表于 2016-7-29 10:53:18 | 显示全部楼层 |阅读模式

有三种不同的机制允许进程共享内核对象:
      1、使用对象句柄继承
      2、为对象命名
      3、复制对象句柄

一、使用对象句柄继承
       进程之间的关系为父子进程关系的时候才能继承。实质为:父进程在创建子进程的时候,如果需要继承对象句柄,那么系统的扫描父进程的句柄表,将需要继承的对象句柄表中的信息,复制到子进程的句柄表中,然后通过某种方式将句柄值传给子进程,这样子进程就可以使用的这内核对象了。在这儿父进程、子进程对于内核对象而言是相同级别的,对两个进程而言,他们得到的句柄值是相同的,而且指向的是内核中的相同的一个对象。
      所以我们可以看出,在这儿继承的不是对象,而仅仅是对象的句柄!!!
那么我们如何去设置呢?
      首先我们要知道,实现继承必须要有三个开关:
    1、创建内核对象时,有个参数开关                                        //针对于某个对象
    2、父进程句柄表的记录项中有个标志位的开关                       //针对于某个对象
    3、父进程创建子进程的时候,有个参数开关                          //针对于子进程(所有的可继承对象)
    那么我们分别来看:
1、创建内核对象时,有个参数开关           
    父进程必须分配并初始化一个SECURITY_ATTRIBUTES结构,然后将这个结构传给Create函数:
      SECURITY_ATTRIBUTES   sa ;
      sa.nLength = sizeof( sa );
     sa.lpSecurityDescriptor = NULL ;    //默认安全属性
     sa.bInhertHandle = TRUE ;  //make the returned handle  interitable  可继承的
     HANDLE   hMutex = CreateMutex ( &sa , FLASE , NULL ) ;
  2、父进程句柄表的记录项中有个标志位的开关      
      那就是句柄表中每一个记录项中保存的标志:
      如果标志位0x00000000则表示此对象不可继承   如果标志位为0x00000001表示可以继承。
     在这儿用函数SetHandleInformation在程序中可以改变句柄标志,
宏定义两个标志
#define   HANDLE_FLAG_INHERIT                           0x00000001      //打开继承标志
#define   HANDLE_FLAG_RPOTECT_FROM_CLOSE    0x00000002      //标志此对象不允许用CloseHandle关闭句柄
   BOOL   SetHandleInformation (
           HANDLE   hObject ,    //标识某个句柄
           DWORD   dwMask ,   //表示我们想要修改哪个标志   有两个标志可以再这儿修改
           DWORD   dwFlags ) ;
          例如
       SetHandleInformation (hObj , HANDLE_FLAG_INHERIT , HANGDLE_FLAG_INHERIT ) ;  打开继承
      SetHandleInformation (hObj , HANDLE_FLAG_INHERIT , 0) ;                                  关闭继承
      SetHandleInformation (hObj , HANDLE_FLAG_RPOTECT_FROM_CLOSE ,                        
                                                             HANDLE_FLAG_RPOTECT_FROM_CLOSE) ;  不允许关闭
       CloseHandle(hObj);  //这样会引发异常  因为标志设为不允许关闭!!!
      注:还有一个函数GetHandleInformation可以在程序中查询当前标志位!!!
  3、父进程创建子进程的时候,有个参数开关         CreateProcess函数
     BOOL    CreateProcess(
            PCTSTR   pszApplicationName ,
            PTSTR   pszCommandLine ,                              //命令行参数
            PSECURITY_ATTRIBUTES   psaProcess ,
            PSECURITY_ATTRIBUTES   psaThread ,
            BOOL   bInheritHandles ,                 //设置子进程是否可以继承的属性  这又是一个开关!!!
            DWORD   dwCreationFlags ,
            PVOID   pvEnvironment ,
            PCTSTR   pszCurrentDirectory ,
            LPSTARTUPINFO   pStartupInfo ,
            PPROCESS_INFORMATION   pProcessInformation ) ;
  最后这儿有一个问题:子进程是继承了父进程的对象,复制工作操作系统也都已经完成,但是子进程还不知道所继承的对象的句柄呢...这个问题的解决方案是:在创建子进程的时候,将所继承的句柄通过命令行参数传进去,让子进程取得这个句柄!!!



二、为对象命名
    只是许多(而不是全部)内核对象可以进行命名,必须为对象指定一个名称才能用这种方法实现对象的共享。
如 CreateMutex   CreateEvent   CreateSemphore   CreateWaitableTimer   CreateFileMapping   CreateJobObject等,这些函数的最后一个参数是pszName。如果向这个参数传入NULL,那么这个对象就是匿名的,如果传入一个名称,那么这个对象就是有名称的。
   实质:例如A进程调用CreateMutex
      HANDLE hMutexPeocessA = CreateMutex ( NULL, FLASE, TEXT("AAA") ) ;
    当B进程也调用CreateMutex时      HANDLE hMutexPeocessB = CreateMutex ( NULL, FLASE, TEXT("AAA") ) ;
   系统首先会查看是否存在一个名为“AAA”的内核对象,如果不存在,那么创建,如果存在,内核会接着检查对象的类型,如果类型相符(A的是互斥,B也想创建互斥),那么这时候系统会进行安全检查,验证调用者是否拥有对该对象的完全访问权限。如果有权限,那么系统会再B进程的句柄表中找到一个空白位置,初始化这个记录项指向现有的那个对象。
特点:1、A进程和B进程得到的两个句柄值很有可能不相等,但是两者都指向的是同一个内核对象
         2、B进程可以不是A进程的子进程。
     用这个方式为对象命名的时候,出现的情况是,如果要创建的对象没有,则会创建,如果要创建的对象存在,则实现共享。
         但是后者才是我们想实现的,即我们想仅仅实现共享。
    所以在这儿我们可以调用OpenMutex   OpenEvent   OpenSemphore   OpenWaitableTimer   OpenFileMapping   OpenJobObject这些函数的最后一个参数也是pszName,用这些函数可以实现,如果要打开的对象没有,则会返回失败,如果要打开的对象存在,则实现共享。



三、复制对象句柄
跨进程边界共享内核对象的最后一招是  使用  DuplicateHandle函数:
  这个参数的第一个和第三个是进程内核对象,必须是相对于调用这个函数的那个进程(需要理解)
BOOL  DuplicateHandle (
      HANDLE   hSourceProcessHandle ; //源进程的进程内核对象,是进程内核对象  传进其他内核对象会调用失败
      HANDLE    hSourceHandle ; //想要复制的内核对象的句柄,这个句柄和本进程无关,是源进程中的内核对象
      HANDLE    hTargetPeocessHandle ; //目标进程的进程内核对象   传进其他内核对象会调用失败
      PHANDLE   phTargetHandle ;  //得到新复制的内核对象在本进程中体现的句柄值
      DWORD   dwDesiredAccess ,  //设置新复制的对象的访问掩码
      BOOL   bInheritHandle ;        //设置新复制的对象的继承标志
      DWORD   dwOptions ) ;    //这个参数的设定和上面两个参数相关联,这个参数可以设置为0或               
                //DUPLICATE_SAME_ACCESS或DUPLICATE_CLOSE_SOURCE
              //如果这个参数设置为0,则上面两个参数就会起作用.
              //如果这个参数设置为DUPLICATE_SAME_ACCESS,那么目标句柄会获得和源进程的句柄一样的访问掩码
                                                            //而且如果设置这个参数的话,程序将不会在看其他两个参数
             //如果这个参数设置为DUPLICATE_CLOSE_SOURCE,会关闭源进程中的句柄,如果是这样,内核对象的
            //计数就不会增加,刚好加1又减一,注意:1、这儿是关闭的源进程的对应的对象的句柄
             //                                      2、DUPLICATE_SAME_ACCESS和DUPLICATE_CLOSE_SOURCE也可以联合使用
   
简单的说,这个函数就是获得一个进程的句柄表中的一个记录项,然后在另一个进程的句柄表中创建一个副本。 在这儿两个进程得到的某对象的句柄值也不一定相等,复制的是句柄表中记录项,而不是复制的句柄值
    例子:进程S是源进程,它拥有一个对象的访问权。进程T是目标进程,它想要获得这个内核对象的访问权。进程C则是一个催化剂过程,它执行DuplicateHandle 这个函数。见《windows核心编程》P60
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 17:15

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表