一。对象管理第一次初始化(ObInitSystem) + 类型对象的创建(ObCreateObjectType)

本文详细介绍了Windows系统中对象管理器的初始化过程,包括对象类型的创建、句柄表的初始化及对象根目录的设置等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一。对象管理第一次初始化(ObInitSystem) + 类型对象的创建(ObCreateObjectType)
2010年05月09日 星期日 11:10
BOOLEAN ObInitSystem (VOID) 函数在系统初始化阶段被调用

它对对象管理器进行了初始化操作。这个函数创建了目录(Directory)对象类型、类型(Type)对象类型,并且建立了对象的根目录对象"/"
初始化完毕后,系统就可以通过对象管理器提供的函数操作对象了。

ObInitSystem 会在系统初始化时被调用两次,路径分别是
KiSystemStartup -> KiInitializeKernel -> ExpInitializeExecutive -> ObInitSystem 和
KiThreadStartup -> PspSystemThreadStartup -> Phase1Initialization -> ObInitSystem

这两次调用会走函数的两条不同分支, 函数中使用全局变量InitializationPhase来控制
BOOLEAN ObInitSystem (VOID) {
 .....
 if(InitializationPhase == 0) {
  //这里面是第一次初始化
 }
 if(InitializationPhase == 1) {
  //第二次初始化
 }
 return TRUE;
}

第一次调用时进行的操作 
1。 ObInitSystem初始化了两个LookasideList, ObpCreateInfoLookasideList用来存储OBJECT_CREATE_INFORMATION结构, ObpNameBufferLookasideList存储对象名
2。 使用 ObCreateObjectType 函数创建了 Type、Directory、SymbolicLink 类型对象
3。 为系统进程创建了句柄表 
BOOLEAN ObInitSystem (VOID) {
 .....
    if (InitializationPhase == 0) { 
  // 首先初始化两个缓冲区,来盛放以后可能会生成的OBJECT_CREATE_INFORMATION结构和对象名
        ExInitializeSystemLookasideList( &ObpCreateInfoLookasideList,
                                         NonPagedPool,
                                         sizeof(OBJECT_CREATE_INFORMATION),
                                         'iCbO',
                                         CreateInfoMaxDepth,
                                         &ExSystemLookasideListHead );

        ExInitializeSystemLookasideList( &ObpNameBufferLookasideList,
                                         PagedPool,
                                         OBJECT_NAME_BUFFER_SIZE,
                                         'mNbO',
                                         NameBufferMaxDepth,
                                         &ExSystemLookasideListHead );

  // 把两个LookasideList记录在初始化CPU的KPRCB结构中 
        Prcb = KeGetCurrentPrcb();
        Prcb->PPLookasideList[LookasideCreateInfoList].L = &ObpCreateInfoLookasideList;
        Prcb->PPLookasideList[LookasideCreateInfoList].P = &ObpCreateInfoLookasideList;
        Prcb->PPLookasideList[LookasideNameBufferList].L = &ObpNameBufferLookasideList;
        Prcb->PPLookasideList[LookasideNameBufferList].P = &ObpNameBufferLookasideList;

  // 初始化一些同步和权限检查用到的数据
        ObpRemoveObjectList = NULL;
        ObpInitSecurityDescriptorCache();
        KeInitializeEvent( &ObpDefaultObject, NotificationEvent, TRUE );
        ExInitializePushLock( &ObpLock );
        PsGetCurrentProcess()->GrantedAccess = PROCESS_ALL_ACCESS;
        PsGetCurrentThread()->GrantedAccess = THREAD_ALL_ACCESS;
        KeInitializeGuardedMutex( &ObpDeviceMapLock );

  // 初始化系统配额。不影响Ob管理的理解,这里略过了
        PsInitializeQuotaSystem ();

  // 初始化系统进程的句柄表,
        ObpKernelHandleTable = PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable( NULL );

  // 删除对象时要用到WorkItem派遣到系统线程里进行, 对ObpRemoveObjectWorkItem进行初始化
  // 删除对象用到的回调函数是 ObpProcessRemoveObjectQueue
        ExInitializeWorkItem( &ObpRemoveObjectWorkItem,
                              ObpProcessRemoveObjectQueue,
                              NULL );

  // 创建Type对象类型
        RtlZeroMemory( &ObjectTypeInitializer, sizeof( ObjectTypeInitializer ) );
        ObjectTypeInitializer.Length = sizeof( ObjectTypeInitializer );
        ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
        ObjectTypeInitializer.PoolType = NonPagedPool;

        RtlInitUnicodeString( &TypeTypeName, L"Type" );
        ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
        ObjectTypeInitializer.GenericMapping = ObpTypeMapping;
        ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_TYPE );
        ObjectTypeInitializer.MaintainTypeList = TRUE;
        ObjectTypeInitializer.UseDefaultObject = TRUE;
        ObjectTypeInitializer.DeleteProcedure = &ObpDeleteObjectType;
        ObCreateObjectType( &TypeTypeName,
                            &ObjectTypeInitializer,
                            (PSECURITY_DESCRIPTOR)NULL,
                            &ObpTypeObjectType );

  // 创建Directory对象类型
        ObjectTypeInitializer.PoolType = OB_NAMESPACE_POOL_TYPE;

        RtlInitUnicodeString( &DirectoryTypeName, L"Directory" );
        ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_DIRECTORY );
        ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS;
        ObjectTypeInitializer.CaseInsensitive = TRUE;
        ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping;
        ObjectTypeInitializer.UseDefaultObject = TRUE;
        ObjectTypeInitializer.MaintainTypeList = FALSE;
        ObjectTypeInitializer.DeleteProcedure = NULL;
        ObCreateObjectType( &DirectoryTypeName,
                            &ObjectTypeInitializer,
                            (PSECURITY_DESCRIPTOR)NULL,
                            &ObpDirectoryObjectType );
        
  // 清除目录对象的Synchronize权限
        ObpDirectoryObjectType->TypeInfo.ValidAccessMask &= ~SYNCHRONIZE;

  // 创建SymbolicLink对象类型
        RtlInitUnicodeString( &SymbolicLinkTypeName, L"SymbolicLink" );
        ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof( OBJECT_SYMBOLIC_LINK );
        ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS;
        ObjectTypeInitializer.CaseInsensitive = TRUE;
        ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping;
        ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink;
        ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink;
        ObCreateObjectType( &SymbolicLinkTypeName,
                            &ObjectTypeInitializer,
                            (PSECURITY_DESCRIPTOR)NULL,
                            &ObpSymbolicLinkObjectType );

        ObpSymbolicLinkObjectType->TypeInfo.ValidAccessMask &= ~SYNCHRONIZE;

  // 之后是和Cache有关的, 略过了

    } // 第一次初始化结束

 if(InitializationPhase == 1) {
  //第二次初始化
 }
 return TRUE;
}

