Windows驱动开发入门-磁盘虚拟

KMDF开发入门

项目建立

建立后可能报错找不到driver.tmh文件,但能正常编译,剩下的问题同普通WDM驱动的编写。

入口函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT  DriverObject, _In_ PUNICODE_STRING RegistryPath) {
WDF_DRIVER_CONFIG config;
NTSTATUS status;
WDF_OBJECT_ATTRIBUTES attributes;
//WPP_INIT_TRACING(DriverObject, RegistryPath);
//TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.EvtCleanupCallback = KMDFDriver1EvtDriverContextCleanup;
WDF_DRIVER_CONFIG_INIT(&config, KMDFDriver1EvtDeviceAdd);
status = WdfDriverCreate(DriverObject, RegistryPath, &attributes, &config, WDF_NO_HANDLE);
if (!NT_SUCCESS(status)) {
//TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "WdfDriverCreate failed %!STATUS!", status);
//WPP_CLEANUP(DriverObject);
return status;
};
//TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
return status;
};

EvtDriverDeviceAdd

DriverEntry执行完毕后这个驱动只依靠RamDiskEvtDeviceAdd和系统保持联系了。系统再运行时一旦发现了这种类型的设备就会调用这个。

1
2
3
4
5
6
7
8
9
NTSTATUS KMDFDriver1EvtDeviceAdd(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit) {
NTSTATUS status;
UNREFERENCED_PARAMETER(Driver);
PAGED_CODE();
//TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
status = KMDFDriver1CreateDevice(DeviceInit);
//TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit");
return status;
};

EvtDriverContextCleanup

1
2
3
4
5
6
7
VOID KMDFDriver1EvtDriverContextCleanup(_In_ WDFOBJECT DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
PAGED_CODE();
//TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry");
//WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject));
return;
};

磁盘虚拟

Ramdisk驱动入口

WDF_DRIVER_CONFIG类型保存了一些驱动程序的可配置项,包括支持PnP操作所需的EvtDriverDeviceAdd函数,这个用WDF_DRIVER_CONFIG_INIT宏来进行初始化。WdfDriverCreate是使用任何WDF框架提供的函数之前必须调用的一个函数,参数分别为驱动对象、注册表路径、驱动对象属性(用WDF_NO_OBJECT_ATTRIBUTES来敷衍过去)、WDF_DRIVER_CONFIG类型变量、输出的WDF对象。

1
2
3
4
5
6
7
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
WDF_DRIVER_CONFIG config;
KdPrint(("Windows Ramdisk Driver - Driver Framework Edition.\n"));
KdPrint(("Built %s %s\n", __DATE__, __TIME__));
WDF_DRIVER_CONFIG_INIT(&config, RamDiskEvtDeviceAdd);
return WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE);
};

用户配置数据结构

这个看不懂再说,先看下面的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct _DISK_INFO {
ULONG DiskSize; // 磁盘大小 单位字节 磁盘最大只有4GB
ULONG RootDirEntries; // 磁盘上根文件系统进入节点
ULONG SectorsPerCluster; // 磁盘每个簇由多少扇区组成
UNICODE_STRING DriveLetter; // 磁盘盘符
} DISK_INFO, * PDISK_INFO;
typedef struct _DEVICE_EXTENSION {
PUCHAR DiskImage; // 指向内存盘实际数据存储空间
DISK_GEOMETRY DiskGeometry; // 内存盘的磁盘Geometry
DISK_INFO DiskRegInfo; // 自定义的磁盘信息结构 安装时存放在注册表中
UNICODE_STRING SymbolicLink; // 符号链接名
WCHAR DriveLetterBuffer[DRIVE_LETTER_BUFFER_SIZE]; //DiskRegInfo中DriverLetter存储空间 用户在注册表中指定的盘符
WCHAR DosDeviceNameBuffer[DOS_DEVNAME_BUFFER_SIZE]; //SymbolicLink的存储空间
} DEVICE_EXTENSION, * PDEVICE_EXTENSION;

发现设备时建立新设备

在WDF驱动框架中直接提供了这种处理队列,将所有发送到这个设备的请求都插入队列中,再由另一个线程去处理队列。可以分配的内存有两种:分页内存和非分页内存。分页内存可能只是个标识,实际数据可能放在磁盘上页面文件中,访问时系统发生缺页中断,再由页面管理机制将所缺页面调入内存。非分页内存不会被交换到磁盘上,永远在内存里,所以非分页内存可供分配的很少,方便起见这里都申请非分页内存。分配内存时还需要一个内存TAG值,标识这个内存是谁分配的,需要赋值为这个驱动特殊的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
NTSTATUS RamDiskEvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) {
//一些局部变量
WDF_OBJECT_ATTRIBUTES deviceAttributes; //将要建立的设备对象的属性描述变量
NTSTATUS status; //将要调用的各种函数的状态返回值
WDFDEVICE device; //将要建立的设备
WDF_OBJECT_ATTRIBUTES queueAttributes; //将要建立的队列对象的属性描述变量
WDF_IO_QUEUE_CONFIG ioQueueConfig; //将要建立的队列配置变量
PDEVICE_EXTENSION pDeviceExtension; //这个设备所对应的设备扩展域指针
PQUEUE_EXTENSION pQueueContext = NULL; //将要建立的队列扩展域指针
WDFQUEUE queue; //将要建立的队列
DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME); //声明一个UNICODE_STRING类型字符串,初始化为宏NT_DEVICE_NAME的内容
PAGED_CODE(); //保证这个函数可以操作paged内存
UNREFERENCED_PARAMETER(Driver);

//磁盘设备创建
status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName); //起个名字 要不应用层没法访问
if (!NT_SUCCESS(status))
return status;
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK); //设置设备类型 所有磁盘设备都需要这个设备类型
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); //IO类型设置为Direct 读写DeviceIoControl的IRP发送过来时所携带的缓冲区将可直接被使用
WdfDeviceInitSetExclusive(DeviceInit, FALSE); //Exclusive属性 该设备可被多次打开
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION); //指定设备对象扩展 DEVICE_EXTENSION是头文件自定义的 用这个宏来设置好
deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup; //指定这个设备的清除回调函数
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); //建立设备 保存到device中
if (!NT_SUCCESS(status))
return status;
pDeviceExtension = DeviceGetExtension(device); //指向新建立的设备的设备扩展

