Windows Via C/C++ Part Ⅰ Chapter3: 内核对象(2)

进程的内核对象句柄表

 

当进程初始化时,系统会给其分配一个句柄表用来存储与其相关的内核对象的信息。微软隐藏了句柄表的构造细节和管理模式,也没有提供相应的文档。通常我不会讨论没有文档支持的话题,但我会破例讨论句柄表,因为理解它对于Windows开发人员来说非常重要。句柄表的细节不为人知并且通常随着Windows版本而不断更新,因而以下的论述在细节上可能不完全准确。本节的话题用来帮助开发人员理解一些基础知识,而不是揭示句柄表的真正工作方式——除了微软没人知道。

3-1模拟了句柄表的结构,它只是某个数据结构的数组,每个结构中包括一个指向内核对象的指针、一个访问掩码和某些标志。

Index

Pointer to Kernel Object Memory Block

Acess Mask (DWORD of Flag Bits)

Flags

1

0x????????

0x????????

0x????????

2

0x????????

0x????????

0x????????

1 创建内核对象

当进程首次加载时它的句柄表是空的。当进程中的某一线程创建内核对象时,内核会负责为该对象分配内存空间并初始化它,然后内核会扫描线程所在进程的句柄表并试图找到一个空的入口。比如在表3-1中,内核在发现索引1处的结构为空之后会初始化它:指针域将指向刚刚创建的内核对象的内存地址,访问掩码和标志被置位。以下是一些用来创建内核对象的函数(当然不是全部):

所有用来创建内核对象的函数都会返回一个进程间独立的句柄值,进程内的所有线程都可以使用它。将句柄值除以4就可以得到该内核对象在进程句柄表中的索引值,比如某个对象的句柄值是0x00000fb8,那么它在相应进程句柄表中的索引就是1006。因此在debug模式下观察句柄的值时,你会发现所有句柄都能被4整除。不过要记住,句柄的真正含义是隐藏的并且可能随着Windows版本的变化而变化。

当你需要调用操作内核对象的方法时,你可以将Create*方法传回的句柄作为参数传入。被调用的函数会按句柄值计算出当前进程句柄表中的索引,假如该索引处的入口为空或是对象类型不匹配,函数调用就会失败并将错误码设置为6ERROR_INVALID_HANDLE)。由于句柄值是进程间独立的,因此你不能简单的将进程A句柄表中的某个对象的句柄传递给句柄B,以期望进程B会正确的使用该句柄,这样做可能导致该句柄值计算出的索引在进程B的句柄表中指向一个空入口或者完全不同类型的内核对象。

如果创建内核对象的函数失败,返回的句柄时通常是0NULL),这可能是由于计算机系统内存不足或者遇到了某些安全原因。不幸的是,并非所有Create*函数在失败时都会返回0,有些会返回-1INVALID_HANDLE_VALUE),比如CreateFile。因此在使用这些函数时你要异常小心,比如以下的代码是不对的:

 

2 关闭内核对象

所有的内核对象都可以用CloseHandle函数关闭:

CloseHandle会首先检查传递给它的句柄值,计算出该句柄在当前进程句柄表中对应的索引值,然后按该值检查相应入口处的对象,假如入口中含有进程有权限访问的对象,那么内核将从入口的指针域中获得对象的内存地址并将其引用计数减1,若此时该对象的引用计数为0内核将销毁它。假如传递给CloseHandle的句柄值无效,CloseHanlde返回FALSE并将错误码设置为ERROR_INVALID_HANDLE,在debug模下式程序会弹出异常对话框提示发生0xC0000008异常。

CloseHandle成功返回之前,它会将进程句柄表中相应的入口清空,这时传递给CloseHandle的句柄成为无效句柄,你也不应该再试图使用它。在CloseHandle调用之后,无论相应的内核对象是否被销毁,这种清除工作总会发生。要记住CloseHandle之后你无权再访问相应的内核对象,但是如果对象的引用计数不为0,它仍然是存在的,这只说明有别的进程正在使用它。

假如开发者在对象使用完毕后忘记调用CloseHandle会不会造成内存泄露呢?呃,会也不会。在进程依然运行时,这可能会造成内存泄露,但当进程终止时,操作系统将保证回收进程使用的一切资源,对于内核对象,系统会在进程中止时扫描其句柄表,如果发现有未释放的对象入口,系统会帮你关闭该对象,如果该对象的引用计数变为0,系统将销毁它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值