Esempio n. 1
1
/*---------------------------------------------------------
函数名称:	FileIsEncrypted
函数描述:	判断文件是否是机密文件
输入参数:
			pfiInstance					过滤器实例
			pfoFileObject				文件对象
			pfcdCBD						回调参数
			ulFlags						标志位

输出参数:
			pbIsFileEncrypted 文件是否被加密
返回值:		
			STATUS_SUCCESS					成功(未写加密头)	
			STATUS_FILE_NOT_ENCRYPTED		不是机密文件
			STATUS_REPARSE_OBJECT			在这个新建的文件 在本函数
											中被写入了加密头

其他:		这个函数设计的不是很好,把写文件头和修改IRP参数
			也包含在里面了.暂时不修改了.

			如果这个文件已经存在在机密表中,函数将返回
			STATUS_IMAGE_ALREADY_LOADED

			如果查询名称失败(根本无名称)将返回
			STATUS_OBJECT_NAME_NOT_FOUND

			pbAutoWriteEncryptedHeader传入状态为TRUE时将自动
			补齐加密头,同时将修改FLT_PARAMETER部分数据,若输出
			TRUE说明已经进行,需要外部调用FltSetCallbackDataDirty

更新维护:	2011.4.9     最初版本
			2011.4.13    增加了判断是否已经存在在表中
			2011.4.19    Bug:未执行FltCreateFile也会
								   运行FltClose,已修正.
		    2011.4.30    修改查询不到名称时的返回值.
			2011.5.1     Bug:未赋pbIsFileEncrypted
								   初值会造成判断错误.已修正.
		    2011.5.2     将打开文件的操作独立出去.
			2011.7.8     Bug:修改了FLT_PARAMETER却没有
								   通知FLTMGR.通知外部是否需
								   要Dirty.已修正.
			2011.7.20    修改了数据结构增加了定义
			2012.1.1     Bug:发现此函数导致一些图标加载
			                       异常,FltReadFile造成,使用
								   自己重新打开的文件对象即可.
								   已修正.
---------------------------------------------------------*/
NTSTATUS 
FileIsEncrypted(
	__in PFLT_INSTANCE pfiInstance,
	__in PFILE_OBJECT pfoFileObjectOpened,
	__in PFLT_CALLBACK_DATA pfcdCBD,
	__in PVOLUME_CONTEXT pvcVolumeContext,
	__in PFILE_STREAM_CONTEXT  pscFileStreamContext,
	__in ULONG	ulFlags 
	)
{
	//是否是目录
	BOOLEAN bDirectory;

	//文件长度
	LARGE_INTEGER nFileSize;

	//状态
	NTSTATUS status;

	//完成事件
	KEVENT keEventComplete;

	//偏移量
	LARGE_INTEGER nOffset;

	//加密标识
	WCHAR wEncryptedLogo[ENCRYPTION_HEAD_LOGO_SIZE]	= ENCRYPTION_HEADER;

	//读取的数据内容 用于同加密标识比较 多申请了一个存放\0的空间
	WCHAR wBufferRead[ENCRYPTION_HEAD_LOGO_SIZE+2] = {0};

	//文件句柄
	HANDLE hFile = NULL;

	//对象属性,用于打开文件时使用
	OBJECT_ATTRIBUTES oaObjectAttributes;

	//文件路径
	UNICODE_STRING usPath;

	//文件路径存放数据地址
	WCHAR wPath[NORMAL_FILE_PATH_LENGTH];

	//文件路径指针
	PWSTR pwPath = wPath;

	//文件路径长度
	ULONG ulPathLength;

	//需要的权限
	ULONG ulDesiredAccess;

	//准备返回的返回值
	NTSTATUS statusRet = STATUS_FILE_NOT_ENCRYPTED;

	//函数返回值
	BOOLEAN bReturn;

	//过滤器IO参数
	PFLT_PARAMETERS  pfpParameters;

	//用于存放读取的文件开头部分的内存
	PWCHAR pwFileHead;

	//
	//保存访问权限的值 参数等
	//
	FltDecodeParameters(
		pfcdCBD,
		NULL,
		NULL,
		NULL,
		(LOCK_OPERATION *)&ulDesiredAccess
		);

	pfpParameters = &pfcdCBD -> Iopb -> Parameters;

	do{

		//
		//查询文件基本信息
		//
		status = FileGetStandardInformation(
				pfiInstance,
				pfoFileObjectOpened,
				NULL,
				&nFileSize,
				&bDirectory
				);

		if( !NT_SUCCESS(status) ){
			statusRet = status;
			break;
		}

		//
		//如果是目录,直接返回不需要加密
		//
		if( bDirectory ){
			statusRet = STATUS_FILE_NOT_ENCRYPTED;
			
			break;
		}

		//
		//如果文件大小为0(新建的文件),并且准备写操作,而且是机密进程,那么加密
		//
		if( ( nFileSize.QuadPart == 0 ) &&//文件大小为0
			(ulDesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA) )&&//准备写文件 
			IsCurrentProcessConfidential()){
			//
			//如果要求自动补齐加密头,那么现在写入 写入前重新设置文件大小
			//
			if(!(ulFlags&FILE_IS_ENCRYPTED_DO_NOT_WRITE_LOGO)){

				statusRet = FileWriteEncryptionHeader(
					pfiInstance,
					pfoFileObjectOpened,
					pvcVolumeContext,
					pscFileStreamContext
					);
				
				if(NT_SUCCESS(statusRet)){
					FileClearCache(pfoFileObjectOpened);
					//
					//恢复偏移量到0
					//

					DebugTraceFileAndProcess(
						DEBUG_TRACE_IMPORTANT_INFO|DEBUG_TRACE_CONFIDENTIAL,
						"FileIsEncrypted",
						FILE_OBJECT_NAME_BUFFER(pfoFileObjectOpened),
						("Header has been written.Set offset. High:%d,Low:%d,Quard:%d",
							nOffset.HighPart,nOffset.LowPart,nOffset.QuadPart)
						);

					nOffset.QuadPart = 0;

					status = FileSetOffset(pfiInstance,pfoFileObjectOpened,&nOffset);

					if( !NT_SUCCESS(status) )
					{
						statusRet = status;
						break;
					}
					statusRet = STATUS_REPARSE_OBJECT;
				}else{

					DebugTraceFileAndProcess(
						DEBUG_TRACE_ERROR,
						"FileIsEncrypted",
						FILE_OBJECT_NAME_BUFFER(pfoFileObjectOpened),
						("Cannot write header.")
						);
				}
				
				break;
			}

			statusRet =  STATUS_SUCCESS;

			break;
		}

		//
		//如果文件大小小于加密头,那么肯定不是加密文件
		//
		if( nFileSize.QuadPart < CONFIDENTIAL_FILE_HEAD_SIZE ){
			statusRet = STATUS_FILE_NOT_ENCRYPTED;

			break;
		}

		//
		//现在读出前几个字符判断是否是加密文件,字符数
		//取决于FileFunction.h中ENCRYPTION_HEAD_LOGO_SIZE
		//

		//
		//开始前先初始化事件对象
		//

		KeInitializeEvent(
			&keEventComplete,
			SynchronizationEvent,//同步事件
			FALSE//事件初始标志为FALSE
			);

		nOffset.QuadPart = 0;

		//
		//获取一个内存块用于存放
		//
//		pwFileHead = (PWCHAR)ExAllocateFromNPagedLookasideList(
//			pvcVolumeContext->pnliReadEncryptedSignLookasideList);

		__try{

			status = FltReadFile(
				pfiInstance,
				pfoFileObjectOpened,
				&nOffset,
				ENCRYPTION_HEAD_LOGO_SIZE,//pvcVolumeContext->ulSectorSize,//由于非缓存必须一次性读一个读一个SectorSize,所以这里就读一个ENCRYPTION_HEAD_LOGO_SIZE,//,ulLengthToRead,//读出一个标识长度的数据
				wBufferRead,//pwFileHead,//保存在pwFileHead
				FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,//FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
				NULL,
				FileCompleteCallback,
				(PVOID)&keEventComplete
				);

			KeWaitForSingleObject(&keEventComplete, Executive, KernelMode, TRUE, 0);

		}__except(EXCEPTION_EXECUTE_HANDLER){

//			ExFreeToNPagedLookasideList(
//				pvcVolumeContext->pnliReadEncryptedSignLookasideList,pwFileHead);

			return STATUS_UNSUCCESSFUL;
		}

		if( !NT_SUCCESS(status) ){
			statusRet = status;
			break;
		}
		
		//
		//恢复偏移量到0
		//
		status = FileSetOffset(pfiInstance,pfoFileObjectOpened,&nOffset);
		if( !NT_SUCCESS(status) )
		{
			statusRet = status;
			break;
		}

		//
		//比较标志是否相等
		//
		//DebugPrintFileObject("Read file check",pfoFileObjectOpened,FALSE);
		//KdPrint(("\t\tRead file %ws\n",wBufferRead));

		if( RtlCompareMemory(
				wBufferRead,
				wEncryptedLogo,
				ENCRYPTION_HEAD_LOGO_SIZE)
					== ENCRYPTION_HEAD_LOGO_SIZE){
			statusRet = STATUS_SUCCESS;

			DebugTraceFileAndProcess(
				DEBUG_TRACE_IMPORTANT_INFO|DEBUG_TRACE_CONFIDENTIAL,
				"FileIsEncrypted",
				FILE_OBJECT_NAME_BUFFER(pfoFileObjectOpened),
				("Confidential file detected.")
				);
//			ExFreeToNPagedLookasideList(
//				pvcVolumeContext->pnliReadEncryptedSignLookasideList,pwFileHead);
			break;
		}

//		ExFreeToNPagedLookasideList(
//			pvcVolumeContext->pnliReadEncryptedSignLookasideList,pwFileHead);

	}while(0);

	//
	//善后工作
	//
