1

Windows 驱动开发入门

 1 year ago
source link: https://paper.seebug.org/2063/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

作者:0x7F@知道创宇404实验室
时间:2023年4月18日

0x00 前言

随着 windows 系统的更新迭代,windows 驱动开发技术也是不断的升级:从最早期的 VXD(Virtual X Driver)(已废弃)到 windows 2000 上推出的 WDM(Windows Driver Model)驱动模型,随后从 windows vista 推出的 WDF(Windows Driver Foudation)驱动模型,沿用至今;WDF 是 WDM 的升级版,并且在一定程度上兼容,WDF 是微软目前推荐的驱动开发模型。

WDF 还可以细分为内核模式 KMDF(Kernel-Mode Driver Framework) 和用户模式 UMDF(User-Mode Driver Framework),顾名思义 UMDF 将受到更多的限制从而换来更高的操作系统稳定性,其二进制扩展名为 *.dll;UMDF 和 KMDF 开发基本相同,本文这里仅介绍使用更广泛的 KMDF 开发。

本文实验环境

windows 10 专业版 x64 1909
Visual Studio 2019
SDK 10.0.19041.685
WDK 10.0.19041.685

0x01 搭建驱动开发环境

首先配置 Visual Studio 2019 的 C/C 开发环境(https://visualstudio.microsoft.com/),按 Visual Studio 官方教程,自动下载安装「使用C的桌面开发」,其中 SDK 默认为 10.0.19041.0

1.安装VisualStudio

开发软件需要 SDK(Software Development Kit),而开发 windows 驱动则需要 WDK(Windows Driver Kit);现在我们来配置 WDK 环境,从官网(https://learn.microsoft.com/zh-cn/windows-hardware/drivers/download-the-wdk)下载 WDK 在线安装包(版本必须和 SDK 一致),按如下进行安装:

对于 WDF 驱动模型其开发环境叫 WDK(Windows Driver Kit)
对于 WDM 驱动模型其开发环境叫 DDK(Driver Development Kit)

2.安装WDK

安装完毕后,其窗口会默认勾选为 Visual Studio 安装 WDK 扩展插件,按照指导进行安装即可,随后我们可以在 Visual Studio 的创建项目页面,就看到 KMDF/UMDF 等选项,表示 windows 驱动开发环境配置成功。

3.vs创建kmdf项目

windows 驱动开发环境可能会受操作系统、Visual Studio、SDK、WDK 的版本影响,配置过程需要多留心这些环节,如遇见问题可以参考如下版本信息 https://learn.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads。

0x02 HelloWorld开发

根据官方教程,我们在 Visual Studio 中创建空的 KMDF 项目,并在其中创建 Driver.c 文件,编写代码如下:

#include <ntddk.h>
#include <wdf.h>
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT     DriverObject,
    _In_ PUNICODE_STRING    RegistryPath
)
{
    // NTSTATUS variable to record success or failure
    NTSTATUS status = STATUS_SUCCESS;

    // Allocate the driver configuration object
    WDF_DRIVER_CONFIG config;

    // Print "Hello World" for DriverEntry
    KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n"));

    // Initialize the driver configuration object to register the
    // entry point for the EvtDeviceAdd callback, KmdfHelloWorldEvtDeviceAdd
    WDF_DRIVER_CONFIG_INIT(&config,
        KmdfHelloWorldEvtDeviceAdd
    );

    // Finally, create the driver object
    status = WdfDriverCreate(DriverObject,
        RegistryPath,
        WDF_NO_OBJECT_ATTRIBUTES,
        &config,
        WDF_NO_HANDLE
    );
    return status;
}

NTSTATUS
KmdfHelloWorldEvtDeviceAdd(
    _In_    WDFDRIVER       Driver,
    _Inout_ PWDFDEVICE_INIT DeviceInit
)
{
    // We're not using the driver object,
    // so we need to mark it as unreferenced
    UNREFERENCED_PARAMETER(Driver);

    NTSTATUS status;

    // Allocate the device object
    WDFDEVICE hDevice;

    // Print "Hello World"
    KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n"));

    // Create the device object
    status = WdfDeviceCreate(&DeviceInit,
        WDF_NO_OBJECT_ATTRIBUTES,
        &hDevice
    );
    return status;
}

在「配置管理器」中设置为 Debug/x64,编译生成项目发现如下错误:

4.spectre缓解设置

Visual Studio 默认开启了缓解 Spectre 攻击的机制,可在 VS 安装器中选择安装指定的支持库,我们实验环境下可以直接关闭该功能,在 项目属性-C/C++-代码生成-Spectre Mitigation 设置为 Disable

5.spectre缓解设置

随后便可以成功编译,在 [src]/x64/Debug/ 下,可以看到生成的二进制文件 KmdfHelloWorld.sys

0x03 部署和测试

驱动程序一般以服务(service)或设备(device)的方式运行工作,这点和普通应用程序不同,所以不能像应用程序那样进行调试和测试。官方指导中提供一种基于双机调试环境的驱动调试方法,这种方式较为繁琐,我们这里进行简要介绍;想了解更方便的本机调试驱动程序的小伙伴,可跳转至「0x04 本机调试驱动程序」。

按照官方指导,我们将驱动程序作为设备进行运行调试,在此之前需要再提供一台主机作为被调试机(debugee),驱动程序将在被调试机上(debugee)进行部署和测试,而本台主机即作为开发主机同时作为调试机(debugger),如下:

6.网络双机调试环境

首先在被调试机(debugee)上也安装上 WDK 环境,随后在 WDK 的安装目录下运行该工具 WDK Test Target Setup,默认路径:C:\Program Files (x86)\Windows Kits\10\Remote\x64\WDK Test Target Setup x64-x64_en-us.msi;在之后调试机(debugger)中的 Visual Studio 将连接被调试机(debugee)的 WDK Test Target Setup 的工具,自动完成双机调试环境的配置。

在开发主机上(debugger)初始化被调试机的相关信息,在 项目属性-Driver Install-Deployment 中添加新设备,我们这里使用网络双机调试的方式,默认参数即可:

7.初始化被调试机信息

随后将自动完成配置,如下:

8.自动配置双机调试环境

Visual Studio 中将被调试机(debugee)添加完毕后,在如下窗口选择该主机并设置驱动的硬件 ID 为 Root\KmdfHelloWorld,如下:

9.配置目标设备信息

配置完成后,我们在 Visual Studio 菜单中 生成-部署解决方案,驱动程序将自动部署在被调试机上(debugee)并进行测试运行:

10.vs自动部署驱动程序

在被调试机(debugee)上我们在设备管理器中可以看到 KmdfHelloWorld 已经成功部署了:

11.部署和测试驱动程序

如果想调试驱动程序,则可以使用 WinDBG 依据以上的双机调试环境对驱动程序进行调试。

12.windbg查看驱动模块

0x04 本机调试驱动程序

官方提供的驱动程序部署和测试方法,虽然有效的隔离开发环境和调试环境,但实在是过于繁琐了,更不用说其中双机调试环境下的各种问题。而驱动程序还可以以服务的方式进行运行,我们通过这种方式可以更加方便的在本机调试驱动程序。

在日常安全工作中,我更喜欢使用这种方式,因为大多数情况我只需要工作在内核层的驱动代码,而不关心其是否是完整的 windows 驱动设备,这种方式能帮助我快速进行安全验证工作。

创建 KMDF 项目并编写代码如下:

#include <ntddk.h>
#include <wdf.h>

VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
    UNREFERENCED_PARAMETER(DriverObject);
    KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "test: unload driver\n"));
}

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT     DriverObject,
    _In_ PUNICODE_STRING    RegistryPath
)
{
    UNREFERENCED_PARAMETER(DriverObject);
    UNREFERENCED_PARAMETER(RegistryPath);

    KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "test: driver entry\n"));

    DriverObject->DriverUnload = OnUnload;

    return STATUS_SUCCESS;
}

