講講怎麼列舉MmMapViewInSystemSpace分配的記憶體

Editor發表於2018-09-19
之前曝光了一個利用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看一下:

講講怎麼列舉MmMapViewInSystemSpace分配的記憶體

發現和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)


講講怎麼列舉MmMapViewInSystemSpace分配的記憶體


從分配前的檢查也可以看出,不能分配超過(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


遍歷結果:


講講怎麼列舉MmMapViewInSystemSpace分配的記憶體


然後看一下win10的 MiInsertInSystemSpace ,貌似變化有點大,不用hash表而是用紅黑樹了。


講講怎麼列舉MmMapViewInSystemSpace分配的記憶體

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 )這麼一點,而是

講講怎麼列舉MmMapViewInSystemSpace分配的記憶體

而是有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,我們要去掉:

講講怎麼列舉MmMapViewInSystemSpace分配的記憶體


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下遍歷結果確實有丶多,遞迴很容易爆棧:

講講怎麼列舉MmMapViewInSystemSpace分配的記憶體

以上,完。



原文作者:hzqst

原文連結:https://bbs.pediy.com/thread-246843.htm

轉載請註明:轉自看雪學院



看雪閱讀推薦:


1、[翻譯] 利用DNS重繫結攻擊專用網路


2、[翻譯]利用機器學習檢測惡意PowerShell


3、[原創]看雪.京東 2018CTF 第十五題 智慧裝置 Writeup


4、[原創]淺談編碼與記憶體----自我總結與經驗分享


5、[翻譯]radare2高階


相關文章