应用层的控制程序的功能:创建,打开,关闭函数的主要操作:
(1)MiniDiskCreateMount
检测指定盘符是否存在
若不存在,创建盘符并关联盘符和设备
打开虚拟磁盘设备,发送自定义IOCTL_MINI_DISK_CREATE_FILE控制码
int MiniDiskCreateMount(char DeviceNumber,POPEN_FILE_INFORMATION pOpen,char DriverTarget)
{
……
//尝试打开指定卷
hDevice = CreateFile(
VolumeName,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL);
……
//创建虚拟磁盘设备,盘符和设备捆绑
if(!DefineDosDevice(DDD_RAW_TARGET_PATH,&VolumeName[4],DeviceName))
{
……
}
//打开虚拟磁盘设备
hDevice = CreateFile(
VolumeName,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL);
if(hDevice == INVALID_HANDLE_VALUE)
{
……
}
//发送IOCTL_MINI_DISK_CREATE_FILE控制码
if(!DeviceIoControl(
hDevice,
IOCTL_MINI_DISK_CREATE_FILE,
pOpen,
sizeof(OPEN_FILE_INFORMATION)+pOpen->FileNameLength - 1,
TempBuf,
sizeof(TempBuf)/sizeof(char),
&BytesReturned,
NULL))
{
……
}
……
}
(2)MiniDiskOpenMount
检测指定盘符是否存在
若不存在,创建盘符并关联盘符和设备
打开虚拟磁盘设备,发送自定义IOCTL_MINI_DISK_OPEN_FILE控制码
int MiniDiskOpenMount(char DeviceNumber,POPEN_FILE_INFORMATION pOpen,char DriverTarget)
{
……
//尝试打开指定卷
hDevice = CreateFile(
VolumeName,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL);
//当前卷已经存在,需要更改盘符
if(hDevice != INVALID_HANDLE_VALUE)
{
……
}
……
//创建虚拟磁盘设备,盘符和设备捆绑
if(!DefineDosDevice(DDD_RAW_TARGET_PATH,&VolumeName[4],DeviceName))
{
……
}
//打开虚拟磁盘设备
hDevice = CreateFile(
VolumeName,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL);
if(hDevice == INVALID_HANDLE_VALUE)
{
……
}
//发送IOCTL_MINI_DISK_OPEN_FILE控制码
if(!DeviceIoControl(
hDevice,
IOCTL_MINI_DISK_OPEN_FILE,
pOpen,
sizeof(OPEN_FILE_INFORMATION)+pOpen->FileNameLength - 1,
TempBuf,
sizeof(TempBuf)/sizeof(char),
&BytesReturned,
NULL))
{
……
}
……
}
(3)MiniDiskUnMount
打开虚拟磁盘设备
发送自定义IOCTL_MINI_DISK_CLOSE_FILE控制码
发送系统控制码FSCTL_DISMOUNT_VOLUME
删除盘符
int MiniDiskUnMount(char DriverTarget)
{
……
//检测设备是否存在
hDevice = CreateFile(
VolumeName,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL);
if(hDevice == INVALID_HANDLE_VALUE)
{
……
}
//发送控制码FSCTL_LOCK_VOLUME
/*if(!DeviceIoControl(hDevice,FSCTL_LOCK_VOLUME,NULL,0,NULL,0,&BytesReturned,NULL))
{
……
}*/
//发送控制码IOCTL_MINI_DISK_CLOSE_FILE
if(!DeviceIoControl(hDevice,IOCTL_MINI_DISK_CLOSE_FILE,NULL,0,Buf,sizeof(Buf)/sizeof(char),&BytesReturned,NULL))
{
……
}
//发送控制码FSCTL_DISMOUNT_VOLUME
if(!DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME,NULL,0,NULL,0,&BytesReturned,NULL))
{
……
}
//发送控制码FSCTL_UNLOCK_VOLUME
/*if(!DeviceIoControl(hDevice,FSCTL_UNLOCK_VOLUME,NULL,0,NULL,0,&BytesReturned,NULL))
{
……
}*/
//删除盘符
if(!DefineDosDevice(DDD_REMOVE_DEFINITION,&VolumeName[4],NULL))
{
……
}
……
}
注:在原来的FileDisk项目中,关闭磁盘前,先用FSCTL_LOCK_VOLUME控制码锁住磁盘然后在进行关闭操作后再发送FSCTL_UNLOCK_VOLUME控制码解锁,存在一个问题,当磁盘里面有文件被引用时,FSCTL_LOCK_VOLUME控制码就会发送失败,后来查了一下,强行关闭,只需要发送FSCTL_DISMOUNT_VOLUME控制码即可。(强行关闭可能会造成没完成的数据丢失!)
内核层的驱动的几个主要功能:
(1)MiniDiskCreateDevice
创建设备,设置设备属性,创建符号链接,初始化读写请求链表,初始化自旋锁和事件,创建一个系统线程用于处理IO请求,该线程通过事件对象激活。
NTSTATUS MiniDiskCreateDevice(IN PDRIVER_OBJECT pDriverObject,IN ULONG Number,IN DEVICE_TYPE DeviceType)
{
……
//创建设备
status = IoCreateDevice(
pDriverObject,
sizeof(DEVICE_EXTENSION),
&DeviceName,
DeviceType,
0,
FALSE,
&pDeviceObject);
……
//添加DO_DIRECT_IO标志
pDeviceObject->Flags |= DO_DIRECT_IO;
pDeviceExtension = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
pDeviceExtension->FileExist = FALSE;
pDeviceExtension->CheckDigest = FALSE;
pDeviceExtension->key = NULL;
//pDeviceExtension->pCProDigest = NULL;
//初始化符号链接名
RtlInitUnicodeString(&SymLinkName,L"\\??\\MiniDisk");
pDeviceExtension->SymLinkName = SymLinkName;
//创建符号链接
status = IoCreateSymbolicLink(&SymLinkName,&DeviceName);
……
//初始化读写请求链表头
InitializeListHead(&pDeviceExtension->ListHead);
//初始化自旋锁[读写链表操作]
KeInitializeSpinLock(&pDeviceExtension->ListLock);
//初始化事件[线程等待]
KeInitializeEvent(&pDeviceExtension->RequestEvent,SynchronizationEvent,FALSE);
pDeviceExtension->TerminateThead = FALSE;
//创建系统线程
status = PsCreateSystemThread(&hThread,(ACCESS_MASK)0L,NULL,NULL,NULL,MiniDiskThread,pDeviceObject);
……
}
(2)IOCTL_MINI_DISK_CREATE_FILE控制码
主要是参数检查,把当前IRP插入读写链表中,激活线程。在线程中主要是保存密钥,调用MiniDiskCreateFile函数创建密盘文件。
(3)IOCTL_MINI_DISK_OPEN_FILE控制码
主要是参数检查,把当前IRP插入读写链表中,激活线程。在线程中,检验密钥,若成功,调用MiniDiskOpenFile函数打开密盘文件。
(4)IOCTL_MINI_DISK_CLOSE_FILE控制码
主要是参数检查,把当前IRP插入读写链表中,激活线程。在线程中,调用MiniDiskCloseFile函数关闭密盘文件。
(5)IRP_MJ_READ,IRP_MJ_WRITE
在主要是线程中完成加解密操作,然后读写文件。写之前加密,读之后解密。
//读文件操作
ZwReadFile(pDeviceExtension->hFile,NULL,NULL,NULL,&pIrp->IoStatus,Buffer,pIo_Stack>Parameters.Read.Length,&pIo_Stack-
>Parameters.Read.ByteOffset,NULL);
//解密
for(i = 0; i < pIo_Stack->Parameters.Read.Length;i+=16)
{
InvCipher(pDeviceExtension,Buffer+i,Buffer+i);
}
RtlCopyMemory(SystemBuffer,Buffer,pIo_Stack->Parameters.Read.Length);
……
RtlCopyMemory(Buffer,SystemBuffer,pIo_Stack->Parameters.Write.Length);
//加密
for(i = 0; i < pIo_Stack->Parameters.Read.Length;i+=16)
{
Cipher(pDeviceExtension,Buffer+i,Buffer+i);
}
//写文件操作
ZwWriteFile(pDeviceExtension->hFile,NULL,NULL,NULL,&pIrp->IoStatus,Buffer,pIo_Stack->Parameters.Write.Length,&pIo_Stack-
>Parameters.Write.ByteOffset,NULL);
(6)MiniDiskCreateFile
创建[ZwCreateFile]指定大小文件
查询[ZwQueryInformationFile]文件相关信息[FILE_STANDARD_INFORMATION、FILE_ALIGNMENT_INFORMATION和FILE_BASIC_INFORMATION]并保存到设备扩展
更新设备扩展中的设备状态标志。
(7)MiniDiskOpenFile
打开[ZwCreateFile]指定文件
查询[ZwQueryInformationFile]文件相关信息并保存到设备扩展
更新设备扩展中的设备状态标志。
(8)MiniDiskCloseFile
关闭文件句柄,释放内存空间,更新设备扩展中的设备状态标志。
(9)读写的序列化操作:
把读写请求按顺序插入一个链表中,再按顺序一个个取出来逐个处理,避免了读写重入的问题。
分发函数中:
//挂起当前IRP
IoMarkIrpPending(pIrp);
//插入请求队列
ExInterlockedInsertTailList(&pDeviceExtension->ListHead,&pIrp->Tail.Overlay.ListEntry,&pDeviceExtension->ListLock);
//激活线程事件
KeSetEvent(&pDeviceExtension->RequestEvent,IO_NO_INCREMENT,FALSE);
线程中:
while(1)
{
//等待线程事件
KeWaitForSingleObject(&pDeviceExtension->RequestEvent,Executive,KernelMode,FALSE,NULL);
//从链表中取出读写请求
while(RequestList = ExInterlockedRemoveHeadList(&pDeviceExtension->ListHead,&pDeviceExtension->ListLock))
{
pIrp = CONTAINING_RECORD(RequestList,IRP,Tail.Overlay.ListEntry);
pIo_Stack = IoGetCurrentIrpStackLocation(pIrp);
switch(pIo_Stack->MajorFunction)
{
……
}
}
}
(10)需要响应的系统IO控制码(处理代码见源码):
IOCTL_DISK_CHECK_VERIFY
IOCTL_STORAGE_CHECK_VERIFY
IOCTL_STORAGE_CHECK_VERIFY2
IOCTL_DISK_GET_DRIVE_GEOMETRY
IOCTL_DISK_GET_LENGTH_INFO
IOCTL_DISK_GET_PARTITION_INFO
IOCTL_DISK_GET_PARTITION_INFO_EX
IOCTL_DISK_IS_WRITABLE
IOCTL_STORAGE_MEDIA_REMOVAL
IOCTL_DISK_MEDIA_REMOVAL
IOCTL_DISK_SET_PARTITION_INFO
IOCTL_DISK_VERIFY
(源码)单向链表:
http://bbs.pediy.com/showthread.php?t=170857
[课程]Linux pwn 探索篇!