微软的wdk开发包里自带了一些sample,这是些质量不错并且权威的学习资料,最好的学习驱动的方法就是阅读和修改这些代码。其中Ramdisk实现了一个虚拟磁盘,可以作为WDF编程的经典代码材料,《寒江独钓-Windows内核安全编程》第5章“磁盘的虚拟”便以此为例,这篇博客是一篇学习总结。
驱动的入口函数很简洁:
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
WDF_DRIVER_CONFIG config;
KdPrint(("Windows Ramdisk Driver - Driver Framework Edition.\n"));
WDF_DRIVER_CONFIG_INIT( &config, RamDiskEvtDeviceAdd );
return WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE);
}
上面代码最主要的任务就是创建一个“驱动对象”并马上返回了,我们看WDF_DRIVER_CONFIG这个玩意:
typedef struct _WDF_DRIVER_CONFIG {
ULONG Size; //这个结构体的大小,以自己为单位;
PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; //Windows驱动的EvtDriverDeviceAdd回调函数指针;
PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; //Windows驱动的EvtDriverUnload回调函数指针;
ULONG DriverInitFlags; //驱动初始化标志位,由一个或者多个WDF_DRIVER_INIT_FLAGS类型值构成;
ULONG DriverPoolTag; //驱动定义的内存池标签,是Framework分配给驱动的内存标签。调试时可以显示这个标签。
} WDF_DRIVER_CONFIG, *PWDF_DRIVER_CONFIG;
上面的WDF_DRIVER_CONFIG_INIT( &config, RamDiskEvtDeviceAdd );其实就是把 RamDiskEvtDeviceAdd 赋给结构体的第2项。上面有注释,它是一个回调函数指针,注意这是一个非常重要的参数,因为创建完驱动对象后主函数就返回了,而这个回调函数是后面驱动和系统联系起来的唯一纽带,在今后系统运行过程中,一旦发现了此类设备, RamDiskEvtDeviceAdd就会被 Windows 的PnP manager调用,这个驱动的处理流程也将在此后上演。
接下来看 RamDiskEvtDeviceAdd 这个函数:
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);
PAGED_CODE();
UNREFERENCED_PARAMETER(Driver); //此函数不使用Driver参数,加这句为避免编译告警
status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName); //1.为设备指定名字
if (!NT_SUCCESS(status)) {
return status;
}
//2.设置设备的一些属性
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
WdfDeviceInitSetExclusive(DeviceInit, FALSE);
//指定设备的设备对象扩展
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION);
deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup; //建立设备的清除回调函数
//3.创建设备
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
if (!NT_SUCCESS(status)) {
return status;
}
//声明一个指向设备扩展的指针
pDeviceExtension = DeviceGetExtension(device);
//将队列的配置变量初始化为默认值
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE (
&ioQueueConfig,
WdfIoQueueDispatchSequential
);
//设置我们感兴趣的请求的处理函数,这里处理了Read/Write/DeviceIoControl请求
ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl;
ioQueueConfig.EvtIoRead = RamDiskEvtIoRead;
ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION); //指定一下队列的队列对象扩展
__analysis_assume(ioQueueConfig.EvtIoStop != 0);
status = WdfIoQueueCreate( device, //4.用初始化好的参数创建队列
&ioQueueConfig,
&queueAttributes,
&queue );
__analysis_assume(ioQueueConfig.EvtIoStop == 0);
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
);
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);
//5.为设备建立符号链接,即DOS_DEVICE_NAME+注册表中读取的盘符
status = WdfDeviceCreateSymbolicLink(device,
&pDeviceExtension->SymbolicLink);
}
return status;
}
上面代码注释的已经比较清晰,再简要描述一下我们做了什么。
首先创建一个“驱动对象”,并设置一个 RamDiskEvtDeviceAdd 回调函数,这个回调函数很重要,它是驱动和系统相联系的纽带。在 RamDiskEvtDeviceAdd 函数里面,最重要的任务便是建立一个“设备对象”,在这之后各种请求就会纷至踏来。而如何处理这些请求呢,一种常用的方式就是使用队列,把接收到的请求放入一个或多个队列中,另一个线程去处理这些队列,这是一个典型的生产者——消费者模型。为了方便我们编程,微软实现了这个轮子,这显然比我们自己处理方便许多,这里用到了“队列对象”。
目前为止我们用到了3个内核对象,分别是“驱动对象”,“设备对象”,“队列对象”,现在来总结一下他们有没有共性。
1.“对象”都有可配置的属性,如“驱动对象”通过WDF_DRIVER_CONFIG变量,“设备对象”和“队列对象”的WDF_OBJECT_ATTRIBUTES变量,“队列对象”的WDF_IO_QUEUE_CONFIG变量。
2.正确处理这上述“对象”结构的各个成员,那么驱动就实现它的功能了,这是使用框架开发带来的便捷。我们的编程工作最终就变成了:创建一个个“对象”,并妥善处理好它们。
现在我们还有几个问题没有处理,一是初始化磁盘的业务逻辑部分,二是请求的处理部分,三是设备的清除回调函数部分,下面分别说明。
初始化磁盘属于业务逻辑,与我们想要说明的WDF编程框架并没有联系,所以不作代码注释,如下:
NTSTATUS
RamDiskFormatDisk(
IN PDEVICE_EXTENSION devExt
)
{
PBOOT_SECTOR bootSector = (PBOOT_SECTOR) devExt->DiskImage;
PUCHAR firstFatSector;
ULONG rootDirEntries;
ULONG sectorsPerCluster;
USHORT fatType; // Type FAT 12 or 16
USHORT fatEntries; // Number of cluster entries in FAT
USHORT fatSectorCnt; // Number of sectors for FAT
PDIR_ENTRY rootDir; // Pointer to first entry in root dir
PAGED_CODE();
ASSERT(sizeof(BOOT_SECTOR) == 512);
ASSERT(devExt->DiskImage != NULL);
RtlZeroMemory(devExt->DiskImage, devExt->DiskRegInfo.DiskSize);
devExt->DiskGeometry.BytesPerSector = 512;
devExt->DiskGeometry.SectorsPerTrack = 32; // Using Ramdisk value
devExt->DiskGeometry.TracksPerCylinder = 2; // Using Ramdisk value
devExt->DiskGeometry.Cylinders.QuadPart = devExt->DiskRegInfo.DiskSize / 512 / 32 / 2;
devExt->DiskGeometry.MediaType = RAMDISK_MEDIA_TYPE;
KdPrint((
"Cylinders: %I64d\n TracksPerCylinder: %lu\n SectorsPerTrack: %lu\n BytesPerSector: %lu\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)) {
rootDirEntries =
(rootDirEntries + (DIR_ENTRIES_PER_SECTOR - 1)) &
~ (DIR_ENTRIES_PER_SECTOR - 1);
}
KdPrint((
"Root dir entries: %lu\n Sectors/cluster: %lu\n",
rootDirEntries, sectorsPerCluster
));
bootSector->bsJump[0] = 0xeb;
bootSector->bsJump[1] = 0x3c;
bootSector->bsJump[2] = 0x90;
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;
bootSector->bsFATs = 1;
bootSector->bsRootDirEnts = (USHORT)rootDirEntries;
bootSector->bsSectors = (USHORT)(devExt->DiskRegInfo.DiskSize /
devExt->DiskGeometry.BytesPerSector);
bootSector->bsMedia = (UCHAR)devExt->DiskGeometry.MediaType;
bootSector->bsSecPerClus = (UCHAR)sectorsPerCluster;
fatEntries =
(bootSector->bsSectors - bootSector->bsResSectors -
bootSector->bsRootDirEnts / DIR_ENTRIES_PER_SECTOR) /
bootSector->bsSecPerClus + 2;
if (fatEntries > 4087) {
fatType = 16;
fatSectorCnt = (fatEntries * 2 + 511) / 512;
fatEntries = fatEntries + fatSectorCnt;
fatSectorCnt = (fatEntries * 2 + 511) / 512;
}
else {
fatType = 12;
fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
fatEntries = fatEntries + fatSectorCnt;
fatSectorCnt = (((fatEntries * 3 + 1) / 2) + 511) / 512;
}
bootSector->bsFATsecs = fatSectorCnt;
bootSector->bsSecPerTrack = (USHORT)devExt->DiskGeometry.SectorsPerTrack;
bootSector->bsHeads = (USHORT)devExt->DiskGeometry.TracksPerCylinder;
bootSector->bsBootSignature = 0x29;
bootSector->bsVolumeID = 0x12345678;
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‘;
bootSector->bsSig2[0] = 0x55;
bootSector->bsSig2[1] = 0xAA;
firstFatSector = (PUCHAR)(bootSector + 1);
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;
}
这里我们使用的内存来虚拟磁盘,所以对磁盘的读写等操作最后都映射到内存,以下是3种请求的处理函数部分:
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;
_Analysis_assume_(Length > 0);
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, // Destination
0, // Offset into the destination
devExt->DiskImage + ByteOffset.LowPart, // source
Length);
}
}
WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
}
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;
_Analysis_assume_(Length > 0);
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, // Source
0, // offset in Source memory where the copy has to start
devExt->DiskImage + ByteOffset.LowPart, // destination
Length);
}
}
WdfRequestCompleteWithInformation(Request, Status, (ULONG_PTR)Length);
}
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;
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));
Status = STATUS_SUCCESS;
}
}
break;
case IOCTL_DISK_CHECK_VERIFY:
case IOCTL_DISK_IS_WRITABLE:
Status = STATUS_SUCCESS;
break;
}
WdfRequestCompleteWithInformation(Request, Status, information);
}
设备的清除回调函数比较简单,主要进行释放分配的内存操作:
VOID
RamDiskEvtDeviceContextCleanup(
IN WDFOBJECT Device
)
{
PDEVICE_EXTENSION pDeviceExtension = DeviceGetExtension(Device);
PAGED_CODE();
if(pDeviceExtension->DiskImage) {
ExFreePool(pDeviceExtension->DiskImage);
}
}
从注册表中读取配置参数的代码如下:
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;
}
磁盘虚拟的驱动代码在这里作为WDF编程方式的总结案例,它的应用场景也是非常诱人的,实现数据隐藏、Sandbox、网吧无盘系统...这个代码使用内存作为磁盘存储介质,其实这个介质还可以是文件、注册表、网络文件等,实现功能而定了。
最后分享几个网站
收录一些Undocumented Kernel Data Structure的网站 http://www.nirsoft.net/kernel_struct/vista/index.html
张银奎先生关于软件调试内容的网站 http://advdbg.org/default.aspx
原文:http://my.oschina.net/zangzy/blog/330652