驱动开发:内核解锁与强删文件

在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用ObSetHandleAttributes函数将特定句柄设置为可关闭状态,然后在调用ZwClose将其文件关闭,强制删除则是通过ObReferenceObjectByHandle在对象上提供相应的权限后直接调用ZwDeleteFile将其删除,虽此类代码较为普遍,但作为揭秘ARK工具来说也必须要将其分析并讲解一下。

驱动开发:内核解锁与强删文件

首先封装lyshark.h通用头文件,并定义好我们所需要的结构体,以及特定未导出函数的声明,此处的定义部分是微软官方的规范,如果不懂结构具体含义可自行去微软官方查阅参考资料。

// 署名权 // right to sign one's name on a piece of work // PowerBy: LyShark // Email: me@lyshark.com  #include <ntddk.h>  // ------------------------------------------------------- // 引用微软结构 // ------------------------------------------------------- // 结构体定义 typedef struct _HANDLE_INFO { 	UCHAR ObjectTypeIndex; 	UCHAR HandleAttributes; 	USHORT  HandleValue; 	ULONG GrantedAccess; 	ULONG64 Object; 	UCHAR Name[256]; } HANDLE_INFO, *PHANDLE_INFO;  HANDLE_INFO HandleInfo[1024];  typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO { 	USHORT  UniqueProcessId; 	USHORT  CreatorBackTraceIndex; 	UCHAR ObjectTypeIndex; 	UCHAR HandleAttributes; 	USHORT  HandleValue; 	PVOID Object; 	ULONG GrantedAccess; } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;  typedef struct _SYSTEM_HANDLE_INFORMATION { 	ULONG64 NumberOfHandles; 	SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;  typedef enum _OBJECT_INFORMATION_CLASS { 	ObjectBasicInformation, 	ObjectNameInformation, 	ObjectTypeInformation, 	ObjectAllInformation, 	ObjectDataInformation } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;  typedef struct _OBJECT_BASIC_INFORMATION { 	ULONG                   Attributes; 	ACCESS_MASK             DesiredAccess; 	ULONG                   HandleCount; 	ULONG                   ReferenceCount; 	ULONG                   PagedPoolUsage; 	ULONG                   NonPagedPoolUsage; 	ULONG                   Reserved[3]; 	ULONG                   NameInformationLength; 	ULONG                   TypeInformationLength; 	ULONG                   SecurityDescriptorLength; 	LARGE_INTEGER           CreationTime; } OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;  typedef struct _OBJECT_TYPE_INFORMATION { 	UNICODE_STRING          TypeName; 	ULONG                   TotalNumberOfHandles; 	ULONG                   TotalNumberOfObjects; 	WCHAR                   Unused1[8]; 	ULONG                   HighWaterNumberOfHandles; 	ULONG                   HighWaterNumberOfObjects; 	WCHAR                   Unused2[8]; 	ACCESS_MASK             InvalidAttributes; 	GENERIC_MAPPING         GenericMapping; 	ACCESS_MASK             ValidAttributes; 	BOOLEAN                 SecurityRequired; 	BOOLEAN                 MaintainHandleCount; 	USHORT                  MaintainTypeList; 	POOL_TYPE               PoolType; 	ULONG                   DefaultPagedPoolCharge; 	ULONG                   DefaultNonPagedPoolCharge; } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;  typedef struct _KAPC_STATE { 	LIST_ENTRY ApcListHead[2]; 	PVOID Process; 	BOOLEAN KernelApcInProgress; 	BOOLEAN KernelApcPending; 	BOOLEAN UserApcPending; }KAPC_STATE, *PKAPC_STATE;  typedef struct _OBJECT_HANDLE_FLAG_INFORMATION { 	BOOLEAN Inherit; 	BOOLEAN ProtectFromClose; }OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION;  typedef struct _LDR_DATA_TABLE_ENTRY64 {   LIST_ENTRY64 InLoadOrderLinks;   LIST_ENTRY64 InMemoryOrderLinks;   LIST_ENTRY64 InInitializationOrderLinks;   ULONG64 DllBase;   ULONG64 EntryPoint;   ULONG64 SizeOfImage;   UNICODE_STRING FullDllName;   UNICODE_STRING BaseDllName;   ULONG Flags;   USHORT LoadCount;   USHORT TlsIndex;   LIST_ENTRY64 HashLinks;   ULONG64 SectionPointer;   ULONG64 CheckSum;   ULONG64 TimeDateStamp;   ULONG64 LoadedImports;   ULONG64 EntryPointActivationContext;   ULONG64 PatchInformation;   LIST_ENTRY64 ForwarderLinks;   LIST_ENTRY64 ServiceTagLinks;   LIST_ENTRY64 StaticLinks;   ULONG64 ContextInformation;   ULONG64 OriginalBase;   LARGE_INTEGER LoadTime; } LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;  // ------------------------------------------------------- // 导出函数定义 // -------------------------------------------------------  NTKERNELAPI NTSTATUS ObSetHandleAttributes ( 	HANDLE Handle, 	POBJECT_HANDLE_FLAG_INFORMATION HandleFlags, 	KPROCESSOR_MODE PreviousMode );  NTKERNELAPI VOID KeStackAttachProcess ( 	PEPROCESS PROCESS, 	PKAPC_STATE ApcState );  NTKERNELAPI VOID KeUnstackDetachProcess ( 	PKAPC_STATE ApcState );  NTKERNELAPI NTSTATUS PsLookupProcessByProcessId ( 	IN HANDLE ProcessId, 	OUT PEPROCESS *Process );  NTSYSAPI NTSTATUS NTAPI ZwQueryObject ( 	HANDLE  Handle, 	ULONG ObjectInformationClass, 	PVOID ObjectInformation, 	ULONG ObjectInformationLength, 	PULONG  ReturnLength OPTIONAL );  NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation ( 	ULONG SystemInformationClass, 	PVOID SystemInformation, 	ULONG SystemInformationLength, 	PULONG  ReturnLength );  NTSYSAPI NTSTATUS NTAPI ZwDuplicateObject ( 	HANDLE    SourceProcessHandle, 	HANDLE    SourceHandle, 	HANDLE    TargetProcessHandle OPTIONAL, 	PHANDLE   TargetHandle OPTIONAL, 	ACCESS_MASK DesiredAccess, 	ULONG   HandleAttributes, 	ULONG   Options );  NTSYSAPI NTSTATUS NTAPI ZwOpenProcess ( 	PHANDLE       ProcessHandle, 	ACCESS_MASK     AccessMask, 	POBJECT_ATTRIBUTES  ObjectAttributes, 	PCLIENT_ID      ClientId );  #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004 

