[Windows内核源码分析0] 引导过程(Phase0部分分析)

本文详细跟踪了Windows启动时KiInitializeKernel和ExpInitializeExecutive函数的执行流程,涉及内核初始化、组件加载与初始化过程,包括内存管理、对象管理、执行体层设置等关键步骤。

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

第一个能显示出源码并下到断点的函数是ExpInitializeExecutive上面的描述说该例程会被调用2次, 首先在Phase0阶段初始化执行体层和所有它的子组件, 接着在Phase1阶段再次执行初始化工作。
在这里插入图片描述
来看看当前的调用堆栈:
在这里插入图片描述
可以看到调用顺序是KiSystemStartup调用了KiInitializeKernel接着在调用了ExpInitializeExecutive
接下来在这三个函数上下断点, 然后再次尝试, 发现在KiInitializeKernel上断了下来, 先尝试调试KiInitializeKernel
在这里插入图片描述
KiSystemStartup是有源码的, 但是我在这个函数上下断点没断下来, 所以我在单步补过后直接进入了KiInitializeKernel内。
这个函数的的描述说明了该函数的作用:
该函数的主要目的是初始化内核数据结构, 初始化空闲线程和处理器对象, 初始化PCB结构即进程控制块, 并调用执行体层的初始化例程, 并且也用于新处理器上线时的初始化。
进入KiInitializeKernel后首先:
在这里插入图片描述
接着填充R0和R3都共享的SharedUserData区域关于引导选项的信息, 这些信息都是从boot.ini中设置的
在这里插入图片描述
下面同样都是初始化PRCB中的数据结构初始化一些分发器内核对象
在这里插入图片描述
如果主处理器初始化成功了,则继续初始化处理器控制块PRCB中的内容,并将处理器的一些信息保存下来
在这里插入图片描述
调用了KiInitSystem, 初始化各类分发器对象和内核对象
在这里插入图片描述
初始化了DPC对象, 一些自旋锁以及各类链表
在这里插入图片描述
初始化了定时器链表对象等
在这里插入图片描述
SSDT和Shadow SSDT的初始化
在这里插入图片描述
接下去调用了KeInitializeProcess初始化内核进程对象
在这里插入图片描述
说白了就是把一些信息填充到这个结构体里:
在这里插入图片描述初始化内核线程对象
在这里插入图片描述
KeInitializeThread内部首先调用了KeInitalThread初始化了线程对象后调用KeStartThread启动该线程
在这里插入图片描述
看一下KeStartThread内部做了什么, 首先继续填充线程对象包括线程优先级, 处理器亲和性等信息
在这里插入图片描述
从处理器亲和性数值判断出该线程最适合使用哪一个处理器(WRK必须运行在多核处理器上, 所以要选择一个处理器)
在这里插入图片描述
将该对象插入到进程的线程链表中,等待处理器调度,至此该线程便要开始运行了。
在这里插入图片描述
初始化处理器控制块
在这里插入图片描述
接下去调用了ExpInitializeExecutive函数
在这里插入图片描述
进入后调用的第一个判断是ExpIsLoaderValid
在这里插入图片描述
来看看这个函数的原型:
在这里插入图片描述
其内部使用了一个名为LOADER_PARAMETER_BLOCK的结构体,看一下这个结构体的数据结构:

