#include "pch.h" #include "FileManager.h" #include "ObjectAttributes.h" #include "kstring.h" #include "Memory.h" NTSTATUS FileManager::Open(PUNICODE_STRING fileName, FileAccessMask accessMask /* = FileAccessMask::All */) { NTSTATUS status; IO_STATUS_BLOCK ioStatus; ObjectAttributes attr(fileName, ObjectAttributesFlags::Caseinsensive | ObjectAttributesFlags::KernelHandle); status = ZwCreateFile(&_handle, static_cast(accessMask), &attr, &ioStatus, nullptr, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, // 打开或创建文件 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT| // 文件被同步的打开 FILE_RANDOM_ACCESS, nullptr, 0); return status; } NTSTATUS FileManager::OpenFileForRead(PCWSTR path) { UNICODE_STRING name; RtlInitUnicodeString(&name, path); ObjectAttributes attr(&name, ObjectAttributesFlags::Caseinsensive | ObjectAttributesFlags::KernelHandle); IO_STATUS_BLOCK ioStatus; return ZwOpenFile(&_handle, FILE_GENERIC_READ, &attr, &ioStatus, FILE_SHARE_READ, 0); } NTSTATUS FileManager::Close() { if (_handle) return ZwClose(_handle); } FileManager::~FileManager() { Close(); } NTSTATUS FileManager::ReadFile(PVOID buffer,ULONG size,PIO_STATUS_BLOCK ioStatus,PLARGE_INTEGER offset) { NTSTATUS status; status = ZwReadFile(_handle, nullptr, // 同步读 nullptr, // nullptr, // ioStatus, buffer, size, offset, // specifies the starting byte offset in the file where the read operation will begin nullptr); return status; } NTSTATUS FileManager::WriteFile(PVOID buffer, ULONG size, PIO_STATUS_BLOCK ioStatus, PLARGE_INTEGER offset) { NTSTATUS status; status = ZwWriteFile(_handle, nullptr,// 同步写 nullptr, nullptr, ioStatus,buffer,size,offset,nullptr); return status; } NTSTATUS FileManager::GetFileSize(PLARGE_INTEGER fileSize) { FILE_STANDARD_INFORMATION info = { 0 }; IO_STATUS_BLOCK ioStatus; NTSTATUS status = ZwQueryInformationFile(_handle, &ioStatus, &info, sizeof(info), FileStandardInformation); if (NT_SUCCESS(status)) { if (!fileSize) { return STATUS_INVALID_PARAMETER; } *fileSize = info.EndOfFile; return status; } return status; } /* Note Do not specify FILE_READ_DATA, FILE_WRITE_DATA, FILE_APPEND_DATA, or FILE_EXECUTE when you create or open a directory. */ NTSTATUS FileManager::DeleteFile(PUNICODE_STRING fileName) { NTSTATUS status; IO_STATUS_BLOCK ioStatus; ObjectAttributes attr(fileName, ObjectAttributesFlags::Caseinsensive | ObjectAttributesFlags::KernelHandle); status = ZwDeleteFile(&attr); return status; } NTSTATUS FileManager::ConvertDosNameToNtName(_In_ PCWSTR dosName, _Out_ PUNICODE_STRING ntName) { ntName->Buffer = nullptr; // in case of failure auto dosNameLen = ::wcslen(dosName); if (dosNameLen < 3) return STATUS_BUFFER_TOO_SMALL; // make sure we have a driver letter if (dosName[2] != L'\\' || dosName[1] != L':') return STATUS_INVALID_PARAMETER; kstring<'rgmf'> symLink(L"\\??\\"); symLink.Append(dosName, 2); // driver letter and colon UNICODE_STRING symLinkFull; symLink.GetUnicodeString(&symLinkFull); OBJECT_ATTRIBUTES symLinkAttr; InitializeObjectAttributes(&symLinkAttr, &symLinkFull, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, nullptr, nullptr); HANDLE hSymLink = nullptr; auto status = STATUS_SUCCESS; do { // open symbolic link status = ZwOpenSymbolicLinkObject(&hSymLink, GENERIC_READ, &symLinkAttr); if (!NT_SUCCESS(status)) break; USHORT maxLen = 1024; // arbitray ntName->Buffer = (WCHAR*)ExAllocatePool(PagedPool, maxLen); if (!ntName->Buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ntName->MaximumLength = maxLen; // read target of symbolic link status = ZwQuerySymbolicLinkObject(hSymLink, ntName, nullptr); if (!NT_SUCCESS(status)) break; } while (false); if (!NT_SUCCESS(status)) { if (ntName->Buffer) { ExFreePool(ntName->Buffer); ntName->Buffer = nullptr; } } else { RtlAppendUnicodeToString(ntName, dosName + 2); // directory part } if (hSymLink) ZwClose(hSymLink); return status; } NTSTATUS FileManager::GetRootName(_In_ PCWSTR dosName, _Out_ PUNICODE_STRING rootName) { rootName->Buffer = nullptr; // in case of failure auto dosNameLen = ::wcslen(dosName); if (dosNameLen < 3) return STATUS_BUFFER_TOO_SMALL; // make sure we have a driver letter if (dosName[2] != L'\\' || dosName[1] != L':') return STATUS_INVALID_PARAMETER; kstring<'rgmf'> symLink(L"\\??\\"); symLink.Append(dosName, 3); // driver letter,colon,backslash symLink.GetUnicodeString(rootName); return STATUS_SUCCESS; } VOID FileManager::FreeMdl(_In_ PMDL mdl){ PMDL pCur = mdl, pNext; while (pCur != nullptr) { pNext = pCur->Next; if (pCur->MdlFlags & MDL_PAGES_LOCKED) { MmUnlockPages(pCur); } IoFreeMdl(pCur); pCur = pNext; } } NTSTATUS IoCompletionRoutine( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context){ PKEVENT UserEvent = Irp->UserEvent; ASSERT(UserEvent != nullptr); // 拷贝完成状态 RtlCopyMemory(Irp->UserIosb, &Irp->IoStatus, sizeof(IO_STATUS_BLOCK)); // 检查并释放MDL if (Irp->MdlAddress != nullptr) { FileManager::FreeMdl(Irp->MdlAddress); Irp->MdlAddress = nullptr; } // 释放Irp IoFreeIrp(Irp); KeSetEvent(UserEvent, IO_NO_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS FileManager::IrpCreateFile( _Out_ PFILE_OBJECT* pFileObject, _Out_ PDEVICE_OBJECT* pDeviceObject, _In_ ACCESS_MASK DesiredAccess, _In_ PCWSTR DosName, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _In_opt_ PLARGE_INTEGER AllocationSize, _In_ ULONG FileAttributes, _In_ ULONG ShareAccess, _In_ ULONG CreateDisposition, _In_ ULONG CreateOptions, _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, _In_ ULONG EaLength ) { PAUX_ACCESS_DATA AuxData = nullptr; HANDLE hRoot = nullptr; PFILE_OBJECT RootObject = nullptr, FileObject = nullptr; PDEVICE_OBJECT DeviceObject = nullptr, RealDeviceObject = nullptr; PIRP Irp; PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_UNSUCCESSFUL; ACCESS_STATE AccessState; KEVENT notifyEvent; IO_SECURITY_CONTEXT IoSecurityContext; UNICODE_STRING rootName, fileName; RtlInitUnicodeString(&fileName, &DosName[2]); do { // 打开根目录 IO_STATUS_BLOCK ioStatus; status = GetRootName(DosName, &rootName); if (!NT_SUCCESS(status)) { break; } ObjectAttributes attr(&rootName, ObjectAttributesFlags::Caseinsensive | ObjectAttributesFlags::KernelHandle); status = IoCreateFile(&hRoot, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &ioStatus, nullptr, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, nullptr, 0, CreateFileTypeNone, nullptr, IO_NO_PARAMETER_CHECKING); *IoStatusBlock = ioStatus; if (!NT_SUCCESS(status)) { break; } // 得到根目录文件对象 status = ObReferenceObjectByHandle(hRoot, FILE_READ_ATTRIBUTES, *IoFileObjectType, KernelMode, (PVOID*)&RootObject, nullptr); if (!NT_SUCCESS(status)) { break; } if (RootObject->Vpb == nullptr || RootObject->Vpb->DeviceObject == nullptr || RootObject->Vpb->RealDevice == nullptr) { status = STATUS_INVALID_PARAMETER; break; } // 得到文件系统卷设备 DeviceObject = RootObject->Vpb->DeviceObject; // 卷管理器生成的卷设备(物理设备) RealDeviceObject = RootObject->Vpb->RealDevice; RootObject = nullptr; ZwClose(hRoot); hRoot = nullptr; // 创建文件对象 attr = ObjectAttributes(nullptr, ObjectAttributesFlags::Caseinsensive); status = ObCreateObject(KernelMode, *IoFileObjectType, &attr, KernelMode, nullptr, sizeof(FILE_OBJECT), 0, 0, (PVOID*)&FileObject); if (!NT_SUCCESS(status)) { break; } RtlZeroMemory(FileObject, sizeof(FILE_OBJECT)); FileObject->Type = IO_TYPE_FILE; FileObject->Size = sizeof(FILE_OBJECT); FileObject->DeviceObject = RealDeviceObject; FileObject->Flags = FO_SYNCHRONOUS_IO; FileObject->FileName.Buffer = fileName.Buffer; FileObject->FileName.Length = fileName.Length; FileObject->FileName.MaximumLength = fileName.MaximumLength; KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE); // 分配AUX_ACCESS_DATA缓冲区 AuxData = new (NonPagedPool) AUX_ACCESS_DATA; if (AuxData == nullptr) { status = STATUS_INSUFFICIENT_RESOURCES; break; } status = SeCreateAccessState(&AccessState, AuxData, DesiredAccess, IoGetFileObjectGenericMapping()); if (!NT_SUCCESS(status)) { break; } // 分配IRP Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if (Irp == nullptr) { status = STATUS_INSUFFICIENT_RESOURCES; break; } // 填写Irp Irp->MdlAddress = nullptr; Irp->UserBuffer = nullptr; Irp->AssociatedIrp.SystemBuffer = EaBuffer; Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API; Irp->RequestorMode = KernelMode; Irp->PendingReturned = FALSE; Irp->Cancel = FALSE; Irp->CancelRoutine = nullptr; KeInitializeEvent(¬ifyEvent, NotificationEvent, FALSE); Irp->UserEvent = ¬ifyEvent; Irp->UserIosb = &ioStatus; Irp->Overlay.AllocationSize.QuadPart = AllocationSize != nullptr ? AllocationSize->QuadPart : 0; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); Irp->Tail.Overlay.OriginalFileObject = FileObject; Irp->Tail.Overlay.AuxiliaryBuffer = nullptr; // 得到下层栈空间 stack = IoGetNextIrpStackLocation(Irp); ASSERT(stack != nullptr); stack->MajorFunction = IRP_MJ_CREATE; IoSecurityContext.SecurityQos = nullptr; IoSecurityContext.AccessState = &AccessState; IoSecurityContext.DesiredAccess = DesiredAccess; IoSecurityContext.FullCreateOptions = 0; stack->Parameters.Create.SecurityContext = &IoSecurityContext; stack->Parameters.Create.Options = (CreateDisposition << 24) | CreateOptions; stack->Parameters.Create.FileAttributes = (USHORT)FileAttributes; stack->Parameters.Create.ShareAccess = (USHORT)ShareAccess; stack->Parameters.Create.EaLength = EaLength; stack->FileObject = FileObject; stack->DeviceObject = DeviceObject; // 设置完成例程 IoSetCompletionRoutine(Irp, IoCompletionRoutine, nullptr, TRUE, TRUE, TRUE); // 下发Irp请求 status = IoCallDriver(DeviceObject, Irp); // 等待完成 KeWaitForSingleObject(¬ifyEvent, Executive, KernelMode, FALSE, nullptr); // 得到完成状态 *IoStatusBlock = ioStatus; status = IoStatusBlock->Status; } while (false); if (NT_SUCCESS(status)) { //成功后的处理 ASSERT(FileObject != NULL && FileObject->DeviceObject != NULL); InterlockedIncrement(&FileObject->DeviceObject->ReferenceCount); if (FileObject->Vpb != NULL) { InterlockedIncrement((PLONG)&FileObject->Vpb->ReferenceCount); } *pFileObject = FileObject; *pDeviceObject = DeviceObject; } else { //失败后的处理 if (FileObject != NULL) { FileObject->DeviceObject = NULL; ObDereferenceObject(FileObject); } IoStatusBlock->Status = status; } //检查并释放相关资源 if (AuxData != NULL) { delete AuxData; } if (RootObject != NULL) { ObDereferenceObject(RootObject); } if (hRoot != NULL) { ZwClose(hRoot); } return status; } //获取目录下的文件及子目录(MajorFunction: IRP_MJ_DIRECTORY_CONTROL, MinorFunction: IRP_MN_QUERY_DIRECTORY) NTSTATUS FileManager::IrpQueryDirectoryFile( _In_ PDEVICE_OBJECT DeviceObject, _In_ PFILE_OBJECT FileObject, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _Out_writes_bytes_(Length) PVOID FileInformation, _In_ ULONG Length, _In_ FILE_INFORMATION_CLASS FileInformationClass, _In_ BOOLEAN ReturnSingleEntry, _In_opt_ PUNICODE_STRING FileName, _In_ BOOLEAN RestartScan ) { PIRP Irp; PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_UNSUCCESSFUL; KEVENT notifyEvent; IO_STATUS_BLOCK ioStatus; //分配IRP Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); RtlZeroMemory(IoStatusBlock, sizeof(IO_STATUS_BLOCK)); if (Irp == NULL) { IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES; } //填写IRP Irp->MdlAddress = nullptr; Irp->AssociatedIrp.SystemBuffer = nullptr; Irp->UserBuffer = FileInformation; Irp->Flags = IRP_SYNCHRONOUS_API; Irp->RequestorMode = KernelMode; Irp->UserIosb = &ioStatus; KeInitializeEvent(¬ifyEvent, NotificationEvent, FALSE); Irp->UserEvent = ¬ifyEvent; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); Irp->Tail.Overlay.OriginalFileObject = FileObject; //得到下层栈空间 stack = IoGetNextIrpStackLocation(Irp); ASSERT(stack != NULL); //填写下层栈空间 stack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; stack->MinorFunction = IRP_MN_QUERY_DIRECTORY; stack->Flags = 0; if (ReturnSingleEntry) stack->Flags |= SL_RETURN_SINGLE_ENTRY; if (RestartScan) stack->Flags |= SL_RESTART_SCAN; stack->Parameters.QueryDirectory.Length = Length; stack->Parameters.QueryDirectory.FileName = FileName; stack->Parameters.QueryDirectory.FileInformationClass = FileInformationClass; stack->DeviceObject = DeviceObject; stack->FileObject = FileObject; //设置完成例程: IoSetCompletionRoutine(pIrp, FileOperationCompletion, NULL, TRUE, TRUE, TRUE); stack->CompletionRoutine = IoCompletionRoutine; stack->Context = NULL; stack->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL; //下发IO请求 status = IoCallDriver(DeviceObject, Irp); //等候请求完成 KeWaitForSingleObject(¬ifyEvent, Executive, KernelMode, FALSE, NULL); //得到完成状态 *IoStatusBlock = ioStatus; status = IoStatusBlock->Status; return status; } /* ZwQueryInformationFile( _In_ HANDLE FileHandle, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _Out_writes_bytes_(Length) PVOID FileInformation, _In_ ULONG Length, _In_ FILE_INFORMATION_CLASS FileInformationClass ); */ //文件查询(IRP_MJ_QUERY_INFORMATION) NTSTATUS FileManager::IrpQueryInformationFile( _In_ PDEVICE_OBJECT DeviceObject, _In_ PFILE_OBJECT FileObject, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _Out_writes_bytes_(Length) PVOID FileInformation, _In_ ULONG Length, _In_ FILE_INFORMATION_CLASS FileInformationClass ){ PIRP Irp; PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK ioStatus; KEVENT notifyEvent; //分配IRP Irp = IoAllocateIrp(DeviceObject->StackSize,FALSE); RtlZeroMemory(IoStatusBlock,sizeof(IO_STATUS_BLOCK)); if (Irp == NULL) { IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES; } //填写IRP Irp->MdlAddress = NULL; Irp->AssociatedIrp.SystemBuffer = FileInformation; Irp->UserBuffer = NULL; Irp->Flags = IRP_SYNCHRONOUS_API; Irp->RequestorMode = KernelMode; Irp->UserIosb = &ioStatus; KeInitializeEvent(¬ifyEvent, NotificationEvent, FALSE); Irp->UserEvent = ¬ifyEvent; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); Irp->Tail.Overlay.OriginalFileObject = FileObject; //获取下层栈空间 stack = IoGetNextIrpStackLocation(Irp); ASSERT(stack != NULL); //填写栈空间 stack->MajorFunction = IRP_MJ_QUERY_INFORMATION; stack->Parameters.QueryFile.FileInformationClass = FileInformationClass; stack->Parameters.QueryFile.Length = Length; stack->FileObject = FileObject; stack->DeviceObject = DeviceObject; //设置完成例程: IoSetCompletionRoutine(pIrp,FileOperationCompletion,NULL,TRUE,TRUE,TRUE); stack->CompletionRoutine = IoCompletionRoutine; stack->Context = NULL; stack->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL; //下发IRP请求 status = IoCallDriver(DeviceObject,Irp); //等候请求完成 KeWaitForSingleObject(¬ifyEvent, Executive, KernelMode, FALSE, NULL); //得到完成状态 *IoStatusBlock = ioStatus; status = IoStatusBlock->Status; return status; } //文件设置(IRP_MJ_SET_INFORMATION) NTSTATUS FileManager::IrpSetInformationFile( _In_ PDEVICE_OBJECT DeviceObject, _In_ PFILE_OBJECT FileObject, _In_opt_ PFILE_OBJECT TargetFileObject, _Out_ PIO_STATUS_BLOCK IoStatusBlock, _In_reads_bytes_(Length) PVOID FileInformation, _In_ ULONG Length, _In_ FILE_INFORMATION_CLASS FileInformationClass ) { PIRP Irp = NULL; PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK ioStatus; KEVENT notifyEvent; //分配IRP Irp = IoAllocateIrp(DeviceObject->StackSize,FALSE); RtlZeroMemory(IoStatusBlock,sizeof(IO_STATUS_BLOCK)); if (Irp == NULL) { IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES; } //填写IRP Irp->MdlAddress = NULL; Irp->UserBuffer = NULL; Irp->AssociatedIrp.SystemBuffer = FileInformation; Irp->Flags = IRP_SYNCHRONOUS_API; Irp->RequestorMode = KernelMode; Irp->UserIosb = &ioStatus; KeInitializeEvent(¬ifyEvent,NotificationEvent,FALSE); Irp->UserEvent = ¬ifyEvent; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); Irp->Tail.Overlay.OriginalFileObject = FileObject; //得到下层栈空间 stack = IoGetNextIrpStackLocation(Irp); ASSERT(stack != NULL); //填写栈空间 stack->MajorFunction = IRP_MJ_SET_INFORMATION; stack->Parameters.SetFile.Length = Length; stack->Parameters.SetFile.FileInformationClass = FileInformationClass; stack->Parameters.SetFile.FileObject = TargetFileObject; //对于文件重命名,创建硬链接需要考虑: ReplaceIfExists switch (FileInformationClass) { case FileRenameInformation: stack->Parameters.SetFile.ReplaceIfExists = ((PFILE_RENAME_INFORMATION)FileInformation)->ReplaceIfExists; break; case FileLinkInformation: stack->Parameters.SetFile.ReplaceIfExists = ((PFILE_LINK_INFORMATION)FileInformation)->ReplaceIfExists; break; } stack->FileObject = FileObject; stack->DeviceObject = DeviceObject; //设置完成例程: IoSetCompletionRoutine(pIrp,FileOperationCompletion,NULL,TRUE,TRUE,TRUE); stack->CompletionRoutine = IoCompletionRoutine; stack->Context = NULL; stack->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL; //下发IRP请求 status = IoCallDriver(DeviceObject,Irp); //等候IRP完成 KeWaitForSingleObject((PVOID)¬ifyEvent, Executive, KernelMode, FALSE, NULL); //保存完成状态 *IoStatusBlock = ioStatus; status = IoStatusBlock->Status; return status; } //自己发送IRP请求关闭文件的第1步(IRP_MJ_CLEANUP),表示文件对象句柄数为0 NTSTATUS FileManager::IrpCleanupFile( _In_ PDEVICE_OBJECT DeviceObject, _In_ PFILE_OBJECT FileObject ) { PIRP Irp; PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_UNSUCCESSFUL; KEVENT notifyEvent; IO_STATUS_BLOCK ioStatus; //卷参数块检查 if (FileObject->Vpb == NULL || FileObject->Vpb->DeviceObject == NULL) { return STATUS_INVALID_PARAMETER; } // // IRP_MJ_CLEANUP // //分配IRP Irp = IoAllocateIrp(DeviceObject->StackSize,FALSE); if (Irp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } //填写IRP Irp->MdlAddress = nullptr; Irp->AssociatedIrp.SystemBuffer = nullptr; Irp->UserBuffer = nullptr; Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API; Irp->RequestorMode = KernelMode; Irp->UserIosb = &ioStatus; KeInitializeEvent(¬ifyEvent, NotificationEvent, FALSE); Irp->UserEvent = ¬ifyEvent; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); Irp->Tail.Overlay.OriginalFileObject = FileObject; //得到下层栈空间 stack = IoGetNextIrpStackLocation(Irp); ASSERT(stack != NULL); //填写下层栈空间 stack->MajorFunction = IRP_MJ_CLEANUP; stack->FileObject = FileObject; stack->DeviceObject = DeviceObject; //设置完成例程: IoSetCompletionRoutine(pIrp,FileOperationCompletion,NULL,TRUE,TRUE,TRUE); stack->CompletionRoutine = IoCompletionRoutine; stack->Context = nullptr; stack->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL; //下发请求 status = IoCallDriver(DeviceObject,Irp); //等待请求结束 KeWaitForSingleObject(¬ifyEvent, Executive, KernelMode, FALSE, NULL); //得到完成状态 status = ioStatus.Status; return status; } //自己发送IRP请求关闭文件的第2步(IRP_MJ_CLOSE),表示引用计数数为0 NTSTATUS FileManager::IrpCloseFile( _In_ PDEVICE_OBJECT DeviceObject, _In_ PFILE_OBJECT FileObject ){ PIRP Irp; PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_UNSUCCESSFUL; KEVENT notifyEvent; IO_STATUS_BLOCK ioStatus; //检查并设置文件打开取消标志 if (FileObject->Vpb != NULL && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { InterlockedDecrement(reinterpret_cast(&FileObject->Vpb->ReferenceCount)); FileObject->Flags |= FO_FILE_OPEN_CANCELLED; } //分配IRP Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if (Irp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } //填写IRP Irp->MdlAddress = nullptr; Irp->AssociatedIrp.SystemBuffer = nullptr; Irp->UserBuffer = nullptr; Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API; Irp->RequestorMode = KernelMode; Irp->UserIosb = &ioStatus; KeInitializeEvent(¬ifyEvent, NotificationEvent, FALSE); Irp->UserEvent = ¬ifyEvent; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); Irp->Tail.Overlay.OriginalFileObject = FileObject; //得到IRP下层栈空间 stack = IoGetNextIrpStackLocation(Irp); ASSERT(stack != NULL); //填写IRP下层栈空间 stack->MajorFunction = IRP_MJ_CLOSE; stack->FileObject = FileObject; stack->DeviceObject = DeviceObject; //设置完成例程: IoSetCompletionRoutine(pIrp,FileOperationCompletion,NULL,TRUE,TRUE,TRUE); stack->CompletionRoutine = IoCompletionRoutine; stack->Context = NULL; stack->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL; //下发IRP请求 status = IoCallDriver(DeviceObject,Irp); //等待请求结束 KeWaitForSingleObject(¬ifyEvent,Executive, KernelMode, FALSE, NULL); //得到完成状态 status = ioStatus.Status; return status; } //自己发送IRP请求删除文件 NTSTATUS FileManager::IrpDeleteFile( IN PDEVICE_OBJECT DeviceObject, //如果指定为pFileObject->Vpb->DeviceObject,可绕过文件系统过滤驱动 IN PFILE_OBJECT FileObject ){ PFILE_BASIC_INFORMATION fileBasicInfo = NULL; PFILE_DISPOSITION_INFORMATION fileDispInfo = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK ioStatus; SECTION_OBJECT_POINTERS secObjPointers; PAGED_CODE(); ASSERT(DeviceObject != NULL && FileObject != NULL); do { //分配属性缓冲区 fileBasicInfo = new (PagedPool) FILE_BASIC_INFORMATION; if (fileBasicInfo == nullptr) { status = STATUS_INSUFFICIENT_RESOURCES; break; } //下发IRP_MJ_QUERY_INFORMATION请求查询文件属性 status = IrpQueryInformationFile(DeviceObject,FileObject, &ioStatus, (PVOID)fileBasicInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(status)) { break; } //检查并去掉只读属性 if (fileBasicInfo->FileAttributes & FILE_ATTRIBUTE_READONLY) { fileBasicInfo->FileAttributes &= ~FILE_ATTRIBUTE_READONLY; //下发IRP_MJ_SET_INFORMATION请求去掉文件只读属性 status = IrpSetInformationFile(DeviceObject, FileObject, NULL, &ioStatus, (PVOID)fileBasicInfo, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(status)) { break; } } delete fileBasicInfo; fileBasicInfo = nullptr; //分配删除操作缓冲区 fileDispInfo = new (PagedPool) FILE_DISPOSITION_INFORMATION; if (fileDispInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } fileDispInfo->DeleteFile = TRUE; //关闭时删除 //检查并备份文件对象的SectionObjectPointer所指的内容,然后各域置空 if (FileObject->SectionObjectPointer != NULL) { secObjPointers.DataSectionObject = FileObject->SectionObjectPointer->DataSectionObject; secObjPointers.SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; secObjPointers.ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject; FileObject->SectionObjectPointer->DataSectionObject = nullptr; FileObject->SectionObjectPointer->SharedCacheMap = nullptr; FileObject->SectionObjectPointer->ImageSectionObject = nullptr; } //下发IRP_MJ_SET_INFORMATION请求,设置关闭时删除 status = IrpSetInformationFile(DeviceObject, FileObject, NULL, &ioStatus, (PVOID)fileDispInfo, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation); //检查并恢复文件对象的SectionObjectPointer所指的内容 if (FileObject->SectionObjectPointer != NULL) { FileObject->SectionObjectPointer->DataSectionObject = secObjPointers.DataSectionObject; FileObject->SectionObjectPointer->SharedCacheMap = secObjPointers.SharedCacheMap; FileObject->SectionObjectPointer->ImageSectionObject = secObjPointers.ImageSectionObject; } } while (FALSE); //检查并释放缓冲区 if (fileDispInfo != NULL) { delete fileBasicInfo; fileBasicInfo = nullptr; } if (fileBasicInfo != nullptr) { delete fileBasicInfo; fileBasicInfo = nullptr; } return status; } //强删文件(设备控制请求中调用) NTSTATUS FileManager::ForceDeleteFile(PCWSTR fileName){ PDEVICE_OBJECT DeviceObject = nullptr; PFILE_OBJECT FileObject = nullptr; NTSTATUS status = STATUS_NOT_SUPPORTED; IO_STATUS_BLOCK ioStatus; UNICODE_STRING unsFilePath; PAGED_CODE(); //自己发送IRP_MJ_CREATE请求打开文件 status = IrpCreateFile(&FileObject, &DeviceObject, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE, fileName, &ioStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_VALID_FLAGS, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(status)) { return status; } //强删文件 status = IrpDeleteFile(DeviceObject, FileObject); //自己发送请求IRP_MJ_CLEANUP/IRP_MJ_CLOSE关闭文件 status = IrpCleanupFile(DeviceObject, FileObject); ASSERT(NT_SUCCESS(status)); if (NT_SUCCESS(status)) { status = IrpCloseFile(DeviceObject, FileObject); ASSERT(NT_SUCCESS(status)); } return status; } NTSTATUS FileManager::SetInformationFile(PIO_STATUS_BLOCK ioStatus, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) { return ZwSetInformationFile(_handle, ioStatus, FileInformation, Length, FileInformationClass); }