Bitdefender Hypervisor Memory Introspection
swapmem.h File Reference
#include "introtypes.h"

Go to the source code of this file.

Macros

#define SWAPMEM_FLAG_ASYNC_CALL   0x00000001
 
#define SWAPMEM_FLAG_ENTRY_XD   0x00000002
 
#define SWAPMEM_OPT_NO_FAULT   0x00000001
 If set, no PF will be injected. Introcore will wait for the pages to be naturally swapped in. More...
 
#define SWAPMEM_OPT_UM_FAULT   0x00000002
 If set, the PF must be injected only while in user-mode. Use it when reading user-mode memory. More...
 
#define SWAPMEM_OPT_KM_FAULT   0x00000004
 
#define SWAPMEM_OPT_BP_FAULT   0x00000010
 If set, the #PF will be generated from an int3 detour. Use this when injecting kernel PFs. More...
 
#define SWAPMEM_OPT_RW_FAULT   0x00000020
 If set, the PF will be generated with write access. Useful when CoW must be done. More...
 
#define SWAPMEM_OPT_NO_DUPS   0x80000000
 If set, will make sure that a single PF is scheduled for this page. More...
 

Typedefs

typedef INTSTATUS(* PFUNC_PagesReadCallback) (void *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)
 Called when all the required data is available. More...
 
typedef INTSTATUS(* PFUNC_PreInjectCallback) (void *Context, QWORD Cr3, QWORD VirtualAddress)
 Called before injecting a PF inside the guest. More...
 

Functions

INTSTATUS IntSwapMemReadData (QWORD Cr3, QWORD VirtualAddress, DWORD Length, DWORD Options, void *Context, DWORD ContextTag, PFUNC_PagesReadCallback Callback, PFUNC_PreInjectCallback PreInject, void **SwapHandle)
 Reads a region of guest virtual memory, and calls the indicated callback when all the data is available. More...
 
INTSTATUS IntSwapMemInjectPendingPF (void)
 Inject a PF for a pending page. More...
 
void IntSwapMemCancelPendingPF (QWORD VirtualAddress)
 Cancel a pending PF. More...
 
void IntSwapMemReinjectFailedPF (void)
 Reinject timed-out PFs. More...
 
INTSTATUS IntSwapMemRemoveTransaction (void *Transaction)
 Remove a transaction. More...
 
INTSTATUS IntSwapMemRemoveTransactionsForVaSpace (QWORD Cr3)
 Remove all transactions initiated for a virtual address space. More...
 
INTSTATUS IntSwapMemInit (void)
 Init the swapmem system. More...
 
INTSTATUS IntSwapMemUnInit (void)
 Uninit the swapmem system. More...
 
void IntSwapMemDump (void)
 Dump all active transactions & pages. More...
 

Macro Definition Documentation

◆ SWAPMEM_FLAG_ASYNC_CALL

#define SWAPMEM_FLAG_ASYNC_CALL   0x00000001

This means that the callback was invoked after a PF injection. Otherwise, the callback has been invoked before returning from the IntSwapMemRead function.

Definition at line 12 of file swapmem.h.

Referenced by IntSwapMemPageSwappedIn(), IntWinGuestSectionInMemory(), IntWinHalSectionInMemory(), IntWinObjHandleDriverDirectoryEntryInMemory(), IntWinObjHandleObjectInMemory(), and IntWinObjParseDriverDirectory().

◆ SWAPMEM_FLAG_ENTRY_XD

#define SWAPMEM_FLAG_ENTRY_XD   0x00000002

If set, than the newly mounted entry is installed as XD. This will be set if any page inside the read area is XD.

Definition at line 15 of file swapmem.h.

Referenced by IntSwapMemPageSwappedIn(), and IntSwapMemReadData().

◆ SWAPMEM_OPT_BP_FAULT

◆ SWAPMEM_OPT_KM_FAULT

#define SWAPMEM_OPT_KM_FAULT   0x00000004

If set, the PF must be injected only while in kernel-mode. Use it when reading kernel-mode memory. Note, however, that the PF will be injected as soon as possible, and may result in a bug-check. It is recommended to use SWAPMEM_OPT_BP_FAULT instead.

Definition at line 25 of file swapmem.h.

Referenced by IntSwapMemInjectPendingPF().

◆ SWAPMEM_OPT_NO_DUPS

#define SWAPMEM_OPT_NO_DUPS   0x80000000

If set, will make sure that a single PF is scheduled for this page.

Definition at line 31 of file swapmem.h.

Referenced by IntSwapMemReadData(), IntWinStackHandleUserStackPagedOut(), and IntWinVadIsExecSuspicious().

◆ SWAPMEM_OPT_NO_FAULT

#define SWAPMEM_OPT_NO_FAULT   0x00000001

If set, no PF will be injected. Introcore will wait for the pages to be naturally swapped in.

Definition at line 19 of file swapmem.h.

Referenced by IntSwapMemInjectPendingPF(), and IntWinDrvProtect().

