8.2 Windows驱动开发:内核解锁与强删文件
在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用ObSetHandleAttributes
函数将特定句柄设置为可关闭状态,然后在调用ZwClose
将其文件关闭,强制删除则是通过ObReferenceObjectByHandle
在对象上提供相应的权限后直接调用ZwDeleteFile
将其删除。
在内核中实现解锁和强制删除文件是一种常见的技术,通常用于删除被其他进程占用的文件。下面是一些实现方式:
-
使用 ZwOpenFile 函数打开文件,并指定 FILE_SHARE_DELETE 标志,这将允许其他进程在文件打开期间进行删除操作。然后,调用 ZwSetInformationFile 函数,将文件句柄作为参数传递给它,并指定 FILE_DISPOSITION_INFORMATION 类型,以删除文件。
-
使用 NtQuerySystemInformation 函数获取系统进程信息,并枚举每个进程以查找拥有要删除文件的句柄的进程。然后,使用 ZwQuerySystemInformation 函数获取有关进程打开句柄的信息,并枚举每个句柄以查找要删除的文件句柄。一旦找到了该句柄,就可以使用 ZwClose 函数关闭该句柄,并调用 ZwSetInformationFile 函数删除文件。
需要注意的是,强制删除文件可能会引起系统稳定性问题和数据丢失,因此应该谨慎使用,并避免误删重要文件。此外,一些安全软件和操作系统可能会检测到这些操作,并采取防御措施。因此,在实现这些技术时,需要遵循操作系统和安全软件的规定,以确保系统的安全和稳定。
虽此类代码较为普遍,但作为揭秘ARK工具来说也必须要将其分析并讲解一下。
首先封装lyshark.h
通用头文件,并定义好我们所需要的结构体,以及特定未导出函数的声明,此处的定义部分是微软官方的规范,如果不懂结构具体含义可自行去微软官方查阅参考资料。
#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
程序的句柄占用;
#include "lyshark.h"// 根据PID得到EProcess
PEPROCESS LookupProcess(HANDLE Pid)
{PEPROCESS eprocess = NULL;if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess)))return eprocess;elsereturn 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 \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);// SystemHandleInformationStatus = 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;}// 查询对象句柄的信息并放入BasicInfoZwQueryObject(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()
函数即可实现强制删除文件的效果,其核心代码如下所示;
#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;// 判断中断等级不大于0if (KeGetCurrentIrql() > PASSIVE_LEVEL){return FALSE;}if (pwzFileName.Buffer == NULL || pwzFileName.Length <= 0){return FALSE;}__try{// 读取当前进程的EProcesspCurEprocess = 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;// 调用删除文件APIstatus = 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 \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.exeref = ForceDeleteFile(file_path);if (ref == TRUE){DbgPrint("[+] 已删除 %wZ \n",file_path);}// 删除WinDDK.sysref = ForceDeleteFile(local_path);if (ref == TRUE){DbgPrint("[+] 已删除 %wZ \n", local_path);}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
编译并运行如上程序,则会分别将c://lyshark.exe
以及驱动程序自身删除,并输出如下图所示的提示信息;
相关文章:

8.2 Windows驱动开发:内核解锁与强删文件
在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用ObSetHandleAttri…...
【Spark源码分析】事件总线机制分析
Spark事件总线机制 采用Spark2.11源码,以下类或方法被DeveloperApi注解额部分,可能出现不同版本不同实现的情况。 Spark中的事件总线用于接受事件并提交到对应的监听器中。事件总线在Spark应用启动时,会在SparkContext中激活spark运行的事件总…...
c语言第七弹--扫雷小游戏!
今天做一个有趣的扫雷小游戏 现在正式开始设计。 思路:想要根本上实现必须拥有 实现函数的主体.c文件 头文件.h 及头文件实现.c。 头文件.h #pragma once #include <stdio.h> #include <stdlib.h> #include <time.h> #define EASY_COUNT 10 #d…...

浏览器是什么
浏览器是什么 本文简要介绍浏览器的功能和组成。 浏览器(Web Browser)是一种用于访问和浏览互联网上的网页和资源的软件应用程序。它是用户与互联网交互的主要工具之一。 浏览器通过使用网络协议(如HTTP、HTTPS等)与远程服务器通…...

