Blue Pill源代码分析(1)

一直都有写blog的想法,但是每次总觉得写东西很浪费时间,还不如利用这些时间多学点东西。不过每次学到东西之后,总是很容易遗忘,学到方法不假,一些零碎细节忘的很快,于是决定还是应该写点东西出来作备忘。
去年末,对Blue Pill有稍微了解一下,但终究是没有完整阅读过源代码,今天花了一天的时间把Blue Pill的源代码看了一下,总算对其中的奥妙之处有所了解。原先对VT技术不是特别了解的地方今天看了代码之后也了解,这下就不用去看IA-32开发手册了(不过有时间还是需要去求证)。
Blue Pill的源代码可以从这里下载http://bluepillproject.org/
在代码目录中dbgclient是调试时使用的客户端驱动,bpknock是演示时使用的命令行程序(主要是对CPUID指令的执行),Blue Pill核心代码在nbp-0.32-public目录下,代码结构如下:
amd64和i386分别用各自的体系内的机器指令实现底层调用界面(客户机与宿主机之间)
svm实现amd64体系内的虚拟机svm
vmx实现i386体系内的虚拟机vmx
common平台无关代码部分

Blue Pill事实上在这里是一个普通的windows内核驱动,我们从入口点开始沿着驱动的执行流分析Blue Pill。DriverEntry的代码如下(去掉调试输出代码):

NTSTATUS DriverEntry (
  PDRIVER_OBJECT DriverObject,
  PUNICODE_STRING RegistryPath
)
{
  NTSTATUS Status;

  Status = MmInitManager (); //建立四级页表结构,Blue Pill有自己的页表,但是页表的自映射虚拟地址和Windows相同
//
//
  if (!NT_SUCCESS (Status)) {
    return Status;
  }

  // We need it only for VMX
  // TODO: this should be conditionally executed only if Arch == VMX
  Status = MmInitIdentityPageTable ();  //分配页表,为了在客户机关闭CPU分页机制的时候,仍然可以访问内存
  if (!NT_SUCCESS (Status)) {  //
   
    MmShutdownManager ();
    return Status;
  }

  Status = MmMapGuestKernelPages ();  //映射当前操作系统内核态部分的页表到Blue Pill的页表中,使用的是一样的虚拟地址(不是必须,主要是为了方便),这样就可以保证使用和windows的内核API
  if (!NT_SUCCESS (Status)) {
  
    MmShutdownManager ();
    return Status;
  }
#ifdef RUN_BY_SHELLCODE
  Status = MmMapGuestPages (DriverObject, (ULONG) BYTES_TO_PAGES ((ULONG64) RegistryPath)); //映射本驱动代码到BP的虚拟地址空间中,使用当前Guest的虚拟地址
#else
  Status = MmMapGuestPages (DriverObject->DriverStart, BYTES_TO_PAGES (DriverObject->DriverSize));
#endif
  if (!NT_SUCCESS (Status)) {
   
    MmShutdownManager ();
    return Status;
  }

  _KdPrint (("NEWBLUEPILL: g_PageMapBasePhysicalAddress: 0x%p/n", g_PageMapBasePhysicalAddress));//BP第四级页表物理地址

  if (!NT_SUCCESS (Status = HvmInit ())) {//判断当前平台是否支持VT
   
    MmShutdownManager ();
    return Status;
  }

  if (!NT_SUCCESS (Status = HvmSwallowBluepill ())) {//让操作系统吞下这药丸,Swallow这动词用的不错,函数成功返回后操作系统就运行在一个客户虚拟机中
  
    MmShutdownManager ();
    return Status;
  }
#ifndef RUN_BY_SHELLCODE
  DriverObject->DriverUnload = DriverUnload;
#endif

  return STATUS_SUCCESS;
}


这个过程其实就分为两个部分:1.分配BP的页表结构,2.设置vmx/svm,让当前所有运行的逻辑CPU转到虚拟运行模式(通过内核API KeSetSystemAffinityThread将当前线程调度到

指定的逻辑CPU上),由于时间关系,就写到这里明天继续.....

你可能感兴趣的:(Blue Pill源代码分析(1))