• 【驱动笔记14】初步认识MDL

    2009-03-17

    分类:内核编程

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://nokyo.blogbus.com/logs/36654356.html

    前段时间在群里有人问起什么是MDL,当时三言两语也不知道解释清楚了没,今天闲着无事,索性记录下来吧,就当是做个笔记,以后忘了也好查阅。

    我们知道,系统中一些重要的表项如SSDT是只读的,如果我们强行对其进行修改就会造成BSOD的严重后果。当然这种保护方式很容易被绕过,我们曾经介绍了通过修改cr0来禁用WP(Write Protect,写保护)位的方法,现在再介绍一种不需要使用汇编的方法,就是MDL。

    MDL的全称是Memory Descriptor List,即内存描述符表。我们可以通过MDL描述一块内存区域,在MDL中包含了该内存区域的起始地址、拥有者进程、字节数量、标记等信息,如下所示:
    typedef struct _MDL
    {
        struct _MDL  *Next;
        CSHORT       Size;
        CSHORT       MdlFlags;
        struct _EPROCESS *Process;
        PVOID          MappedSystemVa;
        PVOID          StartVa;
        ULONG         ByteCount;
        ULONG   ByteOffset;
    } MDL, *PMDL;

    我们先来看一段在SSDT HOOK中常见的代码,如下所示:
    PMDL MDSystemCall;
    PVOID *MappedSCT;

    MDSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
    if(!MDSystemCall)
    {
        return STATUS_UNSUCCESSFUL;
    }
    MmBuildMdlForNonPagedPool(MDSystemCall);
    MDSystemCall->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
    MappedSCT = MmMapLockedPages(MDSystemCall, KernelMode);
    HookOn( ZwTerminateProcess, New_ZwTerminateProcess);

    其中KeServiceDescriptorTable描述的是SSDT,其中ServiceTableBase标明了SSDT的起始地址,因此我们通过MmCreateMdl函数创建一个MDL,它刚好把SSDT这块内存包含在内,有人可能会问,它的长度为啥是“KeServiceDescriptorTable.NumberOfServices*4”字节呢?很简单,因为指针的长度是4个字节。

    后面的代码首先从不分页的内存池中Build MDL,然后添加一个MDL_MAPPED_TO_SYSTEM_VA标记以便允许写入该内存区域;然后我们将这块内存锁起来,现在可以就开始HOOK SSDT了,直到关闭HOOK后才将其释放。从这里就可以看出,这种方式明显没有修改cr0的方法好,呵呵呵呵。

    不过这种方法的应用范围比较广,控制精度也较好,精确地指定了要修改哪一块内存的标记,两者方法算是各有千秋吧,谁喜欢用哪一种都可以。





    评论

  • 你好,我一直以来就有个疑问,
    PVOID *MappedSCT;//MappedSCT是PVOID *型

    MmMapLockedPages在MSDN上是这样的:
    PVOID
    MmMapLockedPages(
    IN PMDL MemoryDescriptorList,
    IN KPROCESSOR_MODE AccessMode
    );
    也就是说MmMapLockedPages返回是PVOID型的,
    但是为什么每个人都会直接这样写:
    MappedSCT = MmMapLockedPages(MDSystemCall, KernelMode);
    VS2008下,会发生 cannot convert from 'PVOID' to 'PVOID *'编译错误,但DDK默认的那个却能通过编译,
    期待博主的回答!

  • 很好,很强大.