学习BluePill源码笔记-2

这篇博客详细探讨了BluePill操作系统中私有页表的构建初始化过程,从MmCreateMapping到MmMapGuestKernelPages映射内核空间。博主深入分析了MmFindPageByPA函数的递归实现,以及不同内存分配函数如MmAllocatePages在系统中的应用。最后提到了BluePill内存系统的关闭函数MmShutdownManager。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值