學習BluePill源碼筆記-2

1.5 MmCreateMapping過程——私有頁表構建初始化

NTSTATUS NTAPI MmCreateMapping (
  PHYSICAL_ADDRESS PhysicalAddress,
  PVOID VirtualAddress,
  BOOLEAN bLargePage
)
{
  PALLOCATED_PAGE Pml4Page;
  NTSTATUS Status;

  Status = MmFindPageByPA (g_PageMapBasePhysicalAddress, &Pml4Page);
  if (!NT_SUCCESS (Status)) {
    return STATUS_UNSUCCESSFUL;
  }

  PhysicalAddress.QuadPart = PhysicalAddress.QuadPart & 0x000ffffffffff000;
  VirtualAddress = (PVOID) ((ULONG64) VirtualAddress & 0xfffffffffffff000);

  return MmUpdatePageTable (Pml4Page->GuestAddress, 4, VirtualAddress, PhysicalAddress, bLargePage);
}


MmCreateMapping聲明兩個變量後,調用了MmFindPageByPA。


1.5.1 調用MmFindPageByPA ——獲得PML4頁表在OS中的線性地址

static NTSTATUS NTAPI MmFindPageByPA (
  PHYSICAL_ADDRESS PhysicalAddress,
  PALLOCATED_PAGE * pAllocatedPage
)
{
  PALLOCATED_PAGE AllocatedPage;
  KIRQL OldIrql;

  if (!pAllocatedPage)
    return STATUS_INVALID_PARAMETER;

  KeAcquireSpinLock (&g_PageTableListLock, &OldIrql);

  PhysicalAddress.QuadPart = PhysicalAddress.QuadPart & 0x000ffffffffff000;

  AllocatedPage = (PALLOCATED_PAGE) g_PageTableList.Flink;
  while (AllocatedPage != (PALLOCATED_PAGE) & g_PageTableList) {
    AllocatedPage = CONTAINING_RECORD (AllocatedPage, ALLOCATED_PAGE, le);

    if (AllocatedPage->PhysicalAddress.QuadPart == PhysicalAddress.QuadPart) {
      *pAllocatedPage = AllocatedPage;
      KeReleaseSpinLock (&g_PageTableListLock, OldIrql);
      return STATUS_SUCCESS;
    }

    AllocatedPage = (PALLOCATED_PAGE) AllocatedPage->le.Flink;
  }

  KeReleaseSpinLock (&g_PageTableListLock, OldIrql);
  return STATUS_UNSUCCESSFUL;
}

1.5.2 return MmUpdatePageTable (Pml4Page->GuestAddress, 4, VirtualAddress, PhysicalAddress, bLargePage);

這是一個遞歸函數。第二個參數取值1-4,分別代表PT PD PDP PML4。宏定義SET_PCD_BIT針對的是大頁映射。


首先根據虛擬地址算出當前頁表項的偏移

PageTableOffset = (((ULONG64) VirtualAddress & (((ULONG64) 1) << (12 + PageTableLevel * 9))
                      - 1) >> (12 + ((ULONG64) PageTableLevel - 1) * 9));

若參數爲1(PTE)時,修改頁表項,遞歸結束。

((PULONG64) PageTable)[PageTableOffset] = PhysicalAddress.QuadPart | /*P_GLOBAL | */ P_WRITABLE | P_PRESENT;

若參數不爲1時,計算下一級頁表偏移

 GlobalOffset =
    (((ULONG64) VirtualAddress & (((ULONG64) 1) << (12 + 4 * 9)) - 1) >> (12 + ((ULONG64) PageTableLevel - 2) * 9));
  LowerPageTablePA.QuadPart = ((PULONG64) PageTable)[PageTableOffset] & 0x000ffffffffff000;
  LowerPageTableHostVA = GlobalOffset * 8 + g_PageTableBases[PageTableLevel - 2];


最後檢查LowerPageTablePA項(本級頁表項所存儲的物理頁號)。如果是空,則說明本級頁表對應的下一級頁表尚未創建。先試圖調用MmFindPageByHostVA函數進行查找,若找不到,則開闢內存創建下一級頁表。

  if (!LowerPageTablePA.QuadPart) {
<span style="white-space:pre">	</span>...
  }

之後,調用MmCreateMapping函數,創建映射關係。

Status = MmCreateMapping (LowerPageTablePA, LowerPageTableHostVA, FALSE);

1.6 此時回頭一看,MmInitManager()已經運行完畢了。接下來DriverEntry運行至:

Status = MmInitIdentityPageTable ();
Identity Page Table是用於對將來某時刻虛擬機環境禁用分頁模式的支持。Identity Page Table是用於模擬Guest中未開啓分頁模式的效果。CPU發出的地址直接視爲PA。


1.7 構建Identity Page Table之後,BluePill要調用MmMapGuestKernelPages()函數映射操作系統整個內核空間到私有頁表上。
具體流程如下:遍歷PML4高256項(系統內核空間),若發現某個PML4項正被使用,則調用MmWalkGuestPageTable()函數對其所指向的PDP頁表進行進一步的遍歷。該函數掛載Windows內核空間各頁到BluePill私有頁表。

細節:以後有空吧


1.8 私有頁表的分配內存

MmAllocatePages() 分配池類型內存

MmAllocateContiguousPages() 分配物理地址連續的內存區域~要求處理器緩存該內存區域

MmAllocateCojntiguousPaegesSpecifyCache() 分配物理地址連續的內存區域~要求處理器使用指定的緩存策略


1.9 BluePill內存系統的關閉

MmShutdownManager()






發佈了49 篇原創文章 · 獲贊 4 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章