Bitdefender Hypervisor Memory Introspection
callbacks.c File Reference
#include "callbacks.h"
#include "decoder.h"
#include "gpacache.h"
#include "hook.h"
#include "hook_cr.h"
#include "hook_dtr.h"
#include "hook_msr.h"
#include "hook_xcr.h"
#include "memtables.h"
#include "ptfilter.h"
#include "rtlpvirtualunwind.h"
#include "swapmem.h"
#include "vecore.h"
#include "winprocesshp.h"
#include "winselfmap.h"
#include "wininfinityhook.h"
#include "exceptions.h"
#include "wincmdline.h"
#include "lixcmdline.h"
#include "scan_engines.h"
#include "wintoken.h"
#include "winsecdesc.h"
#include "winsud.h"

Go to the source code of this file.

Macros

#define MAX_GLAS   32
 

Functions

static BOOLEAN IntValidateTranslation (PHOOK_GPA Hook)
 Checks if the given GPA hook points to a valid GVA hook with a correct translation. More...
 
static BOOLEAN IntValidatePageRightsEx (QWORD LinearAddress, QWORD PhysicalAddress, DWORD Access)
 Check if the access rights for the provided PhysicalAddress are up-to-date in the EPT. This function will get called oon each EPT violation. More...
 
static void IntValidatePageRights (QWORD LinearAddress, QWORD PhysicalAddress, DWORD Access)
 Check if the access rights for the provided PhysicalAddress are up-to-date in the EPT. This function will get called only if the page wasn't hooked. More...
 
static INTSTATUS IntHandleMemAccess (QWORD LinearAddress, QWORD PhysicalAddress, DWORD Length, INTRO_ACTION *Action, BOOLEAN *CallbackFound, BOOLEAN *PageHooked, BOOLEAN ProbeOnly, IG_EPT_ACCESS AccessType)
 Handle a memory access to a guest linear address. More...
 
static BOOLEAN IntHandleFetchRetryOnPageBoundary (DWORD CpuNumber)
 Handle instruction fetch at page boundary, if an EPT execute violation has been generated. More...
 
static BOOLEAN IntHandleCowOnPage (QWORD Gla, DWORD CpuNumber, BYTE AccessType)
 Handle copy-on-write on a page. More...
 
static BOOLEAN IntHandlePageBoundaryCow (QWORD Gla, DWORD AccessSize, BYTE AccessType, DWORD CpuNumber)
 Check if we have a copy-on-write condition at a page boundary. More...
 
INTSTATUS IntHandleEptViolation (void *GuestHandle, QWORD PhysicalAddress, DWORD Length, QWORD LinearAddress, DWORD CpuNumber, INTRO_ACTION *Action, IG_EPT_ACCESS AccessType)
 Handle an EPT violation. More...
 
INTSTATUS IntHandleMsrViolation (void *GuestHandle, DWORD Msr, IG_MSR_HOOK_TYPE Flags, INTRO_ACTION *Action, QWORD OriginalValue, QWORD *NewValue, DWORD CpuNumber)
 Handle a model specific register violation. More...
 
INTSTATUS IntHandleCrWrite (void *GuestHandle, DWORD Cr, DWORD CpuNumber, QWORD OldValue, QWORD NewValue, INTRO_ACTION *Action)
 Handle a control register violation. More...
 
static INTSTATUS IntDispatchPtAsEpt (void)
 Dispatch a VMCALL issued by the PT filter as an EPT violation. More...
 
static INTSTATUS IntDispatchVeAsEpt (void)
 Dispatch a VE as an EPT violation. More...
 
INTSTATUS IntHandleIntroCall (void *GuestHandle, QWORD Rip, DWORD CpuNumber)
 Handle a VMCALL issued inside the guest. More...
 
INTSTATUS IntHandleTimer (void *GuestHandle)
 Periodically called by the integrator, once every second. More...
 
INTSTATUS IntHandleXcrWrite (void *GuestHandle, DWORD CpuNumber, INTRO_ACTION *Action)
 Handle extended control registers writes. More...
 
INTSTATUS IntHandleBreakpoint (void *GuestHandle, QWORD GuestPhysicalAddress, DWORD CpuNumber)
 Handle guest breakpoints. More...
 
