VoidSec/DriverBuddyReloaded
GitHub: VoidSec/DriverBuddyReloaded
一款 IDA Pro 插件,通过自动化逆向分析与启发式漏洞检测,显著简化 Windows 内核驱动程序的安全审计流程。
Stars: 429 | Forks: 59
# Driver Buddy Reloaded 快速入门
## 目录
- [Driver Buddy Reloaded 快速入门](#driver-buddy-reloaded-quickstart)
- [目录](#table-of-contents)
- [安装说明](#installation)
- [快速使用](#quick-usage)
- [高级用法](#advanced-usage)
- [关于 Driver Buddy Reloaded](#about-driver-buddy-reloaded)
- [查找 DispatchDeviceControl](#finding-dispatchdevicecontrol)
- [标记 WDM 和 WDF 结构](#labelling-wdm-and-wdf-structures)
- [查找并解码 IOCTL 代码](#finding-and-decoding-ioctl-codes)
- [标记函数](#flagging-functions)
- [查找 DeviceName](#finding-devicename)
- [导出 Pooltags](#dumping-pooltags)
- [启发式漏洞检测](#heuristic-vulnerability-checks)
- [功能开关](#feature-flags)
- [已修复的问题](#fixed-issues)
- [已知的注意事项与限制](#known-caveats-and-limitations)
- [致谢与感谢](#credits-and-acknowledgements)
## 安装说明
将 `DriverBuddyReloaded` 文件夹和 `DriverBuddyReloaded.py` 脚本文件复制到 IDA plugins 文件夹中,例如:
- `%APPDATA%\Hex-Rays\IDA Pro\plugins\`
- `C:\Program Files\IDA Pro 8.4\plugins\`
- `~/.idapro/plugins/`
如果你的 IDA 配置的是 Python 2,请运行 `idapyswitch` 可执行文件(位于 IDA 的文件夹中)将其切换到 Python 3。
**注意:** Driver Buddy Reloaded 运行在 IDA 7.x、8.x(包括 8.4)以及 9.0+ 上,并需要使用 Python 3。所有特定版本相关的
IDA API 差异(例如 IDA 9.0 中移除了 `get_inf_structure`、`ida_struct` 模块以及 `idc.*struc*` 辅助工具等)
均由内部的 `DriverBuddyReloaded/ida_compat.py` 兼容层进行处理。
## 快速使用
要使用自动分析功能:
1. 启动 IDA 并加载一个 Windows 内核驱动程序。
2. 进入 `Edit -> Plugins -> Driver Buddy Reloaded` 或按下 `CTRL+ALT+A` 启动自动分析。
3. 查看“Output”窗口获取分析结果,以及运行结束时打开的 **Driver Buddy Reloaded - Findings** 窗口(双击某一行即可跳转到对应地址)。
4. 以下文件将被写入 IDA 的 DB 目录下(均以 `-YYYY-MM-DD-TIMESTAMP-` 为前缀):
- `autoanalysis.txt` - 完整的文本分析日志
- `findings.json` - 机器可读的分析结果(IOCTLs、被标记的函数、设备名称、pooltags、调用链)
- `report.html` - 独立的、按严重程度分组的 HTML 报告
- `ioctl_pocs.c` - 按严重程度排序的 `DeviceIoControl` PoC 骨架代码
- `pooltags.txt` - 以 WinDbg 可用的 `pooltags.txt` 格式导出的 Pooltags
要解码单个 IOCTL:
1. 将鼠标光标放在包含疑似 IOCTL 代码的行上。
2. 右键点击并选择 `Driver Buddy Reloaded -> Decode IOCTL`;或者按下 `CTRL+ALT+D` 快捷键。
要解码函数内的所有 IOCTL:
1. 将鼠标光标放在你认为是 IOCTL 派发函数(
`DispatchDeviceControl`、`DispatchInternalDeviceControl`、`Possible_DispatchDeviceControl_#`)的第一条指令上
2. 右键点击并选择 `Driver Buddy Reloaded -> Decode ALL IOCTLs in Function`;或者按下 `CTRL+ALT+F`
快捷键。
3. 一个包含到目前为止所有已解码 IOCTL 的 `DriverName.sys-2021-12-10-TIME_STAMP-IOCTLs.txt`/`DriverName.sys-2021-12-10-TIME_STAMP-IOCTLs.txt_dumb.txt` 文件
将被写入 IDA 的 DB 目录下。
### 高级用法
- [vulnerable_function_lists](DriverBuddyReloaded/vulnerable_functions_lists) 目录包含了一系列潜在的
危险/问题函数、Windows API 和操作码的列表;并提供了关于特定函数/API 为何被列入其中的简要描述。你可以编辑 `custom` 列表以加入驱动程序的特定函数。
**注意**:`winapi_function_prefixes` 会对函数名的开头进行部分匹配(例如 `Zw` 会匹配到 `ZwClose`、`ZwCommitComplete` 等),而 `winapi_functions` 仅执行完全匹配。
- 在 [find_opcodes.py](DriverBuddyReloaded/find_opcodes.py) 中,`find_opcode_data` 选项会阻止 Driver Buddy
Reloaded 在数据段中查找操作码。将其设置为 `True` 将会输出类似此[行](https://github.com/VoidSec/DriverBuddyReloaded/issues/11)的信息:
`Found jnz short loc_15862 in sub_15820 at 0x00015852`
通常,前往显示的地址并将该区域重新定义为代码,即可找回所搜索的操作码。
**注意**:将其切换为 `True` 将会产生更多的误报!
## 关于 Driver Buddy Reloaded
**Driver Buddy Reloaded** 是一个 IDA Pro 的 Python 插件,旨在帮助自动化完成一些繁琐的 Windows 内核驱动程序逆向
工程任务。它具有许多实用的功能,例如:
* 识别驱动程序的类型(WDM, KMDF, UMDF, Mini-Filter, Stream Minidriver, AVStream, PortCls)
* 定位 `DispatchDeviceControl` / `DispatchInternalDeviceControl` 函数
* 为 `WDF` 和 `WDM` 驱动程序填充通用结构
* 尝试识别并标记如 `IRP` 和 `IO_STACK_LOCATION` 等结构
* 为通常未被标记的 `WDF` 函数调用添加标签
* 创建一个 `IRP_MJ_FUNCTION` IDA 枚举,并将其应用到 `DriverEntry` 的 `MajorFunction` 数组槽中(WDM)
* 查找并解码 IOCTL 代码
* 对已识别的派发函数进行自动化流程图扫描(无需手动放置光标)
* 从 IDA 类型数据库中动态解析 NTSTATUS 值(无需静态列表)
* 标记容易被滥用的函数
* 查找潜在的 `DeviceName`(mmap 扫描 + IDA Strings DB 后备,附带源地址)
* 导出 `Pooltags`(基于导入表的主扫描 + 针对暂存于寄存器中的标签的寄存器传播后备扫描)
* **启发式漏洞检测**:未经验证的用户拷贝、缺失的权限检查、IRQL 不匹配、不安全的
MDL 映射、栈分配的缓冲区(`_alloca`) - 参见 [启发式漏洞检测](#heuristic-vulnerability-checks)
* **导出审计**:标记内部交叉引用为零的驱动程序导出项(潜在的攻击面)
* 对解码出的 IOCTL 进行**风险评分**(优先考虑 `METHOD_NEITHER` / `FILE_ANY_ACCESS` 以及触达
诸如 `MmMapIoSpace`、`memcpy`、`__writemsr` 等危险接收器的处理程序),并按严重程度在
可点击的结果窗口中展示所有发现(双击可跳转至对应地址)
* 追踪从派发程序 / IOCTL 处理程序到危险接收器的**调用链**(启发式、基于名称)
* 将结果导出为机器可读的 **JSON** 文件、独立的 **HTML 报告**,以及生成的 **C/C++
`DeviceIoControl` PoC harness**,以快速启动测试/模糊测试

### 查找 DispatchDeviceControl
该工具能够自动定位并识别 `DispatchDeviceControl` 例程。此函数用于将所有
传入的 `DeviceIoControl` 代码路由到与该代码关联的特定驱动程序函数。自动识别
此函数使得查找每个驱动程序的有效 `DeviceIoControl` 代码变得更加快捷。此外,当
调查由于崩溃导致的驱动程序潜在漏洞时,了解该函数的位置有助于将注意力缩小到
与引发崩溃的 `DeviceIoControl` 代码关联的特定函数调用上。
- `DriverEntry`:驱动程序加载后调用的原始的第一个驱动程序提供的例程。它负责
初始化驱动程序。
- `Real_Driver_Entry`:通常是 `DriverEntry` 的执行流程转移到的函数。它
通常是初始化 `DeviceName` 的地方。
- `DispatchDeviceControl`/`DispatchInternalDeviceControl`:如果工具能够恢复特定偏移量处的函数,
这些函数将被重命名为相应的名称。
- `Possible_DispatchDeviceControl_#`:如果工具无法恢复 `DispatchDeviceControl`
或 `DispatchInternalDeviceControl`,它会采用一种实验性的搜索方法,跟踪执行流,并
检查函数是否正在加载已知的 `IO_STACK_LOCATION` 和 `IRP` 地址;这表明该函数
可能就是 DispatchDeviceControl。由于这是基于启发式的,它可能会返回多个结果,并且
很容易产生误报。

### 标记 WDM 和 WDF 结构
所有的 `WDM`/`WDF` 驱动程序共享一些驱动程序结构。该工具能够自动识别这些
结构,例如 `IO_STACK_LOCATION`、`IRP` 和 `DeviceObject` 结构,这有助于在
逆向工程过程中节省时间,并为正在使用这些函数的驱动程序区域提供上下文信息。

### 查找并解码 IOCTL 代码
在对驱动程序进行逆向时,作为分析的一部分,通常会遇到 IOCTL 代码。这些代码解码后
会揭示有用的信息,并可能将注意力吸引到驱动程序中更有可能
存在漏洞的特定部分。
右键点击潜在的 IOCTL 代码,会弹出一个上下文菜单选项(或者当光标位于包含疑似 IOCTL 代码的行上时,使用
`Ctrl+Alt+D` 快捷键),该选项可用于解码该值。这会输出一个包含所有已解码 IOCTL 代码的表格。在反汇编视图中,
右键点击已解码的 IOCTL 代码时,可以将其标记为无效;这将保留任何非 IOCTL 的注释不变。
如果你右键点击(或者使用
`Ctrl+Alt+F` 快捷键),在你认为是 IOCTL 派发程序(
`DispatchDeviceControl`、`DispatchInternalDeviceControl`、`Possible_DispatchDeviceControl_#`)的函数的第一条指令上,在 Driver Buddy
Reloaded 菜单下,会出现一个“**Decode All**”选项,它会尝试解码它在该函数中能找到的所有 IOCTL 代码。
这有点取巧,但大多数情况下它可以加快分析速度。
- 一个包含所有已解码 IOCTL 的 `IOCTLs.txt` 文件(以 `-YYYY-MM-DD-TIMESTAMP-` 为前缀)将被
写入到 IDA 的 DB 目录下。
此外,自动分析会对已识别的派发函数进行流程图扫描,从而自动发现 IOCTL,而无需手动放置光标。


### 标记函数
Driver Buddy Reloaded 包含一系列 C/C++ 函数、操作码和 Windows API(定义在
[vulnerable_function_lists](DriverBuddyReloaded/vulnerable_functions_lists) 目录中),这些通常是存在漏洞的,
或者可能引发缓冲区溢出条件。在自动分析期间会报告所有找到的实例,
这有助于寻找可能触达敏感函数的受用户控制的代码路径。

### 查找 DeviceName
该工具会自动尝试查找驱动程序注册的设备路径(`DeviceName`),如果通过
查看二进制文件中的 Unicode 字符串无法找到任何路径,那么分析师可以手动尝试使用
Madiant 的 [FLOSS](https://github.com/mandiant/flare-floss/) 来尝试寻找混淆的路径。

### 导出 Pooltags
在自动分析过程中,该工具还会以适用于 `pooltags.txt` 的格式导出二进制文件使用的 `Pooltags`。
随后可以将输出内容复制粘贴到该文件的末尾,并由 WinDbg 读取。
- 一个包含所有导出的 Pooltags 的 `DriverName.sys-2021-12-10-TIME_STAMP-pooltags.txt` 文件,将被写入到
IDA 的 DB 目录下。

### 启发式漏洞检测
`heuristics.py` 模块在调用链追踪完成后运行,并检查每个识别出的派发处理程序函数。
它会在 **heuristic**(启发式)类别中输出检测结果:
| 检查项 | 标记对象 | 严重程度 |
|---|---|---|
| 未经验证的用户拷贝 | 附近没有 `ProbeForRead`/`ProbeForWrite`/安全字符串防护的 `memcpy`/`RtlCopyMemory`/等 | HIGH(处理程序),MEDIUM(其他) |
| 缺失权限校验 | 函数中没有 `SeSinglePrivilegeCheck`/`SeAccessCheck` 的ZwOpenProcess`/`ZwAllocateVirtualMemory`/等 | HIGH |
| IRQL 不匹配 | 当存在提升 IRQL 的函数时,调用了 Pageable / `Zw*` / `MmMap*` | MEDIUM |
| 不安全的 MDL 映射 | 反汇编中包含 `UserMode` 的 `MmMapLockedPages`/`MmProbeAndLockPages`/等 | HIGH,否则为 MEDIUM |
| 栈分配 | 调用 `_alloca`/`_malloca`/`_chkstk`(大型或动态栈分配) | LOW |
这些是**线索生成器**,而不是已确认的漏洞。请将 HIGH/CRITICAL 级别的发现视为手动审查的起点。
## 功能开关
所有可选的分析阶段均由 `DriverBuddyReloaded/config.py` 控制。编辑 `Feature` 类即可
启用或禁用它们:
| 标志 | 默认值 | 描述 |
|---|---|---|
| `HEURISTICS` | `True` | 启发式漏洞检测(拷贝验证、权限校验、IRQL、MDL、alloca) |
| `EXPORTS_AUDIT` | `True` | 标记内部交叉引用为零的驱动程序导出项 |
| `POOLTAG_FALLBACK` | `True` | 寄存器传播的 pool tag 扫描器(在基于导入的扫描未发现任何内容时使用) |
| `IRP_MJ_ENUM` | `True` | 创建 `IRP_MJ_FUNCTION` IDA 枚举并应用于 `MajorFunction` 插槽(仅限 WDM) |
| `CALLCHAIN` | `True` | 从处理程序到危险接收器的 BFS 调用链追踪 |
| `RISK_SCORING` | `True` | IOCTL 风险评分(METHOD/ACCESS 权重 + 接收器权重提升) |
| `RESULTS_WINDOW` | `True` | 分析后显示 Driver Buddy Reloaded 的结果窗口 |
| `JSON_EXPORT` | `True` | 写入 `findings.json` |
| `HTML_REPORT` | `True` | 写入 `report.html` |
| `POC_HARNESS` | `True` | 写入 `ioctl_pocs.c` PoC harness |
| `SEGMENT_OPCODE_SCAN` | `False` | 线性段级操作码扫描(噪音较大,默认关闭) |
## 已修复的问题
以下上游问题在 v1.1.0 版本中已解决:
| 问题 | 描述 |
|---|---|
| [#31](https://github.com/VoidSec/DriverBuddyReloaded/issues/31) | 未将 `GsDriverEntry`(IDA 8.2+ 的 security-cookie 包装器)识别为驱动程序入口点 |
| [#30](https://github.com/VoidSec/DriverBuddyReloaded/issues/30) | 当通过 IDA Strings DB 解析时,`DeviceName` 的查找结果现在包含源地址(EA) |
| [#29](https://github.com/VoidSec/DriverBuddyReloaded/issues/29) | 当存在 WDF 库前缀时,驱动程序类型被报告为 "WDF" 而不是 "KMDF" 或 "UMDF" |
| [#27](https://github.com/VoidSec/DriverBuddyReloaded/issues/27) | 在 IDA < 7.6 上加载时显示明确的错误信息;记录了支持的最低版本 |
| [#25](https://github.com/VoidSec/DriverBuddyReloaded/issues/25) | 创建了 `IRP_MJ_FUNCTION` IDA 枚举并应用于 `DriverEntry` 中的 `MajorFunction` 数组操作数 |
| [#16](https://github.com/VoidSec/DriverBuddyReloaded/issues/16) | 错过了通过寄存器传播的 Pool tags(在 alloc 调用之前暂存于 `mov reg, 'ABCD'` 中) |
| [#15](https://github.com/VoidSec/DriverBuddyReloaded/issues/15) | NTSTATUS 过滤器现在使用 IDA 类型数据库而不是静态列表(如果枚举不存在,则回退到一个小型的硬编码集合) |
## 已知的注意事项与限制
- 为了防止出现大量误报,仅会自动解码 >= `0x10000` 的 IOCTL 值。[Issue #15](https://github.com/VoidSec/DriverBuddyReloaded/issues/15)
- 风险评分和调用链追踪是**启发式的、基于名称的线索生成器**,而不是数据流分析;请将
High/Critical 级别的发现视为优先检查的地方,而不是已确认的漏洞。功能开关位于
`DriverBuddyReloaded/config.py` 中。
- 实验性的 `DispatchDeviceControl` 搜索仅适用于 x64 驱动程序
- 快捷键与 F-Secure 的 [win_driver_plugin](https://github.com/FSecureLABS/win_driver_plugin) 不兼容
- 快捷键与 [findcrypt-yara](https://github.com/polymorf/findcrypt-yara) 不兼容
- 在 [find_opcodes.py](DriverBuddyReloaded/find_opcodes.py) 中,`find_opcode_data` 选项会阻止 Driver Buddy
Reloaded 在数据段中查找操作码。将其设置为 `True` 将会输出类似此[行](https://github.com/VoidSec/DriverBuddyReloaded/issues/11)的信息:
`Found jnz short loc_15862 in sub_15820 at 0x00015852`
通常,前往显示的地址并将该区域重新定义为代码,即可找回所搜索的操作码。
**注意**:这很容易产生误报!
标签:IDA插件, Python, Web报告查看器, Windows驱动, 云资产清单, 无后门, 逆向工具, 逆向工程