windows定义了很多内核对象:进程对象、线程对象、互斥量对象、信号量对象、事件对象、文件对象等等。在调用相应的函数创建这些对象后,我们都可以通过HANDLE类型的句柄来引用它们。或许你在一些书上看到过说句柄相当于指针,它指向具体的对象。在某种程度上来说这是不错的,但是进一步深入探究时就会发现这样的说法很不准确。说到句柄就不能不提句柄表,句柄必须通过句柄表才能找到所引用的内核对象,但是很多书中对句柄表却是一带而过,不加深究。这是因为Microsoft并未就句柄表发布过任何官方的文档,通过逆向工程获得结论又很难让人信服。

相信没有什么能比windows公布的源代码更有说服力了,接下来我会通过windows公布的WRK(windows research kernel)源代码,来为大家深入解析一下windows句柄表。虽然是基于WRK的,不能保证其他版本的windows系统也采用相同的机制,但是我想它们之间或许都是大同小异的。

windows使用句柄对进程中的各种对象进行引用。实际上windows句柄就是一个索引,它存储了关联对象在句柄表的索引值,每个索引对应句柄表中的一个表项。通过句柄存储的索引,就可以很容易获得该句柄项对应的对象的指针。

句柄表中存储了很多了句柄表项,类似下面的结构:

上图仅仅为了演示用,并不代表实际意义。

句柄表是针对于进程而言的,在一个进程使用的句柄,直接在另一个进程中使用是毫无意义的。换句话说,句柄仅在一个进程内有效。当一个进程的句柄传递给另一个句柄后,句柄就不再有效。举例来说:在进程A中索引值为8的句柄,用于引用a对象。在进程B的句柄表中,虽然索引为8的句柄项可能不为空,但是有可能是引用的b对象。此对象非彼对象。

在windows Server 2003(与WRK有相同的内核)中,句柄表是一个多层次的结构。它的类型为:HANDLE_TABLE。定义如下:

