25.句柄表

在这里插入图片描述
32位参考:https://blog.youkuaiyun.com/Kwansy/article/details/109801722

一、内核对象,句柄

这次课讨论的内核对象是指创建时需要指定 LPSECURITY_ATTRIBUTES 参数的对象,例如 Mutex, Thread。

调用 CreateThread 等函数会返回一个 HANDLE 类型值,这种就叫句柄,它对应一个内核对象;

调用 CloseHandle 函数对某个内核对象计数减一,当内核对象计数为0,这个对象就被销毁了。

内核对象在内核存储,直接把地址给3环用很不安全,所以微软设计了句柄(HANDLE)给3环使用,句柄是一个整数,它的值除以4是句柄表的下标,通过下标能找到存储在句柄表里的句柄表项,每个占8字节。

二、句柄表,句柄表项

1.句柄表结构

句柄表存储在 EPROCESS.ObjectTable.TableCode 里:

kd> dt _ePROCESS fffffa801adab060
ntdll!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x160 ProcessLock      : _EX_PUSH_LOCK
   +0x168 CreateTime       : _LARGE_INTEGER 0x01d77e09`56302ac0
   +0x170 ExitTime         : _LARGE_INTEGER 0x0
   +0x178 RundownProtect   : _EX_RUNDOWN_REF
   +0x180 UniqueProcessId  : 0x00000000`00000be4 Void
   +0x188 ActiveProcessLinks : _LIST_ENTRY [ 0xfffff800`0402bb90 - 0xfffffa80`1ac42cb8 ]
   +0x198 ProcessQuotaUsage : [2] 0x3c10
   +0x1a8 ProcessQuotaPeak : [2] 0x3df0
   +0x1b8 CommitCharge     : 0x6a3
   +0x1c0 QuotaBlock       : 0xfffffa80`1a37f400 _EPROCESS_QUOTA_BLOCK
   +0x1c8 CpuQuotaBlock    : (null) 
   +0x1d0 PeakVirtualSize  : 0x8fc2000
   +0x1d8 VirtualSize      : 0x7bfe000
   +0x1e0 SessionProcessLinks : _LIST_ENTRY [ 0xfffff880`0526a010 - 0xfffffa80`1ac4a580 ]
   +0x1f0 DebugPort        : (null) 
   +0x1f8 ExceptionPortData : 0xfffffa80`1a2c5730 Void
   +0x1f8 ExceptionPortValue : 0xfffffa80`1a2c5730
   +0x1f8 ExceptionPortState : 0y000
   +0x200 ObjectTable      : 0xfffff8a0`010b3c50 _HANDLE_TABLE     !!在这里
   +0x208 Token            : _EX_FAST_REF
   +0x210 WorkingSetPage   : 0x73cbe
   +0x218 AddressCreationLock : _EX_PUSH_LOCK

((ntdll!_HANDLE_TABLE *)0xfffff8a0010b3c50)                 : 0xfffff8a0010b3c50 [Type: _HANDLE_TABLE *]
    [+0x000] TableCode        : 0xfffff8a0015b5000 []2位代表几级句柄表
    [+0x008] QuotaProcess     : 0xfffffa801adab060 [Type: _EPROCESS *]   当前进程结构体
    [+0x010] UniqueProcessId  : 0xbe4 [Type: void *]   进程ID
    [+0x018] HandleLock       [Type: _EX_PUSH_LOCK]   
    [+0x020] HandleTableList  [Type: _LIST_ENTRY]
    [+0x030] HandleContentionEvent [Type: _EX_PUSH_LOCK]
    [+0x038] DebugInfo        : 0x0 [Type: _HANDLE_TRACE_DEBUG_INFO *]
    [+0x040] ExtraInfoPages   : 0 [Type: long]
    [+0x044] Flags            : 0x0 [Type: unsigned long]
    [+0x044 ( 0: 0)] StrictFIFO       : 0x0 [Type: unsigned char]
    [+0x048] FirstFreeHandle  : 0x248 [Type: unsigned long]
    [+0x050] LastFreeHandleEntry : 0xfffff8a0015b5ff0 [Type: _HANDLE_TABLE_ENTRY *]
    [+0x058] HandleCount      : 0x90 [Type: unsigned long]  句柄数量
    [+0x05c] NextHandleNeedingPool : 0x400 [Type: unsigned long]    //分配下一层句柄表之前可以容纳的最大句柄的值
    [+0x060] HandleCountHighWatermark : 0x94 [Type: unsigned long]

特别留意 TableCode 的第2位,它表明了句柄表的结构,如果第2位是01,表示现在句柄表有两级, TableCode 指向的表存储了 4KB / 4 = 1024 个句柄表的地址,每个地址指向一个句柄表。
特别留意 TableCode 的第2位,它表明了句柄表的结构,如果低两位是0,则一级表大小4096/16= 256,如果低两位是01,表示现在句柄表有两级, TableCode 指向的表存储了 4096/8256个句柄表的地址,每个地址指向一个句柄表。如果低两位是02,则存储 4096/84096/8*256

举个例子
先用一层表举例子()

1: kd> dq 0xfffff8a0015b5000 l14
fffff8a0`015b5000  00000000`00000000 fffff8a0`fffffffe
fffff8a0`015b5010  fffff8a0`0155b8b1 00000000`00000009
fffff8a0`015b5020  fffff8a0`02e979b1 00000000`00000003
fffff8a0`015b5030  fffffa80`1a3684a1 00000000`00100020
fffff8a0`015b5040  fffffa80`1ad22531 00000000`00100020
fffff8a0`015b5050  fffffa80`1a6efc81 00000000`00100020
fffff8a0`015b5060  fffffa80`18e96e31 00000000`001f0001
fffff8a0`015b5070  fffff8a0`00c05f71 00000000`00020019
fffff8a0`015b5080  fffff8a0`00eea1d1 00000000`00000001
fffff8a0`015b5090  fffffa80`1ada24e1 00000000`021f0003

