Windows 内核对象管理器学习笔记
Windows 10 Kernel Version 10240 MP (1 procs) Free x64
Edition build lab: 10240.16384.amd64fre.th1.150709-1700
对象
对象的总体结构包括:附加信息头,对象头和对象体。附加信息头是可选的,InfoMask字段表示存在哪些附加信息头。
OBJECT_HEADER_*
可选头名称 | 结构 | 作用 |
---|---|---|
创建信息头 | OBJECT_HEADER_CREATOR_INFO | 包含创建者信息,用来将创建的对象挂入其创建者的对象队列 |
命名信息头 | OBJECT_HEADER_NAME_INFO | 载有对象名和目录节点的指针 |
句柄信息头 | OBJECT_HEADER_HANDLE_INFO | 关于句柄的信息 |
配额信息头 | OBJECT_HEADER_QUOTA_INFO | 关于耗用内存配额的信息 |
#define OB_INFOMASK_CREATOR_INFO 0x01
#define OB_INFOMASK_NAME 0x02
#define OB_INFOMASK_HANDLE 0x04
#define OB_INFOMASK_QUOTA 0x08
#define OB_INFOMASK_PROCESS_INFO 0x10
_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 对象标志
+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 Spare : Uint4B
+0x020 ObjectCreateInfo : Ptr64 _OBJECT_CREATE_INFORMATION 来源于创建对象时的 OBJECT_ATTRIBUTES
+0x020 QuotaBlockCharged : Ptr64 Void
+0x020 QuotaBlockCharged : Ptr64 Void
+0x028 SecurityDescriptor : Ptr64 Void 安全描述符
+0x030 Body : _QUAD 通用对象头后面紧跟着真正的结构体(这个字段是后面真正结构体中的第一个成员)
_OBJECT_CREATE_INFORMATION
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
nt!_OBJECT_CREATE_INFORMATION
+0x000 Attributes : Uint4B
+0x008 RootDirectory : Ptr64 Void
+0x010 ProbeMode : Char
+0x014 PagedPoolCharge : Uint4B
+0x018 NonPagedPoolCharge : Uint4B
+0x01c SecurityDescriptorCharge : Uint4B
+0x020 SecurityDescriptor : Ptr64 Void
+0x028 SecurityQos : Ptr64 _SECURITY_QUALITY_OF_SERVICE
+0x030 SecurityQualityOfService : _SECURITY_QUALITY_OF_SERVICE
对象目录
对象目录是由多个"节点"连接而成的树状结构,树的根是一个“目录”对象,即类型为OBJECT_DIRECTORY的对象。树中的每个节点都是对象,所以"节点名"就是"对象名"。除根节点之外,树中的所有中间节点都必须是目录对象或“符号连接”对象(即类型为OBJECT_SYMBOLIC_LINK的对象),而普通的对象则只能成为"叶节点"。对于对象目录中的任何节点,如果从根节点或某个中间节点开始逐节向此节点前进,记下沿途各个节点的节点名,并以分隔符"“加以分隔,就形成一个"路径名”。如果路径名中的第一个节点是根节点,就是全路径名或称绝对路径。根节点的节点名是"",内核中全局指针ObpRootDirectoryObject指向的就是对象目录的根节点。
_OBJECT_DIRECTORY
nt!_OBJECT_DIRECTORY
+0x000 HashBuckets : [37] Ptr64 _OBJECT_DIRECTORY_ENTRY 数组中的每个指针都可以用来维持一个"(对象)目录项
+0x128 Lock : _EX_PUSH_LOCK
+0x130 DeviceMap : Ptr64 _DEVICE_MAP
+0x138 ShadowDirectory : Ptr64 _OBJECT_DIRECTORY
+0x140 SessionId : Uint4B
+0x148 NamespaceEntry : Ptr64 Void
+0x150 Flags : Uint4B
_OBJECT_DIRECTORY_ENTRY
nt!_OBJECT_DIRECTORY_ENTRY
+0x000 ChainLink : Ptr64 _OBJECT_DIRECTORY_ENTRY 指针ChanLink用来构成队列
+0x008 Object : Ptr64 Void 指针Object则指向其所连接的对象
+0x010 HashValue : Uint4B 具体挂在哪一个队列中则取决于节点名(对象名)的Hash值
对象类型
_OBJECT_TYPE
一类内核对象的通用属性
_OBJECT_TYPE
+0x000 TypeList : _LIST_ENTRY 类型链表,确切地说是类型对象的链表,所有类型相同的对象通过该双向链表连接
+0x010 Name : _UNICODE_STRING 类型名称
+0x020 DefaultObject : Ptr64 Void 默认对象
+0x028 Index : UChar 类型索引
+0x02c TotalNumberOfObjects : Uint4B
+0x030 TotalNumberOfHandles : Uint4B
+0x034 HighWaterNumberOfObjects : Uint4B
+0x038 HighWaterNumberOfHandles : Uint4B
+0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER 对象类型初始化信息
+0x0b8 TypeLock : _EX_PUSH_LOCK 对象类型锁
+0x0c0 Key : Uint4B 事实上用作内存分配的tag,同类对象占用的内存块都标记为同一个tag
+0x0c8 CallbackList : _LIST_ENTRY 回调函数链表
_OBJECT_TYPE_INITIALIZER
_OBJECT_TYPE_INITIALIZER
+0x000 Length : Uint2B 结构长度
+0x002 ObjectTypeFlags : UChar 类型标志
+0x002 CaseInsensitive : Pos 0, 1 Bit 对象名是否大小写不敏感
+0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
+0x002 UseDefaultObject : Pos 2, 1 Bit
+0x002 SecurityRequired : Pos 3, 1 Bit
+0x002 MaintainHandleCount : Pos 4, 1 Bit
+0x002 MaintainTypeList : Pos 5, 1 Bit
+0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
+0x002 CacheAligned : Pos 7, 1 Bit
+0x004 ObjectTypeCode : Uint4B
+0x008 InvalidAttributes : Uint4B
+0x00c GenericMapping : _GENERIC_MAPPING 通用映射
+0x01c ValidAccessMask : Uint4B 有效访问掩码
+0x020 RetainAccess : Uint4B
+0x024 PoolType : _POOL_TYPE 池类型(PagePool, NonPagePool)
+0x028 DefaultPagedPoolCharge : Uint4B 默认分页池消耗
+0x02c DefaultNonPagedPoolCharge : Uint4B 默认分页非池消耗
// object hook 就是改变这几个成员指向的函数地址
+0x030 DumpProcedure : Ptr64 void 转储例程
+0x038 OpenProcedure : Ptr64 long 打开例程
+0x040 CloseProcedure : Ptr64 void 关闭例程
+0x048 DeleteProcedure : Ptr64 void 删除例程
+0x050 ParseProcedure : Ptr64 long 解析例程
+0x058 SecurityProcedure : Ptr64 long 安全例程
+0x060 QueryNameProcedure : Ptr64 long 查找名称例程
+0x068 OkayToCloseProcedure : Ptr64 unsigned char 关闭例程拓展
+0x070 WaitObjectFlagMask : Uint4B
+0x074 WaitObjectFlagOffset : Uint2B
+0x076 WaitObjectPointerOffset : Uint2B
句柄表
句柄表是windows对象管理器用来管理句柄的结构,每个进程都包含一个执行体进程结构块(_EPROCESS),而该结构中的的ObjectTable字段就是句柄表的指针。
_HANDLE_TABLE
ACPI!_HANDLE_TABLE
+0x000 NextHandleNeedingPool : Uint4B
+0x004 ExtraInfoPages : Int4B
+0x008 TableCode : Uint8B 一个指向顶层句柄表树节点的指针(低2位为句柄表层数)
+0x010 QuotaProcess : Ptr64 _EPROCESS
+0x018 HandleTableList : _LIST_ENTRY
+0x028 UniqueProcessId : Uint4B 这个进程的 ProcessID
+0x02c Flags : Uint4B
+0x02c StrictFIFO : Pos 0, 1 Bit
+0x02c EnableHandleExceptions : Pos 1, 1 Bit
+0x02c Rundown : Pos 2, 1 Bit
+0x02c Duplicated : Pos 3, 1 Bit
+0x02c RaiseUMExceptionOnInvalidHandleClose : Pos 4, 1 Bit
+0x030 HandleContentionEvent : _EX_PUSH_LOCK
+0x038 HandleTableLock : _EX_PUSH_LOCK
+0x040 FreeLists : [1] _HANDLE_TABLE_FREE_LIST
+0x040 ActualEntry : [32] UChar
+0x060 DebugInfo : Ptr64 _HANDLE_TRACE_DEBUG_INFO
_HANDLE_TABLE_ENTRY
ACPI!_HANDLE_TABLE_ENTRY
+0x000 VolatileLowValue : Int8B
+0x000 LowValue : Int8B
+0x000 InfoTable : Ptr64 _HANDLE_TABLE_ENTRY_INFO
+0x008 HighValue : Int8B
+0x008 NextFreeHandleEntry : Ptr64 _HANDLE_TABLE_ENTRY
+0x008 LeafHandleValue : _EXHANDLE
+0x000 RefCountField : Int8B
+0x000 Unlocked : Pos 0, 1 Bit
+0x000 RefCnt : Pos 1, 16 Bits
+0x000 Attributes : Pos 17, 3 Bits 句柄的属性
+0x000 ObjectPointerBits : Pos 20, 44 Bits 内核对象指针
+0x008 GrantedAccessBits : Pos 0, 25 Bits 句柄的访问掩码
+0x008 NoRightsUpgrade : Pos 25, 1 Bit
+0x008 Spare1 : Pos 26, 6 Bits
+0x00c Spare2 : Uint4B
windbg脚本
打印系统内所有对象类型的对象名和地址
r @$t0=(ObTypeIndexTable+0x10);
.for(r @$t8=2;poi(@$t0)!=0;r @$t0=@$t0+0x8;r @$t8=@$t8+1)
{
r @$t1=poi(@$t0);
.printf "name:%msu address:%p index:%d\n",@$t1+0x10,@$t1,@$t8;
}
.printf "Enum Type Name end"
打印根目录对象或指定对象目录
// ObpRootDirectoryObject 根目录对象指针
r @$t0=poi(ObpRootDirectoryObject);
// 可选参数,目录对象地址
.if(${/d:$arg1})
{
r @$t0 = ${/f:$arg1};
}
.for(r @$t6=0; @$t6<0n37; r @$t6=@$t6+1;)
{
r @$t2=poi(@$t0+(@$t6*0x08));
.if(@$t2!=0)
{
r @$t2 = poi(@$t2+0x8);
.printf "address:%p ,Num:%d\n",@$t2,@$t6;
!object @$t2 0x1;
}
}
打印句柄所指对象
//两个参数分别为进程EPROCESS地址和HANDLE值
.if( ${/d:$arg1} ){
r @$t0 = poi( ${$arg1}+0x418 ) ;
r @$t1 = by(@$t0 +0x8 ) &0x03;
r @$t0 = poi(@$t0 +0x8 )&0xfffffffffffffffc;
.if( ${/d:$arg2} ){
r @$t2 = ( ${$arg2} / 0n4 ) / 0n256;
r @$t3 = ( ${$arg2} / 0n4 ) % 0n256;
.if( @$t1 == 1 ){
r @$t0 = poi( @$t0 + @$t2 * 0x10 );
}
.if( @$t1 == 2 ){
.printf "not support 3 layer";
}
r @$t0 = poi(@$t0+@$t3*0x10);
!object ((((@$t0>>0x14)<<0x4)|0xFFFF000000000000))+0x30;
}
.else{
.printf "please entry eprocess and handle";
}
}
参考资料
- 《Windows内核原理与实现》
- https://blog.csdn.net/joshua_yu/article/details/590266