//处理发往设备的请求
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); //ioQueueConfig说明队列各种属性 设置为默认状态
ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl; //DeviceIoControl请求
ioQueueConfig.EvtIoRead = RamDiskEvtIoRead; //读请求
ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite; //写请求
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION); //指定队列的队列对象扩展 QUEUE_EXTENSION头文件中自定义
status = WdfIoQueueCreate(device, &ioQueueConfig, &queueAttributes, &queue); //创建队列 之前创建的对象作为对象父对象 这个设备被销毁同时队列也会被销毁
if (!NT_SUCCESS(status))
return status;
pQueueContext = QueueGetExtension(queue); //刚生成的队列扩展
pQueueContext->DeviceExtension = pDeviceExtension; //方便以后轻松获取队列对应设备扩展

//初始化用户配置
pDeviceExtension->DiskRegInfo.DriveLetter.Buffer = (PWSTR)&pDeviceExtension->DriveLetterBuffer;
pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength = sizeof(pDeviceExtension->DriveLetterBuffer);
RamDiskQueryDiskRegParameters(WdfDriverGetRegistryPath(WdfDeviceGetDriver(device)), &pDeviceExtension->DiskRegInfo); //从系统提供的注册表键中获取我们需要的信息

//链接给应用程序
pDeviceExtension->DiskImage = ExAllocatePoolWithTag(NonPagedPool, pDeviceExtension->DiskRegInfo.DiskSize, RAMDISK_TAG); //分配指定大小非分页内存 指定TAG
if (pDeviceExtension->DiskImage) { //分配成功时
UNICODE_STRING deviceName;
UNICODE_STRING win32Name;
RamDiskFormatDisk(pDeviceExtension);
status = STATUS_SUCCESS;
RtlInitUnicodeString(&win32Name, DOS_DEVICE_NAME);
//RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME); //这个没啥用 走个形式
pDeviceExtension->SymbolicLink.Buffer = (PWSTR)&pDeviceExtension->DosDeviceNameBuffer;
pDeviceExtension->SymbolicLink.MaximumLength = sizeof(pDeviceExtension->DosDeviceNameBuffer);
pDeviceExtension->SymbolicLink.Length = win32Name.Length;
RtlCopyUnicodeString(&pDeviceExtension->SymbolicLink, &win32Name);
RtlAppendUnicodeStringToString(&pDeviceExtension->SymbolicLink, &pDeviceExtension->DiskRegInfo.DriveLetter); //DosDevices后附加用户指定的盘符
status = WdfDeviceCreateSymbolicLink(device, &pDeviceExtensionSymbolicLink); //为设备建立符号链接
};
return status;
};

FAT12/16磁盘卷结构

FAT32与FAT12/16的差别不大,NTFS也就微软官方懂,下面讲解FAT12/16。

第一个扇区512字节叫MBR主引导记录,起始处是一段程序,在BIOS代码执行到最后时BIOS将程序加载到内存中并开始执行。程序后面是个硬盘分区表。MBR指向的第一个扇区为DBR,是操作系统引导记录。DBR最开始是个跳转指令,跳转到后面一点的引导程序处,是一段用来加载真正操作系统的程序。厂商标志为OEM串,由格式化程序填写。BPB数据描述区记录分区众多信息,用于系统为这个逻辑盘建立文件系统,如文件系统格式、根目录大小、簇大小等。在DBR后为FAT文件分配表区,一式两份形式连续保存,这玩意儿是个链表,表项编号代表磁盘上一个簇,表项内容是另一个簇编号。FAT12/16/32区别就在用多少位表示一个表项索引值。FAT32索引值就是4096,FAT16就是65536个簇。多个根目录入口点形成了个表,紧跟着FAT表存储,每个表项代表根目录下一个文件或一个目录,表项里记载很多相关信息如文件/目录名、属性修改日期、文件/目录在FAT表中起点等。

上述东西不会全都用到。

DISK_GEOMETRY数据结构:

1
2
3
4
5
6
7
typedef struct _DISK_GEOMETRY { //这个WDK里已经有了不用声明
LARGE_INTEGER Cylinders; //有多少柱面
MEDIA_TYPE MediaType; //磁盘介质类型
ULONG TracksPerCylinder; //每个柱面有多少磁道(磁盘面数)
ULONG SectorsPerTrack; //每个磁道有多少扇区
ULONG BytesPerSector; //每个扇区多少字节
} DISK_GEOMETRY, *PDISK_GEOMETRY;

标准DBR结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef struct  _BOOT_SECTOR{
UCHAR bsJump[3]; //跳转指令 跳转到DBR中引导程序
CCHAR bsOemName[8]; //卷OEM名称
USHORT bsBytesPerSec; //每个扇区多少字节
UCHAR bsSecPerClus; //每个簇多少扇区
USHORT bsResSectors; //保留扇区数 第一个FAT表开始前扇区数包括DBR本身
UCHAR bsFATs; //这个卷多少FAT表
USHORT bsRootDirEnts; //这个卷几个根目录入口点
USHORT bsSectors; //这个卷扇区数 大于65535时写0
UCHAR bsMedia; //这个卷介质类型
USHORT bsFATsecs; //每个FAT表占用多少扇区
USHORT bsSecPerTrack; //每个磁道多少扇区
USHORT bsHeads; //磁头数
ULONG bsHiddenSecs; //隐藏扇区数
ULONG bsHugeSectors; //扇区数超过65535写这儿
UCHAR bsDriveNumber; //驱动器编号
UCHAR bsReserved1; //保留字段
UCHAR bsBootSignature; //磁盘扩展引导区标签 Windows要求为0x28或0x29
ULONG bsVolumeID; //磁盘卷ID
CCHAR bsLabel[11]; //磁盘卷标
CCHAR bsFileSystemType[8];//磁盘上文件系统类型
CCHAR bsReserved2[448]; //保留字段
UCHAR bsSig2[2]; //DBR结束签名
} BOOT_SECTOR, * PBOOT_SECTOR;

根目录入口点数据结构:

1
2
3
4
5
6
7
8
9
10
typedef struct _DIR_ENTRY{
UCHAR deName[8]; //文件名
UCHAR deExtension[3]; //文件扩展名
UCHAR deAttributes; //文件属性
UCHAR deReserved; //系统保留
USHORT deTime; //文件建立时间
USHORT deDate; //文件建立日期
USHORT deStartCluster; //文件第一个簇编号
ULONG deFileSize; //文件大小
} DIR_ENTRY, * PDIR_ENTRY;

