问题: 什么是内核对象?

答:内核对象实际上时由内核分配的一块内存,而且只能由内核来访问。它时一个数据结构,成员包含有关于该对象的信息。一些成员对于所有对象类型都是一样的,比如对象名称、安全描述、使用计数等,而大部分时针对某一特定对象类型的。比如进程对象ID、基本优先级和返回码。

内核对象

windows操作系统创建和管理着已下几种类型。

 
对象英文名称 对象中文名称
Event objects 事件对象
File-mapping objects 文件映射对象
File objects 文件对象
Mailslot objects 邮件槽对象
Mutex objects 互斥对象
Pipe objects 管道对象
Process objects 进程对象
Semaphore objects 信号量对象
Thread objects 线程对象

问题:内核对象产生的途径是什么?

不同内核对象通过不同得到Win32API函数产生

内核对象的产生途径

内核对象的创建和访问 
内核对象的数据结构内容只能由内核访问,应用程序不可能在内存中定位和更改这些内容。应用程序只能使用win32 API函数来间接操作这些结构。
这些创建内核对象的函数返回一个标识该对象的句柄,这个句柄就是一个32位数值,它能被进程中任意线程使用。
内核对象的句柄都是进程相关的,如果一个句柄值船体给另一个进程的某一线程,这个进程试图访问该句柄时将会产生错误。当然,操作系统也允许通过一定方式进行多个进程间共享内核对象。
  • 计数
内核对象是属于内核而不是进程的,只有内核对象的句柄同进程相关!通过内核对象的计数,系统内核可以知道有多少个进程在使用某一内核对象。有一个进程访问该对象时,计数加1。进程终结时,计数减1。如果一个对象的计数变为0,内核将释放该对象。
  • 安全

内核对象能被一个安全描述保护着,这个安全描述描述了谁创建了该对象,谁能访问或使用该对象,谁对该对象的访问要被拒绝。

几乎所有创建核心对象的函数都有一个指向SECURITY_ATTRIBUTES结构的指针作为参数。一般而言都只是将这个参数设置为NULL,而这样创建的内核对象使用了缺省的安全属性。缺省的安全属性表明只有管理员和对象的创建者对它有完全的访问权限,其他都不能访问该对象。

typedef struct _SECURITY_ATTRIBUTES{
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
}SECURITY_ATTRIBUTES;

SECURITY_ATTRIBUTES结构

结构中lpSecurityDescriptor是描述安全的

SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE; HANDLE hFileMapping = CreateFileMapping((HANDLE) 0xffffffff,&sa,PAGE_READWRITE,,,"MyFileMapping");
  • 进程的内核对象句柄表

进程初始化时,系统为进程分配一张句柄表。这个句柄表只用于内核对象,而不用于用户或GDI对象。

进程首次初始化时,句柄表时空白的。如果进程一个线程调用了创建内核对象的函数,内核就为该对象分配一块内存,并初始化它;然后内核扫描进程的句柄表来寻找一个空白项,找到空白项后进行初始化。

所有创建内核对象的函数都返回一个进程相关的句柄,因为时进程相关的,所以能够在本进程中所有线程中使用。这个句柄值实际上时进程的句柄表中知名内核对象的信息存取之处的索引。

因为时进程相关的,句柄值时进程句柄表中的索引,所以在其他进程中不能正确使用。

创建内核对象的函数如果失败,返回的句柄值通常是0(NULL)。通常原因是系统的可用内存太少了,或者发生了安全性问题。不过有几个函数失败时返回的句柄时-1(INVALID_HANDLE_VALUE),比如CreateFile没能打开指定文件时就返回-1而不是0。在判断是否调用成功时要看情况比较:

HANDLE hMutex = CreateMutex(...);
if(hMutex == INVALID_HANDLE_VALUE)
{
//下列代码将永远不会执行
//因为CreateMutex失败时返回的是NULL而不是INVALID_HANDLE_VALUE
}

下面判断是否成功的代码是错误的

  • 关闭内核对象

不管内核对象是如何创建的,都是通过调用CloseHandle来告诉操作系统已经完成了对对象的操作。BOOL CloseHandle(HANDLE hobj);

如果忘记了调用CloseHandle,可能会发生内存泄漏。不过当进程终结时,操作系统将释放所有资源。

进程间共享内核对象

需要共享内核对象的原因:

  1. 文件映像对象允许运行在同一计算机上的两个进程共享数据库块。
  2. 邮件槽和命名管道允许应用程序在联网的计算机的进程之间传送数据块。
  3. 互斥量、信号量和事件允许不同进程中的线程同步他们的行动。

共享内核对象的3种机制:

  1. 对象句柄继承
  2. 对象句柄命名
  3. 对象句柄复制
  • 对象句柄继承