static INTSTATUS IntHandleEventInjection (void *GuestHandle, DWORD Vector, QWORD ErrorCode, QWORD Cr2, DWORD CpuNumber)
 Handle event injections inside the guest. More...
 
INTSTATUS IntHandleDtrViolation (void *GuestHandle, DWORD Flags, DWORD CpuNumber, INTRO_ACTION *Action)
 Handle GDTR, IDTR, LDTR, TR accesses. More...
 
INTSTATUS IntEnginesResultCallback (void *GuestHandle, PENG_NOTIFICATION_HEADER EngineNotification)
 Handler called by the integrator as soon as the engines report a scan result for a buffer. More...
 
INTSTATUS IntCallbacksInit (void)
 Initialize the callbacks. More...
 
INTSTATUS IntCallbacksUnInit (void)
 Uninit all the Introcore callbacks. More...
 

Variables

QWORD gEptEvents
 
BOOLEAN gInjectVeLoader
 
BOOLEAN gInjectVeUnloader
 
BOOLEAN gLoadPtDriver
 
BOOLEAN gUnloadPtDriver
 
static BOOLEAN gForceActionOnBeta
 

Macro Definition Documentation

◆ MAX_GLAS

#define MAX_GLAS   32

Referenced by IntHandleEptViolation().

Function Documentation

◆ IntCallbacksInit()

INTSTATUS IntCallbacksInit ( void  )

Initialize the callbacks.

Most of the callbacks are initialized here. As soon as a callback is registered for a certain type of event, Introcore can start processing them. NOTE: Some callbacks, such as the breakpoint handler or the EPT violation handler are registered on the init flow, so as to avoid having to handle many irrelevant events while we initialize.

Return values
INT_STATUS_SUCCESSOn success.

Definition at line 3527 of file callbacks.c.

Referenced by IntGuestHandleCr3Write().

◆ IntCallbacksUnInit()

INTSTATUS IntCallbacksUnInit ( void  )

Uninit all the Introcore callbacks.

Return values
INT_STATUS_SUCCESSOn success.

Definition at line 3576 of file callbacks.c.

Referenced by IntGuestUninit().

◆ IntDispatchPtAsEpt()

static INTSTATUS IntDispatchPtAsEpt ( void  )
static

Dispatch a VMCALL issued by the PT filter as an EPT violation.

This function will act as the main EPT violation handler for very specific accesses filtered by the PT filter. This function will be called when the PT filter intercepts a guest instruction which does a relevant modification to a page-table entry. At that point, the PT filter will issue a VMCALL, but inside Introcore, in order to maintain a good separation between events, we will directly invoke the main memory access handle in order to treat the instruction as if it triggered an EPT violation. This function simply fills in the VCPU context and calls the memory access function, which will treat the page-table write instruction. In addition, if the page-table entry is not monitored by Introcore, it will be added to the PT cache, so as to not generate any more VMCALLs for it, until it becomes hooked.

Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1843 of file callbacks.c.

Referenced by IntHandleIntroCall().

◆ IntDispatchVeAsEpt()

static INTSTATUS IntDispatchVeAsEpt ( void  )
static

Dispatch a VE as an EPT violation.

This function gets called when the VE agent issues a VMCALL, as a result from an in-guest VE which is considered relevant. The VE agent will issue a VMCALL only for page-table writes which hit a protected page-table, and if the write modifies a relevant bit. In that case, the agent will notify Introcore, which will handle the page-table modification by properly updating the protection on the old/new pages. This function will fill in the VCPU context (including the registers and the instruction, which are all provided in the VE info page) and will call the memory access handler, which will behave as if the event was indeed generated as an EPT violation. This function also has special handling for page-walks: due to KPTI, page-walks will always be emulated in the context of the kernel CR3; however, sometimes, for some processes, the user CR3 PML4 entry will lack the A or D bit, and since we cannot switch into the user-mode CR3 from inside the guest, we will simply ask Introcore to handle those page walks, which are extremely rare, but would cause a guest hang otherwise (because the page-walk VE would be triggered in an infinite loop, as the user CR3 would never end up having the A/D bits set).

Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_SUPPORTEDIf a walk is requested from a Linux guest.
INT_STATUS_NOT_FOUNDIf the process with the current CR3 is not found.

