首页
社区
课程
招聘
[原创]Windows句柄表分配算法分析 (实验部分)
发表于: 2009-3-29 14:43 6819

[原创]Windows句柄表分配算法分析 (实验部分)

2009-3-29 14:43
6819
本文是《Windows句柄表分配算法分析》的随文实验
回顾:
TableLevle=HandleTable->TableCode&3;
CapturedTable=HandleTable->TableCode&~3;
句柄表的结构根据TableLevel来确定:
TableLevel为0时,CapturedTable是一级表
TableLevel为1时,CapturedTable是二级表,CapturedTable[i]是一级表
TableLevel为2时,CapturedTable是三级表,CapturedTable[i]是二级表,CapturedTable[i][j]是一级表

三级表的内容是二级表指针,二级表的内容是一级表指针,一级表中放的才是对象及访问属性(HANDLE_TABLE_ETNRY结构)
实验目的:以实验的方式观察PspCidTable的变化,从中了解Windows句柄表的分配过程.
实验器材:Windbg,RunIt(一个可控的不断创建线程的程序,见附件)
准备工作:获取PspCidTable的基本信息
lkd> dd PspCidTable l1
8055a360  e1001810 //获取PspCidTable的地址
lkd> dt _HANDLE_TABLE e1001810
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0xe1003000 //表基址为0xe1003000,一级表
   +0x004 QuotaProcess     : (null) 
   +0x008 UniqueProcessId  : (null) 
   +0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
   +0x01c HandleTableList  : _LIST_ENTRY [ 0xe100182c - 0xe100182c ]
   +0x024 HandleContentionEvent : _EX_PUSH_LOCK
   +0x028 DebugInfo        : (null) 
   +0x02c ExtraInfoPages   : 0
   +0x030 FirstFree        : 0x308
   +0x034 LastFree         : 0x34c
   +0x038 NextHandleNeedingPool : 0x800  //当前的句柄上限
   +0x03c HandleCount      : 329
   +0x040 Flags            : 1
   +0x040 StrictFIFO       : 0y1

此时可以观察到PspCidTable=e1001810,当前TableCode为0xe1003000,低两位表明是一级表,表地址为0xe1003000
lkd> dd 0xe1003000
e1003000  00000000 fffffffe 821bb661 00000000
e1003010  821bb3e9 00000000 821ba021 00000000
e1003020  821bad21 00000000 821baaa9 00000000
e1003030  821ba831 00000000 821ba5b9 00000000
e1003040  821ba341 00000000 821b9021 00000000
e1003050  821b9da9 00000000 821b9b31 00000000
e1003060  821b98b9 00000000 821b9641 00000000
e1003070  821b93c9 00000000 821b8021 00000000

这时可以看到一级表存放的进线程对象了
实验一:观察句柄表的升级
由于二级表升级为三级表需要极大的句柄容量,因此我们通常只能观察到句柄表由一级表升为二级表的过程
运行RunIt.exe,按回车不断创建线程,直至新线程的ThreadId大于当前句柄表的上限0x800.

此时再观察PspCidTable:
lkd> dt _HANDLE_TABLE e1001810
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0xe11a4001 //这时已经为二级表了
   +0x004 QuotaProcess     : (null) 
   +0x008 UniqueProcessId  : (null) 
   +0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
   +0x01c HandleTableList  : _LIST_ENTRY [ 0xe100182c - 0xe100182c ]
   +0x024 HandleContentionEvent : _EX_PUSH_LOCK
   +0x028 DebugInfo        : (null) 
   +0x02c ExtraInfoPages   : 0
   +0x030 FirstFree        : 0x860
   +0x034 LastFree         : 0x38c
   +0x038 NextHandleNeedingPool : 0x1000 //句柄上限达到了0x800*2=0x1000
   +0x03c HandleCount      : 529
   +0x040 Flags            : 1
   +0x040 StrictFIFO       : 0y1