当进程存在父子关系时才能使用对象句柄继承。在这种情况下,父进程拥有一个或多个内核对象句柄,它决定派生出一个子进程,给子进程访问它的内核对象权限。要实现这种操作,父进程必须执行若干操作。

首先,父进程创建内核对象时,它必须告诉系统它想让该对象的句柄能够被继承。注意,内核对象的句柄是可继承的,内核对象本身却不是。

要创建一个可继承的句柄,父进程必须分配和初始化一个SECURITY_ATTRIBUTES结构,并把该结构的地址传递给特定的Create*函数。这个SECURITY_ATTRIBUTES结构的bInheritHandle需要为TRUE。

下面,用父进程派生出子进程。调用CreateProcess函数时参数BOOL bInheritHandles需要为TRUE,子进程这时候将继承父进程的可继承的句柄值。

创建子进程时,操作系统也会像创建任何新进程一样,给一张新的、空的进程的句柄表。由于CreateProcess的bInheritHandles参数为TRUE,系统将多做一件事:查看父进程的句柄表,将每条可继承的句柄表项拷贝到子进程的句柄表种。拷贝到子进程句柄表种的位置同父进程的句柄表一模一样。

除了拷贝句柄表项之外,系统还增加内核对象的使用计数。

***注意:对象句柄继承只发生在派生子进程的那一时刻,如果父进程要创建带可继承句柄的内核对象,这些新句柄将不能被已经运行着的子进程继承。

对象句柄继承有个特点:子进程并不知道已经继承了句柄。因此,需要通过几个方式将句柄值传给子进程。一般有3种方式:1.将句柄值作为命令行参数传给子进程。2.使用其他形式的进程间通信来从父进程向子进程传递继承的内核对象句柄值3.使用父进程的环境变量,因为子进程能继承父进程的环境变量表,可以容易地调用GetEnvironmentVariable函数来得到被继承的对象句柄值。

  • 命名对象

第二种进程间共享内核对象的方法是给对象命名。虽然不是全部,但是很多内核对象能够被命名。

创建内核对象时,将参数lpszName赋值为以0结尾的字符串名字,而不是NULL。就实现了对内核对象命名。

***注意:在系统种,互斥量、事件、信号量、文件映射和等待记时器都共享一个名字空间。因此,要创建一个名为"JeffObj"对象,不能保证系统中没有名为"JeffObj"对象存在。

如果进程A使用CreateMutex创建了一个"JeffMutex"互斥对象后,当进程B调用CreateMutex(NULL,FALSE,"JeffMutex")后,系统首先检查是否已经存在一个名为"JeffMutex"的内核对象。因为存在名字叫这个名字的对象,内核会继续检查对象的类型。通过检查发现名为"JeffMutex"的对象也是一个互斥对象,系统就认为进程B对CreateMutex的调用成功了。也就是说,系统在进程B的句柄表中找到一个空表项,然后初始化该表项指向已经存在的内核对象。

***注意:进程A和进程B没有继承关系,虽然都是操作“JeffMutex"互斥对象,但是A和B进程中的句柄值很可能时不同的值,两个进程分别使用了自己的句柄值。
当然,除了Create*函数还可以用Open*函数来创建通过名字的共享对象。不过Create*在没有这个名字的内核对象时创建这个内核对象,而Open*在没有命名的对象时返回失败。

  • 复制对象句柄

在进程之间共享内核对象句柄的最后一个技术是使用DuplicateHandle函数。

BOOL DuplicateHandle(
HANDLE hSourceProcessHandle, HANDLE hSourceHandle,
HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle,
DWORD dwDesiredAccess, BOOL bInheritHandle,DWORD dwOptions);

函数DuplicateHandle

  这个函数取得某个进程句柄表中的一个表项,然后把它拷贝到另一个进程的句柄表中。

第1个和第3个参数,hSourceProcessHandle和hTargetProcessHandle是内核对象句柄。他们本身必须是相对于调用该函数的进程的,而且,着两个参数必须标识进程内核对象。如果传递其他类型的内核对象句柄,函数就会失败。第2个参数hSourceHandle是任意类型的内核对象的句柄。这个句柄值不是相对于调用该函数的进程,必须相对于句柄hSourceProcessHandle所标识的进程。第4个参数lpTargetHandle是一个HANDLE变量的地址,它将接受得到源句柄信息的拷贝的表项的索引值。返回的该句柄值是相对于由hTargetProcessHandle所标识的进程。

