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()