Definition at line 1916 of file callbacks.c.

Referenced by IntHandleIntroCall().

◆ IntEnginesResultCallback()

INTSTATUS IntEnginesResultCallback ( void *  GuestHandle,
PENG_NOTIFICATION_HEADER  EngineNotification 
)

Handler called by the integrator as soon as the engines report a scan result for a buffer.

Introcore may request the AV engines to scan certain memory buffers (for example, Powershell command lines or memory areas that get executed inside the guest). Since the scanning is done in a different thread/process, and due to performance concerns, we resume guest execution as soon as we have sent the buffer to be scanned. When the engines finish the scan, Introcore will be notified of the result via this handler. This handler simply dispatches the result to the appropriate callback, and they will send an alert, if a detection was generated. Currently, only two types of buffers are scanned using the AV engines:

  1. Executed memory pages which are deemed legit by Introcore
  2. Powershell command lines If other types of buffers need to be scanned, make sure you add the result handling here as well.
Parameters
[in]GuestHandleThe guest handle.
[in]EngineNotificationA structure describing the buffer that was scanned and the scan result.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized.

Definition at line 3426 of file callbacks.c.

Referenced by IntCallbacksInit().

◆ IntHandleBreakpoint()

INTSTATUS IntHandleBreakpoint ( void *  GuestHandle,
QWORD  GuestPhysicalAddress,
DWORD  CpuNumber 
)

Handle guest breakpoints.

This handler is called by the integrator whenever a breakpoint (INT3) takes place inside the guest. This function will just dispatch the event to an appropriate Introcore handler, in this order:

  1. Detours;
  2. Agents;
  3. The PT filter. If no handler claims ownership for a particular INT3, we will disassemble the instruction pointed by the current RIP. If indeed there is an INT3 there, we will re-inject it to the guest, as it probably really is an in-guest breakpoint. If the instruction is not INT3, it may have been replaced by the PT filter, for example, when inspecting a candidate instruction. In that case, we will simply re-entry inside the guest at the same RIP. Handling the breakpoint can be done in three ways:
  1. Reinject it; if the INT3 wasn't triggered by our detours, agents or PT filter, it gets reinjected;
  2. Skip it; if the INT3 was handled by us, simply move the RIP over it;
  3. Re-entry at the same instruction; if introcore replaced the INT3 with something else in the meantime, simply re-enter at the same RIP.
Parameters
[in]GuestHandleThe guest handle.
[in]GuestPhysicalAddressUnused.
[in]CpuNumberThe VCPU number.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized.
INT_STATUS_NOT_FOUNDIf Introcore did not handle the VMCALL.
INT_STATUS_FATAL_ERRORIf a fatal error occurred and the integrator should unload Introcore.
INT_STATUS_UNINIT_BUGCHECKIf a bug-check occurred inside the guest and Introcore should be unloaded.

Definition at line 2734 of file callbacks.c.

Referenced by IntEnableBreakpointNotifications(), and IntWinGuestInit().

◆ IntHandleCowOnPage()

static BOOLEAN IntHandleCowOnPage ( QWORD  Gla,
DWORD  CpuNumber,
BYTE  AccessType 
)
static

Handle copy-on-write on a page.

This function handles copy-on-write events on a given guest linear address. This is needed because of an emulator flaw in Xen: a CMPXCHG instruction at a page-boundary would be emulated badly by copying the first chunk of data inside the first page, then injection a PF for the second page, if it isn't writable. When re-executing the CMPXCHG after the fault is handled, the memory value would be different, and the instruction would not execute correctly (since the first page has already been written). Check if this is a write access, inside user-mode, on a non-present or non-writable page, and inject a PF if needed.

Parameters
[in]GlaThe accessed guest linear address.
[in]CpuNumberThe VCPU number.
[in]AccessTypeAccess type.
Returns
True if a PF has been injected due to CoW, false otherwise.

Definition at line 700 of file callbacks.c.

Referenced by IntHandleDtrViolation(), and IntHandlePageBoundaryCow().

◆ IntHandleCrWrite()

