zoukankan      html  css  js  c++  java
  • Windows内核源码分析 1.初始化内核与执行体子系统

    本文结构:
    一、内核初始化
    1.1  系统启动过程简介
    1.2  内核初始化
    二、源码分析
    2.1 内核初始化KiInitializeKernel
    2.2 初始化内核数据结构KiInitSystem
    2.3 [phase0]Ntoskrnl初始化ExpInitializeExecutive
    2.4 [phase0]初始化进程管理器PsInitPhase0
    2.5 [phase1]Ntoskrnl初始化Phase1Initialiation

    ==========================================================
    一、内核初始化
    1.1  系统启动过程简介
          对于系统启动过程,已经有太多的资料介绍过了。这里只是稍作温习,为介绍后续内容做准备。这部分的内容参考了http://www.yesky.com/317/1711317.shtml。
    系统的启动过程一般分为5个步骤:
    (1)预引导过程
      [1] 计算机加电自检,同时完成硬件设备的枚举和配置。
      [2] BIOS确定引导设备位置,加载引导设备的MBR。
      [3] 在MBR中扫描分区表,定位活动分区,并加载活动分区上引导扇区到内存
      [4] 加载系统根目录的ntldr。 
    (2)引导过程
      [5] 初始化Ntldr,完成处理器模式切换和文件系统驱动的加载,如果使用SCSI设备,
    Ntldr将Ntbootdd.sys加载到内存。
      [6] Ntldr读取系统根目录的boot.ini
    ,在屏幕显示系统启动菜单,等待用户选择所需要加载的操作系统。
      [7] Ntldr读取并运行程序Ntdetect.com,完成硬件的检测。
      [8] Ntldr根据用户的选择调用系统的硬件配置文件。 
    (3)内核加载,在[8]后清除屏幕,显示进度条。
      [9] 加载执行体ntoskrnl.exe
      [10] 加载Hal.dll
      [11] 加载%systemroot\System32\Config\System下的注册表项HKEY_LOCAL_MACHINE\
    SYSTEM。
      [12] 选择加载控制集,初始化计算机。
      [13] 根据控制集加载低级硬件设备驱动程序。 
    (4)内核初始化,显示图形界面。
      [14] 内核会使用检测到的硬件数据,在注册表中创建HKEY_LOCAL_MACHINE\HARDWA项。
      [15] 其次的工作是内核通过复制HKEY_LOCAL_MACHINE\SYSTEM\Select子键Current
    项引用的控制集创建Clone控制集。
      [16] 内核开始进一步加载和初始化设备驱动程序。
      [17] Session Manager(Smss.exe)按顺序启动Windows 2000
    更高一层次的子系统和各项服务。 
    (5)系统登陆过程
      [18] 系统首先启动Winlogon.exe。
      [19] 启动Local Security Authority(Lsass.exe)
       [20] 屏幕显示出登陆对话框。
      [21] 系统执行Service Controller(Screg.exe)再次扫描注册表HKEY_LOCAL_MACHINE\
    SYSTEM\CurrentControlSet\Control项并自动加载其中系统的或用户的服务。
      [22] 此时,用户已成功的登陆到了Windows 2000系统,系统随后把Clone控制集拷贝到
    LastKnownGood控制集。

    1.2  内核初始化
         本文所要介绍的重点是ntoskrnl的初始化流程。这个初始化过程大致分为两个阶段:phase0和phase1。对于具体所处的阶段是由一 个全局变量InitializationPhase来标识,当InitializationPhase为0时表示处于phase0,当 InitializationPhase为1时表示处于phase1。
        Ntoskrnl在入口函数中调用KiSystemStartup,而KiSystemStartup又依次为每个CPU调用 HalInitializeProcessor和KiInitializeKernel。如果KiInitializeKernel运行在引导CPU上, 则会调用KiInitSystem执行系统范围全局的内核初始化。然后KiInitializeKernel调用 ExpInitializeExecutive函数,负责实现phase0阶段的初始化工作。
        (注:引导CPU,即0号CPU,每个CPU都以整数标识,0号CPU是第一个被初始化的CPU。当初始化第1个CPU时需要进行额外的操作,因而称之为引导CPU)
        在phase0阶段的初始化过程中首先调用HalInitSystem初始化HAL,然后依次初始化内存管理器、对象管理器、安全引用监视器、进 程管理器和即插即用管理器。其中在调用PsInitSystem执行进程管理器在phase0阶段初始化时,创建了一个新的系统线程即为 Phase1Initialization,用于执行phase1阶段的初始化。由于此时并不允许中断,Phase1Initialization线程并 不立即执行。当完成phase0阶段初始化并返回到KiInitializeKernel时,设置IRQL到DISPATCH_LEVEL并使CPU调度 Phase1Initialization线程,从而进行phase1阶段的初始化。

    关于内核初始化流程可以用下图表示,从上到下表示时间顺序:

    图示说明:
    [1] 关于KiInitializeKernel的具体实现参见2.1小节。
    [2] 关于KiInitSystem的具体实现参见2.2小节
    [3] 关于phase0阶段ExpInitializeExecutive的具体实现参见2.3小节。
    [4] 关于phase0阶段进程管理器初始化(PsInitSystem)的具体实现参见2.4小节。
    [5] 关于Phase1Initialization线程实现phase1阶段初始化的具体过程参见2.5小节。

    二、源码分析
    2.1  内核初始化KiInitializeKernel
          这个函数在系统由bootstrapped启动后且系统未被初始化之前取得控制权。当新的处理器加入时,调用这个例程可以初始化处理器相关的数据结构。主要功能是:
    (1)初始化内核数据结构
    (2)初始化处理控制块(Processor Control Block)
    (3)调用内核执行体初始化例程
    (4)最后返回系统启动例程(KiSystemStartup)   
          下面就是KiInitializeKernel的执行流程:

    代码:

    VOID KiInitializeKernel (

              IN PKPROCESS Process,

              IN PKTHREAD Thread,

              IN PVOID IdleStack,      // IDLE线程的内核堆栈基地址

              IN PKPRCB Prcb,      // 指向处理器控制块结构

              IN CCHAR Number,      // 指定当前正在初始化的处理器索引号

              PLOADER_PARAMETER_BLOCK LoaderBlock

              )

    {

      // 初始化Prcb的部分成员

      // ……

     

      // 在系统初始化过程(KiSystemStartup)会枚举所有CPU,

      // 然后循环调用KiInitializeKernel依次初始化每个CPU

      // 在初始化号CPU时,会初始化一部分内核数据结构

      if (Number == 0) {

     

        // 初始化处理器相关的全局信息

        // 例如KeI386NpxPresent,KeI386CpuType,KeI386CpuStep,KeI386FxsrPresent等

        // ……

     

        // 初始化体系无关的内核数据结构

        KiInitSystem();

     

        // 初始化idle线程的进程对象

        KeInitializeProcess(Process,…… );

      } 

      else

      {

        // ……

      }

     

      // ……

     

      // 初始化线程对象

      KeInitializeThread(Thread, (PVOID)((ULONG)IdleStack),

        (PKSYSTEM_ROUTINE)NULL, (PKSTART_ROUTINE)NULL,

        (PVOID)NULL, (PCONTEXT)NULL, (PVOID)NULL, Process);

     

      // ……

     

      // 调用内核执行体的初始化例程

      try {

        ExpInitializeExecutive(Number, LoaderBlock);

      } except (EXCEPTION_EXECUTE_HANDLER) {

        KeBugCheck (PHASE0_EXCEPTION);

      }

     

      // ……

     

      // 如果是启动CPU(0号),动态分配内核堆栈空间和K的IOPM存储区域

      if (Number == 0) {

        PVOID DpcStack = MmCreateKernelStack(FALSE);

        if (DpcStack == NULL) {

          KeBugCheckEx(NO_PAGES_AVAILABLE, 1, 0, 0, 0);

        }

        Prcb->DpcStack = DpcStack;

     

        // 分配K的IOPM存储区域,用于BiosCall交换

        Ki386IopmSaveArea = ExAllocatePoolWithTag(PagedPool,PAGE_SIZE * 2,'  eK');

        if (Ki386IopmSaveArea == NULL) {

          KeBugCheckEx(NO_PAGES_AVAILABLE, 2, PAGE_SIZE * 2, 0, 0);

        }

      }

      

        // 设置IRQL为DISPATCH_LEVEL级别,允许线程派发

        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);

     

        // 设置当前线程优先级为0,这样才能调度Phase1Initialization线程

        KeSetPriorityThread(Thread, (KPRIORITY)0);

     

        // 检测是否存在就绪线程,如果不存在则把当前CPU添加到KiIdleSummary

        KiAcquireQueuedSpinLock(KiQueuedSpinLockContext(LockQueueDispatcherLock));

        if (Prcb->NextThread == (PKTHREAD)NULL) {

            SetMember(Number, KiIdleSummary);

        }

        KiReleaseQueuedSpinLock(KiQueuedSpinLockContext(LockQueueDispatcherLock));

     

        // 提升IRQL到HIGH_LEVEL,屏蔽中断

    KeRaiseIrql(HIGH_LEVEL, &OldIrql);

     

      return;

    }

    这里有3个关键处:
    (1)当初始化0号CPU时调用KiInitSystem用于初始化内核数据结构。
    (2)调用执行体初始化例程ExpInitializeExecutive。
    (3)在调用ExpInitializeExecutive返回后,首先设置IRQL为DISPATCH_LEVEL
    级别,允许线程派发,然后设置当前线程优先级为0,表明当前线程放弃下一个时间片,使得CPU可以执行Phase1Initialization线程,最后提升IRQL为HIGH_LEVEL,屏蔽系统中断,保证phase1阶段的初始化不可中断。

    2.2  初始化内核数据结构KiInitSystem
    KiInitSystem
    初始化了一些比较重要也比较常见的内核数据结构,这些数据结构中大量地使用了
    LIST_ENTRY结构。如下所示:

    代码:

    VOID KiInitSystem (VOID)

    {

      ULONG Index;

     

      // 初始化调度队列链表头,每一个优先级都有一个独立的进程链表

      for (Index = 0; Index < MAXIMUM_PRIORITY; Index += 1) {

        InitializeListHead(&KiDispatcherReadyListHead[Index]);

      }

     

      // 初始化BugCheck回调函数链表,及其旋转锁

      InitializeListHead(&KeBugCheckCallbackListHead);

      KeInitializeSpinLock(&KeBugCheckCallbackLock);

     

      // 初始化定时器过期的DPC对象

      KeInitializeDpc(&KiTimerExpireDpc,

        (PKDEFERRED_ROUTINE)KiTimerExpiration, NIL);

     

      // 初始化profile链表,及其旋转锁

      KeInitializeSpinLock(&KiProfileLock);

      InitializeListHead(&KiProfileListHead);

     

      // 初始化当前活动的profile链表

      InitializeListHead(&KiProfileSourceListHead);

     

      // 初始化定时器链表

      for (Index = 0; Index < TIMER_TABLE_SIZE; Index += 1) {

        InitializeListHead(&KiTimerTableListHead[Index]);

      }

     

      // 初始化swap通知事件

      KeInitializeEvent(&KiSwapEvent,SynchronizationEvent,FALSE);

     

      InitializeListHead(&KiProcessInSwapListHead);

      InitializeListHead(&KiProcessOutSwapListHead);

      InitializeListHead(&KiStackInSwapListHead);

      InitializeListHead(&KiWaitInListHead);

      InitializeListHead(&KiWaitOutListHead);

     

      // 初始化SSDT

      KeServiceDescriptorTable[0].Base = &KiServiceTable[0];

      KeServiceDescriptorTable[0].Count = NULL;

      KeServiceDescriptorTable[0].Limit = KiServiceLimit;

    #if defined(_IA64_)

      KeServiceDescriptorTable[0].TableBaseGpOffset =

        (LONG)(*(KiServiceTable-1) - (ULONG_PTR)KiServiceTable);

    #endif

      KeServiceDescriptorTable[0].Number = &KiArgumentTable[0];

      for (Index = 1; Index < NUMBER_SERVICE_TABLES; Index += 1) {

        KeServiceDescriptorTable[Index].Limit = 0;

      }

     

      // 拷贝SSDT到Shadow服务表

      RtlCopyMemory(KeServiceDescriptorTableShadow,

        KeServiceDescriptorTable,

        sizeof(KeServiceDescriptorTable));

     

      // ……

      return;

    }

    2.3  [phase0]Ntoskrnl初始化ExpInitializeExecutive
    ExpInitializeExecutive函数负责阶段0(phase 0)的所有其他初始化工作。
    ExpInitializeExecutive首先调用HalInitSystem初始化HAL,其中一个功能是为每个CPU
    准备系统中断控制器。接下来,依次执行执行体的5个组件在phase 0
    的初始化工作,如下:
    (1)调用MmInitSystem,初始化内存管理器。
    (2)调用ObInitSystem,初始化对象管理器。
    (3)调用SeInitSystem,初始化安全引用监视器。
    (4)调用PsInitSystem,初始化进程管理器。
    (5)调用PpInitSystem,初始化即插即用管理器。
    这5个调用中MmInitSystem和ObInitSystem
    复杂,剩余的三个步骤都具有相似的结构,如下:

    代码:

    BOOLEAN SeInitSystem( VOID )

    {

        switch ( InitializationPhase ) {

        case 0 :        return SepInitializationPhase0();

        case 1 :        return SepInitializationPhase1();

        default:        KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);

        }

        return 0;

    }

    BOOLEAN PsInitSystem ( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock )

    {

        switch ( InitializationPhase ) {

        case 0 :        return PspInitPhase0(LoaderBlock);

        case 1 :        return PspInitPhase1(LoaderBlock);

        default:        KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);

        }

        return 0;

    }

    BOOLEAN PpInitSystem ( VOID )

    {

        switch ( InitializationPhase ) {

        case 0 :        return PiInitPhase0();

        case 1 :        return PiInitPhase1();

        default:        KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);

        }

    }

    共同点是根据InitializationPhase所指定的phase完成特定的初始化工作,其中
    InitializationPhase是个全局变量,可以设置为0、1、2,设置为0表示进行phase0
    初始化,设置为1表示进行phase1初始化,成功初始化内核后则设置为2。
    ExpInitializeExecutive的具体实现如下:

    代码:

    VOID ExpInitializeExecutive(

      IN ULONG Number,            // CPU索引号

      IN PLOADER_PARAMETER_BLOCK LoaderBlock  // loader parameter block

    )

    {

      NTSTATUS Status;

      PLDR_DATA_TABLE_ENTRY DataTableEntry;

      PMESSAGE_RESOURCE_ENTRY MessageEntry;

      PLIST_ENTRY NextEntry;

      ANSI_STRING AnsiString;

      STRING NameString;

      CHAR Buffer[ 256 ];

      CHAR VersionBuffer[ 64 ];

      PCHAR s, sMajor, sMinor;

      ULONG ImageCount, i;

      BOOLEAN IncludeType[LoaderMaximum];  // 标识特定类型的内存是否存在

      ULONG MemoryAlloc[(sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +

        sizeof(PHYSICAL_MEMORY_RUN)*MAX_PHYSICAL_MEMORY_FRAGMENTS) /

        sizeof(ULONG)];

      PPHYSICAL_MEMORY_DESCRIPTOR Memory;// 物理内存描述符

      ULONG   ResourceIdPath[3];  

      PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;

      PIMAGE_NT_HEADERS NtHeaders;

      PMESSAGE_RESOURCE_DATA  MessageData;

     

      if (Number == 0) {

        InitializationPhase = 0L;    // 设置为phase 0

     

        // 计算物理内存块

        Memory = (PPHYSICAL_MEMORY_DESCRIPTOR)&MemoryAlloc;

        Memory->NumberOfRuns = MAX_PHYSICAL_MEMORY_FRAGMENTS;

     

        // 包含除LoaderBad等3种外的所有内存类型

        for (i=0; i < LoaderMaximum; i++) {

          IncludeType[i] = TRUE;

        }

        IncludeType[LoaderBad] = FALSE;

        IncludeType[LoaderFirmwarePermanent] = FALSE;

        IncludeType[LoaderSpecialMemory] = FALSE;

     

        MmInitializeMemoryLimits(LoaderBlock, IncludeType, Memory);

     

        InitNlsTableBase = LoaderBlock->NlsData->AnsiCodePageData;

        InitAnsiCodePageDataOffset = 0;

        InitOemCodePageDataOffset = ((PUCHAR)LoaderBlock->NlsData->OemCodePageData 

    - (PUCHAR)LoaderBlock->NlsData->AnsiCodePageData);

        InitUnicodeCaseTableDataOffset = ((PUCHAR)LoaderBlock->NlsData->

    UnicodeCaseTableData - (PUCHAR)LoaderBlock->NlsData->AnsiCodePageData);

     

        RtlInitNlsTables(

          (PVOID)((PUCHAR)InitNlsTableBase+InitAnsiCodePageDataOffset),

          (PVOID)((PUCHAR)InitNlsTableBase+InitOemCodePageDataOffset),

          (PVOID)((PUCHAR)InitNlsTableBase+InitUnicodeCaseTableDataOffset),

          &InitTableInfo

          );

     

        RtlResetRtlTranslations(&InitTableInfo);

     

        // 初始化HAL(Hardware Architecture Layer)

        if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {

          KeBugCheck(HAL_INITIALIZATION_FAILED);

        }

     

    #if i386

        // 允许中断

        KiRestoreInterrupts (TRUE);

    #endif

        // ……

     

        // LoadOrderListHead的第一结点必定是内核模块(例如ntoskrnl.exe)

        DataTableEntry = CONTAINING_RECORD(

          LoaderBlock->LoadOrderListHead.Flink,

          LDR_DATA_TABLE_ENTRY,

          InLoadOrderLinks);

     

        ResourceIdPath[0] = 11;

        ResourceIdPath[1] = 1;

        ResourceIdPath[2] = 0;

     

        // 寻找BugCheck消息资源,并设置到KiBugCodeMessages

        // LdrFindResource_U在指定DLL中定位指定ID的资源

        Status = LdrFindResource_U(

          DataTableEntry->DllBase,    // DLL模块基地址

          ResourceIdPath,        // 资源ID数组

          3,              // 资源ID数组长度

          (VOID *) &ResourceDataEntry);  // 指向IMAGE_RESOURCE_DATA_ENTRY结构

        if (NT_SUCCESS(Status)) {

          Status = LdrAccessResource(

            DataTableEntry->DllBase,

            ResourceDataEntry,

            &MessageData,

            NULL);

     

          if (NT_SUCCESS(Status)) {

            KiBugCodeMessages = MessageData;

          }

        }

     

        // 遍历已加载的模块列表,并加载符号文件

        ImageCount = 0;

        NextEntry = LoaderBlock->LoadOrderListHead.Flink;

        while (NextEntry != &LoaderBlock->LoadOrderListHead) {

          // 获取LDR_DATA_TABLE_ENTRY结构指针

          DataTableEntry = CONTAINING_RECORD(NextEntry,

            LDR_DATA_TABLE_ENTRY,

            InLoadOrderLinks);

     

          // 通过内核调试器加载模块符号

          sprintf( Buffer, "%ws\\System32\\%s%wZ",

            &SharedUserData->NtSystemRoot[2],

            ImageCount++ < 2 ? "" : "Drivers\\",

            &DataTableEntry->BaseDllName

            );

          RtlInitString( &NameString, Buffer );

          DbgLoadImageSymbols(&NameString, DataTableEntry->DllBase, (ULONG)-1);

          NextEntry = NextEntry->Flink;    // 下一个结点

        }

      } 

      else 

      {

        // 初始化HAL

        if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {

          KeBugCheck(HAL_INITIALIZATION_FAILED);

        }

      }

     

      if (Number == 0) {

        // ……

        

        // 初始化执行体(phase 0)

        if (!ExInitSystem()) {

          KeBugCheck(PHASE0_INITIALIZATION_FAILED);

        }

     

        ExBurnMemory(LoaderBlock);

     

        // 初始化内存管理器(phase 0)

        MmInitSystem(0, LoaderBlock, Memory);

     

        {

          PLIST_ENTRY NextMd;

          PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;

     

          // 遍历内存描述符,统计LoaderNlsData类型内存区域总大小

          NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;

          while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {

            MemoryDescriptor = CONTAINING_RECORD(NextMd,

              MEMORY_ALLOCATION_DESCRIPTOR,

              ListEntry);

            switch (MemoryDescriptor->MemoryType) {

              case LoaderNlsData:

                InitNlsTableSize += MemoryDescriptor->PageCount*PAGE_SIZE;

                break;

              default:

                break;

            }

            NextMd = MemoryDescriptor->ListEntry.Flink;

          }

     

          // 分配非分页的NLS区域

          InitNlsTableBase = ExAllocatePoolWithTag(NonPagedPool,InitNlsTableSize,' 

    slN');

          if ( !InitNlsTableBase ) {

            KeBugCheck(PHASE0_INITIALIZATION_FAILED);

          }

     

          // 拷贝NLS数据到刚才分配的区域

          RtlMoveMemory(

            InitNlsTableBase,

            LoaderBlock->NlsData->AnsiCodePageData,

            InitNlsTableSize

            );

     

          // 初始化NLS表信息结构

          RtlInitNlsTables(

            (PVOID)((PUCHAR)InitNlsTableBase+InitAnsiCodePageDataOffset),

            (PVOID)((PUCHAR)InitNlsTableBase+InitOemCodePageDataOffset),

            (PVOID)((PUCHAR)InitNlsTableBase+InitUnicodeCaseTableDataOffset),

            &InitTableInfo

            );

     

          RtlResetRtlTranslations(&InitTableInfo);

        }

     

        // ……

     

        // 初始化静态句柄表

        ExInitializeHandleTablePackage();

     

        // 初始化对象管理器(phase 0)

        if (!ObInitSystem()) {

          KeBugCheck(OBJECT_INITIALIZATION_FAILED);

        }

     

        // 初始化安全引用监视器(phase 0)

        if (!SeInitSystem()) {

          KeBugCheck(SECURITY_INITIALIZATION_FAILED);

        }

     

        // 初始化进程管理器(phase 0)

        if (PsInitSystem(0, LoaderBlock) == FALSE) {

          KeBugCheck(PROCESS_INITIALIZATION_FAILED);

        }

     

        // 初始化即插即用管理器(phase 0)

        if (!PpInitSystem()) {

          KeBugCheck(PP0_INITIALIZATION_FAILED);

        }

        

        // 设置SharedUserData成员

        // ……

      }

    }

    2.4  [phase0]初始化进程管理器PsInitPhase0
          这里介绍的是进程管理器在phase 0的初始化过程,之所以介绍这个过程是因为phase 1 
    初始化过程正是从这里展开。在上一节上已经提到PsInitSystem,在phase0,实际上调用
    PsInitPhase0实现进程管理器的初始化。PsInitPhase0主要实现以下几个功能:
    (1)设置系统启动进程(即当前进程)为Idle进程,并改名为"Idle"。
    (2)初始化进程、Job等相关的全局变量。
    (3)创建系统进程并命名为"System"。
    (4)创建系统线程用于实现phase1过程的初始化。
    PsInitPhase0的具体实现如下:

    代码:

    BOOLEAN PspInitPhase0 ( IN PLOADER_PARAMETER_BLOCK LoaderBlock   )

    {

        UNICODE_STRING NameString;

        OBJECT_ATTRIBUTES ObjectAttributes;

        OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;

        HANDLE ThreadHandle;

        PETHREAD Thread;

        MM_SYSTEMSIZE SystemSize;

     

        SystemSize = MmQuerySystemSize();

    PspDefaultPagefileLimit = (ULONG)-1;

    // ……

     

        // 初始化进程相关的锁

        ExInitializeFastMutex( &PspProcessLockMutex );

        ExInitializeFastMutex( &PsProcessSecurityLock );

     

        // 当前进程即是Idle进程

        PsIdleProcess = PsGetCurrentProcess();

        PsIdleProcess->Pcb.KernelTime = 0;

        PsIdleProcess->Pcb.KernelTime = 0;

     

        // 初始化OBJECT_TYPE_INITIALIZER结构

        RtlZeroMemory( &ObjectTypeInitializer, sizeof( ObjectTypeInitializer ) );

        ObjectTypeInitializer.Length = sizeof( ObjectTypeInitializer );

        ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;

        ObjectTypeInitializer.SecurityRequired = TRUE;

        ObjectTypeInitializer.PoolType = NonPagedPool;

        ObjectTypeInitializer.InvalidAttributes = OBJ_PERMANENT | OBJ_EXCLUSIVE | 

    OBJ_OPENIF;

     

        // 创建进程对象

        RtlInitUnicodeString(&NameString, L"Process");

        ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_PROCESS_PAGED_CHARGE;

        ObjectTypeInitializer.DefaultNonPagedPoolCharge = 

    PSP_PROCESS_NONPAGED_CHARGE;

        ObjectTypeInitializer.DeleteProcedure = PspProcessDelete; // 

    删除进程对象回调函数

        ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;

        ObjectTypeInitializer.GenericMapping = PspProcessMapping;

        if ( !NT_SUCCESS(ObCreateObjectType(&NameString,

                                         &ObjectTypeInitializer,

                                         (PSECURITY_DESCRIPTOR) NULL,

                                         &PsProcessType

                                         )) ){

            return FALSE;

        }

     

        // 创建线程对象

        RtlInitUnicodeString(&NameString, L"Thread");

        ObjectTypeInitializer.DefaultPagedPoolCharge = PSP_THREAD_PAGED_CHARGE;

        ObjectTypeInitializer.DefaultNonPagedPoolCharge = 

    PSP_THREAD_NONPAGED_CHARGE;

        ObjectTypeInitializer.DeleteProcedure = PspThreadDelete; // 

    删除线程对象回调函数

        ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;

        ObjectTypeInitializer.GenericMapping = PspThreadMapping;

        if ( !NT_SUCCESS(ObCreateObjectType(&NameString,

                                         &ObjectTypeInitializer,

                                         (PSECURITY_DESCRIPTOR) NULL,

                                         &PsThreadType

                                         )) ){

            return FALSE;

        }

     

        // 创建Job对象

        RtlInitUnicodeString(&NameString, L"Job");

        ObjectTypeInitializer.DefaultPagedPoolCharge = 0;

        ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EJOB);

        ObjectTypeInitializer.DeleteProcedure = PspJobDelete;  // 删除Job

    对象回调函数

        ObjectTypeInitializer.CloseProcedure = PspJobClose;    // 关闭Job对象回调函数

        ObjectTypeInitializer.ValidAccessMask = JOB_OBJECT_ALL_ACCESS;

        ObjectTypeInitializer.GenericMapping = PspJobMapping;

        ObjectTypeInitializer.InvalidAttributes = 0;

        if ( !NT_SUCCESS(ObCreateObjectType(&NameString,

                                         &ObjectTypeInitializer,

                                         (PSECURITY_DESCRIPTOR) NULL,

                                         &PsJobType

                                         )) ){

            return FALSE;

        }

     

        // 初始化进程链表,及保护该链表的互斥对象

        InitializeListHead(&PsActiveProcessHead);

        ExInitializeFastMutex(&PspActiveProcessMutex);

     

        // 初始化Job链表,及保护该链表的互斥对象

        InitializeListHead(&PspJobList);

        ExInitializeFastMutex(&PspJobListLock);

     

        // 初始化工作集链表,及保护该链表的互斥对象

        InitializeListHead(&PspWorkingSetChangeHead.Links);

        ExInitializeFastMutex(&PspWorkingSetChangeHead.Lock);

     

        // 创建CID句柄表

        PspCidTable = ExCreateHandleTable(NULL);

        if ( ! PspCidTable ) {

            return FALSE;

        }

        // ?? 从链表中移除CID表,避免被ExSnapShotHandleTables或调试器扩展命令!

    handle枚举到

        ExRemoveHandleTable(PspCidTable);

     

    #if defined(i386)

        // ?? LDT初始化

        if ( !NT_SUCCESS(PspLdtInitialize()) ) {

            return FALSE;

        }

        // ?? VDM初始化

        if ( !NT_SUCCESS(PspVdmInitialize()) ) {

            return FALSE;

        }

    #endif

     

        // 初始化Reaper链表及数据结构

        InitializeListHead(&PsReaperListHead);

        ExInitializeWorkItem(&PsReaperWorkItem, PspReaper, NULL);

     

    // 保存系统启动进程令牌到全局变量PspBootAccessToken

        PspBootAccessToken = PsGetCurrentProcess()->Token;

     

        // 初始化对象安全属性结构

        InitializeObjectAttributes( &ObjectAttributes,NULL,0,NULL,NULL); 

     

        // 创建系统进程

        if ( !NT_SUCCESS(PspCreateProcess(

                        &PspInitialSystemProcessHandle,

                        PROCESS_ALL_ACCESS,

                        &ObjectAttributes,

                        0L,

                        FALSE,

                        0L,

                        0L,

                        0L

                        )) ) {

            return FALSE;

        }

     

        // 增加引用计数,并获取EPROCESS结构,保存到全局变量PsInitialSystemProcess

        if ( !NT_SUCCESS(ObReferenceObjectByHandle(

                                            PspInitialSystemProcessHandle,

                                            0L,

                                            PsProcessType,

                                            KernelMode,

                                            (PVOID *)&PsInitialSystemProcess,

                                            NULL

                                            )) ) {

            return FALSE;

        }

     

        // 设置当前进程映像名称为"Idle"

        strcpy(&PsGetCurrentProcess()->ImageFileName[0],"Idle");

        // 设置新创建的进程映像名称为"System"

        strcpy(&PsInitialSystemProcess->ImageFileName[0],"System");

     

        // 创建系统线程用于实现phase1的初始化过程,线程函数为Phase1Initialization

        if ( !NT_SUCCESS(PsCreateSystemThread(

                        &ThreadHandle,

                        THREAD_ALL_ACCESS,

                        &ObjectAttributes,

                        0L,

                        NULL,

                        Phase1Initialization,

                        (PVOID)LoaderBlock

                        )) ) {

            return FALSE;

        }

     

        // 增加引用计数

        if ( !NT_SUCCESS(ObReferenceObjectByHandle(

                            ThreadHandle,

                            0L,

                            PsThreadType,

                            KernelMode,

                            (PVOID *)&Thread,

                            NULL

                            )) ) {

            return FALSE;

        }

     

        // 关闭线程句柄

        ZwClose( ThreadHandle );

     

        return TRUE;

    }

    在这个过程中,对于几个重要的全局变量进行初始化,例如PspCidTable、
    PsActiveProcessHead等。
    另外在_OBJECT_TYPE_INITIALIZER有几个成员是由于注册对象操作回调函数的,例如
    PsInitPhase0中注册删除进程对象回调函数PspProcessDelete
    。因而对于内核对象来说,完全可以从_OBJECT_TYPE_INITIALIZER结构入手HOOK
    对应的回调函数实现对内核对象的完全监控。

    2.5  [phase1]Ntoskrnl初始化Phase1Initialiation
    (这里以wrk v1.2作为参考)
    在上一小节中已经提到,在进程管理器进行phase0阶段初始化时会创建新线程
    phase1Initialation,来实现phase1阶段的初始化。phase1Initialation函数实现如下:

    代码:

    VOID Phase1Initialization (IN PVOID Context)

    {

      Phase1InitializationDiscard (Context);

      MmZeroPageThread();

      return;

    }

    Phase1Initialization分为两个步骤:
    (1)调用Phase1InitializationDiscard真正实现phase1阶段的初始化工作。
    (2)当完成phase1阶段的初始化后系统已经启动,线程Phase1Initialization已经完成最重要任务,接下去就以零页面线程的角色继续为系统提供服务。
    注:零页面线程,线程优先级为0,循环地从空闲页面链表中获取页面并清0,然后添加到零页面链表中。系统在运行过程会频繁的申请、释放内存,然后释放后的 页面一般都不为0。零页面线程就好比是垃圾回收站的加工人员,把回收的垃圾粉刷一遍就变成新的了。这里主要目标是分析 Phase1InitializationDiscard的具体实现过程,对于零页面线程不作过多探讨。
    这里的分析过程参考了《深入解析Windows操作系统》,关于phase1阶段的初始化流程虽然wrk与书中的描述非常接近,但并不完全一样。另外,我对于这些步骤进行了一定的简化。Phase1阶段的初始化具体如下:
    (1)phase 0% -- 10%    
       [1] 调用HalInitSystem,让系统做好准备接受来自设置的中断,并允许中断
      [2] 调用InbvEnableBootDriver引导视频驱动,调用InbvDriverInitialize
    初始化视频驱动,并显示启动界面
      [3] 调用PoInitSystem初始化电源管理器(phase0)
       [4] 调用KeSetSystemTime初始化系统时间,设置系统启动时间并保存为全局变量
    KeBootTime
       [5] 在多处理器系统上,调用KeStartAllProcessors初始化其他处理器
      [6] 调用ObInitSystem初始化对象管理器(phase1)
       [7] 调用ExInitSystem初始化执行体(phase1)
       [8] 调用KeInitSystem初始化内核(phase1)
       [9] 调用KdInitSystem初始化内核调试器(phase1)
       [10] 调用SeInitSystem初始化安全引用监视器(phase1)
    (2)phase 10% -- 15%
       [11] 调用MmInitSystem初始化内存管理器(phase1)
       [12] 把国家语言支持(NLS)表映射到系统空间
      [13] 调用CcInitializeCacheManager初始化缓存管理器
      [14] 调用CmInitSystem1初始化配置管理器
    (3)phase 15% -- 20%
       [15] 调用FsRtlInitSystem初始化全局的文件系统驱动程序数据结构
      [16] 调用PpInitSystem初始化即插即用管理器(PNP)(phase1),必须在初始化I/O
    管理器之前进行
    (4)phase 20% -- 25%
       [17] 调用LpcInitSystem初始化LPC,必须在初始化I/O管理器之前进行
    (5)phase 25% -- 75%
       [18] 调用IoInitSystem初始化I/O
    管理器,设置进度条为局部更新模式,逐步更新进度条从%到%
    (6)phase 75% -- 80%
       [19] 调用MmInitSystem初始化内存管理器(phase2),开启分页机制
    (7)phase 80% -- 85%
       [20] 调用PoInitSystem初始化电源管理器(phase1)
       [21] 调用PsInitSystem初始化进程管理器(phase1),可以定位NTDLL.DLL和SMSS.EXE
    (8)phase 85% -- 90%
       [22] 调用SeRmInitPhase1初始化性能引用监视器(phase1)
    ,包括创建命令服务器线程,这个线程将会创建一个名为SeRmCommandPort的LPC
    端口,使用这个端口可以接收本地安全认证子系统(LSASS)发送的命令。
    (9)phase 90% -- 100%
       [23] 调用RtlCreateUserProcess创建会话管理器进程(SMSS)
    (10)phase 100% ------
       [24] 等待会话管理器SMSS 5秒,如果等待超时表明SMSS进程正常启动

    根据进度条设置情况大致可以分为10个步骤,可以结合下面Phase1InitializationDiscard的源码来看:

    代码:

    VOID Phase1InitializationDiscard (IN PVOID Context)

    {

      PLOADER_PARAMETER_BLOCK LoaderBlock;

      PETHREAD Thread;

      PKPRCB Prcb;

      KPRIORITY Priority;

      NTSTATUS Status;

      UNICODE_STRING SessionManager;

      PRTL_USER_PROCESS_PARAMETERS ProcessParameters;

      PVOID Address;

      SIZE_T Size;

      LARGE_INTEGER UniversalTime;

      LARGE_INTEGER CmosTime;

      LARGE_INTEGER OldTime;

      TIME_FIELDS TimeFields;

      UNICODE_STRING EnvString, NullString, UnicodeSystemDriveString;

      PWSTR Src, Dst;

      BOOLEAN ResetActiveTimeBias;

      HANDLE NlsSection;

      LARGE_INTEGER SectionSize;

      LARGE_INTEGER SectionOffset;

      PVOID SectionBase;

      PVOID ViewBase;

      ULONG CacheViewSize;

      SIZE_T CapturedViewSize;

      ULONG SavedViewSize;

      LONG BootTimeZoneBias;

      PKLDR_DATA_TABLE_ENTRY DataTableEntry;

    #ifndef NT_UP

      PMESSAGE_RESOURCE_ENTRY MessageEntry1;

    #endif

      PCHAR MPKernelString;

      PCHAR Options;

      PCHAR YearOverrideOption;

      LONG  CurrentYear = 0;

      BOOLEAN NOGUIBOOT;

      BOOLEAN SOS;

      PVOID Environment;

      PRTL_USER_PROCESS_INFORMATION ProcessInformation;

     

      // ……

     

      

    ///////////////////////////////////////////////////////////////////////////////

      //    进入phase1初始化阶段      //

      //////////////////////////////////////////////////////////////////////////////

      InitializationPhase = 1;

     

      // 提升线程优先级

      Thread = PsGetCurrentThread();

      Priority = KeSetPriorityThread( &Thread->Tcb,MAXIMUM_PRIORITY - 1 );

     

      // [1] 调用HalInitSystem,让系统做好准备接受来自设置的中断,并允许中断

      LoaderBlock = (PLOADER_PARAMETER_BLOCK)Context;

      if (HalInitSystem(InitializationPhase, LoaderBlock) == FALSE) {

        KeBugCheck(HAL1_INITIALIZATION_FAILED);

      }

     

      // 根据处理器控制块的LoadOptions成员判断是否以GUI方式启动

      Options = LoaderBlock->LoadOptions ? _strupr(LoaderBlock->LoadOptions) : NULL;

      if (Options) {

        NOGUIBOOT = (BOOLEAN)(strstr(Options, "NOGUIBOOT") != NULL);

      } else {

        NOGUIBOOT = FALSE;

      }

     

      // [2] 调用引导视频驱动程序(Bootvid.dll)

      InbvEnableBootDriver((BOOLEAN)!NOGUIBOOT);

     

      // 初始化视频驱动程序

      InbvDriverInitialize(LoaderBlock, 18);

     

      // 显示启动界面

      // ……

     

      // [3] 初始化电源管理器(phase0)

      if (!PoInitSystem(0)) {

        KeBugCheck(INTERNAL_POWER_ERROR);

      }

     

      // ……

     

      // [4] 初始化系统时间和系统启动时间

      if (ExCmosClockIsSane && HalQueryRealTimeClock(&TimeFields)) {

        // ……

        

        // 设置系统时间

        KeSetSystemTime(&UniversalTime, &OldTime, FALSE, NULL);

     

        // 通知其他组建系统时间被设置

        PoNotifySystemTimeSet();

     

        // 设置系统启动的绝对时间

        KeBootTime = UniversalTime;

        KeBootTimeBias = 0;

      }

     

      // ……

     

      // [5] 在多处理器系统上,初始化其他处理器

      KeStartAllProcessors();

      // ……

     

     

      // [6] 初始化对象管理器(phase1)

      if (!ObInitSystem()) {

        KeBugCheck(OBJECT1_INITIALIZATION_FAILED);

      }

     

      // [7] 初始化执行体(phase1)

      if (!ExInitSystem()) {

        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,STATUS_UNSUCCESSFUL,0,1,0);

      }

     

      // [8] 初始化内核(phase1)

      if (!KeInitSystem()) {

        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,STATUS_UNSUCCESSFUL,0,2,0);

      }

     

      // [9] 初始化内核调试器(phase1)

      if (!KdInitSystem(InitializationPhase, NULL)) {

        KeBugCheckEx(PHASE1_INITIALIZATION_FAILED,STATUS_UNSUCCESSFUL,0,3,0);

      }

     

      // [10] 初始化安全引用监视器(phase1)

      if (!SeInitSystem()) {

        KeBugCheck(SECURITY1_INITIALIZATION_FAILED);

      }

     

      // 设置进度条到%

      InbvUpdateProgressBar(10);

     

      Status = CreateSystemRootLink(LoaderBlock);

      if ( !NT_SUCCESS(Status) ) {

        KeBugCheckEx(SYMBOLIC_INITIALIZATION_FAILED,Status,0,0,0);

      }

     

      // [11] 初始化内存管理器(phase1)

      if (MmInitSystem(1, LoaderBlock) == FALSE) {

        KeBugCheck(MEMORY1_INITIALIZATION_FAILED);

      }

     

      // [12] 把国家语言支持(NLS)表映射到系统空间

      // ……

     

      // [13] 初始化缓存管理器

      if (!CcInitializeCacheManager()) {

        KeBugCheck(CACHE_INITIALIZATION_FAILED);

      }

     

      // [14] 初始化配置管理器

      if (!CmInitSystem1(LoaderBlock)) {

        KeBugCheck(CONFIG_INITIALIZATION_FAILED);

      }

     

      // ??

      CcPfInitializePrefetcher();

     

      // 设置进度条到%

      InbvUpdateProgressBar(15);

     

      // 计算时区偏差

      // ……

     

      // [15] 初始化全局的文件系统驱动程序数据结构

      if (!FsRtlInitSystem()) {

        KeBugCheck(FILE_INITIALIZATION_FAILED);

      }

     

      // 在PNP初始化时需要使用range list,因而在PNP初始化之前需要初始化range list

      RtlInitializeRangeListPackage();

      HalReportResourceUsage();

      KdDebuggerInitialize1(LoaderBlock);

     

      // [16] 初始化即插即用管理器(PNP)(phase1),必须在初始化I/O管理器之前进行

      if (!PpInitSystem()) {

        KeBugCheck(PP1_INITIALIZATION_FAILED);

      }

     

      // 设置进度条到%

      InbvUpdateProgressBar(20);

     

      // [17] 初始化LPC,必须在初始化I/O管理器之前进行

      if (!LpcInitSystem()) {

        KeBugCheck(LPC_INITIALIZATION_FAILED);

      }

     

      // 此时系统已经处于运行阶段

      ExInitSystemPhase2();

     

      // [18] 初始化I/O管理器,设置进度条为局部更新模式,逐步更新进度条从%到%

      InbvSetProgressBarSubset(25, 75);

      if (!IoInitSystem(LoaderBlock)) {

        KeBugCheck(IO1_INITIALIZATION_FAILED);

      }

     

      // 撤消局部更新模式

      InbvSetProgressBarSubset(0, 100);

      CmpInitSystemVersion(6, NULL);

     

      // [19] 初始化内存管理器(phase2),开启分页机制

      MmInitSystem(2, LoaderBlock);

     

      // 设置进度条到%

      InbvUpdateProgressBar(80);

     

      // [20] 初始化电源管理器(phase1)

      if (!PoInitSystem(1)) {

        KeBugCheck(INTERNAL_POWER_ERROR);

      }

     

      // [21] 初始化进程管理器(phase1)

      // 由于SystemRoot已经被定义,可以定位NTDLL.DLL和SMSS.EXE

      if (PsInitSystem(1, LoaderBlock) == FALSE) {

        KeBugCheck(PROCESS1_INITIALIZATION_FAILED);

      }

     

      // 设置进度条到%

      InbvUpdateProgressBar(85);

     

      if (LoaderBlock == KeLoaderBlock) {

        KeLoaderBlock = NULL;

      }

     

      // 释放加载器Ntldr参数信息块

      MmFreeLoaderBlock (LoaderBlock);

      LoaderBlock = NULL;

      Context = NULL;

     

      // [22] 初始化性能引用监视器(phase1),包括创建命令服务器线程,

      // 这个线程将会创建一个名为SeRmCommandPort的LPC端口。

      // 使用这个端口可以接收本地安全认证子系统(LSASS)发送的命令。

      if (!SeRmInitPhase1()) {

        KeBugCheck(REFMON_INITIALIZATION_FAILED);

      }

     

      // 设置进度条到%

      InbvUpdateProgressBar(90);

     

      // 设置会话管理器子系统(SMSS)进程信息

      // ……

     

      // [23] 创建会话管理器进程(SMSS)

      Status = RtlCreateUserProcess(

        &SessionManager,

        OBJ_CASE_INSENSITIVE,

        RtlDeNormalizeProcessParams( ProcessParameters ),

        NULL,

        NULL,

        NULL,

        FALSE,

        NULL,

        NULL,

        ProcessInformation);

      // ……

     

      // 设置进度条到%

      InbvUpdateProgressBar(100);

     

      InbvEnableDisplayString(TRUE);

     

      // [24] 等SMSS.EXE 5秒,如果等待超时表明SMSS进程正常启动

      OldTime.QuadPart = Int32x32To64(5, -(10 * 1000 * 1000));

      Status = ZwWaitForSingleObject(

        ProcessInformation->Process,

        FALSE,

        &OldTime

        );

      if (Status == STATUS_SUCCESS) {

        KeBugCheck(SESSION5_INITIALIZATION_FAILED);

      }

     

      // 空间释放与关闭句柄

      // ……

     

      // 系统启动成功后设置InitializationPhase为

      InitializationPhase += 1;

    }

     

     

  • 相关阅读:
    读后感
    mysql分库分表的基本方法
    pdo接口用法
    视频技术基础
    【原创】shell易错语法汇总
    php底层的运行机制
    mysql统计函数
    etc/shadow 登陆口令破解
    JAVA学习(方法重载)
    JAVA学习(方法的定义及调用)
  • 原文地址:https://www.cnblogs.com/mayingkun/p/2974905.html
Copyright © 2011-2022 走看看