typedef struct _LOADER_PARAMETER_BLOCK {
    LIST_ENTRY LoadOrderListHead; // 加载模块链表
    LIST_ENTRY MemoryDescriptorListHead; // 内存描述符链表
    LIST_ENTRY BootDriverListHead; // 引导驱动链表
    ULONG_PTR KernelStack; 
    ULONG_PTR Prcb;  
    ULONG_PTR Process;
    ULONG_PTR Thread;
    ULONG RegistryLength;
    PVOID RegistryBase;
    PCONFIGURATION_COMPONENT_DATA ConfigurationRoot;
    PCHAR ArcBootDeviceName;
    PCHAR ArcHalDeviceName;
    PCHAR NtBootPathName;
    PCHAR NtHalPathName; 
    PCHAR LoadOptions;
    PNLS_DATA_BLOCK NlsData;
    PARC_DISK_INFORMATION ArcDiskInformation;
    PVOID OemFontFile;
    struct _SETUP_LOADER_BLOCK *SetupLoaderBlock;
    PLOADER_PARAMETER_EXTENSION Extension;

    union {
        I386_LOADER_BLOCK I386;
        // ALPHA_LOADER_BLOCK Alpha;
        // IA64_LOADER_BLOCK Ia64;
    } u;


} LOADER_PARAMETER_BLOCK, *PLOADER_PARAMETER_BLOCK;

来看看监视里该结构的内容, 其中红框框出的部分实际上是在C:\boot.ini中的配置信息, 这个信息会在windows刚开启位于实模式时显示,并让用户选择引导选项。由于当前还没有任何一个进程被创建, 所以Prcb和Process都是0.
在这里插入图片描述
设置InitializationPhase为0代表我们在Phase0
在这里插入图片描述
调用HalInitSystem来初始化HAL硬件抽象层
在这里插入图片描述
这部分没有源码, 但从反汇编里可以看到其是从halacpim.dll中导出的。
在这里插入图片描述
从其内部的函数名可以看出与硬件关系非常大,HAL硬件抽象层原本就是微软用于屏蔽不同物理设备上不同接口的不一致从而提供一组同一的接口。其中包含了关于PIC可编程控制器, CMOS等硬件相关,这里不做深究。
在这里插入图片描述
初始化完HAL后将中断打开
在这里插入图片描述
拼搭出路径C:\WINDOWS:
在这里插入图片描述
将其转成ANSI:
在这里插入图片描述
调用ExInitSystem初始化执行体各个组件和数据结构:
在这里插入图片描述
进入ExInitSystem后根据之前设置的InitializationPhase来判定是对Phase0的初始化还是Phase1的,这里很显然是Phase0
在这里插入图片描述
进入ExpInitSystemPhase0后对各类执行体资源进行初始化
在这里插入图片描述初始化分页内存池的链表
在这里插入图片描述
以及其他各类自旋锁和链表
在这里插入图片描述
返回后调用MmInitSystem初始化内存管理器和内存池, 在阶段0其只要工作是初始化内存管理页函数, 分页内存池即堆空间和PFN数据库:
获取页表地址:
在这里插入图片描述
设置堆区信息:
在这里插入图片描述
初始化各类执行体对象
在这里插入图片描述
确定用户态与内核态之间的界限
在这里插入图片描述
MmInitSystem函数代码量非常大, 分别分了2个阶段来进行初始化,这里不做详细讨论。
接下去遍历当前的PRCB中的模块链表并加载对应的符号
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看了下之后加载了APCI.sys, pci.sys, isapnp.sys, compbatt.sys, intelide.sys, MountMgr.sys, ftdisk.sys等等
接着执行了ObInitSystem初始化对象管理器, SeInitSystem初始化安全子系统, PsInitSystem初始化进程线程管理器, PpInitSystem初始化即插即用管理器, DbgkInitialize初始化调试子系统等。
由于篇幅都比较长这4个部分我都会专门用博客来记录详细过程。
在这里插入图片描述
完成这四部分的初始化后, 对SharedUserData设置一些关于操作系统的信息后便返回了
在这里插入图片描述
ExpInitializeExecutive返回后, 对PRCB和线程对象进行最后的一些设置后返回
在这里插入图片描述
返回后发现程序竟然回到了KiSystemStartup内
在这里插入图片描述
把当前线程设为idle线程
在这里插入图片描述
蜕变成Idle线程后就是执行KiIdleLoop, Idle线程不停的自旋。
在这里插入图片描述
(完)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值