西河刘卡车医 发表于 2023-6-15 10:01:53

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

在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用ObSetHandleAttributes函数将特定句柄设置为可关闭状态,然后在调用ZwClose将其文件关闭,强制删除则是通过ObReferenceObjectByHandle在对象上提供相应的权限后直接调用ZwDeleteFile将其删除,虽此类代码较为普遍,但作为揭秘ARK工具来说也必须要将其分析并讲解一下。
https://img2023.cnblogs.com/blog/1379525/202302/1379525-20230226100526660-1901282721.png
首先封装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;
        USHORTHandleValue;
        ULONG GrantedAccess;
        ULONG64 Object;
        UCHAR Name;
} HANDLE_INFO, *PHANDLE_INFO;

HANDLE_INFO HandleInfo;

typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
        USHORTUniqueProcessId;
        USHORTCreatorBackTraceIndex;
        UCHAR ObjectTypeIndex;
        UCHAR HandleAttributes;
        USHORTHandleValue;
        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;
} 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;
        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;
        ULONG                   HighWaterNumberOfHandles;
        ULONG                   HighWaterNumberOfObjects;
        WCHAR                   Unused2;
        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;
        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
(
        HANDLEHandle,
        ULONG ObjectInformationClass,
        PVOID ObjectInformation,
        ULONG ObjectInformationLength,
        PULONGReturnLength OPTIONAL
);

NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation
(
        ULONG SystemInformationClass,
        PVOID SystemInformation,
        ULONG SystemInformationLength,
        PULONGReturnLength
);

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_ATTRIBUTESObjectAttributes,
        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(
            HANDLE      SourceProcessHandle,    // 要复制的句柄的源进程的句柄。
            HANDLE      SourceHandle,         // 要复制的句柄。
HANDLE      TargetProcessHandle,    // 要接收新句柄的目标进程的句柄。
PHANDLE   TargetHandle,         // 指向例程写入新重复句柄的 HANDLE 变量的指针。
            ACCESS_MASK DesiredAccess,          // 一个ACCESS_MASK值,该值指定新句柄的所需访问。
            ULONG       HandleAttributes,       // 一个 ULONG,指定新句柄的所需属性。
            ULONG       Options               // 一组标志,用于控制重复操作的行为。
);函数ZwQueryObject()其可以返回特定的一个对象参数,此函数尤为注意第二个参数,当下我们传入的是ObjectNameInformation则代表需要取出对象名称,而如果使用ObjectTypeInformation则是返回对象类型,该函数微软定义如下所示;
NTSYSAPI NTSTATUS ZwQueryObject(
HANDLE                   Handle,                        // 要获取相关信息的对象句柄。
            OBJECT_INFORMATION_CLASS ObjectInformationClass,      // 该值确定 ObjectInformation 缓冲区中返回的信息的类型。
PVOID                  ObjectInformation,             // 指向接收请求信息的调用方分配缓冲区的指针。
            ULONG                  ObjectInformationLength,       // 指定 ObjectInformation 缓冲区的大小(以字节为单位)。
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 = { 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.UniqueProcessId;
                cid.UniqueProcess = (HANDLE)ulProcessID;
                cid.UniqueThread = (HANDLE)0;
                hHandle = (HANDLE)p.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.UniqueProcessId));

                        // 占用则强制关闭
                        ForceCloseHandle(ep, p.HandleValue);
                        ObDereferenceObject(ep);
                }
        }

        Driver->DriverUnload = UnDriver;
        return STATUS_SUCCESS;
}编译并运行这段驱动程序,则会将pagefile.sys内核文件进行解锁,输出效果如下所示;
https://img2023.cnblogs.com/blog/1379525/202302/1379525-20230226120957215-2048968564.png
聊完了文件解锁功能,接下来将继续探讨如何实现强制删除文件的功能,文件强制删除的关键在于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(
          PHANDLE            FileHandle,               // 指向变量的指针,该变量接收文件对象的句柄。
         ACCESS_MASK      DesiredAccess,            // 标志的位掩码,指定调用方需要对文件或目录的访问类型。
         POBJECT_ATTRIBUTES ObjectAttributes,         // 指向已由 InitializeObjectAttributes 例程初始化的OBJECT_ATTRIBUTES结构的指针。
          PIO_STATUS_BLOCK   IoStatusBlock,            // 指向 IO_STATUS_BLOCK 结构的指针,该结构接收最终完成状态和有关所请求操作的信息。
PLARGE_INTEGER   AllocationSize,         // 指定文件的初始分配大小(以字节为单位)。
         ULONG            FileAttributes,         // 仅当文件创建、取代或在某些情况下被覆盖时,才会应用显式指定的属性。
         ULONG            ShareAccess,            // 指定调用方希望的对文件的共享访问类型(为零或 1,或以下标志的组合)。
         ULONG            Disposition,            // 指定一个值,该值确定要执行的操作,具体取决于文件是否已存在。
         ULONG            CreateOptions,            // 指定要在创建或打开文件时应用的选项。
PVOID            EaBuffer,               // 指向调用方提供的 FILE_FULL_EA_INFORMATION结构化缓冲区的指针。
         ULONG            EaLength,               // EaBuffer 的长度(以字节为单位)。
         CREATE_FILE_TYPE   CreateFileType,         // 驱动程序必须将此参数设置为 CreateFileTypeNone。
PVOID            InternalParameters,       // 驱动程序必须将此参数设置为 NULL。
         ULONG            Options,                  // 指定要在创建请求期间使用的选项。
PVOID            DeviceObject            // 指向要向其发送创建请求的设备对象的指针。
);当调用IoCreateFileSpecifyDeviceObjectHint()函数完成初始化并创建设备后,则下一步就是调用ObReferenceObjectByHandle()并传入初始化好的设备句柄到Handle参数上,
NTSTATUS ObReferenceObjectByHandle(
            HANDLE                     Handle,             // 指定对象的打开句柄。
            ACCESS_MASK                DesiredAccess,      // 指定对对象的请求访问类型。
POBJECT_TYPE               ObjectType,         // 指向对象类型的指针。
            KPROCESSOR_MODE            AccessMode,         // 指定要用于访问检查的访问模式。 它必须是 UserMode 或 KernelMode。
         PVOID                      *Object,            // 指向接收指向对象正文的指针的变量的指针。
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以及驱动程序自身删除,并输出如下图所示的提示信息;
https://img2023.cnblogs.com/blog/1379525/202302/1379525-20230226133125808-1351812901.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 驱动开发:内核解锁与强删文件