Windows驱动框架

@lzeroyuee  May 2, 2020

内核驱动框架

实现框架的步骤

  1. 注册卸载函数,在卸载函数中完成对设备的删除

    DriverObject->DriverUnload = 卸载函数

    卸载函数声明为:

    typedef
    VOID
    DRIVER_UNLOAD (
        _In_ struct _DRIVER_OBJECT *DriverObject
        );
    typedef DRIVER_UNLOAD *PDRIVER_UNLOAD;
  2. 注册派遣函数

    DriverObject->MajorFunction[xxx] = 派遣函数

    派遣函数声明为:

    typedef
    NTSTATUS
    DRIVER_DISPATCH (
        _In_ struct _DEVICE_OBJECT *DeviceObject,
        _Inout_ struct _IRP *Irp
        );
    typedef DRIVER_DISPATCH *PDRIVER_DISPATCH;
  3. 设置IO模式

    DriverObject->Flags |= DO_BUFFERED_IO;     // 缓冲区,在R0中开辟空间,复制缓冲区内容到此处
    DriverObject->Flags |= DO_DIRECT_IO;     // 直接,映射内存到R3的物理地址上

    常用缓冲区模式,通过Irp->AssociatedIrp.SystemBuffer来获取内核申请的缓冲区

  4. 创建设备对象

    IoCreateDevice函数,指定内核设备FILE_DEVICE_UNKNOWN

    NTSTATUS IoCreateDevice(
        PDRIVER_OBJECT DriverObject,     // 驱动对象的指针
        ULONG DeviceExtensionSize,         // 设备扩展大小
        PUNICODE_STRING DeviceName,     // Nt设备名
        DEVICE_TYPE DeviceType,         // 设备类型,FILE_DEVICE_UNKNOWN为内核设备
        ULONG DeviceCharacteristics,     // 指定一个或多个系统定义的常量,它们一起提供有关驱动程序设备的附加信息
        BOOLEAN Exclusive,                 // 指定设备对象是否表示独占设备,大多数情况是FALSE
        PDEVICE_OBJECT *DeviceObject     // 传出参数,PDEVICE_OBJECT的指针
    );

    Nt设备名格式: \Device\DeviceName ,参考:https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/nt-device-names

  5. 如果R3需要交互,则为设备对象创建一个符号链接

    // 创建符号链接
    NTSTATUS IoCreateSymbolicLink(
        PUNICODE_STRING SymbolicLinkName,     // 符号链接名
        PUNICODE_STRING DeviceName             // 设备名
    );
    
    // 删除符号链接
    NTSTATUS IoDeleteSymbolicLink(
        PUNICODE_STRING SymbolicLinkName     // 符号链接名
    );

    符号链接名格式:\DosDevices\DosDeviceName或者\??\DosDeviceName ,参考:https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-ms-dos-device-names

派遣函数

派遣函数的原型为:

typedef
NTSTATUS
DRIVER_DISPATCH (
    _In_ struct _DEVICE_OBJECT *DeviceObject,     // 设备对象
    _Inout_ struct _IRP *Irp                     // IO请求包
);
typedef DRIVER_DISPATCH *PDRIVER_DISPATCH;

IRP

IO请求包(IO Request Packet),属于派遣函数的第二个参数

  • 完成请求:IoCompleteRequest

    • 常用,需要填写Irp参数信息:Irp->IoStatus.Infomation操作的字节数、Irp->IoStatus.Status
      操作的状态
  • 异步回调:IoSetCompletionRoutine

每个派遣函数在返回之前都要设置IO完成状态,不然R3那边会阻塞(在同步的情况下)

实现框架

protocol.h头文件中,定义R0和R3的驱动设备名、符号链接名,并且自定义MY_CODE宏封装操作码

/********************************protocol.h***************************************/
#ifndef __PROTOCOL_H__
#define __PROTOCOL_H__

// 驱动中使用
#define MY_DEVICE_NAME TEXT("\\Device\\MyDevice-abc")           // 设备名
#define MY_SYMBOL_NAME TEXT("\\DosDevices\\MyDevice-abc")       // 符号名

// 应用程序中使用
#define MY_DRIVER_FILE "MyHunterDriver.sys"         // 驱动文件名
#define MY_SYMBOL_FILE TEXT("\\\\.\\MyDevice-abc")  // 符号连接名

//自定义操作码宏
#define MY_CODE(function) CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800 + (function), METHOD_BUFFERED, FILE_ANY_ACCESS)

#endif

MyDriver.h头文件中,声明函数原型

/********************************MyDriver.h***************************************/
#pragma once
#include <Ntddk.h>
#include "protocol.h"

// 入口函数
DRIVER_INITIALIZE DriverEntry;