对磁盘映像空间进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
NTSTATUS RamDiskFormatDisk(IN PDEVICE_EXTENSION devExt){
//本地变量声明
PBOOT_SECTOR bootSector = (PBOOT_SECTOR)devExt->DiskImage; //指向磁盘启动扇区
PUCHAR firstFatSector; //指向第一个FAT表
ULONG rootDirEntries; //根目录入口点数
ULONG sectorsPerCluster; //每个簇由多少扇区组成
USHORT fatType; // FAT12还是FAT16
USHORT fatEntries; // FAT表里面共有多少个表项
USHORT fatSectorCnt; // 一个FAT表需要占用多少扇区来存储
PDIR_ENTRY rootDir; // 第一个根目录入口点
PAGED_CODE(); //确认该函数可以存取分页内存
ASSERT(sizeof(BOOT_SECTOR) == 512); //引导扇区大小确实是一个扇区大小
ASSERT(devExt->DiskImage != NULL); //确认操作的磁盘映像不是不可用指针
RtlZeroMemory(devExt->DiskImage, devExt->DiskRegInfo.DiskSize); //清空磁盘映像

//初始化DiskGeometry数据结构
devExt->DiskGeometry.BytesPerSector = 512; //每个扇区512字节
devExt->DiskGeometry.SectorsPerTrack = 32; //每个磁道32扇区
devExt->DiskGeometry.TracksPerCylinder = 2; //每个柱面2磁道
devExt->DiskGeometry.Cylinders.QuadPart = devExt->DiskRegInfo.DiskSize / 512 / 32 / 2; //柱面数由磁盘总容量计算
devExt->DiskGeometry.MediaType = RAMDISK_MEDIA_TYPE; //自定义的磁盘介质类型 :)
KdPrint(("Cylinders: %ld\n TracksPerCylinder: %ld\n SectorsPerTrack: %ld\n BytesPerSector: %ld\n",devExt->DiskGeometry.Cylinders.QuadPart, devExt->DiskGeometry.TracksPerCylinder,devExt->DiskGeometry.SectorsPerTrack, devExt->DiskGeometry.BytesPerSector));

//初始化文件系统相关参数
rootDirEntries = devExt->DiskRegInfo.RootDirEntries; //根目录项数目
sectorsPerCluster = devExt->DiskRegInfo.SectorsPerCluster; //每个簇由多少扇区
if (rootDirEntries & (DIR_ENTRIES_PER_SECTOR - 1)) //根目录入口点只使用32字节但占1个扇区 为了充分利用空间在不合适时修正这个数目 使扇区空间充分利用
rootDirEntries =(rootDirEntries + (DIR_ENTRIES_PER_SECTOR - 1)) &~(DIR_ENTRIES_PER_SECTOR - 1);
KdPrint(("Root dir entries: %ld\n Sectors/cluster: %ld\n",rootDirEntries, sectorsPerCluster));

//FAT结构体成员初始化
//跳转指令直接硬编码 Windows指定的
bootSector->bsJump[0] = 0xeb;
bootSector->bsJump[1] = 0x3c;
bootSector->bsJump[2] = 0x90;
//OEM名称成员 随便填 这里是程序作者名字
bootSector->bsOemName[0] = 'R';
bootSector->bsOemName[1] = 'a';
bootSector->bsOemName[2] = 'j';
bootSector->bsOemName[3] = 'u';
bootSector->bsOemName[4] = 'R';
bootSector->bsOemName[5] = 'a';
bootSector->bsOemName[6] = 'm';
bootSector->bsOemName[7] = ' ';
bootSector->bsBytesPerSec = (SHORT)devExt->DiskGeometry.BytesPerSector; //每个扇区多少字节
bootSector->bsResSectors = 1; //只有DBR本身一个保留扇区
bootSector->bsFATs = 1; //为了节省空间就一份FAT表 而不是一式两份
bootSector->bsRootDirEnts = (USHORT)rootDirEntries; //根目录入口点数
bootSector->bsSectors = (USHORT)(devExt->DiskRegInfo.DiskSize /devExt->DiskGeometry.BytesPerSector); //总扇区数
bootSector->bsMedia = (UCHAR)devExt->DiskGeometry.MediaType; //磁盘介质类型
bootSector->bsSecPerClus = (UCHAR)sectorsPerCluster; //每个簇多少扇区

//FAT表的表项数目
fatEntries =(bootSector->bsSectors - bootSector->bsResSectors -bootSector->bsRootDirEnts / DIR_ENTRIES_PER_SECTOR) /bootSector->bsSecPerClus + 2;
if (fatEntries > 4087) { //用FAT16
fatType = 16;
fatSectorCnt = (fatEntries * 2 + 511) / 512;
fatEntries = fatEntries + fatSectorCnt;
fatSectorCnt = (fatEntries * 2 + 511) / 512;
}
else { //用FAT12
fatType = 12;
fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
fatEntries = fatEntries + fatSectorCnt;
fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
};

//初始化DBR数据结构
bootSector->bsFATsecs = fatSectorCnt; //FAT表所占用分区数
bootSector->bsSecPerTrack = (USHORT)devExt->DiskGeometry.SectorsPerTrack; //DBR每个磁道扇区数
bootSector->bsHeads = (USHORT)devExt->DiskGeometry.TracksPerCylinder; //磁头数(每个柱面磁道数)
bootSector->bsBootSignature = 0x29; //启动签名 Windows要求0x28或0x29
bootSector->bsVolumeID = 0x12345678; //随便写个卷ID
//卷标
bootSector->bsLabel[0] = 'R';
bootSector->bsLabel[1] = 'a';
bootSector->bsLabel[2] = 'm';
bootSector->bsLabel[3] = 'D';
bootSector->bsLabel[4] = 'i';
bootSector->bsLabel[5] = 's';
bootSector->bsLabel[6] = 'k';
bootSector->bsLabel[7] = ' ';
bootSector->bsLabel[8] = ' ';
bootSector->bsLabel[9] = ' ';
bootSector->bsLabel[10] = ' ';
//文件系统
bootSector->bsFileSystemType[0] = 'F';
bootSector->bsFileSystemType[1] = 'A';
bootSector->bsFileSystemType[2] = 'T';
bootSector->bsFileSystemType[3] = '1';
bootSector->bsFileSystemType[4] = '?';
bootSector->bsFileSystemType[5] = ' ';
bootSector->bsFileSystemType[6] = ' ';
bootSector->bsFileSystemType[7] = ' ';
bootSector->bsFileSystemType[4] = (fatType == 16) ? '6' : '2';
//签署DBR结束标志0x55AA
bootSector->bsSig2[0] = 0x55;
bootSector->bsSig2[1] = 0xAA;

//FAT表初始化
firstFatSector = (PUCHAR)(bootSector + 1); //FAT表起始点 因为DBR只有一个扇区所以能这么算:)
//介质类型标识
firstFatSector[0] = (UCHAR)devExt->DiskGeometry.MediaType;
firstFatSector[1] = 0xFF;
firstFatSector[2] = 0xFF;
if (fatType == 16)
firstFatSector[3] = 0xFF;

//根目录入口点初始化
rootDir = (PDIR_ENTRY)(bootSector + 1 + fatSectorCnt); //根目录入口点表起始位置
//初始化卷标
rootDir->deName[0] = 'M';
rootDir->deName[1] = 'S';
rootDir->deName[2] = '-';
rootDir->deName[3] = 'R';
rootDir->deName[4] = 'A';
rootDir->deName[5] = 'M';
rootDir->deName[6] = 'D';
rootDir->deName[7] = 'R';
rootDir->deExtension[0] = 'I';
rootDir->deExtension[1] = 'V';
rootDir->deExtension[2] = 'E';
//入口点属性设置为卷标属性
rootDir->deAttributes = DIR_ATTR_VOLUME;
return STATUS_SUCCESS;
};

