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

打印 上一主题 下一主题

主题 919|帖子 919|积分 2757

在某些时候我们的系统中会出现一些无法被正常删除的文件,如果想要强制删除则需要在驱动层面对其进行解锁后才可删掉,而所谓的解锁其实就是释放掉文件描述符(句柄表)占用,文件解锁的核心原理是通过调用ObSetHandleAttributes函数将特定句柄设置为可关闭状态,然后在调用ZwClose将其文件关闭,强制删除则是通过ObReferenceObjectByHandle在对象上提供相应的权限后直接调用ZwDeleteFile将其删除,虽此类代码较为普遍,但作为揭秘ARK工具来说也必须要将其分析并讲解一下。

首先封装lyshark.h通用头文件,并定义好我们所需要的结构体,以及特定未导出函数的声明,此处的定义部分是微软官方的规范,如果不懂结构具体含义可自行去微软官方查阅参考资料。
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include <ntddk.h>
  6. // -------------------------------------------------------
  7. // 引用微软结构
  8. // -------------------------------------------------------
  9. // 结构体定义
  10. typedef struct _HANDLE_INFO
  11. {
  12.         UCHAR ObjectTypeIndex;
  13.         UCHAR HandleAttributes;
  14.         USHORT  HandleValue;
  15.         ULONG GrantedAccess;
  16.         ULONG64 Object;
  17.         UCHAR Name[256];
  18. } HANDLE_INFO, *PHANDLE_INFO;
  19. HANDLE_INFO HandleInfo[1024];
  20. typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
  21. {
  22.         USHORT  UniqueProcessId;
  23.         USHORT  CreatorBackTraceIndex;
  24.         UCHAR ObjectTypeIndex;
  25.         UCHAR HandleAttributes;
  26.         USHORT  HandleValue;
  27.         PVOID Object;
  28.         ULONG GrantedAccess;
  29. } SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
  30. typedef struct _SYSTEM_HANDLE_INFORMATION
  31. {
  32.         ULONG64 NumberOfHandles;
  33.         SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
  34. } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
  35. typedef enum _OBJECT_INFORMATION_CLASS
  36. {
  37.         ObjectBasicInformation,
  38.         ObjectNameInformation,
  39.         ObjectTypeInformation,
  40.         ObjectAllInformation,
  41.         ObjectDataInformation
  42. } OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
  43. typedef struct _OBJECT_BASIC_INFORMATION
  44. {
  45.         ULONG                   Attributes;
  46.         ACCESS_MASK             DesiredAccess;
  47.         ULONG                   HandleCount;
  48.         ULONG                   ReferenceCount;
  49.         ULONG                   PagedPoolUsage;
  50.         ULONG                   NonPagedPoolUsage;
  51.         ULONG                   Reserved[3];
  52.         ULONG                   NameInformationLength;
  53.         ULONG                   TypeInformationLength;
  54.         ULONG                   SecurityDescriptorLength;
  55.         LARGE_INTEGER           CreationTime;
  56. } OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
  57. typedef struct _OBJECT_TYPE_INFORMATION
  58. {
  59.         UNICODE_STRING          TypeName;
  60.         ULONG                   TotalNumberOfHandles;
  61.         ULONG                   TotalNumberOfObjects;
  62.         WCHAR                   Unused1[8];
  63.         ULONG                   HighWaterNumberOfHandles;
  64.         ULONG                   HighWaterNumberOfObjects;
  65.         WCHAR                   Unused2[8];
  66.         ACCESS_MASK             InvalidAttributes;
  67.         GENERIC_MAPPING         GenericMapping;
  68.         ACCESS_MASK             ValidAttributes;
  69.         BOOLEAN                 SecurityRequired;
  70.         BOOLEAN                 MaintainHandleCount;
  71.         USHORT                  MaintainTypeList;
  72.         POOL_TYPE               PoolType;
  73.         ULONG                   DefaultPagedPoolCharge;
  74.         ULONG                   DefaultNonPagedPoolCharge;
  75. } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
  76. typedef struct _KAPC_STATE
  77. {
  78.         LIST_ENTRY ApcListHead[2];
  79.         PVOID Process;
  80.         BOOLEAN KernelApcInProgress;
  81.         BOOLEAN KernelApcPending;
  82.         BOOLEAN UserApcPending;
  83. }KAPC_STATE, *PKAPC_STATE;
  84. typedef struct _OBJECT_HANDLE_FLAG_INFORMATION
  85. {
  86.         BOOLEAN Inherit;
  87.         BOOLEAN ProtectFromClose;
  88. }OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION;
  89. typedef struct _LDR_DATA_TABLE_ENTRY64
  90. {
  91.   LIST_ENTRY64 InLoadOrderLinks;
  92.   LIST_ENTRY64 InMemoryOrderLinks;
  93.   LIST_ENTRY64 InInitializationOrderLinks;
  94.   ULONG64 DllBase;
  95.   ULONG64 EntryPoint;
  96.   ULONG64 SizeOfImage;
  97.   UNICODE_STRING FullDllName;
  98.   UNICODE_STRING BaseDllName;
  99.   ULONG Flags;
  100.   USHORT LoadCount;
  101.   USHORT TlsIndex;
  102.   LIST_ENTRY64 HashLinks;
  103.   ULONG64 SectionPointer;
  104.   ULONG64 CheckSum;
  105.   ULONG64 TimeDateStamp;
  106.   ULONG64 LoadedImports;
  107.   ULONG64 EntryPointActivationContext;
  108.   ULONG64 PatchInformation;
  109.   LIST_ENTRY64 ForwarderLinks;
  110.   LIST_ENTRY64 ServiceTagLinks;
  111.   LIST_ENTRY64 StaticLinks;
  112.   ULONG64 ContextInformation;
  113.   ULONG64 OriginalBase;
  114.   LARGE_INTEGER LoadTime;
  115. } LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;
  116. // -------------------------------------------------------
  117. // 导出函数定义
  118. // -------------------------------------------------------
  119. NTKERNELAPI NTSTATUS ObSetHandleAttributes
  120. (
  121.         HANDLE Handle,
  122.         POBJECT_HANDLE_FLAG_INFORMATION HandleFlags,
  123.         KPROCESSOR_MODE PreviousMode
  124. );
  125. NTKERNELAPI VOID KeStackAttachProcess
  126. (
  127.         PEPROCESS PROCESS,
  128.         PKAPC_STATE ApcState
  129. );
  130. NTKERNELAPI VOID KeUnstackDetachProcess
  131. (
  132.         PKAPC_STATE ApcState
  133. );
  134. NTKERNELAPI NTSTATUS PsLookupProcessByProcessId
  135. (
  136.         IN HANDLE ProcessId,
  137.         OUT PEPROCESS *Process
  138. );
  139. NTSYSAPI NTSTATUS NTAPI ZwQueryObject
  140. (
  141.         HANDLE  Handle,
  142.         ULONG ObjectInformationClass,
  143.         PVOID ObjectInformation,
  144.         ULONG ObjectInformationLength,
  145.         PULONG  ReturnLength OPTIONAL
  146. );
  147. NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation
  148. (
  149.         ULONG SystemInformationClass,
  150.         PVOID SystemInformation,
  151.         ULONG SystemInformationLength,
  152.         PULONG  ReturnLength
  153. );
  154. NTSYSAPI NTSTATUS NTAPI ZwDuplicateObject
  155. (
  156.         HANDLE    SourceProcessHandle,
  157.         HANDLE    SourceHandle,
  158.         HANDLE    TargetProcessHandle OPTIONAL,
  159.         PHANDLE   TargetHandle OPTIONAL,
  160.         ACCESS_MASK DesiredAccess,
  161.         ULONG   HandleAttributes,
  162.         ULONG   Options
  163. );
  164. NTSYSAPI NTSTATUS NTAPI ZwOpenProcess
  165. (
  166.         PHANDLE       ProcessHandle,
  167.         ACCESS_MASK     AccessMask,
  168.         POBJECT_ATTRIBUTES  ObjectAttributes,
  169.         PCLIENT_ID      ClientId
  170. );
  171. #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变量传入不同的参数可实现对不同结构的枚举工作,具体的定义可去查阅微软定义规范;
  1. NTSTATUS WINAPI ZwQuerySystemInformation(
  2.   _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,      // 传入不同参数则输出不同内容
  3.   _Inout_   PVOID                    SystemInformation,           // 输出数据
  4.   _In_      ULONG                    SystemInformationLength,     // 长度
  5.   _Out_opt_ PULONG                   ReturnLength                 // 返回长度
  6. );