INTSTATUS IntHandleCrWrite ( void *  GuestHandle,
DWORD  Cr,
DWORD  CpuNumber,
QWORD  OldValue,
QWORD  NewValue,
INTRO_ACTION Action 
)

Handle a control register violation.

This function is called by the integrator/HV on each CR violation. The handler will simply iterate the list of registered callbacks for this particular CR, and call each one of them. Introcore only places write hooks on the control registers; read hooks may trigger a very high performance impact.

Parameters
[in]GuestHandleThe guest handle.
[in]CrThe accessed CR.
[in]CpuNumberThe VCPU number.
[in]OldValueOld CR value.
[in]NewValueNew CR value.
[in]ActionThe desired action.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized yet.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_NOT_FOUNDIf no callback is found for this MSR.
INT_STATUS_FATAL_ERRORA fatal error occurred, and the integrator should unload Introcore.

Definition at line 1692 of file callbacks.c.

Referenced by IntEnableCrNotifications().

◆ IntHandleDtrViolation()

INTSTATUS IntHandleDtrViolation ( void *  GuestHandle,
DWORD  Flags,
DWORD  CpuNumber,
INTRO_ACTION Action 
)

Handle GDTR, IDTR, LDTR, TR accesses.

This function is called on descriptor table registers accesses. This function will iterate registered callbacks and it will call all of them. Special handling is done, however, for these instructions, as they generate a descriptor table access VM exit before doing any kind of memory checks; therefore, emulating such an instruction may lead to an EPT protection bypass (since the HV may not check EPT access rights when emulating instructions). As a result, we do some serious checks when handling these instructions:

  1. Bail out if the instruction is not LIDT, LGDT, LLDT, LTR, SIDT, SGDT, SLDT, STR;
  2. Bail out if the instruction doesn't operate on memory - we are only interested in LGDT/LIDT, which can only operate on memory operands;
  3. Decode the accessed linear address, and call the CoW and regular memory access handlers for that address;
  4. If the access is valid, carry on by calling the LIDT/LGDT handlers. NOTE: The instruction will be allowed by default when loading a non-null value over a previously null value; this is basically the initialization of that register.
Parameters
[in]GuestHandleThe guest handle.
[in]FlagsDescriptor table accessed & accessed type. Check out IG_DESC_ACCESS.
[in]CpuNumberThe VCPU number.
[out]ActionDesired action.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized.
INT_STATUS_FATAL_ERRORIf a fatal error occurred and Introcore should be unloaded.

(for example, GDTR READ, IDTR WRITE, etc.).

Definition at line 3116 of file callbacks.c.

Referenced by IntEnableDtrNotifications().

◆ IntHandleEptViolation()

INTSTATUS IntHandleEptViolation ( void *  GuestHandle,
QWORD  PhysicalAddress,
DWORD  Length,
QWORD  LinearAddress,
DWORD  CpuNumber,
INTRO_ACTION Action,
IG_EPT_ACCESS  AccessType 
)

Handle an EPT violation.