windows运行过程中会创建许多对象实例。系统把功能相似的对象分成了不同的类型,每个对象都对应唯一一种对象类型,如目录对象(Directory)、设备对象(Device)、驱动对象(Driver)等等。
所有对象实例中都有一个指针指向一个表示它的对象类型的数据结构。同时这些对象类型本身也是一类对象——类型对象(Type)。也就是说Directory对象的类型是Type, 同时Type对象的类型是Type对象本身。Type类型是自描述的。
不知道说清楚了没有…………
上面的 ObCreateObjectType 函数就用于创建一个对象类型(Directory、SymbolicLink、Type类型)。

NTSTATUS ObCreateObjectType (
 __in PUNICODE_STRING TypeName,       // 类型的名称
    __in POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, // 这个结构里包含了若干重要的信息, 解析函数、删除函数、默认权限等等
    __in_opt PSECURITY_DESCRIPTOR SecurityDescriptor,  // 不管它....
    __out POBJECT_TYPE *ObjectType       // 创建后的类型对象通过这个参数传递给调用者
    ) {
 ......
 //参数合法性检测
 ......
 
 // 类型名中不能包含 “/” 字符
 s = TypeName->Buffer;
    i = TypeName->Length / sizeof( WCHAR );
    while (i--) {

        if (*s++ == OBJ_NAME_PATH_SEPARATOR) {

            return( STATUS_OBJECT_NAME_INVALID );
        }
    }
 
 // 所有的类型对象都存在与 /ObjectTypes 目录下。查询这个目录下是否有当前名字的类型, 如果存在就出错。
 // 注意,第一次初始化时,在这里根目录对象ObpTypeDirectoryObject还没有建立,所以不会进入这个if
    ObpInitializeLookupContext( &LookupContext );
    if (ObpTypeDirectoryObject) {
        ObpLockLookupContext( &LookupContext, ObpTypeDirectoryObject);
        if (ObpLookupDirectoryEntry( ObpTypeDirectoryObject,
                                     TypeName,
                                     OBJ_CASE_INSENSITIVE,
                                     FALSE,
                                     &LookupContext )) {
            ObpReleaseLookupContext( &LookupContext );
            return( STATUS_OBJECT_NAME_COLLISION );
        }
    }
 
 // 为类型名称生成一个空间并复制进去
    ObjectName.Buffer = ExAllocatePoolWithTag( PagedPool,
                                               (ULONG)TypeName->MaximumLength,
                                               'mNbO' );
    if (ObjectName.Buffer == NULL) {
        ObpReleaseLookupContext( &LookupContext );
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    ObjectName.MaximumLength = TypeName->MaximumLength;
    RtlCopyUnicodeString( &ObjectName, TypeName );
 
 // 生成对象体, 这个函数后面会详谈。NewObjectTypeHeader是对象头指针。
    Status = ObpAllocateObject( NULL,
                                KernelMode,
                                ObpTypeObjectType,
                                &ObjectName,
                                sizeof( OBJECT_TYPE ),
                                &NewObjectTypeHeader );

    if (!NT_SUCCESS( Status )) {
  .........
    }
 
 // 初始化对象头的Flag域, 
 // TotalNumberOfObjects、TotalNumberOfHandles、HighWaterNumberOfObjects、HighWaterNumberOfHandles 为0
 // Name指向类型对象名
 NewObjectTypeHeader->Flags |= OB_FLAG_KERNEL_OBJECT |
                                  OB_FLAG_PERMANENT_OBJECT;
    NewObjectType = (POBJECT_TYPE)&NewObjectTypeHeader->Body;
    NewObjectType->Name = ObjectName;
    RtlZeroMemory( &NewObjectType->TotalNumberOfObjects,
                   FIELD_OFFSET( OBJECT_TYPE, TypeInfo ) -
                   FIELD_OFFSET( OBJECT_TYPE, TotalNumberOfObjects ));
 
 // 正如ObInitSystem函数中描述的一样 ObCreateObjectType 是可以创建Type类型对象本身的
 // Type对象的对象类型应该指向Type本身, 若是创建Type本身, 则现在他的NewObjectTypeHeader->Type应该指向NULL
 // 这里修正了这种情况
 if (!ObpTypeObjectType) {
  ObpTypeObjectType = NewObjectType;
        NewObjectTypeHeader->Type = ObpTypeObjectType;
        NewObjectType->TotalNumberOfObjects = 1;
    }
 
 // 又继续初始化TypeObject->TypeInfo域, 这个域是传入的ObjectTypeInitializer的复制, 并且记录了对象使用的内存大小
 // TypeInfo包含了众多函数(如解析路径等), 在以后会提到
 NewObjectType->TypeInfo = *ObjectTypeInitializer;
    NewObjectType->TypeInfo.PoolType = PoolType;
    if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST) {
        NewObjectType->TypeInfo.MaintainTypeList = TRUE;
    }
    StandardHeaderCharge = sizeof( OBJECT_HEADER ) +
                           sizeof( OBJECT_HEADER_NAME_INFO ) +
                           (ObjectTypeInitializer->MaintainHandleCount ?
                                sizeof( OBJECT_HEADER_HANDLE_INFO )
                              : 0 );
    if ( PoolType == NonPagedPool ) {
        NewObjectType->TypeInfo.DefaultNonPagedPoolCharge += StandardHeaderCharge;
    } else {
        NewObjectType->TypeInfo.DefaultPagedPoolCharge += StandardHeaderCharge;
    }
 if (ObjectTypeInitializer->SecurityProcedure == NULL) {
        NewObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod;
    }
 
 // Type对象中包含一个TypeList列表, 记录了所有是此类型的对象。这里初始化列表和同步数据结构
 ExInitializeResourceLite( &NewObjectType->Mutex );
    for (i = 0; i < OBJECT_LOCK_COUNT; i++) {
        ExInitializeResourceLite( &NewObjectType->ObjectLocks[i] );
    }
    InitializeListHead( &NewObjectType->TypeList );
 

 // DefaultObject和同步有关, 以后再关注
    if (NewObjectType->TypeInfo.UseDefaultObject) {
        NewObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
        NewObjectType->DefaultObject = &ObpDefaultObject;
    } else if (ObjectName.Length == 8 && !wcscmp( ObjectName.Buffer, L"File" )) {
        NewObjectType->DefaultObject = ULongToPtr( FIELD_OFFSET( FILE_OBJECT, Event ) );
    } else if ( ObjectName.Length == 24 && !wcscmp( ObjectName.Buffer, L"WaitablePort")) {

        NewObjectType->DefaultObject = ULongToPtr( FIELD_OFFSET( LPCP_PORT_OBJECT, WaitEvent ) );
    } else {
        NewObjectType->DefaultObject = NULL;
    }
 

 // OBJECT_HEADER_TO_CREATOR_INFO 函数中ObjectHeader->Flags & OB_FLAG_CREATOR_INFO是否为0
 // 不为0则ObjectHeader上面为OBJECT_HEADER_CREATOR_INFO结构, OBJECT_HEADER_CREATOR_INFO中的TypeList连入ObpTypeObjectType->TypeList
    ObpEnterObjectTypeMutex( ObpTypeObjectType );
    CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO( NewObjectTypeHeader );
    if (CreatorInfo != NULL) {
        InsertTailList( &ObpTypeObjectType->TypeList, &CreatorInfo->TypeList );
    }
 
 // 全局有一个叫ObpObjectTypes的数组, 存储了所有的类型对象。当前类型的Index域是当前类型数组下标+1
 NewObjectType->Index = ObpTypeObjectType->TotalNumberOfObjects;
    if (NewObjectType->Index < OBP_MAX_DEFINED_OBJECT_TYPES) {
        ObpObjectTypes[ NewObjectType->Index - 1 ] = NewObjectType;
    }
 
 ObpLeaveObjectTypeMutex( ObpTypeObjectType );
 
 // 如果已经存在Directory类型, 用ObpInsertDirectoryEntry函数把当前创建的类型插入/ObjectTypes目录
 // 根据第一次调用 ObInitSystem 函数初始化类型对象的顺序,Type类型对象时不会在这个目录中的。
 // 在第二次初始化之前, 找到它的方法就是通过全局的ObpTypeObjectType变量, 或者ObpObjectTypes数组的第0项
 if (!ObpTypeDirectoryObject ||
  ObpInsertDirectoryEntry( ObpTypeDirectoryObject, &LookupContext, NewObjectTypeHeader )) {
        if (ObpTypeDirectoryObject) {
            ObReferenceObject( ObpTypeDirectoryObject );
        }
        ObpReleaseLookupContext( &LookupContext );
        *ObjectType = NewObjectType;
        return( STATUS_SUCCESS );
    } else {
        ObpReleaseLookupContext( &LookupContext );
        return( STATUS_INSUFFICIENT_RESOURCES );
    }
}