读请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
VOID RamDiskEvtIoRead(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) {
PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension; //从队列扩展中获取对应磁盘设备扩展
NTSTATUS Status = STATUS_INVALID_PARAMETER;
WDF_REQUEST_PARAMETERS Parameters; //获取请求参数
LARGE_INTEGER ByteOffset; //获取读请求起始地址变量
WDFMEMORY hMemory; //用于获取读缓冲区的内存句柄
WDF_REQUEST_PARAMETERS_INIT(&Parameters); //初始化参数变量
WdfRequestGetParameters(Request, &Parameters); //从请求参数中获取信息
ByteOffset.QuadPart = Parameters.Parameters.Read.DeviceOffset; //获取读的起始位置
if (RamDiskCheckParameters(devExt, ByteOffset, Length)) { //读取范围不超过磁盘镜像大小 扇区对齐
Status = WdfRequestRetrieveOutputMemory(Request, &hMemory); //读缓冲区内存句柄
if (NT_SUCCESS(Status))
Status = WdfMemoryCopyFromBuffer(hMemory, 0, devExt->DiskImage + ByteOffset.LowPart, Length); //内存拷贝
};
WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length); //结束这个请求
return;
};

写请求

跟上面的一模一样,不写注释了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
VOID RamDiskEvtIoWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) {
PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
WDF_REQUEST_PARAMETERS Parameters;
LARGE_INTEGER ByteOffset;
WDFMEMORY hMemory;
WDF_REQUEST_PARAMETERS_INIT(&Parameters);
WdfRequestGetParameters(Request, &Parameters);
ByteOffset.QuadPart = Parameters.Parameters.Write.DeviceOffset;
if (RamDiskCheckParameters(devExt, ByteOffset, Length)) {
Status = WdfRequestRetrieveInputMemory(Request, &hMemory);
if (NT_SUCCESS(Status))
Status = WdfMemoryCopyToBuffer(hMemory, 0, devExt->DiskImage + ByteOffset.LowPart, Length);
};
WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
return;
};

DeviceIoControl

自己实现的这些功能读写请求就够了,但是系统要发来一大堆DeviceIoControl控制请求,例如询问磁盘大小、数据处理能力等。有些无所谓的控制请求就算了,下面示例写了几个必需的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
VOID RamDiskEvtIoDeviceControl(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) {
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; //无所谓的控制请求返回这个就行
ULONG_PTR information = 0; //返回的控制请求要求的数据长度
size_t bufSize;
PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension; //同读写请求
UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(InputBufferLength);
switch (IoControlCode) {
case IOCTL_DISK_GET_PARTITION_INFO: {
PPARTITION_INFORMATION outputBuffer; //输出缓冲区指针
PBOOT_SECTOR bootSector = (PBOOT_SECTOR)devExt->DiskImage; //指向DBR指针
information = sizeof(PARTITION_INFORMATION); //要返回给上层设备的信息长度
Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PARTITION_INFORMATION), &outputBuffer, &bufSize); //获取这个请求携带的输出缓冲区
if (NT_SUCCESS(Status)) {
//随便编一些数据
outputBuffer->PartitionType = (bootSector->bsFileSystemType[4] == '6') ? PARTITION_FAT_16 : PARTITION_FAT_12;
outputBuffer->BootIndicator = FALSE;
outputBuffer->RecognizedPartition = TRUE;
outputBuffer->RewritePartition = FALSE;
outputBuffer->StartingOffset.QuadPart = 0;
outputBuffer->PartitionLength.QuadPart = devExt->DiskRegInfo.DiskSize;
outputBuffer->HiddenSectors = (ULONG)(1L);
outputBuffer->PartitionNumber = (ULONG)(-1L);
Status = STATUS_SUCCESS; //成功填充了输出缓冲区:)
};
};
break;
case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
PDISK_GEOMETRY outputBuffer;
information = sizeof(DISK_GEOMETRY);
Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(DISK_GEOMETRY), &outputBuffer, &bufSize);
if (NT_SUCCESS(Status)) {
RtlCopyMemory(outputBuffer, &(devExt->DiskGeometry), sizeof(DISK_GEOMETRY)); //就填之前设置好的磁盘几何信息 DiskGeometry
Status = STATUS_SUCCESS;
};
};
break;
case IOCTL_DISK_CHECK_VERIFY: //这俩请求不需要啥信息
case IOCTL_DISK_IS_WRITABLE:
Status = STATUS_SUCCESS;
break;
};
WdfRequestCompleteWithInformation(Request, Status, information);
return;
};

代码总览

Driver.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
#include "Driver.h"
#include "ntintsafe.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, RamDiskEvtDeviceAdd)
#pragma alloc_text(PAGE, RamDiskEvtDeviceContextCleanup)
#pragma alloc_text(PAGE, RamDiskQueryDiskRegParameters)
#pragma alloc_text(PAGE, RamDiskFormatDisk)
#endif

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
WDF_DRIVER_CONFIG config;
KdPrint(("Windows Ramdisk Driver - Driver Framework Edition.\n"));
KdPrint(("Built %s %s\n", __DATE__, __TIME__));
WDF_DRIVER_CONFIG_INIT(&config, RamDiskEvtDeviceAdd);
return WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE);
};

VOID RamDiskEvtIoRead(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) {
PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension; //从队列扩展中获取对应磁盘设备扩展
NTSTATUS Status = STATUS_INVALID_PARAMETER;
WDF_REQUEST_PARAMETERS Parameters; //获取请求参数
LARGE_INTEGER ByteOffset; //获取读请求起始地址变量
WDFMEMORY hMemory; //用于获取读缓冲区的内存句柄
WDF_REQUEST_PARAMETERS_INIT(&Parameters); //初始化参数变量
WdfRequestGetParameters(Request, &Parameters); //从请求参数中获取信息
ByteOffset.QuadPart = Parameters.Parameters.Read.DeviceOffset; //获取读的起始位置
if (RamDiskCheckParameters(devExt, ByteOffset, Length)) { //读取范围不超过磁盘镜像大小 扇区对齐
Status = WdfRequestRetrieveOutputMemory(Request, &hMemory); //读缓冲区内存句柄
if (NT_SUCCESS(Status))
Status = WdfMemoryCopyFromBuffer(hMemory, 0, devExt->DiskImage + ByteOffset.LowPart, Length); //内存拷贝
};
WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length); //结束这个请求
return;
};