一文彻底看懂Python切片,Python切片理解与操作
1.什么是切片 切片是Python中一种用于操作序列类型(如列表、字符串和元组)的方法。它通过指定起始索引和结束索引来截取出序列的一部分,形成一个新的序列。切片是访问特定范围内的元素,就是一个Area。 说个笑话:切片不是切片,而是切片,但是又是切片。大家理解下呢(末…...
聊聊tomcat的connection-timeout
序 本文主要研究一下tomcat的connection-timeout ServerProperties.Tomcat org/springframework/boot/autoconfigure/web/ServerProperties.java public static class Tomcat {/*** Access log configuration.*/private final Accesslog accesslog new Accesslog();/*** Th…...

HCIA-RS基础:动态路由协议基础
摘要:本文介绍动态路由协议的基本概念,为后续动态路由协议原理课程提供基础和引入。主要讲解常见的动态路由协议、动态路由协议的分类,以及路由协议的功能和自治系统的概念。文章旨在优化标题吸引力,并通过详细的内容夯实读者对动…...

jQuery 第十一章(表单验证插件推荐)
文章目录 前言jValidateZebra FormjQuery.validValValidityValidForm BuilderForm ValidatorProgressionformvalidationjQuery Validation PluginjQuery Validation EnginejQuery ValidateValidarium后言 前言 hello world欢迎来到前端的新世界 😜当前文章系列专栏&…...

SSL握手失败的解决方案
一、SSL握手失败的原因: 1,证书过期:SSL证书有一个有效期限,如果证书过期,就会导致SSL握手失败。 2,证书不被信任:如果网站的SSL证书不被浏览器或操作系统信任,也会导致SSL握手失败…...

K8S客户端一 Rancher的安装
一 安装方式一 通过官网方式安装:官网 sudo docker run --privileged -d --restartunless-stopped -p 80:80 -p 443:443 rancher/rancher:stable访问服务器地址即可:http://192.168.52.128 修改语言 第一次安装会生成密码,查看密码步骤如下…...
websocket与node.js实现
什么是 websocket? websoket 是一种网络通信协议,基于 tcp 连接的全双工通信协议(客户端和服务器可以同时收发信息),值得注意的是他不基于 http 协议,websocket 只有在建立连接的时候使用到 http 协议进行…...
postpresql 查询某张表的字段名和字段类型
postpresql 查询某张表的字段名和字段类型 工作中第一次接触postpresql,接触到这么个需求,只是对sql有点了解,于是就网上查阅资料。得知通过系统表可以查询,设计到几张系统表:pg_class、pg_attrubute、information_sc…...

jetson NX部署Yolov8
一,事情起因,由于需要对无人机机载识别算法进行更新,所以需要对yolov8算法进行部署到边缘端。 二,环境安装 安装虚拟环境管理工具,这个根据个人喜好。 我们需要选择能够在ARM架构上运行的conda,这里我们选择conda-forge 下载地址 安装即可 剩下的就是和conda 创建虚拟…...

【论文阅读笔记】Emu Edit: Precise Image Editing via Recognition and Generation Tasks
【论文阅读笔记】Emu Edit: Precise Image Editing via Recognition and Generation Tasks 论文阅读笔记论文信息摘要背景方法结果额外 关键发现作者动机相关工作1. 使用输入和编辑图像的对齐和详细描述来执行特定的编辑2. 另一类图像编辑模型采用输入掩码作为附加输入 。3. 为…...
python:列表的拷贝详解
python:列表的拷贝详解 文章目录 python:列表的拷贝详解方法1:直接赋值()方法2:浅拷贝(.copy方法)格式原理注意 方法3:深拷贝(.deepcopy方法)格式…...
zip4j压缩使用总结
一、引入依赖 <dependency><groupId>net.lingala.zip4j</groupId><artifactId>zip4j</artifactId><version>1.3.1</version></dependency>二、使用添加文件(addFiles)的方式生成压缩包 /*** Author wan…...

【第一部分:概述】ARM Realm Management Monitor specification
目录 概述机密计算系统软件组成MonitorRealmRealm Management Monitor (RMM)Virtual Machine (VM)HypervisorSecure Partition Manager (SPM)Trusted OS (TOS)Trusted Application (TA) Realm Management Monitor 参考文献 概述 RMM是一个软件组件,它构成了实现ARM…...

切换服务器上自己用户目录下的 conda 环境和一个外部的 Conda 环境
如果我们有自己的 Miniconda 安装和一个外部的 Conda 环境(比如一个全局安装的 Anaconda),我们可以通过修改 shell 环境来切换使用它们。这通常涉及到更改 PATH 环境变量,以便指向你想要使用的 Conda 安装的可执行文件:…...
移动端的自动化基于类实现启动一次应用跑全部用例
1.unittest框架 class TestStringMethods(unittest.TestCase): def setUp(self) -> None: # 每一条测试用例开始前执行 print("setup") def tearDown(self) -> None: # 每一条测试用例结束后执行 print("teardown") …...
Python与设计模式--抽象工厂模式
Python与设计模式–抽象工厂模式 一、快餐点餐系统 想必大家一定见过类似于麦当劳自助点餐台一类的点餐系统吧。在一个大的触摸显示屏上,有三类可以选择的上餐品:汉堡等主餐、小食、饮料。当我们选择好自己需要的食物,支付完成后࿰…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...

9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...

C# winform教程(二)----checkbox
一、作用 提供一个用户选择或者不选的状态,这是一个可以多选的控件。 二、属性 其实功能大差不差,除了特殊的几个外,与button基本相同,所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...