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

news2024/11/24 17:22:24

在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用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以及驱动程序自身删除,并输出如下图所示的提示信息;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/648441.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【科学文献计量】关于使用metaknowledge读取文献后转化字典结构报错PD问题的解决方式

关于使用metaknowledge读取文献后转化字典结构报错PD问题的解决方式 1 问题说明2 问题探索3 问题解决4 数据核实1 问题说明 在进行文献下载完毕后,使用metaknowledge读入文献时候是正常的,但是要通过RC.makeDict()方法转化为字典结构,却发生了PD报错问题(KeyError: PD),如…

基于SpringBoot+vue的在线考试系统设计和实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…

阿里云新人专享是什么意思?是新注册用户还是新用户或者老用户?

阿里云2023年促销活动中云服务器购买条件大多都指定为新人专享&#xff0c;有的用户购买提示“不满足购买条件”&#xff0c;有的虽然能买&#xff0c;但是点击购买之后的价格却跟活动显示价格有很大的出入&#xff0c;活动中的云服务器会提示“新人专享”&#xff0c;那么什么…

Python爬取城市天气数据,并作数据可视化

1.爬取广惠河深2022-2024年的天气数据 import requests # 发送请求要用的模块 需要额外安装的 import parsel import csvf open(广-惠-河-深天气.csv, modea, encodingutf-8, newline) csv_writer csv.writer(f) csv_writer.writerow([日期, 最高温度, 最低温度, 天气,…

EEPROM 磨损管理算法

这里写目录标题 前言需求结构局限性代码示例 前言 …最近工作上有用到EEPROM&#xff0c;在我的应用中需要一分钟一次的擦写频率&#xff0c;按照设备一天工作16h&#xff0c;十年的设备设计寿命来计算&#xff0c;大概要擦写300万次。超出了一般的EEPROM擦写循环次数100万。 …

【前端 - CSS】第 17 课 - CSS 特性

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、缘起 2、CSS 三大特性 2.1、继承性 2.2、层叠性 2.3、优先级 3、总结 1、缘起 CSS 是一种用于样式化网页的语言&#xf…

无代码开发smardaten与Power Platform详细对比

文章目录 前言&#xff1a;亟待转型的软开创业者什么是低/无代码居高不下的企业级软件搭建成本1. 开发周期较长2. 在需求明确、软件修改、系统集成等方面存在多种卡点3. 数据管理混乱 无代码/低代码开发&#xff0c;时代的潮流无代码平台 smardaten1. smardaten 简介2. smardat…

一起看 I/O | 将 Kotlin 引入 Web

作者 / 产品经理 Vivek Sekhar 我们将在本文为您介绍 JetBrains 和 Google 的早期实验性工作。您可以观看今年 Google I/O 大会中的 WebAssembly 相关演讲&#xff0c;了解更多详情: https://youtu.be/RcHER-3gFXI?t604 应用开发者想要尽可能地在更多平台上最大限度地吸引用户…

高阶智驾进入「普及」周期,这四家车企包揽年度方案创新奖

特斯拉、理想等新能源汽车头部企业推动的NOA高阶智能驾驶上车潮&#xff0c;正在席卷整个汽车行业。包括吉利、广汽、长安、红旗等头部自主品牌也在加速推进&#xff0c;同时&#xff0c;在NOA、电子电气架构、数据闭环平台等方面&#xff0c;实现科技平权。 6月8-9日&#xff…

三菱FX3U中级课程-模拟量与PID

可别小看FX3U&#xff0c;它的功能比西门子200smart要强大&#xff0c;对于使用三菱PLC的设备&#xff0c;很多小型设备都可以用FX3U来做。 ​​ 三菱FX3U模拟量与PID 课程章节 第一节课 必须知道的模拟量理论知识 - 大白话讲解00:50:33 第二节课 通过测量空压机的压力才学习…

不确定 A Survey of Uncertainty in Deep Neural Networks(乱记)

