您的位置:首页 > 编程语言

【Window编程】内核对象

2016-10-12 21:22 197 查看

内核对象

    比如存取符号对象、事件对象、文件对象、文件映射对象、

    I / O完成端口对象、作业对象、信箱对象、互斥对象、管道对象、进程对象、信标对象、线程

    对象和等待计时器对象等

1. 每个内核对象只是内核分配的一个内存块,并且只能

   由该内核访问。该内存块是一种数据结构,它的成员负责维护该对象的各种信息

2. 句柄指向 内核对象 ,为了使操作系统变得更加健壮,这些句柄值是与进程密切相关的。因此,如果将该句柄值

   传递给另一个进程中的一个线程(使用某种形式的进程间的通信)那么这另一个进程使用你的进程的句柄值所

   作的调用就会失败

3.  内核对象由内核所拥有,而不是由进程所拥有。换句话说,如果你的进程调用了一个创建

    内核对象的函数,然后你的进程终止运行,那么内核对象不一定被撤消。在大多数情况下,对

    象将被撤消,但是如果另一个进程正在使用你的进程创建的内核对象,那么该内核知道,在另

    一个进程停止使用该对象前不要撤消该对象,必须记住的是,内核对象的存在时间可以比创建

    该对象的进程长。

4.内核对象能够得到安全描述符的保护。安全描述符用于描述谁创建了该对象,谁能够访问

    或使用该对象,谁无权访问该对象。

    PSECURITY_ATTRIBUTES 结构体

    typedef struct _SECURITY_ATTRIBUTES

    {

        DWORD nLength; //sizeof(SECURITY_ATTRIBUTES)

        LPVOID lpSecurityDescriptor; //pSD

        BOOL bInheritHandle;    //是否可被继承

    }SECURITY_ATTRIBUTES;

5. 句柄表,系统为每一个进程维护一个句柄表,项目指向了该进程拥有的句柄,也就是内核对象的句柄,

   内核对象只能由内核访问,Window提供了一系列函数访问内核对象,函数会转到内核态再访问内核对象。

   用户对象和GDI对象并不存储在这里,而且可以有用户直接在用户态使用。

window跨进程访问内核对象方法:

1. 父子进程继承句柄

   如果设置内核对象可继承且CreateProcess选择了继承,那么子进程将继承父进程

   句柄表,和Linux文件描述符表类似,window用句柄,linux用文件描述符

2.   给内核对象命名

   许多(虽然不是全部)内核对象都是可以命名的,指定名字的参数不为NULL

    a.名字为NULL时,只能通过继承性(父子进程)共享
CreateMutex
CreateEvent
CreateSamaphore
CreateWaitableTimer
CreateJobObject
CreateFileMapping


    两个不相关进程通过一样的名字创建相同类型的句柄即可完成进程间共享命名句柄,句柄表就初始化一个项目指向现有的

    内核对象,同时,互斥对象的使用计数就会递增。

    注意:句柄值不一定相同,两个不想关的进程,联想虚拟地址,一般编程取地址符获得的都是虚拟地址。

    如果类型不匹配或者调用者被拒绝访问,那么函数就会返回NULL

    注意:

    当你的多个内核对象拥有相同的名字时,有一个非常重要的细节必须知道。

    当Process B调用C r e a t e M u t e x时,它将安全属性信息和第二个参数传递给该函数。如

    果已经存在带有指定名字的对象,那么这些参数将被忽略。应用程序能够确定它是否

    确实创建了一个新内核对象,而不是打开了一个现有的对象。

    判断if (GetLastError() == ERROR_ALREADY_EXISTS) {...}

    b.名字不能设置为NULL
OpenMutex
OpenEvent
OpenSamaphore
OpenWaitableTimer
OpenJobObject
OpenFileMapping


    注意,所有这些函数都拥有相同的原型。最后一个参数p s z N a m e用于指明内核对象的名字。

    不能为该参数传递N U L L,必须传递以0结尾的地址。这些函数要搜索内核对象的单个名空间,

    以便找出匹配的空间。如果不存在带有指定名字的内核对象,该函数返回N U L L,G e t L a s t E r r o r

    返回2(E R R O R F I L E N O T F O U N D)。但是,如果存在带有指定名字的内核对象,并且它是

    相同类型的对象,那么系统就要查看是否允许执行所需的访问(通过d w D e s i r e d A c c e s s参数进

    行访问)。如果拥有该访问权,调用进程的句柄表就被更新,对象的使用计数被递增。如果为

    b I n h e r i t H a n d l e参数传递T R U E,那么返回的句柄将是可继承的。

    重:
    Microsoft没有提供唯一对象名的指导原则,所以同一程序的多个实例化就会有问题,不同程序间

    也可能有问题,解决之道是使用 GUID.

    为了保证对象的唯一性,建议创建一个G U I D,并将G U I D的字符串表达式用作对象名。

3. 使用复制内核对象句柄

    DuplicateHandle(只是在目标进程的句柄表创建了项目,目标进程对句柄值毫无所知)

    (

    HANDLE srcProHandle,

    HANDLE strHandle,

    HANDLE tagProHandle,

    PHANDLE tagHandle,  //返回目标进程的句柄值,此操作后需要IPC传递给目标进程

    ,

    ,

    )

    与继承性一样,D u p l i c a t e H a n d l e函数存在的奇怪现象之一是,目标进程没有得到关于新内

    核对象现在可以访问它的通知。因此, Process C必须以某种方式来通知Process T,它现在拥有

    对内核对象的访问权,并且必须使用某种形式的进程间通信方式,以便将h O b j中的句柄值传递

    给Process T,所以现在只需要某种IPC进程间通信,将句柄值传递到目标进程

    a.

        在Process C 调用 DuplicateHandle ,src 是 Process S ,dest 是Process T,这就涉及到三个进程

    b.

        通常,当只涉及两个进程时,才调用D u p l i c a t e H a n d l e函数。比如一个进程拥有对另一

        个进程想要访问的对象的访问权,或者一个进程想要将内核对象的访问权赋予另一个进程

    Process S有Process T想要访问的对象,那么在Process S 调用

    DuplicateHandle(GetCurrentProcess(), ....);

    接下来使用某种IPC通知Process T.

    DuplicateHandle的特别用处:

    假设一个进程拥有对一个文件映射对象的

    读和写访问权。在某个位置上,一个函数被调用,它通过读取文件映射对象来访问它。为了使

    应用程序更加健壮,可以使用D u p l i c a t e H a n d l e为现有的对象创建一个新句柄,并确保这个新句

    柄拥有对该对象的只读访问权。然后将只读句柄传递给该函数,这样,该函数中的代码就永远

    不会偶然对该文件映射对象执行写入操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息