DTrace 是一个命令行实用工具,允许用户实时监视和调试其系统性能,windows的Dtrace是移植其他操作系统的开放源代码的事件追踪平台,从win10的1900内核版本开始集成的,可以借助 dtrace,用户可以动态检测内核和用户空间代码,而无需修改代码本身。https://learn.microsoft.com/zh-cn/windows-server/administration/windows-commands/dtrace下载安装DTrace注意: 启用后重启机器cmd里输入 dtrac -l 会列举一些使用的探查项目
输入:dtrace -Fn "tick-5sec {exit(0);} syscall:::entry{ @num[pid,execname] = count();} " tick-5sec 指定五秒内事件,exit(0) 完成后就结束,显示记录的进程pid 、进程名以及记录的次数在命令行cmd里输入bcdedit /set dtrace ON会设置注册表 HKEY_LOCAL_MACHINE\BCD00000000\Objects\{5ea502ac-8b8f-11f0-9f0f-70d823d98bbc}\Elements\26000145,就会设置Key键Element的value值为 1
如果 /set dtrace OFF key键Element的value就设置为0了
接下来,我们就通过逆向bcdedit.exe分析下这块功能如何实现的在BcdEditMain的函数里,有个判断参数,其中BcdEditIsSwitchPresent("Set")函数是取当前参数是否是参数“Set”,如果是Set参数则进入BcdEditSetSwitch(),接下来看BcdEditSetSwitch函数。(1) 首先会根据传入的进程参数返回对应的注册表对象GUID这行代码 ParameterSet = BcdEditGetParameterSet(L"set");BcdEditGetParameterSet函数会根据设置的参数"Set" 从全局BcdEditParameterList中找到进程传入的参数,其结构如下如下
BcdElements里面总共定义了284个元素接下里就是通过BcdStringToGuid函数找到set参数对应Store的GUIDSet参数返回的GUID是 {0FA926493h, 6F1Ch, 4193h, <0A4h, 14h, 58h, 0F0h, 0B2h, 45h, 6Dh,1Eh>}(2) BcdEditOpenStore打开Store,然后通过BcdOpenObject函数打开GUID的对象下面就是使用BcdEditOpenStore 打开的一些参数详解 再往下就是通过BcdOpenObject打开GUID的对象Object(3) 通过BcdiStringToDataType找到对应的Set里的dtrace的Element的对象Value, BcdiStringToDataType会根据全局结构数组的BcdElements去查找相应的对象ID ValueBcdElements结构定义大致如下
BcdElements里面总共定义了284个元素BcdElements里面总共定义了284个元素,可以寻找到dtrace对应的Elment定义结构
这里就看到了dtrace对应的Element的Id注册表项的Value: 26000145h(3) 通过BcdSetElementDataWithFlags函数设置BCD注册表的Object的Element的开关 ON(1) / OFF(0)BcdSetElementDataWithFlags 最终会调用BiSetRegistryValue去设置Element的key对应的value: 0/1
至此bcedit的部分分析完毕,接下来是重启后系统去开启dtrace
在前面我们讲解了bcdedit.exe设置bcd的注册表打开的dtrace的对象的开关,因为需要重启windows才能生效,所以我们接下来分析efi引导程序winload.efiwinload.efi中有一块结构体定义了Dtrace扩展
可以看到第三个结构体是一个函数OslpDtraceExtensionEnabledOslpDtraceExtensionEnabled函数中可以看到一个逻辑是获取bcd对象26000145的boolean值BootOptionBoolean = BlGetBootOptionBoolean(*(_QWORD *)(ApplicationEntry + 24), 0x26000145, v12);26000145对象的boolean值就是前面提到的dtrace的set值,v10的默认值是0,如果BootOptionBoolean获取的set值是1,那么v10的值就是1,如果v10的值是1就调用OslpIsApiSetHosted加载dtrace.sys什么时候会调用OslpDtraceExtensionEnabled这个函数呢?这个函数会在 OslpApplyDynamicSchemaExtensions的函数里调用,其调用栈如下:下面就看下windbg双机调试下看到的运行逻辑,windbg输入:sxe ld winload.efi,重启debug模式后会自动进入winload的debugservice服务入口同时看kb命令看堆栈如下:
接下里就是设置断点: bp winload!OslpDtraceExtensionEnabled ,然后g,windbg就会断点在了winload!OslpDtraceExtensionEnabled的函数入口点,目前看只有一个winload.efi加载了我们一步步单独到这块代码看看返回值是多少?目前我们看到r8对应的内存值里的boolean值为0运行完BlGetBootOptionBoolean 函数后可以看到r8 对应的内存的里的boolean变成了1
那么就表示要开启dtrace的功能,这里只是设置了apischem驱动是否加载的点,并且后续会通过加载BlLdrLoadImage函数来加载dtarce.sys从上整个过程可以看到从winload.efi的入口函数OslpMain一直调到该函数的,引导启动dtrace.sys驱动后就进入nto内核启动了。操作系统初始化Windows启动初始化分为Phase0(阶段0)和Phase1(阶段1)两个阶段,而Dtrace是在Phase1的阶段KeInitSystem
在KeInitSystem的过程当中,其中有一个步骤是KiInitDynamicTraceSupport()
该函数的大致逻辑是给KiDynamicTraceEnnable 默认值是0,当调用TraceInitSystem成功后,KiDynamicTraceEnnable 的值就被赋予了 1 | 2 , KiDynamicTraceEnnable = 3, 当判断KdDebuggerNotPresen
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289503.htm