前面两篇介绍了windows Dtrace的set以及efi引导启动,这一章讲解windows引导进入系统内核ntos后,ntos是如何初始化Dtrace
Windows DTrace及实现原理(一) ——bcdedit.exe的set实现
Windows DTrace及实现原理(二) ——winload.efi启动加载dtrace
众所周知,Windows启动初始化分为Phase0(阶段0)和Phase1(阶段1)两个阶段,而Dtrace是在操作系统初始化的Phase1的KeInitSystem的时候来初始化的,可以看下该函数的逻辑

在KeInitSystem的过程当中,其中有一个步骤是KiInitDynamicTraceSupport()


该函数的大致逻辑是给KiDynamicTraceEnnable默认值是0,当调用TraceInitSystem成功后,KiDynamicTraceEnnable的值就被赋予了 1 | 2 , KiDynamicTraceEnnable= 3, 当判断KdDebuggerNotPresent值不为0时,就是存在内核调试状态,KiDynamicTraceEnnable= 2 | 5,KiDynamicTraceEnnable= 7,主要的功能就在TraceInitSystem是外部驱动的一个导出函数,如果开启了Dtrace功能,这个函数就会被调用成功。
该函数的实现逻辑实在Dtrace.sys中实现,因为KiInitDynamicTraceSupport 会调用这个函数来初始化Dtrace 
系统build号要> 1900,这个版是win10,下面可以在TaceInitSystem函数看到他支持几种信息的callback和probe(探查)

DtEtwpEventCallback : ETW事件信息探查
StpCallbackEntry: Syscall Entry 探查
StpCallbackReturn: SysCall Return 探查
FbtpCallback: 函数边界探查
FtpPidCallback: 进程pid相关的函数探查
在dtrace.sys的TraceInitSystem函数下断点,然后g

在调用进入该函数前可以看到这个汇编代码如下:

可以看到这里指令是 call dtrace!TraceInitSystem (fffff801`40fdd010),说明这个TraceInitSystem实在Dtrace里实现的
可以看到一会停在了该函数的入口点,以及当前调用堆栈 
同时看kb命令看堆栈如下:
# RetAddr : Args to Child : Call Site
00 fffff803`cc9e8941 : 00000000`00000000 00000000`00000000 : dtrace!TraceInitSystem
01 fffff803`cca2067b : 00000000`00000000 00000000`00000000 : nt!KiInitDynamicTraceSupport+0x51
02 fffff803`cc9cba4f : 00000000`00000001 ffffd401`30e06b10 : nt!KeInitSystem+0x153
03 fffff803`cc4ca713 : fffff803`cc4ca6f0 fffff803`5a63e530 : nt!Phase1InitializationDiscard+0xaf7
04 fffff803`cc25904a : ffffa585`1f702080 fffff803`cc4ca6f0 : nt!Phase1Initialization+0x23
05 fffff803`cc4741c4 : fffff803`5b87c180 ffffa585`1f702080 : nt!PspSystemThreadStartup+0x5a
06 00000000`00000000 : ffffd401`30e07000 ffffd401`30e01000 : nt!KiStartSystemThread+0x34dtrace!TraceInitSystem的第一个参数ecx,会返回dtrace内部的dtrace!TraceSystemApi表所在的地址,最后ntoskrnl会对该地址赋值为KiDynamicTraceContext,也就是说dtrace!TraceSystemApi最后会指向KiDynamicTraceContext


dtrace!TraceInitSystem的第二个参数edx会传入KiDynamicTraceCallouts结构体,是个全局的结构体


dtrace!TraceInitSystem的第三个参数edx会传入KiDynamicTraceCallouts结构体,是个全局的地址qword_140D1F2A8,将会被该函数赋值为dtarce!TraceAccessMemory函数

dtrace!TraceInitSystem调用结束后,可以看到eax返回值为0,表示成功
由上可以看到ntos初始化系统内核的Phase1的时候会调用Dtrace.sys的TraceInitSystem来初始化Dtrace的一些结构体,其调用图如下: 