VOID RamDiskEvtIoWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) {
PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension;
NTSTATUS Status = STATUS_INVALID_PARAMETER;
WDF_REQUEST_PARAMETERS Parameters;
LARGE_INTEGER ByteOffset;
WDFMEMORY hMemory;
WDF_REQUEST_PARAMETERS_INIT(&Parameters);
WdfRequestGetParameters(Request, &Parameters);
ByteOffset.QuadPart = Parameters.Parameters.Write.DeviceOffset;
if (RamDiskCheckParameters(devExt, ByteOffset, Length)) {
Status = WdfRequestRetrieveInputMemory(Request, &hMemory);
if (NT_SUCCESS(Status))
Status = WdfMemoryCopyToBuffer(hMemory, 0, devExt->DiskImage + ByteOffset.LowPart, Length);
};
WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
return;
};

VOID RamDiskEvtIoDeviceControl(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) {
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; //无所谓的控制请求返回这个就行
ULONG_PTR information = 0; //返回的控制请求要求的数据长度
size_t bufSize;
PDEVICE_EXTENSION devExt = QueueGetExtension(Queue)->DeviceExtension; //同读写请求
UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(InputBufferLength);
switch (IoControlCode) {
case IOCTL_DISK_GET_PARTITION_INFO: {
PPARTITION_INFORMATION outputBuffer; //输出缓冲区指针
PBOOT_SECTOR bootSector = (PBOOT_SECTOR)devExt->DiskImage; //指向DBR指针
information = sizeof(PARTITION_INFORMATION); //要返回给上层设备的信息长度
Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PARTITION_INFORMATION), &outputBuffer, &bufSize); //获取这个请求携带的输出缓冲区
if (NT_SUCCESS(Status)) {
//随便编一些数据
outputBuffer->PartitionType = (bootSector->bsFileSystemType[4] == '6') ? PARTITION_FAT_16 : PARTITION_FAT_12;
outputBuffer->BootIndicator = FALSE;
outputBuffer->RecognizedPartition = TRUE;
outputBuffer->RewritePartition = FALSE;
outputBuffer->StartingOffset.QuadPart = 0;
outputBuffer->PartitionLength.QuadPart = devExt->DiskRegInfo.DiskSize;
outputBuffer->HiddenSectors = (ULONG)(1L);
outputBuffer->PartitionNumber = (ULONG)(-1L);
Status = STATUS_SUCCESS; //成功填充了输出缓冲区:)
};
};
break;
case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
PDISK_GEOMETRY outputBuffer;
information = sizeof(DISK_GEOMETRY);
Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(DISK_GEOMETRY), &outputBuffer, &bufSize);
if (NT_SUCCESS(Status)) {
RtlCopyMemory(outputBuffer, &(devExt->DiskGeometry), sizeof(DISK_GEOMETRY)); //就填之前设置好的磁盘几何信息 DiskGeometry
Status = STATUS_SUCCESS;
};
};
break;
case IOCTL_DISK_CHECK_VERIFY: //这俩请求不需要啥信息
case IOCTL_DISK_IS_WRITABLE:
Status = STATUS_SUCCESS;
break;
};
WdfRequestCompleteWithInformation(Request, Status, information);
return;
};

VOID RamDiskEvtDeviceContextCleanup(IN WDFDEVICE Device) {
PDEVICE_EXTENSION pDeviceExtension = DeviceGetExtension(Device);
PAGED_CODE();
if (pDeviceExtension->DiskImage)
ExFreePool(pDeviceExtension->DiskImage);
return;
};

NTSTATUS RamDiskEvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) {
//一些局部变量
WDF_OBJECT_ATTRIBUTES deviceAttributes; //将要建立的设备对象的属性描述变量
NTSTATUS status; //将要调用的各种函数的状态返回值
WDFDEVICE device; //将要建立的设备
WDF_OBJECT_ATTRIBUTES queueAttributes; //将要建立的队列对象的属性描述变量
WDF_IO_QUEUE_CONFIG ioQueueConfig; //将要建立的队列配置变量
PDEVICE_EXTENSION pDeviceExtension; //这个设备所对应的设备扩展域指针
PQUEUE_EXTENSION pQueueContext = NULL; //将要建立的队列扩展域指针
WDFQUEUE queue; //将要建立的队列
DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME); //声明一个UNICODE_STRING类型字符串,初始化为宏NT_DEVICE_NAME的内容
PAGED_CODE(); //保证这个函数可以操作paged内存
UNREFERENCED_PARAMETER(Driver);

//磁盘设备创建
status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName); //起个名字 要不应用层没法访问
if (!NT_SUCCESS(status))
return status;
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK); //设置设备类型 所有磁盘设备都需要这个设备类型
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); //IO类型设置为Direct 读写DeviceIoControl的IRP发送过来时所携带的缓冲区将可直接被使用
WdfDeviceInitSetExclusive(DeviceInit, FALSE); //Exclusive属性 该设备可被多次打开
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION); //指定设备对象扩展 DEVICE_EXTENSION是头文件自定义的 用这个宏来设置好
deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup; //指定这个设备的清除回调函数
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); //建立设备 保存到device中
if (!NT_SUCCESS(status))
return status;
pDeviceExtension = DeviceGetExtension(device); //指向新建立的设备的设备扩展

//处理发往设备的请求
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); //ioQueueConfig说明队列各种属性 设置为默认状态
ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl; //DeviceIoControl请求
ioQueueConfig.EvtIoRead = RamDiskEvtIoRead; //读请求
ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite; //写请求
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION); //指定队列的队列对象扩展 QUEUE_EXTENSION头文件中自定义
status = WdfIoQueueCreate(device, &ioQueueConfig, &queueAttributes, &queue); //创建队列 之前创建的对象作为对象父对象 这个设备被销毁同时队列也会被销毁
if (!NT_SUCCESS(status))
return status;
pQueueContext = QueueGetExtension(queue); //刚生成的队列扩展
pQueueContext->DeviceExtension = pDeviceExtension; //方便以后轻松获取队列对应设备扩展

//初始化用户配置
pDeviceExtension->DiskRegInfo.DriveLetter.Buffer = (PWSTR)&pDeviceExtension->DriveLetterBuffer;
pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength = sizeof(pDeviceExtension->DriveLetterBuffer);
RamDiskQueryDiskRegParameters(WdfDriverGetRegistryPath(WdfDeviceGetDriver(device)), &pDeviceExtension->DiskRegInfo); //从系统提供的注册表键中获取我们需要的信息

