首页
社区
课程
招聘
[原创](补充)关于那个密盘程序的一点说明
发表于: 2013-5-6 20:14 9237

[原创](补充)关于那个密盘程序的一点说明

2013-5-6 20:14
9237
应用层的控制程序的功能:创建,打开,关闭函数的主要操作:
(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

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 6
支持
分享
最新回复 (13)
雪    币: 440
活跃值: (968)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
mark一下,,,,
2013-5-6 21:20
0
雪    币: 1867
活跃值: (1619)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
看不懂,太难了
2013-5-7 00:17
0
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
好厉害啊!!!膜拜
2013-5-7 02:04
0
雪    币: 141
活跃值: (318)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
呵呵。不错、、、、、、、
2013-5-7 11:26
0
雪    币: 10853
活跃值: (17241)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
路过,看不懂啊,以后再来学习
2013-5-7 15:29
0
雪    币: 558
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
注:在原来的FileDisk项目中,关闭磁盘前,先用FSCTL_LOCK_VOLUME控制码锁住磁盘然后在进行关闭操作后再发送FSCTL_UNLOCK_VOLUME控制码解锁,存在一个问题,当磁盘里面有文件被引用时,FSCTL_LOCK_VOLUME控制码就会发送失败,后来查了一下,强行关闭,只需要发送FSCTL_DISMOUNT_VOLUME控制码即可。(强行关闭可能会造成没完成的数据丢失!)


强行关闭FDisk,先Mark一下,有空好好看看
2013-5-7 19:01
0
雪    币: 558
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
FileDisk驱动在Win7-32下,如果访问过一次虚拟磁盘,就无法停止驱动(net stop Filedisk),只能重启系统了
奇怪的是,如果只是 Start Driver -> Stop Driver,中间没有打过开虚拟磁盘,停止驱动就是成功的,Why?

而在Xp系统下,不管怎么打开磁盘,都是可以正常停止驱动的

怀疑是Win7系统打开了某些虚拟磁盘的句柄,没有释放,所以才这样的。

请问,大家有人遇到过这样的问题吗?请赐教
2013-5-9 11:06
0
雪    币: 284
活跃值: (106)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
9
我以前遇到过这种情况,一般出现这种驱动卸载不掉的情况就是驱动还在某个地方被拥有着,检查卸载虚拟卷时候的几个步骤的顺序就可以解决了
2013-5-9 11:42
0
雪    币: 558
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
FileDisk中关闭虚拟磁盘的顺序是这样的,FSCTL_LOCK_VOLUME -> IOCTL_MINI_DISK_CLOSE_FILE -> FSCTL_DISMOUNT_VOLUME -> FSCTL_UNLOCK_VOLUME。而且虚拟磁盘的确是已经卸载掉了

但是,驱动就是无法停止,不知道应该怎样调整?
2013-5-9 13:43
0
雪    币: 275
活跃值: (51)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
11
filedisk 我记得那时候我也用过这个玩意  尼玛最近 你在忙什么呢,考研怎么样了
2013-5-9 14:45
0
雪    币: 328
活跃值: (154)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
12
应该是卸载例程的某些细节问题没有处理好,
2013-5-11 23:43
0
雪    币: 34
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
现在看不太明白,以后慢慢研究
2013-6-4 16:41
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
留着瞧瞧先
2013-9-4 17:08
0
游客
登录 | 注册 方可回帖
返回
//