⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jiurl玩玩win2k内存篇 page frame number database.htm

📁 关于win2000核心编程的文章
💻 HTM
📖 第 1 页 / 共 2 页
字号:
      <P>struct PageListHead (大小16个字节,即0x10个字节)<BR>/*00*/ uint32 
      NumberOfPagesInList<BR>/*04*/ uint32 TypeOfList<BR>/*08*/ uint32 
      FirstPage<BR>/*0C*/ uint32 LastPage</P>
      <P>/*00*/ uint32 NumberOfPagesInList<BR>这个链表的项数<BR><BR>/*04*/ uint32 
      TypeOfList<BR>这个链表上 PfnDataBaseEntry 
      的类型(Zeroed,Free,Standby,Modified,ModifiedNoWrite,Bad 
      这6种中的一种)<BR><BR>/*08*/ uint32 FirstPage<BR>flink的第一项,是一个页帧号。<BR><BR>/*0C*/ 
      uint32 LastPage<BR>blink的第一项,是一个页帧号。<BR><BR>8种 page state 对应的值 ( 
      PfnDataBaseEntry 中的 page state 和 PageListHead 中的 TypeOfList)<BR>Zeroed 
      0x00<BR>Free 0x01<BR>Standby 0x02<BR>Modified 0x03<BR>Modified no-write 
      0x04<BR>Bad 0x05<BR>Active (Valid) 0x06<BR>Transition 
      0x07<BR><BR>实际上还存在着一个数组 MmPageLocationList 。这个数组共6项,每项4个字节。数组第0项的内容为全局变量 
      MmZeroedPageListHead 中的值,注意 Zeroed 类型的值为0。数组第1项的内容为全局变量MmFreePageListHead 
      中的值,注意 Free 类型的值为1。以此类推。存在这个数组的原因是一些函数中可以使用物理页的类型作为索引,在这个数组中找到该类型物理页链的 
      PageListHead 结构的地址。<BR><BR>对于 Win2k Build 2195 来说,使用 kd 
      来获得全局变量的地址<BR><BR>比如<BR><BR>kd&gt; ? MmPfnDatabase<BR>? 
      MmPfnDatabase<BR>Evaluate expression: -2142854772 = 
      8046a18c<BR><BR>用这种方法得到<BR><BR>6个 PageListHead 
      的地址为<BR>MmZeroedPageListHead 0x80470a00<BR>MmFreePageListHead 
      0x80470a10<BR>MmStandbyPageListHead 0x80470a20<BR>MmModifiedPageListHead 
      0x80470a30<BR>MmModifiedNoWritePageListHead 
      0x80470a40<BR>MmBadPageListHead 0x80470a50<BR><BR>MmPageLocationList 
      数组的地址为<BR>MmPageLocationList 
      0x80470a60<BR><BR>可以发现他们是紧紧的挨在一起的。<BR><BR>下面我就来看一个具体的例子,以下内容通过 SoftICE 
      获得。<BR><BR>:dd 80470a00 l 80<BR>0010:80470A00 0000090E 00000000 00007F0A 
      0000009E ...............<BR>0010:80470A10 00000004 00000001 00002987 
      00006ACA .........)...j..<BR>0010:80470A20 0000242B 00000002 000042A6 
      00003ADB +$.......B...:..<BR>0010:80470A30 000001CB 00000003 FFFFFFFF 
      FFFFFFFF ................<BR>0010:80470A40 00000000 00000004 FFFFFFFF 
      FFFFFFFF ................<BR>0010:80470A50 00000000 00000005 FFFFFFFF 
      FFFFFFFF ................<BR>0010:80470A60 80470A00 80470A10 80470A20 
      80470A30 ..G...G. .G.0.G.<BR>0010:80470A70 80470A40 80470A50 00000000 
      00000000 @.G.P.G.........<BR>// 6个链表的 PageListHead 结构,可以看到每个 PageListHead 
      结构偏移 +4 处的 4个字节内容就是该链表// 上物理页的状态值<BR>// MmPageLocationList 
      数组共有6项,每项4个字节,相应物理页状态值作为索引的项的内容,就是相应的<BR>// PageListHead 结构的地址<BR><BR>// 
      下面我们来遍历 FreePage List ,可以看到这个链上一共有4项,我们从FirstPage遍历这个链表。<BR>// 从 
      PageListHead 中,我们可以看到 FirstPage 值为 00002987<BR><BR>// 
      PfnDataBase的首地址保存在全局变量 MmPfnDatabase 中<BR>// 前面已经看到 Win2k Build 2195 的 
      MmPfnDatabase 地址为8046a18c,<BR>// 对于当前我的系统中,地址8046a18c处的值为 81456000 ,<BR>// 
      即当前 PfnDataBase的首地址为 81456000<BR><BR>// 第2987项 PfnDataBaseEntry 的虚拟地址为 
      81456000+18*2987 ,该结构大小为 0x18<BR>:dd 81456000+18*2987 l 
      18<BR>0010:814944A8 00006B68 FFFFFFFF FFFFFFFF 00000101 
      hk..............<BR>0010:814944B8 FFFFFFFF 0000064C 00002EB1 FFFFFFFF 
      ....L...........<BR>// 可以看到该项的后一项为 FFFFFFFF ,说明了这一项的确是 FirstPage<BR><BR>// 
      第6B68项<BR>:dd 81456000+18*6b68 l 18<BR>0010:814F71C0 00000169 FFFFFFFF 
      00002987 00000101 i........)......<BR>0010:814F71D0 FFFFFFFF 0000064C 
      0000268D C038CA6C ....L....&amp;..l.8.<BR><BR>// 第169项<BR>:dd 
      81456000+18*169 l 18<BR>0010:814581D8 00006ACA FFFFFFFF 00006B68 00000101 
      .j......hk......<BR>0010:814581E8 FFFFFFFF 0000064C 000042E6 E17BE324 
      ....L....B..$.{.<BR><BR>// 第6ACA项<BR>:dd 81456000+18*6aca l 
      18<BR>0010:814F62F0 FFFFFFFF FFFFFFFF 00000169 00000101 
      ........i.......<BR>0010:814F6300 FFFFFFFF 0000064C 00004EC4 E35E0BE0 
      ....L....N....^.<BR>// 它的flink项的值为FFFFFFFF,表明flink已经结束了。也表明它是LastPage,从 
      PageListHead 结构中// 我们也看到 LastPage 的确是 00006ACA<BR><BR>注意我们遍历的是 FreePage 
      List ,我们检查每项的 TypeOfList 字段(偏移+d处的一个字节),值都为01。的确是Free类型。</P>
      <P>&nbsp;&nbsp;&nbsp; 从6个 PageListHead 结构之后紧跟着 MmPageLocationList 数组,以及 
      MmPageLocationList 
      数组只有6项,可以看出系统中只有这6种状态类型的物理页存在着链表。另两种状态类型的物理页并没有被链表链起来。对于这6个 PageListHead 
      结构,进行一定时间观察后,发现 MmModifiedNoWritePageListHead,MmBadPageListHead 
      的两个链总是空的。我的内存中没有硬件损坏的单元,所以 MmBadPageListHead 
      应该是空的。MmModifiedNoWritePageListHead 链上我也没有看到过有链表项(我硬盘中没有ntfs分区)。我能看到经常变化的是 
      Zeroed,Free,Standby,Modified 这4种链。需要说明的是,这4种链的变化是非常频繁的。一定要注意这一点,如果你这一秒你读出了 
      Free 链上的一项,那么下一秒它很有可能已经不在 Free 链上了,系统的一些线程可能已经对该页做了某些操作,并把该页对应的 
      PfnDataBaseEntry 做相应修改。不过对于 SoftICE 不存在这个问题。可以使用 SoftICE 的命令 BPMD 
      来对这种变化,和引起这个变化的函数进行观察。 BPMD 就是在指定地址的 DWORD 大小的内存上下断点,任何访问(读写)这个 DWORD 
      的指令,将被 SoftICE 断到。加上参数W,就只中断对这个DWORD写的指令。比如使用 BPMD 80470a00 W 来观察 Zeroed 
      Page List 的变化,因为 80470a00 处是MmZeroedPageListHead结构的 entry count 
      (这个链的链表项项数),链如果变化,必须要相应的改变这个值。使用 dex 0 80470a00 来使数据窗口0 始终观察 80470a00 
      处的内存,或者 data 1 开一个新的数据窗口,然后 dex 1 80470a00 用数据窗口1始终观察 80470a00 
      处的内存。方便我们的观察。同样的方法观察另外3个链,或者同时观察几个链。你就会看到这些链的变化是多么的频繁。</P>
      <P>&nbsp;&nbsp;&nbsp; 我们还可以注意到 FreePageList 
      这个链上的项数总是不多,几个,十几个,或者为零。这是由于,当Free 链上的项数到达一定数量,会引发 zero-page thread 
      ,如果系统空闲的话,zero-page thread 就会被执行,它会把把 Free 链上的物理页清零,放到 Zeroed 链上。</P>
      <P>&nbsp;&nbsp;&nbsp; 关于物理页状态变化,链的变化更多的内容可以参考 Mark Russinovich 的文章《Inside 
      Memory Management》,这篇文章你可以在网上找到。</P>
      <P>&nbsp;&nbsp;&nbsp; 对于每一个物理页,都在页帧数据库中有相应的一个 PfnDataBaseEntry 
      ,这样每一个物理页本身就需要使用一定的物理内存。一页物理页大小为4KB,需要一个大小为24字节的PfnDataBaseEntry。即4KB物理内存需要24B内存来保存信息,24/4096=0.005859375,也就是说 
      整个物理内存的 0.005859375 
      需要被PfnDataBase<BR>使用。对于128M物理内存来说,需要0.75M内存来保存PfnDataBase中的信息。128M物理内存,将被分成<BR>(128*1024*1024)/(4*1024)=(32*1024)页。所以PfnDataBase需要的页数是(32*1024)*24/4096=192页。对于128MB物理内存来说,最大的页帧号也不会超过(128*1024*1024)/(4*1024)=0x8000,也就是说PfnDataBase 
      的内容中,形成链的PfnDataBaseEntry的flink,blink 
      处的值除了0xFFFFFFFF,不会超过0x8000。而0xFFFFFFFF 经常在 PfnDataBaseEntry 
      中出现。根据这些,我们对于一段内存可以感觉到它是否是PfnDataBaseEntry 中的内容。我们观察 PfnDataBase 
      之后的第192页中的内容,可以感觉到是 PfnDataBase 的内容。而第193页中的内容就已经明显不是PfnDataBase 的内容了。</P>
      <P>&nbsp;&nbsp;&nbsp; 需要注意的是,PfnDataBaseEntry 
      结构,根据物理页状态的不同,结构的各字段的含义也是不一样的。前面对 PfnDataBaseEntry 
      结构的定义只是帮助你建立起大概的印象,是很不准确的。各种状态下,各字段的含义,会在其他用到的地方做更多的介绍。<BR><BR><B>8种状态对应值的获得 
      以及 PageListHead 结构的获得</B></P>
      <P>&nbsp;&nbsp;&nbsp; 8种状态对应值,是使用 kd 得到的。kd 的命令 !pfn 
      可以分析指定页帧号的PfnDataBaseEntry,指出这个PfnDataBaseEntry是哪种状态类型的。于是我利用驱动程序,申请了一块内存。由于每个PfnDataBaseEntry的地址都是从PfnDataBase 
      开始以0x18为边界的地址。所计算出在申请的这段内存中第一个从 PfnDataBase 
      开始以0x18为边界的地址,和这个地址对应的页帧号(其实申请的这块内存并不在PfnDataBase中,不过kd的命令!pfn并不管这些,只是根据页帧号算地址,然后分析该地址处的24个字节)。在这个地址开始的内存中写入一些值。使用!pfn分析。实际上我一次申请了10个0x18字节,对齐之后的9个0x18字节中,第一个0x18字节中每个字节都写入0x00。第二个0x18字节中每个字节都写入0x01,直到第九个0x18字节中每个字节都写入0x09。然后用这些地址相应的页块号做参数,使用!pfn命令,就得到了每个值所代表的物理页状态类型。<BR><BR>&nbsp;&nbsp;&nbsp; 
      MmPageLocationList 数组,以及 PageListHead 结构是使用SoftICE跟函数 MiRemovePageByColor 
      的过程中发现的。使用 kd 的 u MiRemovePageByColor ,反汇编 MiRemovePageByColor 我们可以得到 
      MiRemovePageByColor 的地址,还可以看到 MmPageLocationList 这个全局变量。 SoftICE 在该地址上下断点, 
      bpx 地址。在跟这个函数的过程中,你可以看到对 PageListHead 结构的操作,从而判断出这个结构中每项的作用。后来又在 
      www.insidewindows.info 的 unofficial ntifs.h 
      中也看到了这个结构,和我定义的内容是一样的。不过名字起的更好一些,于是我把该结构中各字段的名字改成了 unofficial ntifs.h 
      中的名字。<BR><BR><BR>欢迎交流,欢迎交朋友,<BR>欢迎访问 <A 
      href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A> <A 
      href="http://jiurl.cosoft.org.cn/forum">http://jiurl.cosoft.org.cn/forum</A> 
      <BR><BR><BR></P>
      <P>  </P></TD></TR></TBODY></TABLE></DIV></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -