美文网首页
枚举MmMapViewInSystemSpace分配的内存

枚举MmMapViewInSystemSpace分配的内存

作者: 看雪学院 | 来源:发表于2018-09-19 18:00 被阅读38次

    之前曝光了一个利用MmMapViewInSystemSpace往驱动空间所在区域分配内存的外挂

    传送门:https://bbs.pediy.com/thread-230129.htm

    闲的蛋疼就研究了一下怎么枚举这种方法分配出来的内存。

    首先明确一下虚拟内存的分配流程:

    vista以上:

    MmMapViewInSystemSpace ->MiMapViewInSystemSpace->MiInsertInSystemSpace->MiReserveSystemPtes(&MiSystemPteInfo, PteCount)

    (不同系统可能不同,但是总之是预留PTE)

    xp:

    MmMapViewInSystemSpace ->MiMapViewInSystemSpace->MiInsertInSystemSpace->

    从SystemSpaceBitMap找一块满足sizein64k大小的空的bitmap出来,对应到预先分配好的SystemSpaceViewStart里,直接作为分配出的地址

    物理内存的分配流程:

    刚才分配的PTE present位为0,访问时触发pagefault再分配物理内存,原理和NtMapViewOfSection差不多,都是只管分配VA,访问时#pf才给分配物理内存

    这种情况下分配物理内存时不会往MmPfnDatabase中写入pfn对应的pte信息(毕竟一个section可以被多个PTE映射不是么),导致MmGetVirtualForPhysical无法从物理地址反查虚拟地址

    我们可以找个有符号的win7看一下:

    发现和wrk差不多,直接看wrk。

    关键代码

    Entry = (ULONG_PTR) MI_64K_ALIGN(Base) + SizeIn64k;

        Hash = (ULONG) ((Entry >> 16) % Session->SystemSpaceHashKey);

        while (Session->SystemSpaceViewTable[Hash].Entry != 0) {

            Hash += 1;

            if (Hash >= Session->SystemSpaceHashSize) {

                Hash = 0;

            }

        }

        Session->SystemSpaceHashEntries += 1;

        Session->SystemSpaceViewTable[Hash].Entry = Entry;

        Session->SystemSpaceViewTable[Hash].ControlArea = ControlArea;

    那么只要遍历MmSession的SystemSpaceViewTable就能找到所有的va。

    entry的算法是这样的:

    entry=64k对齐(虚拟地址)  +  多少个64k

    也就是说entry的高48位是虚拟地址,低16位是大小(指有几个64k)

    从分配前的检查也可以看出,不能分配超过(65535=64k-1)个64k,否则超过低16位能保存的大小了。

    算出来的entry会简单计算一个hash放到 SystemSpaceViewTable 里。

    那么我们遍历这个表就能拿到所有的SystemSpaceView VA和大小了,遍历前记得加锁SystemSpaceViewLockPointer。

    PMMSESSION_WIN7 Session = (PMMSESSION_WIN7)MmSession;

    for (ULONG i = 0; i < Session->SystemSpaceHashSize; i ++) {

        if (Session->SystemSpaceViewTable[i].Entry != 0) {

                PVOID BaseAddress = (PVOID)(((Session->SystemSpaceViewTable[i].Entry >> 16) << 16) | 0xFFFF000000000000ull);//Higher 48 bit of Entry is BaseAddress aligned to 64k

                SIZE_T ViewSize = (Session->SystemSpaceViewTable[i].Entry & 0xFFFFull) * 0x10000;//lowest 16 bit of Entry is SizeIn64k

                //Now you get BaseAddress and ViewSize, ViewSize is count in bytes.

            }

        }

    }

    32位系统的区别仅在于高16位是虚拟地址,低16位是大小,其他和64位没有任何区别,因此以上代码甚至只需要把PMMESSION结构换成32位版本就行了。

    至于PMMSESSION结构,自己找个有符号的win7自提。

    MMSESSION  MmSession变量在MmMapViewInSystemSpace入口一个lea rdx就有

    以上遍历兼容xp~win8.1

    遍历结果:

    然后看一下win10的 MiInsertInSystemSpace ,貌似变化有点大,不用hash表而是用红黑树了。

    typedef struct _MMSESSION_WIN10

    {

    EX_PUSH_LOCK SystemSpaceViewLock;

    PEX_PUSH_LOCK SystemSpaceViewLockPointer;

    PRTL_AVL_TREE ViewRoot;

    ULONG ViewCount;

    ULONG BitmapFailures;

    }MMSESSION_WIN10, *PMMSESSION_WIN10;

    ViewRoot这个 RTL_BALANCED_NODE 其实是一个侵入式数据结构,他的大小远不止sizeof( RTL_AVL_NODE )这么一点,而是:

    而是有0x60这么大。

    遍历这个红黑树需要你有 RTL_BALANCED_NODE 所在完整的结构,我随便逆了一下,只拿了几个重要的成员:

    typedef struct __declspec(align(8)) _MMVIEW_WIN10

    {

        RTL_BALANCED_NODE SectionNode;

        ULONG64 Unkown1;

        ULONG_PTR ViewSize;

        ULONG_PTR Unkown2;

        PVOID ControlArea;

        PVOID FileObject;

        ULONG_PTR Unknown3;

        ULONG_PTR Unknown4;

        PVOID SessionViewVa;

        ULONG Unknown5;

        ULONG Unknown6;

    }MMVIEW_WIN10, *PMMVIEW_WIN10;

    那我们遍历红黑树岂不是写个递归就完事了。

    要注意写入VA的时候会遇上一些奇怪的bit,我们要去掉:

    void EnumSystemSpaceViewWin10(PMMVIEW_WIN10 view)

    {

        PVOID BaseAddress = (PVOID)((ULONG_PTR)view->SessionViewVa & (~3));

        //now you have

        //BaseAddress

        //view->ViewSize

        PMMVIEW_WIN10 right = (PMMVIEW_WIN10)view->SectionNode.Right;

        if (right)

        {

            EnumSystemSpaceViewWin10(right);

        }

        PMMVIEW_WIN10 left = (PMMVIEW_WIN10)view->SectionNode.Left;

        if (left)

        {

            EnumSystemSpaceViewWin10(left);

        }

    }

    EnumSystemSpaceViewWin10((PMMVIEW_WIN10)Session->ViewRoot); 

    记得win10也要加锁,而且锁换成了PUSH_LOCK。

    然后你拿这份代码试了一下,发现在systemspaceview非常多的情况下会栈溢出爆炸。

    因为递归层数太多了,你需要把递归算法改成循环。

    修改过的循环遍历代码由于过于丑陋这里就不放了,类似于这种:(以下代码是网上抄的)

    void xunhuanzhongxubianli(BinaryTreeNode * root)

    {

    stack<BinaryTreeNode*> ss;

    if (root == NULL)

    {

    return;

    }

    BinaryTreeNode * pRoot = root;

    while (pRoot || ss.size() > 0)

    {

    while (pRoot)

    {

    ss.push(pRoot);

    pRoot = pRoot->m_pLeft;

    }

    BinaryTreeNode * temp = ss.top();

    ss.pop();

    cout << temp->m_nValue << " ";

    pRoot = temp->m_pRight;

    }

    }

    win10下遍历结果确实有丶多,递归很容易爆栈:

    以上,完。

    原文作者:hzqst

    原文链接:https://bbs.pediy.com/thread-246843.htm

    转载请注明:转自看雪学院

    看雪阅读推荐:

    1、[翻译] 利用DNS重绑定攻击专用网络

    2、[翻译]利用机器学习检测恶意PowerShell

    3、[原创]看雪.京东 2018CTF 第十五题 智能设备 Writeup

    4、[原创]浅谈编码与内存----自我总结与经验分享

    5、[翻译]radare2高阶

    相关文章

      网友评论

          本文标题:枚举MmMapViewInSystemSpace分配的内存

          本文链接:https://www.haomeiwen.com/subject/smoinftx.html