天天看點

windbg下看系統非分頁記憶體

    這篇文章實在是閑的無聊才寫的,因為快過年了...文章基于xpsp3

    先看看和非分頁記憶體相關的全局變量,也好有個大局觀:

kd> x nt!MmNonPaged*
805517d8          nt!MmNonPagedPoolEnd = <no type information>
8055af84          nt!MmNonPagedPoolEnd0 = <no type information>
8055af80          nt!MmNonPagedPoolExpansionStart = <no type information>
8055fb20          nt!MmNonPagedSystemStart = <no type information>
8055af60          nt!MmNonPagedPoolFreeListHead = <no type information>
8055ae38          nt!MmNonPagedPoolStart = <no type information>

kd> dd nt!MmNonPagedPoolStart L1
8055ae38  8164b000
kd> dd nt!MmNonPagedPoolEnd0 L1
8055af84  86800000      

    x nt!MmNonPaged*列出了可能和非分頁記憶體池相關的全局變量。在這篇文章裡,主要涉及3個變量:

nt!MmNonPagedPoolEnd0:儲存基本NonPagedd記憶體池的結束位址

nt!MmNonPagedSystemStart:儲存基本NonPagedd記憶體池的開始位址

nt!MmNonPagedPoolFreeListHead:空閑Nonpaged頁面隊列頭數組;xp下該數組有4個元素,每個數組元素都是_LIST_ENTRY結構。MmNonPagedPoolFreeListHead[0]中的節點包含1個頁面;MmNonPagedPoolFreeListHead[1]中的節點儲存了2個頁面,以此類推。

    來看下這幾個隊列的使用情況:

kd> dd nt!MmNonPagedPoolFreeListHead L8 ;下面的[]是我自己加的,用于分割各個_LIST_ENTRY結構
8055af60  [8055af60 8055af60] [86674000 863e9000]
8055af70  [86071000 86071000] [863ec000 8164b000]      

    從dd的結果可以看出,現在數組元素0和2是空隊列,裡面的空閑頁面已被瓜分完。也就是單頁面和3頁面的Nonpaged記憶體池已用完。現在我們知道Nonpaged記憶體池的使用情況,再來看看各個空閑頁面連結清單中的節點。既然MmNonPagedPoolFreeListHead[0]和MmNonPagedPoolFreeListHead[2]已經告罄,我們就來看看剩下的兩個連結清單:

kd> dt nt!*MMFREE*
          ntoskrnl!_MMFREE_POOL_ENTRY
kd> dt ntoskrnl!_MMFREE_POOL_ENTRY
   +0x000 List             : _LIST_ENTRY
   +0x008 Size             : Uint4B
   +0x00c Signature        : Uint4B
   +0x010 Owner            : Ptr32 _MMFREE_POOL_ENTRY      

    上面的結構是空閑頁面隊列中各個節點的類型。以MmNonPagedPoolFreeListHead[1]中的節點為例,每個節點中包含2個連續的頁面,每個頁面的起始位置被用作ntoskrnl!_MMFREE_POOL_ENTRY結構。再繼續下去前,先讓我介紹一下各個域的作用:

1.隻有節點中的第一個頁面的ntoskrnl!_MMFREE_POOL_ENTRY!_LIST_ENTRY域會被加入到MmNonPagedPoolFreeListHead[1]所在的空閑頁面連結清單中,第二個頁面的ntoskrnl!_MMFREE_POOL_ENTRY!_LIST_ENTRY域不起作用;

2.由于節點中的兩個頁面的位址是連續的,是以,在MmNonPagedPoolFreeListHead[1]中定位到第一個頁面的ntoskrnl!_MMFREE_POOL_ENTRY!_LIST_ENTRY域,再加上PAGE_SIZE,就可以獲得後續頁面。至于ntoskrnl!_MMFREE_POOL_ENTRY!Size的作用,則用于反應節點中有多少個頁面;

3.除了節點中第一個頁面的ntoskrnl!_MMFREE_POOL_ENTRY!Owner域指向本頁面的ntoskrnl!_MMFREE_POOL_ENTRY以外,節點中的其他頁面的Owner域都指向第一個頁面的ntoskrnl!_MMFREE_POOL_ENTRY。

    了解了這個背景後,看下MmNonPagedPoolFreeListHead[1]中的節點的值:

kd> dt _LIST_ENTRY 8055af60+8 ;MmNonPagedPoolFreeListHead[1]的位址
nt!_LIST_ENTRY
 [ 0x86674000 - 0x863e9000 ]
   +0x000 Flink            : 0x86674000 _LIST_ENTRY [ 0x863c8000 - 0x8055af68 ] ;記憶體0x86674000處有一個_MMFREE_POOL_ENTRY類型的節點
   +0x004 Blink            : 0x863e9000 _LIST_ENTRY [ 0x8055af68 - 0x86197000 ]
kd> dt ntoskrnl!_MMFREE_POOL_ENTRY 0x86674000 
   +0x000 List             : _LIST_ENTRY [ 0x863c8000 - 0x8055af68 ]
   +0x008 Size             : 2 ;節點中有2個頁面
   +0x00c Signature        : 2
   +0x010 Owner            : 0x86674000 _MMFREE_POOL_ENTRY ;Owner指向自己
kd> dt ntoskrnl!_MMFREE_POOL_ENTRY 0x86674000+0x1000 ;節點中的第二個頁面
   +0x000 List             : _LIST_ENTRY [ 0x44524352 - 0x90028 ]
   +0x008 Size             : 0x35e41f0
   +0x00c Signature        : 0
   +0x010 Owner            : 0x86674000 _MMFREE_POOL_ENTRY ;owner指向前一個頁面的_MMFREE_POOL_ENTRY結構      

    Windows就是基于這樣的結構,對Nonpaged記憶體池進行管理的~

繼續閱讀