我之前写过一个有关于对象管理的读书笔记。但是这篇文章与前面的不同,这是我个人对对象管理器到底是什么的一个分析,而且也是直接对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 }
我们可以看到实质上内核对象就是用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()加锁修改这个值。
四.控制对象访问
在打开一个对象时,参数中要填写预期的操作以申请权限。