驱动开发:内核解锁与强删文件
在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用ObSetHandleAttributes
函数将特定句柄设置为可关闭状态,然后在调用ZwClose
将其文件关闭,强制删除则是通过ObReferenceObjectByHandle
在对象上提供相应的权限后直接调用ZwDeleteFile
将其删除。
在内核中实现解锁和强制删除文件是一种常见的技术,通常用于删除被其他进程占用的文件。下面是一些实现方式:
使用 ZwOpenFile 函数打开文件,并指定 FILE_SHARE_DELETE 标志,这将允许其他进程在文件打开期间进行删除操作。然后,调用 ZwSetInformationFile 函数,将文件句柄作为参数传递给它,并指定 FILE_DISPOSITION_INFORMATION 类型,以删除文件。
使用 NtQuerySystemInformation 函数获取系统进程信息,并枚举每个进程以查找拥有要删除文件的句柄的进程。然后,使用 ZwQuerySystemInformation 函数获取有关进程打开句柄的信息,并枚举每个句柄以查找要删除的文件句柄。一旦找到了该句柄,就可以使用 ZwClose 函数关闭该句柄,并调用 ZwSetInformationFile 函数删除文件。
需要注意的是,强制删除文件可能会引起系统稳定性问题和数据丢失,因此应该谨慎使用,并避免误删重要文件。此外,一些安全软件和操作系统可能会检测到这些操作,并采取防御措施。因此,在实现这些技术时,需要遵循操作系统和安全软件的规定,以确保系统的安全和稳定。
虽此类代码较为普遍,但作为揭秘ARK工具来说也必须要将其分析并讲解一下。
首先封装lyshark.h
通用头文件,并定义好我们所需要的结构体,以及特定未导出函数的声明,此处的定义部分是微软官方的规范,如果不懂结构具体含义可自行去微软官方查阅参考资料。
|
接下来将具体分析如何解锁指定文件的句柄表,强制解锁文件句柄表,大体步骤如下所示。
- 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( |
函数ZwDuplicateObject()
,该函数例程用于创建一个句柄,该句柄是指定源句柄的副本,此函数的具体声明部分如下;
NTSYSAPI NTSTATUS ZwDuplicateObject( |
函数ZwQueryObject()
其可以返回特定的一个对象参数,此函数尤为注意第二个参数,当下我们传入的是ObjectNameInformation
则代表需要取出对象名称,而如果使用ObjectTypeInformation
则是返回对象类型,该函数微软定义如下所示;
NTSYSAPI NTSTATUS ZwQueryObject( |
而对于ForceCloseHandle
函数中,需要注意的只有一个ObSetHandleAttributes
该函数微软并没有格式化文档,但是也并不影响我们使用它,如下最需要注意的是PreviousMode
变量,该变量如果传入KernelMode
则是内核模式,传入UserMode
则代表用户模式,为了权限最大化此处需要写入KernelMode
模式;
NTSYSAPI NTSTATUS ObSetHandleAttributes( |
实现文件解锁,该驱动程序不仅可用于解锁应用层程序,也可用于解锁驱动,如下代码中我们解锁pagefile.sys
程序的句柄占用;
|
编译并运行这段驱动程序,则会将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( |
当调用IoCreateFileSpecifyDeviceObjectHint()
函数完成初始化并创建设备后,则下一步就是调用ObReferenceObjectByHandle()
并传入初始化好的设备句柄到Handle
参数上,
NTSTATUS ObReferenceObjectByHandle( |
通过调用如上两个函数将权限设置好以后,我们再手动将ImageSectionObject
也就是映像节对象填充为0,然后再将DeleteAccess
删除权限位打开,最后调用ZwDeleteFile()
函数即可实现强制删除文件的效果,其核心代码如下所示;
|
编译并运行如上程序,则会分别将c://lyshark.exe
以及驱动程序自身删除,并输出如下图所示的提示信息;