接下来将具体分析如何解锁指定文件的句柄表,强制解锁文件句柄表,大体步骤如下所示。

  • 1.首先调用ZwQuerySystemInformation的16功能号SystemHandleInformation来枚举系统里的句柄。
  • 2.通过ZwOpenProcess()打开拥有此句柄的进程,通过ZwDuplicateObject创建一个新的句柄,并把此句柄复制到自己的进程内。
  • 3.通过调用ZwQueryObject并传入ObjectNameInformation查询到句柄的名称,并将其放入到pNameInfo变量内。
  • 4.循环这个过程并在每次循环中通过strstr()判断是否是我们需要关闭的文件名,如果是则调用ForceCloseHandle强制解除占用。
  • 5.此时会进入到ForceCloseHandle流程内,通过KeStackAttachProcess附加到进程内,并调用ObSetHandleAttributes将句柄设置为可关闭状态。
  • 6.最后调用ZwClose关闭句柄占用,并KeUnstackDetachProcess脱离该进程。

实现代码流程非常容易理解,此类功能也没有其他别的写法了一般也就这种,但是还是需要注意这些内置函数的参数传递,这其中ZwQuerySystemInformation()一般用于查询系统进程等信息居多,但通过对SystemInformationClass变量传入不同的参数可实现对不同结构的枚举工作,具体的定义可去查阅微软定义规范;

