Windows核心執行體物件管理器的操作過程與分析

Ox9A82發表於2016-04-22

我之前寫過一個有關於物件管理的讀書筆記。但是這篇文章與前面的不同,這是我個人對物件管理器到底是什麼的一個分析,而且也是直接對WRK程式碼進行的閱讀。

執行體物件即我們通常所言的核心物件,我們知道Windows核心中有許多“管理器”,然而管理器並不是一個實體的存在而是一個抽象的概念。它更像是一系列相關函式和資料結構的集合。

《Windows Internals》中如此定義物件管理器:“本節將介紹Windows的物件管理器,即執行體內部負責建立、刪除、保護和跟蹤物件的元件”。

我們先從建立物件開始。依次是:建立物件、刪除物件、引用物件、解除引用物件、控制物件訪問、查詢物件、

 

一.建立物件

物件建立操作肯定從r3傳來。

針對每個物件型別都有各自的建立核心物件的函式。舉個例子,

NtCreateFile()

NtCreateEvent()

NtCreateTimer()

NtCreateKey()

NtCreateProcess()

NtCreateThread()

這些函式都是由相應的Zw版本對應而來的。

這些函式內部都是用了ObCreateObject()這個函式來建立物件。

ObCreateObject()函式主要做了兩件事

1.解析傳入的OBJECT_ATTRIBUTES結構到物件的OBJECT_CREATE_INFORMATION結構以及其他結構中。

2.呼叫ObpAllocateObject()函式建立物件。