![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/d230820f8dba0b5ad3e7f0f97fca37b6.png#pic_center在这里插入图片描述

由图可知,句柄表内结构是这样

struct handle
{
	LONG64 Objress //对象低三位为属性,需要清空,另外需要补上_OBJECT_HEADER的大小
	LONG64 属性
}

但是肉眼看的可以看见对象地址和ARK地址是不一致的,主要原因是属性位和_OBJECT_HEADER的原因
句柄表内:1.对象低三位为属性,需要清空
2.所有对象前面都有一个_OBJECT_HEADER结构,而句柄结构在这个结构的后面,64位下这个结构大小为0X30

nt!_OBJECT_HEADER
   +0x000 PointerCount     : Int8B
   +0x008 HandleCount      : Int8B
   +0x008 NextToFree       : Ptr64 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : UChar
   +0x019 TraceFlags       : UChar
   +0x019 DbgRefTrace      : Pos 0, 1 Bit
   +0x019 DbgTracePermanent : Pos 1, 1 Bit
   +0x01a InfoMask         : UChar
   +0x01b Flags            : UChar         // 0x71; //进程退出
   +0x01b NewObject        : Pos 0, 1 Bit
   +0x01b KernelObject     : Pos 1, 1 Bit
   +0x01b KernelOnlyAccess : Pos 2, 1 Bit
   +0x01b ExclusiveObject  : Pos 3, 1 Bit
   +0x01b PermanentObject  : Pos 4, 1 Bit
   +0x01b DefaultSecurityQuota : Pos 5, 1 Bit
   +0x01b SingleHandleEntry : Pos 6, 1 Bit
   +0x01b DeletedInline    : Pos 7, 1 Bit
   +0x01c Reserved         : Uint4B
   +0x020 ObjectCreateInfo : Ptr64 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : Ptr64 Void
   +0x028 SecurityDescriptor : Ptr64 Void
   +0x030 Body             : _QUAD            //句柄的对象在这个位置

FFFFFA801A449603 & FFFFFFFFFFFFFFF8 + 0X30 = 0XFFFF FA80 1A44 9630
现在WINDBG的对象就和ARK一致了,windbg访问对象结构也没问题了
dt _eprocess 0XFFFF FA801A44963

二、查看一个二级句柄表
现在进程大多数是一级和二级句柄表,拿个二级表举个例子

在这里插入图片描述
在这里插入图片描述
让我们来找找这个句柄吧 0x468

句柄是需要/4的,0x468/4取值,如果小于0x100就在第一张表,0x100<值<0x200就在第二张表,依次类推
0x468/4=11A,
11A-0X100=1A,
可知该句柄在第二张表的1A位置
公式:第二张表地址1A0x10=句柄对象结构

//和ARK工具一致,差0x30还是_OBJECT_HEADER结构问题,前面已经解释了
3: kd> dq fffff8a0`01e0e000+1a*10
fffff8a0`01e0e1a0  fffffa80`1a5ea411 00000000`00100020 
fffff8a0`01e0e1b0  fffffa80`1a490161 00000000`00000804
fffff8a0`01e0e1c0  fffffa80`194df771 00000000`00000804
fffff8a0`01e0e1d0  fffffa80`194df6b1 00000000`00000804
fffff8a0`01e0e1e0  fffffa80`194df5f1 00000000`00000804
fffff8a0`01e0e1f0  fffffa80`194df531 00000000`00000804
fffff8a0`01e0e200  fffffa80`194df471 00000000`00000804
fffff8a0`01e0e210  fffffa80`1a97f431 00000000`00100003

我们看到fffffa80`1a5ea411 最后一个字节为1,其实最后三位是属性位,使用时需要清0
那么我们看看这三位代表什么吧
在这里插入图片描述

至此,已经知道句柄表的寻找方式了,那么取到的对象可以来查看这些信息
首先是查看句柄对象的信息,用到这个结构体

3: kd> dt _object_header fffffa80`1a5ea410 //第三位要清0,上面讲了
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n1
   +0x008 HandleCount      : 0n1
   +0x008 NextToFree       : 0x00000000`00000001 Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0x1c ''          //和ARK一致为28    因为加密了所以不做参考,下节课有解密讲解
   +0x019 TraceFlags       : 0 ''
   +0x01a InfoMask         : 0xc ''
   +0x01b Flags            : 0x40 '@'
   +0x020 ObjectCreateInfo : 0xfffffa80`1a374040 _OBJECT_CREATE_INFORMATION
   +0x020 QuotaBlockCharged : 0xfffffa80`1a374040 Void
   +0x028 SecurityDescriptor : (null) 
   +0x030 Body             : _QUAD


下面看看句柄的权限结构信息,和遍历句柄号一样

3: kd> dt _handle_table_entry fffff8a0`01e0e000+1a*10
ntdll!_HANDLE_TABLE_ENTRY
   +0x000 Object           : 0xfffffa80`1a5ea411 Void
   +0x000 ObAttributes     : 0x1a5ea411
   +0x000 InfoTable        : 0xfffffa80`1a5ea411 _HANDLE_TABLE_ENTRY_INFO
   +0x000 Value            : 0xfffffa80`1a5ea411
   +0x008 GrantedAccess    : 0x100020
   +0x008 GrantedAccessIndex : 0x20
   +0x00a CreatorBackTraceIndex : 0x10
   +0x008 NextFreeTableEntry : 0x100020

dt _eprocess fffffa80`1a5ea410+30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值