据说这里挺抽象,不知道自己能不能读懂。
1、操作系统内核怎么操作内核对象:
每个内核对象都只有一个内存块,它有操作系统内核分配,这个内存块是一个数据结构,其成员维护着与对象相关的信息,这个内核对象的数据结构只能有操作系统内核访问。也就是说操作系统内核来通过计数的方式来操作内核对象。
2、应用程序怎么操作内核对象:
应用程序通过利用windows提供的一组函数,来操作这些内核对象。也就是说:我们通过进程调用函数来创建内核对象,但是内核对象的生命期是可能长于创建它的进程的生命期。为了让操作系统知道我们对哪个内核对象进行操作,这就需要我们把创建内核对象的函数的返回值就是句柄传给各个windows函数。
3、内核对象的安全性:
创建内核对象的函数较普通函数的地方是,有一个明显的参数,即都有一个指向SECURITY_ATTRIBUTES结构体的指针作为参数。该参数就是用来指定安全性。
除了内核对象还有用户对象和GDI对象(有待进一步理解)。
4、创建一个内核对象:
程内的一个线程调用会创建内核对象的函数,该函数创建内核对象成功返回一个句柄,该句柄可以供该进程的中的所有线程使用,内核为这个对象分配并初始化一个内存块,然后内核扫描进程的句柄表,查找一个空白的记录项。并进行记录。
要注意的是创建内核对象的函数的返回值,判断是否失败不一致的问题,也就是说null不一定都是失败了,有的函数失败了也不一定返回null可能是其它的值。
5、关闭内核对象:
通过函数CloseHandle,仅仅是向系统表明我们已经结束使用了对象就是说我不使用这个对象了,至于你怎么销毁那是另外一件事情。
进程终止运行时,系统会确保进程不会留下任何痕迹,要是检查内核对象是否有内存泄露,简单的方法是使用windows任务管理器和Process Explorer工具。
6、跨进程边界共享内核对象的三种不同机制
6.1使用对象句柄继承
实现条件:只有在进程之间有一个父子关系的时候,才可以使用对象句柄继承机制。也就是说,对象句柄的继承只会在生成子进程的时候发生。也就是说子进程一旦在运行,父进程再创建的内核对象不会被子进程继承,哪怕这个刚刚创建的内核对象标志位是可以继承。
创建可继承的句柄:父进程创建内核对象,同时告诉系统他希望这个内核对象的句柄可以被以后的子进程继承,怎么告诉系统呢?这就是父进程创建内核对象的时候还要必须分配和初始化一个SECURITY_ATTRIBUTES结构(该结构中有标志位参数指定是否同意继承),并将这个结构的地址传给具体的Create函数(该函数用于创建内核对象),返回可继承的句柄。
使用对象句柄继承:父进程通过函数创建子进程,例如CreateProcess函数,其中创建子进程或者线程的函数中也有标志位参数指定是否要继承父进程的可继承的内核对象句柄。
内核对象句柄继承实质:其实内核对象的继承是父进程和子进程共享内核对象的句柄值。父进程将这个同意共享的内核对象句柄值传递给子进程的方法,第一,可以是通过命令行参数传递,比如CreateProcess函数中也有这个参数用来传递命令行参数;第二,就是通过子进程会继承父进程的环境变量来实现。
可继承句柄标识改变:这里就是说,创建可继承句柄后,怎么设置继承句柄的标识,来控制让那些子进程继承,不让那些子进程继承。设置函数为SetHandIeInformation。这个函数可以通过参数设置,来打开内核对象句柄可继承、关闭内核对象继承、或者告诉系统禁止关闭某个句柄。同时函数GetHandleInformation函数可以检查或者返回某个句柄是否可以被继承。
6.2 使用对象命名继承
前提条件:许多但不是全部内核对象都可以进行命名。使用这中机制来共享内核对象,最大的好处是两个进程可以不是父子进程关系。
可以创建命名的内核对象的函数有:CreateMutex、CreateEvent、CreateSemaphore、CreateWaitebleTimer、CreateFileMapping和CreateJobobject函数的最后有一个参数,就是为创建的内核对象命名。但是windows还没有很好的机制,来检测内核对象的名称唯一。
继承的实现:一个进程创建内核对象并命名同时返回句柄1.另一个进程创建内核对象并命名命同样的名字返回句柄2,这里的句柄1和句柄2很可能不一样,但是也是没有关系,只要两个内核对象名字一样,他们两个进程就会共享同一个内核对象。可以通过GetLastError函数来得到第二个进程是创建了内核对象还是仅仅打开了同名的内核对象;另一种办法是,第一个进程通过Create函数创建命名内核对象,第二个进程通过函数Open*函数来打开这个想要共享的内核对象。不同的返回值都可以通过GetLastError函数来捕捉。
6.3 复制对象句柄继承
实现方法:做为催化剂的一个进程使用函数DuplicateHandle获得一个源进程的句柄表中的一个记录项,然后在另一个目标进程的句柄表中创建这个记录项的一个副本。这时目标进程任然不知道自己能够访问一个新的内核对象,那个催化剂进程必须将自己得到的可以访问的内核对象的句柄值传递给那个目标进程。使用的传递句柄的机制有窗口消息或者其他进程间通信(IPC)机制。
适合场景:DuplicateHandle函数的适合场景,上面的实现方法是三个进程的场景;当然还有两个进程的场景,比如源进程也想访问目标进程正在访问的一个对象;还可以通过该函数为一个对象创建一个新的句柄,确保这个新句柄有只读或者读写权限。