简单总结一下ObCreateObjectType。
所有类型对象都在 /ObjectTypes目录里, 使用ObpLookupDirectoryEntry可以查询这个目录, 若名字有冲突就出错。
ObpAllocateObject建立对象体和对象头, 这个函数以后再看。
ObCreateObjectType函数处理了Directory和Type对象没有建立好时的情况。
对象头结构是
kd> dt _OBJECT_HEADER
nt!_OBJECT_HEADER
   +0x000 PointerCount     : Int4B
   +0x004 HandleCount      : Int4B
   +0x008 Type             : Ptr32 _OBJECT_TYPE  这个域指向当前对象的类型, 对于类型对象它指向Type类型对象, Type对象指向Type对象本身, ObCreateObjectType函数处理了这种情况
   +0x004 NextToFree       : Ptr32 Void
   +0x00c NameInfoOffset   : UChar
   +0x00d HandleInfoOffset : UChar
   +0x00e QuotaInfoOffset  : UChar
   +0x00f Flags            : UChar 有OB_FLAG_CREATOR_INFO标志说明紧挨着OBJECT_HEADER上面就是OBJECT_HEADER_CREATOR_INFO结构
   +0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : Ptr32 Void
   +0x014 SecurityDescriptor : Ptr32 Void
   +0x018 Body             : _QUAD

Type对象体结构是
kd> dt _OBJECT_TYPE
nt!_OBJECT_TYPE
   +0x000 Mutex            : _ERESOURCE 
   +0x038 TypeList         : _LIST_ENTRY  记录这个类型的所有对象、连入对象实例对应的OBJECT_HEADER_CREATOR_INFO结构
   +0x040 Name             : _UNICODE_STRING 对象名称(Directory、Type、SymbolicLink等)
   +0x048 DefaultObject    : Ptr32 Void   用于同步
   +0x04c Index            : Uint4B    Index - 1 当做ObpObjectTypes的下标找到自身, 这个数组中记录了所有的Type结构指针
   +0x050 TotalNumberOfObjects : Uint4B
   +0x054 TotalNumberOfHandles : Uint4B
   +0x058 HighWaterNumberOfObjects : Uint4B
   +0x05c HighWaterNumberOfHandles : Uint4B
   +0x060 TypeInfo         : _OBJECT_TYPE_INITIALIZER  这个结构记录了众多相关函数路径(如解析等)
   +0x0ac Key              : Uint4B
   +0x0b0 ObjectLocks      : [4] _ERESOURCE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值