复制代码
函数ZwDuplicateObject(),该函数例程用于创建一个句柄,该句柄是指定源句柄的副本,此函数的具体声明部分如下;
  1. NTSYSAPI NTSTATUS ZwDuplicateObject(
  2.   [in]            HANDLE      SourceProcessHandle,    // 要复制的句柄的源进程的句柄。
  3.   [in]            HANDLE      SourceHandle,           // 要复制的句柄。
  4.   [in, optional]  HANDLE      TargetProcessHandle,    // 要接收新句柄的目标进程的句柄。
  5.   [out, optional] PHANDLE     TargetHandle,           // 指向例程写入新重复句柄的 HANDLE 变量的指针。
  6.   [in]            ACCESS_MASK DesiredAccess,          // 一个ACCESS_MASK值,该值指定新句柄的所需访问。
  7.   [in]            ULONG       HandleAttributes,       // 一个 ULONG,指定新句柄的所需属性。
  8.   [in]            ULONG       Options                 // 一组标志,用于控制重复操作的行为。
  9. );
复制代码
函数ZwQueryObject()其可以返回特定的一个对象参数,此函数尤为注意第二个参数,当下我们传入的是ObjectNameInformation则代表需要取出对象名称,而如果使用ObjectTypeInformation则是返回对象类型,该函数微软定义如下所示;
  1. NTSYSAPI NTSTATUS ZwQueryObject(
  2.   [in, optional]  HANDLE                   Handle,                        // 要获取相关信息的对象句柄。
  3.   [in]            OBJECT_INFORMATION_CLASS ObjectInformationClass,        // 该值确定 ObjectInformation 缓冲区中返回的信息的类型。
  4.   [out, optional] PVOID                    ObjectInformation,             // 指向接收请求信息的调用方分配缓冲区的指针。
  5.   [in]            ULONG                    ObjectInformationLength,       // 指定 ObjectInformation 缓冲区的大小(以字节为单位)。
  6.   [out, optional] PULONG                   ReturnLength                   // 指向接收所请求密钥信息的大小(以字节为单位)的变量的指针。
  7. );
