1.每个内核对象都只是一个内存块,它由操作系统内核分配,并只能由操作系统内核访问。这个内存块是一个数据结构,其成员维护着与对象相关的信息。

2.调用一个会创建内核对象的函数后,函数会返回一个句柄,它标识了所创建的对象。在32位windows进程中,句柄是一个32位的值,在64位windows进程中,则是一个64位的值。

3.为了增强操作系统的可靠性,这些句柄值是与进程相关的,不可以直接跨进程使用。

4.内核对象的所有者是操作系统内核,而非进程,在进程内创建的内核对象在进程终止时不一定会被销毁。大多数情况下是会被销毁的,但是假如另一个进程正在使用我们的进程创建的内核对象,那么在其他进程停止使用它之前是不会被销毁的。

5.操作系统的内核知道当前有多少个进程正在使用一个特定的内核对象,因为每个对象都包含一个使用计数。使用计数是所有内核对象类型都有的一个数据成员。初次创建 一个对象的时候,使用计数被设为1,另一个进程获得对现有内核对象的访问后,使用计数就会递增。进程终止运行后,操作系统内核将自动递减此进程仍然打开的所有内核对象的使用计数。一旦使用计数变成0,操作系统内核就会销毁该对象。可以保证系统中不存在没有被任何进程引用的内核对象。

6.内核对象可以用一个安全描述符来保护。安全描述符描述了谁拥有对象,哪些组和用户被允许/拒绝访问或使用此对象。

7.一个进程在初始化时,系统将为它分配一个句柄表。这个句柄表仅供内核对象使用。

8.系统用索引来表示内核对象的信息保存在进程句柄表中的具体位置,要得到实际的索引值,句柄值实际应该除以4(忽略Windows操作系统内部使用的最后两位)。

9.CloseHandle() 会先检查句柄是否有效,如果有效,系统就将获得内核对象的数据结构的地址,并将结构中的“使用计数”成员递减,如果变成0,则内核对象将被销毁,并从内存中移出去。

10.在CloseHandle() 函数返回之前,它会清除进程句柄表中对应的记录项,无论内核对象当前是否销毁,这个清除过程都会发生。

11.三种不同的机制允许进程共享内核对象:使用对象句柄继承,为对象命名,复制对象句柄。

使用对象句柄继承

1.只有在进程之间有一个父子关系的时候,才可以使用对象句柄继承。句柄表中的每个记录项都有一个指明句柄是否可以继承的标志位,如果PSECURUTY_ATTRIBUTES传入的参数时NULL,则返回的句柄是不可继承的,这个标志位为0,将bInheritHandle成员设置为TRUE,则导致这个标志位被设为1。

2.例如在CreateProcess函数的bInheritHandles参数的值是TRUE,系统会遍历父进程的句柄表,对它的每一个记录项进行检查,凡是包含一个有效的"可继承的句柄"项,都会被完整地复制到子进程的句柄表。而且在子进程的句柄表中,复制项的位置与它在父进程句柄表中的位置是完全一样的。也意味着:在父进程和子进程中,对一个内核对象进行标识的句柄值是完全一样的。同时系统还会递增内核对象的使用计数。同理,孙进程也会继承这个内核对象句柄。

3.对象句柄的继承只会发生在生成子进程的时候,假如父进程后来又创建了新的内核对象,那么子进程是不会继承这些新的句柄。

4.子进程并不知道自己继承了任何句柄。

5. SetHandleInformation()函数可以用来改变内核对象句柄的继承标志,GetHandleInformation()可以获得指定句柄的状态标志。

为对象命名

1.所有对象都共享同一个命名空间,即使它们类型并不相同。

2.如果进程A中已经创建了一个命名对象(即使是不可继承的),那么在进程B中以同样的名字来创建命名对象时,系统会首先查看是否存在相同名称的内核对象,如果确实存在,内核接着检查对象的类型,如果类型不匹配就会返回NULL。如果匹配则系统接着执行一次安全检查,严重调用者是否拥有对该对象的完全访问权限,如果拥有则系统会在进程B的句柄表中查找一个空白记录项,并将其初始化为指向现有的内核对象。如果被拒绝访问,则失败。

    // Process A
HANDLE hMutexA = CreateMutex(NULL,false,_T("MyMutex")); // Process B
HANDLE hMutexB = CreateMutex(NULL, false, _T("MyMutex"));

3.用于创建内核对象的函数(比如CreateSemaphore)总是返回具有完全访问权限的句柄。如果想限制一个句柄的访问权限,可以使用这些函数的扩展版本(*ex)。

4.由于在进程B的句柄表中,用一个新的记录项来引用了这个对象,所以这个互斥量对象的使用计数会被增加。

5。进程B创建内核对象时,如果已经存在,则传递的安全属性和其他参数会被忽略。

6.调用Create*函数和调用Open*函数的主要区别在于,如果对象不存在,Create*会创建,Open*只是调用失败。

7.终端服务的情况和前面描述的稍微有所区别。正在运行终端服务的计算机中,有多个用于内核对象的命名空间。其中一个时全局命名空间,所有客户端都能访问的内核对象要放在这个命名空间中。这个命名空间主要由服务使用。此外,每个客户端会话都有一个自己的命名空间,这样即使对象的名称相同也会不互相干扰。并非只有服务器才会遇到这种情况,因为Remote Desktop和快速用户切换特性也是利用终端服务会话来实现的。

8.在没有任何用户登陆的时候,服务会在第一个会话(Session 0)中启动,这个会话不是交互式的。和以前的版本不同,在Windows Vista中,只要用户登陆,应用程序就会在一个新的会话(与Session 0不同的一个会话)中启动。所以.任何对象想要和用户应用程序共享,都必须在全局命名空间中创建它。

