首页
社区
课程
招聘
[求助]minifilter 线程重入
发表于: 2018-6-12 10:20 3794

[求助]minifilter 线程重入

2018-6-12 10:20
3794


这个线程函数去操作\\DEVICE\\HARDDISKVOLUME3\\BACKUP 这个目录也会重新进入这个IRP??操作会被拒绝
这种重入怎么解决呀?  






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

收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 216
活跃值: (250)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
用FltCreateFile      /  FltReadFIle  /  FltWriteFile
2018-6-12 12:48
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
tsoo 用FltCreateFile / FltReadFIle / FltWriteFile
我用的就是这呀
2018-6-12 13:30
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4

 VOID StartThread1(COPYTHREAD Copy)
 { 
	 NTSTATUS status = STATUS_SUCCESS;
	 HANDLE   hThread = NULL;
	 KEVENT kEvent = {0};

	// KdPrint(("jinle \n"));
	 //初始化参数
	 KeInitializeEvent(&kEvent,SynchronizationEvent,FALSE);

	 Copy.PKE = &kEvent;
	// KdPrint(("Copy.PKE \n"));
	 status = PsCreateSystemThread(&hThread, //创建新线程
		 0,
		 NULL,
		 NULL,//NtCurrentProcess(),线程所在地址空间的进程的handle
		 NULL,
		 (PKSTART_ROUTINE)ThreadProc1,
		 (PVOID)&Copy);  //PVOID       StartContext   对应ThreadProc中的参数
	 if (!NT_SUCCESS(status))
	 {
		 KdPrint(("创建失败 \n"));
		 ZwClose(hThread);
		 return ;
	 }
	 KdPrint(("创建成功 \n"));
	 //等待线程返回
	 KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
	 ZwClose(hThread);
	 return ;
 }


 VOID  ThreadProc1(IN PVOID pContext)  
 {  
	 
	 PCOPYTHREAD copyThread;
	 copyThread = (PCOPYTHREAD)pContext;
	 dfDeleteDirectory(copyThread->Data,copyThread->FltObjects,L"\\??\\d:\\Backup");
	 KeSetEvent(copyThread->PKE,IO_NO_INCREMENT,FALSE); 
	 KdPrint(("线程函数结束\n"));
	 PsTerminateSystemThread(STATUS_SUCCESS);   
	 return ;
 }  








