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);
}
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];
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()