windows内核情景分析读书笔记-----HYPERSPACE

来源:互联网 发布:中日互译软件 编辑:程序博客网 时间:2024/06/09 16:53

主要介绍HYPERSPACE的创建映射函数

赏光看我这一系列文章的朋友最好结合毛德操老师的书来看,具体的细节我这里就不阐述了

简单说下这个函数功能

Windows内核有时候需要把某些物理页面临时映射到内核的虚存空间,用做临时的用途

#define HYPERSPACE (Ke386Pae?0x c080 0000:0x c040 0000)

区间大小为0x0040 0000  也就是1024个页面

其中Ke386Pae这个布尔值代表系统是32位还是64

PVOID

NTAPI

MmCreateHyperspaceMapping(PFN_TYPE Page)

{

   PVOID Address;

   ULONG i;

 

   if (Ke386Pae)

   {

      ULONGLONG Entry;

      ULONGLONG ZeroEntry = 0LL;

      PULONGLONG Pte;

 

      Entry = PFN_TO_PTE(Page) | PA_PRESENT | PA_READWRITE;

      Pte = PAE_ADDR_TO_PTE(HYPERSPACE) + Page % 1024;

 

      if (Page & 1024)

      {

         for (i = Page %1024; i < 1024; i++, Pte++)

         {

            if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry))

    {

       break;

    }

         }

         if (i >= 1024)

         {

            Pte = PAE_ADDR_TO_PTE(HYPERSPACE);

    for (i = 0; i < Page % 1024; i++, Pte++)

    {

               if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry))

       {

          break;

       }

    }

    if (i >= Page % 1024)

    {

       KEBUGCHECK(0);

    }

         }

      }

      else

      {

         for (i = Page %1024; (LONG)i >= 0; i--, Pte--)

         {

            if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry))

    {

       break;

    }

         }

         if ((LONG)i < 0)

         {

            Pte = PAE_ADDR_TO_PTE(HYPERSPACE) + 1023;

    for (i = 1023; i > Page % 1024; i--, Pte--)

    {

               if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry))

       {

          break;

       }

    }

    if (i <= Page % 1024)

    {

       KEBUGCHECK(0);

    }

         }

      }

   }

   else

   {

      ULONG Entry;

      PULONG Pte;

      Entry = PFN_TO_PTE(Page) | PA_PRESENT | PA_READWRITE;//构建页面表项PTE内容,设置PRESENT,WRITEREAD标志位等

      Pte = ADDR_TO_PTE(HYPERSPACE) + Page % 1024;//页面表项的地址 讲解点A

      if (Page & 1024)//page10位为1,代表虚存页面搜索的方向为上

      {

         for (i = Page % 1024; i < 1024; i++, Pte++)

         {

            if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))

            {//Pte0比较,如果相等,返回Pte。否则返回Entry

               break;

            }

         }

         if (i >= 1024)//遍历到上边界,则要重新返回下边界,下边界就是那个特殊页面

         {

            Pte = ADDR_TO_PTE(HYPERSPACE);

            for (i = 0; i < Page % 1024; i++, Pte++)

            {

               if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))

               {

                  break;

               }

            }

            if (i >= Page % 1024)

            {

               KEBUGCHECK(0);

            }

         }

      }

      else

      {

         for (i = Page % 1024; (LONG)i >= 0; i--, Pte--)

         {

            if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))

            {

               break;

            }

         }

         if ((LONG)i < 0)

         {

            Pte = ADDR_TO_PTE(HYPERSPACE) + 1023;

            for (i = 1023; i > Page % 1024; i--, Pte--)

            {

               if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))

               {

                  break;

               }

            }

            if (i <= Page % 1024)

            {

               KEBUGCHECK(0);

            }

         }

      }

   }

   Address = (PVOID)((ULONG_PTR)HYPERSPACE + i * PAGE_SIZE);

   __invlpg(Address);

   return Address;

}

 

讲解点A

   #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))

   首先我们先看几个宏

   #define PAGETABLE_MAP  0xC000 0000

   #define HYPERSPACE      0xC040 0000

   我们应当明确,虚拟地址中从PAGETABLE_MAP,也就是0xC000 0000一直到C03f ffff保存着该进程的页表,而从下一个单元,也就是HYPERSPACEC040 0000)开始一直到C0C0 0000,这一段空间则是大小为4MHYPERSPACE空间,我们知道一个页面是4K大小,则4M就是1K个页面大小的空间。

   而页表空间,从0xC000 0000一直到C03f ffff大小则为2^22次方,也就是4M,也就是1K个一个页面的大小。

   这个页面空间大家要注意,我们知道,这里的页面对应于整个4G空间,也就是说,里面一个32位的单元,就对应于整个4G的虚存空间的一个页面。

   这个方式比较神奇,也就是说,自己的一部分,对应于自己的整个身体。

   如果我们把计算机比作一个人体,则在人体肚子上取几个细胞,每个细胞从上到下依次对应着人的头,胳膊,胸,腹,腿等··(当然这个脑洞开的有点大),自己映射了自己。

   那么,页表中肯定有几个32位的值,对应着页表自身,同时,肯定也有几个32位的值,对应着后面大小为4MHYPERSPACE

   我们既然知道页表大小为4M,而且这4M对应着整个4G空间,其中每个32位的值(也就是4B)对应着一个页面,所以其中页面项在页表中的偏移就是其对应的物理页面在整个4G空间的偏移。

  在非Ke386Pae部分,我们看到了

  Pte = ADDR_TO_PTE(HYPERSPACE) + Page % 1024;

  ADDR_TO_PTE宏定义如下

  #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))

  经过上面的叙述,这个应该不难分析了,部分映射整体。

  经过计算,该宏结果为C030 1000

  整体过程分析如下:

 

 

 

 

 

 

 

 

    

 蓝色代表页表空间,红色代表HYPERSPACE,二者大小都是4M

 而位于蓝色页表中的黄色部分,则映射着整个HYPERSPACE,也就是红色部分。

 程序首先从 ADDR_TO_PTE(HYPERSPACE) + Page % 1024位置处开始寻找(这里假设为),如果B101,则往上找,到了顶点后,再返回最下边,往上找,如果B100,则相反。

  这里有个比较有意思的事情,它并不是直接在红色部分直接一个一个页面的找自由页面的,而是在它的映射里(也就是黄色部分)中查找的。

  所以循环里i的变化,pte的变化,一直限定在黄色部分。直到循环结束,i确定后,才从红色部分基址C040 0000开始,加上i*PAGESIZE,返回的结果就是红色部分中一个页面的地址。

  

 

 


0 0
原创粉丝点击