This callback is called by the HV/integrator whenever an EPT violation takes place. Introcore will handle the event by calling registered callbacks for the accessed memory area. Note that Introcore will also call the callbacks for other linear addresses that may be accessed by the instruction. Upon return, it has to return an action to the integrator. The main steps taken by this function are:

  1. Decode the instruction that triggered the EPT violation;
  2. Handle PT filter or mem-table instructions that triggered an exit after being handled by another VCPU;
  3. Check if the EPT violation took place inside the protected EPT view; if so, call the appropriate handler;
  4. Handle the execute EPT violation, if it's the case;
  5. Decode all addresses the instruction accesses, and, for each decoded linear address, translate it to a physical address, and call the IntHandleMemAccess function (note that the translation will not be done if the accessed linear address is the same as LinearAddress);
  6. Handle REP instructions: if a REP prefixed instruction touches a region of memory which is hooked, disable REP optimizations, and re-execute that instruction step by step;
  7. Handle read emulation. If we have reads made by the patch-guard inside hidden memory areas, return the original data;
  8. Handle x86 PAE page table writes. If one 4 bytes piece from an 8 bytes page-table entry is written, search for the instruction which writes the second 4 bytes piece, and emulate that too;
  9. Handle Copy-on-Write at page boundary. NOTE: A good security measure is to not handle an EPT violation if the instruction that triggered it is not cached. The reasoning behind this is TOCTOU: while we disassemble & analyze the instruction that triggered the fault, an attacker may replace that instruction with a malicious one, which may get emulated once Introcore decides that the action was legitimate. Therefore, if an EPT violation is generated from an instruction that is not cached, simply cache the instruction, and re-execute it. The second time the EPT violation takes place, the instruction will be cached, and an attacker won't be able to replace it inside guest memory, since a cached instruction means that the page it lies in is marked non-writable inside EPT. NOTE: The reason why we may call the memory access function for linear addresses for which no EPT violation has been generated is because we must inspect each address accessed by the instruction in order to conclude that it is legitimate. For example, let's say the instruction "PUSH [rax]" is executed, and it triggers a read EPT violation on the memory pointed by "rax". Introcore may conclude that this is legitimate, that memory can be read, and the instruction can be emulated. However, the instruction also writes to the memory pointed by "rsp" (the stack), which may also be hooked against writes! However, because Introcore allowed the instruction to be emulated, this stack write would no longer generate an EPT violation, and protection may be bypassed. Therefore, in order to deem an instruction safe to be emulated, we analyze every address accessed by the instruction.
Parameters
[in]GuestHandleA handle to the guest that generated the EPT violation.
[in]PhysicalAddressAccessed guest physical address.
[in]LengthAccess size. Note that this parameter is reserved for future use, as the HV does not decode (and the CPU does not provide) the access size.
[in]LinearAddressThe accessed guest linear address.
[in]CpuNumberVCPU number.
[out]ActionWill contain, upon successful return, the action to be taken fro the access.
[in]AccessTypeAccess type: IG_EPT_HOOK_READ, IG_EPT_HOOK_WRITE & IG_EPT_HOOK_EXECUTE.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_FORCE_ACTION_ON_BETAForce the introGuestNotAllowed, even in beta mode. This ensures that our hooks don't get overwritten.
INT_STATUS_FATAL_ERRORA fatal error occurred, and the integrator should unload Introcore.

NOTE: The instruction may be modified after the fault is triggered. Therefore, we may process the GLA/GPA the fault took place at, but the instruction may encode a different address.

Definition at line 825 of file callbacks.c.

Referenced by IntEnableEptNotifications().

◆ IntHandleEventInjection()

static INTSTATUS IntHandleEventInjection ( void *  GuestHandle,
DWORD  Vector,
QWORD  ErrorCode,
QWORD  Cr2,
DWORD  CpuNumber 
)
static

Handle event injections inside the guest.

This event will be the first event to be generated once we inject an exception on CPU CpuNumber. This is used to know if an exception that we injected inside the guest really got injected. If something else got injected, Introcore can retry the injection at a later point. This simplifies the exception injection algorithm, especially because the HV may inject other things inside the guest. This function will check if the HV injected our PF or UD (which we requested earlier).

Parameters
[in]GuestHandleThe guest handle.
[in]VectorThe vector that got injected inside the guest.
[in]ErrorCodeThe delivered error code, if any.
[in]Cr2The CR2, if a PF was injected.
[in]CpuNumberThe VCPU number.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is used.

Definition at line 2986 of file callbacks.c.

Referenced by IntCallbacksInit().

◆ IntHandleFetchRetryOnPageBoundary()

static BOOLEAN IntHandleFetchRetryOnPageBoundary ( DWORD  CpuNumber)
static

Handle instruction fetch at page boundary, if an EPT execute violation has been generated.

Special handling for introGuestRetry on EPT exec violations. We may request a retry when we cannot fetch the RIP, for example. Sometimes, the instruction may be situated at a page boundary and be contained inside both pages. In this case, if at least the first page is exec hooked and the second one is not present, we will induce an infinite loop by requesting introGuestRetry, because the PF on the second page will never be triggered since the EPT violation on the first one will always take place first. In this case, we will manually inject the PF on the second page.

Parameters
[in]CpuNumberVCPU number.
Returns
True if a PF has been injected inside the guest, false otherwise.