在「配置管理器」中设置为 Debug/x64,编译生成项目。

在运行测试前,我们需要在本机(即开发主机)上打开测试模式(重启生效),使得操作系统可以加载我们编译的驱动程序,使用管理员权限打开 powershell:

# 打开测试模式
bcdedit /set testsigning on

重启主机后,使用管理员权限打开 powershell,通过 sc.exe 命令为驱动程序创建服务(命令详解请参考:https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/sc-create):

# 创建服务名为 test,类型为 kernel,启动方式为 demand 的服务,并指定驱动程序路径
# (注意参数等号后必须有一个空格)
sc.exe create test type= kernel start= demand binPath= C:\Users\john\Desktop\workspace\kmdf_test\x64\Debug\kmdf_test\kmdf_test.sys

# 使用 queryex 查看创建的服务信息
sc.exe queryex test

创建服务如下:

13.sc.exe创建服务

随后便可以使用 sc.exe 命令启动驱动程序运行,并使用 DebugView 查看调试输出(需要勾选 Capture KernelEnable Verbose Kernel Output 才能看到输出):

# 启动运行驱动程序
sc.exe start test
# 停止运行驱动程序
sc.exe stop test

运行如下:

14.sc.exe启动和停止服务

当我们更新了驱动代码、编译项目后,可以再次 start/stop 这个服务,便可以快捷的进行驱动程序代码的测试和调试。

0x05 References

https://learn.microsoft.com/zh-cn/windows-hardware/drivers/gettingstarted/
https://github.com/microsoft/Windows-driver-samples
https://visualstudio.microsoft.com/
https://learn.microsoft.com/zh-cn/windows-hardware/drivers/download-the-wdk
https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/sc-create


Paper 本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/2063/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK