主頁 > 後端開發 > 驅動開發:內核解鎖與強刪檔案

驅動開發:內核解鎖與強刪檔案

2023-06-16 07:36:25 後端開發

在某些時候我們的系統中會出現一些無法被正常洗掉的檔案,如果想要強制洗掉則需要在驅動層面對其進行解鎖后才可刪掉,而所謂的解鎖其實就是釋放掉檔案描述符(句柄表)占用,檔案解鎖的核心原理是通過呼叫ObSetHandleAttributes函式將特定句柄設定為可關閉狀態,然后在呼叫ZwClose將其檔案關閉,強制洗掉則是通過ObReferenceObjectByHandle在物件上提供相應的權限后直接呼叫ZwDeleteFile將其洗掉,雖此類代碼較為普遍,但作為揭秘ARK工具來說也必須要將其分析并講解一下,

首先封裝lyshark.h通用頭檔案,并定義好我們所需要的結構體,以及特定未匯出函式的宣告,此處的定義部分是微軟官方的規范,如果不懂結構具體含義可自行去微軟官方查閱參考資料,

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

#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程式的句柄占用;

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

#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 = https://www.cnblogs.com/LyShark/archive/2023/06/15/[ %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[260] = { 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[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;
		}

		// 查詢物件句柄的資訊并放入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[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()函式即可實作強制洗掉檔案的效果,其核心代碼如下所示;

// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]

#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以及驅動程式自身洗掉,并輸出如下圖所示的提示資訊;

文章作者:lyshark (王瑞)
文章出處:https://www.cnblogs.com/LyShark/p/17155477.html
本博客所有文章除特別宣告外,均采用 BY-NC-SA 許可協議,轉載請注明出處!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555240.html

標籤:其他

上一篇:springboot啟動流程 (1) 流程概覽

下一篇:返回列表

標籤雲
其他(161033) Python(38230) JavaScript(25496) Java(18240) C(15237) 區塊鏈(8270) C#(7972) AI(7469) 爪哇(7425) MySQL(7253) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4594) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2435) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) 功能(1967) HtmlCss(1966) Web開發(1951) C++(1940) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 驅動開發:內核解鎖與強刪檔案

    在某些時候我們的系統中會出現一些無法被正常洗掉的檔案,如果想要強制洗掉則需要在驅動層面對其進行解鎖后才可刪掉,而所謂的解鎖其實就是釋放掉檔案描述符(句柄表)占用,檔案解鎖的核心原理是通過呼叫`ObSetHandleAttributes`函式將特定句柄設定為可關閉狀態,然后在呼叫`ZwClose`將其... ......

    uj5u.com 2023-06-16 07:36:25 more
  • springboot啟動流程 (1) 流程概覽

    本文將通過閱讀原始碼方式分析SpringBoot應用的啟動流程,不涉及Spring啟動部分(有相應的文章介紹)。 本文不會對各個流程做展開分析,后續會有文章介紹詳細流程。 # SpringApplication類 ## 應用啟動入口 使用以下方式啟動一個SpringBoot應用: ```java @S ......

    uj5u.com 2023-06-16 07:36:15 more
  • Scala基本語法

    # scala的基本語法 ## 注釋 對于scala的注釋,簡而言之就是一句話,和java的注釋一模一樣 基本語法 ``` (1)單行注釋:// (2)多行注釋:/* */ (3)檔案注釋:/** * */ ``` 代碼示例: ```Scala package com.doitedu.demo01 ......

    uj5u.com 2023-06-16 07:30:15 more
  • C++面試八股文:在C++中,有哪些可執行體?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第14面: > 面試官:在C++中,有哪些可執行體? > > 二師兄:可執行體? > > 面試官:也就是可呼叫物件。 > > 二師兄:讓我想一想。函式、函式指標、類的靜態方法、類的成員方法、仿函式、lambda運算式。 > > 面試官:能說一說他們之 ......

    uj5u.com 2023-06-15 08:10:42 more
  • Set 介面及其常用方法

    Set 介面是 Collection 介面的一個子介面。Set 介面的實作類不會包含重復的元素,并且最多只能有一個 null 元素。當嘗試添加重復元素時,添加操作將被忽略。Set 介面取出元素的順序和添加元素的順序不一致(但是每次取出的順序是固定的),即無法通過索引訪問 Set 中的元素。 ......

    uj5u.com 2023-06-15 08:10:38 more
  • Go語言中的結構體:靈活性與可擴展性的重要角色

    # 1. 引言 結構體是Go語言中重要且靈活的概念之一。結構體的使用使得我們可以定義自己的資料型別,并將不同型別的欄位組合在一起,實作更靈活的資料結構。本文旨在深入介紹Go語言中的結構體,揭示其重要性和靈活性,并向讀者展示結構體支持的眾多特性,展示其強大之處。 # 2. 什么是結構體? 在Go語言中 ......

    uj5u.com 2023-06-15 08:10:33 more
  • 【python基礎】函式-初識函式

    函式是帶名字的代碼塊,用于完成具體的作業,無需反復撰寫完成該作業的代碼。之前我們接觸過print函式,資料型別轉換中的int函式、str函式,還有串列中的append函式、pop函式、remove函式,以及字典中的keys函式、values函式等等,其實在正式學習函式之前,我們已經接觸了函式,只不過 ......

    uj5u.com 2023-06-15 08:10:23 more
  • rocketMQ訊息佇列簡介及其實體

    一、RocketMQ 核心的四大組件: Producer:就是訊息生產者,可以集群部署。它會先和 NameServer 集群中的隨機一臺建立長連接,得知當前要發送的 Topic 存在哪臺 Broker Master上,然后再與其建立長連接,支持多種負載平衡模式發送訊息。 Consumer:訊息消費者 ......

    uj5u.com 2023-06-15 08:10:11 more
  • jvm垃圾回收及記憶體模型

    1、了解垃圾回收之前,必須先了解記憶體模型 2、垃圾回收區域 a、 首先要標記垃圾,找出垃圾 b、Java垃圾回收(一)_java 垃圾回收_頭發慢點掉的小馬的博客-CSDN博客 垃圾回收器 方法區不需要連續的記憶體,可以選擇固定大小或者可擴展。并且還可以選擇不實作垃圾收集。相對而言,垃圾收集行為在這個 ......

    uj5u.com 2023-06-15 08:09:55 more
  • Dubbo負載均衡策略之 一致性哈希

    本文主要講解了一致性哈希演算法的原理以及其存在的資料傾斜的問題,然后引出解決資料傾斜問題的方法,最后分析一致性哈希演算法在Dubbo中的使用。通過這篇文章,可以了解到一致性哈希演算法的原理以及這種演算法存在的問題和解決方案。 ......

    uj5u.com 2023-06-15 08:09:44 more