typedef struct _HANDLE_TABLE {  ULONG_PTR TableCode;//指针指向句柄表的存储结构。  struct _EPROCESS *QuotaProcess;  // 所属进程的指针  HANDLE UniqueProcessId;     // 这个进程的 ProcessID  EX_PUSH_LOCK  HandleTableLock[HANDLE_TABLE_LOCKS];//句柄表所,仅在句柄表扩展时使用。  LIST_ENTRY HandleTableList;   // 所有的 HandleTAble 在内核中形成一个 List ,这是 Entry  EX_PUSH_LOCK hangleConventionEvent//若在访问句柄表时发生了竞争则在此锁上等待。  PHANDLE_TRACE_DEBUG_INFO DebugInfo;  LONG extrainfoPag;  ULONG FirstFree; // 空闲链表表头句柄索引。  ULONG LastFree; // 最近被释放的句柄索引。  ULONG NextHandleNeedingPool;//下一次句柄表扩展的起始句柄索引。  LONG HandleCount;//正在使用的句柄表项数量。  union{  ULONG Flags;//标志域  BOOLEAN StrictFIFO:1;//是否使用FIFO风格的重用。  };  } HANDLE_TABLE, *PHANDLE_TABLE;

我们看到该结构包含很多的成员,但此处我们仅讨论对我们有帮助的几个。

我们看到HANDLE_TABLE的TableCode成员是一个指针,实际上它的高30位指向存储句柄表的存储结构,该存储结构初始时为4KB大小的一个页面。低2位代表当前句柄表的层数。最多为三层,但是初始时只有一层,以后随着句柄数量的不断增加会不断扩展。

每个句柄表项大小为8Byte,其结构为HANGLE_TABLE_ENTRY。

,由于windows在为句柄表分配内存时是按页面大小4KB来申请内存的。因此每次为句柄表申请一个新的页面时,句柄表就增加了512项。

前面我们曾提过,windows句柄表是层次结构的。下图就是当句柄表为三层时的结构图:

如果低2位为0,说明句柄表只有一层。TableCode指向的页面直接存储的句柄,由于每个表项占8Byte,因此4KB页面最多可以存储512个表项。

下图为当句柄表为一层时的结构图:

如果低2的值为1,此时句柄表有两层,TableCode指向最高层页面。而最高层页面用于存储指向下一层页面的指针。由于32位系统下指针占4Byte,因此最高层页面可以存储1024个指针。每个指针同样指向4KB的存储表项的页面。可以存储512个句柄表项。此时整个windows句柄表可以存储1024*512个表项。如下图所示:

如果低2位值为2,此时句柄表有三层,如下图所示:

最高层和次高层都是存储的指针,最低层页面存储句柄项,因此此时可以整个句柄表可以存储1024*1024*512个句柄表项。

但是window限定了每个进程句柄表存储的句柄表项不得超过:2^24=16777216。

实际上,在每个最低层页面的第一个表项都有特殊用途,所以每个最低层页面真正供进程使用的表项为511个。

在进程创建时,系统会给新进程分配一个单层的句柄表。随着进程中句柄数量的不断增加,句柄表会由单层扩展为二层,最后被扩展为三层。

在HANDLE_TABLE结构中,FirstFree域记录了当前句柄表中的空闲句柄单链表。说其是单链表,但是每个元素之间不是通过指针而是通过句柄索引值来连接的。句柄值按HANDLE_VALUE_INC宏定义逐个递增,windows定义该宏的值为4,为什么是4?我们可以通过windbg的!handle命令我们可以查看一下windows自带的计算器程序的句柄表的情况:

可以看到第一个表项对应的句柄值为4,而且后面的句柄值都是4的倍数。这是为什么呢?这因为microsoft将句柄的低两位用来存储该索引对应的句柄表的层次号。在前面曾介绍过,TableCode成员的低两位用以控制句柄表的层次。而此处句柄表的低两位是用于指明该索引所处的层次,有助于快速的定位索引。因此所有的句柄必须右移两位,也就是除以4才能得到它的实际在句柄表中的索引。这也就是句柄值都是4的倍数的原因。

FirstFree成员存储链表头句柄的索引值。在索引项HANDLE_TABLE_ENTRY结构(马上会介绍)中,我们看到有一个名为NextFreeTableEntry的成员。该成员存储下一个空闲句柄索引值。 当进程需要创建新的句柄,该句柄会被加入到句柄。这时就可以从FirstFree取得第一个空闲句柄索引,假设该索引指向x表项,并将该x表项的NextFreeTableEntry成员赋值给FirstFree。此时,原来链表头的NextFreeTableEntry就变成了现在的FirstFree,成为链表头。

伪代码如下:

1:从FirstFree取出索引,该索引指向的句柄表项x。

2:FirstFree=x.NextFreeTableEntry;

在释放x句柄项时,将x句柄索引赋值给FirstFree,并将赋值前的FirstFree的值赋值给x.NextFreeTableEntry。

伪代码如下:

1:Index temp=FirstFree;

2:将x表项的索引赋值给FirstFree

3:x.NextFreeTableEntry=temp;

NextHandleNeedingPool成员记录了下一次对句柄表进行扩展时,扩展页面的第一个索引。也就是说当句柄表所有已分配的页面都满了之后,下一个页面的其实索引值。因此,windows句柄表只是在确实不够用的时候才进行简单的线性增长。并不会一次分配多个页面或扩展多层。

前面我们曾多次提到句柄表项,其实它是HANDLE_TABLE_ENTRY结构,定义如下:

    typedef struct _HANDLE_TABLE_ENTRY   {  union {  PVOID Object;//内核对象指针。  ULONG ObAttributes;//内核对象属性。  PHANDLE_TABLE_ENTRY_INFO InfoTable;//  ULONG_PTR Value;  };  union {  union {  ACCESS_MASK GrantedAccess;  struct{  USHORT GrantedAccessIndex;  USHORT CreatorBackTraceIndex;  };  };  LONG NextFreeTableEntry;  };  } HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;  

该结构由两个大的union组成,占8字节。句柄表项存储了该表项对应的对象的地址,以及其他的一些属性信息。

在第一个union中有一个Object指针,它指向了句柄所代表的内核对象。第二个union中,如果句柄表项指向了一个有效的对象,那么GrantedAccess成员记录了该句柄的访问掩码。当句柄为空闲时,NextFreeTableEntry成员存储下一空闲节点的索引值,用以连接句柄表的空闲链表。

window提供的API:GetCurrentThread和GetCurrentProcess,可以返回当前线程和进程的句柄。其实在句柄表中是没有存储当前进程的句柄和当前线程句柄。GetCurrentThread返回句柄的值是-2,当我们以此句柄作为参数传递给windows其他API函数时,在函数内部如果检测到该句柄值为-2,不会查找句柄表,立即返回到线程对象地址。类似的调用GetCurrentProcess时,其实返回的是-1,当使用此进程句柄时,同样不需要查找句柄表,会立即返回指向当前进程对象的指针。

本文使用比较通俗的语言,对windows句柄表的结构做了简单的介绍。目的是让对句柄表存在疑问的童鞋对句柄表有个清晰的认识。有说的不对的地方,欢迎指正!!

浅谈windows句柄表相关推荐

  1. Windows句柄表学习笔记 —— 句柄表全局句柄表

    Windows句柄表学习笔记 -- 句柄表&全局句柄表 句柄表 实验一:在WinDbg中查看句柄表 第一步:打开一个Win32窗口程序 第二步:编译并运行以下代码 第三步:查看运行结果 第四步 ...

  2. 浅谈eform自定义表单工具和协同办公系统

    浅谈eform自定义表单工具和协同办公系统 提起"协同办公",随便在百度或者Google搜索一下,就能让你看到眼花缭乱的信息,国内的各大协同办公软件厂商都在鼓吹着自己对协同的理解和 ...

  3. 浅谈Windows XP系统漏洞的封堵

    浅谈Windows XP系统漏洞的封堵 2010年11月18日 9号    浏览:96次 发表评论 阅读评论 微软WindowsXP自出世以来就在中国市场中获得了广泛好评和客户的认同,它出色的兼容性和 ...

  4. 浅谈 MySQL 连表查询

    浅谈 MySQL 连表查询 连表查询是一把双刃剑, 优点是适应范式, 减少数据冗余; 缺点是连表查询特别是多张表的连表会增加数据库的负担, 降低查询效率. 简介 连表查询就是 2 张表或者多张表的联合 ...

  5. 计算机病毒的隐藏方式有ign,浅谈windows下的病毒隐藏技术.doc

    浅谈windows下的病毒隐藏技术 浙江工业职业技术学院 毕业论文 (2011届) 浅谈windows下的病毒隐藏技术 学生姓名 学 号 分 院 专 业 信 指导教师 完成日期 2011年5月 19日 ...

  6. 用户数据表设计借鉴 浅谈数据库用户表结构设计,第三方登录 基于 Token 的身份验证

    最近对用户数据表的设计比较感兴趣,看到了两篇比较好的文章. 浅谈数据库用户表结构设计,第三方登录 转载于: https://www.cnblogs.com/jiqing9006/p/5937733.h ...

  7. 浅谈 Windows API 编程

    原文地址:http://blog.sina.com.cn/s/blog_46d85b2a01010qpt.html http://blog.sina.com.cn/s/articlelist_1188 ...

  8. 大白菜浅谈Windows 7 32位与64位之区别

    如今安装Windows 7已经不是什么新鲜事儿了,如果你还没有装Windows 7,那未免也太Out了.说起Windows 7的好处,那真是一堆一堆的,所以别犹豫,赶紧装一个吧. 哎,等等,装之前咱得 ...

  9. 浅谈windows 编程中SendMessage函数的妙用!!!

    windows编程中SendMessage函数是非常重要的,而且这个对于理解windows的消息机制也很重要.本文用代码的方式实现了一些功能,借以说明此函数之妙用.说明不当之处,希望批评指正,谢谢! ...

最新文章

  1. Cortana 的谢幕,不一定是产品问题
  2. SpringBoot 2.x 整合Mybatis三:tk.mybatis
  3. Top-down与Bottom-up
  4. 乱谈卡巴CCTV黄金时段广告
  5. 势逼 React Native,跨平台开发框架 Flutter 很凶猛 | 码书
  6. memcached SASL验证状态安全绕过漏洞
  7. 用c语言编写一个打勾的图形,C语言图形编程.ppt
  8. 《全球变化与地球系统科学》章节测试答案
  9. Java 上传--upload
  10. 【Cornerstone Mac系统下的安装】
  11. 我的Java研发实习面试经历
  12. 如何有效管理自己电脑里的文件
  13. JQuery滚动条及位置相关方法
  14. vue 的computed和watch在什么时候触发
  15. 世界女性科技群落(五):数字化黄金时代,东南亚女性都是隐藏的阿尔法
  16. oracle 水晶报表开发,水晶报表连接Oracle做数据报表笔记
  17. 自制板载ST-LINKV2-1下载器
  18. linux下使用微信web开发者工具
  19. mysql获取上月月份_mysql 查询当前月份 上个月份 上上个月份
  20. 晋中计算机专业对口大学,山西晋中计算机专业学校排名太重基础差也能上好学校...

热门文章

  1. 2017云计算及工业物联网论坛即将于广州开幕
  2. 年末盘点 2016 年最严重的 7 起 DDoS 攻击事件
  3. ES6标准学习: 4、数组的扩展
  4. [转]CSS3 transform顺序问题
  5. 《Java Web高级编程——涵盖WebSockets、Spring Framework、JPA H
  6. android之权限大全
  7. asp.net c#截取指定字符串函数
  8. 放弃OpenStack?恐怕还不到时候
  9. JavaScript七种非常经典的创建对象方式
  10. 网络安全行业的未来在哪里?