【旧文章搬运】Win7可变对象头结构之InfoMask解析
原文发表于百度空间,2010-08-11
==========================================================================
对Windows对象管理有一定了解的人都知道,在固定对象头(OBJECT_HEADER)前面是一块可变区域,称为可变对象头,它所包含的结构内容并不固定。在Win7之前,可变区域实际有哪些结构,通常是由OBJECT_HEADER中的几个偏移值指出。如下:
lkd> dt _OBJECT_HEADER(WinXP SP2)nt!_OBJECT_HEADER +0x000 PointerCount : Int4B
+0x004 HandleCount : Int4B
+0x004 NextToFree : Ptr32 Void
+0x008 Type : Ptr32 _OBJECT_TYPE
+0x00c NameInfoOffset : UChar
+0x00d HandleInfoOffset : UChar
+0x00e QuotaInfoOffset : UChar
+0x00f Flags : UChar
+0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : Ptr32 Void
+0x014 SecurityDescriptor : Ptr32 Void
+0x018 Body : _QUAD
其中的NameInfoOffset、HandleInfoOffset、QuotaInfoOffset就是用于指出该结构相对于固定对象头(OBJECT_HEADER)的偏移。
如果NtGlobalFlags设置了MaintainTypeList标志,那么由于CreatorInfo的存在,这个部分还会更复杂一点,还得依据OBJECT_HEADER->Flag中的标志位来作一些判断才能具体确定某个结构的具体偏移。
在Win7中,这一部分显然经过了精心设计,一个InfoMask域再加一个ObpInfoMaskToOffset表就搞定了,显得更加简捷快速。
顾名思义,InfoMask就是一个掩码,它的每一位表示可变对象头中某个指定的结构是否存在。在Win7中,对象的结构大体上没有太大变化,固定对象头的前面仍然是可变对象头。
根据不同类型的对象及实际情况,可变对象头可能包含以下5个结构中的一个或几个:
(Size=0x08)ntkrpamp!_OBJECT_HEADER_PROCESS_INFO
(Size=0x10)ntkrpamp!_OBJECT_HEADER_QUOTA_INFO
(Size=0x08)ntkrpamp!_OBJECT_HEADER_HANDLE_INFO
(Size=0x10)ntkrpamp!_OBJECT_HEADER_NAME_INFO
(Size=0x10)ntkrpamp!_OBJECT_HEADER_CREATOR_INFO
这些结构对应的掩码分别为:
#define OB_INFOMASK_PROCESS_INFO 0x10
#define OB_INFOMASK_QUOTA 0x08
#define OB_INFOMASK_HANDLE 0x04
#define OB_INFOMASK_NAME 0x02
#define OB_INFOMASK_CREATOR_INFO 0x01
因为可变对象头可能包含5种结构,每一种结构包括存在或不存在两种情况,那么一共是2^5=32种结果。所以,ObpInfoMaskToOffset表定义如下:
BYTE ObpInfoMaskToOffset[];
而存在的结构就要占据一定的空间,那么对象头(OBJECT_HEADER)距PoolHeader的偏移就会因结构存在与否产生对应的变化,该偏移实际上也就是可变对象头的总大小。该表的初始化是在ObInitSystem()中进行的。初始化代码如下:
ULONG i = ;
ULONG offset = ;
do
{
offset = ;
if ( i & OB_INFOMASK_CREATOR_INFO )
offset = sizeof(_OBJECT_HEADER_CREATOR_INFO);
if ( i & OB_INFOMASK_NAME )
offset += sizeof(_OBJECT_HEADER_NAME_INFO);
if ( i & OB_INFOMASK_HANDLE )
offset += sizeof(_OBJECT_HEADER_HANDLE_INFO);
if ( i & OB_INFOMASK_QUOTA )
offset += sizeof(_OBJECT_HEADER_QUOTA_INFO);
if ( i & OB_INFOMASK_PROCESS_INFO )
offset += sizeof(_OBJECT_HEADER_PROCESS_INFO);
ObpInfoMaskToOffset[i++] = offset;
}while(i<);初始化完成后表的内容如下:
kd> db ObpInfoMaskToOffset
83b97e60 - ... ...(. .((
83b97e70 - ...(. .(( @
可以看到,根据掩码不同,那么实际存在的可变头结构就不同,其大小是掩码所代表的有效结构的大小之和。
可变头为空,那么偏移自然为0,若5个结构都包含了,那么偏移就是所有结构之和,也就是0x40。
所以,根据对象头中的掩码InfoMask,就可以确定可变头部分的大小和具体包含的结构,及每一个结构相对于固定对象头(OBJECT_HEADER)的实际偏移。
因为这个偏移是相对于固定对象头(OBJECT_HEADER)往前的偏移,而在初始化过程中,这个偏移的值却又是依次累加的,所以后来加上的结构大小,在整个可变对象头中反而比较靠上,掩码小的结构离固定对象头越近。我以一个明确的图来说明这些信息:
举个例子,比如某对象的ObjectHeader->InfoMask值为9,那么就说明它包含了_OBJECT_HEADER_CREATOR_INFO(对应掩码为1)和_OBJECT_HEADER_QUOTA_INFO(对应掩码为8)两个结构,ObpInfoMaskToOffset[9]的值为0x20,正是这两个结构的大小之和。并且,由于掩码小的结构离固定对象头越近,所以可以明确知道ObjectHeader-0x10是_OBJECT_HEADER_CREATOR_INFO结构,ObjectHeader->0x20是_OBJECT_HEADER_QUOTA_INFO结构。
下面我以一个实际的例子来详细说明。
kd> dt _OBJECT_TYPE 84e4aa38 //查看对象类型
nt!_OBJECT_TYPE
+0x000 TypeList : _LIST_ENTRY [ 0x8603a548 - 0x863593e8 ] //为了便观察到同类型的所有对象,我设置了MaintainTypeList标志
+0x008 Name : _UNICODE_STRING "WindowStation"
+0x010 DefaultObject : (null)
+0x014 Index : 0x14 ''
+0x018 TotalNumberOfObjects :
+0x01c TotalNumberOfHandles : 0x35
+0x020 HighWaterNumberOfObjects :
+0x024 HighWaterNumberOfHandles : 0x3f
+0x028 TypeInfo : _OBJECT_TYPE_INITIALIZER
+0x078 TypeLock : _EX_PUSH_LOCK
+0x07c Key : 0x646e6957
+0x080 CallbackList : _LIST_ENTRY [ 0x84e4aab8 - 0x84e4aab8 ]
kd> !pool 0x8603a548 //观察第一个对象的内存池分配
Pool page 8603a548 region is Nonpaged pool
8603a500 size: previous size: (Allocated) MmSi
*8603a518 size: b0 previous size: (Allocated) *Wind (Protected)
Owning component : Unknown (update pooltag.txt)
8603a5c8 size: previous size: b0 (Allocated) EtwR (Protected)
...
可以看到,内存池的分配从8603a518开始。
kd> dd 8603a518
8603a518 e46e6957
8603a528 83b44c40 8a42edb8
8603a538 90ca2cd8 000e000e 90d95cd0
8603a548 86062f80 84e4aa38 0000016c
8603a558 0000000c 000f0014
8603a568 83b44c40 90d9c23e
8603a578 8604d8c8 91badaa0 ffabb8e8
8603a588
根据对象的TypeIndex为0x14,及TypeIndex在OBJECT_HEADER中的偏移,不难看出8603a558就是对象头。
kd> dt _OBJECT_HEADER 8603a558
nt!_OBJECT_HEADER
+0x000 PointerCount :
+0x004 HandleCount :
+0x004 NextToFree : 0x00000005
+0x008 Lock : _EX_PUSH_LOCK
+0x00c TypeIndex : 0x14 ''
+0x00d TraceFlags : ''
+0x00e InfoMask : 0xf ''
+0x00f Flags : ''
+0x010 ObjectCreateInfo : 0x83b44c40 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x83b44c40
+0x014 SecurityDescriptor : 0x90d9c23e
+0x018 Body : _QUAD
可以看到,InfoMask为0xF=8+4+2+1,也就是说包含了_OBJECT_HEADER_QUOTA_INFO(掩码为8)、_OBJECT_HEADER_HANDLE_INFO(掩码为4)、_OBJECT_HEADER_NAME_INFO(掩码为2)和_OBJECT_HEADER_CREATOR_INFO(掩码为1)这四个结构。掩码最大的结构_OBJECT_HEADER_QUOTA_INFO在最上面:
kd> dt _OBJECT_HEADER_QUOTA_INFO 8603a520
nt!_OBJECT_HEADER_QUOTA_INFO
+0x000 PagedPoolCharge :
+0x004 NonPagedPoolCharge : 0x68
+0x008 SecurityDescriptorCharge : 0x94
+0x00c SecurityDescriptorQuotaBlock : 0x83b44c40
//加上该结构的大小,就是下一个结构_OBJECT_HEADER_HANDLE_INFO
kd> dt _OBJECT_HEADER_HANDLE_INFO 8603a520+
nt!_OBJECT_HEADER_HANDLE_INFO
+0x000 HandleCountDataBase : 0x8a42edb8 _OBJECT_HANDLE_COUNT_DATABASE
+0x000 SingleEntry : _OBJECT_HANDLE_COUNT_ENTRY
//同理,下一个结构是_OBJECT_HEADER_NAME_INFO
kd> dt _OBJECT_HEADER_NAME_INFO 8603a520++
nt!_OBJECT_HEADER_NAME_INFO
+0x000 Directory : 0x90ca2cd8 _OBJECT_DIRECTORY
+0x004 Name : _UNICODE_STRING "WinSta0"
+0x00c ReferenceCount :
//然后是_OBJECT_HEADER_CREATOR_INFO
kd> dt _OBJECT_HEADER_CREATOR_INFO 8603a520+++
nt!_OBJECT_HEADER_CREATOR_INFO
+0x000 TypeList : _LIST_ENTRY [ 0x86062f80 - 0x84e4aa38 ]
+0x008 CreatorUniqueProcess : 0x0000016c
+0x00c CreatorBackTraceIndex :
+0x00e Reserved :
kd> !process 16c
Searching for Process with Cid == 16c
Cid Handle table at with Entries in use
PROCESS 84e39d40 SessionId: Cid: 016c Peb: 7ffd4000 ParentCid:
DirBase: 1ee8a0a0 ObjectTable: 90cae1f8 HandleCount: .
Image: wininit.exe
查看WinSta0的创建者,发现是wininit.exe~~
理解上以上结构,相信对于获取可变对象头中某个结构的位置已经不在话下。实际上,Win7的内核导出了一个函数专门用于获取对象头中的_OBJECT_HEADER_NAME_INFO结构。该函数就是ObQueryNameInfo(),还原成源码如下:
PVOID ObQueryNameInfo(IN PVOID Object)
{
POBJECT_HEADER ObjectHeader=OBJECT_TO_OBJECT_HEADER(Object);
BYTE InfoMask=ObjectHeader->InfoMask;
ULONG NameInfo=;
if(InfoMask & OB_INFOMASK_NAME)
{
NameInfo=(ULONG)ObjectHeader - ObpInfoMaskToOffset[InfoMask & (OB_INFOMASK_NAME+OB_INFOMASK_CREATOR_INFO)];
}
else
{
NameInfo=;
}
return (PVOID)NameInfo;
}
源码很好理解,取ObjectHeader->InfoMask,判断OB_INFOMASK_NAME标志位是否有效,若无效说明可变头中并没有这个结构。若有效,就根据掩码取_OBJECT_HEADER_NAME_INFO靠下的两个结构的大小(包括_OBJECT_HEADER_NAME_INFO和_OBJECT_HEADER_CREATOR_INFO两个结构),然后对象头减去这个偏移量,就是_OBJECT_HEADER_NAME_INFO结构的位置了,结合前面的结构图,相信不难理解。
实际上,根据掩码与结构大小的对应关系,完全可以用一个更一般的方式来获取相应的可变对象头结构信息。如下:
PVOID GetSpecificObjectHeaderInfo(PVOID Object,BYTE HeaderMask)
{
POBJECT_HEADER ObjectHeader=(POBJECT_HEADER)OBJECT_TO_OBJECT_HEADER(Object);
BYTE InfoMask=ObjectHeader->InfoMask;
BYTE MaxMask=;
ULONG HeaderInfo=;
if(InfoMask & HeaderMask)
{
MaxMask=*HeaderMask-;
HeaderInfo=(ULONG)ObjectHeader - ObpInfoMaskToOffset[InfoMask & MaxMask];
}
else
{
HeaderInfo=;
}
return (PVOID)HeaderInfo;
}
参数解释:
Object : 欲操作的对象
HeaderMask : 要获取的对象结构对应的掩码
函数中的ObpInfoMaskToOffset可以自己定义,反正内容和初始化方式已经清楚了,内容一样用起来没什么影响
这样,直接用GetSpecificObjectHeaderInfo(Object,OB_INFOMASK_NAME)就可以代替ObQueryNameInfo(Object)了。
如果要获取_OBJECT_HEADER_HANDLE_INFO结构,那么GetSpecificObjectHeaderInfo(Object,OB_INFOMASK_HANDLE)就可以了,,获取其它结构信息也是如此,非常方便~~
关于Win7的可变对象头,就说到这里~~
【旧文章搬运】Win7可变对象头结构之InfoMask解析的更多相关文章
- 【旧文章搬运】Win7 OBJECT_HEADER之TypeIndex解析
原文发表于百度空间,2010-08-09========================================================================== 在Wind ...
- 【旧文章搬运】从XP到Win7看Windows对象管理的变化(概述)
原文发表于百度空间,2010-08-01========================================================================== 今天花了一 ...
- 【旧文章搬运】深入分析Win7的对象引用跟踪机制
原文发表于百度空间及看雪论坛,2010-09-12 看雪论坛地址:https://bbs.pediy.com/thread-120296.htm============================ ...
- 码农会锁,synchronized 对象头结构(mark-word、Klass Pointer)、指针压缩、锁竞争,源码解毒、深度分析!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 感觉什么都不会,从哪开始呀! 这是最近我总能被问到的问题,也确实是.一个初入编程职场 ...
- 【旧文章搬运】Windows句柄表格式
原文发表于百度空间,2009-02-28========================================================================== 句柄是Wi ...
- 【旧文章搬运】PspCidTable概述
原文发表于百度空间,2009-03-28========================================================================== PspCi ...
- 【旧文章搬运】PsVoid中IrpCreateFile函数在Win7下蓝屏BUG分析及解决
原文发表于百度空间,2010-04-05========================================================================== 这也许是我 ...
- 【旧文章搬运】Windows内核常见数据结构(内核对象)
原文发表于百度空间,2008-7-23========================================================================== 继续学习,继 ...
- 【旧文章搬运】分析了一下360安全卫士的HOOK(二)——架构与实现
原文发表于百度空间及看雪论坛,2009-10-14 看雪论坛地址:https://bbs.pediy.com/thread-99460.htm 刚发这篇文章的时候,因为内容涉及360的核心产品,文章被 ...
随机推荐
- 浅谈PropertyChanged是如何被初始化的?
http://www.cnblogs.com/wpcockroach/p/3909081.html
- 【Sprint3冲刺之前】项目可行性研究报告
TD校园手机助手软件可行性研究报告 1.引言 在信息化时代高速发展的今天,手机成了每个人的必备物品之一.随着科技的迅猛发展,人们已经不仅仅满足于用手机发短信,打电话,因此,android手机应运而生, ...
- 使用Python处理Excel文件的一些代码示例
笔记:使用Python处理Excel文件的一些代码示例,以下代码来自于<Python数据分析基础>一书,有删改 #!/usr/bin/env python3 # 导入读取Excel文件的库 ...
- 使用mark-sweep算法的垃圾回收器
在我写C++代码的那些时间里,我没有写过垃圾回收器,也没有实现过自己的内存分配器,这方面的文章倒是看了不 少.比如我在写C#代码时只管new而不需要释放,我也明白有个垃圾回收器在那帮我回收那些堆上的对 ...
- hdu1878欧拉回路(DFS+欧拉回路)
欧拉回路 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- VS重置命令:devenv.exe/resetuserdata
VS命令行下执行下面的命令: devenv.exe/resetuserdata
- Hadoop实战-Flume之Hello world(九)
环境介绍: 主服务器ip:192.168.80.128 1.准备apache-flume-1.7.0-bin.tar文件 2.上传到master(192.168.80.128)服务器上 3.解压apa ...
- (非原)SQL注入专题--整理帖 && like 语句拼sql 如何防止注入攻击。
原地址:blog.csdn.net/lvjin110/article/details/28697695 like 语句拼sql 如何防止注入攻击?http://bbs.csdn.net/topics/ ...
- MARA 附加结构(增强字段)
- Android在有存储卡和无存储卡情况下拍照后固定尺寸和压缩大小
我最近工作挺忙,距离上一次写博客转眼已经过了一个多月,每次学到和用到点新东西,其实都有分享的欲望,但奈何文笔太差,而一篇文章包括构思,排版,修改发布的时间最少要花费2个小时(这其中还不包括写完后未保存 ...