NTSTATUS WINAPI ZwQuerySystemInformation(   _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,      // 传入不同参数则输出不同内容   _Inout_   PVOID                    SystemInformation,           // 输出数据   _In_      ULONG                    SystemInformationLength,     // 长度   _Out_opt_ PULONG                   ReturnLength                 // 返回长度 ); 

函数ZwDuplicateObject(),该函数例程用于创建一个句柄,该句柄是指定源句柄的副本,此函数的具体声明部分如下;

NTSYSAPI NTSTATUS ZwDuplicateObject(   [in]            HANDLE      SourceProcessHandle,    // 要复制的句柄的源进程的句柄。   [in]            HANDLE      SourceHandle,           // 要复制的句柄。   [in, optional]  HANDLE      TargetProcessHandle,    // 要接收新句柄的目标进程的句柄。   [out, optional] PHANDLE     TargetHandle,           // 指向例程写入新重复句柄的 HANDLE 变量的指针。   [in]            ACCESS_MASK DesiredAccess,          // 一个ACCESS_MASK值,该值指定新句柄的所需访问。   [in]            ULONG       HandleAttributes,       // 一个 ULONG,指定新句柄的所需属性。    [in]            ULONG       Options                 // 一组标志,用于控制重复操作的行为。 ); 

函数ZwQueryObject()其可以返回特定的一个对象参数,此函数尤为注意第二个参数,当下我们传入的是ObjectNameInformation则代表需要取出对象名称,而如果使用ObjectTypeInformation则是返回对象类型,该函数微软定义如下所示;

NTSYSAPI NTSTATUS ZwQueryObject(   [in, optional]  HANDLE                   Handle,                        // 要获取相关信息的对象句柄。   [in]            OBJECT_INFORMATION_CLASS ObjectInformationClass,        // 该值确定 ObjectInformation 缓冲区中返回的信息的类型。   [out, optional] PVOID                    ObjectInformation,             // 指向接收请求信息的调用方分配缓冲区的指针。   [in]            ULONG                    ObjectInformationLength,       // 指定 ObjectInformation 缓冲区的大小(以字节为单位)。   [out, optional] PULONG                   ReturnLength                   // 指向接收所请求密钥信息的大小(以字节为单位)的变量的指针。  ); 

而对于ForceCloseHandle函数中,需要注意的只有一个ObSetHandleAttributes该函数微软并没有格式化文档,但是也并不影响我们使用它,如下最需要注意的是PreviousMode变量,该变量如果传入KernelMode则是内核模式,传入UserMode则代表用户模式,为了权限最大化此处需要写入KernelMode模式;

NTSYSAPI NTSTATUS ObSetHandleAttributes(   HANDLE Handle,                                        // 传入文件句柄   POBJECT_HANDLE_FLAG_INFORMATION HandleFlags,          // OBJECT_HANDLE_FLAG_INFORMATION标志   KPROCESSOR_MODE PreviousMode                          // 指定运行级别KernelMode ) 

实现文件解锁,该驱动程序不仅可用于解锁应用层程序,也可用于解锁驱动,如下代码中我们解锁pagefile.sys程序的句柄占用;

// 署名权 // right to sign one's name on a piece of work // PowerBy: LyShark // Email: me@lyshark.com  #include "lyshark.h"  // 根据PID得到EProcess PEPROCESS LookupProcess(HANDLE Pid) { 	PEPROCESS eprocess = NULL; 	if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess))) 		return eprocess; 	else 		return NULL; }  // 将uncode转为char* VOID UnicodeStringToCharArray(PUNICODE_STRING dst, char *src) { 	ANSI_STRING string; 	if (dst->Length > 260) 	{ 		return; 	}  	RtlUnicodeStringToAnsiString(&string, dst, TRUE); 	strcpy(src, string.Buffer); 	RtlFreeAnsiString(&string); }  // 强制关闭句柄 VOID ForceCloseHandle(PEPROCESS Process, ULONG64 HandleValue) { 	HANDLE h; 	KAPC_STATE ks; 	OBJECT_HANDLE_FLAG_INFORMATION ohfi;  	if (Process == NULL) 	{ 		return; 	} 	// 验证进程是否可读写 	if (!MmIsAddressValid(Process)) 	{ 		return; 	}  	// 附加到进程 	KeStackAttachProcess(Process, &ks); 	h = (HANDLE)HandleValue; 	ohfi.Inherit = 0; 	ohfi.ProtectFromClose = 0;  	// 设置句柄为可关闭状态 	ObSetHandleAttributes(h, &ohfi, KernelMode);  	// 关闭句柄 	ZwClose(h);  	// 脱离附加进程 	KeUnstackDetachProcess(&ks);  	DbgPrint("EP = [ %d ] | HandleValue = [ %d ] 进程句柄已被关闭 n",Process,HandleValue); }  VOID UnDriver(PDRIVER_OBJECT driver) { 	DbgPrint("驱动卸载成功 n"); }  NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { 	DbgPrint("Hello LyShark.com n");  	PVOID Buffer; 	ULONG BufferSize = 0x20000, rtl = 0; 	NTSTATUS Status, qost = 0; 	NTSTATUS ns = STATUS_SUCCESS; 	ULONG64 i = 0; 	ULONG64 qwHandleCount;  	SYSTEM_HANDLE_TABLE_ENTRY_INFO *p; 	OBJECT_BASIC_INFORMATION BasicInfo; 	POBJECT_NAME_INFORMATION pNameInfo;  	ULONG ulProcessID; 	HANDLE hProcess; 	HANDLE hHandle; 	HANDLE hDupObj; 	CLIENT_ID cid; 	OBJECT_ATTRIBUTES oa; 	CHAR szFile[260] = { 0 };  	Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, "LyShark"); 	memset(Buffer, 0, BufferSize);  	// SystemHandleInformation 	Status = ZwQuerySystemInformation(16, Buffer, BufferSize, 0); 	while (Status == STATUS_INFO_LENGTH_MISMATCH) 	{ 		ExFreePool(Buffer); 		BufferSize = BufferSize * 2; 		Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, "LyShark"); 		memset(Buffer, 0, BufferSize); 		Status = ZwQuerySystemInformation(16, Buffer, BufferSize, 0); 	}  	if (!NT_SUCCESS(Status)) 	{ 		return; 	}  	// 获取系统中所有句柄表 	qwHandleCount = ((SYSTEM_HANDLE_INFORMATION *)Buffer)->NumberOfHandles;  	// 得到句柄表的SYSTEM_HANDLE_TABLE_ENTRY_INFO结构 	p = (SYSTEM_HANDLE_TABLE_ENTRY_INFO *)((SYSTEM_HANDLE_INFORMATION *)Buffer)->Handles;  	// 初始化HandleInfo数组 	memset(HandleInfo, 0, 1024 * sizeof(HANDLE_INFO));  	// 开始枚举句柄 	for (i = 0; i<qwHandleCount; i++) 	{ 		ulProcessID = (ULONG)p[i].UniqueProcessId; 		cid.UniqueProcess = (HANDLE)ulProcessID; 		cid.UniqueThread = (HANDLE)0; 		hHandle = (HANDLE)p[i].HandleValue;  		// 初始化对象结构 		InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);  		// 通过句柄信息打开占用进程 		ns = ZwOpenProcess(&hProcess, PROCESS_DUP_HANDLE, &oa, &cid);  		// 打开错误 		if (!NT_SUCCESS(ns)) 		{ 			continue; 		}  		// 创建一个句柄,该句柄是指定源句柄的副本。 		ns = ZwDuplicateObject(hProcess, hHandle, NtCurrentProcess(), &hDupObj, PROCESS_ALL_ACCESS, 0, DUPLICATE_SAME_ACCESS); 		if (!NT_SUCCESS(ns)) 		{ 			continue; 		}  		// 查询对象句柄的信息并放入BasicInfo 		ZwQueryObject(hDupObj, ObjectBasicInformation, &BasicInfo, sizeof(OBJECT_BASIC_INFORMATION), NULL);  		// 得到对象句柄的名字信息 		pNameInfo = ExAllocatePool(PagedPool, 1024); 		RtlZeroMemory(pNameInfo, 1024);  		// 查询对象信息中的对象名,并将该信息保存到pNameInfo中 		qost = ZwQueryObject(hDupObj, ObjectNameInformation, pNameInfo, 1024, &rtl);  		// 获取信息并关闭句柄 		UnicodeStringToCharArray(&(pNameInfo->Name), szFile); 		ExFreePool(pNameInfo); 		ZwClose(hDupObj); 		ZwClose(hProcess);  		// 检查句柄是否被占用,如果被占用则关闭文件并删除 		if (strstr(_strlwr(szFile), "pagefile.sys")) 		{ 			PEPROCESS ep = LookupProcess((HANDLE)(p[i].UniqueProcessId));  			// 占用则强制关闭 			ForceCloseHandle(ep, p[i].HandleValue); 			ObDereferenceObject(ep); 		} 	}  	Driver->DriverUnload = UnDriver; 	return STATUS_SUCCESS; } 

编译并运行这段驱动程序,则会将pagefile.sys内核文件进行解锁,输出效果如下所示;

驱动开发:内核解锁与强删文件

聊完了文件解锁功能,接下来将继续探讨如何实现强制删除文件的功能,文件强制删除的关键在于ObReferenceObjectByHandle函数,该函数可在对象句柄上提供访问验证,并授予访问权限返回指向对象的正文的相应指针,当有了指定的权限以后则可以直接调用ZwDeleteFile()将文件强制删除。

在调用初始化句柄前提之下需要先调用KeGetCurrentIrql()函数,该函数返回当前IRQL级别,那么什么是IRQL呢?

Windows中系统中断请求(IRQ)可分为两种,一种外部中断(硬件中断),一种是软件中断(INT3),微软将中断的概念进行了扩展,提出了中断请求级别(IRQL)的概念,其中就规定了32个中断请求级别。

  • 其中0-2级为软中断,顺序由小到大分别是:PASSIVE_LEVEL,APC_LEVEL,DISPATCH_LEVEL
  • 其中27-31为硬中断,顺序由小到大分别是:PROFILE_LEVEL,CLOCK1_LEVEL,CLOCK2_LEVEL,IPI_LEVEL,POWER_LEVEL,HIGH_LEVEL

我们的代码中开头部分KeGetCurrentIrql() > PASSIVE_LEVEL则是在判断当前的级别不大于0级,也就是说必须要大于0才可以继续执行。

好开始步入正题,函数ObReferenceObjectByHandle需要传入一个文件句柄,而此句柄需要通过IoCreateFileSpecifyDeviceObjectHint对其进行初始化,文件系统筛选器驱动程序使用IoCreateFileSpecifyDeviceObjectHint函数创建,该函数的微软完整定义如下所示;

NTSTATUS IoCreateFileSpecifyDeviceObjectHint(   [out]          PHANDLE            FileHandle,               // 指向变量的指针,该变量接收文件对象的句柄。   [in]           ACCESS_MASK        DesiredAccess,            // 标志的位掩码,指定调用方需要对文件或目录的访问类型。   [in]           POBJECT_ATTRIBUTES ObjectAttributes,         // 指向已由 InitializeObjectAttributes 例程初始化的OBJECT_ATTRIBUTES结构的指针。   [out]          PIO_STATUS_BLOCK   IoStatusBlock,            // 指向 IO_STATUS_BLOCK 结构的指针,该结构接收最终完成状态和有关所请求操作的信息。   [in, optional] PLARGE_INTEGER     AllocationSize,           // 指定文件的初始分配大小(以字节为单位)。   [in]           ULONG              FileAttributes,           // 仅当文件创建、取代或在某些情况下被覆盖时,才会应用显式指定的属性。   [in]           ULONG              ShareAccess,              // 指定调用方希望的对文件的共享访问类型(为零或 1,或以下标志的组合)。   [in]           ULONG              Disposition,              // 指定一个值,该值确定要执行的操作,具体取决于文件是否已存在。   [in]           ULONG              CreateOptions,            // 指定要在创建或打开文件时应用的选项。   [in, optional] PVOID              EaBuffer,                 // 指向调用方提供的 FILE_FULL_EA_INFORMATION结构化缓冲区的指针。   [in]           ULONG              EaLength,                 // EaBuffer 的长度(以字节为单位)。   [in]           CREATE_FILE_TYPE   CreateFileType,           // 驱动程序必须将此参数设置为 CreateFileTypeNone。   [in, optional] PVOID              InternalParameters,       // 驱动程序必须将此参数设置为 NULL。   [in]           ULONG              Options,                  // 指定要在创建请求期间使用的选项。   [in, optional] PVOID              DeviceObject              // 指向要向其发送创建请求的设备对象的指针。 ); 

当调用IoCreateFileSpecifyDeviceObjectHint()函数完成初始化并创建设备后,则下一步就是调用ObReferenceObjectByHandle()并传入初始化好的设备句柄到Handle参数上,

NTSTATUS ObReferenceObjectByHandle(   [in]            HANDLE                     Handle,             // 指定对象的打开句柄。   [in]            ACCESS_MASK                DesiredAccess,      // 指定对对象的请求访问类型。   [in, optional]  POBJECT_TYPE               ObjectType,         // 指向对象类型的指针。   [in]            KPROCESSOR_MODE            AccessMode,         // 指定要用于访问检查的访问模式。 它必须是 UserMode 或 KernelMode。   [out]           PVOID                      *Object,            // 指向接收指向对象正文的指针的变量的指针。   [out, optional] POBJECT_HANDLE_INFORMATION HandleInformation   // 驱动程序将此设置为 NULL。 ); 

通过调用如上两个函数将权限设置好以后,我们再手动将ImageSectionObject也就是映像节对象填充为0,然后再将DeleteAccess删除权限位打开,最后调用ZwDeleteFile()函数即可实现强制删除文件的效果,其核心代码如下所示;

// 署名权 // right to sign one's name on a piece of work // PowerBy: LyShark // Email: me@lyshark.com  #include "lyshark.h"  // 强制删除文件 BOOLEAN ForceDeleteFile(UNICODE_STRING pwzFileName) { 	PEPROCESS pCurEprocess = NULL; 	KAPC_STATE kapc = { 0 }; 	OBJECT_ATTRIBUTES fileOb; 	HANDLE hFile = NULL; 	NTSTATUS status = STATUS_UNSUCCESSFUL; 	IO_STATUS_BLOCK iosta; 	PDEVICE_OBJECT DeviceObject = NULL; 	PVOID pHandleFileObject = NULL;   	// 判断中断等级不大于0 	if (KeGetCurrentIrql() > PASSIVE_LEVEL) 	{ 		return FALSE; 	} 	if (pwzFileName.Buffer == NULL || pwzFileName.Length <= 0) 	{ 		return FALSE; 	}  	__try 	{ 		// 读取当前进程的EProcess 		pCurEprocess = IoGetCurrentProcess();  		// 附加进程 		KeStackAttachProcess(pCurEprocess, &kapc);  		// 初始化结构 		InitializeObjectAttributes(&fileOb, &pwzFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);  		// 文件系统筛选器驱动程序 仅向指定设备对象下面的筛选器和文件系统发送创建请求。 		status = IoCreateFileSpecifyDeviceObjectHint(&hFile, 			SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_READ_DATA, 			&fileOb, 			&iosta, 			NULL, 			0, 			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 			FILE_OPEN, 			FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 			0, 			0, 			CreateFileTypeNone, 			0, 			IO_IGNORE_SHARE_ACCESS_CHECK, 			DeviceObject); 		if (!NT_SUCCESS(status)) 		{ 			return FALSE; 		}  		// 在对象句柄上提供访问验证,如果可以授予访问权限,则返回指向对象的正文的相应指针。 		status = ObReferenceObjectByHandle(hFile, 0, 0, 0, &pHandleFileObject, 0); 		if (!NT_SUCCESS(status)) 		{ 			return FALSE; 		}  		// 镜像节对象设置为0 		((PFILE_OBJECT)(pHandleFileObject))->SectionObjectPointer->ImageSectionObject = 0;  		// 删除权限打开 		((PFILE_OBJECT)(pHandleFileObject))->DeleteAccess = 1;  		// 调用删除文件API 		status = ZwDeleteFile(&fileOb); 		if (!NT_SUCCESS(status)) 		{ 			return FALSE; 		} 	}  	_finally 	{ 		if (pHandleFileObject != NULL) 		{ 			ObDereferenceObject(pHandleFileObject); 			pHandleFileObject = NULL; 		} 		KeUnstackDetachProcess(&kapc);  		if (hFile != NULL || hFile != (PVOID)-1) 		{ 			ZwClose(hFile); 			hFile = (PVOID)-1; 		} 	} 	return TRUE; }  VOID UnDriver(PDRIVER_OBJECT driver) { 	DbgPrint("驱动卸载成功 n"); }  NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { 	DbgPrint("Hello LyShark.com n");  	UNICODE_STRING local_path; 	UNICODE_STRING file_path; 	BOOLEAN ref = FALSE; 	 	// 初始化被删除文件 	RtlInitUnicodeString(&file_path, L"\??\C:\lyshark.exe");  	// 获取自身驱动文件 	local_path = ((PLDR_DATA_TABLE_ENTRY64)Driver->DriverSection)->FullDllName;  	// 删除lyshark.exe 	ref = ForceDeleteFile(file_path); 	if (ref == TRUE) 	{ 		DbgPrint("[+] 已删除 %wZ n",file_path); 	}  	// 删除WinDDK.sys 	ref = ForceDeleteFile(local_path); 	if (ref == TRUE) 	{ 		DbgPrint("[+] 已删除 %wZ n", local_path); 	}  	Driver->DriverUnload = UnDriver; 	return STATUS_SUCCESS; } 

编译并运行如上程序,则会分别将c://lyshark.exe以及驱动程序自身删除,并输出如下图所示的提示信息;

驱动开发:内核解锁与强删文件

发表评论

评论已关闭。

相关文章