对象的创建
依旧是针对定时器,定时器对象的创建是通过NtCreateTimer来的。
构成这个系统调用的三个步骤是
- 通过ObCreateObject创建目标对象
- 对具体对象做相应的本身的初始化
- 通过ObInsertObject将目标对象插入对象目录和句柄表,并返回句柄。
凡是创建对象的系统调用,都要提供至少两个输入参数。其中之一就是DesiredAccess,这个参数的含义是创建对象的访问模式,例如“只读”。另一个是ObjectAttributes,另一个是ObjectAttributes,这是一个OBJECT_ATTRIBUTES的结构指针。
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length; //sizeof(_OBJECT_ATTRIBUTES)
HANDLE RootDirectory; //目标对象所在的目录
PUNICODE_STRING ObjectName; //对象名 是一个UNICODE_STRING结构
ULONG Attributes; //对象属性
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
对象总是创建在某一个目录,这个目录对象自然首先被打开,这样通过进程与该目录对象建立一个连接,也就是说获取该目录的句柄,这里的字段RootDirectory就是这个目录节点的句柄。
另一个字段Attributes是一些表示各种属性的标志位
#define OBJ_INHERIT 0x00000002L //表示该对象可以遗传给子进程
#define OBJ_PERMANENT 0x00000010L //永久性对象
#define OBJ_EXCLUSIVE 0x00000020L //不允许(别的进程)同时打开 相当于一个Mute了
#define OBJ_CASE_INSENSITIVE 0x00000040L //对象名是否大小写敏感
#define OBJ_OPENIF 0x00000080L //如果对象已存在就打开
#define OBJ_OPENLINK 0x00000100L //允许打开符号链接
#define OBJ_KERNEL_HANDLE 0x00000200L //表示采用内核句柄表
#define OBJ_FORCE_ACCESS_CHECK 0x00000400L //来自用户空间
#define OBJ_VALID_ATTRIBUTES 0x000007F2L //有效的Attributes标志位
其中的有些信息会进入到对象头部ObjectHeader的Flag字段,只是标志位的定义不同。
例如OBJ_PERMANENT变成了OB_FLAG_PERMANENT,等等
ObCreateObject
三大步骤的第一步是创建对象,相应的调用是ObCreateObject
NTSTATUS
NTAPI
ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, //也就是PreviousMode
IN POBJECT_TYPE Type, //对象类型指针 表示要创建的对象类型
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, //对象属性
IN KPROCESSOR_MODE AccessMode, //PreviousMode
IN OUT PVOID ParseContext OPTIONAL,
IN ULONG ObjectSize, //所创建的对象的大小
IN ULONG PagedPoolCharge OPTIONAL, //可选择创建对象所用可置换页面的大小
IN ULONG NonPagedPoolCharge OPTIONAL, //可选择创建对象所用不可置换页面的大小
OUT PVOID *Object) //最后返回创建的对象被保存在这里
{
NTSTATUS Status;
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
UNICODE_STRING ObjectName;
POBJECT_HEADER Header;
/* Allocate a capture buffer */
ObjectCreateInfo = ObpAllocateCapturedAttributes(LookasideCreateInfoList); //分配一个OBJECT_CREATE_INFORMATION结构
if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
/* Capture all the info */
Status = ObpCaptureObjectAttributes(ObjectAttributes,//从ObjectAttributes获取要创建的对象的信息
ProbeMode,
FALSE,
ObjectCreateInfo,
&ObjectName);
if (NT_SUCCESS(Status)) //若成功
{
/* Validate attributes */
if (Type->TypeInfo.InvalidAttributes & ObjectCreateInfo->Attributes) //判断Attributes是否合法
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
else //检验的Attributes合法
{
/* Check if we have a paged charge */
if (!PagedPoolCharge) //若PagedPoolCharge不为空 添加到所创建对象的Type中
{
/* Save it */
PagedPoolCharge = Type->TypeInfo.DefaultPagedPoolCharge;
}
/* Check for nonpaged charge */
if (!NonPagedPoolCharge) //与上面类似
{
/* Save it */
NonPagedPoolCharge = Type->TypeInfo.DefaultNonPagedPoolCharge;
}
/* Write the pool charges */
ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
/* Allocate the Object */
Status = ObpAllocateObject(ObjectCreateInfo, //为目标对象分配一个空间
&ObjectName,
Type,
ObjectSize,
AccessMode,
&Header);
if (NT_SUCCESS(Status)) //若成功
{
/* Return the Object */
*Object = &Header->Body; //将对象的Body作为创建的对象返回
/* Check if this is a permanent object */
if (Header->Flags & OB_FLAG_PERMANENT) //若是创建的永久性对象
{
/* Do the privilege check */
if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
ProbeMode))
{
/* Fail */
ObpDeallocateObject(*Object);
Status = STATUS_PRIVILEGE_NOT_HELD;
}
}
/* Return status */
return Status;
}
}
/* Release the Capture Info, we don't need it */
ObpReleaseCapturedAttributes(ObjectCreateInfo); //失败了 则自然不需要ObjectCreateInfo了
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
}
/* We failed, so release the Buffer */
ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
return Status;
}
由OBJECT_ATTRIBUTES数据结构带下来的某些信息最后会进入OBJECT_HEADER和OBJECT_CREATE_INFOMATION数据结构,后者是对象头部的一个可选的组成部分。虽然是可选,但是对于一般对象这个结构实际上总是存在的,除非目标对象是对象类型。OBJECT_ATTRIBUTES结构中进入OBJECT_HEADER的信息是由OBJECT_CREATE_INFOMATION中转的。对象中的有些信息并非来自用户空间,也是需要OBJECT_CREATE_INFOMATION中转的。
- 所以先通过ObpAllocateCapturedAttributes分配一个OBJECT_CREATE_INFOMATION结构出来
- 然后由ObpCaptureObjectAttributes将OBJECT_ATTRIBUTES进行一个提取,转移到ObjectCreateInfo和ObjectName。除了对象名在ObjectName中,对象属性结构大部分信息会被转移到ObjectCreateInfo。
- 不过在分配对象结构之前还需要在此之前进行一次对于属性字段的合理性校验。对象类型结构中会定义创建该类型对象的时候说不允许的标志位,若跟我们想创建的对象属性有冲突,则是不允许创建的。另外在ObjectCreateInfo中会收集对于内存消耗的一些指标,包括PagedPoolCharge和NonPagedPoolCharge
- 顺利完成后,下面就可以通过ObpAllocateObject为目标对象分配数据结构了
- 成功分配后,Object就是Header的Body域,也就是具体对象的对象数据结构了,如果对象头中的Flags标志位即OB_FLAG_PERMANENT为1,则还要通过SeSinglePrivilegeCheck检测是否为系统的安全机制所允许。
ObpAllocateObject
NTSTATUS
NTAPI
ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, //创建者信息
IN PUNICODE_STRING ObjectName, //创建的对象名
IN POBJECT_TYPE ObjectType, //要创建的对象类型
IN ULONG ObjectSize, //分配的对象空间大小
IN KPROCESSOR_MODE PreviousMode,
IN POBJECT_HEADER *ObjectHeader)
{
POBJECT_HEADER Header;
ULONG QuotaSize, HandleSize, NameSize, CreatorSize;
POBJECT_HEADER_HANDLE_INFO HandleInfo;
POBJECT_HEADER_NAME_INFO NameInfo;
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
POBJECT_HEADER_QUOTA_INFO QuotaInfo;
POOL_TYPE PoolType;
ULONG FinalSize;
ULONG Tag;
PAGED_CODE(); //中断级别是低于DISPATCH_LEVEL的
/* Accounting */
ObpObjectsCreated++; //创建的对象数量加1
/* Check if we don't have an Object Type yet */
if (!ObjectType) //若未指定创建的对象类型,则对象类型指定为Type类型
{
/* Use default tag and non-paged pool */
PoolType = NonPagedPool;
Tag = TAG('O', 'b', 'j', 'T');
}
else
{
/* Use the pool and tag given */
PoolType =