◆ SWAPMEM_OPT_RW_FAULT

#define SWAPMEM_OPT_RW_FAULT   0x00000020

If set, the PF will be generated with write access. Useful when CoW must be done.

Definition at line 29 of file swapmem.h.

Referenced by IntSwapMemInjectPendingPF(), IntSwapMemReadData(), and IntWinDagentHandleVerifierReason().

◆ SWAPMEM_OPT_UM_FAULT

Typedef Documentation

◆ PFUNC_PagesReadCallback

typedef INTSTATUS(* PFUNC_PagesReadCallback) (void *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)

Called when all the required data is available.

This callback is called as soon as all the data has been read from guest memory. The callback may be called even before returning from IntSwapMemReadData, if all the pages are present in physical memory. If at least one page is missing, the callback will be called later, after the pages have been swapped in, and all the data has been read.

Parameters
[in]ContextOptional context, as passed to the IntSwapMemReadData function.
[in]Cr3The virtual address space.
[in]VirtualAddressThe base virtual address read.
[in]PhysicalAddressThe physical address of the first page (VirtualAddress) read.
[in]DataBuffer containing the read data. This will be freed once the callback returns!
[in]DataSizeSize of the Data buffer. Will normally be equal to the Length passed to read function.
[in]FlagsSwap flags. Check out SWAPMEM_FLG* for more info.

Definition at line 52 of file swapmem.h.

◆ PFUNC_PreInjectCallback

typedef INTSTATUS(* PFUNC_PreInjectCallback) (void *Context, QWORD Cr3, QWORD VirtualAddress)

Called before injecting a PF inside the guest.

This callback is called before injecting a PF inside the guest. If it returns INT_STATUS_NOT_NEEDED_HINT, the PF will no longer be injected. This may be useful if the caller wishes to inhibit PF injection in certain cases (for example, you may want to check the existence of a VAD before injecting a PF for a newly loaded module). NOTE: This callback is optional. If it is not used, the PF will be injected as soon as possible, when the scheduler decides it is safe.

Parameters
[in]ContextContext, as passed to the IntSwapMemReadData function.
[in]Cr3The virtual address space.
[in]VirtualAddressThe address the PF is about to be injected for.
Return values
INT_STATUS_NOT_NEEDED_HINTIf the PF should not be injected.

Definition at line 80 of file swapmem.h.

Function Documentation

◆ IntSwapMemCancelPendingPF()

void IntSwapMemCancelPendingPF ( QWORD  VirtualAddress)

Cancel a pending PF.

Cancel the pending PF on the provided VirtualAddress. This can happen if we requested a PF injection, but the HV had to inject something else. In this case, we cancel the injection, and we mark the page Ready, allowing it to be re-injected later.

Parameters
[in]VirtualAddressThe virtual address the PF was requested for.

Definition at line 879 of file swapmem.c.

Referenced by IntHandleEventInjection(), and IntSwapMemHandleBreakpointAgent().

◆ IntSwapMemDump()

void IntSwapMemDump ( void  )

Dump all active transactions & pages.

Definition at line 1066 of file swapmem.c.

◆ IntSwapMemInit()

INTSTATUS IntSwapMemInit ( void  )

Init the swapmem system.

Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1026 of file swapmem.c.

Referenced by IntGuestInit().

◆ IntSwapMemInjectPendingPF()

INTSTATUS IntSwapMemInjectPendingPF ( void  )

Inject a PF for a pending page.

This is the main PF scheduling algorithm. This is called before returning from every callback, and it checks the list of existing transactions & pages, in order to inject a PF inside the guest. Note that only a single PF can be injected at any given time (even if we have multiple VCPUs), as this makes the scheduler much simpler, and it avoids spamming the guest kernel with unexpected PFs. Before injecting a PF, it makes sure the context is right (user/kernel, CR3), and it calls the PreInjectCallback; of the PreInject callback does not return INT_STATUS_SUCCESS, the PF for that page will not be injected, and another page will be selected. PFs can be either injected directly (user-mode PFs, when the context is right) or indirectly (kernel-mode PFs) via the breakpoint agent. No other PFs will be injected until the pending one has been handled (the page has been swapped in).

Return values
INT_STATUS_SUCCESSOn success.

Definition at line 698 of file swapmem.c.

Referenced by IntGuestPreReturnCallback().

◆ IntSwapMemReadData()

INTSTATUS IntSwapMemReadData ( QWORD  Cr3,
QWORD  VirtualAddress,
DWORD  Length,
DWORD  Options,
void *  Context,
DWORD  ContextTag,
PFUNC_PagesReadCallback  Callback,
PFUNC_PreInjectCallback  PreInject,
void **  SwapHandle 
)

Reads a region of guest virtual memory, and calls the indicated callback when all the data is available.