//链接给应用程序
pDeviceExtension->DiskImage = ExAllocatePoolWithTag(NonPagedPool, pDeviceExtension->DiskRegInfo.DiskSize, RAMDISK_TAG); //分配指定大小非分页内存 指定TAG
if (pDeviceExtension->DiskImage) { //分配成功时
UNICODE_STRING deviceName;
UNICODE_STRING win32Name;
RamDiskFormatDisk(pDeviceExtension);
status = STATUS_SUCCESS;
RtlInitUnicodeString(&win32Name, DOS_DEVICE_NAME);
//RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME);
pDeviceExtension->SymbolicLink.Buffer = (PWSTR)&pDeviceExtension->DosDeviceNameBuffer;
pDeviceExtension->SymbolicLink.MaximumLength = sizeof(pDeviceExtension->DosDeviceNameBuffer);
pDeviceExtension->SymbolicLink.Length = win32Name.Length;
RtlCopyUnicodeString(&pDeviceExtension->SymbolicLink, &win32Name);
RtlAppendUnicodeStringToString(&pDeviceExtension->SymbolicLink, &pDeviceExtension->DiskRegInfo.DriveLetter); //DosDevices后附加用户指定的盘符
status = WdfDeviceCreateSymbolicLink(device, &pDeviceExtension->SymbolicLink); //为设备建立符号链接
};
return status;
};

