【旧文章搬运】Win7可变对象头结构之InfoMask解析
原文發(fā)表于百度空間,2010-08-11
==========================================================================
?對(duì)Windows對(duì)象管理有一定了解的人都知道,在固定對(duì)象頭(OBJECT_HEADER)前面是一塊可變區(qū)域,稱(chēng)為可變對(duì)象頭,它所包含的結(jié)構(gòu)內(nèi)容并不固定。在Win7之前,可變區(qū)域?qū)嶋H有哪些結(jié)構(gòu),通常是由OBJECT_HEADER中的幾個(gè)偏移值指出。如下:
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就是用于指出該結(jié)構(gòu)相對(duì)于固定對(duì)象頭(OBJECT_HEADER)的偏移。
如果NtGlobalFlags設(shè)置了MaintainTypeList標(biāo)志,那么由于CreatorInfo的存在,這個(gè)部分還會(huì)更復(fù)雜一點(diǎn),還得依據(jù)OBJECT_HEADER->Flag中的標(biāo)志位來(lái)作一些判斷才能具體確定某個(gè)結(jié)構(gòu)的具體偏移。
在Win7中,這一部分顯然經(jīng)過(guò)了精心設(shè)計(jì),一個(gè)InfoMask域再加一個(gè)ObpInfoMaskToOffset表就搞定了,顯得更加簡(jiǎn)捷快速。
顧名思義,InfoMask就是一個(gè)掩碼,它的每一位表示可變對(duì)象頭中某個(gè)指定的結(jié)構(gòu)是否存在。在Win7中,對(duì)象的結(jié)構(gòu)大體上沒(méi)有太大變化,固定對(duì)象頭的前面仍然是可變對(duì)象頭。
根據(jù)不同類(lèi)型的對(duì)象及實(shí)際情況,可變對(duì)象頭可能包含以下5個(gè)結(jié)構(gòu)中的一個(gè)或幾個(gè):?
這些結(jié)構(gòu)對(duì)應(yīng)的掩碼分別為:
#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因?yàn)榭勺儗?duì)象頭可能包含5種結(jié)構(gòu),每一種結(jié)構(gòu)包括存在或不存在兩種情況,那么一共是2^5=32種結(jié)果。所以,ObpInfoMaskToOffset表定義如下:
BYTE ObpInfoMaskToOffset[32];而存在的結(jié)構(gòu)就要占據(jù)一定的空間,那么對(duì)象頭(OBJECT_HEADER)距PoolHeader的偏移就會(huì)因結(jié)構(gòu)存在與否產(chǎn)生對(duì)應(yīng)的變化,該偏移實(shí)際上也就是可變對(duì)象頭的總大小。該表的初始化是在ObInitSystem()中進(jìn)行的。初始化代碼如下:
ULONG i = 0;ULONG offset = 0;do{offset = 0;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<32);初始化完成后表的內(nèi)容如下: kd> db ObpInfoMaskToOffset 83b97e60 00 10 10 20 08 18 18 28-10 20 20 30 18 28 28 38 ... ...(. 0.((8 83b97e70 08 18 18 28 10 20 20 30-18 28 28 38 20 30 30 40 ...(. 0.((8 00@可以看到,根據(jù)掩碼不同,那么實(shí)際存在的可變頭結(jié)構(gòu)就不同,其大小是掩碼所代表的有效結(jié)構(gòu)的大小之和。
可變頭為空,那么偏移自然為0,若5個(gè)結(jié)構(gòu)都包含了,那么偏移就是所有結(jié)構(gòu)之和,也就是0x40。
所以,根據(jù)對(duì)象頭中的掩碼InfoMask,就可以確定可變頭部分的大小和具體包含的結(jié)構(gòu),及每一個(gè)結(jié)構(gòu)相對(duì)于固定對(duì)象頭(OBJECT_HEADER)的實(shí)際偏移。
因?yàn)檫@個(gè)偏移是相對(duì)于固定對(duì)象頭(OBJECT_HEADER)往前的偏移,而在初始化過(guò)程中,這個(gè)偏移的值卻又是依次累加的,所以后來(lái)加上的結(jié)構(gòu)大小,在整個(gè)可變對(duì)象頭中反而比較靠上,掩碼小的結(jié)構(gòu)離固定對(duì)象頭越近。我以一個(gè)明確的圖來(lái)說(shuō)明這些信息:
舉個(gè)例子,比如某對(duì)象的ObjectHeader->InfoMask值為9,那么就說(shuō)明它包含了_OBJECT_HEADER_CREATOR_INFO(對(duì)應(yīng)掩碼為1)和_OBJECT_HEADER_QUOTA_INFO(對(duì)應(yīng)掩碼為8)兩個(gè)結(jié)構(gòu),ObpInfoMaskToOffset[9]的值為0x20,正是這兩個(gè)結(jié)構(gòu)的大小之和。并且,由于掩碼小的結(jié)構(gòu)離固定對(duì)象頭越近,所以可以明確知道ObjectHeader-0x10是_OBJECT_HEADER_CREATOR_INFO結(jié)構(gòu),ObjectHeader->0x20是_OBJECT_HEADER_QUOTA_INFO結(jié)構(gòu)。
下面我以一個(gè)實(shí)際的例子來(lái)詳細(xì)說(shuō)明。
可以看到,內(nèi)存池的分配從8603a518開(kāi)始。
kd> dd 8603a518 8603a518 04160003 e46e6957 00000000 00000068 8603a528 00000094 83b44c40 8a42edb8 00000002 8603a538 90ca2cd8 000e000e 90d95cd0 00000000 8603a548 86062f80 84e4aa38 0000016c 00000000 8603a558 0000000c 00000005 00000000 000f0014 8603a568 83b44c40 90d9c23e 00000000 86022848 8603a578 8604d8c8 91badaa0 00000000 ffabb8e8 8603a588 00000000 00000000 00000000 00000000根據(jù)對(duì)象的TypeIndex為0x14,及TypeIndex在OBJECT_HEADER中的偏移,不難看出8603a558就是對(duì)象頭。
kd> dt _OBJECT_HEADER 8603a558 nt!_OBJECT_HEADER+0x000 PointerCount : 12+0x004 HandleCount : 5+0x004 NextToFree : 0x00000005 +0x008 Lock : _EX_PUSH_LOCK+0x00c TypeIndex : 0x14 ''+0x00d TraceFlags : 0 ''+0x00e InfoMask : 0xf ''+0x00f Flags : 0 ''+0x010 ObjectCreateInfo : 0x83b44c40 _OBJECT_CREATE_INFORMATION+0x010 QuotaBlockCharged : 0x83b44c40 +0x014 SecurityDescriptor : 0x90d9c23e +0x018 Body : _QUAD可以看到,InfoMask為0xF=8+4+2+1,也就是說(shuō)包含了_OBJECT_HEADER_QUOTA_INFO(掩碼為8)、_OBJECT_HEADER_HANDLE_INFO(掩碼為4)、_OBJECT_HEADER_NAME_INFO(掩碼為2)和_OBJECT_HEADER_CREATOR_INFO(掩碼為1)這四個(gè)結(jié)構(gòu)。掩碼最大的結(jié)構(gòu)_OBJECT_HEADER_QUOTA_INFO在最上面:
kd> dt _OBJECT_HEADER_QUOTA_INFO 8603a520 nt!_OBJECT_HEADER_QUOTA_INFO+0x000 PagedPoolCharge : 0+0x004 NonPagedPoolCharge : 0x68+0x008 SecurityDescriptorCharge : 0x94+0x00c SecurityDescriptorQuotaBlock : 0x83b44c40 //加上該結(jié)構(gòu)的大小,就是下一個(gè)結(jié)構(gòu)_OBJECT_HEADER_HANDLE_INFO kd> dt _OBJECT_HEADER_HANDLE_INFO 8603a520+10 nt!_OBJECT_HEADER_HANDLE_INFO+0x000 HandleCountDataBase : 0x8a42edb8 _OBJECT_HANDLE_COUNT_DATABASE+0x000 SingleEntry : _OBJECT_HANDLE_COUNT_ENTRY //同理,下一個(gè)結(jié)構(gòu)是_OBJECT_HEADER_NAME_INFO kd> dt _OBJECT_HEADER_NAME_INFO 8603a520+10+8 nt!_OBJECT_HEADER_NAME_INFO+0x000 Directory : 0x90ca2cd8 _OBJECT_DIRECTORY+0x004 Name : _UNICODE_STRING "WinSta0"+0x00c ReferenceCount : 0 //然后是_OBJECT_HEADER_CREATOR_INFO kd> dt _OBJECT_HEADER_CREATOR_INFO 8603a520+10+8+10 nt!_OBJECT_HEADER_CREATOR_INFO+0x000 TypeList : _LIST_ENTRY [ 0x86062f80 - 0x84e4aa38 ]+0x008 CreatorUniqueProcess : 0x0000016c +0x00c CreatorBackTraceIndex : 0+0x00e Reserved : 0 kd> !process 16c 0 Searching for Process with Cid == 16c Cid Handle table at 93365000 with 553 Entries in use PROCESS 84e39d40 SessionId: 0 Cid: 016c Peb: 7ffd4000 ParentCid: 0140DirBase: 1ee8a0a0 ObjectTable: 90cae1f8 HandleCount: 75.Image: wininit.exe查看WinSta0的創(chuàng)建者,發(fā)現(xiàn)是wininit.exe~~
理解上以上結(jié)構(gòu),相信對(duì)于獲取可變對(duì)象頭中某個(gè)結(jié)構(gòu)的位置已經(jīng)不在話下。實(shí)際上,Win7的內(nèi)核導(dǎo)出了一個(gè)函數(shù)專(zhuān)門(mén)用于獲取對(duì)象頭中的_OBJECT_HEADER_NAME_INFO結(jié)構(gòu)。該函數(shù)就是ObQueryNameInfo(),還原成源碼如下:
PVOID ObQueryNameInfo(IN PVOID Object) {POBJECT_HEADER ObjectHeader=OBJECT_TO_OBJECT_HEADER(Object);BYTE InfoMask=ObjectHeader->InfoMask;ULONG NameInfo=0;if(InfoMask & OB_INFOMASK_NAME){NameInfo=(ULONG)ObjectHeader - ObpInfoMaskToOffset[InfoMask & (OB_INFOMASK_NAME+OB_INFOMASK_CREATOR_INFO)];}else{NameInfo=0;}return (PVOID)NameInfo; }源碼很好理解,取ObjectHeader->InfoMask,判斷OB_INFOMASK_NAME標(biāo)志位是否有效,若無(wú)效說(shuō)明可變頭中并沒(méi)有這個(gè)結(jié)構(gòu)。若有效,就根據(jù)掩碼取_OBJECT_HEADER_NAME_INFO靠下的兩個(gè)結(jié)構(gòu)的大小(包括_OBJECT_HEADER_NAME_INFO和_OBJECT_HEADER_CREATOR_INFO兩個(gè)結(jié)構(gòu)),然后對(duì)象頭減去這個(gè)偏移量,就是_OBJECT_HEADER_NAME_INFO結(jié)構(gòu)的位置了,結(jié)合前面的結(jié)構(gòu)圖,相信不難理解。
實(shí)際上,根據(jù)掩碼與結(jié)構(gòu)大小的對(duì)應(yīng)關(guān)系,完全可以用一個(gè)更一般的方式來(lái)獲取相應(yīng)的可變對(duì)象頭結(jié)構(gòu)信息。如下:
PVOID GetSpecificObjectHeaderInfo(PVOID Object,BYTE HeaderMask) {POBJECT_HEADER ObjectHeader=(POBJECT_HEADER)OBJECT_TO_OBJECT_HEADER(Object);BYTE InfoMask=ObjectHeader->InfoMask;BYTE MaxMask=0;ULONG HeaderInfo=0;if(InfoMask & HeaderMask){MaxMask=2*HeaderMask-1;HeaderInfo=(ULONG)ObjectHeader - ObpInfoMaskToOffset[InfoMask & MaxMask];}else{HeaderInfo=0;}return (PVOID)HeaderInfo; }參數(shù)解釋:
?Object : 欲操作的對(duì)象
?HeaderMask : 要獲取的對(duì)象結(jié)構(gòu)對(duì)應(yīng)的掩碼
?函數(shù)中的ObpInfoMaskToOffset可以自己定義,反正內(nèi)容和初始化方式已經(jīng)清楚了,內(nèi)容一樣用起來(lái)沒(méi)什么影響
這樣,直接用GetSpecificObjectHeaderInfo(Object,OB_INFOMASK_NAME)就可以代替ObQueryNameInfo(Object)了。
如果要獲取_OBJECT_HEADER_HANDLE_INFO結(jié)構(gòu),那么GetSpecificObjectHeaderInfo(Object,OB_INFOMASK_HANDLE)就可以了,,獲取其它結(jié)構(gòu)信息也是如此,非常方便~~
關(guān)于Win7的可變對(duì)象頭,就說(shuō)到這里~~
轉(zhuǎn)載于:https://www.cnblogs.com/achillis/p/10183526.html
總結(jié)
以上是生活随笔為你收集整理的【旧文章搬运】Win7可变对象头结构之InfoMask解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: P2016 战略游戏
- 下一篇: springboot中关闭eureka