windows Object Manager
来源:互联网 发布:大数据时代读书报告 编辑:程序博客网 时间:2024/06/03 16:17
Handles Object Manager Initialization and Shutdown
阶段 0 初始化:
1.初始化obci和obnm,创建信息和对象名称链表
2.创建安全描述符缓存
3.初始化默认对象事件和设备映射锁
4.在EPROCESS AND ETHREAD set GrantedAccess 为高等访问权限
5.创建句柄表,并设置到EPROCESS 的ObjectTable上。
6.创建 Type Diretory SymbolicLink 三种对象类型
阶段1初始化:
1.初始化对象目录,L”\”,L”\KernelObjects”, L”\ObjectTypes”
2.检索ObpTypeObjectType->TypeList,将类型对象加入到 L”\ObjectTypes”中
3.创建DosDeviceDirectory L”\GLOBAL??”
4.创建关于dos device directory 的符号连接
对象的具体管理
创建对象 ObCreateObject
我们先看对象头部,这个是对象管理器来管理的,它自己创建对象头部的相关信息。
typedef struct _OBJECT_HEADER{ LONG PointerCount; union { LONG HandleCount; volatile PVOID NextToFree; }; POBJECT_TYPE Type; UCHAR NameInfoOffset; UCHAR HandleInfoOffset; UCHAR QuotaInfoOffset; UCHAR Flags; union { POBJECT_CREATE_INFORMATION ObjectCreateInfo; PVOID QuotaBlockCharged; }; PSECURITY_DESCRIPTOR SecurityDescriptor; QUAD Body;} OBJECT_HEADER, *POBJECT_HEADER;
一般情况下创建对象就是根据不同的要求设置对象头,对应的申请空间也是不同大小的,要在ObpAllocateObject中计算对象头的大小,然后申请内存供上层函数完成对象的创建。跟着对象头一起创建的还有quotainfo,handleinfo,nameinfo,creatorinfo.然后将这些信息的偏移地址分别设置到header上,然后初始化header数据结构中的其他变量。设置PointCount 和HandleCount,并设置对象类型,以分辨出是何种对象等等。
以创建timer为例,当上层调用对象管理器的api来创建对象时,使用如下参数创建
/* Create the Object */ Status = ObCreateObject(PreviousMode, ExTimerType, ObjectAttributes, PreviousMode, NULL, sizeof(ETIMER), 0, 0, (PVOID*)&Timer);
我们可以在ObCreateObject获知创建模式,创建属性和创建的对象大小。计算出FinaSize的值(即header中额外的管理信息)和objectSize 是个sizeof(ETIMER)。再根据该对象自己的属性,来决定是创建在换页或是非换页的内存上。
Header = ExAllocatePoolWithTag(PoolType, FinalSize + ObjectSize, Tag);
然后如上申请了某个对象内存空间,获得该对象的一个指针,此时系统中存在了一个内核对象的数据实例,当创建成功后,ObCreateObject最后一个参数获得的是一个header->Body,此时我们知道,对于对象的其他数据是通过对象管理器来管理的,而且提供对外接口,当外部引用这个数据的时候,我们会增加引用计数和句柄计数,修改对象头内部数据。
插入对象ObInsertObject
当我们创建成功后,我们修改自己的对象内容,比如:
Timer->ApcAssociated = FALSE; Timer->WakeTimer = FALSE; Timer->WakeTimerListEntry.Flink = NULL;
设置完对象数据后,我们调用插入对象,这里一般是获得对象操作的句柄,还是以timer为例
/* Insert the Timer */ Status = ObInsertObject((PVOID)Timer, NULL, DesiredAccess, 0, NULL, &hTimer);
在函数中我们根据对象体Timer来获取对象头header,然后取出对象头中的createinfo,nameinfo, objecttype,objectname.
然后根据对象名在对象管理器中查找对象。
Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory, ObjectName, ObjectCreateInfo->Attributes, ObjectType, (ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ? KernelMode : UserMode, ObjectCreateInfo->ParseContext, ObjectCreateInfo->SecurityQos, Object, AccessState, &Context, &InsertObject);
当找到对象后,ObpCreateHandle来创建对象句柄。这种情况一般是向上层提供句柄,供上层使用。
创建对象类型
NTSTATUSNTAPIObCreateObjectType(IN PUNICODE_STRING TypeName, IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, IN PVOID Reserved, OUT POBJECT_TYPE *ObjectType);
我们现在对象管理器的类型目录中查找该对象类型,看是否已经存在该对象。如果存在我们返回,如果不存在,那么调用ObpAllocateObject申请对象
并设置header->Type = ObpTypeObjectType,设置成为一个类型对象。
对象目录
在系统启动时初始化对象类型目录,如下创建目录对象,一共创建三个基础目录L”\”,L”\KernelObjects”, L”\ObjectTypes”
NTSTATUSNTAPINtCreateDirectoryObject(OUT PHANDLE DirectoryHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
如下创建自己的根目录对象
/* Initialize Object Types directory attributes */ RtlInitUnicodeString(&Name, L"\\"); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, SePublicDefaultUnrestrictedSd); /* Create the directory */ Status = NtCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes); if (!NT_SUCCESS(Status)) return FALSE; /* Get a handle to it */ Status = ObReferenceObjectByHandle(Handle, 0, ObDirectoryType, KernelMode, (PVOID*)&ObpRootDirectoryObject, NULL); if (!NT_SUCCESS(Status)) return FALSE; /* Close the extra handle */ Status = NtClose(Handle); if (!NT_SUCCESS(Status)) return FALSE;
当我们要查找对象时,就指定在那个目录下查找,这个范围通过ObpRootDirectoryObject来指定。
自己创建的类型对象放置于 L”\ObjectTypes”中,新创建也会检索这个路径下是否已存在。而类型也是一个对象,创建起来没有和正常对象又太大的区别。
这个函数中,我们通过对象属性和访问标志,创建对象目录。内部调用ObCreateObject来创建对象,使用的参数是ObDirectoryType,来表示创建的是个目录对象。
当我们要创建新的对象类型时,要查找类型目录,看这个对象类型是否已存在。
在对象目录中查找对象
PVOIDNTAPIObpLookupEntryDirectory(IN POBJECT_DIRECTORY Directory, IN PUNICODE_STRING Name, IN ULONG Attributes, IN UCHAR SearchShadow, IN POBP_LOOKUP_CONTEXT Context)
上述函数用来在类型目录中查找已存在的类型。
这个函数中我们使用的是hash算法来查找的,我们找到对应的目录,然查看目录中是否有我们这个名字的对象,最终还是根据对象名来最终匹配是否是我们建立的对象类型。
向目录中插入对象
BOOLEANNTAPIObpInsertEntryDirectory(IN POBJECT_DIRECTORY Parent, IN POBP_LOOKUP_CONTEXT Context, IN POBJECT_HEADER ObjectHeader);
对象目录中每一项如下定义,函数中申请_OBJECT_DIRECTORY_ENTRY实例内存,填写内部信息,修改ChainLink链表,将新的对象挂入到制定的目录中。并设置ObjectHeader的内部信息,指向这个目录。
//// Object Directory Structures//typedef struct _OBJECT_DIRECTORY_ENTRY{ struct _OBJECT_DIRECTORY_ENTRY *ChainLink; PVOID Object;#if (NTDDI_VERSION >= NTDDI_WS03) ULONG HashValue;#endif} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;
如果我们要删除对象目录时,我们使用ObpDeleteEntryDirectory来删除目录,我们是找到指定的链表,然后断开链表,释放object_directory_entry所指向的空间。
浏览对象
Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory, ObjectName, ObjectCreateInfo->Attributes, ObjectType, (ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ? KernelMode : UserMode, ObjectCreateInfo->ParseContext, ObjectCreateInfo->SecurityQos, Object, AccessState, &Context, &InsertObject);it look up a name under only two circumstances:1. when a process creates a names object2. when a process opens a handle to a named object.
句柄的管理
句柄的创建
在进程创建的时候即PspCreateProcess,某一时刻调用ObinitProcess 来初始化进程关于对象处理方面的操作。这里一般是继承句柄表或者是创建进程的句柄表。
根据对象名打开对象
NTSTATUSNTAPIObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, IN PACCESS_STATE PassedAccessState, IN ACCESS_MASK DesiredAccess, IN OUT PVOID ParseContext, OUT PHANDLE Handle)
一般情况下,以thread操作为例,当我们打开某个线程时使用NtOpenThread函数,在这个函数的内部,检查属性判断是否按线程对象名打开线程,如果是,我们开始调用ObOpenObjectByName函数来处理我们这一操作。在ObOpenObjectByName中,开始我们进行参数检测和安全性检查,然后我们使用ObpLookupObjectName在对象根目录中查找该对象,当我们找到对象的时候,得到了该对象的指针,然后根据对象中是否有创建信息,来判断我们是创建句柄释放创建信息还是打开句柄。无论是创建还是打开,我们都使用ObpCreateHandle来获得对象对应的句柄。
NTSTATUSNTAPIObpCreateHandle(IN OB_OPEN_REASON OpenReason, IN PVOID Object, IN POBJECT_TYPE Type OPTIONAL, IN PACCESS_STATE AccessState, IN ULONG AdditionalReferences, IN ULONG HandleAttributes, IN POBP_LOOKUP_CONTEXT Context, IN KPROCESSOR_MODE AccessMode, OUT PVOID *ReturnedObject, OUT PHANDLE ReturnedHandle);
这个函数来处理对象和句柄的关系,并调用ExCreatehandle来实际创建句柄,首先我们获取创建进程的句柄表即PsGetCurrentProcess()->ObjectTable,并更根据参数属性设置句柄项的值,单例句柄数据结构如下,当我们找到了对象后,使用Object(指向对象体)来分析出内核对象头,然后将对象标记到句柄项_HANDLE_TABLE_ENTRY中,这个实例句柄就已经指向一个对象了。然后我们设置其他相关值,设置句柄的访问属性。当然在创建之前使用了ObpIncrementHandleCount来递增了该对象的句柄计数。我们稍后分析这个函数。首先我们分析一下如何创建的句柄。也就是ExCreateHandle函数。
typedef struct _HANDLE_TABLE_ENTRY{ union { PVOID Object; ULONG_PTR ObAttributes; PHANDLE_TABLE_ENTRY_INFO InfoTable; ULONG_PTR Value; }; union { ULONG GrantedAccess; struct { USHORT GrantedAccessIndex; USHORT CreatorBackTraceIndex; }; LONG NextFreeTableEntry; };} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
如下函数,返回一个句柄,而返回值typedef void *HANDLE; 由此可以看到在windows 32 位平台下,HANDLE 只不过是一个32位的指针,函数参数也是极其简单,在内核中也是少见的简单的两个参数的函数,一个是句柄表,这个从指定进程的EPROCESS中给出,另外一个是句柄表项,表示一个单例句柄。后期我们会分析关于进程句柄表的组织结构。
HANDLENTAPIExCreateHandle(IN PHANDLE_TABLE HandleTable, IN PHANDLE_TABLE_ENTRY HandleTableEntry)
在函数内部,我们根据句柄表使用ExpAllocateHandleTableEntry创建一个句柄表项,将参数中的表项复制给这个新创建的句柄项。
递增句柄引用计数(todo)
当我们创建句柄时,我们需要在对象上递增句柄的引用计数,
NTSTATUS
NTAPI
ObpIncrementHandleCount(IN PVOID Object,
IN PACCESS_STATE AccessState OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
IN ULONG HandleAttributes,
IN PEPROCESS Process,
IN OB_OPEN_REASON OpenReason)
对象的引用与释放
对象的释放
/* Check whether the object can now be deleted. */ OldCount = InterlockedDecrement(&Header->PointerCount);
首先递减指针计数,然后判断指针计数是否为零,如果是,查看是否当前可以进行apc,如果是则延迟删除对象,如果不是则直接删除对象。
删除对象
VOIDNTAPIObpDeleteObject(IN PVOID Object, IN BOOLEAN CalledFromWorkerThread);
函数中分别通过对象指针获取文件头,命名信息和创建信息。分别释放创建信息和命名信息,如果此对象又安全描述符回调函数和删除对象的回调函数,则调用之。最后我们释放对象体的空间。
根据指针引用对象
NTSTATUSNTAPIObReferenceObjectByPointer(IN PVOID Object, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode) /* Get the header */ Header = OBJECT_TO_OBJECT_HEADER(Object);
这里的一个参数是对象指针,实际上指向对象体,我们通过这个指针得到对象头并验证对象类型和访问方式。而且不能是链接对象。然后检查通过后,递增指针计数
/* Increment the reference count and return success */ InterlockedIncrement(&Header->PointerCount);
根据句柄引用对象 ObReferenceObjectByHandle
我们先检查一下该句柄是不是特殊句柄,如果这个句柄是当前进程句柄,那么使用
CurrentProcess = PsGetCurrentProcess(); *Object = CurrentProcess; 直接获取到了进程对象指针
如果是一个当前线程句柄 CurrentThread = PsGetCurrentThread(); *Object = CurrentThread; 然后增加进程和线程对象的引用计数。
否则如果是内核模式,我们使用内核句柄表,如果是用户模式,我们使用当前进程的句柄表。
然后将句柄在句柄表中查询,得到对应句柄项,然后将从句柄项中提取对象头,返回对象体,并递增对象头中的PointerCount。
- windows Object Manager
- [ZT]Inside WINDOWS NT Object Manager
- Inside WINDOWS NT Object Manager -- From xfocus
- object manager
- 15.Object Manager
- Windows Heap Manager
- windows qemu manager
- Credential manager of windows
- windows config manager
- windows message manager
- windows Heap manager
- windows handle manager
- Object Technology: A Manager's Guide
- Object-c 内存管理 (Memory Manager)
- c# windows小程序manager
- Windows对象(Object)结构
- Windows对象 (Object) 结构
- Windows对象 (Object) 结构
- 卸载oracle所有的安装东西
- 支付宝即时支付原理
- iOS开发 app内购In-App Purchase(二)
- 10个最好的 Node.js MVC 框架2016年7月下载排行
- Grand Central Dispatch (GCD) Reference
- windows Object Manager
- PHP抽象类与接口的区别
- Maven - 插件
- 欢迎使用CSDN-markdown编辑器
- docker学习6--容器搭建JDK/tomcat环境
- To Java程序员:切勿用普通for循环遍历LinkedList
- D-Link NAS, DNS 系列:通过非认证SMB实现存储型XSS
- java辅助开发的两个封装类
- [299] Bulls and Cows