Definition at line 614 of file callbacks.c.

Referenced by IntHandleEptViolation().

◆ IntHandleIntroCall()

INTSTATUS IntHandleIntroCall ( void *  GuestHandle,
QWORD  Rip,
DWORD  CpuNumber 
)

Handle a VMCALL issued inside the guest.

This function will be called by the hypervisor whenever a VMCALL is executed inside the guest with a magic value in EAX register. For the Xen hypervisor, this magic value involves several registers: On x64: RAX = 0x22, RDI = 0x18, RSI = 0 On x86: EAX = 0x22, EBX = 0x18, ECX = 0 The EAX register will be overwritten by the HV on guest re-entry, so don't use it to pass the result of the VMCALL. This function will dispatch the VMCALL to the following handlers, in this order:

  1. VE handler, if the RIP is inside the VE agent;
  2. PT handler, if the RIP is inside the PT filter;
  3. Detours, if VMCALL is used as the hyper call method;
  4. Agents. After dispatching the VMCALL appropriately, this function will finally dispatch it as an EPT violation if either the PT filter or the VE agent requested so.
Parameters
[in]GuestHandleThe guest handle.
[in]RipRIP where the VMCALL originates.
[in]CpuNumberThe VCPU number.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized.
INT_STATUS_NOT_FOUNDIf Introcore did not handle the VMCALL.
INT_STATUS_FATAL_ERRORIf a fatal error occurred and the integrator should unload Introcore.
INT_STATUS_UNINIT_BUGCHECKIf a bug-check occurred inside the guest and Introcore should be unloaded.

Definition at line 2140 of file callbacks.c.

Referenced by IntCallbacksInit().

◆ IntHandleMemAccess()

static INTSTATUS IntHandleMemAccess ( QWORD  LinearAddress,
QWORD  PhysicalAddress,
DWORD  Length,
INTRO_ACTION Action,
BOOLEAN CallbackFound,
BOOLEAN PageHooked,
BOOLEAN  ProbeOnly,
IG_EPT_ACCESS  AccessType 
)
static

Handle a memory access to a guest linear address.

This function handles one GLA access (execute, read, write or read-write). The access can be combined (for example, read-write). The function will iterate the list of registered callbacks for the PhysicalAddress the given LinearAddress translates to, and it will call each registered callback. The actions returned by the callback will be combined (the numerically higher action will be kept) and returned. Each access will be handled individually; for example, if the AccessType is RWX, the function will first handle the execute access, followed by the read access, followed finally by the write access. For read accesses which do not have a registered callback, the mem-tables and the RtlpVirtualUnwind optimizations will be invoked, to see if we can instrument the instruction, for better performance. NOTE: If no callback is found, the default action is introGuestAllowed. NOTE: This function may be called for PhysicalAddress values for which an EPT violation has not been generated. This happens because when handling an instruction, Introcore will call this function for every accessed linear address, even for those for which an EPT violation may never be generated.

Parameters
[in]LinearAddressThe guest linear address accessed.
[in]PhysicalAddressThe guest physical address accessed.
[in]LengthThe size of the access. For execute accesses, this is the length of the instruction For read/write accesses, this is the size of the access.
[out]ActionThe final action returned by the invoked callbacks.
[out]CallbackFoundSet to true if at least one callback is found for the provided address.
[out]PageHookedSet to true if the page is indeed hooked.
[in]ProbeOnlyIf set, simply check if there is at least a callback for the address. If this is set, no callbacks will be invoked, as the function will return as soon as at find the first registered callback.
[in]AccessTypeAccess type. Can be a combination of IG_EPT_HOOK_EXECUTE, IG_EPT_HOOK_READ and IG_EPT_HOOK_WRITE.
Return values
INT_STATUS_SUCCESSOn success. This does not necessarily mean that a callback was found!
INT_STATUS_NOT_INITIALIZEDIf the hooks system is not initialized.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.

Definition at line 311 of file callbacks.c.

Referenced by IntDispatchPtAsEpt(), IntDispatchVeAsEpt(), IntHandleDtrViolation(), and IntHandleEptViolation().

◆ IntHandleMsrViolation()

