Windows内核执行体对象管理器的操作过程与分析

发布者:Ox9A82
发布于:2016-04-22 10:42

我之前写过一个有关于对象管理的读书笔记。但是这篇文章与前面的不同,这是我个人对对象管理器到底是什么的一个分析,而且也是直接对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()加锁修改这个值。

 

四.控制对象访问

在打开一个对象时,参数中要填写预期的操作以申请权限。


声明:该文观点仅代表作者本人,转载请注明来自看雪