Bitdefender Hypervisor Memory Introspection
vecore.c File Reference

Handles the introspection part of the VE agent injection and handling. More...

#include "vecore.h"
#include "winagent.h"
#include "alerts.h"
#include "crc32.h"
#include "decoder.h"
#include "hook.h"
#include "kernvm.h"
#include "loader.h"
#include "memcloak.h"
#include "winagent_ve_x64.h"
#include "winapi.h"
#include "winpe.h"
#include "winpower.h"
#include "ptfilter.h"

Go to the source code of this file.

Macros

#define VE_DRV_NAME   u"#VE Agent"
 
#define VE_DRV_PATH   VE_DRV_NAME
 
#define VE_TRAMPO_SIZE   24
 
#define MAX_INSTRUX_VE_KERNEL_OBJECTS_COUNT   1024
 

Functions

static INTSTATUS IntVeFindKernelKvaShadowAndKernelExit (QWORD *KiKernelExit)
 Searches for the KvaShadow and KiKernelExit. More...
 
static INTSTATUS IntVeSetVeInfoPage (DWORD CpuNumber, QWORD VeInfoPageGva)
 Sets the VE info page on the provided VCPU. More...
 
static void IntVeResetState (void)
 Reset the VE state. More...
 
static void IntVeDumpVeInfoPage (DWORD CpuNumber)
 Dump the VE info page on the provided VCPU. More...
 
INTSTATUS IntVeHandleEPTViolationInProtectedView (IG_EPT_ACCESS AccessType, INTRO_ACTION *Action)
 Handle an EPT violation inside the protected EPT view. More...
 
