文件强删
在日常生活使用电脑的过程中,遇到删不掉的文件的时候,我们总会通过一些软件提供的强制删除文件功能来删除顽固的文件。文件强删技术对于杀软来说是清楚病毒木马的武器,在扫描器检测出恶意文件的时候,就需要强删功能来清除恶意文件。而对于病毒木马来说,反过来可以用强删技术来强制删除系统保护文件或是受杀软保护的文件。
本文将会介绍文件强删技术,即使文件正在运行,也能强制删除本地文件。
实现过程
当文件是PE文件而且已经被加载到内存中的时候,正常情况下是无法通过资源管理器explorer.exe来删除本地文件的,因为在删除运行中的文件或者被加载的DLL文件的时候,系统会调用MmFlushImageSection内核函数来检测文件是否处于运行状态,若是,则拒绝删除操作。其中,系统中的MmFlushImageSection内核函数,主要是通过检查文件对象中的PSECTION_OBJECT_POINTERS结构数据来判断该文件是否处于运行状态、是否可以删除。
同时,在发送IRP删除文件的时候,系统同样会判断文件的属性是否是只读,若是只读属性则会拒绝删除操作。
所以,根据上述的删除原理,文件强制删除的具体实现流程如下所示。
首先,发送IRP打开删除文件,并获取文件对象。
然后,发送IRP设置文件属性,属性类型为FileBasicInformation,将文件属性重新设置为FILE_ATTRIBUTE_NORMAL,防止原来的文件属性为只读属性。并保存文件对象中的PSECTION_OBJECT_POINTERS结构的值,保存完成后,再对该结构进行清空处理。
接着,发送IRP设置文件属性,属性类型为FileDispositionInformation,实现删除文件操作。这样,即使是运行中的文件也能被强制删除。
最后,还原文件对象中的PSECTION_OBJECT_POINTERS结构,并调用ObDereferenceObject函数释放文件对象,完成清理工作。
那么,实现文件强制删除的实现代码如下所示。
// 强制删除文件
NTSTATUS ForceDeleteFile(UNICODE_STRING ustrFileName)
{
NTSTATUS status = STATUS_SUCCESS;
PFILE_OBJECT pFileObject = NULL;
IO_STATUS_BLOCK iosb = { 0 };
FILE_BASIC_INFORMATION fileBaseInfo = { 0 };
FILE_DISPOSITION_INFORMATION fileDispositionInfo = { 0 };
PVOID pImageSectionObject = NULL;
PVOID pDataSectionObject = NULL;
PVOID pSharedCacheMap = NULL;
// 发送IRP打开文件
status = IrpCreateFile(&pFileObject, GENERIC_READ | GENERIC_WRITE, &ustrFileName,
&iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
{
DbgPrint("IrpCreateFile Error[0x%X]\n", status);
return FALSE;
}
// 发送IRP设置文件属性, 去掉只读属性, 修改为 FILE_ATTRIBUTE_NORMAL
RtlZeroMemory(&fileBaseInfo, sizeof(fileBaseInfo));
fileBaseInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
status = IrpSetInformationFile(pFileObject, &iosb, &fileBaseInfo, sizeof(fileBaseInfo), FileBasicInformation);
if (!NT_SUCCESS(status))
{
DbgPrint("IrpSetInformationFile[SetInformation] Error[0x%X]\n", status);
return status;
}
// 清空PSECTION_OBJECT_POINTERS结构
if (pFileObject->SectionObjectPointer)
{
// 保存旧值
pImageSectionObject = pFileObject->SectionObjectPointer->ImageSectionObject;
pDataSectionObject = pFileObject->SectionObjectPointer->DataSectionObject;
pSharedCacheMap = pFileObject->SectionObjectPointer->SharedCacheMap;
// 置为空
pFileObject->SectionObjectPointer->ImageSectionObject = NULL;
pFileObject->SectionObjectPointer->DataSectionObject = NULL;
pFileObject->SectionObjectPointer->SharedCacheMap = NULL;
}
// 发送IRP设置文件属性, 设置删除文件操作
RtlZeroMemory(&fileDispositionInfo, sizeof(fileDispositionInfo));
fileDispositionInfo.DeleteFile = TRUE;
status = IrpSetInformationFile(pFileObject, &iosb, &fileDispositionInfo, sizeof(fileDispositionInfo), FileDispositionInformation);
if (!NT_SUCCESS(status))
{
DbgPrint("IrpSetInformationFile[DeleteFile] Error[0x%X]\n", status);
return status;
}
//还原旧值
if (pFileObject->SectionObjectPointer)
{
pFileObject->SectionObjectPointer->ImageSectionObject = pImageSectionObject;
pFileObject->SectionObjectPointer->DataSectionObject = pDataSectionObject;
pFileObject->SectionObjectPointer->SharedCacheMap = pSharedCacheMap;
}
// 关闭文件对象
ObDereferenceObject(pFileObject);
return status;
}
测试
在64位Windows 10操作系统上,运行C:\520.exe程序后,直接加载并运行上述驱动程序,强制删除正在运行的520.exe文件。520.exe本地文件成功被删除,如图:
小结
本文介绍的文件强删技术的实现原理是,通过发送IRP打开文件,获取文件对象;发送IRP设置文件属性,去掉只读属性;清空文件对象中的PSECTION_OBJECT_POINTERS结构,使运行中的程序文件能够被删除;最后发送IRP删除文件并释放文件对象。
本文介绍的文件强删技术可以删除正在运行的exe文件,但是不适用于前面介绍的发送IRP打开文件不关闭的文件保护方法。要想强制删除发送IRP打开文件不关闭的文件保护,需要关闭打开的文件对象。可以利用XCB解锁技术,通过硬编码定位出文件对象中SCB(Stream Control Block)、FCB(File Control Blokc)、CCB(Context Control Block)结构的CleanupCount变量,并将CleanupCount都置为1,再调用ObDereferenceObject函数关闭文件对象并释放资源。XCB解锁技术不仅可以解锁发送IRP打开文件的保护方式,同样适用于硬链接文件保护。