INTSTATUS IntHandleMsrViolation ( void *  GuestHandle,
DWORD  Msr,
IG_MSR_HOOK_TYPE  Flags,
INTRO_ACTION Action,
QWORD  OriginalValue,
QWORD NewValue,
DWORD  CpuNumber 
)

Handle a model specific register violation.

This callback is called on MSR violations. This handle will iterate the list of registered callbacks for that particular MSR, and will call each one of them. NOTE: Although read hooks can also be established on MSRs, Introcore does not make use of that, only write hooks are set.

Parameters
[in]GuestHandleThe guest handle.
[in]MsrThe accessed MSR.
[in]FlagsMSR violation type (read or write).
[out]ActionDesired action.
[in]OriginalValueOriginal MSR value.
[out]NewValueNew MSR value. Can be modified, but whether the HV will take this into consideration or not is implementation dependent, so it is advisable to not modify this value.
[in]CpuNumberThe VCPU number.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized yet.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_NOT_FOUNDIf no callback is found for this MSR.
INT_STATUS_FATAL_ERRORA fatal error occurred, and the integrator should unload Introcore.

Definition at line 1536 of file callbacks.c.

Referenced by IntEnableMsrNotifications().

◆ IntHandlePageBoundaryCow()

static BOOLEAN IntHandlePageBoundaryCow ( QWORD  Gla,
DWORD  AccessSize,
BYTE  AccessType,
DWORD  CpuNumber 
)
static

Check if we have a copy-on-write condition at a page boundary.

Check if the accessed gla spans inside two pages, and it it is the case, call the CoW handler.

Parameters
[in]GlaThe accessed guest linear address.
[in]AccessSizeThe access size, in bytes.
[in]AccessTypeAccess type (should be read-write or write).
[in]CpuNumberVCPU number.
Returns
True if a PF has been injected due to CoW, false otherwise.

Definition at line 792 of file callbacks.c.

Referenced by IntHandleDtrViolation(), and IntHandleEptViolation().

◆ IntHandleTimer()

INTSTATUS IntHandleTimer ( void *  GuestHandle)

Periodically called by the integrator, once every second.

This function is called every second. Tasks such as integrity checks can be done here. The main tasks this handle carries are:

  1. Infinity hook protection;
  2. Integrity checks on structures that cannot be protected using EPT/SPP;
  3. Process token integrity checks - it will check every second if a system token has been stolen;
  4. System CR3 integrity - it will check every second to see of the System CR3 has been modified;
  5. Self-map integrity - it will check every second of the self-map entry inside the page-tables has been modified;
  6. Re-inject page-faults that did not get to be processes in the last second;
  7. Do PT integrity checks; since the PT monitors page-tables by intercepting instructions inside NT that modify them, there is a chance that someone else could modify a page-table entry without us knowing; this integrity check will make sure that every page-table entry that we monitor hasn't been tampered with;
  8. Once every hour, dump performance statistics; NOTE: this may be called on any processor. However, code must not make assumptions regarding the PCPUS/VCPUS it gets called on, and neither should it assume that it will be called on more than one processor. This function will get called every second. This also ensures us that every second, the hooks will be committed or cleaned up. IMPORTANT: Any function called here must be TIMER_FRIENDLY: it must not rely on VCPU state or on the fact that a "current VCPU exits" - it should assume that all the VCPUs are running and it must rely only on the global, known state of the guest: system CR3, cached paging mode, etc. Doing any kind of state query will lead to a VCPU pause, will return the state of that VCPU, but the VCPU will then be resumed, resulting in a dangling state, which may quickly become invalid. If guest state is required, make sure you pause all the VCPUs.
Parameters
[in]GuestHandleThe guest handle.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized.

It would be nice to pause the guest while we do the checks; However, since we're doing read-only operations and the protected areas should not be modified during the normal usage, we can safely let all other processors run code.

Definition at line 2359 of file callbacks.c.

Referenced by IntCallbacksInit().

◆ IntHandleXcrWrite()

INTSTATUS IntHandleXcrWrite ( void *  GuestHandle,
DWORD  CpuNumber,
INTRO_ACTION Action 
)

Handle extended control registers writes.

