08.09.09
终于创建一个设备,并且能与应用层通信
今天打算研究下,filedisk 是如何虚拟出一个分区出来的
首先看下 filedisk 在应用层的实现
filedisk 在应用层执行 Mount 时,调用 DeviceIoControl() 向驱动层发送 IOCTL_FILE_DISK_OPEN_FILE 指令
相关代码如下:
if (!DeviceIoControl(
Device,
IOCTL_FILE_DISK_OPEN_FILE,
OpenFileInformation,
sizeof(OPEN_FILE_INFORMATION) + OpenFileInformation->FileNameLength - 1,
NULL,
0,
&BytesReturned,
NULL
))
{
PrintLastError("FileDisk:");
DefineDosDevice(DDD_REMOVE_DEFINITION, &VolumeName[4], NULL);
return -1;
}
现在需要来看一下,驱动层在收到 IOCTL_FILE_DISK_OPEN_FILE 指令时,干了哪些事
看了 .sys 的实现,没看出个所以然
再次 Google 了一下
1. 创建设备 DriverEntry 创建类型为 FILE_DEVICE_DISK_FILE_SYSTEM 的设备
3. 在IRP_MJ_DEVICE_CONTROL中需要响应几个系统要求的IOCTL:
IOCTL_DISK_GET_DRIVE_GEOMETRY (需要引入 #include <ntdddisk.h> 头文件 )
IOCTL_DISK_GET_PARTITION_INFO
IOCTL_DISK_IS_WRITABLE
IOCTL_DISK_SET_PARTITION_INFO
IOCTL_DISK_VERIFY
IOCTL_DISK_CHECK_VERIFY
接下来,重写 DeviceControl() 处理系统要求的 IOCTL
发现响应上述的IRP也不会显示出一个“虚拟分区”
……
(经过长时间的的折腾……折腾……折腾……)
……
找到 DefineDosDevice() API函数
DefineDosDevice(0, "g:", "c:\\");
这句语句就相当于 Windows 下面的 subst 命令了
cmd:> subst g: c:\
将应用层的代码修改为
虽然显示 DefindDosDevice OK ErrCode = 0
但依然不能在我的电脑里显示分区
查了相关资料,发现
应用层的 DefineDosDevice() 函数相当于 内核的 IoCreateSymbolicLink() 函数
不如试下直接在驱动层创建
于是修改了内核的函数试一下
#define DEVICE_NAME L" \\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L" \\x:"
加载驱动后,并没有显示设备,用 winobj 查看, 在设备路径的根目录下确实多了 x:
但还是没有显示设备
再修改为:
#define DEVICE_NAME L" \\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L" \\\\.\\x:"
加载驱动时,提示“卷标,路径不合法”,用 Winobj查看,设备创建了,显然是 IoCreateSymbolicLink() 创建失败
再再修改为:
#define DEVICE_NAME L" \\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L" \\DosDevices\\x:"
创建的符号在设备路径 \Global??\ 下面,
Description:
Name: \GLOBAL??\x:
Type: SymbolicLink
To: \DosDevices\SimpleDriver
Count: 135
看到 C: 盘的符号也是在这个目录下面,但为何 X: 盘为何没有在我的电脑中显示?
运行 cmd.exe 输入 X:
可以把路径切换到 X:
但执行 dir 时,显示函数不正确,这显然是没有处理相应的 IRP 的缘故
处理了上述的 IRP 依然不显示 X: 盘出来
于是 加上
DriverObject->MajorFunction[IRP_MJ_READ] = FileDiskReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = FileDiskReadWrite;
试试
还是在我的电脑中没有显示 X: 盘出来
5集 终
终于创建一个设备,并且能与应用层通信
今天打算研究下,filedisk 是如何虚拟出一个分区出来的
首先看下 filedisk 在应用层的实现
filedisk 在应用层执行 Mount 时,调用 DeviceIoControl() 向驱动层发送 IOCTL_FILE_DISK_OPEN_FILE 指令
相关代码如下:
if (!DeviceIoControl(
Device,
IOCTL_FILE_DISK_OPEN_FILE,
OpenFileInformation,
sizeof(OPEN_FILE_INFORMATION) + OpenFileInformation->FileNameLength - 1,
NULL,
0,
&BytesReturned,
NULL
))
{
PrintLastError("FileDisk:");
DefineDosDevice(DDD_REMOVE_DEFINITION, &VolumeName[4], NULL);
return -1;
}
现在需要来看一下,驱动层在收到 IOCTL_FILE_DISK_OPEN_FILE 指令时,干了哪些事
看了 .sys 的实现,没看出个所以然
再次 Google 了一下
1. 创建设备 DriverEntry 创建类型为 FILE_DEVICE_DISK_FILE_SYSTEM 的设备
3. 在IRP_MJ_DEVICE_CONTROL中需要响应几个系统要求的IOCTL:
IOCTL_DISK_GET_DRIVE_GEOMETRY (需要引入 #include <ntdddisk.h> 头文件 )
IOCTL_DISK_GET_PARTITION_INFO
IOCTL_DISK_IS_WRITABLE
IOCTL_DISK_SET_PARTITION_INFO
IOCTL_DISK_VERIFY
IOCTL_DISK_CHECK_VERIFY
接下来,重写 DeviceControl() 处理系统要求的 IOCTL
发现响应上述的IRP也不会显示出一个“虚拟分区”
……
(经过长时间的的折腾……折腾……折腾……)
……
找到 DefineDosDevice() API函数
DefineDosDevice(0, "g:", "c:\\");
这句语句就相当于 Windows 下面的 subst 命令了
cmd:> subst g: c:\
将应用层的代码修改为
void
mount()
{
if (!DefineDosDevice(DDD_RAW_TARGET_PATH, "x:",
"\\\\.\\SimpleDriver"
))
{
printf("DefineDosDevice Error ErrCode = %d", ::GetLastError());
}
else
{
printf("DefineDosDevice OK ErrCode = %d", ::GetLastError());
}
}
int main( int argc, char * argv[])
{
mount();
return 0;
}
{
if (!DefineDosDevice(DDD_RAW_TARGET_PATH, "x:",
"\\\\.\\SimpleDriver"
))
{
printf("DefineDosDevice Error ErrCode = %d", ::GetLastError());
}
else
{
printf("DefineDosDevice OK ErrCode = %d", ::GetLastError());
}
}
int main( int argc, char * argv[])
{
mount();
return 0;
}
虽然显示 DefindDosDevice OK ErrCode = 0
但依然不能在我的电脑里显示分区
查了相关资料,发现
应用层的 DefineDosDevice() 函数相当于 内核的 IoCreateSymbolicLink() 函数
不如试下直接在驱动层创建
于是修改了内核的函数试一下
#define DEVICE_NAME L" \\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L" \\x:"
加载驱动后,并没有显示设备,用 winobj 查看, 在设备路径的根目录下确实多了 x:
但还是没有显示设备
再修改为:
#define DEVICE_NAME L" \\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L" \\\\.\\x:"
加载驱动时,提示“卷标,路径不合法”,用 Winobj查看,设备创建了,显然是 IoCreateSymbolicLink() 创建失败
再再修改为:
#define DEVICE_NAME L" \\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L" \\DosDevices\\x:"
创建的符号在设备路径 \Global??\ 下面,
Description:
Name: \GLOBAL??\x:
Type: SymbolicLink
To: \DosDevices\SimpleDriver
Count: 135
看到 C: 盘的符号也是在这个目录下面,但为何 X: 盘为何没有在我的电脑中显示?
运行 cmd.exe 输入 X:
可以把路径切换到 X:
但执行 dir 时,显示函数不正确,这显然是没有处理相应的 IRP 的缘故
处理了上述的 IRP 依然不显示 X: 盘出来
于是 加上
DriverObject->MajorFunction[IRP_MJ_READ] = FileDiskReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = FileDiskReadWrite;
试试
#include
<
ntddk.h
>
#include < ntdddisk.h >
#define DEVICE_NAME L"\\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L"\\DosDevices\\X:"
#define SECTOR_SIZE 512
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS DeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DeviceCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DeviceReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
#pragma code_seg( " INIT " )
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING uniNameString;
UNICODE_STRING uniLinkString;
DEVICE_OBJECT *pCDO = NULL;
KdPrint(("SimpleDriver!DriverEntry \n"));
RtlInitUnicodeString(&uniNameString, DEVICE_NAME);
status = IoCreateDevice(DriverObject, 0, &uniNameString, FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN, FALSE, &pCDO);
if( !NT_SUCCESS(status) )
return status;
RtlInitUnicodeString(&uniLinkString, DEVICE_LINK_NAME);
status = IoCreateSymbolicLink(&uniLinkString, &uniNameString);
if(!NT_SUCCESS(status))
return status;
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
DriverObject->MajorFunction[IRP_MJ_READ] = DeviceReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DeviceReadWrite;
return STATUS_SUCCESS;
}
#pragma code_seg( " PAGE " )
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING uniNameString;
PAGED_CODE();
KdPrint(("SimpleDriver!DriverUnload \n"));
RtlInitUnicodeString(&uniNameString, DEVICE_LINK_NAME);
IoDeleteSymbolicLink(&uniNameString);
IoDeleteDevice(DriverObject->DeviceObject);
}
NTSTATUS DeviceCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PAGED_CODE();
KdPrint(("SimpleDriver!DeviceCreateClose \n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG nIoCtrlCodes = 0; // IO控制码
PIO_STACK_LOCATION IrpStack = NULL; //IRP堆栈
KdPrint(("SimpleDriver!DeviceControl \n"));
//得到当前调用者的IRP
IrpStack = IoGetCurrentIrpStackLocation(Irp);
nIoCtrlCodes = IrpStack->Parameters.DeviceIoControl.IoControlCode;
KdPrint(("SimpleDriver!DeviceControl IoControlCode = 0x%X\n", nIoCtrlCodes));
switch( IrpStack->Parameters.DeviceIoControl.IoControlCode )
{
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
{
PDISK_GEOMETRY disk_geometry;
ULONGLONG length;
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof
(DISK_GEOMETRY))
{
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
disk_geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
// #define SECTOR_SIZE 512
disk_geometry->Cylinders.QuadPart = 41940668416 / SECTOR_SIZE / 32 / 2;
disk_geometry->MediaType = FixedMedia;
disk_geometry->TracksPerCylinder = 2;
disk_geometry->SectorsPerTrack = 32;
disk_geometry->BytesPerSector = SECTOR_SIZE;
Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
case IOCTL_DISK_GET_PARTITION_INFO:
{
PPARTITION_INFORMATION partition_information;
ULONGLONG length;
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof
(PARTITION_INFORMATION))
{
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
partition_information = (PPARTITION_INFORMATION) Irp-
>AssociatedIrp.SystemBuffer;
partition_information->StartingOffset.QuadPart = 0;
partition_information->PartitionLength.QuadPart = 41940668416;
partition_information->HiddenSectors = 1;
partition_information->PartitionNumber = 0;
partition_information->PartitionType = 0;
partition_information->BootIndicator = FALSE;
partition_information->RecognizedPartition = FALSE;
partition_information->RewritePartition = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
}
break;
case IOCTL_DISK_IS_WRITABLE:
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
}
break;
case IOCTL_DISK_SET_PARTITION_INFO:
{
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof
(SET_PARTITION_INFORMATION))
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
}
break;
case IOCTL_DISK_VERIFY:
{
PVERIFY_INFORMATION verify_information;
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof
(VERIFY_INFORMATION))
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
verify_information = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = verify_information->Length;
}
break;
case IOCTL_DISK_CHECK_VERIFY:
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
};
status = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS DeviceReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION io_stack;
io_stack = IoGetCurrentIrpStackLocation(Irp);
if (io_stack->Parameters.Read.Length == 0)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
IoMarkIrpPending(Irp);
return STATUS_PENDING;
}
#pragma code_seg()
#include < ntdddisk.h >
#define DEVICE_NAME L"\\DosDevices\\SimpleDriver"
#define DEVICE_LINK_NAME L"\\DosDevices\\X:"
#define SECTOR_SIZE 512
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS DeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DeviceCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DeviceReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
#pragma code_seg( " INIT " )
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING uniNameString;
UNICODE_STRING uniLinkString;
DEVICE_OBJECT *pCDO = NULL;
KdPrint(("SimpleDriver!DriverEntry \n"));
RtlInitUnicodeString(&uniNameString, DEVICE_NAME);
status = IoCreateDevice(DriverObject, 0, &uniNameString, FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN, FALSE, &pCDO);
if( !NT_SUCCESS(status) )
return status;
RtlInitUnicodeString(&uniLinkString, DEVICE_LINK_NAME);
status = IoCreateSymbolicLink(&uniLinkString, &uniNameString);
if(!NT_SUCCESS(status))
return status;
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl;
DriverObject->MajorFunction[IRP_MJ_READ] = DeviceReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DeviceReadWrite;
return STATUS_SUCCESS;
}
#pragma code_seg( " PAGE " )
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING uniNameString;
PAGED_CODE();
KdPrint(("SimpleDriver!DriverUnload \n"));
RtlInitUnicodeString(&uniNameString, DEVICE_LINK_NAME);
IoDeleteSymbolicLink(&uniNameString);
IoDeleteDevice(DriverObject->DeviceObject);
}
NTSTATUS DeviceCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PAGED_CODE();
KdPrint(("SimpleDriver!DeviceCreateClose \n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG nIoCtrlCodes = 0; // IO控制码
PIO_STACK_LOCATION IrpStack = NULL; //IRP堆栈
KdPrint(("SimpleDriver!DeviceControl \n"));
//得到当前调用者的IRP
IrpStack = IoGetCurrentIrpStackLocation(Irp);
nIoCtrlCodes = IrpStack->Parameters.DeviceIoControl.IoControlCode;
KdPrint(("SimpleDriver!DeviceControl IoControlCode = 0x%X\n", nIoCtrlCodes));
switch( IrpStack->Parameters.DeviceIoControl.IoControlCode )
{
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
{
PDISK_GEOMETRY disk_geometry;
ULONGLONG length;
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof
(DISK_GEOMETRY))
{
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
disk_geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
// #define SECTOR_SIZE 512
disk_geometry->Cylinders.QuadPart = 41940668416 / SECTOR_SIZE / 32 / 2;
disk_geometry->MediaType = FixedMedia;
disk_geometry->TracksPerCylinder = 2;
disk_geometry->SectorsPerTrack = 32;
disk_geometry->BytesPerSector = SECTOR_SIZE;
Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
case IOCTL_DISK_GET_PARTITION_INFO:
{
PPARTITION_INFORMATION partition_information;
ULONGLONG length;
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof
(PARTITION_INFORMATION))
{
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
partition_information = (PPARTITION_INFORMATION) Irp-
>AssociatedIrp.SystemBuffer;
partition_information->StartingOffset.QuadPart = 0;
partition_information->PartitionLength.QuadPart = 41940668416;
partition_information->HiddenSectors = 1;
partition_information->PartitionNumber = 0;
partition_information->PartitionType = 0;
partition_information->BootIndicator = FALSE;
partition_information->RecognizedPartition = FALSE;
partition_information->RewritePartition = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
}
break;
case IOCTL_DISK_IS_WRITABLE:
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
}
break;
case IOCTL_DISK_SET_PARTITION_INFO:
{
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof
(SET_PARTITION_INFORMATION))
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
}
break;
case IOCTL_DISK_VERIFY:
{
PVERIFY_INFORMATION verify_information;
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof
(VERIFY_INFORMATION))
{
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
verify_information = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = verify_information->Length;
}
break;
case IOCTL_DISK_CHECK_VERIFY:
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
};
status = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS DeviceReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION io_stack;
io_stack = IoGetCurrentIrpStackLocation(Irp);
if (io_stack->Parameters.Read.Length == 0)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
IoMarkIrpPending(Irp);
return STATUS_PENDING;
}
#pragma code_seg()
还是在我的电脑中没有显示 X: 盘出来
5集 终