我們主要關注ObpAllocateObject()函式怎麼建立的物件。

  1 NTSTATUS
  2 ObpAllocateObject (
  3     IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
  4     IN KPROCESSOR_MODE OwnershipMode,
  5     IN POBJECT_TYPE ObjectType OPTIONAL,
  6     IN PUNICODE_STRING ObjectName,
  7     IN ULONG ObjectBodySize,
  8     OUT POBJECT_HEADER *ReturnedObjectHeader
  9     )
 10 
 11 /*++
 12 
 13 Routine Description:
 14 
 15     This routine allocates a new object including the object header
 16     and body from pool and fill in the appropriate fields.
 17 
 18 Arguments:
 19 
 20     ObjectCreateInfo - Supplies the create information for the new object
 21 
 22     OwnershipMode - Supplies the processor mode of who is going to own
 23         the object
 24 
 25     ObjectType - Optionally supplies the object type of the object being
 26         created. If the object create info not null then this field must
 27         be supplied.
 28 
 29     ObjectName - Supplies the name of the object being created
 30 
 31     ObjectBodySize - Specifies the size, in bytes, of the body of the object
 32         being created
 33 
 34     ReturnedObjectHeader - Receives a pointer to the object header for the
 35         newly created objet.
 36 
 37 Return Value:
 38 
 39     An appropriate status value.
 40 
 41 --*/
 42 
 43 {
 44     ULONG HeaderSize;
 45     POBJECT_HEADER ObjectHeader;
 46     ULONG QuotaInfoSize;
 47     ULONG HandleInfoSize;
 48     ULONG NameInfoSize;
 49     ULONG CreatorInfoSize;
 50     POBJECT_HEADER_QUOTA_INFO QuotaInfo;
 51     POBJECT_HEADER_HANDLE_INFO HandleInfo;
 52     POBJECT_HEADER_NAME_INFO NameInfo;
 53     POBJECT_HEADER_CREATOR_INFO CreatorInfo;
 54     POOL_TYPE PoolType;
 55 
 56     PAGED_CODE();
 57 
 58     //
 59     //  Compute the sizes of the optional object header components.
 60     //
 61 
 62     if (ObjectCreateInfo == NULL) {
 63 
 64         QuotaInfoSize = 0;
 65         HandleInfoSize = 0;
 66         NameInfoSize = sizeof( OBJECT_HEADER_NAME_INFO );
 67         CreatorInfoSize = sizeof( OBJECT_HEADER_CREATOR_INFO );//OBJECT_HEADER_CREATOR_INFO一定存在
 68 
 69     } else {
 70 
 71         //
 72         //  The caller specified some additional object create info
 73         //
 74         //  First check to see if we need to set the quota
 75         //
 76 
 77         if (((ObjectCreateInfo->PagedPoolCharge != ObjectType->TypeInfo.DefaultPagedPoolCharge ||
 78               ObjectCreateInfo->NonPagedPoolCharge != ObjectType->TypeInfo.DefaultNonPagedPoolCharge ||
 79               ObjectCreateInfo->SecurityDescriptorCharge > SE_DEFAULT_SECURITY_QUOTA) &&
 80                  PsGetCurrentProcess() != PsInitialSystemProcess) ||
 81             (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) {
 82             //這時,配額頭才是存在的
 83             QuotaInfoSize = sizeof( OBJECT_HEADER_QUOTA_INFO );
 84 
 85 
 86         } else {
 87 
 88             QuotaInfoSize = 0;
 89         }
 90 
 91         //
 92         //  Check if we are to allocate space to maintain handle counts
 93         //
 94 
 95         if (ObjectType->TypeInfo.MaintainHandleCount) {
 96             //這時,控制程式碼頭才是存在的
 97             HandleInfoSize = sizeof( OBJECT_HEADER_HANDLE_INFO );
 98 
 99 
100         } else {
101 
102             HandleInfoSize = 0;
103         }
104 
105         //
106         //  Check if we are to allocate space for the name
107         //
108 
109         if (ObjectName->Buffer != NULL) {
110             //這時,名字頭才是存在的
111             NameInfoSize = sizeof( OBJECT_HEADER_NAME_INFO );
112 
113 
114         } else {
115 
116             NameInfoSize = 0;
117         }
118 
119         //
120         //  Finally check if we are to maintain the creator info
121         //
122 
123         if (ObjectType->TypeInfo.MaintainTypeList) {
124 
125             CreatorInfoSize = sizeof( OBJECT_HEADER_CREATOR_INFO );
126 
127         } else {
128 
129             CreatorInfoSize = 0;
130         }
131     }
132 
133     //
134     //  Now compute the total header size
135     //
136     //計算整個頭的大小
137     HeaderSize = QuotaInfoSize +
138                  HandleInfoSize +
139                  NameInfoSize +
140                  CreatorInfoSize +
141                  FIELD_OFFSET( OBJECT_HEADER, Body );
142 
143     //
144     //  Allocate and initialize the object.
145     //
146     //  If the object type is not specified or specifies nonpaged pool,
147     //  then allocate the object from nonpaged pool.
148     //  Otherwise, allocate the object from paged pool.
149     //
150 
151     if ((ObjectType == NULL) || (ObjectType->TypeInfo.PoolType == NonPagedPool)) {
152         //為啥等於空時要用非分頁池?
153         PoolType = NonPagedPool;
154 
155     } else {
156 
157         PoolType = PagedPool;
158     }
159 
160     ObjectHeader = ExAllocatePoolWithTag( PoolType,
161                                           HeaderSize + ObjectBodySize,
162                                           (ObjectType == NULL ? 'TjbO' : ObjectType->Key) |//這裡體現了物件型別中國Key欄位的作用
163                                             PROTECTED_POOL );
164 
165     if (ObjectHeader == NULL) {
166 
167         return STATUS_INSUFFICIENT_RESOURCES;
168     }
169 
170     //
171     //  Now based on if we are to put in the quota, handle, name, or creator info we
172     //  will do the extra work.  This order is very important because we rely on
173     //  it to free the object.
174     //
175 
176     if (QuotaInfoSize != 0) {
177         //設定配額頭OBJECT_HEADER_QUOTA_INFO
178         QuotaInfo = (POBJECT_HEADER_QUOTA_INFO)ObjectHeader;
179         QuotaInfo->PagedPoolCharge = ObjectCreateInfo->PagedPoolCharge;
180         QuotaInfo->NonPagedPoolCharge = ObjectCreateInfo->NonPagedPoolCharge;
181         QuotaInfo->SecurityDescriptorCharge = ObjectCreateInfo->SecurityDescriptorCharge;
182         QuotaInfo->ExclusiveProcess = NULL;
183         ObjectHeader = (POBJECT_HEADER)(QuotaInfo + 1);
184     }
185 
186     if (HandleInfoSize != 0) {
187         //設定Handle頭OBJECT_HEADER_HANDLE_INFO
188         HandleInfo = (POBJECT_HEADER_HANDLE_INFO)ObjectHeader;
189         HandleInfo->SingleEntry.HandleCount = 0;
190         ObjectHeader = (POBJECT_HEADER)(HandleInfo + 1);
191     }
192 
193     if (NameInfoSize != 0) {
194         //設定Name頭OBJECT_HEADER_NAME_INFO
195         NameInfo = (POBJECT_HEADER_NAME_INFO)ObjectHeader;
196         NameInfo->Name = *ObjectName;
197         NameInfo->Directory = NULL;
198         NameInfo->QueryReferences = 1;
199 
200         if ( (OwnershipMode == KernelMode) 
201                 && 
202              (ObjectCreateInfo != NULL)
203                 &&
204              (ObjectCreateInfo->Attributes & OBJ_KERNEL_EXCLUSIVE) ) {
205 
206             NameInfo->QueryReferences |= OBP_NAME_KERNEL_PROTECTED;
207         }
208        
209         ObjectHeader = (POBJECT_HEADER)(NameInfo + 1);
210     }
211 
212     if (CreatorInfoSize != 0) {
213         //設定建立資訊頭OBJECT_HEADER_CREATOR_INFO
214         CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)ObjectHeader;
215         CreatorInfo->CreatorBackTraceIndex = 0;
216         CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcess()->UniqueProcessId;//把建立物件的程式的資訊存在建立資訊頭中
217         InitializeListHead( &CreatorInfo->TypeList );//加入到同一型別的核心物件的列表
218 
219         PERFINFO_ADD_OBJECT_TO_ALLOCATED_TYPE_LIST(CreatorInfo, ObjectType);
220 
221         ObjectHeader = (POBJECT_HEADER)(CreatorInfo + 1);
222     }
223 
224     //
225     //  Compute the proper offsets based on what we have
226     //
227     
228     //設定OBJECT_HEADER中幾個可選頭的偏移值
229     if (QuotaInfoSize != 0) {
230 
231         ObjectHeader->QuotaInfoOffset = (UCHAR)(QuotaInfoSize + HandleInfoSize + NameInfoSize + CreatorInfoSize);
232 
233     } else {
234 
235         ObjectHeader->QuotaInfoOffset = 0;
236     }
237 
238     if (HandleInfoSize != 0) {
239 
240         ObjectHeader->HandleInfoOffset = (UCHAR)(HandleInfoSize + NameInfoSize + CreatorInfoSize);
241 
242     } else {
243 
244         ObjectHeader->HandleInfoOffset = 0;
245     }
246 
247     if (NameInfoSize != 0) {
248 
249         ObjectHeader->NameInfoOffset =  (UCHAR)(NameInfoSize + CreatorInfoSize);
250 
251     } else {
252 
253         ObjectHeader->NameInfoOffset = 0;
254     }
255 
256     //
257     //  Say that this is a new object, and conditionally set the other flags
258     //
259     //新增標誌位
260     ObjectHeader->Flags = OB_FLAG_NEW_OBJECT;
261 
262     if (CreatorInfoSize != 0) {
263 
264         ObjectHeader->Flags |= OB_FLAG_CREATOR_INFO;
265     }
266 
267     if (HandleInfoSize != 0) {
268 
269         ObjectHeader->Flags |= OB_FLAG_SINGLE_HANDLE_ENTRY;
270     }
271 
272     //
273     //  Set the counters and its type
274     //
275 
276     ObjectHeader->PointerCount = 1;//引用數
277     ObjectHeader->HandleCount = 0;//控制程式碼引用數
278     ObjectHeader->Type = ObjectType;
279 
280     //
281     //  Initialize the object header.
282     //
283     //  N.B. The initialization of the object header is done field by
284     //       field rather than zeroing the memory and then initializing
285     //       the pertinent fields.
286     //
287     //  N.B. It is assumed that the caller will initialize the object
288     //       attributes, object ownership, and parse context.
289     //
290 
291     //根據使用者傳入的引數設定OBJECT_HEADER的Flags值
292     if (OwnershipMode == KernelMode) {
293 
294         ObjectHeader->Flags |= OB_FLAG_KERNEL_OBJECT;
295     }
296 
297     if (ObjectCreateInfo != NULL &&
298         ObjectCreateInfo->Attributes & OBJ_PERMANENT ) {
299 
300         ObjectHeader->Flags |= OB_FLAG_PERMANENT_OBJECT;
301     }
302 
303     if ((ObjectCreateInfo != NULL) &&
304         (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) {
305 
306         ObjectHeader->Flags |= OB_FLAG_EXCLUSIVE_OBJECT;
307     }
308 
309     ObjectHeader->ObjectCreateInfo = ObjectCreateInfo;
310     ObjectHeader->SecurityDescriptor = NULL;
311 
312     if (ObjectType != NULL) {
313 
314         InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfObjects);
315 
316         if (ObjectType->TotalNumberOfObjects > ObjectType->HighWaterNumberOfObjects) {
317 
318             ObjectType->HighWaterNumberOfObjects = ObjectType->TotalNumberOfObjects;
319         }
320     }
321 
322 
323     //返回的值
324     *ReturnedObjectHeader = ObjectHeader;
325 
326     return STATUS_SUCCESS;
327 }
View Code

