首页
社区
课程
招聘
[原创]庖丁解牛之----Windows DTrace实现原理【重加了图片】
发表于: 5小时前 122

[原创]庖丁解牛之----Windows DTrace实现原理【重加了图片】

5小时前
122

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的GUID

Set参数返回的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 Value

BcdElements结构定义大致如下


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.efi

winload.efi中有一块结构体定义了Dtrace扩展



可以看到第三个结构体是一个函数OslpDtraceExtensionEnabled

OslpDtraceExtensionEnabled函数中可以看到一个逻辑是获取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, 当判断KdDebuggerNotPresent值不为0时,就是存在内核调试状态,KiDynamicTraceEnnable = 2 | 5,KiDynamicTraceEnnable = 7,主要的功能就在TraceInitSystem是外部驱动的一个到处函数,如果开启了Dtrace功能,这个函数就会被调用成功。


传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 40分钟前 被basketwill编辑 ,原因:
收藏
免费 6
支持
分享
最新回复 (1)
雪    币: 2743
活跃值: (6243)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
牛逼牛逼牛逼
24分钟前
0
游客
登录 | 注册 方可回帖
返回