刺激战场
  • 1565阅读
  • 1回复

Blue Pill源代码分析(2) [复制链接]

上一主题 下一主题
离线天道酬勤
 

只看楼主 倒序阅读 使用道具 楼主  发表于: 2016-02-02
— 本帖被 天道酬勤 从 驱动保护 移动到本区(2016-05-19) —
为了在虚拟运行之后,客户机被宿主机接管,驱动程序代码还能被访问,BP使用了和windows一样的虚拟地址映射方式,以下四个常量:
#define PML4_BASE 0xFFFFF6FB7DBED000
#define PDP_BASE 0xFFFFF6FB7DA00000
#define PD_BASE  0xFFFFF6FB40000000
#define PT_BASE  0xFFFFF68000000000
和windows内核的下面四个常量对应(WRK中base/ntos/inc/amd64.h(2528)):
#define PXE_BASE          0xFFFFF6FB7DBED000UI64
#define PPE_BASE          0xFFFFF6FB7DA00000UI64
#define PDE_BASE          0xFFFFF6FB40000000UI64
#define PTE_BASE          0xFFFFF68000000000UI64
      7B40000000
这四个常量的计算方法如下:
首先选定PTE_BASE,windows选择把页表映射到虚拟地址0xFFFFF68000000000UI64的位置,则后面的PDE_BASE、PPE_BASE和PXE_BASE依次算出
PDE_BASE = ((PTE_BASE & 0x0000FFFFFFFFF000) >> 12) * 8 + PTE_BASE = 0xF68000000 * 8 + PTE_BASE = 0x7B40000000 + PTE_BASE = 0xFFFFF6FB40000000
PPE_BASE = ((PDE_BASE & 0x0000FFFFFFFFF000) >> 12) * 8 + PTE_BASE = 0xF6FB40000 * 8 + PTE_BASE = 0x7B7DA00000 + PTE_BASE = 0xFFFFF6FB7DA00000
PXE_BASE = ((PPE_BASE & 0x0000FFFFFFFFF000) >> 12) * 8 + PTE_BASE = 0xF6FB7DA00 * 8 + PTE_BASE = 0x7B7DBED000 + PTE_BASE = 0xFFFFF6FB7DBED000
这里需要注意的是IA32体系当前的虚拟地址空间是2^48B=256TB,高16位是符号扩展位,在实际计算中要去掉,因此在这里使用了掩码0x0000FFFFFFFFF000,而每个页表项占8个字节
下面这个常量指出了虚拟地址PXE_BASE页表项所在的位置
#define PXE_SELFMAP       0xFFFFF6FB7DBEDF68UI64
PXE_SELFMAP = ((PXE_BASE & 0x0000FFFFFFFFF000) >> 12) * 8 + PTE_BASE = 0xF6FB7DBED * 8 + PTE_BASE = 0x7B7DBEDF68 + PTE_BASE = 0xFFFFF6FB7DBEDF68


在MmInitManager函数中首先初始化BP维护的g_PageTableList和g_PageTableListLock,g_PageTableList将BP通过windows内核API ExAllocatePoolWithTag或者MmAllocateContiguousMemorySpecifyCache从操作系统分配出来的非分页内存链接在一起,g_PageTableListLock则是进行操作链表的同步锁。
BP维护如下所示的三种分配类型的内存页面
typedef enum
{
  PAT_DONT_FREE = 0,  //表示这个内存页面不是单独分配的,是在一大块连续内存的中间位置,不能被释放
  PAT_POOL,   //表示这个内存页面是通过调用ExAllocatePoolWithTag从非分页池中分配的第一个内存页
  PAT_CONTIGUOUS  //表示这个内存页面是通过调用MmAllocateContiguousMemorySpecifyCache分配的第一个内存页
} PAGE_ALLOCATION_TYPE;
内存页有如下标志
#define AP_PAGETABLE 1       // 表示是宿主机的页表
#define AP_PT  2
#define AP_PD  4
#define AP_PDP  8
#define AP_PML4  16
分别表示作为各级页表的内存页

接着调用ExAllocatePoolWithTag从非分页池中分配一个内存页作为PML4-table,调用MmSavePage将这块内存的宿主机虚拟地址PML4_BASE、客户机虚拟地址Pml4Page(从ExAllocatePoolWithTag返回的操作系统维护的虚拟地址)和物理地址g_PageMapBasePhysicalAddress(调用MmGetPhysicalAddress获取)映射关系分配结构体保存在g_PageTableList链表中,成功之后调用MmCreateMapping建立虚拟地址PML4_BASE和物理地址g_PageMapBasePhysicalAddress的实际映射,该函数调用MmUpdatePageTable更新页表实现这个动作。
具体代码如下:
NTSTATUS NTAPI MmInitManager (
)
{
  PVOID Pml4Page;
  NTSTATUS Status;
  PHYSICAL_ADDRESS l1, l2, l3;

  InitializeListHead (&g_PageTableList);
  KeInitializeSpinLock (&g_PageTableListLock);

  Pml4Page = ExAllocatePoolWithTag (NonPagedPool, PAGE_SIZE, ITL_TAG);
  if (!Pml4Page)
    return STATUS_INSUFFICIENT_RESOURCES;
  RtlZeroMemory (Pml4Page, PAGE_SIZE);

  g_PageMapBasePhysicalAddress = MmGetPhysicalAddress (Pml4Page);
  if (!NT_SUCCESS
      (Status =
       MmSavePage (g_PageMapBasePhysicalAddress, (PVOID) PML4_BASE, Pml4Page, PAT_POOL, 1, AP_PAGETABLE | AP_PML4))) {
    DbgPrint ("MmInitManager(): MmSavePage() failed to save PML4 page, status 0x%08X/n", Status);
    return Status;
  }

  if (!NT_SUCCESS (Status = MmCreateMapping (g_PageMapBasePhysicalAddress, (PVOID) PML4_BASE, FALSE))) {
    DbgPrint ("MmInitManager(): MmCreateMapping() failed to map PML4 page, status 0x%08X/n", Status);
    return Status;
  }

  return STATUS_SUCCESS;
}


这里面的一个重要函数就是MmUpdatePageTable,它递归更新在映射过程中所需要引入的内存页的页表映射关系。今天到这里,待续........

离线v2680267313

只看该作者 沙发  发表于: 2016-04-30
用户被禁言,该主题自动屏蔽!
快速回复
限100 字节
如果您在写长篇帖子又不马上发表,建议存为草稿
 
上一个 下一个