// 卸载函数
DRIVER_UNLOAD DriverUnload;

// 创建
NTSTATUS
MyDispatchCreate(
    _In_ struct _DEVICE_OBJECT *DeviceObject,
    _Inout_ struct _IRP *Irp
);

// 控制
NTSTATUS
MyDispatchControl(
    _In_ struct _DEVICE_OBJECT *DeviceObject,
    _Inout_ struct _IRP *Irp
);

// 关闭
NTSTATUS
MyDispatchClose(
    _In_ struct _DEVICE_OBJECT *DeviceObject,
    _Inout_ struct _IRP *Irp
);

// 将函数放入分页内存中
#pragma alloc_text("INIT", DriverEntry)
#pragma alloc_text("PAGE", DriverUnload)
#pragma alloc_text("PAGE", MyDispatchCreate)
#pragma alloc_text("PAGE", MyDispatchControl)
#pragma alloc_text("PAGE", MyDispatchClose)

MyDriver.c中,实现驱动框架

/********************************MyDriver.c**************************************/
#include <Ntddk.h>
#include "MyDriver.h"

// 入口函数
_Use_decl_annotations_
NTSTATUS
DriverEntry(struct _DRIVER_OBJECT* DriverObject, PUNICODE_STRING  RegistryPath)
{
    KdBreakPoint();
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Hello Kernel! - Install\n");

    // 注册卸载函数
    DriverObject->DriverUnload = DriverUnload;

    // 注册派遣函数
    DriverObject->MajorFunction[IRP_MJ_CREATE] = MyDispatchCreate;              // 创建
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyDispatchControl;     // 控制
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyDispatchClose;                // 关闭

    // 设置IO模式
    DriverObject->Flags |= DO_BUFFERED_IO;   // 复制缓冲区,在R0中开辟空间,复制缓冲区内容到此处

    NTSTATUS status;    // 返回状态

    // 创建设备对象,一般为IO管理器管理,内核设备FILE_DEVICE_UNKNOWN
    UNICODE_STRING driver_name;
    RtlInitUnicodeString(&driver_name, MY_DEVICE_NAME);
    PDEVICE_OBJECT device_object_ptr = NULL;
    status = IoCreateDevice(DriverObject, 0, &driver_name, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &device_object_ptr);

    if(!NT_SUCCESS(status)) {
        DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "IoCreateDevice Error: %p\n", status);
        return status;
    }

    // 创建符号连接
    UNICODE_STRING symbo_name;
    RtlInitUnicodeString(&symbo_name, MY_SYMBOL_NAME);
    status = IoCreateSymbolicLink(&symbo_name, &driver_name);

    if (!NT_SUCCESS(status)) {
        DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "IoCreateSymbolicLink Error: %p\n", status);
        return status;
    }

    return STATUS_SUCCESS;
}


// 卸载驱动
void DriverUnload(struct _DRIVER_OBJECT* DriverObject)
{
    // 删除设备
    IoDeleteDevice(DriverObject->DeviceObject);     // 这是个链表,多个设备对象时就需要遍历了

    // 删除符号链接,如果有的话
    UNICODE_STRING symbo_name;
    RtlInitUnicodeString(&symbo_name, MY_SYMBOL_NAME);
    IoDeleteSymbolicLink(&symbo_name);

    DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Hello Kernel! - UnInstall\n");
}


// 创建
NTSTATUS
MyDispatchCreate(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
{
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Dispatch: [MyDispatchCreate]\n");

    // 完成请求
    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}

// 控制
NTSTATUS
MyDispatchControl(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
{
    KdBreakPoint();
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Dispatch: [MyDispatchControl]\n");

    NTSTATUS Status = STATUS_SUCCESS;
    ULONG_PTR Information = 0;
    
    PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation(Irp);                  // 获取Irp堆栈
    ULONG input_length = stack_location->Parameters.DeviceIoControl.InputBufferLength;      // 获取输入缓冲区长度
    ULONG output_length = stack_location->Parameters.DeviceIoControl.OutputBufferLength;    // 获取输出缓冲区长度
    ULONG control_code = stack_location->Parameters.DeviceIoControl.IoControlCode;          // 控制码
    PVOID systembuff = Irp->AssociatedIrp.SystemBuffer;                                     // 内核缓冲区


    // 具体工作任务
    switch(control_code) {
    default:
        break;
    }

    // 完成请求
    Irp->IoStatus.Information = Information;
    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}

// 关闭
NTSTATUS
MyDispatchClose(_In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp)
{
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Dispatch: [MyDispatchClose]\n");

    // 完成请求
    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;
}

如果使用C++,需要使用extern "C"包含函数原型以免C++式名称粉碎


添加新评论