1. 程式人生 > >windows核心情景分析讀書筆記-----HYPERSPACE

windows核心情景分析讀書筆記-----HYPERSPACE

主要介紹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,返回的結果就是紅色部分中一個頁面的地址。