NTSTATUS
	dfDeleteDirectory(PFLT_CALLBACK_DATA Data,PCFLT_RELATED_OBJECTS FltObjects,const WCHAR * directory)
{
	OBJECT_ATTRIBUTES                	objAttributes = { 0 };
	IO_STATUS_BLOCK                    	iosb = { 0 };
	HANDLE                            	handle = NULL;
	FILE_DISPOSITION_INFORMATION    	disInfo = { 0 };
	PVOID                            	buffer = NULL;
	ULONG                            	bufferLength = 0;
	BOOLEAN                            	restartScan = FALSE;
	PFILE_DIRECTORY_INFORMATION        	dirInfo = NULL;
	PWSTR                            	nameBuffer = NULL;	//记录文件夹
	UNICODE_STRING                    	nameString = { 0 };
	NTSTATUS                        	status = 0;
	LIST_ENTRY                        	listHead = { 0 };	//链表,用来存放删除过程中的目录
	PFILE_LIST_ENTRY                	tmpEntry = NULL;	//链表结点
	PFILE_LIST_ENTRY                	preEntry = NULL;
	UNICODE_STRING						uDirName = { 0 };

	RtlInitUnicodeString(&uDirName, directory);

	nameBuffer = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, uDirName.Length + sizeof(WCHAR), 'DRID');
	if (!nameBuffer)
	{
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	tmpEntry = (PFILE_LIST_ENTRY)ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_LIST_ENTRY), 'DRID');
	if (!tmpEntry)
	{
		ExFreePool(nameBuffer);
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	RtlCopyMemory(nameBuffer, uDirName.Buffer, uDirName.Length);
	nameBuffer[uDirName.Length / sizeof(WCHAR)] = L'\0';

	InitializeListHead(&listHead);	//初始化链表
	tmpEntry->NameBuffer = nameBuffer;
	InsertHeadList(&listHead, &tmpEntry->Entry);	//将要删除的文件夹首先插入链表   

	//listHead里初始化为要删除的文件夹。
	//之后遍历文件夹下的文件和目录,判断是文件,则立即删除;判断是目录,则放进listHead里面
	//每次都从listHead里拿出一个目录来处理
	while (!IsListEmpty(&listHead))
	{
		//先将要删除的文件夹和之前打算删除的文件夹比较一下,如果从链表里取下来的还是之前的Entry,表明没有删除成功,说明里面非空
		//否则,已经成功删除,不可能是它自身;或者还有子文件夹,在前面,也不可能是它自身。
		tmpEntry = (PFILE_LIST_ENTRY)RemoveHeadList(&listHead);
		if (preEntry == tmpEntry)
		{
			status = STATUS_DIRECTORY_NOT_EMPTY;
			break;
		}

		preEntry = tmpEntry;
		InsertHeadList(&listHead, &tmpEntry->Entry); //放进去,等删除了里面的内容,再移除。如果移除失败,则说明还有子文件夹或者目录非空

		RtlInitUnicodeString(&nameString, tmpEntry->NameBuffer);
		InitializeObjectAttributes(&objAttributes, &nameString,
			OBJ_CASE_INSENSITIVE, NULL, NULL);
		//打开文件夹,进行查询
		status = FltCreateFile(
			FltObjects->Filter,
			NULL,
			&handle,
			DELETE, //开始写的所有会失败
			&objAttributes,
			&iosb,
			NULL,
			0,
			0,
			FILE_OPEN,
			FILE_SYNCHRONOUS_IO_NONALERT,
			NULL,
			0,
			0);
		if (!NT_SUCCESS(status))
		{
			KdPrint(("2 FltCreateFile(%ws) failed(%x)\n", tmpEntry->NameBuffer, status));
		//	KdPrint(("2ZwCreateFilefailed(%x)\n", status));
			break;
		}
		//从第一个扫描
		restartScan = TRUE;
		PFILE_OBJECT fileObject = NULL;
		while (TRUE)
		{

			buffer = NULL;
			bufferLength = 64;
			status = STATUS_BUFFER_OVERFLOW;

			while ((status == STATUS_BUFFER_OVERFLOW) || (status == STATUS_INFO_LENGTH_MISMATCH))
			{
				if (buffer)
				{
					ExFreePool(buffer);
				}

				bufferLength *= 2;
				buffer = ExAllocatePoolWithTag(NonPagedPool, bufferLength, 'DRID');
				if (!buffer)
				{
					KdPrint(("ExAllocatePool failed\n"));
					status = STATUS_INSUFFICIENT_RESOURCES;
					break;
				}

				// 通过文件句柄得到文件对象传给FltQueryDirectoryFile
				
				status = ObReferenceObjectByHandle(handle, 0, NULL, KernelMode,
					reinterpret_cast<void **>(&fileObject),
					NULL);
				if (!NT_SUCCESS(status)) {
					KdPrint(("ObReferenceObjectByHandle 1 fail  \n"));
				}


				status = FltQueryDirectoryFile(FltObjects->Instance,
					                           fileObject,
					                           buffer,
					                           bufferLength, 
											   FileDirectoryInformation,
				                           	   FALSE,
											   NULL,
											   restartScan,
											   NULL);
				if (fileObject) {
					ObDereferenceObject(fileObject);
				}
			}

			if (status == STATUS_NO_MORE_FILES)
			{
				ExFreePool(buffer);
				status = STATUS_SUCCESS;
				break;
			}

			restartScan = FALSE;

		
			if (!NT_SUCCESS(status))
			{
				KdPrint(("FltQueryDirectoryFile(%ws) failed(%x),\n", tmpEntry->NameBuffer, status));
				if (buffer)
				{
					ExFreePool(buffer);
				}
				break;
			}

			dirInfo = (PFILE_DIRECTORY_INFORMATION)buffer;

			nameBuffer = (PWSTR)ExAllocatePoolWithTag(    NonPagedPool,
				wcslen(tmpEntry->NameBuffer) * sizeof(WCHAR) + dirInfo->FileNameLength + 4, 'DRID');
			if (!nameBuffer)
			{
				KdPrint(("ExAllocatePool failed\n"));
				ExFreePool(buffer);
				status = STATUS_INSUFFICIENT_RESOURCES;
				break;
			}

			//tmpEntry->NameBuffer是当前文件夹路径
			//下面的操作在拼接文件夹下面的文件路径

			RtlZeroMemory(nameBuffer, wcslen(tmpEntry->NameBuffer) * sizeof(WCHAR) + dirInfo->FileNameLength + 4);
			wcscpy(nameBuffer, tmpEntry->NameBuffer);
			wcscat(nameBuffer, L"\\");
			RtlCopyMemory(&nameBuffer[wcslen(nameBuffer)], dirInfo->FileName, dirInfo->FileNameLength);
			RtlInitUnicodeString(&nameString, nameBuffer);

			if (dirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			{
				//如果是非'.'和'..'两个特殊的目录,则将目录放入listHead
				if ((dirInfo->FileNameLength == sizeof(WCHAR)) && (dirInfo->FileName[0] == L'.'))
				{

				}
				else if ((dirInfo->FileNameLength == sizeof(WCHAR) * 2) &&
					(dirInfo->FileName[0] == L'.') &&
					(dirInfo->FileName[1] == L'.'))
				{
				}
				else
				{
					//将文件夹插入listHead中
					PFILE_LIST_ENTRY localEntry;
			localEntry = (PFILE_LIST_ENTRY)ExAllocatePoolWithTag(   NonPagedPool, sizeof(FILE_LIST_ENTRY), 'DRID');
					if (!localEntry)
					{
						KdPrint(("ExAllocatePool failed\n"));
						ExFreePool(buffer);
						ExFreePool(nameBuffer);
						status = STATUS_INSUFFICIENT_RESOURCES;
						break;
					}

					localEntry->NameBuffer = nameBuffer;
					nameBuffer = NULL;
					InsertHeadList(&listHead, &localEntry->Entry); //插入头部,先把子文件夹里的删除
				
				}
			}
			else
			{
				//文件,直接删除
		//		KdPrint(("文件路径:%S\n",nameBuffer));


//在删除前恢复
				status = CopyFileBeforeDel(Data,FltObjects,nameBuffer);
				if (!NT_SUCCESS(status))
				{
				    KdPrint(("CopyFileBeforeDel(%wZ) failed(%x)\n", &nameString, status));
				    ExFreePool(buffer);
				    ExFreePool(nameBuffer);
				    break;
				}
			}

			ExFreePool(buffer);
			if (nameBuffer)
			{
				ExFreePool(nameBuffer);
			}//继续在循环里处理下一个子文件或者子文件夹
		}//  while (TRUE) ,一直弄目录里的文件和文件夹



		if (NT_SUCCESS(status))
		{
			//删除目录
			
			/*PFILE_OBJECT fileObject1 = NULL;
			status = ObReferenceObjectByHandle(handle, 0, NULL, KernelMode,
				reinterpret_cast<void **>(&fileObject1),
				NULL);
			if (!NT_SUCCESS(status)) {
				KdPrint(("ObReferenceObjectByHandle 1 fail  \n"));
			}
			disInfo.DeleteFile = TRUE;
			status = FltSetInformationFile( FltObjects->Instance,
				                            fileObject1,
											&disInfo,
											sizeof(disInfo),
											FileDispositionInformation);
			if (NT_SUCCESS(status))
			{
				if (fileObject1)
				{
					ObDereferenceObject(fileObject1);
				}
			}
			else {
				KdPrint(("3  FltSetInformationFile(%ws) failed(%x)\n", tmpEntry->NameBuffer, status));
			}		*/
			
		}

		FltClose(handle);

		if (NT_SUCCESS(status))
		{
			//删除成功,从链表里移出该目录
			RemoveEntryList(&tmpEntry->Entry);
			ExFreePool(tmpEntry->NameBuffer);
			ExFreePool(tmpEntry);
		}
		//如果失败,则表明在文件夹还有子文件夹,继续先删除子文件夹
	}// while (!IsListEmpty(&listHead)) 

	while (!IsListEmpty(&listHead))
	{
		tmpEntry = (PFILE_LIST_ENTRY)RemoveHeadList(&listHead);
		ExFreePool(tmpEntry->NameBuffer);
		ExFreePool(tmpEntry);
	}

	
	return status;
}


完整代码如上,第一个FltCreateFile就返回拒绝了
2018-6-12 13:33
0
雪    币: 216
活跃值: (250)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
FltCreateFile  参数肯定传错了.  自己检查下.
2018-6-14 16:33
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
tsoo FltCreateFile 参数肯定传错了. 自己检查下.
确实是FltCreateFile的参数传错了,第二个参数不应该写成NULL,应该写操作文件的实例。一语中的呀
2018-6-14 19:27
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
tsoo FltCreateFile 参数肯定传错了. 自己检查下.
已解决
2018-6-14 19:28
0
游客
登录 | 注册 方可回帖
返回
//