内核对象 windows操作系统的更多相关文章

  1. Windows核心编程&内核对象

    1. 一个进程在初始化时,系统将会他分配一个空的句柄表,这个句柄表仅供内核对象使用,不供用户对象和GDI对象使用.进程在首次 初始化时,该句柄表为空.句柄表是一个由数据结构组成的数组,包含一个内核对象 ...

  2. Windows内核对象

    1. 内核对象 Windows中每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核进行访问,应用程序不能在内存中定位这些数据结构并直接更改其内容.这个内存块是一个数据结构,其成员 ...

  3. 【Windows 操作系统】Windows 进程的内核对象句柄表

    总结: 1.句柄就是进程句柄表中的索引.2.句柄是对进程范围内一个内核对象地址的引用,一个进程的句柄传给另一个进程是无效的.一个内核对象可用有多个句柄.Windows之所以要设立句柄,根本上源于内存管 ...

  4. 【Windows 操作系统】 内核对象|句柄

    内核对象简介 内核对象就是 一些数据结构该结构用来描述存储内核中的一个内存块中的数据信息.   内存块是一种数据结构,其中的数据成员负责维护该对象的相应信息,这个数据结构以及其中的数据成员只能由内核访 ...

  5. Windows API学习---线程与内核对象的同步

    前言 若干种内核对象,包括进程,线程和作业.可以将所有这些内核对象用于同步目的.对于线程同步来说,这些内核对象中的每种对象都可以说是处于已通知或未通知的状态之中.这种状态的切换是由Microsoft为 ...

  6. Windows Internals 笔记——内核对象

    1.每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问.这个内存块是一个数据结构,其成员维护着与对象相关的信息. 2.调用一个会创建内核对象的函数后,函数会返回一个句柄,它标 ...

  7. Windows进程的内核对象句柄表

    当一个进程被初始化时,系统要为它分配一个句柄表.该句柄表只用于内核对象 ,不用于用户对象或GDI对象. 创建内核对象 当进程初次被初始化时,它的句柄表是空的.然后,当进程中的线程调用创建内核对象的函数 ...

  8. windows编程之内核对象

          学好windows编程,理解内核对象还是至关重要的(●'◡'●).闲话不多说,下面先来了解一下关于内核对象的知识:       内核对象(kernel object):内核对象是用于管理进 ...

  9. Windows核心编程 第九章 线程与内核对象的同步(下)

    9.4 等待定时器内核对象 等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象.它们通常用来在某个时间执行某个操作. 若要创建等待定时器,只需要调用C r e a t e Wa i ...

随机推荐

  1. 人生苦短 我用Python 第二周的第一天 (数据类型)

    数字:  整形  int  长整形(Python3里面把整形.长整形和到一起啦) 浮点型( float) 1.3 5.2 等等  科学技术发表示 1.3e-3=0.0013 e的代表10. bin是二 ...

  2. 在Windows的Dos命令中切换盘符

    在Windows的Dos命令中切换盘符... ---------------------------- --------------------------------------- -------- ...

  3. 2_linux 常用基本命令

    相信当你看到此帖子时,你已不再是当年那个颓废的你,你一定也在追梦的路上奔跑,那么请留下你的“梦”,让我们用心去交流,好吗? 废话不多说,直接说正事! 一.查看磁盘分区 1.fdisk -l  查看磁盘 ...

  4. 再起航,我的学习笔记之JavaScript设计模式15(组合模式)

    组合模式 组合模式(Composite): 又称部分-整体模式,将对象组合成树形结构以表示"部分整体"的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性. 如果有一个 ...

  5. open文件操作之mode模式剖析

    Python可以使用open函数来实现文件的打开,关闭,读写操作: Python3中的open函数定义为: open(file, mode='r', buffering=None, encoding= ...

  6. jquery的2.0.3版本源码系列(2):21行-94行定义了一些变量和函数 jQuery=function(){}

    2.1.bug通过索引查询 这里的#13335是bug的索引,如何查询呢? 第一步,浏览器地址栏输入"https://bugs.jquery.com/". 第二步,在网页的搜索框里 ...

  7. TCP协议三次握手与四次挥手通俗解析

    TCP/IP协议三次握手与四次握手流程解析 一.TCP报文格式 TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: 图1 TCP报文格式 上图中有几个字 ...

  8. java选择排序详解

    排序算法--选择排序 public class Selector implements ISortAble{ @Override public void sort(int[] a) { int n=a ...

  9. HTTPS 证书配置

    HTTPS 证书配置 现在阿里云和腾讯云都支持申请 HTTPS 证书,这里不再提,有需要的可自行google解决方案. 本文主要介绍的是通过 letsencrypt 申请免费的HTTPS证书,并将其配 ...

  10. webSocket浏览器握手不成功(解决)

    websocket与服务端握手会报握手不成功的错误解决方法: 首先是服务端首次收到请求要回报给客户端的报文要做处理多的不说,方法敬上: /// <summary> /// 打包请求连接数据 ...