9.如果必须知道我们的进程在哪个Terminal Services会话中运行,可以借助于ProcessIdToSessionId函数。

10.一个服务的命名内核对象始终位于全局命名空间内。默认情况下,在终端服务中,应用程序自己的命名内核对象在会话的命名空间内。不过我们可以在其名称前加上“Global\”前缀强制把一个命名对象放入全局命名空间。或者在名称前加上“Local\”前缀把内核对象放入当前会话的命名空间中。

HANDLE hGlobal = CreateEvent(NULL,FALSE,FALSE,_T("Global\\MyName"));
HANDLE hLocal = CreateEvent(NULL, FALSE, FALSE, _T("Local\\MyName"));

11.Microsoft认为Global和Local是保留关键字,所以除非为了强制一个特定的命名空间,否则不应在对象名称中使用它们。Session也是保留关键字,我们可以使用Session\<当前会话ID>\,但是不能使用另一个会话中的名称和Session前缀来新建一个对象,这样会导致函数调用失败。

12.所有保留关键字都是区分大小写的。

复制对象句柄

1.DuplicateHandle函数获得一个进程的句柄表中的一个记录项,然后在另一个进程的句柄表中创建这个记录项的一个副本。其第一个和第三个参数必须是进程内核对象。第二个参数是指向任何类型的内核对象的一个句柄。但是它的句柄值一定不能与调用DuplicateHandle函数的那个进程相关。

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

2.进程中永远不要关闭为另外一个进程复制出来的句柄。

Windows Internals 笔记——内核对象的更多相关文章

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

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

  2. Windows Internals 笔记——关联性

    1.默认情况下,Windows Vista在给线程分配处理器时,使用软关联.意思是如果其他因素都一样,系统将使线程在上一次运行的处理器上运行.让线程始终在同一个处理器上运行有助于重用仍在处理器高速缓存 ...

  3. Windows Internals 笔记——线程调度

    1.线程内核对象中的CONTEXT反应了线程上一次执行时CPU寄存器的状态.大约每隔20ms,Windows都会查看所有当前存在的线程内核对象.Windows在可调度的线程内核对象中选择一个,并将上次 ...

  4. Windows Internals 笔记——线程

    1.进程有两个组成部分,一个进程内核对象和一个地址空间.线程也有两个组成部分: 一个是线程的内核对象,操作系统用它管理线程.系统还用内核对象来存放线程统计信息的地方. 一个线程栈,用于维护线程执行时所 ...

  5. Windows Internals 笔记——作业

    1.Windows提供了一个作业内核对象,它允许我们将进程组合在一起并创建一个“沙箱”来限制进程能够做什么.创建只包含一个进程的作业同样非常有用,因为这样可以对进程施加平时不能施加的限制. 2.如果进 ...

  6. Windows Internals 笔记——CreateProcess

    1.一个线程调用CreateProcess时,系统将创建一个进程内核对象,其初始使用计数为1.然后系统为新进程的主线程创建一个线程内核对象(使其计数为1). 2.CreateProcess在进程完全初 ...

  7. Windows Internals 笔记——进程

    1.一般将进程定义成一个正在运行的程序的一个实例,由以下两部分构成: 一个内核对象,操作系统用它来管理进程,内核对象也是系统保存进程统计信息的地方. 一个地址空间,其中包含所有可执行文件或DLL模块的 ...

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

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

  9. windows编程之内核对象

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

随机推荐

  1. Java中反射机制详解

    序言 在学习java基础时,由于学的不扎实,讲的实用性不强,就觉得没用,很多重要的知识就那样一笔带过了,像这个马上要讲的反射机制一样,当时学的时候就忽略了,到后来学习的知识中,很多东西动不动就用反射, ...

  2. SpringMVC DispatcherServlet在配置Rest url-pattern的一点技巧

    SpringMVC的Controller中已经有了@RequestMapping(value = "detail.do", method = RequestMethod.GET)的 ...

  3. Django初印象之视图(view)

    一.view的初印象 一个视图函数(类),简称视图.我们发起web请求时,返回的web响应.[大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件中.] ...

  4. [模板] 数学基础:快速幂/乘/逆元/exGCD/(ex)CRT/(ex)Lucas定理

    方便复制 快速乘/幂 时间复杂度 \(O(\log n)\). ll nmod; //快速乘 ll qmul(ll a,ll b){ ll l=a*(b>>hb)%nmod*(1ll< ...

  5. UVA 10118 Free Candies

    https://vjudge.net/problem/UVA-10118 题目 桌上有4堆糖果,每堆有$N$($N\leqslant 40$)颗.有个熊孩子拿了个可以装5颗糖的篮子,开始玩无聊的装糖游 ...

  6. (二分查找 拓展) leetcode278. First Bad Version

    You are a product manager and currently leading a team to develop a new product. Unfortunately, the ...

  7. 第五节: Quartz.Net五大构件之Trigger的四大触发类

    一. WithSimpleSchedule(ISimpleTrigger) 1. 用途:时.分.秒上的轮询(和timer类似),实际开发中,该场景占绝大多数. 2. 轮询的种类:永远轮询和限定次数轮询 ...

  8. DTO/DO等POJO对象的使用场景和 orika-mapper 框架的使用

    对于项目而言, 我们一般会有DAO->Service->Controller分层设计, 这些层次体现了每层的作用, 而层次之间的数据传递对象设计很少被提及, 下面是一个相对完整的数据转换过 ...

  9. MD5 两次加密

    1.添加依赖 <dependency> <groupId>commons-codec</groupId> <artifactId>commons-cod ...

  10. [译]Ocelot - Delegating Handlers

    原文 可以为HttpClient添加delegating handlers. Usage 为了添加delegating handler需要做两件事. 首先如下一样创建一个类. public class ...