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与设计模式–抽象工厂模式 一、快餐点餐系统 想必大家一定见过类似于麦当劳自助点餐台一类的点餐系统吧。在一个大的触摸显示屏上,有三类可以选择的上餐品:汉堡等主餐、小食、饮料。当我们选择好自己需要的食物,支付完成后࿰…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