随着深度学习技术的不断发展&#xff0c;DNN模型的预测能力变得越来越强&#xff0c;然而在一些情况下这却并不是我们想要的&#xff0c;比如说给模型一个与训练集完全不相关的测试样本&#xff0c;我们希望模型能够承认自己的“无知”&#xff0c;而不是强行给出一个预测结果&…

【深度学习】1 感知机(人工神经元)

认识感知机 感知机接收多个输入信号&#xff0c;输出一个信号 感知机的信号只有“流/不流”(1/0)两种取值 0对应“不传递信号”&#xff0c;1对应“传递信号”。 输入信号被送往神经元时&#xff0c;会被分别乘以固定的权重。神经元会计算传送过来的信号的综合&#xff0c;只有…

云平台 stm32连接oneNET保姆级别教学只看这一篇就够了~

1 注册账号 oneNET点击直达 如图点击右上角开发者中心 点击多协议接入 点击添加产品 如下图设置参数 点击立即添加设备 点击添加设备 如下图设置参数 点击右边的详情查看设备ID和鉴权信息 点击产品概况获取 产品ID 平台注册告一段落 你现在拥有了一个oneNET账号 设备ID …

easycode-自定义的模板-类型对应问题

一、遇到的问题 1、mysql数据库中有些字段没有生成到 在图形工具中修改了表结构 &#xff0c;增加了字段&#xff0c;这个时候要在idea中刷新下数据库 2、数据库中有tinyint 类型的字段&#xff0c;生成代码后mapper.xml中jdbcType总是BYTE&#xff0c;但是mybatis中并没有BYT…

echarts分割柱形图实现渐变电量效果柱状图

先看下效果图是这个样子的 &#xff0c;和普通的柱状图最明显的区别就是需要做成类似于电池格电量显示效果。 目录 1、官网找例子 2、改造示例 3、全部代码 4、初始效果和完成效果对比 1、官网找例子 首先到Echarts官网找到基础的柱状图 官网初始option 我们将option复制到…

一文教你彻底学会IIC协议

一文教你如何看懂I2C协议 一.序言二.IIC读写过程2.1主机向从机写入数据2.2主机向从机读取数据2.3 I2C起始信号和停止信号 三. 数据的有效性四.时序要求4.1 起始信号4.2 终止信号4.3 应答信号4.4 非应答信号读取数据五.代码实例 结语 一.序言 背景知识&#xff1a;I2C总线上是通…

顶奢好文:3W字,穿透Spring事务原理、源码,至少读10遍

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、美团、极兔、有赞、希音的面试资格&#xff0c;Spring事务源码的面试题&#xff0c;经常遇到&#xff1a; (1) spring什么情况下进行事务回滚&#xff1f; (2) spring 事务…

微服务springcloud 04. 远程调用,负载平衡,重试,ribbon框架

01.springcloud中关于远程调用&#xff0c;负载平衡。 02.远程调用 ribbon 提供了负载均衡和重试功能, 它底层是使用 RestTemplate 进行 Rest api 调用RestTemplate&#xff0c;RestTemplate 是SpringBoot提供的一个Rest远程调用工具。 它的常用方法: getForObject() - 执行…

「深度学习之优化算法」(六)遗传算法

1. 遗传算法简介 遗传算法(Genetic Algorithms&#xff0c;GA)是一种模拟自然中生物的遗传、进化以适应环境的智能算法。由于其算法流程简单&#xff0c;参数较少优化速度较快&#xff0c;效果较好&#xff0c;在图像处理、函数优化、信号处理、模式识别等领域有着广泛的应用。…

电气火灾探测器在智慧城市消防安全的应用 安科瑞 许敏

【摘要】智慧消防应用是重要的建设内容之一。根据固定资产投资额和消防经费测算&#xff0c;2017年消防市场容量合计约2761.65亿元&#xff0c;2020年消防市场规模可达5200亿元。通过梳理各地政府招标项目&#xff0c;预计全国政府智慧消防项目的投入总额可达92.8亿元。 【关键…