复制代码
而对于ForceCloseHandle函数中,需要注意的只有一个ObSetHandleAttributes该函数微软并没有格式化文档,但是也并不影响我们使用它,如下最需要注意的是PreviousMode变量,该变量如果传入KernelMode则是内核模式,传入UserMode则代表用户模式,为了权限最大化此处需要写入KernelMode模式;
  1. NTSYSAPI NTSTATUS ObSetHandleAttributes(
  2.   HANDLE Handle,                                        // 传入文件句柄
  3.   POBJECT_HANDLE_FLAG_INFORMATION HandleFlags,          // OBJECT_HANDLE_FLAG_INFORMATION标志
  4.   KPROCESSOR_MODE PreviousMode                          // 指定运行级别KernelMode
  5. )
复制代码
实现文件解锁,该驱动程序不仅可用于解锁应用层程序,也可用于解锁驱动,如下代码中我们解锁pagefile.sys程序的句柄占用;
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include "lyshark.h"
  6. // 根据PID得到EProcess
  7. PEPROCESS LookupProcess(HANDLE Pid)
  8. {
  9.         PEPROCESS eprocess = NULL;
  10.         if (NT_SUCCESS(PsLookupProcessByProcessId(Pid, &eprocess)))
  11.                 return eprocess;
  12.         else
  13.                 return NULL;
  14. }
  15. // 将uncode转为char*
  16. VOID UnicodeStringToCharArray(PUNICODE_STRING dst, char *src)
  17. {
  18.         ANSI_STRING string;
  19.         if (dst->Length > 260)
  20.         {
  21.                 return;
  22.         }
  23.         RtlUnicodeStringToAnsiString(&string, dst, TRUE);
  24.         strcpy(src, string.Buffer);
  25.         RtlFreeAnsiString(&string);
  26. }
  27. // 强制关闭句柄
  28. VOID ForceCloseHandle(PEPROCESS Process, ULONG64 HandleValue)
  29. {
  30.         HANDLE h;
  31.         KAPC_STATE ks;
  32.         OBJECT_HANDLE_FLAG_INFORMATION ohfi;
  33.         if (Process == NULL)
  34.         {
  35.                 return;
  36.         }
  37.         // 验证进程是否可读写
  38.         if (!MmIsAddressValid(Process))
  39.         {
  40.                 return;
  41.         }
  42.         // 附加到进程
  43.         KeStackAttachProcess(Process, &ks);
  44.         h = (HANDLE)HandleValue;
  45.         ohfi.Inherit = 0;
  46.         ohfi.ProtectFromClose = 0;
  47.         // 设置句柄为可关闭状态
  48.         ObSetHandleAttributes(h, &ohfi, KernelMode);
  49.         // 关闭句柄
  50.         ZwClose(h);
  51.         // 脱离附加进程
  52.         KeUnstackDetachProcess(&ks);
  53.         DbgPrint("EP = [ %d ] | HandleValue = [ %d ] 进程句柄已被关闭 \n",Process,HandleValue);
  54. }
  55. VOID UnDriver(PDRIVER_OBJECT driver)
  56. {
  57.         DbgPrint("驱动卸载成功 \n");
  58. }
  59. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  60. {
  61.         DbgPrint("Hello LyShark.com \n");
  62.         PVOID Buffer;
  63.         ULONG BufferSize = 0x20000, rtl = 0;
  64.         NTSTATUS Status, qost = 0;
  65.         NTSTATUS ns = STATUS_SUCCESS;
  66.         ULONG64 i = 0;
  67.         ULONG64 qwHandleCount;
  68.         SYSTEM_HANDLE_TABLE_ENTRY_INFO *p;
  69.         OBJECT_BASIC_INFORMATION BasicInfo;
  70.         POBJECT_NAME_INFORMATION pNameInfo;
  71.         ULONG ulProcessID;
  72.         HANDLE hProcess;
  73.         HANDLE hHandle;
  74.         HANDLE hDupObj;
  75.         CLIENT_ID cid;
  76.         OBJECT_ATTRIBUTES oa;
  77.         CHAR szFile[260] = { 0 };
  78.         Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, "LyShark");
  79.         memset(Buffer, 0, BufferSize);
  80.         // SystemHandleInformation
  81.         Status = ZwQuerySystemInformation(16, Buffer, BufferSize, 0);
  82.         while (Status == STATUS_INFO_LENGTH_MISMATCH)
  83.         {
  84.                 ExFreePool(Buffer);
  85.                 BufferSize = BufferSize * 2;
  86.                 Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, "LyShark");
  87.                 memset(Buffer, 0, BufferSize);
  88.                 Status = ZwQuerySystemInformation(16, Buffer, BufferSize, 0);
  89.         }
  90.         if (!NT_SUCCESS(Status))
  91.         {
  92.                 return;
  93.         }
  94.         // 获取系统中所有句柄表
  95.         qwHandleCount = ((SYSTEM_HANDLE_INFORMATION *)Buffer)->NumberOfHandles;
  96.         // 得到句柄表的SYSTEM_HANDLE_TABLE_ENTRY_INFO结构
  97.         p = (SYSTEM_HANDLE_TABLE_ENTRY_INFO *)((SYSTEM_HANDLE_INFORMATION *)Buffer)->Handles;
  98.         // 初始化HandleInfo数组
  99.         memset(HandleInfo, 0, 1024 * sizeof(HANDLE_INFO));
  100.         // 开始枚举句柄
  101.         for (i = 0; i<qwHandleCount; i++)
  102.         {
  103.                 ulProcessID = (ULONG)p[i].UniqueProcessId;
  104.                 cid.UniqueProcess = (HANDLE)ulProcessID;
  105.                 cid.UniqueThread = (HANDLE)0;
  106.                 hHandle = (HANDLE)p[i].HandleValue;
  107.                 // 初始化对象结构
  108.                 InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);
  109.                 // 通过句柄信息打开占用进程
  110.                 ns = ZwOpenProcess(&hProcess, PROCESS_DUP_HANDLE, &oa, &cid);
  111.                 // 打开错误
  112.                 if (!NT_SUCCESS(ns))
  113.                 {
  114.                         continue;
  115.                 }
  116.                 // 创建一个句柄,该句柄是指定源句柄的副本。
  117.                 ns = ZwDuplicateObject(hProcess, hHandle, NtCurrentProcess(), &hDupObj, PROCESS_ALL_ACCESS, 0, DUPLICATE_SAME_ACCESS);
  118.                 if (!NT_SUCCESS(ns))
  119.                 {
  120.                         continue;
  121.                 }
  122.                 // 查询对象句柄的信息并放入BasicInfo
  123.                 ZwQueryObject(hDupObj, ObjectBasicInformation, &BasicInfo, sizeof(OBJECT_BASIC_INFORMATION), NULL);
  124.                 // 得到对象句柄的名字信息
  125.                 pNameInfo = ExAllocatePool(PagedPool, 1024);
  126.                 RtlZeroMemory(pNameInfo, 1024);
  127.                 // 查询对象信息中的对象名,并将该信息保存到pNameInfo中
  128.                 qost = ZwQueryObject(hDupObj, ObjectNameInformation, pNameInfo, 1024, &rtl);
  129.                 // 获取信息并关闭句柄
  130.                 UnicodeStringToCharArray(&(pNameInfo->Name), szFile);
  131.                 ExFreePool(pNameInfo);
  132.                 ZwClose(hDupObj);
  133.                 ZwClose(hProcess);
  134.                 // 检查句柄是否被占用,如果被占用则关闭文件并删除
  135.                 if (strstr(_strlwr(szFile), "pagefile.sys"))
  136.                 {
  137.                         PEPROCESS ep = LookupProcess((HANDLE)(p[i].UniqueProcessId));
  138.                         // 占用则强制关闭
  139.                         ForceCloseHandle(ep, p[i].HandleValue);
  140.                         ObDereferenceObject(ep);
  141.                 }
  142.         }
  143.         Driver->DriverUnload = UnDriver;
  144.         return STATUS_SUCCESS;
  145. }