/*	
	//
	//要注意:
    //1.文件的CREATE改为OPEN.
    //2.文件的OVERWRITE去掉.不管是不是要加密的文件,
    //都必须这样做.否则的话,本来是试图生成文件的,
    //结果发现文件已经存在了.本来试图覆盖文件的,再
    //覆盖一次会去掉加密头.
	//

	//
	//如果连名字都没有 什么都没做 就不用修改了
	//
	if( !(ulFlags&FILE_IS_ENCRYPTED_DO_NOT_CHANGE_OPEN_WAY) )
	{
		ULONG ulDisp = FILE_OPEN;
		pfpParameters->Create.Options &= 0x00ffffff;
		pfpParameters->Create.Options |= (ulDisp << 24);
	}*/

	return	statusRet;
}
Esempio n. 2
0
EXTERN_C static NTSTATUS ScvnpReadFile(_In_ PFLT_CALLBACK_DATA Data,
                                       _In_ PCFLT_RELATED_OBJECTS FltObjects,
                                       _Out_ void *Buffer,
                                       _In_ ULONG BufferSize) {
  PAGED_CODE();

  // Use an existing file object when it is NOT IRP_MJ_CLEANUP.
  if (Data->Iopb->MajorFunction != IRP_MJ_CLEANUP) {
    LARGE_INTEGER byteOffset = {};
    auto status = FltReadFile(FltObjects->Instance, FltObjects->FileObject,
                              &byteOffset, BufferSize, Buffer,
                              FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
                              nullptr, nullptr, nullptr);
    if (!NT_SUCCESS(status)) {
      LOG_ERROR_SAFE("FltReadFile failed (%08x)", status);
      return status;
    }
    return status;
  }

  PFILE_OBJECT fileObject = nullptr;

  // Make a new file object since the file is already out of the current IO
  // path.
  PFLT_FILE_NAME_INFORMATION fileNameInformation = nullptr;
  auto status = FltGetFileNameInformationUnsafe(
      FltObjects->FileObject, FltObjects->Instance, FLT_FILE_NAME_NORMALIZED,
      &fileNameInformation);
  if (!NT_SUCCESS(status)) {
    return status;
  }

  OBJECT_ATTRIBUTES objAttr = RTL_INIT_OBJECT_ATTRIBUTES(
      &fileNameInformation->Name, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE);

  HANDLE fileHandle = nullptr;
  IO_STATUS_BLOCK ioStatus = {};
  status = FltCreateFile(
      FltObjects->Filter, FltObjects->Instance, &fileHandle, GENERIC_READ,
      &objAttr, &ioStatus, nullptr, FILE_ATTRIBUTE_NORMAL,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF,
      FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT |
          FILE_NON_DIRECTORY_FILE,
      nullptr, 0, 0);
  if (!NT_SUCCESS(status)) {
    LOG_ERROR_SAFE("FltCreateFile failed (%08x) for %wZ", status,
                   &fileNameInformation->Name);
    goto End;
  }

  status = ObReferenceObjectByHandle(fileHandle, 0, nullptr, KernelMode,
                                     reinterpret_cast<void **>(&fileObject),
                                     nullptr);
  if (!NT_SUCCESS(status)) {
    LOG_ERROR_SAFE("ObReferenceObjectByHandle failed (%08x) for %wZ", status,
                   &fileNameInformation->Name);
    goto End;
  }

  status = FltReadFile(FltObjects->Instance, fileObject, nullptr, BufferSize,
                       Buffer, 0, nullptr, nullptr, nullptr);
  if (!NT_SUCCESS(status)) {
    LOG_ERROR_SAFE("FltReadFile failed (%08x) for %wZ", status,
                   &fileNameInformation->Name);
    goto End;
  }

End:
  if (fileObject) {
    ObDereferenceObject(fileObject);
  }
  if (fileHandle) {
    FltClose(fileHandle);
  }
  if (fileNameInformation) {
    FltReleaseFileNameInformation(fileNameInformation);
  }
  return status;
}
Esempio n. 3
0
NTSTATUS
CopyFile(
		 PFLT_CALLBACK_DATA Data,
		 PCFLT_RELATED_OBJECTS FltObjects,
		 PUNICODE_STRING pCompleteFileName
		 )
{
	NTSTATUS status;
	UNICODE_STRING tempDeletedFilePath;
	OBJECT_ATTRIBUTES tempDeletedObject;
	IO_STATUS_BLOCK ioStatusTempDeleted;
	LARGE_INTEGER allocate;
	FILE_STANDARD_INFORMATION fileStandardInformation;
	HANDLE tempDeletedHandle;
	ULONG returnedLength;
	allocate.QuadPart = 0x10000;

	
	
	InitializeObjectAttributes(
		&tempDeletedObject,
		pCompleteFileName,
		OBJ_CASE_INSENSITIVE,
		NULL,
		NULL
		);
	status = FltQueryInformationFile(
		FltObjects->Instance,
		Data->Iopb->TargetFileObject,
		&fileStandardInformation,
		sizeof(FILE_STANDARD_INFORMATION),
		FileStandardInformation,
		&returnedLength
		);
	if(NT_SUCCESS(status))
	{
		allocate.QuadPart = fileStandardInformation.AllocationSize.QuadPart;
	} else {
		DbgPrint("CaptureFileMonitor: ERROR - Could not get files allocation size\n");
		return status;
	}

	status = FltCreateFile(
		FltObjects->Filter,
		NULL,
		&tempDeletedHandle,
		GENERIC_WRITE,
		&tempDeletedObject,
		&ioStatusTempDeleted,
		&allocate,
		FILE_ATTRIBUTE_NORMAL,
		0,
		FILE_CREATE,
		FILE_NON_DIRECTORY_FILE,
		NULL,
		0,
		0
		);

	if(NT_SUCCESS(status))
	{
		PVOID handleFileObject;
		PVOID pFileBuffer;
		LARGE_INTEGER offset;
	
		ULONG bytesRead = 0;
		ULONG bytesWritten = 0;
		offset.QuadPart = 0;
		status = ObReferenceObjectByHandle(
			tempDeletedHandle,
			0,
			NULL,
			KernelMode,
			&handleFileObject,
			NULL);
		if(!NT_SUCCESS(status))
		{
			DbgPrint("CaptureFileMonitor: ERROR - ObReferenceObjectByHandle - FAILED - %08x\n", status);
			return status;
		}
		
		pFileBuffer = ExAllocatePoolWithTag(NonPagedPool, 65536, FILE_POOL_TAG);
		
		if(pFileBuffer != NULL)
		{
			ObReferenceObject(Data->Iopb->TargetFileObject);
			do {
				IO_STATUS_BLOCK IoStatusBlock;
				bytesWritten = 0;
				status = FltReadFile(
					FltObjects->Instance,
					Data->Iopb->TargetFileObject,
					&offset,
					65536,
					pFileBuffer,
					FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
					&bytesRead ,
					NULL,
					NULL
					);
			
				if(NT_SUCCESS(status) && bytesRead > 0)
				{
					/* You can't use FltWriteFile here */
					/* Instance may not be the same instance we want to write to eg a
					   flash drive writing a file to a ntfs partition */
					status = ZwWriteFile(
						tempDeletedHandle,
						NULL,
						NULL,
						NULL,
						&IoStatusBlock,
						pFileBuffer,
						bytesRead,
						&offset,
						NULL
						);
					if(NT_SUCCESS(status))
					{
						//DbgPrint("WriteFile: FltReadFile - %08x\n", status);
					}
					/*
					status = FltWriteFile(
						FltObjects->Instance,
						handleFileObject,
						&offset,
						bytesRead,
						pFileBuffer,
						FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
						&bytesWritten,
						NULL,
						NULL
						);
						*/
				} else {
					//DbgPrint("CopyFile: FltReadFile - %08x\n", status);
					break;
				}
				offset.QuadPart += bytesRead;
			} while(bytesRead == 65536);
			ObDereferenceObject(Data->Iopb->TargetFileObject);
			ExFreePoolWithTag(pFileBuffer, FILE_POOL_TAG);
		}
		ObDereferenceObject(handleFileObject);
		FltClose(tempDeletedHandle);
	} else {
		if(status != STATUS_OBJECT_NAME_COLLISION)
		{
			DbgPrint("CaptureFileMonitor: ERROR - FltCreateFile FAILED - %08x\n",status);
			return status;
		}
	}
	return STATUS_SUCCESS;
}
Esempio n. 4
0
/*---------------------------------------------------------
函数名称:	FileReadEncryptionHeaderAndDeconstruct
函数描述:	非重入读取整个加密头 同时解包
输入参数:
			pfiInstance			过滤器实例
			pfoFileObject		文件对象
			pvcVolumeContext	卷上下文
			pscFileStreamContext文件流上下文
输出参数:
返回值:		
			STATUS_SUCCESS 成功	否则返回相应状态

其他:		

更新维护:	2011.4.9    修改为使用FltXXX版本
---------------------------------------------------------*/
NTSTATUS 
FileReadEncryptionHeaderAndDeconstruct( 
	__in PFLT_INSTANCE pfiInstance,
	__in PFILE_OBJECT  pfoFileObject,
	__in PVOLUME_CONTEXT pvcVolumeContext,
	__in PFILE_STREAM_CONTEXT  pscFileStreamContext
	)
{

	//完成事件
	KEVENT keEventComplete;

	//文件大小
    LARGE_INTEGER nFileSize;

	//偏移量
	LARGE_INTEGER nOffset;

	//长度 设置为标准加密头长度
    ULONG ulLength = CONFIDENTIAL_FILE_HEAD_SIZE;

	//各函数返回状态
    NTSTATUS status;

	//本函数要返回的状态
	NTSTATUS statusRet;

	//加密头地址
	PVOID pHeader;

	//
	//开始前先初始化事件对象
	//

    KeInitializeEvent(
		&keEventComplete,
		SynchronizationEvent,//同步事件
		FALSE//事件初始标志为FALSE
		);

	//
    //读取加密标识头
	//
    nOffset.QuadPart = 0;

//	ulLength = ROUND_TO_SIZE(ulLength,pvcVolumeContext->ulSectorSize);

	pHeader = ExAllocateFromNPagedLookasideList(&nliNewFileHeaderLookasideList);


	statusRet = FltReadFile(
				pfiInstance,//起始实例,用于防止重入
				pfoFileObject,//文件对象
				&nOffset,//偏移量 从头写起
				CONFIDENTIAL_FILE_HEAD_SIZE,//ulLength,//一个头的大小
				pHeader,
				FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET|FLTFL_IO_OPERATION_NON_CACHED,//非缓存写入
				NULL,//不需要返回读入的字节数
				FileCompleteCallback,//回调,确认执行完毕
				&keEventComplete//回调上下文,传递完成事件
				);

	//
	//等待完成
	//
	KeWaitForSingleObject(&keEventComplete, Executive, KernelMode, TRUE, 0);

	//
	//解包
	//
	FctDeconstructFileHead(pscFileStreamContext,pHeader);

	ExFreeToNPagedLookasideList(&nliNewFileHeaderLookasideList,pHeader);

	//
	//恢复偏移量到0
	//
	status = FileSetOffset(pfiInstance,pfoFileObject,&nOffset);

	if( !NT_SUCCESS(status) ){
		statusRet = status;
	}

	return statusRet;
}