在某些時候我們的系統中會出現一些無法被正常刪除的文件,如果想要強制刪除則需要在驅動層面對其進行解鎖后才可刪掉,而所謂的解鎖其實就是釋放掉文件描述符(句柄表)占用,文件解鎖的核心原理是通過調用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
以及驅動程序自身刪除,并輸出如下圖所示的提示信息;