上面这个连接中的DEMO是比较完整软件,这里我把其中发IRP强制删除文件的部分抽出来了,
学习了下,顺便加点注释。这个程序比较简单,主要练习了两个点:
(1)模拟发送IRP
(2)使用内核事件对象同步IRP的执行
强制删除文件的思路很简单,把SECTION_OBJECT_POINTERS结构的DataSectionObject和ImageSectionObject两个域清空即可删除正在运行的文件。如果不清空就不能删除运行中的文件。正在运行的文件的这两个域值不为0而文件系统正在根据这两个域决定该文件是否可以删除。如果文件系统检测这两个值为0,就理解为文件没有被使用,可以删除。接下去,就是直接发IRP。
测试时,在C盘目录下放一个test.exe并执行,然后加载驱动即可。
强制删除文件功能在ForceDeleteFile中实现,DriverEntry中只需要简单调用即可。具体实现如下
NTSTATUS DriverEntry(
IN OUT PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
// 其他初始化代码
// ……
DbgPrint ( "Delete File %s", ForceDeleteFile(L"//DosDevices//C://test.exe") ? "Success!" : "Failed!" ) ;
return STATUS_SUCCESS;
}
NTSTATUS FD_SetFileCompletion(
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 FD_OpenFile ( WCHAR szFileName[] )
{
NTSTATUS ntStatus ;
UNICODE_STRING FileName ;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE hFile ;
IO_STATUS_BLOCK ioStatus ;
// 确保IRQL在PASSIVE_LEVEL上
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
return NULL;
// 初始化文件名
RtlInitUnicodeString ( &FileName, szFileName ) ;
DbgPrint ( "%ws", FileName.Buffer ) ;
//初始化对象属性
InitializeObjectAttributes ( &objectAttributes, &FileName,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, NULL, NULL ) ;
// 打开文件
ntStatus = IoCreateFile ( &hFile, FILE_READ_ATTRIBUTES, &objectAttributes, &ioStatus, /
0,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_DELETE,FILE_OPEN,0,NULL,0,CreateFileTypeNone,NULL,IO_NO_PARAMETER_CHECKING);
if ( !NT_SUCCESS(ntStatus) )
return NULL ;
return hFile ;
}
BOOLEAN FD_StripFileAttributes ( HANDLE FileHandle )
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT SycEvent;
FILE_BASIC_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
// 获取文件对象
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_StripFileAttributes IoAllocateIrp error" ) ;
return FALSE;
}
// 初始化同步事件对象
KeInitializeEvent ( &SycEvent, SynchronizationEvent, FALSE ) ;
memset ( &FileInformation, 0, 0x28 ) ;
FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
// 初始化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_BASIC_INFORMATION) ;
irpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
irpSp->Parameters.SetFile.FileObject = fileObject ;
// 设置完成例程
IoSetCompletionRoutine ( Irp, FD_SetFileCompletion ,NULL, TRUE, TRUE, TRUE ) ;
// 派发IRP
IoCallDriver(DeviceObject, Irp);
// 等待IRP的完成
KeWaitForSingleObject ( &SycEvent, Executive, KernelMode, TRUE, NULL ) ;
// 递减引用计数
ObDereferenceObject(fileObject);
return TRUE ;
}
BOOLEAN FD_DeleteFile ( 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, FD_SetFileCompletion, NULL, TRUE, TRUE, TRUE ) ;
// 如果没有这3行,就无法删除正在运行的文件
pSectionObjectPointer = fileObject->SectionObjectPointer;
pSectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
// 派发IRP
IoCallDriver ( DeviceObject, Irp ) ;
// 等待IRP完成
KeWaitForSingleObject ( &SycEvent, Executive, KernelMode, TRUE, NULL);
// 递减引用计数
ObDereferenceObject ( fileObject ) ;
return TRUE ;
}
BOOLEAN ForceDeleteFile ( WCHAR szFileName[] )
{
HANDLE hFile = NULL ;
BOOLEAN status = FALSE ;
__try {
// 打开文件
if ( ( hFile = FD_OpenFile( szFileName ) ) == NULL )
{
DbgPrint ( "FD_OpenFile error!" ) ;
return FALSE ;
}
// //去掉只读属性,才能删除只读文件
if ( FD_StripFileAttributes(hFile) == FALSE )
{
ZwClose ( hFile ) ;
DbgPrint ( "FD_StripFileAttributes error!" ) ;
return FALSE ;
}
// 删除文件
status = FD_DeleteFile(hFile) ;
ZwClose ( hFile ) ;
return status ;
} __except ( 1 ) {
DbgPrint ( "execption!" ) ;
}
return FALSE ;
}