内核驱动框架
实现框架的步骤
注册卸载函数,在卸载函数中完成对设备的删除
DriverObject->DriverUnload = 卸载函数
卸载函数声明为:
typedef VOID DRIVER_UNLOAD ( _In_ struct _DRIVER_OBJECT *DriverObject ); typedef DRIVER_UNLOAD *PDRIVER_UNLOAD;
注册派遣函数
DriverObject->MajorFunction[xxx] = 派遣函数
派遣函数声明为:
typedef NTSTATUS DRIVER_DISPATCH ( _In_ struct _DEVICE_OBJECT *DeviceObject, _Inout_ struct _IRP *Irp ); typedef DRIVER_DISPATCH *PDRIVER_DISPATCH;
设置IO模式
DriverObject->Flags |= DO_BUFFERED_IO; // 缓冲区,在R0中开辟空间,复制缓冲区内容到此处 DriverObject->Flags |= DO_DIRECT_IO; // 直接,映射内存到R3的物理地址上
常用缓冲区模式,通过
Irp->AssociatedIrp.SystemBuffer
来获取内核申请的缓冲区创建设备对象
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如果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++式名称粉碎