文件强删

文章目录

  • 前言
  • 内核层强删一个文件的思路
    • 一,需要打开这个文件。
    • 二,被其它程序独占的话如何解决?
    • 三,如果该文件正在运行的话如何解决?
    • 四,构建IRP删除文件。
  • 局限性
  • 扩展——其他方法

前言

本人是驱动新手,因为秋招的一些方面的原因,我最近才进行驱动方面的学习。学了一段时间后了解了一个内核强删文件的方法。

内核层强删一个文件的思路

当病毒或者木马等进行了SSDT HOOK了一些API之后,如何强删一个病毒文件呢?

一,需要打开这个文件。

我选择使用IoCreateFile来打开这个文件,zwCreateFile的底层实现也是调用了这个API,而zwCreateFile是很容易被进行SSDT HOOK的,IoCreateFile这个API的HOOK相对来说麻烦一些。

二,被其它程序独占的话如何解决?

  1. 我们需要找到全局句柄表。

    因为我们无法确定全局句柄表的大小,所以只能通过动态申请一个增长的内存的方式来获取全局句柄表。

    for (size = 1; ; size *= 2)
    	{//从字节数为1开始,每次不够就乘2申请
    		if (NULL == (buf = ExAllocatePoolWithTag(NonPagedPool, size, 'FILE')))
    		{
    			DbgPrint(("alloc mem failed\n"));
    			goto Exit;
    		}
    		RtlZeroMemory(buf, size);
    		status = ZwQuerySystemInformation(SystemHandleInformation, buf, size, NULL);
    		if (!NT_SUCCESS(status))
    		{
    			if (STATUS_INFO_LENGTH_MISMATCH == status)
    			{
    				ExFreePool(buf);
    				buf = NULL;
    			}
    			else
    			{
    				DbgPrint(("ZwQuerySystemInformation() failed"));
    				goto Exit;
    			}
    		}
    		else
    		{
    			break;
    		}
    	}
    
  2. 根据3环传入的路径展开成内核中的符号链接

  3. 在全局句柄表中遍历文件的句柄,然后找到打开的文件句柄,将句柄复制到自己进程空间中,然后根据句柄的值获取到文件Object,然后通过这个Object来获取到文件的符号链接名,然后对比需要强删的文件符号链接名,如果找到要强删的文件,则用ZwDuplicateObject中指定DUPLICATE_CLOSE_SOURCE的方式将句柄复制到自己的进程空间中,然后关闭文件句柄,既可解决独占问题。

    for (i = 0; i < NumOfHandle; i++)
    	{
    		handleTEI = pSysHandleInfo->Handles[i];
    		if (handleTEI.ObjectTypeIndex != 25 && handleTEI.ObjectTypeIndex != 28)//28文件,25设备对象
    			continue;
    		processID = (ULONG)handleTEI.UniqueProcessId;
    		cid.UniqueProcess = (HANDLE)processID;
    		cid.UniqueThread = (HANDLE)0;
    		hHandle = (HANDLE)handleTEI.HandleValue;
    		InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);
    		//根据文件句柄获取所属的进程句柄
    		status = ZwOpenProcess(&hProcess, PROCESS_DUP_HANDLE, &oa, &cid);
    		if (!NT_SUCCESS(status))
    		{
    			KdPrint(("ZwOpenProcess:%d Fail ", processID));
    			continue;
    		}
    		//将句柄复制到自己的进程空间中
    		status = ZwDuplicateObject(hProcess, hHandle, NtCurrentProcess(), &hDupObj, \
    			PROCESS_ALL_ACCESS, 0, DUPLICATE_SAME_ACCESS);
    		if (!NT_SUCCESS(status))
    		{
    			DbgPrint(("ZwDuplicateObject1 : Fail "));
    			continue;
    		}
    		//根据文件句柄获取文件Object
    		status = ObReferenceObjectByHandle(
    			hDupObj,
    			FILE_ANY_ACCESS,
    			0,
    			KernelMode,
    			&fileObject,
    			NULL);
    
    		if (!NT_SUCCESS(status))
    		{
    			DbgPrint(("ObReferenceObjectByHandle : Fail "));
    			continue;
    		}
    
    		pObjName = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, \
    			sizeof(OBJECT_NAME_INFORMATION) + 1024 * sizeof(WCHAR), 'A1');
    		//根据文件对象获取文件的符号链接
    		if (STATUS_SUCCESS != (status = ObQueryNameString(fileObject, pObjName, \
    			sizeof(OBJECT_NAME_INFORMATION) + 1024 * sizeof(WCHAR), &ulRet)))
    		{
    			ObDereferenceObject(fileObject);
    			continue;
    		}
    		if (RtlCompareUnicodeString(&pObjName->Name, &delFileName, TRUE) == 0)
    		{//比对是否是我要强删的文件
    
    			ObDereferenceObject(fileObject);
    			ZwClose(hDupObj);
    			//如果是自己要找到的文件的话,将句柄复制到自己的进程空间中,并关闭原句柄。
    			status = ZwDuplicateObject(hProcess, hHandle, NtCurrentProcess(), &hDupObj, \
    				PROCESS_ALL_ACCESS, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
    			if (!NT_SUCCESS(status))
    			{
    				DbgPrint(("ZwDuplicateObject2 : Fail "));
    				//return FALSE;
    			}
    			else
    			{
    				//然后将复制过来的句柄关闭
    				ZwClose(hDupObj);
    				bRet = TRUE;
    				//return TRUE;
    			}
    			break;
    
    		}
    
    		ExFreePool(pObjName);
    		pObjName = NULL;
    
    		ObDereferenceObject(fileObject);
    		ZwClose(hDupObj);
    		ZwClose(hProcess);
    
    	}
    