This function handles the XSETBV instruction, which modifies XCRs. Currently, only XCR0 can be intercepted. Even this is intercepted in order to aid into activating protection, and it is not protected against attacks. This function will iterate the list of XCR callbacks, and it will call each one.

Parameters
[in]GuestHandleThe guest handle.
[in]CpuNumberThe VCPU number.
[out]ActionThe desired action.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_NOT_INITIALIZED_HINTIf the guest is not initialized.
INT_STATUS_NOT_FOUNDIf Introcore did not handle the VMCALL.
INT_STATUS_FATAL_ERRORIf a fatal error occurred and the integrator should unload Introcore.

Definition at line 2580 of file callbacks.c.

Referenced by IntEnableXcrNotifications().

◆ IntValidatePageRights()

static void IntValidatePageRights ( QWORD  LinearAddress,
QWORD  PhysicalAddress,
DWORD  Access 
)
static

Check if the access rights for the provided PhysicalAddress are up-to-date in the EPT. This function will get called only if the page wasn't hooked.

Sometimes, setting the access rights may silently fail on some HVs. In order to address this, we implement the following workaround: on EPT violations that are generated on a GPA which doesn't have any callback set, we will re-set the access rights again, hopping that this time, no errors will take place in the HV.

Parameters
[in]LinearAddressThe accessed linear address.
[in]PhysicalAddressThe accessed physical address.
[in]AccessThe access type.

Definition at line 228 of file callbacks.c.

Referenced by IntHandleMemAccess().

◆ IntValidatePageRightsEx()

static BOOLEAN IntValidatePageRightsEx ( QWORD  LinearAddress,
QWORD  PhysicalAddress,
DWORD  Access 
)
static

Check if the access rights for the provided PhysicalAddress are up-to-date in the EPT. This function will get called oon each EPT violation.

Sometimes, setting the access rights may silently fail on some HVs. In order to address this, we implement the following workaround: on EPT violations that are generated on a GPA which doesn't have any callback set, we will re-set the access rights again, hopping that this time, no errors will take place in the HV.

Parameters
[in]LinearAddressThe accessed linear address.
[in]PhysicalAddressThe accessed physical address.
[in]AccessThe access type.
Returns
TRUE if the access rights are OK, FALSE if they were not OK, but they have been re-applied.

Definition at line 114 of file callbacks.c.

Referenced by IntHandleEptViolation().

◆ IntValidateTranslation()

static BOOLEAN IntValidateTranslation ( PHOOK_GPA  Hook)
static

Checks if the given GPA hook points to a valid GVA hook with a correct translation.

This function will get the GVA hook (if any) pointing to the GPA hook, and it will attempt to translate the virtual address to a physical address. Normally, the GPA the EPT violation just took place on and the GPA we obtain after we translate the GVA should be the same. However, if there has been a translation error (for example, somehow we missed a PTE write), the translated GPA could differ.

Parameters
[in]HookThe GPA hook.
Returns
TRUE of the translation is OK, FALSE otherwise.

Definition at line 37 of file callbacks.c.

Referenced by IntHandleMemAccess().

Variable Documentation

◆ gEptEvents

QWORD gEptEvents

Definition at line 29 of file callbacks.c.

Referenced by IntHandleEptViolation(), and IntVeDumpStats().

◆ gForceActionOnBeta

BOOLEAN gForceActionOnBeta
static

Definition at line 33 of file callbacks.c.

Referenced by IntHandleEptViolation(), and IntHandleMemAccess().

◆ gInjectVeLoader

BOOLEAN gInjectVeLoader

Definition at line 30 of file callbacks.c.

Referenced by DbgLoadVe(), and IntHandleTimer().

◆ gInjectVeUnloader

BOOLEAN gInjectVeUnloader

Definition at line 30 of file callbacks.c.

Referenced by DbgUnloadVe(), and IntHandleTimer().

◆ gLoadPtDriver

BOOLEAN gLoadPtDriver

Definition at line 31 of file callbacks.c.

Referenced by DbgLoadPt(), and IntHandleTimer().

◆ gUnloadPtDriver

BOOLEAN gUnloadPtDriver

Definition at line 31 of file callbacks.c.

Referenced by DbgUnloadPt(), and IntHandleTimer().