WINDOWS的内核对象——《windows核心编程》读书笔记

    技术2022-07-01  91

     

    1.内核对象概念

    凡是OS内核调度时所需要的数据结构都被称为内核对象,其实质是一个结构体对象而已,如进程对象,它的本质为一个PCB(进程控制块),是一个数据结构,用来标识进程的一些属性。这些对象的一个显著特征是:不能由用户来直接改变其内部信息,对于程序员来说,它就是一个黑盒子(实际上,就是这些黑盒子,才是WINDOWS的摇钱树)。而WIDOWS提供了一些专门用来访问这些信息的API函数(今天的主题),这就方便了程序员来控制自己的内核对象(如进程,线程等)。

    2.内核对象的引用计数

    需要注意的是:内核对象是由内核所拥有,而不是用户所创建的进程所拥有。即当一个进程撤销后,这个进程所创建的内核对象不一定会撤销。如果另一个进程在使用这个内核对象,那么此内核对象的引用计数仅仅减1,当内核对象的应用计数减为0时,内核此时才撤销内核对象。意即:内核对象的生存期不小于进程的生存期。

    3.内核对象安全性

    内核对象由内核来使用,其安全性也是必须要保证的。基本上每一个创建内核对象的函数都有一个指向SECURITY_ATTRBUTES的结构指针,此结构体的具体信息如下:

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

     真正用来描述其安全性的成员只有lpSecurityDescriptor。如果要限制别人对此内核对象的使用,必须对这个安全描述符进行初始化。如下所示:

      SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); //Used for versioning sa.lpSecuntyDescriptor = pSD, //Address of an initialized SD sa.bInheritHandle = FALSE; //Discussed later HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_REAOWRITE, 0, 1024, "MyFileMapping");

     当为lpSecurityDescriptor参数传递NULL时,系统将为其设置一个默认的安全属性。默认安全意味着对象的管理小组成员和创建者对其具有访问权,其它人均无法访问该对象。

     

    4.内核对象的句柄表

     

    当一个进程被初始化时,系统要为之创建一个句柄表,每个进程只有唯一一个句柄表(以前在用MFC写DLL时,遇到DLL中窗口和主进程间的通信问题,实际上,在EXPORT函数中返回一个窗口的指针是徒劳的,因为此指针只是当前DLL模块中的相对地址,在切换到主进程时,此指针已经失效了。后来在网上看到有人建议返回一个窗口的句柄,因为一个进程的句柄是唯一的,而指针在不同模块间是会变的,直到此前我不解为何句柄是唯一的,而指针是会变的,今天在看这本书时才大解心中疑惑)。

     进程的句柄结构:

    索引内核对象内存块的指针访问屏蔽(标志位的D W O R D )标志(标志位的D W O R D )10 x ? ? ? ? ? ? ? ?0 x ? ? ? ? ? ? ? ?0 x ? ? ? ? ? ? ? ?20 x ? ? ? ? ? ? ? ?0 x ? ? ? ? ? ? ? ?0 x ? ? ? ? ? ? ? ?............

     实际的句柄值就是索引的值,索引的值不一定是1,2这样的,但其大致大致原理是这样的,标志位通常用来表示句柄的信息。

    5.内核对象的创建与关闭

    常见内核对象有:存取符号对象、 事件对象、文件对象、文件映射对象、I / O 完成端口对象、作业对象、信箱对象、互斥对象、管道对象、进程对象、信标对象、线程对象和等待计 时器对象等,对于其创建,就是Create*(*号为内核对象名,如Thread,process,mutex等)。

    内核对象的创建一般都要返回一个HANDLE值,如果创建失败,此HANDLE值通常为NULL,但有少数函数返回值为1(INVALID_HANDLE_VALUE)。如:CreateFile函数未能打开指定文件时,将返回1。

    内核对象的关闭意味着此内核对象的引用计数减1,当一个内核对象的引用计数为0时,此内核对象就会从内存中撤销。内核对象的关闭函数为

     BOOL CloseHandle(HANDLE hobj);

    当为其传递一个无效句柄时,函数返回false。

    如果对一个内核对象仅仅是创建,而不关闭它,那么此时就会发生内存泄露。因为内核对象的引用计数少减了1,此内核对象将常驻内存,直至进程撤销为止。


    最新回复(0)