美文网首页
枚举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