在网上看到了北极星2003写的这篇文章,代码写的很好,注释也很清楚,方便了我这个大菜鸟的学习,对他的无私奉献非常非常感谢。
强制删除文件的思路就是,把SECTION_OBJECT_POINTERS结构的DataSectionObject和ImageSectionObject两个域清空即可删除正在运行的文件。如果不清空就不能删除运行中的文件。正在运行的文件的这两个域值不为0而文件系统正在根据这两个域决定该文件是否可以删除。如果文件系统检测这两个值为0,就理解为文件没有被使用,可以删除。接下去,就是直接发IRP,初始化IRP,设置IRP堆栈信息,设置完成例程,派发IRP。
一、获得文件内核句柄
RtlInitUnicodeString ( &FileName, L” \\DosDevices\\C:\\test.exe” ) ;
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);
打开文件应该传入这个文件的路径。但是实际上这个函数IoCreateFile并不直接接受一个字符串。使用者必须首先填写一个OBJECT_ATTRIBUTES 结构。
用到一个宏:InitializeObjectAttributes用来初始化对象属性
我们是对c:\test.exe,这是个固定的文件了,属性应该也固定了,为什么还要初始化属性呢?
其实这里的初始化属性,主要是为了包含文件的对象路径,然后在指明该代码对该文件的一些要求,如获得内核句柄,不区分文件名的大小写,而不是对文件的操作。即将FileName,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,全放入objectAttributes这个结构中。
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
要说明2点:
1、objectAttributes结构中的ObjectName要求的是对象的路径名,因此不能写成c:\test,
c:是一个符号链接对象,内核模式下,符号链接要写成\\??\\C:或者\\DosDevices\\C:
因此对象路径名为:\\DosDevices\\C:\\test.exe或\\??\\C:\\test.exe
2、InitializeObjectAttributes 只需要填写OBJ_CASE_INSENSITIVE| OBJ_KERNEL_HANDLE即可
OBJ_CASE_INSENSITIVE意味着名字字符串是 不区分大小写的
OBJ_KERNEL_HANDLE表明打开的文件句柄一个“内核句柄”
二、发送IRP去除文件的只读属性
对文件的任何操作,最终都是通过IRP请求,然后文件系统驱动对该IRP进行处理,完成对文件的指定操作。
驱动程序,则可以自己创建IRP,初始化IRP,设置IRP堆栈信息,设置完成例程,派发IRP。这里我们采用的就是这种方法。
三、发送IRP删除文件
Windows API中的DeleteFile实现文件删除功能的内部实现:
DeleteFile 通过 IRP_MJ_SET_INFORMATION请求的IRP,并且将pIrpStack->Parameters.SetFile.FileInformationClass设为FileDispositionInformation且((PFILE_DISPOSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->DeleteFile设为TRUE来达到删除文件。
所以我们有:
FILE_DISPOSITION_INFORMATION FileInformation;
FileInformation.DeleteFile = TRUE;
// 初始化IRP
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
…
// 设置IRP堆栈
irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
…
由上,我们可以删除这个文件,但是如果文件在运行,则不能删除,需要加上如下代码:
// 如果没有这4行,就无法删除正在运行的文件
PSECTION_OBJECT_POINTERS pSectionObjectPointer;
pSectionObjectPointer = fileObject->SectionObjectPointer;
pSectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
对于如何创建IRP,初始化IRP,设置IRP堆栈信息,设置完成例程,派发IRP,这里先不写了,等再整理整理后再写吧。