文件删除
操作系统内部文件删除的步骤:
删除的操作,第一步是打开文件,打开文件的时候必须设置为可以删除。如果打开失败,则直接导致无法删除文件。第二步设置文件属性为用于删除,第三步关闭文件即可。关闭的时候,文件被系统删除。 这里的“删除”并非把文件删除到回收站,而是彻底的就爱那个文件清除,文件删除到回收站只是一种改名操作。
I、打开文件 IoCreateFile
完成例程 NTSTATUS SetInformationCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { Irp->UserIosb->Status = Irp->IoStatus.Status; Irp->UserIosb->Information = Irp->IoStatus.Information; KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE); IoFreeIrp(Irp); return STATUS_MORE_PROCESSING_REQUIRED; } /************************************************************************/ /* 根据文件路径打开文件 并获取相应的文件句柄 */ /************************************************************************/ HANDLE OpenFile( IN PCWSTR FileName, IN ACCESS_MASK DesiredAccess, IN ULONG ShareAccess ) { NTSTATUS ntStatus; UNICODE_STRING uniFileName; OBJECT_ATTRIBUTES objectAttributes; HANDLE ntFileHandle; IO_STATUS_BLOCK ioStatus; //确保IRQL在PASSIVE_LEVEL上 if (KeGetCurrentIrql() > PASSIVE_LEVEL) { KdPrint(("Do Not At PASSIVE_LEVEL!\n")); return 0; } RtlInitUnicodeString(&uniFileName, FileName); //初始化对象属性 InitializeObjectAttributes(&objectAttributes, &uniFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); ntStatus = IoCreateFile(&ntFileHandle, GENERIC_READ|SYNCHRONIZE, &objectAttributes, &ioStatus, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN, 0, NULL, 0, CreateFileTypeNone, NULL, IO_NO_PARAMETER_CHECKING); if (!NT_SUCCESS(ntStatus)) { KdPrint(("IrpCreateFile: IoCreateFile 0x%X.\n",ntStatus)); return 0; } return ntFileHandle; } BOOLEAN DeleteFile( IN HANDLE FileHandle ) { NTSTATUS ntStatus = STATUS_SUCCESS; PFILE_OBJECT fileObject; PDEVICE_OBJECT DeviceObject; PIRP Irp; KEVENT SycEvent ; FILE_DISPOSITION_INFORMATION FileInformation; IO_STATUS_BLOCK ioStatus; PIO_STACK_LOCATION irpSp; PSECTION_OBJECT_POINTERS pSectionObjectPointer; // 获取文件对象 ntStatus = ObReferenceObjectByHandle ( FileHandle, DELETE, *IoFileObjectType, KernelMode, (PVOID*)&fileObject, NULL) ; if ( !NT_SUCCESS(ntStatus) ) { DbgPrint ( "ObReferenceObjectByHandle error!" ) ; return FALSE; } // 获取与指定文件对象相关联的设备对象 DeviceObject = IoGetRelatedDeviceObject ( fileObject ) ; // 创建IRP Irp = IoAllocateIrp ( DeviceObject->StackSize, TRUE ) ; if (Irp == NULL) { ObDereferenceObject ( fileObject ) ; DbgPrint ( "FD_DeleteFile IoAllocateIrp error" ) ; return FALSE; } // 初始化同步事件对象 KeInitializeEvent ( &SycEvent, SynchronizationEvent, FALSE ) ; FileInformation.DeleteFile = TRUE; // 初始化IRP Irp->AssociatedIrp.SystemBuffer = &FileInformation; Irp->UserEvent = &SycEvent; Irp->UserIosb = &ioStatus; Irp->Tail.Overlay.OriginalFileObject = fileObject; Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread(); Irp->RequestorMode = KernelMode; // 设置IRP堆栈 irpSp = IoGetNextIrpStackLocation(Irp); irpSp->MajorFunction = IRP_MJ_SET_INFORMATION; irpSp->DeviceObject = DeviceObject; irpSp->FileObject = fileObject; irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION); irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation; irpSp->Parameters.SetFile.FileObject = fileObject; // 设置完成例程 IoSetCompletionRoutine ( Irp, SetInformationCompletion, NULL, TRUE, TRUE, TRUE ) ; // 如果没有这3行,就无法删除正在运行的文件 pSectionObjectPointer = fileObject->SectionObjectPointer; pSectionObjectPointer->ImageSectionObject = 0; pSectionObjectPointer->DataSectionObject = 0; /* 强制删除文件的思路很简单,把SECTION_OBJECT_POINTERS结构的DataSectionObject和 ImageSectionObject两个域清空即可删除正在运行的文件。 如果不清空就不能删除运行中的文件。正在运行的文件的这两个域值不为0而文件系 统正在根据这两个域决定该文件是否可以删除。如果文件系统检测这两个值为0, 就理解为文件没有被使用,可以删除。接下去,就是直接发IRP。 */ // 派发IRP IoCallDriver ( DeviceObject, Irp ) ; // 等待IRP完成 KeWaitForSingleObject ( &SycEvent, Executive, KernelMode, TRUE, NULL); // 递减引用计数 ObDereferenceObject ( fileObject ) ; return TRUE ; }
NTSTATUS
IoCreateFile(
__out PHANDLE FileHandle,//返回的文件句柄
__in ACCESS_MASK DesiredAccess,//访问权限,FILE_READ_ATTRIBUTES
__in POBJECT_ATTRIBUTES ObjectAttributes,
__out PIO_STATUS_BLOCK IoStatusBlock,
__in_opt PLARGE_INTEGER AllocationSize,
__in ULONG FileAttributes,
__in ULONG ShareAccess,
__in ULONG Disposition,
__in ULONG CreateOptions,
__in_opt PVOID EaBuffer,
__in ULONG EaLength,
__in CREATE_FILE_TYPE CreateFileType,
__in_opt PVOID InternalParameters,
__in ULONG Options
);
ObjectAttributes 为文件属性
//初始化对象属性
InitializeObjectAttributes(&objectAttributes, &uniFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
uniFileName 为输入的文件名 绝对路径 "\\??\\C:\\test.exe"(或者"\\DosDevice\\C:\\test.exe")
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
至此生成文件句柄,再根据文件句柄获取文件对象FileObject
// 获取文件对象
ntStatus = ObReferenceObjectByHandle ( FileHandle, DELETE,
*IoFileObjectType, KernelMode, (PVOID*)&fileObject, NULL) ;
FileHandle :IoCreateFile生成的文件句柄
IoFileObjectType:为系统的全局变量
fileObject:生成的文件对象
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 获取与指定文件对象相关联的设备对象
DeviceObject = IoGetRelatedDeviceObject ( fileObject ) ;
// 创建IRP
Irp = IoAllocateIrp ( DeviceObject->StackSize, TRUE ) ;
// 初始化同步事件对象
KeInitializeEvent ( &SycEvent, SynchronizationEvent, FALSE ) ;
FileInformation.DeleteFile = TRUE;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 初始化IRP
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &SycEvent;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
// 设置IRP堆栈
irpSp = IoGetNextIrpStackLocation(Irp);
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
// 设置完成例程
IoSetCompletionRoutine ( Irp, SetInformationCompletion, NULL, TRUE, TRUE, TRUE ) ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
pSectionObjectPointer = fileObject->SectionObjectPointer;
pSectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
强制删除文件的思路很简单,把SECTION_OBJECT_POINTERS结构的DataSectionObject和 ImageSectionObject两个域清空即可删除正在运行的文件。
如果不清空就不能删除运行中的文件。正在运行的文件的这两个域值不为0而文件系 统正在根据这两个域决定该文件是否可以删除。如果文件系统检测这两个值为0,
就理解为文件没有被使用,可以删除。接下去,就是直接发IRP。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
收尾工作
IoCallDriver ( DeviceObject, Irp ) ;
// 等待IRP完成
KeWaitForSingleObject ( &SycEvent, Executive, KernelMode, TRUE, NULL);
// 递减引用计数
ObDereferenceObject ( fileObject ) ;
///////////////////////////////////////////////////////////////////////////////////////////////////