diff --git a/Docs/Building_and_Debugging.md b/Docs/Building_and_Debugging.md index 3398330..9f61dd6 100644 --- a/Docs/Building_and_Debugging.md +++ b/Docs/Building_and_Debugging.md @@ -273,7 +273,7 @@ It is recommended to configure all of them for debugging the UEFI driver. ![Building_and_Testing_VMwareWS_FullLogging.png](Resources/Building_and_Testing_VMwareWS_FullLogging.png) Here is an example output, showing that triple fault occurred. - ![Building_and_Testing_VMwareWS_FullLogging_Sample.png](Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.png) + ![Building_and_Testing_VMwareWS_FullLogging_Sample.jpg](Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.jpg) UEFI: Viewing Serial Output From the Virtual Machine @@ -356,7 +356,7 @@ VMware Workstation is the only supported virtualization platform. However, one c Not usable due to lack of nested virtualization support. -- Boches +- Bochs Not usable due to lack of UEFI support. diff --git a/Docs/Resources/Building_and_Testing_PuTTY_Exception_with_VMware.png b/Docs/Resources/Building_and_Testing_PuTTY_Exception_with_VMware.png index 144ebb9..1bd606f 100644 Binary files a/Docs/Resources/Building_and_Testing_PuTTY_Exception_with_VMware.png and b/Docs/Resources/Building_and_Testing_PuTTY_Exception_with_VMware.png differ diff --git a/Docs/Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.jpg b/Docs/Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.jpg new file mode 100644 index 0000000..318e629 Binary files /dev/null and b/Docs/Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.jpg differ diff --git a/Docs/Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.png b/Docs/Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.png deleted file mode 100644 index aee877c..0000000 Binary files a/Docs/Resources/Building_and_Testing_VMwareWS_FullLogging_Sample.png and /dev/null differ diff --git a/Docs/Resources/Readme_Showcase1.jpg b/Docs/Resources/Readme_Showcase1.jpg new file mode 100644 index 0000000..5b0edf2 Binary files /dev/null and b/Docs/Resources/Readme_Showcase1.jpg differ diff --git a/Docs/Resources/Readme_Showcase2.jpg b/Docs/Resources/Readme_Showcase2.jpg new file mode 100644 index 0000000..aa60044 Binary files /dev/null and b/Docs/Resources/Readme_Showcase2.jpg differ diff --git a/README.md b/README.md index 8fc6db7..a891575 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -What's This -============ +MiniVisor +========== This is a research hypervisor written as a UEFI and Windows driver for the educational purpose for Intel processors. @@ -9,7 +9,11 @@ This MiniVisor, as a UEFI driver, provides the ability to inspect system activit Showcase --------- -TBD. +* Loading the hypervisor from the UEFI shell. +![Readme_Showcase1.jpg](Docs/Resources/Readme_Showcase1.jpg) + +* Logging boot activities and interacting with the guest. +![Readme_Showcase2.jpg](Docs/Resources/Readme_Showcase2.jpg) Motivation @@ -17,7 +21,7 @@ Motivation The goal of this project is to share an additional learning resource for writing UEFI hypervisors with the community and researchers. -There are numerous open source hypervisors that can relatively easily study their implementations, but those that support booting operating systems as UEFI drivers are still not many. +There are numerous open source hypervisors with small and easy-to-study implementations, but those that support booting operating systems as UEFI drivers are still not many. Given the universality of UEFI systems on the AMD64 ecosystem and the unique ability to monitor, attack and protect the system throughout operating system startup on bare-metal systems, the authors believe that having the understanding and being able to author this type of hypervisors are valuable for research. @@ -47,6 +51,18 @@ Requirements for the Windows driver: See [Building and Debugging](Docs/Building_and_Debugging.md) for testing. +Advantages and Use Cases +------------------------ + +While this project does not implement any immediately useful features, UEFI-based hypervisors have multiple advantages over Windows driver-based ones and can implement unique features. + +* No need of disabling Hyper-V (Virtualization Based Security) to run the custom hypervisor +* No need of enabling the test-signing mode +* Zero direct indicator of existence of the hypervisor from Windows perspective +* Installing hooks during the early boot phase and letting PatchGuard to protect them +* Detecting bootkit and early system modification + + Limitations ------------ diff --git a/Sources/HostMain.c b/Sources/HostMain.c index d102050..f5a0f3a 100644 --- a/Sources/HostMain.c +++ b/Sources/HostMain.c @@ -331,6 +331,13 @@ HandleCrAccess ( if (currentCr0.PagingEnable != newCr0.PagingEnable) { SwitchGuestPagingMode(newCr0); + + // + // For demonstration with VMware. On bare-metal, delay because of + // this logging may lead to failure of AP start up. + // + //LOG_INFO("Processor #%d switching to the long mode", + // GuestContext->Contexts->ProcessorNumber); } break; case VMX_EXIT_QUALIFICATION_REGISTER_CR4: @@ -452,7 +459,20 @@ HandleExceptionOrNmi ( ((UINT32)GuestContext->StackBasedRegisters->Rdx == (UINT32)0xffffffff) && ((UINT32)GuestContext->StackBasedRegisters->R8 == (UINT32)-1)) { - LOG_DEBUG("KeInitAmd64SpecificState triggered #DE. Ignoring it."); + UINT64 ntoskrnlBase; + + // + // Just as an example of how to access the guest virtual address, search + // the base address of the NT kernel and print it out. + // + ntoskrnlBase = FindImageBase(GuestContext, GuestContext->VmcsBasedRegisters.Rip); + if (ntoskrnlBase != 0) + { + LOG_INFO("Found ntoskrnl.exe at %016llx", ntoskrnlBase); + } + + LOG_INFO("KeInitAmd64SpecificState triggered #DE"); + LOG_INFO("Skipping main PatchGuard initialization."); isKeInitAmd64SpecificStateCalled = TRUE; AdvanceGuestInstructionPointer(GuestContext); goto Exit; @@ -480,6 +500,12 @@ HandleInitSignal ( { UNREFERENCED_PARAMETER(GuestContext); + // + // For demonstration with VMware. On bare-metal, delay because of this logging + // may lead to failure of AP start up. + // + //LOG_INFO("Starting up processor #%d", GuestContext->Contexts->ProcessorNumber); + // // Simply put the processor into the "wait-for-SIPI" state. // diff --git a/Sources/HostUtils.c b/Sources/HostUtils.c index 1b42097..8f56c64 100644 --- a/Sources/HostUtils.c +++ b/Sources/HostUtils.c @@ -11,6 +11,7 @@ #include "Logger.h" #include "ExtendedPageTables.h" #include "Utils.h" +#include "MemoryAccess.h" /*! @brief Dumps the segment access rights value. @@ -413,3 +414,40 @@ AdjustGuestCr4 ( { return AdjustCr4(Cr4); } + +_Use_decl_annotations_ +UINT64 +FindImageBase ( + GUEST_CONTEXT* GuestContext, + UINT64 GuestVirtualAddress + ) +{ + // + // Starting with the 1MB aligned address, and search up IMAGE_DOS_SIGNATURE + // every 1MB. + // + for (UINT64 imageBase = (GuestVirtualAddress & ~(0x10000 - 1)); + /**/; + imageBase -= 0x10000) + { + BOOLEAN ok; + UINT16 contents; + MEMORY_ACCESS_ERROR_INFORMATION errorInfo; + + ok = ReadGuestVirtualAddress(GuestContext->Contexts->MemoryAccessContext, + TRUE, + imageBase, + &contents, + sizeof(contents), + &errorInfo); + if (ok == FALSE) + { + return 0; + } + + if (contents == 0x5A4D) + { + return imageBase; + } + } +} diff --git a/Sources/HostUtils.h b/Sources/HostUtils.h index 9698f96..0ffbf69 100644 --- a/Sources/HostUtils.h +++ b/Sources/HostUtils.h @@ -215,3 +215,20 @@ CR4 AdjustGuestCr4 ( _In_ CR4 Cr4 ); + +/*! + @brief Find the base address of the image to which the specified address belongs. + + @param[in] GuestContext - The pointer to the guest context. + + @param[in] GuestVirtualAddress - The guest virtual address to find its image + base. + + @return The base address of the image to which GuestVirtualAddress belongs, or + 0 on error. + */ +UINT64 +FindImageBase ( + _In_ GUEST_CONTEXT* GuestContext, + _In_ UINT64 GuestVirtualAddress + ); diff --git a/Sources/MiniVisor.c b/Sources/MiniVisor.c index 138402c..475fad0 100644 --- a/Sources/MiniVisor.c +++ b/Sources/MiniVisor.c @@ -802,6 +802,11 @@ SetupVmcs ( _sgdt(&gdtr); __sidt(&idtr); + // + // Intercept #DB. This is purely for demonstration and can be removed. + // + exceptionBitmap = (1 << DivideError); + // // VM-entry and -exit controls define how processor should operate on // VM-entry and exit. The following configurations are to achieve that: @@ -845,7 +850,9 @@ SetupVmcs ( // instructions. Those instructions are used in Windows 10. If those are // not set, attempt to execute them causes #UD, which results in a bug // check. VPID is enabled, which could lead to better performance for free - // by not flushing all TLB on every VM-exit. Finally, to enable EPT as well. + // by not flushing all TLB on every VM-exit. Finally, to enable EPT and + // unrestricted guest which are required for the UEFI hypervisor to handle + // the real-mode guest. // primaryProcBasedControls.Flags = 0; primaryProcBasedControls.UseMsrBitmaps = TRUE; @@ -915,7 +922,6 @@ SetupVmcs ( VmxWrite(VMCS_CTRL_EPT_POINTER, VpContext->EptContext.EptPointer.Flags); /* 32-Bit Control Fields */ - exceptionBitmap = (1 << DivideError); VmxWrite(VMCS_CTRL_EXCEPTION_BITMAP, exceptionBitmap); VmxWrite(VMCS_CTRL_PIN_BASED_VM_EXECUTION_CONTROLS, pinBasedControls.Flags); VmxWrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, primaryProcBasedControls.Flags); diff --git a/Sources/MiniVisor.vcxproj b/Sources/MiniVisor.vcxproj index 6332572..1181c99 100644 --- a/Sources/MiniVisor.vcxproj +++ b/Sources/MiniVisor.vcxproj @@ -56,9 +56,8 @@ $(SolutionDir)Include;$(Edk2Dir)MdePkg\Include;$(Edk2Dir)MdePkg\Include\X64 $(SolutionDir)Libs .efi - - $(ProjectName)Dxe + false @@ -91,6 +90,7 @@ copy /y $(OutDir)$(TargetName)$(TargetExt) D:\ + Copy the build output to the USB drive. Useful for compile and test interation. diff --git a/Sources/Platform/EFI/EfiLogger.h b/Sources/Platform/EFI/EfiLogger.h index ab9d32c..e90b15a 100644 --- a/Sources/Platform/EFI/EfiLogger.h +++ b/Sources/Platform/EFI/EfiLogger.h @@ -7,6 +7,7 @@ @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved. */ +#pragma once #include "../../Logger.h" /*!