Bitdefender Hypervisor Memory Introspection
Memory cloaking

Hides memory contents from the guest. More...

Data Structures

struct  _MEMCLOAK_PAGE
 A structure that describes a hidden guest memory page. More...
 
struct  _MEMCLOAK_REGION
 A structure that describes a hidden guest memory region. More...
 

Macros

#define MEMCLOACK_PAGE_MAX_COUNT   2
 The maximum number of pages that can be contained in a MEMCLOAK_REGION. More...
 

Typedefs

typedef INTSTATUS(* PFUNC_IntMemCloakWriteHandle) (void *Hook, QWORD Address, QWORD RegionVirtualAddress, void *CloakHandle, INTRO_ACTION *Action)
 The type of custom write handlers that can be used by cloak regions. More...
 
typedef struct _MEMCLOAK_PAGE MEMCLOAK_PAGE
 A structure that describes a hidden guest memory page. More...
 
typedef struct _MEMCLOAK_PAGEPMEMCLOAK_PAGE
 
typedef struct _MEMCLOAK_REGION MEMCLOAK_REGION
 A structure that describes a hidden guest memory region. More...
 
typedef struct _MEMCLOAK_REGIONPMEMCLOAK_REGION
 

Enumerations

enum  MEMCLOAK_OPTIONS { MEMCLOAK_OPT_ALLOW_INTERNAL = 0x00000001, MEMCLOAK_OPT_APPLY_PATCH = 0x00000002 }
 Options that control the way a cloaked memory region is handled. More...
 

Functions

INTSTATUS IntMemClkCloakRegion (QWORD VirtualAddress, QWORD Cr3, DWORD Size, DWORD Options, PBYTE OriginalData, PBYTE PatchedData, PFUNC_IntMemCloakWriteHandle WriteHandler, void **CloakHandle)
 Hides a memory zone from the guest. More...
 
INTSTATUS IntMemClkModifyOriginalData (void *CloakHandle, DWORD Offset, DWORD Size, void *Data)
 Modifies the internal copy of the original data buffer held by a cloak region. More...
 
INTSTATUS IntMemClkModifyPatchedData (void *CloakHandle, DWORD Offset, DWORD Size, const void *Data)
 Modifies the patched data inside the guest memory. More...
 
INTSTATUS IntMemClkUncloakRegion (void *CloakHandle, DWORD Options)
 Removes a cloak region, making the original memory contents available again to the guest. More...
 
INTSTATUS IntMemClkHashRegion (QWORD VirtualAddress, QWORD PhysicalAddress, DWORD Size, DWORD *Crc32)
 Hashes the contents of a cloaked memory page. More...
 
BOOLEAN IntMemClkIsPtrInCloak (const void *Cloak, QWORD Ptr)
 Checks if a guest virtual address is located inside a cloak region. More...
 
INTSTATUS IntMemClkGetOriginalData (void *CloakHandle, BYTE **OriginalData, DWORD *Length)
 Returns the original data of a cloaked region. More...
 
INTSTATUS IntMemClkUnInit (void)
 Uninits the memory cloak subsystem. More...
 
void IntMemClkDump (void)
 Dumps all the active cloak regions. More...
 
static INTSTATUS IntMemClkUncloakRegionInternal (DWORD Options, PMEMCLOAK_REGION Region)
 Removes a cloak region, making the original memory contents available again to the guest. More...
 
static INTSTATUS IntMemClkHandleSwap (MEMCLOAK_PAGE *Context, QWORD VirtualAddress, QWORD OldEntry, QWORD NewEntry, QWORD OldPageSize, QWORD NewPageSize)
 Handles swap-in and swap-outs performed on hidden memory regions. More...
 
static INTSTATUS IntMemClkHandleRead (MEMCLOAK_PAGE *Context, PHOOK_GPA Hook, QWORD Gpa, INTRO_ACTION *Action)
 Handles reads from a hidden memory region. More...
 