我們可以看到實質上核心物件就是用ExAllocatePoolWithTag分配的一塊記憶體。

 這個是OBJECT_HEADER,大量的操作都針對這個位進行。

看以看到物件頭和所有可選頭的填充都在這個函式中完成。

 1      typedef struct _OBJECT_HEADER
 2 {
 3      LONG PointerCount;//引用計數
 4      union
 5      {
 6           LONG HandleCount;//控制程式碼計數
 7           PVOID NextToFree;
 8      };
 9      POBJECT_TYPE Type;//物件型別
10      UCHAR NameInfoOffset;//OBJECT_HEADER_NAME_INFO偏移
11      UCHAR HandleInfoOffset;//OBJECT_HEADER_HANDLE_INFO偏移
12      UCHAR QuotaInfoOffset;//OBJECT_HEADER_QUOTA_INFO偏移
13      UCHAR Flags;//標明此物件各種的屬性的識別符號
14      union
15      {
16           POBJECT_CREATE_INFORMATION ObjectCreateInfo;//OBJECT_CREATE_INFORMATION結構地址
17           PVOID QuotaBlockCharged;
18      };
19      PVOID SecurityDescriptor;//安全描述符結構地址
20      QUAD Body;//物件體地址
21 } OBJECT_HEADER, *POBJECT_HEADER;

 前面說ObCreateObject()函式“解析傳入的OBJECT_ATTRIBUTES結構到物件的OBJECT_CREATE_INFORMATION結構以及其他結構中。”

在ObCreateObject()中的解析,在ObpAllocateObject()中派上了用途。ObpAllocateObject()不再有OBJECT_ATTRIBUTES結構作為引數。

 

二.刪除物件

在ObDereferenceObject()中,會判斷OBJECT_HEADER中的PointerCount值,如果為0就呼叫ObpDeleteObject()函式來進行刪除。

ObpDeleteObject函式先把物件從OBJECT_HEADER_CREATOR_INFO.TypeList列表中刪除,然後釋放名字UNICODE_STRING的緩衝區,最後呼叫OBJECT_TYPE中定義的DeleteProcedure函式。

 

三.引用物件和解除引用物件

比如函式ObReferenceObjectByPointer()

引用和解除引用物件是在獲取了OBJECT指標後,用OBJECT_TO_OBJECT_HEADER宏轉換成OBJECT_HEADER指標,然後用InterlockedIncrement()加鎖修改這個值。

 

四.控制物件訪問

在開啟一個物件時,引數中要填寫預期的操作以申請許可權。

相關文章