三,如果该文件正在运行的话如何解决?

  1. 获取到文件Object,根据Object获取对应的设备对象。

    DeviceObject = IoGetRelatedDeviceObject(fileObject);	//获取到卷设备对象
    
  2. 在向设备发送IRP请求之前,将文件对象的fileObject->SectionObjectPointer->ImageSectionObjectfileObject->pSectionObjectPointer->DataSectionObject清零,即可欺达到骗操作系统的作用,将一个正在运行的文件进行强删。

    //删除正在运行中的exe所做的处理
    	pSectionObjectPointer = fileObject->SectionObjectPointer;
    	if (pSectionObjectPointer)
    	{
    		pSectionObjectPointer->ImageSectionObject = 0;
    		pSectionObjectPointer->DataSectionObject = 0;
    	}
    	//发送IRP请求
    	ntStatus = IoCallDriver(DeviceObject, Irp);
    

四,构建IRP删除文件。

向获取到的卷设备对象发送删除该文件的IRP请求以用来避免病毒木马的APIHOOK。

//irp头部分设置:
	//初始化一个事件对象
	KeInitializeEvent(&event, SynchronizationEvent, FALSE);
	//设置FILE_DISPOSITION_INFORMATION 结构DeleteFile 为TRUE
	FileInformation.DeleteFile = TRUE;
	//将结构体放入irp中
	Irp->AssociatedIrp.SystemBuffer = &FileInformation;
	//设置一个事件
	Irp->UserEvent = &event;
	//设置处理返回结果  
	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);
	//次功能号:FileDispositionInformation 删除文件  
	irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
	//设置参数文件对象
	irpSp->Parameters.SetFile.FileObject = fileObject;

	//设置完成例程  
	IoSetCompletionRoutine(
		Irp,
		dfSkillSetFileCompletion,
		&event,
		TRUE,
		TRUE,
		TRUE);

	//删除正在运行中的exe所做的处理
	pSectionObjectPointer = fileObject->SectionObjectPointer;
	if (pSectionObjectPointer)
	{
		pSectionObjectPointer->ImageSectionObject = 0;
		pSectionObjectPointer->DataSectionObject = 0;
	}
	//发送IRP请求
	ntStatus = IoCallDriver(DeviceObject, Irp);

局限性

无法获取到硬连接的文件句柄,对硬连接文件无效。

扩展——其他方法

强制删除文件还有其他方法:XCB大法,磁盘填0的方式。


如有其它了解会继续补充。

你可能感兴趣的:(内核与驱动)