一:何为内核对象
每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问。这个内存块是一个数据结构,其成员维护着与对象相关的信息。
二:使用计数
每个内核对象都包含一个使用计数,初次创建一个对象的时候,其使用计数被设为1.另一个进程获得对现有内核对象的访问后,使用计数就会递增;进程终止,操作系统内核自动递减打开的所有内核对象的使用计数。若使用计数变为0,则操作系统内核就会销毁该对象。
三:进程内核对象句柄表(一个指向内核对象的指针,一个访问掩码,一些标志)
一个进程在初始化时,系统将为它分配一个句柄表。这个句柄表仅供内核对象使用,不适用于用户对象或GDI对象。一个进程首次初始化的时候,其句柄表为空。当进程的一个线程调用一个会创建内核对象的函数时,内核将为这个对象分配并初始化一个内存块,然后扫描进程的句柄表,查找一个空白的记录项,并对其初始化。(指针成员会被设置成内核对象的数据结构内部内存地址,访问掩码被设置成拥有完全访问权限,标志也会被设置)
用于创建内核对象的任何函数都会返回一个与进程相关的句柄,这个句柄可由同一个进程中运行的所有线程使用。系统用索引来表示内核对象的信息保存在进程句柄表中的具体位置,要得到实际的索引值,句柄值实际应该除以4。由于句柄值实际是作为进程句柄表的索引来使用的,所以这些句柄是与当前这个进程相关的,无法供其他进程使用。
调用函数创建一个内核对象时,若调用失败,那么返回的句柄值通常为0,即为第一个有效的句柄值为4.
四:关闭内核对象
在CloseHandle函数返回之前,会清除进程句柄表中对应的记录项—这个句柄现在对我们的进程来说是无效的,无论内核对象是否销毁,这个清除过程都会发生。
当进程终止时,系统能保证一切都被正确的清除,这适用于所有内核对象,资源以及内存块。进程终止时,系统会确保我们的进程不会留下任何东西。
五:进程共享内核对象
(1)使用对象句柄继承:
只有在进程之间有一个父子关系的时候,才可以使用对象句柄继承。父进程有一个或多个内核对象句柄可以使用,而且父进程决定生成一个子进程,并允许子进程访问父进程的内核对象。
首先,当父进程创建一个内核对象时,父进程必须向系统指出它希望这个对象的句柄是可以继承的(可将对应记录项的是否继承的标志位置1);其次由父进程生成子进程,指定其中的一个参数bInheritHandles参数为TRUE,子进程就会继承父进程的“可继承的句柄”值。传递TRUE时,操作系统会创建新的子进程,但不允许子进程立即执行它的代码。系统为子进程创建一个新的,空白的进程句柄表;然后会遍历父进程的句柄表,对它的每一个记录进行检查,凡是包含一个有效的“可继承的句柄”的项,都会被完整地复制到子进程的句柄表。在子进程的句柄表中,复制项的位置与它在父进程句柄表中的位置是完全一样的,系统还会递增内核对象的使用计数。
内核对象的内容被保存在内核地址空间中—系统上运行的所有进程都共享这个空间。对32位系统,是ox80000000到oxFFFFFFFF之间的内存空间,对64位系统,是0x00000400'00000000到0xFFFFFFFF'FFFFFFFF之间的内存空间。对象句柄的继承只会在生成子进程的时候发生。
(2)为对象命名
对象命名都共享同一个命名空间,即使它们的类型并不相同。
HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("JeffObj"));
HANDLE hSem = CreateSemaphore(NULL, 1, 1, TEXT("JeffObj"));
第二个函数肯定会调用失败。
以此种方式共享对象的方法:
HANDLE hMutexProcessA = CreateMutex(NULL, FALSE, TEXT("JeffMutex")); 进程A创建一个新的互斥量内核对象,后来某个进程B(B不一定是A的子进程)执行以下代码:
HANDLE hMutexProcess = CreateMutex(NULL, FALSE, TEXT("JeffMutex")); 系统查看是否存在一个名为“JeffMutex”的内核对象。若存在,内核接着检查对象的类型,若相同则接着执行一次安全检查,若肯定,系统就会在进程B的句柄表中查找一个空白的记录项,并将其初始化为指向现有的内核对象。若对象的类型不匹配,或拒绝访问,则会失败。
(3)复制对象句柄
使用DuplicateHandle函数,原型如下:
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
HANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions
);
这个函数获得一个进程的句柄表中的一个记录项,然后在另一个进程的句柄表中创建这个记录项的一个副本。
每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问。这个内存块是一个数据结构,其成员维护着与对象相关的信息。
二:使用计数
每个内核对象都包含一个使用计数,初次创建一个对象的时候,其使用计数被设为1.另一个进程获得对现有内核对象的访问后,使用计数就会递增;进程终止,操作系统内核自动递减打开的所有内核对象的使用计数。若使用计数变为0,则操作系统内核就会销毁该对象。
三:进程内核对象句柄表(一个指向内核对象的指针,一个访问掩码,一些标志)
一个进程在初始化时,系统将为它分配一个句柄表。这个句柄表仅供内核对象使用,不适用于用户对象或GDI对象。一个进程首次初始化的时候,其句柄表为空。当进程的一个线程调用一个会创建内核对象的函数时,内核将为这个对象分配并初始化一个内存块,然后扫描进程的句柄表,查找一个空白的记录项,并对其初始化。(指针成员会被设置成内核对象的数据结构内部内存地址,访问掩码被设置成拥有完全访问权限,标志也会被设置)
用于创建内核对象的任何函数都会返回一个与进程相关的句柄,这个句柄可由同一个进程中运行的所有线程使用。系统用索引来表示内核对象的信息保存在进程句柄表中的具体位置,要得到实际的索引值,句柄值实际应该除以4。由于句柄值实际是作为进程句柄表的索引来使用的,所以这些句柄是与当前这个进程相关的,无法供其他进程使用。
调用函数创建一个内核对象时,若调用失败,那么返回的句柄值通常为0,即为第一个有效的句柄值为4.
四:关闭内核对象
在CloseHandle函数返回之前,会清除进程句柄表中对应的记录项—这个句柄现在对我们的进程来说是无效的,无论内核对象是否销毁,这个清除过程都会发生。
当进程终止时,系统能保证一切都被正确的清除,这适用于所有内核对象,资源以及内存块。进程终止时,系统会确保我们的进程不会留下任何东西。
五:进程共享内核对象
(1)使用对象句柄继承:
只有在进程之间有一个父子关系的时候,才可以使用对象句柄继承。父进程有一个或多个内核对象句柄可以使用,而且父进程决定生成一个子进程,并允许子进程访问父进程的内核对象。
首先,当父进程创建一个内核对象时,父进程必须向系统指出它希望这个对象的句柄是可以继承的(可将对应记录项的是否继承的标志位置1);其次由父进程生成子进程,指定其中的一个参数bInheritHandles参数为TRUE,子进程就会继承父进程的“可继承的句柄”值。传递TRUE时,操作系统会创建新的子进程,但不允许子进程立即执行它的代码。系统为子进程创建一个新的,空白的进程句柄表;然后会遍历父进程的句柄表,对它的每一个记录进行检查,凡是包含一个有效的“可继承的句柄”的项,都会被完整地复制到子进程的句柄表。在子进程的句柄表中,复制项的位置与它在父进程句柄表中的位置是完全一样的,系统还会递增内核对象的使用计数。
内核对象的内容被保存在内核地址空间中—系统上运行的所有进程都共享这个空间。对32位系统,是ox80000000到oxFFFFFFFF之间的内存空间,对64位系统,是0x00000400'00000000到0xFFFFFFFF'FFFFFFFF之间的内存空间。对象句柄的继承只会在生成子进程的时候发生。
(2)为对象命名
对象命名都共享同一个命名空间,即使它们的类型并不相同。
HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("JeffObj"));
HANDLE hSem = CreateSemaphore(NULL, 1, 1, TEXT("JeffObj"));
第二个函数肯定会调用失败。
以此种方式共享对象的方法:
HANDLE hMutexProcessA = CreateMutex(NULL, FALSE, TEXT("JeffMutex")); 进程A创建一个新的互斥量内核对象,后来某个进程B(B不一定是A的子进程)执行以下代码:
HANDLE hMutexProcess = CreateMutex(NULL, FALSE, TEXT("JeffMutex")); 系统查看是否存在一个名为“JeffMutex”的内核对象。若存在,内核接着检查对象的类型,若相同则接着执行一次安全检查,若肯定,系统就会在进程B的句柄表中查找一个空白的记录项,并将其初始化为指向现有的内核对象。若对象的类型不匹配,或拒绝访问,则会失败。
(3)复制对象句柄
使用DuplicateHandle函数,原型如下:
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
HANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions
);
这个函数获得一个进程的句柄表中的一个记录项,然后在另一个进程的句柄表中创建这个记录项的一个副本。