这时的TableCode低两位表时现在是二级表,掩去低两位就是二级表的地址0xe11a4000了
lkd> dd 0xe11a4000 //观察二级表的内容
e11a4000  e1003000 e11b5000 00000000 00000000
e11a4010  00000000 00000000 00000000 00000000
e11a4020  00000000 00000000 00000000 00000000
e11a4030  00000000 00000000 00000000 00000000
e11a4040  00000000 00000000 00000000 00000000
e11a4050  00000000 00000000 00000000 00000000
e11a4060  00000000 00000000 00000000 00000000
e11a4070  00000000 00000000 00000000 00000000

可以看到,原来的一级表e1003000已经成为了二级表中的第一个元素.同时新分配了一个一级表为e11b5000.这样,句柄表的升级就完成了
实验二:观察新分配的句柄表是如何填充的
前面已经分析过,新分配的句柄表被填充成一个有序的FreeHandle序列.
观察新分配的这个二级表:
lkd> dd e11b5000
e11b5000  00000000 fffffffe 81f008b9 00000000
e11b5010  81f00641 00000000 81f003c9 00000000
e11b5020  81f5d021 00000000 81f5dda9 00000000
e11b5030  81f5db31 00000000 81f5d8b9 00000000
e11b5040  81f5d641 00000000 81f5d3c9 00000000
e11b5050  81eff021 00000000 81effda9 00000000
e11b5060  81effb31 00000000 81eff8b9 00000000
e11b5070  81eff641 00000000 81eff3c9 00000000 //RunIt创建的最后一个线程的ETHREAD在e11b5078处
lkd> dd
e11b5080  82012921 00000000 00000000 00000220 //这里的一部分句柄也被使用过了,因为可能别的进程也创建了线程
e11b5090  00000000 00000000 00000000 00000478
e11b50a0  00000000 0000038c 81f5cda9 00000000
e11b50b0  00000000 00000850 00000000 0000084c
e11b50c0  00000000 00000864 00000000 00000868
e11b50d0  00000000 0000086c 00000000 00000870
e11b50e0  00000000 00000874 00000000 00000878
e11b50f0  00000000 0000087c 00000000 00000880
lkd> 
e11b5100  00000000 00000884 00000000 00000888
e11b5110  00000000 0000088c 00000000 00000890
e11b5120  00000000 00000894 00000000 00000898
e11b5130  00000000 0000089c 00000000 000008a0
e11b5140  00000000 000008a4 00000000 000008a8
e11b5150  00000000 000008ac 00000000 000008b0
e11b5160  00000000 000008b4 00000000 000008b8
e11b5170  00000000 000008bc 00000000 000008c0

由图可知,最后一个ThreadId=0x83c,那么它在第二个表中的偏移是e11b5000+(0x83c-0x800)*2=e11b5078
从e11b5080到e11b50c0这部分的内容表明该范围内的部分句柄已经被使用过且又释放了(如果想避免该问题,你可以使用livekd的方式进行本实验,这样中断到调试器时就不会有其它动作来干扰我们的观察),但是尚未影响到e11b50c0之后的部分.
来观察这里:
e11b50c0  00000000 00000864 00000000 00000868
e11b50d0  00000000 0000086c 00000000 00000870
e11b50e0  00000000 00000874 00000000 00000878
e11b50f0  00000000 0000087c 00000000 00000880
e11b50c0作为二级表中的第二个一级表,它所对应的句柄为:
(e11b50c0-e11b5000)/2+0x800*(2-1)=0x860  //如果了解了句柄表的基本结构,这个计算很容易理解
而它的NextFreeHadleTableEntry则指向它紧挨着的下一个HANDLE_TABLE_ENTRY的所对应的句柄0x864
而且很容易看出0x864,0x868,0x86c,0x870...构成一个等差数列,这个结果可以与前面对ExpAllocateLowLevelTable函数的分析对比,两者是完全一致的.
实验到此结束.希望在句柄表知识的学习上给别人起到一些帮助作用,也希望我的学习过程对某些人有一定启示.

[课程]Android-CTF解题方法汇总!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 7115
活跃值: (639)
能力值: (RANK:1290 )
在线值:
发帖
回帖
粉丝
2
  文章真细致
2009-3-29 20:01
0
游客
登录 | 注册 方可回帖
返回
//