The function will read Length bytes from VirtualAddress inside Cr3 address space. The function may either read the data directly, if it is present inside the physical memory, or it may inject a page fault in order to force a swap-in of the pages containing the data. Callback will be invoked when all the data has been read. The callback may be invoked synchronously or asynchronously: if a page fault is needed to read parts of the data, it will invoked asynchronously. Otherwise, it will be invoked synchronously. The flag SWAPMEM_FLAG_ASYNC_CALL will be set in the Flags argument of the callback for asynchronously calls. The function can be used to read data of arbitrary length (including data spanning multiple pages). Some pages may be swapped in as a result of us injecting a PF for them, others may be swapped in naturally due to the normal guest activity, and other pages may already be present when calling this function. The PreInject callback will be called before actually injecting a PF inside the guest. This callback is optional, but if it present and it returns INT_STATUS_NOT_NEEDED_HINT, the PF will be inhibited, and therefore, it will not be injected.

Parameters
[in]Cr3Virtual address space where we wish to read data from.
[in]VirtualAddressGuest virtual address we wish to read from.
[in]LengthLength, in bytes. Can span multiple pages.
[in]OptionsOptions. Check out SWAPMEM_OPT* for more info.
[in]ContextOptional context to be passed to the callbacks.
[in]ContextTagIf Context is provided and ContextTag is not 0, the Context will be freed when removing the transaction.
[in]CallbackCalled once all the data is available.
[in]PreInjectCallback invoked BEFORE injecting the PF. If this returns INT_STATUS_NOT_NEEDED_HINT, the PF will not be injected.
[out]SwapHandleContains, upon return, a handle to the swap object. If SWAPMEM_OPT_NO_DUPS is used and a transaction is already present, SwapHandle will be set to NULL. Since the transactions are not reference counted, it would be problematic to return a handle, as it can then get freed more than once.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails.

Definition at line 417 of file swapmem.c.

Referenced by DbgSwap(), IntWinDagentCheckSuspiciousDllLoad(), IntWinDagentHandleVerifierReason(), IntWinDrvProtect(), IntWinGetPrcoCmdLineHandleCmdLineInMemory(), IntWinGetPrcoCmdLineHandleUserParamsInMemory(), IntWinGuestFindDriversNamespace(), IntWinGuestNew(), IntWinGuestReadKernel(), IntWinHalFindPerformanceCounter(), IntWinHalReadHal(), IntWinModBlockBlockModuleLoad(), IntWinModHandleModulePathInMemory(), IntWinObjHandleDirectoryEntryInMemory(), IntWinObjHandleDriverDirectoryEntryInMemory(), IntWinObjHandleObjectInMemory(), IntWinObjHandleRootDirTagInMemory(), IntWinObjParseDriverDirectory(), IntWinProcReadCommandLine(), IntWinStackHandleUserStackPagedOut(), IntWinUmModCacheFillExports(), IntWinVadFetchImageName(), and IntWinVadIsExecSuspicious().

◆ IntSwapMemReinjectFailedPF()

void IntSwapMemReinjectFailedPF ( void  )

Reinject timed-out PFs.

Sometimes, injected PFs may get lost, mainly due to the HV, or may be dropped unexpectedly inside the guest. We detect this by maintaining a time-stamp for each pending PF, and retrying the injection after aprox. 1s. Note that reinjecting a PF more than once is not an issue, as the OS can handle this kind of spurious PFs.

Definition at line 913 of file swapmem.c.

Referenced by IntHandleTimer().

◆ IntSwapMemRemoveTransaction()

INTSTATUS IntSwapMemRemoveTransaction ( void *  Transaction)

Remove a transaction.

Once a transaction is removed, the callback will no longer be called, and the swap hooks will be removed. The data will no longer be available. This should be called, for example, when there is a pending read for a process that is just terminating.

Parameters
[in]TransactionThe transaction to be removed.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.

Definition at line 942 of file swapmem.c.

Referenced by IntWinDrvUnprotect(), IntWinGuestCancelKernelRead(), IntWinHalCancelRead(), IntWinModBlockRemoveBlockObject(), IntWinModCancelExportTransactions(), IntWinModRemoveModule(), IntWinObjCancelRootTransactions(), IntWinObjCleanup(), IntWinProcRemoveProcess(), IntWinProcSwapOut(), and IntWinVadDestroyObject().

◆ IntSwapMemRemoveTransactionsForVaSpace()

INTSTATUS IntSwapMemRemoveTransactionsForVaSpace ( QWORD  Cr3)

Remove all transactions initiated for a virtual address space.

Will remove all active transactions for the given VA space. The read-data callback will not be called for any of the aborted transactions. Useful when a process is terminating.

Parameters
[in]Cr3The virtual address space.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 982 of file swapmem.c.

Referenced by IntWinProcRemoveProcess(), and IntWinProcSwapOut().

◆ IntSwapMemUnInit()

INTSTATUS IntSwapMemUnInit ( void  )

Uninit the swapmem system.

Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZED_HINTIf the system has not been initialized.

Definition at line 1044 of file swapmem.c.

Referenced by IntGuestUninit().