复制代码
编译并运行这段驱动程序,则会将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函数创建,该函数的微软完整定义如下所示;
  1. NTSTATUS IoCreateFileSpecifyDeviceObjectHint(
  2.   [out]          PHANDLE            FileHandle,               // 指向变量的指针,该变量接收文件对象的句柄。
  3.   [in]           ACCESS_MASK        DesiredAccess,            // 标志的位掩码,指定调用方需要对文件或目录的访问类型。
  4.   [in]           POBJECT_ATTRIBUTES ObjectAttributes,         // 指向已由 InitializeObjectAttributes 例程初始化的OBJECT_ATTRIBUTES结构的指针。
  5.   [out]          PIO_STATUS_BLOCK   IoStatusBlock,            // 指向 IO_STATUS_BLOCK 结构的指针,该结构接收最终完成状态和有关所请求操作的信息。
  6.   [in, optional] PLARGE_INTEGER     AllocationSize,           // 指定文件的初始分配大小(以字节为单位)。
  7.   [in]           ULONG              FileAttributes,           // 仅当文件创建、取代或在某些情况下被覆盖时,才会应用显式指定的属性。
  8.   [in]           ULONG              ShareAccess,              // 指定调用方希望的对文件的共享访问类型(为零或 1,或以下标志的组合)。
  9.   [in]           ULONG              Disposition,              // 指定一个值,该值确定要执行的操作,具体取决于文件是否已存在。
  10.   [in]           ULONG              CreateOptions,            // 指定要在创建或打开文件时应用的选项。
  11.   [in, optional] PVOID              EaBuffer,                 // 指向调用方提供的 FILE_FULL_EA_INFORMATION结构化缓冲区的指针。
  12.   [in]           ULONG              EaLength,                 // EaBuffer 的长度(以字节为单位)。
  13.   [in]           CREATE_FILE_TYPE   CreateFileType,           // 驱动程序必须将此参数设置为 CreateFileTypeNone。
  14.   [in, optional] PVOID              InternalParameters,       // 驱动程序必须将此参数设置为 NULL。
  15.   [in]           ULONG              Options,                  // 指定要在创建请求期间使用的选项。
  16.   [in, optional] PVOID              DeviceObject              // 指向要向其发送创建请求的设备对象的指针。
  17. );