static INTSTATUS IntVeHandleAccess (void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
 Handle accesses inside the VE agent (outside the protected view). More...
 
static INTSTATUS IntVeHandleSwap (void *Context, QWORD VirtualAddress, QWORD OldEntry, QWORD NewEntry, QWORD OldPageSize, QWORD NewPageSize)
 Handle VE agent page remapping. More...
 
static INTSTATUS IntVeHookVeDriver (void)
 Protect the VE driver inside the untrusted EPT view. More...
 
static INTSTATUS IntVeEnableDisableDriverAccessInProtectedView (BOOLEAN Enable)
 Protect the VE driver inside the protected EPT view. More...
 
static INTSTATUS IntVeLockDriver (void)
 Monitors all the VE agent pages against translation modifications. More...
 
static INTSTATUS IntVeUnlockDriver (void)
 Removes the translation hook from the VE agent. More...
 
static INTSTATUS IntVeDeployLoader (QWORD GuestVirtualAddress, DWORD AgentTag, void *Context)
 Called once the VE loaded has been injected. More...
 
static INTSTATUS IntVeCompleteLoader (QWORD GuestVirtualAddress, DWORD ErrorCode, DWORD AgentTag, void *Context)
 Called once the VE loader has finished execution. More...
 
static INTSTATUS IntVeDeployUnloader (QWORD GuestVirtualAddress, DWORD AgentTag, void *Context)
 Called after the boot driver (VE unloader) has been successfully injected. More...
 
static INTSTATUS IntVePatchVeCoreJmpTrampoline (QWORD Address, QWORD Target)
 Patches the VE trampoline inside the guest VE handler. More...
 
static INTSTATUS IntVePatchVeCoreJmpKiKernelExit (QWORD VeCoreJmpKiKernelExitAddress)
 This function patches the VE code responsible of jumping to the KiKernelExit routine. More...
 
static QWORD IntVeDeliverDriverForLoad (QWORD GuestVirtualAddress, DWORD MaxSize, void *Context)
 Initializes the VE driver agent inside the guest. More...
 
static INTSTATUS IntVeUnhookVeAgent (void)
 Removes the hooks placed on the VE agent. More...
 
static QWORD IntVeDeliverDriverForUnload (QWORD GuestVirtualAddress, DWORD MaxSize, void *Context)
 Handles the unloading of the VE agent. More...
 
static INTSTATUS IntVeCompleteUnloader (QWORD GuestVirtualAddress, DWORD ErrorCode, DWORD AgentTag, void *Context)
 Finishes the unload procedure, by resetting the state and the power-state spin wait. More...
 
INTSTATUS IntVeHandleHypercall (DWORD CpuNumber)
 Handles hyper calls initiated by the VE agent. More...
 
INTSTATUS IntVeDeployAgent (void)
 Inject the VE agent inside the guest. More...
 
INTSTATUS IntVeRemoveAgent (DWORD AgOpts)
 Removes the VE agent from guest memory. More...
 
QWORD IntVeGetDriverAddress (void)
 Gets the guest virtual address of the VE agent. More...
 
BOOLEAN IntVeIsPtrInAgent (QWORD Ptr, THS_PTR_TYPE Type)
 Check if an address points inside the VE agent. More...
 
BOOLEAN IntVeIsCurrentRipInAgent (void)
 Check if the current RIP points inside the VE agent. More...
 
INTSTATUS IntVeInit (void)
 Initialize the VE system. More...
 
INTSTATUS IntVeUnInit (void)
 Uninit the VE system. More...
 
void IntVeDumpVeInfoPages (void)
 Dumps the VE info pages on all VCPUs. More...
 
void IntVeDumpStats (void)
 Dump VE statistics. More...
 
void IntVeHandleGuestResumeFromSleep (void)
 Simply set the VeAgentWaiting variable to true if VE is enabled. More...
 
INTSTATUS IntVeUpdateCacheEntry (QWORD Address, BOOLEAN Monitored)
 Update an address inside the VE cache. More...
 
BOOLEAN IntVeIsAgentRemapped (QWORD Gla)
 Checks if a given guest linear address belongs to the VE agent. More...
 

Variables

static KERNEL_DRIVER gVeModule
 Indicate the #VE agent state. More...
 
BOOLEAN gVePendingDeploy
 
BOOLEAN gVeDeployed
 
BOOLEAN gVePendingUnload
 
BOOLEAN gVeVeInitialized
 
BOOLEAN gVeLoadFailed
 
QWORD gVeDriverAddress
 The guest virtual address where the driver was deployed. More...
 
DWORD gVeDriverSize
 The driver virtual size. More...
 
DWORD gVeDriverEntryPoint
 The driver entry point (RVA). More...
 
PBYTE gVeLoadedImageBuffer
 Contains the loaded #VE module, relocated and such. More...
 
QWORD gVeInfoPages
 Guest virtual address where the VE info pages are located. More...
 
void * gVeHookObject
 Hook object containing VE agent protection in the untrusted EPT. More...
 
void * gVeHandlerCloak
 Cloak handle used to hide the guest VE handler. More...
 
void ** gVeDriverPages
 Swap hook handle for each VE driver page. More...
 
QWORD gVeMaxGpa
 Maximum GPA accessible to the guest. More...
 
QWORD gVeCache
 The VE page-table cache. More...
 
struct {
   VE_CACHE_LINE *   Page
 Mapped page inside Introspection virtual address space. More...
 
   DWORD   Indexes [VE_CACHE_BUCKETS]
 Array of used indexes inside the cache page. More...
 
gVeCachePages [VE_CACHE_LINES]
 

Detailed Description

Handles the introspection part of the VE agent injection and handling.

This module deals with VE agent injection and handling. The main role is to inject and remove the agent from the guest memory. VE works by marking all hooked page-table pages as convertible - this means that instead of an EPT violation, the CPU would generate an in-guest exception when triggering an EPT fault on them. The in-guest exception is delivered much faster (no need for extensive state save/restore like VM exit/VM entry). In addition, the in-guest agent runs in the context of the faulting process, so there is no need to do slow memory map/unmap operations, as the memory can be directly accessed. Emulating page-table accesses is also very fast, since we don't have to map/unmap memory. The main logical steps done by this module are:

  1. On initialization, determine whether the HV supports VE and VMFUNC; If support is not found, VE will not be used.
  2. Create a new, alternate EPT, called the protected EPT, where the agent will run when a VE takes place;
  3. Inject the VE agent, when needed;
  4. Remove the VE agent, when needed. Additional details can be found in each individual function:
  1. For agent injection & initialization, please check out IntVeDeliverDriverForLoad;
  2. For agent removal, please check out IntVeDeliverDriverForUnload.

Important design decisions

  1. The VE handler is hooked using an inline code hook inside the OS KiVirtualizatonExceptionHandler. The reason behind this decision is PatchGuard: normally hooking the VE handler inside the IDT would trigger PatchGuard bug-checks. In order to hide the hook, complicated steps must be taken:
  • Relocate each IDT inside a new page, where the VE handler will be hooked;
  • Read-hook the original IDT, in order to return the unmodified contents to PatchGuard;
  • Intercept SIDT, in order to show PatchGuard the old IDT;
  • Read-hooking the active IDT (pointed by IDTR) is impossible, as each interrupt delivery will trigger a fault.
  1. We rely on the OS memory-manager to maintain non-paged memory pages accessed and/or dirty. The reason behind this is that during the delivery of another fault, a VE may be generated, which will make the VE handler execute with potentially wrong GS base or even user-mode stack (in case of SYSCALLs). The correct approach is to make the VE handler use IST (like NMI or DF handlers), but again, this is impossible to do because the TSS would also have to be modified, and the modifications hidden from potential PatchGuard reads. Another approach would be to enforce A/D bits always present using the EPT, but this would involve multiple hooks to be placed on memory pages which are otherwise not monitored:
  • The Processor Control Regions of each VCPU;
  • The memory pages containing entry-points for every IDT entry and the SYSCALL;
  • The regular kernel stack;
  • Every IST kernel stack;
  • The IDTs, as it could potentially be accessed during the delivery of another event;
  • The GDTs, as it could potentially be accessed during segmentation related operations;
  • The TSSs, as it could potentially be accessed during an IST lookup. In addition, there are two cases where the A/D must be enforced: whenever the a PTE is modified, and during initialization. However, in both of these cases, enforcing A/D bit without the OS knowing/wanting may lead to other problems (such as memory management bug checks). Instead, we simply leverage the OS itself. Since Windows does not clear the A/D bits for non-paged areas, and since an attacker cannot do this from user-mode, we consider that this is not an avenue for normal privilege escalation, as an A/D VE can't take place in sensitive points during normal execution. These pages are always mapped A/D and remain so. The best approach would be to contact Microsoft and nicely ask them to make their VE handler right.
  1. There are two EPT views: the untrusted EPT view (in which the guest normally runs) and the protected EPT view (in which the agent runs). When a VE takes place, the agent trampoline code will use the VMFUNC instruction to switch into the protected view. When leaving the agent, VMFUNC is used again to switch into the previous EPT view. These two EPT views have different access rights:
  • Inside the untrusted EPT view, all normal HVI protections are set; in addition, the VE agent is protected: all pages belonging to the agent, except for the trampoline page, are marked no-access, so the guest cannot read, write or execute agent pages;
  • Inside the trusted EPT view, the agent has normal restrictions (data pages read/write, code pages read/execute), but the rest of the guest is mapped read/write only - no execute rights means no code can be arbitrary executed inside the agent;
  • The agent pages can be occasionally remapped by the OS; due to this, we handle internally such remappings by moving the contents of the old VE agent page into the new VE agent page; we can't let the OS do this, as a VE can be triggered during normal remapping operation, which could modify the remapped page itself, thus out-dating the freshly copied content.
  1. The VE optimization works only on Windows x64. It seems that the largest page-table related performance overhead is generated on 64 bit Windows. This can be explained by the larger virtual-address spaces and higher number of page-tables.
  2. VE agent initialization is done entirely by Introcore. There are no in-guest initialization steps, so from the guest perspective, the agent appears and disappears atomically. This removes potential security implications such as guest tampering with the agent before initialization is finished.

Definition in file vecore.c.

Macro Definition Documentation

◆ MAX_INSTRUX_VE_KERNEL_OBJECTS_COUNT

#define MAX_INSTRUX_VE_KERNEL_OBJECTS_COUNT   1024

◆ VE_DRV_NAME

#define VE_DRV_NAME   u"#VE Agent"

Definition at line 93 of file vecore.c.

Referenced by IntVeInit().

◆ VE_DRV_PATH

#define VE_DRV_PATH   VE_DRV_NAME

Definition at line 94 of file vecore.c.

Referenced by IntVeInit().

◆ VE_TRAMPO_SIZE

#define VE_TRAMPO_SIZE   24

Definition at line 141 of file vecore.c.

Referenced by IntVePatchVeCoreJmpKiKernelExit(), and IntVePatchVeCoreJmpTrampoline().

Function Documentation

◆ IntVeCompleteLoader()

static INTSTATUS IntVeCompleteLoader ( QWORD  GuestVirtualAddress,
DWORD  ErrorCode,
DWORD  AgentTag,
void *  Context 
)
static

Called once the VE loader has finished execution.

If VE agent injection failed, it will try to inject the PT filter, if the option is enabled. If VE agent injection succeeded, it will enable VE filtering, by marking all the page-table pages as convertible inside EPT. Once the VCPUs are resumed, no more EPT violations will be triggered on page-tables, instead virtualization exceptions will be delivered to the VE agent inside the guest.

Parameters
[in]GuestVirtualAddressUnused.
[in]ErrorCodeInjection error code. Must be 0 on success.
[in]AgentTagUnused.
[in]ContextUnused.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1102 of file vecore.c.

Referenced by IntVeDeployAgent().

◆ IntVeCompleteUnloader()

static INTSTATUS IntVeCompleteUnloader ( QWORD  GuestVirtualAddress,
DWORD  ErrorCode,
DWORD  AgentTag,
void *  Context 
)
static

Finishes the unload procedure, by resetting the state and the power-state spin wait.

Parameters
[in]GuestVirtualAddressUnused.
[in]ErrorCodeUnused.
[in]AgentTagUnused.
[in]ContextUnused.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1946 of file vecore.c.

Referenced by IntVeRemoveAgent().

◆ IntVeDeliverDriverForLoad()

static QWORD IntVeDeliverDriverForLoad ( QWORD  GuestVirtualAddress,
DWORD  MaxSize,
void *  Context 
)
static

Initializes the VE driver agent inside the guest.

This function is responsibility of initializing the VE driver agent inside the guest space. Initialization is done entirely by this function: no initialization steps are carried by the OS, making the loading operation as secure as possible. The steps taken by this initialization function are the following:

  1. Load & write the VE driver image inside the guest space;
  2. Patch the VeCoreProtectedEptIndex - as the protected EPT index cannot be hard-coded, we need to dynamically patch it inside the VE driver at load time. This can be whatever value the HV returns when creating the protected EPT.
  3. Similar for the VeCoreUntrustedEptIndex. This cannot be hard-coded, the untrusted EPT index could be whatever the HV chose to.
  4. Patch the VeCoreSelfMapIndex. This global variable contains the self map index (entry index inside the PML4 which maps itself).
  5. Patch the VeCoreMonitoredPtBits. This global variable tells the VE agent which bits inside the page-table should generate an exit on, should they modify. This can be dynamically modified.
  6. Patch VeCoreJumpToKiKernelExit. This is needed in order to safely leave kernel space if KPTI is on.
  7. Hook the guest VE handler, and make it point to our handler.
  8. Initialize the VCPU map. This is used by the VE agent in order to determine the VCPU index a VE was generated on. Note that we cannot use CPUID, since it generates a VM exit, which would cancer most of the VE optimization.
  9. Protect the VE agent inside the untrusted EPT view.
  10. Protect the VE agent inside the protected EPT view.
  11. Place a swap hook on each page of the agent.
  12. Initialize the VE info pages. Once we resume the VCPUs, the guest can generate virtualization exceptions. However, we make pages convertible only after the loader has finished, in order to make sure the initialization succeeded. NOTE: Any failure in this function will cause the VE agent to be removed, and VE filtering to be disabled.
Parameters
[in]GuestVirtualAddressGuest virtual address where the VE agent is deployed.
[in]MaxSizeUnused.
[in]ContextUnused.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1336 of file vecore.c.

Referenced by IntVeDeployAgent().

◆ IntVeDeliverDriverForUnload()

static QWORD IntVeDeliverDriverForUnload ( QWORD  GuestVirtualAddress,
DWORD  MaxSize,
void *  Context 
)
static

Handles the unloading of the VE agent.

This function is invoked via the boot driver, when we wish to unload the VE agent. This function first checks if the unloading can be carried safely (ie, there are no threads with RIPs pointing inside the agent); if it is safe to unload it, the unload will proceed; otherwise, the in guest boot driver will spin for a while before retrying to unload the VE agent.

Parameters
[in]GuestVirtualAddressUnused.
[in]MaxSizeUnused.
[in]ContextUnused.
Return values
0if the unload can proceed, 1 otherwise.

Definition at line 1870 of file vecore.c.

Referenced by IntVeRemoveAgent().

◆ IntVeDeployAgent()

INTSTATUS IntVeDeployAgent ( void  )

Inject the VE agent inside the guest.

NOTE: If this function returns success, it does not mean that the VE agent has been successfully injected. It just means that it has been successfully scheduled for injection. Failures may still happen during the injection itself.

Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZEDIf the VE system has not been initialized.
INT_STATUS_ALREADY_INITIALIZED_HINTIf the VE agent has already been injected.
INT_STATUS_NOT_NEEDED_HINTIf the OS is not 64 bit Windows.

Definition at line 2063 of file vecore.c.

Referenced by IntGuestPreReturnCallback(), IntGuestUpdateCoreOptions(), and IntWinGuestFinishInit().

◆ IntVeDeployLoader()

static INTSTATUS IntVeDeployLoader ( QWORD  GuestVirtualAddress,
DWORD  AgentTag,
void *  Context 
)
static

Called once the VE loaded has been injected.

Parameters
[in]GuestVirtualAddressUnused.
[in]AgentTagUnused.
[in]ContextUnused.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1076 of file vecore.c.

Referenced by IntVeDeployAgent().

◆ IntVeDeployUnloader()

static INTSTATUS IntVeDeployUnloader ( QWORD  GuestVirtualAddress,
DWORD  AgentTag,
void *  Context 
)
static

Called after the boot driver (VE unloader) has been successfully injected.

Parameters
[in]GuestVirtualAddressUnused.
[in]AgentTagUnused.
[in]ContextUnused.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1174 of file vecore.c.

Referenced by IntVeRemoveAgent().

◆ IntVeDumpStats()

void IntVeDumpStats ( void  )

Dump VE statistics.

Definition at line 2719 of file vecore.c.

Referenced by IntHandleTimer().

◆ IntVeDumpVeInfoPage()

static void IntVeDumpVeInfoPage ( DWORD  CpuNumber)
static

Dump the VE info page on the provided VCPU.

Parameters
[in]CpuNumberThe VCPU number to dump the VE info page from.

Definition at line 146 of file vecore.c.

Referenced by IntVeDumpVeInfoPages(), and IntVeHandleHypercall().

◆ IntVeDumpVeInfoPages()

void IntVeDumpVeInfoPages ( void  )

Dumps the VE info pages on all VCPUs.

Definition at line 2698 of file vecore.c.

Referenced by IntGuestPrepareUninit(), IntVeHandleEPTViolationInProtectedView(), IntVeHandleHypercall(), and IntVeHandleSwap().

◆ IntVeEnableDisableDriverAccessInProtectedView()

static INTSTATUS IntVeEnableDisableDriverAccessInProtectedView ( BOOLEAN  Enable)
static

Protect the VE driver inside the protected EPT view.

This function protects the VE driver inside the protected EPT view. This is needed, in order to remove access rights which are not needed. This function removes write access from all read-only sections and removes execute access from all data sections. Basically, it makes the EPT access rights reflect the page-tables access rights.

Parameters
[in]EnableIf true, enables protection. Otherwise, it disables protection.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_NEEDED_HINTIf the VE image was not loaded.

Definition at line 852 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad(), and IntVeUnhookVeAgent().

◆ IntVeFindKernelKvaShadowAndKernelExit()

static INTSTATUS IntVeFindKernelKvaShadowAndKernelExit ( QWORD KiKernelExit)
static

Searches for the KvaShadow and KiKernelExit.

This function searches the NT image for the KiKernelExit function and the KvaShadow variable.

Parameters
[in,out]KiKernelExitThe address of the KiKernelExit function inside guest space.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 2275 of file vecore.c.

Referenced by IntVePatchVeCoreJmpKiKernelExit().

◆ IntVeGetDriverAddress()

QWORD IntVeGetDriverAddress ( void  )

Gets the guest virtual address of the VE agent.

Return values
Theguest virtual address where the VE agent was loaded.

Definition at line 2200 of file vecore.c.

Referenced by IntWinAgentHandleDriverVmcall().

◆ IntVeHandleAccess()

static INTSTATUS IntVeHandleAccess ( void *  Context,
void *  Hook,
QWORD  Address,
INTRO_ACTION Action 
)
static

Handle accesses inside the VE agent (outside the protected view).

This function handles all invalid accesses inside the VE agent. By default, we block them all.

Parameters
[in]ContextUnused.
[in]HookThe GPA hook handle. Unused.
[in]AddressThe accessed address.
[in]ActionDesired action. By default, this is introGuestNotAllowed.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 398 of file vecore.c.

Referenced by IntVeHookVeDriver().

◆ IntVeHandleEPTViolationInProtectedView()

INTSTATUS IntVeHandleEPTViolationInProtectedView ( IG_EPT_ACCESS  AccessType,
INTRO_ACTION Action 
)

Handle an EPT violation inside the protected EPT view.

This function is called from the main EPT violation handler whenever a violation takes place inside the protected EPT view. We only dump as much info as we can & we generate an alert, after which we re-enter the guest. Normally, this will lead to a hang, as the guest would keep generating such EPT violations, but this is expected, as only a bug or an attack may end up generating such a violation.

Parameters
[in]AccessTypeAccess type. Can be a combination of IG_EPT_HOOK_READ, IG_EPT_HOOK_WRITE and IG_EPT_HOOK_EXECUTE.
[out]ActionDesired action.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.

Definition at line 234 of file vecore.c.

Referenced by IntHandleEptViolation().

◆ IntVeHandleGuestResumeFromSleep()

void IntVeHandleGuestResumeFromSleep ( void  )

Simply set the VeAgentWaiting variable to true if VE is enabled.

Definition at line 2787 of file vecore.c.

Referenced by IntNotifyGuestPowerStateChange().

◆ IntVeHandleHypercall()

INTSTATUS IntVeHandleHypercall ( DWORD  CpuNumber)

Handles hyper calls initiated by the VE agent.

This function handles VE agent VMCALLs. Only a few are defined:

  1. NOP - does nothing, just causes an exit.
  2. BREAK - break into debugger; initiates when the VE agent encounters an exceptional condition that prevents it from safely continuing execution.
  3. TRACE - logs some information.
  4. RAISE EPT - this is the main hyper call, used to raise an EPT violation from a VE that took place inside the guest.
Parameters
[in]CpuNumberGuest VCPU number on which the VMCALL was issued.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_SUPPORTEDIf an unsupported VMCALL number is raised.
INT_STATUS_RAISE_EPTIf an EPT must be raised. This will cause the VMCALL handler to invoke the EPT violation handler, as if a regular memory access took place.

Definition at line 1985 of file vecore.c.

Referenced by IntHandleIntroCall().

◆ IntVeHandleSwap()

static INTSTATUS IntVeHandleSwap ( void *  Context,
QWORD  VirtualAddress,
QWORD  OldEntry,
QWORD  NewEntry,
QWORD  OldPageSize,
QWORD  NewPageSize 
)
static

Handle VE agent page remapping.

This function handles remapping operations that take place on the agent memory. This is a very sensitive operation, as the guest OS may have already copied the contents of the old page into the new page, but by triggering a VE inside the guest, the contents of that page may have modified. Therefore, we must make sure that we do another copy of that page, with the VCPUs paused (in order to make sure no other VCPU touches that page), and then write the new page-table entry ourselves. In addition, this function takes care of moving the EPT page protection from the old page to the new page (in both the untrusted and protected EPT views), and it handles remapping other VE cache pages and of the VE info pages as well.

Parameters
[in]ContextUnused.
[in]VirtualAddressThe swapped guest virtual address, belonging to the VE agent.
[in]OldEntryOld page-table entry.
[in]NewEntryNew page-table entry.
[in]OldPageSizeOld page size. Unused.
[in]NewPageSizeNew page size. Unused.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 546 of file vecore.c.

Referenced by IntVeLockDriver().

◆ IntVeHookVeDriver()

static INTSTATUS IntVeHookVeDriver ( void  )
static

Protect the VE driver inside the untrusted EPT view.

This function will hook the VE driver inside the regular, default, untrusted EPT view. All sections will be hooked against reads & writes, and all the sections, except for the VMFUNC trampoline (section VESTUB) will be hooked against executions as well.

Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERif the VE image was not loaded.

Definition at line 725 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad().

◆ IntVeInit()

INTSTATUS IntVeInit ( void  )

Initialize the VE system.

This function initializes the VE system. In order to do so, it makes sure the VE is supported on the system:

  1. VE must be supported;
  2. VMFUNC must be supported;
  3. At most VE_MAX_CPUS VCPUs must be assigned to the guest;
  4. The Glue must contain all the VE related functions; In order to carry on the initialization, this function:
  1. It creates a new EPT - the protected EPT;
  2. It gets the maximum guest physical address accessible by the guest;
  3. Makes the entire guest space non-executable inside the protected EPT view;
  4. It creates the VE module entry.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_NEEDED_HINTIf VE is not supported on the system.
INT_STATUS_INVALID_INTERNAL_STATEIf there are GPA hooks set.

Definition at line 2493 of file vecore.c.

Referenced by IntWinGuestNew().

◆ IntVeIsAgentRemapped()

BOOLEAN IntVeIsAgentRemapped ( QWORD  Gla)

Checks if a given guest linear address belongs to the VE agent.

The accessed Gla is in fact the address of a page-table entry. The algorithm in this function converts the page-table entry address to the address of the page it maps, by shifting left each self-map index entry.

Parameters
[in]GlaThe guest linear address to check.
Return values
Trueif the Gla belongs to the VE agent, false otherwise.

Definition at line 2899 of file vecore.c.

Referenced by IntDispatchVeAsEpt().

◆ IntVeIsCurrentRipInAgent()

BOOLEAN IntVeIsCurrentRipInAgent ( void  )

Check if the current RIP points inside the VE agent.

This only checks of the current RIP points inside the agent. It doesn't care about the VE handler trampoline or cloaked code, as we only call this to check if a VMCALL was initiated inside the VE agent.

Return values
Trueif the current RIP points inside the agent, false otherwise.

Definition at line 2253 of file vecore.c.

Referenced by IntHandleIntroCall().

◆ IntVeIsPtrInAgent()

BOOLEAN IntVeIsPtrInAgent ( QWORD  Ptr,
THS_PTR_TYPE  Type 
)

Check if an address points inside the VE agent.

Parameters
[in]PtrThe pointer to be checked.
[in]TypePointer type: live RIP or stack value.
Return values
Trueif the pointer points inside any of the VE agent components, false otherwise.

Definition at line 2214 of file vecore.c.

Referenced by IntThrSafeIsLiveRIPInIntro(), and IntThrSafeIsStackPtrInIntro().

◆ IntVeLockDriver()

static INTSTATUS IntVeLockDriver ( void  )
static

Monitors all the VE agent pages against translation modifications.

This function places a swap hook on each page belonging to the VE agent. This is needed in order to copy the contents of the swapped pages when their translation is modified, and to move the VE info pages, if they are swapped. Take a look at IntVeHandleSwap for more info.

Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails.

Definition at line 929 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad().

◆ IntVePatchVeCoreJmpKiKernelExit()

static INTSTATUS IntVePatchVeCoreJmpKiKernelExit ( QWORD  VeCoreJmpKiKernelExitAddress)
static

This function patches the VE code responsible of jumping to the KiKernelExit routine.

Depending on the mode of operation (KPTI on/off), we need to invoke the original KiKernelExit routine to safely leave kernel space, if a VE originated in user space. Therefore, this code makes sure to modify the VE code in such a way that it safely returns into user-space, by using the OS function. NOTE: The KiKernelExit is responsibility of loading the user-mode Cr3 on returns from kernel. NOTE: Since we place a code hook on the OS VE handler, the kernel-mode Cr3 is loaded by the OS. The VE agent has nothing to do with loading the kernel or user Cr3 on transitions, as it leaves this responsibility entirely to the OS.

Parameters
[in]VeCoreJmpKiKernelExitAddressThe address of the VeCoreJumpToKiKernelExit function inside the agent.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_NEEDED_HINTIf KPTI is not enabled, and we can safely return to user-space ourselves.

Definition at line 1272 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad().

◆ IntVePatchVeCoreJmpTrampoline()

static INTSTATUS IntVePatchVeCoreJmpTrampoline ( QWORD  Address,
QWORD  Target 
)
static

Patches the VE trampoline inside the guest VE handler.

This function overwrites the VE handler with the following code sequence: CALL next LFENCE next: MOV dword [rsp], new_handler_low MOV dword [rsp + 4], new_handler_high RET This function is not vulnerable to Spectre, as it is retpoline-like.

Parameters
[in]AddressGuest virtual address of the OS VE handler.
[in]TargetGuest virtual address of the new VE handler.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1203 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad(), and IntVePatchVeCoreJmpKiKernelExit().

◆ IntVeRemoveAgent()

INTSTATUS IntVeRemoveAgent ( DWORD  AgOpts)

Removes the VE agent from guest memory.

NOTE: If this function returns success, it does not mean that the VE agent has been successfully removed from the guest memory; it simply means it has been successfully scheduled for removal.

Parameters
[in]AgOptsAgent options.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_NEEDED_HINTIf VE has not been initialized.

Definition at line 2116 of file vecore.c.

Referenced by IntGuestUpdateCoreOptions(), IntVeDeliverDriverForLoad(), and IntWinPowHandleEventCommon().

◆ IntVeResetState()

static void IntVeResetState ( void  )
static

Reset the VE state.

Definition at line 1931 of file vecore.c.

Referenced by IntVeCompleteLoader(), IntVeCompleteUnloader(), and IntVeRemoveAgent().

◆ IntVeSetVeInfoPage()

static INTSTATUS IntVeSetVeInfoPage ( DWORD  CpuNumber,
QWORD  VeInfoPageGva 
)
static

Sets the VE info page on the provided VCPU.

This function registers the VE info page on the indicated VCPU. It also keeps a mapped cache of each VE info page, as it needs to be accessed by Introcore when the VE agent initiates a hyper-call. If a VE info page has been already registered, it will be overwritten.

Parameters
[in]CpuNumberThe VCPU number on which to set the VE info page.
[in]VeInfoPageGvaGuest virtual address of the VE info page.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1005 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad(), IntVeHandleSwap(), and IntVeUnhookVeAgent().

◆ IntVeUnhookVeAgent()

static INTSTATUS IntVeUnhookVeAgent ( void  )
static

Removes the hooks placed on the VE agent.

This function will remove:

  1. The VE info pages; no more VEs can be generated;
  2. The VE handler hook cloak;
  3. The protection set on the agent inside the untrusted EPT;
  4. The protection set on the agent inside the protected EPT;
  5. The swap hooks placed on the agent pages
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1789 of file vecore.c.

Referenced by IntVeDeliverDriverForUnload(), and IntVeRemoveAgent().

◆ IntVeUnInit()

INTSTATUS IntVeUnInit ( void  )

Uninit the VE system.

This function uninits the VE system. It will destroy the protected EPT. Note that this function does not remove the VE agent from guest memory, it simply uninitializes the VE system. This function should be called only during Introcore uninit.

Definition at line 2654 of file vecore.c.

Referenced by IntGuestUninit().

◆ IntVeUnlockDriver()

static INTSTATUS IntVeUnlockDriver ( void  )
static

Removes the translation hook from the VE agent.

Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZED_HINTIf the swap hook has not been previously set.

Definition at line 972 of file vecore.c.

Referenced by IntVeUnhookVeAgent().

◆ IntVeUpdateCacheEntry()

INTSTATUS IntVeUpdateCacheEntry ( QWORD  Address,
BOOLEAN  Monitored 
)

Update an address inside the VE cache.

This function will map the cache page that should contain the entry. If the entry must be monitored (it has been hooked), it will remove it from the cache. Otherwise, it will add it to the cache. Entries which are present inside this cache are page-table entry which are not effectively monitored by Introcore. This means that writes that take place on them can be safely emulated inside the guest without issuing a VMCALL to Introcore. The Address is the address of the page-table entry, it is not a page-table address, as the cache works with entries, not pages.

Parameters
[in]AddressPage table entry address to be added/removed from the cache.
[in]MonitoredTrue if the entry must be monitored (remove it from the cache), false otherwise.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZED_HINTIf VE is not initialized/the agent is not injected.

Definition at line 2799 of file vecore.c.

Referenced by IntHookPtmSetHook(), and IntHookPtmWriteCallback().

Variable Documentation

◆ gVeCache

QWORD gVeCache

The VE page-table cache.

Definition at line 111 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad(), IntVeHandleSwap(), IntVeResetState(), and IntVeUpdateCacheEntry().

◆ gVeCachePages

struct { ... } gVeCachePages[VE_CACHE_LINES]

Describes one VE cache page.

Referenced by IntVeDeliverDriverForUnload(), IntVeHandleSwap(), and IntVeUpdateCacheEntry().

◆ gVeDeployed

◆ gVeDriverAddress

◆ gVeDriverEntryPoint

DWORD gVeDriverEntryPoint

The driver entry point (RVA).

Definition at line 103 of file vecore.c.

Referenced by IntVeInit().

◆ gVeDriverPages

void** gVeDriverPages

Swap hook handle for each VE driver page.

Definition at line 109 of file vecore.c.

Referenced by IntVeLockDriver(), and IntVeUnlockDriver().

◆ gVeDriverSize

◆ gVeHandlerCloak

void* gVeHandlerCloak

Cloak handle used to hide the guest VE handler.

Definition at line 108 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad(), IntVeIsPtrInAgent(), and IntVeUnhookVeAgent().

◆ gVeHookObject

void* gVeHookObject

Hook object containing VE agent protection in the untrusted EPT.

Definition at line 107 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad(), IntVeHookVeDriver(), and IntVeUnhookVeAgent().

◆ gVeInfoPages

QWORD gVeInfoPages

Guest virtual address where the VE info pages are located.

Definition at line 105 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad(), IntVeDeployAgent(), IntVeHandleSwap(), and IntVeResetState().

◆ gVeLoadedImageBuffer

PBYTE gVeLoadedImageBuffer

Contains the loaded #VE module, relocated and such.

Definition at line 104 of file vecore.c.

Referenced by IntVeDeliverDriverForLoad(), IntVeEnableDisableDriverAccessInProtectedView(), IntVeHookVeDriver(), IntVeUnhookVeAgent(), and IntVeUnInit().

◆ gVeLoadFailed

BOOLEAN gVeLoadFailed

Definition at line 99 of file vecore.c.

Referenced by IntVeCompleteLoader(), IntVeDeliverDriverForLoad(), and IntVeResetState().

◆ gVeMaxGpa

QWORD gVeMaxGpa

Maximum GPA accessible to the guest.

Definition at line 110 of file vecore.c.

Referenced by IntVeInit().

◆ gVeModule

KERNEL_DRIVER gVeModule
static

Indicate the #VE agent state.

Definition at line 97 of file vecore.c.

◆ gVePendingDeploy

BOOLEAN gVePendingDeploy

Definition at line 99 of file vecore.c.

Referenced by IntVeCompleteLoader(), IntVeDeployAgent(), IntVeRemoveAgent(), and IntVeResetState().

◆ gVePendingUnload

BOOLEAN gVePendingUnload

◆ gVeVeInitialized

◆ Indexes

Array of used indexes inside the cache page.

Definition at line 121 of file vecore.c.

Referenced by IntVeUpdateCacheEntry().

◆ Page

Mapped page inside Introspection virtual address space.

Definition at line 120 of file vecore.c.

Referenced by IntVeDeliverDriverForUnload(), IntVeHandleSwap(), and IntVeUpdateCacheEntry().