static INTSTATUS IntMemClkHandleWrite (PMEMCLOAK_PAGE *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
 Handles writes done inside a hidden memory region. More...
 
void IntMemClkCleanup (MEMCLOAK_REGION *Region)
 Frees any resources held by a MEMCLOAK_REGION. More...
 

Variables

static LIST_HEAD gMemClkRegions = LIST_HEAD_INIT(gMemClkRegions)
 A list containing all the memory regions that are currently hidden from the guest. More...
 

Detailed Description

Hides memory contents from the guest.

Introcore may inject code or data, or modify existing guest code or data. This raises a series of problems, from hiding from the guest the fact that it is introspected, to making sure the changes are not seen by integrity mechanisms used by the guest (like patch guard on Windows). We also need to make sure that attackers can not modify code or data owned by introcore, while allowing us to easily modify and use those. This is handled here, by the memory cloak mechanism, which employs three memory hooks:

Macro Definition Documentation

◆ MEMCLOACK_PAGE_MAX_COUNT

#define MEMCLOACK_PAGE_MAX_COUNT   2

The maximum number of pages that can be contained in a MEMCLOAK_REGION.

Definition at line 27 of file memcloak.c.

Referenced by IntMemClkCloakRegion().

Typedef Documentation

◆ MEMCLOAK_PAGE

typedef struct _MEMCLOAK_PAGE MEMCLOAK_PAGE

A structure that describes a hidden guest memory page.

◆ MEMCLOAK_REGION

A structure that describes a hidden guest memory region.

◆ PFUNC_IntMemCloakWriteHandle

typedef INTSTATUS(* PFUNC_IntMemCloakWriteHandle) (void *Hook, QWORD Address, QWORD RegionVirtualAddress, void *CloakHandle, INTRO_ACTION *Action)

The type of custom write handlers that can be used by cloak regions.

Parameters
[in]HookThe hook that triggered the event.
[in]AddressThe physical address written.
[in]RegionVirtualAddressThe virtual address at which the region starts.
[in]CloakHandleThe cloak handle returned by IntMemClkCloakRegion.
[out]ActionThe action that must be taken. This will overwrite the default action, which. is introGuestNotAllowed.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value. Returning an error values will make the returned Action to be ignored, and the default one will be used.

Definition at line 41 of file memcloak.h.

◆ PMEMCLOAK_PAGE

typedef struct _MEMCLOAK_PAGE * PMEMCLOAK_PAGE

◆ PMEMCLOAK_REGION

Enumeration Type Documentation

◆ MEMCLOAK_OPTIONS

Options that control the way a cloaked memory region is handled.

Enumerator
MEMCLOAK_OPT_ALLOW_INTERNAL 

Allows the code inside the region to modify the region.

MEMCLOAK_OPT_APPLY_PATCH 

Will write the contents of the patched data inside the guest.

Definition at line 51 of file memcloak.h.

Function Documentation

◆ IntMemClkCleanup()

void IntMemClkCleanup ( MEMCLOAK_REGION Region)

Frees any resources held by a MEMCLOAK_REGION.

This function will free the MEMCLOAK_REGION.OriginalData and MEMCLOAK_REGION.PatchedData buffers, as well as the Region itself. It does not remove the hooks set for a region.

Parameters
[in,out]RegionThe region to be freed. This pointer is no longer valid after this function returns.

Definition at line 521 of file memcloak.c.

Referenced by IntMemClkUncloakRegionInternal().

◆ IntMemClkCloakRegion()

INTSTATUS IntMemClkCloakRegion ( QWORD  VirtualAddress,
QWORD  Cr3,
DWORD  Size,
DWORD  Options,
PBYTE  OriginalData,
PBYTE  PatchedData,
PFUNC_IntMemCloakWriteHandle  WriteHandler,
void **  CloakHandle 
)

Hides a memory zone from the guest.

This will place an EPT read, EPT write hook on the [VirtualAddress, VirtualAddress + Size) memory region. The read hook will allow us to hide memory from the guest. Attempts to read from the hidden pages will trigger an EPT violation that will be handled by IntMemClkHandleRead. This will allow us to control what the guest sees from a memory page. This is helpful when trying to hide code or data injected by us inside the guest. The write hook will allow us to protect the code or data injected inside the guest. It has a second purpose, as only removing the read permission from the EPT is not allowed, write-execute being an invalid combination. The write will be handled by IntMemClkHandleWrite, but a custom WriteHandler can also be provided. It will also hook the page tables used to translate the hidden pages, in order to catch swaps done on those pages and make sure that the modified data does not leak during page swap-in. The swap operation will be handled by IntMemClkHandleSwap.

Parameters
[in]VirtualAddressThe start of the virtual memory region to be hidden.
[in]Cr3The virtual address space in which the hiding is done.
[in]SizeThe size of the hidden region.
[in]OptionsOptions that control the way accesses to the memory region are handled. Must be 0 or a combination of MEMCLOAK_OPTIONS values.
[in]OriginalDataThe original data. This will be presented to the guest when it tries to read from the cloaked area. If not NULL, it must be Size bytes in length. If it is NULL, the original data is considered to be 0.
[in]PatchedDataThe data patched by Introcore inside the guest.If not NULL, it must be Size bytes in length. If it is NULL, the patched data is considered to be 0.
[in]WriteHandlerA custom handler to use when the guest tries to write to the hidden memory area. It may be NULL, in which case the default handler will be used and all writes will be blocked.
[out]CloakHandleThe handle of the cloaked region. This is used as an unique identifier by APIs that control or modify the cloaked region.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_NOT_SUPPORTEDif the region spans across more than MEMCLOACK_PAGE_MAX_COUNT pages.
INT_STATUS_INSUFFICIENT_RESOURCESif an internal buffer could not be allocated.
INT_STATUS_INVALID_PARAMETER_8if CloakHandle is NULL.

Definition at line 548 of file memcloak.c.

Referenced by DbgTestRead(), IntDetPatchFunction(), IntDetSetHook(), IntLixAgentActivatePendingAgent(), IntLixGuestAllocateDeploy(), IntMtblPatchInstruction(), IntPtiMonitorAllPtWriteCandidates(), IntSwapgsInstallHandler(), IntSwapgsStartMitigation(), IntWinAgentActivatePendingAgent(), IntWinAgentInjectTrampoline(), and IntWinApiHookVeHandler().

◆ IntMemClkDump()

void IntMemClkDump ( void  )

Dumps all the active cloak regions.

Definition at line 1218 of file memcloak.c.

Referenced by IntLogCriticalStructureCoruption().

◆ IntMemClkGetOriginalData()

INTSTATUS IntMemClkGetOriginalData ( void *  CloakHandle,
BYTE **  OriginalData,
DWORD Length 
)

Returns the original data of a cloaked region.

This will return a pointer to the internal MEMCLOAK_REGION.OriginalData buffer.

Parameters
[in]CloakHandleThe cloak handle. This is obtained from IntMemClkCloakRegion.
[out]OriginalDataPointer to a BYTE* that will receive the address of the original data buffer.
[out]LengthPointer to a DWORD that will receive the size of the original data buffer.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1if CloakHandle is NULL.
INT_STATUS_INVALID_PARAMETER_2if OriginalData is NULL.
INT_STATUS_INVALID_PARAMETER_3if Length is NULL.

Definition at line 1121 of file memcloak.c.

Referenced by IntDetHandleWrite().

◆ IntMemClkHandleRead()

static INTSTATUS IntMemClkHandleRead ( MEMCLOAK_PAGE Context,
PHOOK_GPA  Hook,
QWORD  Gpa,
INTRO_ACTION Action 
)
static

Handles reads from a hidden memory region.

This is were the actual hiding takes place. When trying to read from a memory area that is hidden, the guest will generate an EPT violation VMEXIT that will be handled here. This is done using the GLUE_IFACE.SetIntroEmulatorContext mechanism, providing the underlying hypervisor the data that needs to be used when emulating the access done by the guest. In order to do this, we need to figure out where exactly inside the cloaked region is the read done and extract the appropriate parts of the MEMCLOAK_REGION.OriginalData buffer. A read can overlap the hidden memory region in multiple way. If the hidden region is in the range [0x1002, 0x1006], the read can be done for:

  • the entire region: this is the easiest case, we can return the entire MEMCLOAK_REGION.OriginalData buffer
  • a part of the region (for example in the range [0x1003, 0x1004]): this is slightly more complicated, as we now have to compute the offset of the read relative to the start of the region and return only that part of the MEMCLOAK_REGION.OriginalData buffer
  • half inside the region, half outside of it (for example, [0x1000, 0x10004], or [0x1005, 0x1009]), in which case a part of the returned patch buffer needs to contain the information that is already present inside the guest memory, as that is not hidden, and the other part needs to be taken from the original data buffer These scenarios get a bit more complicated when the region or the read crosses a page boundary. If our region is split across two pages, but the read only accesses one of them, the above scenarios apply. If a read crosses a page boundary it is important to decode the instruction that actually does the access and obtain the linear virtual address accessed by that instruction, otherwise we may return wrong values. For example, if the read starts at 0xfff, but we only hooked the page 0x1000, the virtual address reported in the VMEXIT information will be 0x1000, but our emulation must start at 0xfff.
Parameters
[in]ContextThe page for which this handler is invoked.
[in]HookThe GPA hook which triggered this event.
[in]GpaThe guest physical address that was accessed.
[out]ActionThe action that must be taken while handling this event. This will be set to introGuestAllowedPatched if there is something that must be hidden from the guest. If introGuestAllowed is used, this can mean a few things: the accessed page is no longer present, in which case we want to allow the read, as it will generate a page fault inside the guest, which will handle it; or, we decided to allow the read (usually, due to the MEMCLOAK_OPT_ALLOW_INTERNAL option).
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 197 of file memcloak.c.

Referenced by IntMemClkCloakRegion().

◆ IntMemClkHandleSwap()

static INTSTATUS IntMemClkHandleSwap ( MEMCLOAK_PAGE Context,
QWORD  VirtualAddress,
QWORD  OldEntry,
QWORD  NewEntry,
QWORD  OldPageSize,
QWORD  NewPageSize 
)
static

Handles swap-in and swap-outs performed on hidden memory regions.

On swap-in operations, we have to ensure that the patched data is restored. Otherwise, after a swap-out, the original content of the page would be restored, leading to the loss of the patched data.

Parameters
[in]ContextThe page for which this handler is invoked.
[in]VirtualAddressThe guest virtual address for which this handler is invoked.
[in]OldEntryThe old page table entry used to translate VirtualAddress.
[in]NewEntryThe new page table entry used to translate VirtualAddress.
[in]OldPageSizeThe old page size.
[in]NewPageSizeThe new page size.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 64 of file memcloak.c.

Referenced by IntMemClkCloakRegion().

◆ IntMemClkHandleWrite()

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

Handles writes done inside a hidden memory region.

Each region can have its own write handler that can decide the action that must be taken for this event. If no custom write handler is provided, the write is always blocked, as we don't want our code and data to be changed by the guest. Also, even in situations in which we want to allow writes, we must place an EPT write hook for the hidden pages as removing only the read permission from the EPT will cause the EPT rights to be write-execute, which is an invalid combination.

Parameters
[in]ContextThe page for which this handler is invoked.
[in]HookThe hook for which this handler is invoked. It simply passes it further to the custom handler, if one exists.
[in]AddressThe physical address accessed.
[out]ActionThe action that must be taken. The default value is introGuestNotAllowed for regions that do not have a custom write handler.
Returns
INT_STATUS_FORCE_ACTION_ON_BETA regardless of what errors are encountered. The only possible failure point is represented by the custom write handler, in which case it is ignored and the default action will be taken. We need INT_STATUS_FORCE_ACTION_ON_BETA in order to be sure that even if introcore is in log-only mode, the write will be blocked if necessary.

Definition at line 467 of file memcloak.c.

Referenced by IntMemClkCloakRegion().

◆ IntMemClkHashRegion()

INTSTATUS IntMemClkHashRegion ( QWORD  VirtualAddress,
QWORD  PhysicalAddress,
DWORD  Size,
DWORD Crc32 
)

Hashes the contents of a cloaked memory page.

The algorithm used for hashing is the one used by Crc32ComputeFast.

Parameters
[in]VirtualAddressThe virtual address of the start of the region..
[in]PhysicalAddressThe physical address to which VirtualAddress translates to.
[in]SizeThe size of the hashed buffer. This must not be larger than PAGE_SIZE.
[out]Crc32The crc32 of the hashed region.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_3is the hashed region crosses a page boundary.
INT_STATUS_INVALID_PARAMETER_4is Crc32 is NULL.

Definition at line 1005 of file memcloak.c.

Referenced by IntHookGvaDisableHooks(), and IntHookGvaEnableHooks().

◆ IntMemClkIsPtrInCloak()

BOOLEAN IntMemClkIsPtrInCloak ( const void *  Cloak,
QWORD  Ptr 
)

Checks if a guest virtual address is located inside a cloak region.

Parameters
[in]CloakThe cloak handle. This is obtained from IntMemClkCloakRegion
[in]PtrThe guest virtual address to be checked.
Return values
Trueif Ptr is inside the cloak region
Falseif Ptr is not inside the cloak region or if Cloak is NULL.

Definition at line 1089 of file memcloak.c.

Referenced by IntVeIsPtrInAgent().

◆ IntMemClkModifyOriginalData()

INTSTATUS IntMemClkModifyOriginalData ( void *  CloakHandle,
DWORD  Offset,
DWORD  Size,
void *  Data 
)

Modifies the internal copy of the original data buffer held by a cloak region.

This will change the contents of the MEMCLOAK_REGION.OriginalData buffer. This function will not enlarge or shrink the buffer.

Parameters
[in]CloakHandleThe cloak handle. This is returned by IntMemClkCloakRegion when a new cloak is set.
[in]OffsetOffset inside the data buffer at which the change will be done.
[in]SizeThe size of the modified chunk.
[in]DataThe new data.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1is CloakHandle is NULL.
INT_STATUS_INVALID_PARAMETER_2is Offset is outside the region's size.
INT_STATUS_INVALID_PARAMETER_3if Size (or the Size and Offset combination) make the write go beyond the size of the region.
INT_STATUS_INVALID_PARAMETER_4is Data is NULL.

Definition at line 734 of file memcloak.c.

Referenced by IntDetHandleWrite().

◆ IntMemClkModifyPatchedData()

INTSTATUS IntMemClkModifyPatchedData ( void *  CloakHandle,
DWORD  Offset,
DWORD  Size,
const void *  Data 
)

Modifies the patched data inside the guest memory.

This will also change the contents of the MEMCLOAK_REGION.PatchedData buffer. This function will not enlarge or shrink the buffer. It will run with the VCPUs paused in order to ensure consistency of the patched data, as well as the fact that no thread will start using the data while it is being modified. However, it will not check that no guest threads are already inside the patched section. If this needs to be ensured the thread safeness mechanism exposed by IntThrSafeCheckThreads should be used before calling this function. If the patched memory region is swapped out, the write inside the guest will not be possible. But in those cases, the memory contents will be modified when the pages get swapped back in.

Whenever data that is hidden is modified, this function must be called. We must ensure permanent consistency between the data in memory and the data inside the cloak structure, otherwise we may cause corruptions. We also patch the data in memory ourselves, in order to avoid race conditions/sync issues.

Parameters
[in]CloakHandleThe cloak handle. This is returned by IntMemClkCloakRegion when a new cloak is set.
[in]OffsetOffset inside the data buffer at which the change will be done.
[in]SizeThe size of the modified chunk.
[in]DataThe new data. If it is NULL, the buffer will be zeroed..
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1is CloakHandle is NULL.
INT_STATUS_INVALID_PARAMETER_2is Offset is outside the region's size.
INT_STATUS_INVALID_PARAMETER_3if Size (or the Size and Offset combination) make the write go beyond the size of the region.

Definition at line 795 of file memcloak.c.

Referenced by IntDetDisableWinHypercall(), IntDetEnableHypercall(), and IntDetModifyPublicData().

◆ IntMemClkUncloakRegion()

INTSTATUS IntMemClkUncloakRegion ( void *  CloakHandle,
DWORD  Options 
)

Removes a cloak region, making the original memory contents available again to the guest.

This is a thin wrapper over IntMemClkUncloakRegionInternal that does some parameter validation..

Parameters
[in]CloakHandleThe handle of the cloaked region. This is obtained from IntMemClkCloakRegion.
[in]OptionsOptions that control the way accesses to the memory region are handled. Must be 0 or a combination of MEMCLOAK_OPTIONS values.
Return values
INT_STATUS_SUCCESSif successful, or an appropriate INTSTATUS error value.
INT_STATUS_INVALID_PARAMETER_2if CloakHandle is NULL.

Definition at line 970 of file memcloak.c.

Referenced by IntDetRemoveBranch(), IntDetRemoveHandler(), IntLixAgentStart(), IntLixGuestUnhookGuestCode(), IntMtblDisable(), IntMtblRemoveEntry(), IntPtiDeleteInstruction(), IntPtiUnhookPtFilter(), IntSwapgsDisable(), IntSwapgsUninit(), IntVeUnhookVeAgent(), IntWinAgentHandleBreakpointAgent(), IntWinAgentHandleLoader1Hypercall(), IntWinAgentRemove(), and IntWinAgentUnInit().

◆ IntMemClkUncloakRegionInternal()

static INTSTATUS IntMemClkUncloakRegionInternal ( DWORD  Options,
PMEMCLOAK_REGION  Region 
)
static

Removes a cloak region, making the original memory contents available again to the guest.

This function will undo any changes made to the cloaked memory region, as well as free any resources held by the region. It will remove Region from the gMemClkRegions list, will write the MEMCLOAK_REGION.OriginalData buffer back to the guest if the MEMCLOAK_OPT_APPLY_PATCH option is used, will remove the EPT hooks set for the region and will free the internal buffers. Restoring the original contents of the memory is done with the VCPUs paused in order to ensure consistency of the data as well as the fact that no thread will start using the data while it is being modified. However, it will not check that no guest threads are already inside the patched section. If this needs to be ensured, the thread safeness mechanism exposed by IntThrSafeCheckThreads should be used before calling this function.

Parameters
[in]OptionsOptions that control the way accesses to the memory region are handled. Must be 0 or a combination of MEMCLOAK_OPTIONS values.
[in,out]RegionThe region to be removed. This pointer will no longer be valid after this function returns.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 885 of file memcloak.c.

Referenced by IntMemClkCloakRegion(), IntMemClkUncloakRegion(), and IntMemClkUnInit().

◆ IntMemClkUnInit()

INTSTATUS IntMemClkUnInit ( void  )

Uninits the memory cloak subsystem.

This is used when introcore unloads and free any internal resources as well as check if there are still cloak regions set. During a normal unload process, when this function is called, there should be no remaining regions set, as whoever sets them is responsible of undoing any changes it has done. However, in that case the remaining regions will be uncloaked, but that may leave the guest in an unstable guest and no other subsystem should depend on this behavior.

Return values
INT_STATUS_SUCCESSalways.

Definition at line 1169 of file memcloak.c.

Referenced by IntGuestUninit().

Variable Documentation

◆ gMemClkRegions

LIST_HEAD gMemClkRegions = LIST_HEAD_INIT(gMemClkRegions)
static

A list containing all the memory regions that are currently hidden from the guest.

Definition at line 54 of file memcloak.c.