Windows Internals 笔记——内核对象
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 笔记——内核对象的更多相关文章
- Windows核心编程&内核对象
1. 一个进程在初始化时,系统将会他分配一个空的句柄表,这个句柄表仅供内核对象使用,不供用户对象和GDI对象使用.进程在首次 初始化时,该句柄表为空.句柄表是一个由数据结构组成的数组,包含一个内核对象 ...
- Windows Internals 笔记——关联性
1.默认情况下,Windows Vista在给线程分配处理器时,使用软关联.意思是如果其他因素都一样,系统将使线程在上一次运行的处理器上运行.让线程始终在同一个处理器上运行有助于重用仍在处理器高速缓存 ...
- Windows Internals 笔记——线程调度
1.线程内核对象中的CONTEXT反应了线程上一次执行时CPU寄存器的状态.大约每隔20ms,Windows都会查看所有当前存在的线程内核对象.Windows在可调度的线程内核对象中选择一个,并将上次 ...
- Windows Internals 笔记——线程
1.进程有两个组成部分,一个进程内核对象和一个地址空间.线程也有两个组成部分: 一个是线程的内核对象,操作系统用它管理线程.系统还用内核对象来存放线程统计信息的地方. 一个线程栈,用于维护线程执行时所 ...
- Windows Internals 笔记——作业
1.Windows提供了一个作业内核对象,它允许我们将进程组合在一起并创建一个“沙箱”来限制进程能够做什么.创建只包含一个进程的作业同样非常有用,因为这样可以对进程施加平时不能施加的限制. 2.如果进 ...
- Windows Internals 笔记——CreateProcess
1.一个线程调用CreateProcess时,系统将创建一个进程内核对象,其初始使用计数为1.然后系统为新进程的主线程创建一个线程内核对象(使其计数为1). 2.CreateProcess在进程完全初 ...
- Windows Internals 笔记——进程
1.一般将进程定义成一个正在运行的程序的一个实例,由以下两部分构成: 一个内核对象,操作系统用它来管理进程,内核对象也是系统保存进程统计信息的地方. 一个地址空间,其中包含所有可执行文件或DLL模块的 ...
- Windows进程的内核对象句柄表
当一个进程被初始化时,系统要为它分配一个句柄表.该句柄表只用于内核对象 ,不用于用户对象或GDI对象. 创建内核对象 当进程初次被初始化时,它的句柄表是空的.然后,当进程中的线程调用创建内核对象的函数 ...
- windows编程之内核对象
学好windows编程,理解内核对象还是至关重要的(●'◡'●).闲话不多说,下面先来了解一下关于内核对象的知识: 内核对象(kernel object):内核对象是用于管理进 ...
随机推荐
- 输入输出流ObjectInputStream、ObjectOutputStream(对象序列化与反序列化)
对象的输入输出流 : 主要的作用是用于写入对象信息与读取对象信息. 对象信息一旦写到文件上那么对象的信息就可以做到持久化了 对象的输出流: ObjectOutputStream 对象的输入流: Ob ...
- Django标签和过滤器
过滤器格式{{ }} 标签格式{% %} 模板中过滤器filter只能使用一个参数,自定义标签中则可以使用多个参数!!! 过滤器能够采用链式的方式使用,例如:{{ text | escape | ...
- VUE实例方法添加、COOKIE、Token
创建COOKIE const COOKIE = { KEY_TOKEN: 'access_token', KEY_USER: 'nbuser', KEY_PERMISSION: 'nb-permiss ...
- 爬虫免登录进入github
import requests import re ret = requests.get('https://github.com/login') print(ret.headers) cookies ...
- Swagger如何测试Date类型参数
问题 Swagger测试时,参数直接输入日期格式化后的类型,会报参数日期转换错误 :ConversionFailedException 解决 网上说在参数上添加注解 @DateTimeFormat(p ...
- 4.6 并发编程/IO模型
并发编程/IO模型 背景概念 IO模型概念 IO模型分类 阻塞IO (blocking IO) 特点: 两个阶段(等待数据和拷贝数据两个阶段)都被block 设置 server.setsockopt ...
- 多版本python及多版本pip使用
最近做一些网站的发布程序,要用到python3,所以又安装了python3. www.qlrx.netwww.393662.comwww.qnpx.netwww.393225.com ...
- [BJOI2019] 光线
看起来很麻烦,做起来并不难的题 以下设:$a_i=\frac{a_i}{100},b_i=\frac{b_i}{100}$ 显然,如果$b_i=0$的话,直接求$\Pi a_i$就是答案. 解决反射问 ...
- Java基础 -- 访问控制权限
一 包:库单元 假设我们存在两个类名相同的类,如果没有一定的措施对其进行区分,就会无法区别到底使用的是哪一个类.因此java引入了包来进行名字空间管理. 包(类库)包含有一组类,这些类在单一的名字空 ...
- chrome headless 无头浏览器 应用
1. 根据html生成pdf chrome.exe --headless --disable-gpu --print-to-pdf ...../index.html 2. puppeteer --- ...