复制代码
当调用IoCreateFileSpecifyDeviceObjectHint()函数完成初始化并创建设备后,则下一步就是调用ObReferenceObjectByHandle()并传入初始化好的设备句柄到Handle参数上,
  1. NTSTATUS ObReferenceObjectByHandle(
  2.   [in]            HANDLE                     Handle,             // 指定对象的打开句柄。
  3.   [in]            ACCESS_MASK                DesiredAccess,      // 指定对对象的请求访问类型。
  4.   [in, optional]  POBJECT_TYPE               ObjectType,         // 指向对象类型的指针。
  5.   [in]            KPROCESSOR_MODE            AccessMode,         // 指定要用于访问检查的访问模式。 它必须是 UserMode 或 KernelMode。
  6.   [out]           PVOID                      *Object,            // 指向接收指向对象正文的指针的变量的指针。
  7.   [out, optional] POBJECT_HANDLE_INFORMATION HandleInformation   // 驱动程序将此设置为 NULL。
  8. );
复制代码
通过调用如上两个函数将权限设置好以后,我们再手动将ImageSectionObject也就是映像节对象填充为0,然后再将DeleteAccess删除权限位打开,最后调用ZwDeleteFile()函数即可实现强制删除文件的效果,其核心代码如下所示;
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include "lyshark.h"
  6. // 强制删除文件
  7. BOOLEAN ForceDeleteFile(UNICODE_STRING pwzFileName)
  8. {
  9.         PEPROCESS pCurEprocess = NULL;
  10.         KAPC_STATE kapc = { 0 };
  11.         OBJECT_ATTRIBUTES fileOb;
  12.         HANDLE hFile = NULL;
  13.         NTSTATUS status = STATUS_UNSUCCESSFUL;
  14.         IO_STATUS_BLOCK iosta;
  15.         PDEVICE_OBJECT DeviceObject = NULL;
  16.         PVOID pHandleFileObject = NULL;
  17.         // 判断中断等级不大于0
  18.         if (KeGetCurrentIrql() > PASSIVE_LEVEL)
  19.         {
  20.                 return FALSE;
  21.         }
  22.         if (pwzFileName.Buffer == NULL || pwzFileName.Length <= 0)
  23.         {
  24.                 return FALSE;
  25.         }
  26.         __try
  27.         {
  28.                 // 读取当前进程的EProcess
  29.                 pCurEprocess = IoGetCurrentProcess();
  30.                 // 附加进程
  31.                 KeStackAttachProcess(pCurEprocess, &kapc);
  32.                 // 初始化结构
  33.                 InitializeObjectAttributes(&fileOb, &pwzFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
  34.                 // 文件系统筛选器驱动程序 仅向指定设备对象下面的筛选器和文件系统发送创建请求。
  35.                 status = IoCreateFileSpecifyDeviceObjectHint(&hFile,
  36.                         SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_READ_DATA,
  37.                         &fileOb,
  38.                         &iosta,
  39.                         NULL,
  40.                         0,
  41.                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  42.                         FILE_OPEN,
  43.                         FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  44.                         0,
  45.                         0,
  46.                         CreateFileTypeNone,
  47.                         0,
  48.                         IO_IGNORE_SHARE_ACCESS_CHECK,
  49.                         DeviceObject);
  50.                 if (!NT_SUCCESS(status))
  51.                 {
  52.                         return FALSE;
  53.                 }
  54.                 // 在对象句柄上提供访问验证,如果可以授予访问权限,则返回指向对象的正文的相应指针。
  55.                 status = ObReferenceObjectByHandle(hFile, 0, 0, 0, &pHandleFileObject, 0);
  56.                 if (!NT_SUCCESS(status))
  57.                 {
  58.                         return FALSE;
  59.                 }
  60.                 // 镜像节对象设置为0
  61.                 ((PFILE_OBJECT)(pHandleFileObject))->SectionObjectPointer->ImageSectionObject = 0;
  62.                 // 删除权限打开
  63.                 ((PFILE_OBJECT)(pHandleFileObject))->DeleteAccess = 1;
  64.                 // 调用删除文件API
  65.                 status = ZwDeleteFile(&fileOb);
  66.                 if (!NT_SUCCESS(status))
  67.                 {
  68.                         return FALSE;
  69.                 }
  70.         }
  71.         _finally
  72.         {
  73.                 if (pHandleFileObject != NULL)
  74.                 {
  75.                         ObDereferenceObject(pHandleFileObject);
  76.                         pHandleFileObject = NULL;
  77.                 }
  78.                 KeUnstackDetachProcess(&kapc);
  79.                 if (hFile != NULL || hFile != (PVOID)-1)
  80.                 {
  81.                         ZwClose(hFile);
  82.                         hFile = (PVOID)-1;
  83.                 }
  84.         }
  85.         return TRUE;
  86. }
  87. VOID UnDriver(PDRIVER_OBJECT driver)
  88. {
  89.         DbgPrint("驱动卸载成功 \n");
  90. }
  91. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  92. {
  93.         DbgPrint("Hello LyShark.com \n");
  94.         UNICODE_STRING local_path;
  95.         UNICODE_STRING file_path;
  96.         BOOLEAN ref = FALSE;
  97.        
  98.         // 初始化被删除文件
  99.         RtlInitUnicodeString(&file_path, L"\\??\\C:\\lyshark.exe");
  100.         // 获取自身驱动文件
  101.         local_path = ((PLDR_DATA_TABLE_ENTRY64)Driver->DriverSection)->FullDllName;
  102.         // 删除lyshark.exe
  103.         ref = ForceDeleteFile(file_path);
  104.         if (ref == TRUE)
  105.         {
  106.                 DbgPrint("[+] 已删除 %wZ \n",file_path);
  107.         }
  108.         // 删除WinDDK.sys
  109.         ref = ForceDeleteFile(local_path);
  110.         if (ref == TRUE)
  111.         {
  112.                 DbgPrint("[+] 已删除 %wZ \n", local_path);
  113.         }
  114.         Driver->DriverUnload = UnDriver;
  115.         return STATUS_SUCCESS;
  116. }
复制代码
编译并运行如上程序,则会分别将c://lyshark.exe以及驱动程序自身删除,并输出如下图所示的提示信息;


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

西河刘卡车医

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表