警告:一定要在VMWare Workstation、VirtualBox等虚拟机中测试,不要在工作用机中加载编译的驱动程序
内核模式驱动程序非常危险,可能造成蓝屏死机,重要数据损坏丢失,Windows系统损坏,甚至硬件烧毁等严重后果
编译这个驱动需要安装DDK或WDK,编译方法是打开DDK或WDK命令提示,然后cd切换到所在目录执行build命令。
MAKEFILE
从DDK或WDK自带的示例中复制一个即可
SOURCES
<code class="language-makefile">TARGETNAME=mydrv1
TARGETTYPE=DRIVER
TARGETPATH=OBJ
INCLUDES=$(BASEDIR)\inc;\
$(BASEDIR)\inc\ddk
SOURCES=mydrv1.cpp
</code>
头文件
<code class="language-cpp">#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// 包含头文件
#include <ntddk.h>
//#include <wdm.h>
#ifdef __cplusplus
}
#endif
// 代码段定义
#define PAGEDCODE code_seg("PAGE") // 分页代码段(IRQL<=apc_level) #define lockedcode code_seg() 锁定代码段 initcode code_seg("init") 初始化代码段(初始化结束就卸载) 数据段定义 pageddata data_seg("page") 分页数据段(irql<="APC_LEVEL)" lockeddata data_seg() 锁定数据段 initdata data_seg("init") 初始化数据段(初始化结束就卸载) 获取数组大小 arraysize(p) (sizeof(p) sizeof((p)[0])) 自定义的设备附加数据 typedef struct _device_extension { pdevice_object pdevice; 指向当前设备对象 unicode_string ustrdevicename; 设备对象名称 ustrsymlinkname; 设备链接名称 } device_extension, *pdevice_extension; 函数声明 创建设备 ntstatus createdevice(in pdriver_object pdriverobject); 驱动卸载函数 void helloddkunload(in 默认分发函数 defdispatchroutine(pdevice_object pdevobj, pirp pirp); deviceiocontorl分发函数 ioctldispatchroutine(in deviceiocontrol控制码(未知设备,控制码0x800,缓冲的,任何访问权限) ioctl1 ctl_code(file_device_unknown,0x800,method_buffered,file_any_access) < code></=apc_level)></wdm.h></ntddk.h></code>
CPP源文件
<code class="language-cpp">#include "mydrv1.h"
#pragma INITCODE
// 驱动程序入口点
extern "C" NTSTATUS DriverEntry(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS status;
KdPrint(("Enter DriverEntry\n"));
// 设定卸载函数和分发函数
pDriverObject->DriverUnload = HelloDDKUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = // CreateFile
pDriverObject->MajorFunction[IRP_MJ_READ] = // ReadFile
pDriverObject->MajorFunction[IRP_MJ_WRITE] = // WriteFile
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DefDispatchRoutine; // CloseHandle
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoctlDispatchRoutine; // DeviceIoControl
// 创建设备
status = CreateDevice(pDriverObject);
KdPrint(("DriverEntry end\n"));
return status;
}
#pragma INITCODE
// 创建设备
NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
KdPrint(("Enter CreateDevice\n"));
// 初始化设备对象名(\Device\MyDDKDevice)
UNICODE_STRING devName;
RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice");
// 创建设备对象
status = IoCreateDevice(pDriverObject, // 驱动对象
sizeof (DEVICE_EXTENSION), // 设备附加数据大小
&(UNICODE_STRING)devName, // 设备对象名称
FILE_DEVICE_UNKNOWN, // 未知设备类别
0, // 设备特征
TRUE, // 独占设备
&pDevObj); // 返回PDEVICE_OBJECT
if (!NT_SUCCESS(status))
return status; // 创建失败,结束操作
// 设置进行缓冲的I/O
pDevObj->Flags |= DO_BUFFERED_IO;
// 设置设备附加数据
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevExt->pDevice = pDevObj;
pDevExt->ustrDeviceName = devName;
// 初始化设备链接名(\??\HelloDDK == \DosDevice\HelloDDK)
// 在Win32中被映射为\\.\HelloDDK
UNICODE_STRING symLinkName;
RtlInitUnicodeString(&symLinkName, L"\\??\\HelloDDK");
// 将设备链接名保存到设备附加数据
pDevExt->ustrSymLinkName = symLinkName;
// 创建设备链接
status = IoCreateSymbolicLink(&symLinkName, &devName);
if (!NT_SUCCESS(status)) // 创建失败
{
IoDeleteDevice(pDevObj); // 删除设备对象
return status; // 结束操作
}
KdPrint(("CreateDevice end\n"));
return STATUS_SUCCESS;
}
#pragma PAGEDCODE
// 卸载驱动程序
VOID HelloDDKUnload(IN PDRIVER_OBJECT pDriverObject)
{
PAGED_CODE(); // 检验IRQL(Checked Build)
KdPrint(("Enter DriverUnload\n"));
// 查找驱动程序建立的所有设备对象并删除
PDEVICE_OBJECT pNextObj;
pNextObj = pDriverObject->DeviceObject;
while (pNextObj != NULL)
{
// 获取设备附加数据(保存有符号链接名)
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pNextObj->DeviceExtension;
// 删除符号链接
UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
IoDeleteSymbolicLink(&pLinkName);
// 查找下一个设备对象
pNextObj = pNextObj->NextDevice;
// 删除当前设备对象
IoDeleteDevice(pDevExt->pDevice);
}
KdPrint(("DriverUnload end\n"));
}
#pragma PAGEDCODE
// 默认分发函数
NTSTATUS DefDispatchRoutine(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
PAGED_CODE(); // 检查IRQL(Checked Build)
KdPrint(("Enter DefDispatchRoutine\n"));
// 成功完成I/O请求
NTSTATUS status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0; // 处理0字节
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("DefDispatchRoutine end\n"));
return status;
}
// DeviceIoControl分发函数
NTSTATUS IoctlDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
PAGED_CODE(); // 检查IRQL(Checked Build)
KdPrint(("Enter IoctlDispatchRoutine\n"));
NTSTATUS status = STATUS_SUCCESS;
// 从I/O请求包中获取对应于当前驱动的I/O请求
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
// 获取DeviceIoControl相关信息
ULONG in_size = stack->Parameters.DeviceIoControl.InputBufferLength; // 输入缓冲区大小
ULONG out_size = stack->Parameters.DeviceIoControl.OutputBufferLength; // 输出缓冲区大小
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; // 控制码
char *buffer = (char*)pIrp->AssociatedIrp.SystemBuffer; // 系统复制的缓冲区(既输入又输出)
ULONG retsize = 0;
switch (code) // 分析控制码
{
case IOCTL1:
KdPrint(("Get ioctl code 1\n"));
if (out_size < in_size + 11 || in_size < 1)
{
status = STATUS_BUFFER_TOO_SMALL; // 缓冲区太小
retsize = 0;
break;
}
RtlMoveMemory(buffer + in_size - 1, " UPPER CASE", 12); // 追加字符串
retsize = in_size + 11; // 增加11个字节
break;
default:
status = STATUS_INVALID_VARIANT; // 非法控制码
retsize = 0;
}
// 完成请求
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = retsize;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
KdPrint(("IoctlDispatchRoutine end\n"));
return status;
}
</code>
200字以内,仅用于支线交流,主线讨论请采用回复功能。