VOID RamDiskQueryDiskRegParameters(__in PWSTR RegistryPath, __in PDISK_INFO DiskRegInfo) {
RTL_QUERY_REGISTRY_TABLE rtlQueryRegTbl[5 + 1]; // Need 1 for NULL
NTSTATUS Status;
DISK_INFO defDiskRegInfo;
PAGED_CODE();
ASSERT(RegistryPath != NULL);
defDiskRegInfo.DiskSize = DEFAULT_DISK_SIZE;
defDiskRegInfo.RootDirEntries = DEFAULT_ROOT_DIR_ENTRIES;
defDiskRegInfo.SectorsPerCluster = DEFAULT_SECTORS_PER_CLUSTER;
RtlInitUnicodeString(&defDiskRegInfo.DriveLetter, DEFAULT_DRIVE_LETTER);
RtlZeroMemory(rtlQueryRegTbl, sizeof(rtlQueryRegTbl));
rtlQueryRegTbl[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
rtlQueryRegTbl[0].Name = L"Parameters";
rtlQueryRegTbl[0].EntryContext = NULL;
rtlQueryRegTbl[0].DefaultType = (ULONG_PTR)NULL;
rtlQueryRegTbl[0].DefaultData = NULL;
rtlQueryRegTbl[0].DefaultLength = (ULONG_PTR)NULL;
rtlQueryRegTbl[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[1].Name = L"DiskSize";
rtlQueryRegTbl[1].EntryContext = &DiskRegInfo->DiskSize;
rtlQueryRegTbl[1].DefaultType = REG_DWORD;
rtlQueryRegTbl[1].DefaultData = &defDiskRegInfo.DiskSize;
rtlQueryRegTbl[1].DefaultLength = sizeof(ULONG);
rtlQueryRegTbl[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[2].Name = L"RootDirEntries";
rtlQueryRegTbl[2].EntryContext = &DiskRegInfo->RootDirEntries;
rtlQueryRegTbl[2].DefaultType = REG_DWORD;
rtlQueryRegTbl[2].DefaultData = &defDiskRegInfo.RootDirEntries;
rtlQueryRegTbl[2].DefaultLength = sizeof(ULONG);
rtlQueryRegTbl[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[3].Name = L"SectorsPerCluster";
rtlQueryRegTbl[3].EntryContext = &DiskRegInfo->SectorsPerCluster;
rtlQueryRegTbl[3].DefaultType = REG_DWORD;
rtlQueryRegTbl[3].DefaultData = &defDiskRegInfo.SectorsPerCluster;
rtlQueryRegTbl[3].DefaultLength = sizeof(ULONG);
rtlQueryRegTbl[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryRegTbl[4].Name = L"DriveLetter";
rtlQueryRegTbl[4].EntryContext = &DiskRegInfo->DriveLetter;
rtlQueryRegTbl[4].DefaultType = REG_SZ;
rtlQueryRegTbl[4].DefaultData = defDiskRegInfo.DriveLetter.Buffer;
rtlQueryRegTbl[4].DefaultLength = 0;
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, RegistryPath, rtlQueryRegTbl, NULL, NULL);
if (NT_SUCCESS(Status) == FALSE) {
DiskRegInfo->DiskSize = defDiskRegInfo.DiskSize;
DiskRegInfo->RootDirEntries = defDiskRegInfo.RootDirEntries;
DiskRegInfo->SectorsPerCluster = defDiskRegInfo.SectorsPerCluster;
RtlCopyUnicodeString(&DiskRegInfo->DriveLetter, &defDiskRegInfo.DriveLetter);
};
KdPrint(("DiskSize = 0x%lx\n", DiskRegInfo->DiskSize));
KdPrint(("RootDirEntries = 0x%lx\n", DiskRegInfo->RootDirEntries));
KdPrint(("SectorsPerCluster = 0x%lx\n", DiskRegInfo->SectorsPerCluster));
KdPrint(("DriveLetter = %wZ\n", &(DiskRegInfo->DriveLetter)));
return;
};

NTSTATUS RamDiskFormatDisk(IN PDEVICE_EXTENSION devExt){
//本地变量声明
PBOOT_SECTOR bootSector = (PBOOT_SECTOR)devExt->DiskImage; //指向磁盘启动扇区
PUCHAR firstFatSector; //指向第一个FAT表
ULONG rootDirEntries; //根目录入口点数
ULONG sectorsPerCluster; //每个簇由多少扇区组成
USHORT fatType; // FAT12还是FAT16
USHORT fatEntries; // FAT表里面共有多少个表项
USHORT fatSectorCnt; // 一个FAT表需要占用多少扇区来存储
PDIR_ENTRY rootDir; // 第一个根目录入口点
PAGED_CODE(); //确认该函数可以存取分页内存
ASSERT(sizeof(BOOT_SECTOR) == 512); //引导扇区大小确实是一个扇区大小
ASSERT(devExt->DiskImage != NULL); //确认操作的磁盘映像不是不可用指针
RtlZeroMemory(devExt->DiskImage, devExt->DiskRegInfo.DiskSize); //清空磁盘映像

//初始化DiskGeometry数据结构
devExt->DiskGeometry.BytesPerSector = 512; //每个扇区512字节
devExt->DiskGeometry.SectorsPerTrack = 32; //每个磁道32扇区
devExt->DiskGeometry.TracksPerCylinder = 2; //每个柱面2磁道
devExt->DiskGeometry.Cylinders.QuadPart = devExt->DiskRegInfo.DiskSize / 512 / 32 / 2; //柱面数由磁盘总容量计算
devExt->DiskGeometry.MediaType = RAMDISK_MEDIA_TYPE; //自定义的磁盘介质类型 :)
KdPrint(("Cylinders: %ld\n TracksPerCylinder: %ld\n SectorsPerTrack: %ld\n BytesPerSector: %ld\n",devExt->DiskGeometry.Cylinders.QuadPart, devExt->DiskGeometry.TracksPerCylinder,devExt->DiskGeometry.SectorsPerTrack, devExt->DiskGeometry.BytesPerSector));

//初始化文件系统相关参数
rootDirEntries = devExt->DiskRegInfo.RootDirEntries; //根目录项数目
sectorsPerCluster = devExt->DiskRegInfo.SectorsPerCluster; //每个簇由多少扇区
if (rootDirEntries & (DIR_ENTRIES_PER_SECTOR - 1)) //根目录入口点只使用32字节但占1个扇区 为了充分利用空间在不合适时修正这个数目 使扇区空间充分利用
rootDirEntries =(rootDirEntries + (DIR_ENTRIES_PER_SECTOR - 1)) &~(DIR_ENTRIES_PER_SECTOR - 1);
KdPrint(("Root dir entries: %ld\n Sectors/cluster: %ld\n",rootDirEntries, sectorsPerCluster));

//FAT结构体成员初始化
//跳转指令直接硬编码 Windows指定的
bootSector->bsJump[0] = 0xeb;
bootSector->bsJump[1] = 0x3c;
bootSector->bsJump[2] = 0x90;
//OEM名称成员 随便填 这里是程序作者名字
bootSector->bsOemName[0] = 'R';
bootSector->bsOemName[1] = 'a';
bootSector->bsOemName[2] = 'j';
bootSector->bsOemName[3] = 'u';
bootSector->bsOemName[4] = 'R';
bootSector->bsOemName[5] = 'a';
bootSector->bsOemName[6] = 'm';
bootSector->bsOemName[7] = ' ';
bootSector->bsBytesPerSec = (SHORT)devExt->DiskGeometry.BytesPerSector; //每个扇区多少字节
bootSector->bsResSectors = 1; //只有DBR本身一个保留扇区
bootSector->bsFATs = 1; //为了节省空间就一份FAT表 而不是一式两份
bootSector->bsRootDirEnts = (USHORT)rootDirEntries; //根目录入口点数
bootSector->bsSectors = (USHORT)(devExt->DiskRegInfo.DiskSize /devExt->DiskGeometry.BytesPerSector); //总扇区数
bootSector->bsMedia = (UCHAR)devExt->DiskGeometry.MediaType; //磁盘介质类型
bootSector->bsSecPerClus = (UCHAR)sectorsPerCluster; //每个簇多少扇区

//FAT表的表项数目
fatEntries =(bootSector->bsSectors - bootSector->bsResSectors -bootSector->bsRootDirEnts / DIR_ENTRIES_PER_SECTOR) /bootSector->bsSecPerClus + 2;
if (fatEntries > 4087) { //用FAT16
fatType = 16;
fatSectorCnt = (fatEntries * 2 + 511) / 512;
fatEntries = fatEntries + fatSectorCnt;
fatSectorCnt = (fatEntries * 2 + 511) / 512;
}
else { //用FAT12
fatType = 12;
fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
fatEntries = fatEntries + fatSectorCnt;
fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
};

//初始化DBR数据结构
bootSector->bsFATsecs = fatSectorCnt; //FAT表所占用分区数
bootSector->bsSecPerTrack = (USHORT)devExt->DiskGeometry.SectorsPerTrack; //DBR每个磁道扇区数
bootSector->bsHeads = (USHORT)devExt->DiskGeometry.TracksPerCylinder; //磁头数(每个柱面磁道数)
bootSector->bsBootSignature = 0x29; //启动签名 Windows要求0x28或0x29
bootSector->bsVolumeID = 0x12345678; //随便写个卷ID
//卷标
bootSector->bsLabel[0] = 'R';
bootSector->bsLabel[1] = 'a';
bootSector->bsLabel[2] = 'm';
bootSector->bsLabel[3] = 'D';
bootSector->bsLabel[4] = 'i';
bootSector->bsLabel[5] = 's';
bootSector->bsLabel[6] = 'k';
bootSector->bsLabel[7] = ' ';
bootSector->bsLabel[8] = ' ';
bootSector->bsLabel[9] = ' ';
bootSector->bsLabel[10] = ' ';
//文件系统
bootSector->bsFileSystemType[0] = 'F';
bootSector->bsFileSystemType[1] = 'A';
bootSector->bsFileSystemType[2] = 'T';
bootSector->bsFileSystemType[3] = '1';
bootSector->bsFileSystemType[4] = '?';
bootSector->bsFileSystemType[5] = ' ';
bootSector->bsFileSystemType[6] = ' ';
bootSector->bsFileSystemType[7] = ' ';
bootSector->bsFileSystemType[4] = (fatType == 16) ? '6' : '2';
//签署DBR结束标志0x55AA
bootSector->bsSig2[0] = 0x55;
bootSector->bsSig2[1] = 0xAA;

//FAT表初始化
firstFatSector = (PUCHAR)(bootSector + 1); //FAT表起始点 因为DBR只有一个扇区所以能这么算:)
//介质类型标识
firstFatSector[0] = (UCHAR)devExt->DiskGeometry.MediaType;
firstFatSector[1] = 0xFF;
firstFatSector[2] = 0xFF;
if (fatType == 16)
firstFatSector[3] = 0xFF;

//根目录入口点初始化
rootDir = (PDIR_ENTRY)(bootSector + 1 + fatSectorCnt); //根目录入口点表起始位置
//初始化卷标
rootDir->deName[0] = 'M';
rootDir->deName[1] = 'S';
rootDir->deName[2] = '-';
rootDir->deName[3] = 'R';
rootDir->deName[4] = 'A';
rootDir->deName[5] = 'M';
rootDir->deName[6] = 'D';
rootDir->deName[7] = 'R';
rootDir->deExtension[0] = 'I';
rootDir->deExtension[1] = 'V';
rootDir->deExtension[2] = 'E';
//入口点属性设置为卷标属性
rootDir->deAttributes = DIR_ATTR_VOLUME;
return STATUS_SUCCESS;
};

BOOLEAN RamDiskCheckParameters(IN PDEVICE_EXTENSION devExt, IN LARGE_INTEGER ByteOffset, IN size_t Length) {
if (devExt->DiskRegInfo.DiskSize < Length || ByteOffset.QuadPart < 0 || ((ULONGLONG)ByteOffset.QuadPart > (devExt->DiskRegInfo.DiskSize - Length)) || (Length & (devExt->DiskGeometry.BytesPerSector - 1))) {
KdPrint(("Error invalid parameter\n""ByteOffset: %x\n""Length: %d\n", ByteOffset, Length));
return FALSE;
};
return TRUE;
};

Driver.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#ifndef _RAMDISK_H_
#define _RAMDISK_H_
#pragma warning(disable:4201) // nameless struct/union warning
#include <ntddk.h>
#include <ntdddisk.h>
#pragma warning(default:4201)
#include <wdf.h>
#define NTSTRSAFE_LIB
#include <ntstrsafe.h>

#define NT_DEVICE_NAME L"\\Device\\Ramdisk"
#define DOS_DEVICE_NAME L"\\DosDevices\\"
#define RAMDISK_TAG 'DmaR' // "RamD"
#define DOS_DEVNAME_LENGTH (sizeof(DOS_DEVICE_NAME)+sizeof(WCHAR)*10)
#define DRIVE_LETTER_LENGTH (sizeof(WCHAR)*10)
#define DRIVE_LETTER_BUFFER_SIZE 10
#define DOS_DEVNAME_BUFFER_SIZE (sizeof(DOS_DEVICE_NAME) / 2) + 10
#define RAMDISK_MEDIA_TYPE 0xF8
#define DIR_ENTRIES_PER_SECTOR 16
#define DEFAULT_DISK_SIZE (1024*1024) // 1 MB
#define DEFAULT_ROOT_DIR_ENTRIES 512
#define DEFAULT_SECTORS_PER_CLUSTER 2
#define DEFAULT_DRIVE_LETTER L"Z:"

typedef struct _DISK_INFO {
ULONG DiskSize; // 磁盘大小 单位字节 磁盘最大只有4GB
ULONG RootDirEntries; // 磁盘上根文件系统进入节点
ULONG SectorsPerCluster; // 磁盘每个簇由多少扇区组成
UNICODE_STRING DriveLetter; // 磁盘盘符
} DISK_INFO, * PDISK_INFO;

typedef struct _DEVICE_EXTENSION {
PUCHAR DiskImage; // 指向内存盘实际数据存储空间
DISK_GEOMETRY DiskGeometry; // 内存盘的磁盘Geometry
DISK_INFO DiskRegInfo; // 自定义的磁盘信息结构 安装时存放在注册表中
UNICODE_STRING SymbolicLink; // 符号链接名
WCHAR DriveLetterBuffer[DRIVE_LETTER_BUFFER_SIZE]; //DiskRegInfo中DriverLetter存储空间 用户在注册表中指定的盘符
WCHAR DosDeviceNameBuffer[DOS_DEVNAME_BUFFER_SIZE]; //SymbolicLink的存储空间
} DEVICE_EXTENSION, * PDEVICE_EXTENSION;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, DeviceGetExtension)

typedef struct _QUEUE_EXTENSION {
PDEVICE_EXTENSION DeviceExtension;
} QUEUE_EXTENSION, * PQUEUE_EXTENSION;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_EXTENSION, QueueGetExtension)

#pragma pack(1)

typedef struct _BOOT_SECTOR{
UCHAR bsJump[3]; // x86 jmp instruction, checked by FS
CCHAR bsOemName[8]; // OEM name of formatter
USHORT bsBytesPerSec; // Bytes per Sector
UCHAR bsSecPerClus; // Sectors per Cluster
USHORT bsResSectors; // Reserved Sectors
UCHAR bsFATs; // Number of FATs - we always use 1
USHORT bsRootDirEnts; // Number of Root Dir Entries
USHORT bsSectors; // Number of Sectors
UCHAR bsMedia; // Media type - we use RAMDISK_MEDIA_TYPE
USHORT bsFATsecs; // Number of FAT sectors
USHORT bsSecPerTrack; // Sectors per Track - we use 32
USHORT bsHeads; // Number of Heads - we use 2
ULONG bsHiddenSecs; // Hidden Sectors - we set to 0
ULONG bsHugeSectors; // Number of Sectors if > 32 MB size
UCHAR bsDriveNumber; // Drive Number - not used
UCHAR bsReserved1; // Reserved
UCHAR bsBootSignature; // New Format Boot Signature - 0x29
ULONG bsVolumeID; // VolumeID - set to 0x12345678
CCHAR bsLabel[11]; // Label - set to RamDisk
CCHAR bsFileSystemType[8];// File System Type - FAT12 or FAT16
CCHAR bsReserved2[448]; // Reserved
UCHAR bsSig2[2]; // Originial Boot Signature - 0x55, 0xAA
} BOOT_SECTOR, * PBOOT_SECTOR;

typedef struct _DIR_ENTRY{
UCHAR deName[8]; //文件名
UCHAR deExtension[3]; //文件扩展名
UCHAR deAttributes; //文件属性
UCHAR deReserved; //系统保留
USHORT deTime; //文件建立时间
USHORT deDate; //文件建立日期
USHORT deStartCluster; //文件第一个簇编号
ULONG deFileSize; //文件大小
} DIR_ENTRY, * PDIR_ENTRY;

#pragma pack()

#define DIR_ATTR_READONLY 0x01
#define DIR_ATTR_HIDDEN 0x02
#define DIR_ATTR_SYSTEM 0x04
#define DIR_ATTR_VOLUME 0x08
#define DIR_ATTR_DIRECTORY 0x10
#define DIR_ATTR_ARCHIVE 0x20

DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD RamDiskEvtDeviceAdd;
EVT_WDF_DEVICE_CONTEXT_CLEANUP RamDiskEvtDeviceContextCleanup;
EVT_WDF_IO_QUEUE_IO_READ RamDiskEvtIoRead;
EVT_WDF_IO_QUEUE_IO_WRITE RamDiskEvtIoWrite;
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL RamDiskEvtIoDeviceControl;

VOID RamDiskQueryDiskRegParameters(__in PWSTR RegistryPath,__in PDISK_INFO DiskRegInfo);
NTSTATUS RamDiskFormatDisk(IN PDEVICE_EXTENSION DeviceExtension);
BOOLEAN RamDiskCheckParameters(IN PDEVICE_EXTENSION devExt,IN LARGE_INTEGER ByteOffset,IN size_t Length);

#endif

其他Device、Public、Queue、Trace等.c和.h就保持模板默认就好。