Bitdefender Hypervisor Memory Introspection
winvad.c File Reference
#include "winvad.h"
#include "hook.h"
#include "processor.h"
#include "swapmem.h"
#include "winprocesshp.h"
#include "shellcode.h"
#include "winummodule.h"
#include "winthread.h"
#include "exceptions.h"
#include "alerts.h"
#include "scan_engines.h"
#include "winnet.h"

Go to the source code of this file.

Macros

#define VAD_SEARCH_LIMIT   1000
 The maximum number of tries to make when searching for a VAD inside the guest. More...
 
#define MAX_VAD_EXECS   64u
 The maximum number of execution from a VAD that Introcore will take into consideration. More...
 
#define VAD_SHORT_FIELD_PTR(type_, ptr_, field_)   (type_ *)((BYTE *)(ptr_) + WIN_KM_FIELD(VadShort, field_))
 Gives a pointer to a field of a _MMVAD_SHORT structure. More...
 
#define VAD_LONG_FIELD_PTR(type_, ptr_, field_)   (type_ *)((BYTE *)(ptr_) + WIN_KM_FIELD(VadLong, field_))
 Gives a pointer to a field of a _MMVAD_LONG structure. More...
 
#define VadShortByte(ptr_, field_)   *VAD_SHORT_FIELD_PTR(BYTE, ptr_, field_)
 Reads a byte from a VAD short buffer. More...
 
#define VadShortWord(ptr_, field_)   *VAD_SHORT_FIELD_PTR(WORD, ptr_, field_)
 Reads a word from a VAD short buffer. More...
 
#define VadShortDword(ptr_, field_)   *VAD_SHORT_FIELD_PTR(DWORD, ptr_, field_)
 Reads a dword from a VAD short buffer. More...
 
#define VadShortQword(ptr_, field_)   *VAD_SHORT_FIELD_PTR(QWORD, ptr_, field_)
 Reads a qword from a VAD short buffer. More...
 
#define VadShortPtrSize(ptr_, field_)   gGuest.Guest64 ? VadShortQword(ptr_, field_) : VadShortDword(ptr_, field_)
 Reads a guest pointer from a VAD short buffer. More...
 
#define VadShortAnySize(size_, ptr_, field_)
 Reads a certain size from a VAD short buffer. More...
 
#define MAX_LEVEL   64
 

Functions

static INTSTATUS IntWinVadHandleInsertGeneric (WIN_PROCESS_OBJECT *Process, QWORD VadAddress, BOOLEAN StaticScan, VAD **Vad)
 Handles the insertion of a VAD into a process VAD tree. More...
 
static BYTEIntWinVadMapShortVad (QWORD Gva)
 Maps a _MMVAD_SHORT structure inside Introcore. More...
 
static BOOLEAN IntWinVadIsProbablyNaCl (VAD const *Vad)
 Checks if a VAD is used by the Chrome's NaCl mechanism. More...
 
static BOOLEAN IntWinVadIsProbablyDominoJava (VAD const *Vad)
 Checks if a VAD is used by Domino Java. More...
 
static INTSTATUS IntWinVadRemoveRange (VAD *Vad, QWORD StartPage, QWORD EndPage)
 Removes a memory range from a VAD. More...
 
static INTSTATUS IntWinVadRemoveAllPages (VAD *Vad)
 Removes all pages from a VAD. More...
 
void IntWinVadDestroyObject (VAD **Vad)
 Frees a VAD and all the resources held by it. More...
 
static void IntWinVadRbTreeNodeFree (RBNODE *Node)
 The node free callback used by the WIN_PROCESS_OBJECT.VadTree tree. More...
 
static int IntWinVadRbTreeNodeCompare (RBNODE const *Left, RBNODE const *Right)
 The node compare callback used by the WIN_PROCESS_OBJECT.VadTree tree. More...
 
static int IntWinVadRbTreeNodeCompareVa (RBNODE const *Node, void *Key)
 Custom compare function for a VAD RBTREE. This will compare VADs against a given guest virtual address. More...
 
static int IntWinVadRbTreeNodeCompareBases (RBNODE const *Node, void *Key)
 Custom compare function for a VAD RBTREE. This will compare a VAD start page with a given guest virtual address. More...
 
void IntWinVadProcessInit (WIN_PROCESS_OBJECT *Process)
 Initializes a WIN_PROCESS_OBJECT.VadTree. More...
 
static DWORD IntWinVadVmProtectionToIntroProtection (DWORD VmProtection)
 Converts Windows memory protection constants to Introcore protection flags. More...
 
static DWORD IntWinVadVadProtectionToIntroProtection (WIN_VAD_PROT VadProtection)
 Converts Windows VAD protection rights to Introcore protection rights. More...
 
static DWORD IntWinVadVadProtectionToVmProtection (WIN_VAD_PROT VadProtection)
 Converts Windows VAD protection rights to a Windows memory protection constant. More...
 
VADIntWinVadFindByVa (WIN_PROCESS_OBJECT *Process, QWORD Va)
 Finds a VAD that contains a given guest virtual address. More...
 
static VADIntWinVadFindByRange (PWIN_PROCESS_OBJECT Process, QWORD StartPage, QWORD EndPage)
 Finds a VAD by the range it maps. More...
 
static PVAD IntWinVadFindByBase (PWIN_PROCESS_OBJECT Process, QWORD Base)
 Finds a VAD by the start of the virtual address range it represents. More...
 
static INTSTATUS IntWinVadAdjustRange (VAD *Vad, QWORD NewStartPage, QWORD NewEndPage)
 Modifies the range of pages owned by a VAD. More...
 
static INTSTATUS IntWinVadIsExecSuspicious (WIN_PROCESS_OBJECT *Process, QWORD VirtualAddress, QWORD PhysicalAddress, INTRO_ACTION *Action)
 Handle code execution from a memory page. More...
 
static INTSTATUS IntWinVadHandlePageExecution (VAD_PAGE *Context, void const *Hook, QWORD Address, INTRO_ACTION *Action)
 Handles execution attempts from a page owned by a monitored VAD. More...
 
static INTSTATUS IntWinVadHandleFilePathInMemory (VAD *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)
 Handles the swap-in of a file path taken from a Windows VAD structure. More...
 
INTSTATUS IntWinVadRemoveProcessTree (WIN_PROCESS_OBJECT *Process)
 Removes the VAD tree from a process. More...
 
static INTSTATUS IntWinVadFetchVadFromMemory (QWORD VadGva, VAD *Vad, BOOLEAN FailOnCorruptRange)
 Reads a _MMVAD structure from the Windows kernel and creates a corresponding VAD structure. More...
 
static INTSTATUS IntWinVadFetchImageName (VAD *Vad)
 Reads the path of the image file mapped by a _MMVAD_LONG structure. More...
 
static INTSTATUS IntWinVadCreateObject (WIN_PROCESS_OBJECT *Process, QWORD VadGva, VAD **Vad, BOOLEAN StaticScan)
 Creates and initializes a VAD structure. More...
 
INTSTATUS IntWinVadShortDump (QWORD VadNodeGva, DWORD Level, void *Context)
 Prints a _MMVAD_SHORT structure. More...
 
BOOLEAN IntWinVadDump (VAD const *Vad, void *Context)
 Prints a VAD structure. More...
 
static BOOLEAN IntWinVadRemoveRanges (VAD *Vad, void *Context)
 Removes all pages from a VAD. More...
 
void IntWinVadStopExploitMonitor (WIN_PROCESS_OBJECT *Process)
 Disables the exploit monitoring for a process. More...
 
QWORD IntWinVadFindNodeInGuestSpace (QWORD VadRoot, QWORD StartPage, QWORD EndPage, DWORD Level, QWORD OldStartPage, BOOLEAN LastBranchRight)
 Searches for a VAD node inside a guest VAD tree. More...
 
INTSTATUS IntWinVadInOrderRecursiveTraversal (QWORD VadNodeGva, DWORD Level, PFUNC_WinVadTraversalCallback Callback, void *Context)
 Traverses a guest VAD tree. More...
 
INTSTATUS IntWinVadWalkTree (PWIN_PROCESS_OBJECT Process, PFUNC_RbTreeWalkCallback Callback)
 Walks the VAD tree of a process. More...
 
static PVAD IntWinVadRescanVad (WIN_PROCESS_OBJECT *Process, QWORD StartPage, QWORD EndPage)
 Searches for a VAD inside the guest tree and inserts it into our VAD tree. More...
 
VADIntWinVadFindAndUpdateIfNecessary (WIN_PROCESS_OBJECT *Process, QWORD StartHint, QWORD LengthHint)
 Searches for a VAD in the Introcore VAD tree. If no VAD is found, or if the found one does not fully contain the searched range, it will re-scan the guest tree in order to find a matching VAD. If the VAD is taken from the guest, it is inserted in the VAD tree of the given process. More...
 
static INTSTATUS IntWinVadHandleProtectGeneric (WIN_PROCESS_OBJECT *Process, QWORD StartPage, QWORD EndPage, DWORD VmProtection, BOOLEAN AtInsertion)
 Handles a VAD protection change. More...
 
static INTSTATUS IntWinVadReimportProcessTree (WIN_PROCESS_OBJECT *Process)
 Re-scans and re-imports the VAD tree of a process. More...
 
static INTSTATUS IntWinVadHandleDeleteGeneric (WIN_PROCESS_OBJECT *Process, QWORD StartPage, QWORD EndPage, DWORD Level)
 Handles the deletion of a VAD or of memory range from a VAD. More...
 
static INTSTATUS IntWinVadStaticInsertNodeIntoProcess (QWORD VadNodeGva, DWORD Level, WIN_PROCESS_OBJECT *Process)
 Inserts a VAD found by a memory scan inside a Introcore process VAD tree. More...
 
INTSTATUS IntWinVadImportProcessTree (WIN_PROCESS_OBJECT *Process)
 Scans the guest VAD tree and imports the nodes into our VAD tree. More...
 
INTSTATUS IntWinVadHandleInsert (void const *Detour)
 The detour handler that will be invoked when the guest inserts a new VAD in the tree.This is the detour handler for the MiInsertVad guest API. More...
 
INTSTATUS IntWinVadHandleInsertPrivate (void const *Detour)
 The detour handler that will be invoked when the guest inserts a new VAD in the tree.This is the detour handler for the MiInsertPrivateVad guest API. More...
 
INTSTATUS IntWinPatchVadHandleCommit (QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
 This is the PFUNC_PreDetourCallback for the MiCommitExistingVad guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the values of winKmFieldPcrCurrentThread, winKmFieldThreadAttachedProcess, winKmFieldThreadProcess, and winKmFieldProcessSpare. For 32-bit kernels it will also patch the stack location at which the VmProtection parameter is located. More...
 
INTSTATUS IntWinVadHandleCommit (void const *Detour)
 The detour handler that will be invoked when an existing VAD is committed by the guest.This is the detour handler for the MiCommitExistingVad guest API. Due to the way we ignore certain VADs, this can be invoked either when protection is changed for a known VAD, in which case we have to adjust our protection; or, when protection is changed for a previously unknown VAD in a way that makes it relevant for Introcore, in which case we treat as a newly created VAD. More...
 
INTSTATUS IntWinVadHandleInsertMap (void const *Detour)
 The detour handler that will be invoked when a VAD is inserted in the guest VAD tree.This is the detour handler for the MiGetWsAndInsertVad guest API. More...
 
INTSTATUS IntWinVadHandleDeleteVaRange (void const *Detour)
 The detour handler that will be invoked when a memory range contained by a VAD is deleted.This is the detour handler for the MiDeleteVirtualAddresses guest API. More...
 
INTSTATUS IntWinVadHandleFinishVadDeletion (void const *Detour)
 The detour handler that will be invoked when a memory range contained by a VAD is deleted.This is the detour handler for the MiFinishVadDeletion guest API. More...
 
INTSTATUS IntWinVadHandleVirtualProtect (void const *Detour)
 The detour handler that will be invoked when a memory range contained by a VAD has the protection rights changed.This is the detour handler for the MiProtectVirtualMemory guest API, which usually gets called as a result of a user-mode application calling an API like VirtualProtect. More...
 
BOOLEAN IntWinVadIsInTree (const VAD *Vad)
 Checks if a VAD is inserted in a guest VAD tree. More...
 
INTSTATUS IntWinVadPatchInsertPrivate (QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
 This is the PFUNC_PreDetourCallback for the MiInsertPrivateVad guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the value of winKmFieldProcessSpare. More...
 
INTSTATUS IntWinVadPatchInsertMap (QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
 This is the PFUNC_PreDetourCallback for the MiGetWsAndInsertVad guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the value of winKmFieldProcessSpare. More...
 
INTSTATUS IntWinVadPatchVirtualProtect (QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
 This is the PFUNC_PreDetourCallback for the MiProtectVirtualMemory guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the value of winKmFieldProcessSpare. More...
 
INTSTATUS IntWinVadPatchDeleteVaRange (QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
 This is the PFUNC_PreDetourCallback for the MiDeleteVirtualAddresses guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the value of winKmFieldProcessSpare. More...
 
INTSTATUS IntWinVadPatchFinishVadDeletion (QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
 This is the PFUNC_PreDetourCallback for the MiFinishVadDeletion guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the value of winKmFieldProcessSpare. More...
 
INTSTATUS IntWinVadPatchInsert (QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
 This is the PFUNC_PreDetourCallback for the MiInsertVad guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the value of winKmFieldProcessSpare. More...
 
INTSTATUS IntWinVadProcImportMainModuleVad (WIN_PROCESS_OBJECT *Process)
 Imports the VAD that describes the main module of a process. More...
 
INTSTATUS IntWinVadFetchByRange (QWORD VadRoot, QWORD StartPage, QWORD EndPage, VAD *Vad)
 Fetches and returns a VAD object containing the range represented by [StartPage, EndPage]. More...
 

Macro Definition Documentation

◆ MAX_LEVEL

#define MAX_LEVEL   64

◆ MAX_VAD_EXECS

#define MAX_VAD_EXECS   64u

The maximum number of execution from a VAD that Introcore will take into consideration.

Definition at line 21 of file winvad.c.

Referenced by IntWinVadHandleProtectGeneric().

◆ VAD_LONG_FIELD_PTR

#define VAD_LONG_FIELD_PTR (   type_,
  ptr_,
  field_ 
)    (type_ *)((BYTE *)(ptr_) + WIN_KM_FIELD(VadLong, field_))

Gives a pointer to a field of a _MMVAD_LONG structure.

Parameters
[in]type_The type of the field.
[in]ptr_The pointer to the base of the VAD. This is the start of the buffer in which the VAD structure was read. The buffer should be large enough for the requested field to be inside it.
[in]field_The name of the field. This is the same name that would be used for the WIN_KM_FIELD macro.
Returns
A pointer of type type_ inside the VAD buffer.

Definition at line 78 of file winvad.c.

◆ VAD_SEARCH_LIMIT

#define VAD_SEARCH_LIMIT   1000

The maximum number of tries to make when searching for a VAD inside the guest.

Definition at line 19 of file winvad.c.

Referenced by IntWinVadFetchByRange(), IntWinVadFindNodeInGuestSpace(), IntWinVadHandleProtectGeneric(), and IntWinVadRescanVad().

◆ VAD_SHORT_FIELD_PTR

#define VAD_SHORT_FIELD_PTR (   type_,
  ptr_,
  field_ 
)    (type_ *)((BYTE *)(ptr_) + WIN_KM_FIELD(VadShort, field_))

Gives a pointer to a field of a _MMVAD_SHORT structure.

Parameters
[in]type_The type of the field.
[in]ptr_The pointer to the base of the VAD. This is the start of the buffer in which the VAD structure was read (for example, the pointer returned by IntWinVadMapShortVad). The buffer should be large enough for the requested field to be inside it.
[in]field_The name of the field. This is the same name that would be used for the WIN_KM_FIELD macro.
Returns
A pointer of type type_ inside the VAD buffer.

Definition at line 68 of file winvad.c.

◆ VadShortAnySize

#define VadShortAnySize (   size_,
  ptr_,
  field_ 
)
Value:
(size_) == 8 ? VadShortQword(ptr_, field_) : \
(size_) == 4 ? VadShortDword(ptr_, field_) : \
(size_) == 2 ? VadShortWord(ptr_, field_) : \
(size_) == 1 ? VadShortByte(ptr_, field_) : 0
#define VadShortQword(ptr_, field_)
Reads a qword from a VAD short buffer.
Definition: winvad.c:126
#define VadShortDword(ptr_, field_)
Reads a dword from a VAD short buffer.
Definition: winvad.c:114
#define VadShortByte(ptr_, field_)
Reads a byte from a VAD short buffer.
Definition: winvad.c:90
#define VadShortWord(ptr_, field_)
Reads a word from a VAD short buffer.
Definition: winvad.c:102

Reads a certain size from a VAD short buffer.

Parameters
[in]size_Size to read. Valid sizes are 1, 2, 4, or 8. For other sizes memcpy is better suited. No checks are done on the size.
[in]ptr_The pointer to the base of the VAD. This is the start of the buffer in which the VAD structure was read (for example, the pointer returned by IntWinVadMapShortVad). The buffer should be large enough for the requested field to be inside it.
[in]field_The name of the field. This is the same name that would be used for the WIN_KM_FIELD macro.
Returns
The value obtained from the field_. 0 Will be returned for unsupported sizes.

Definition at line 151 of file winvad.c.

Referenced by IntWinVadFetchVadFromMemory().

◆ VadShortByte

#define VadShortByte (   ptr_,
  field_ 
)    *VAD_SHORT_FIELD_PTR(BYTE, ptr_, field_)

Reads a byte from a VAD short buffer.

This is useful for reading _MMVAD_SHORT fields that have a size of a BYTE.

Parameters
[in]ptr_The pointer to the base of the VAD. This is the start of the buffer in which the VAD structure was read (for example, the pointer returned by IntWinVadMapShortVad). The buffer should be large enough for the requested field to be inside it.
[in]field_The name of the field. This is the same name that would be used for the WIN_KM_FIELD macro.
Returns
The first byte of the field_ value inside the _MMVAD_SHORT structure.

Definition at line 90 of file winvad.c.

Referenced by IntWinVadFetchVadFromMemory().

◆ VadShortDword

#define VadShortDword (   ptr_,
  field_ 
)    *VAD_SHORT_FIELD_PTR(DWORD, ptr_, field_)

Reads a dword from a VAD short buffer.

This is useful for reading _MMVAD_SHORT fields that have a size of a DWORD.

Parameters
[in]ptr_The pointer to the base of the VAD. This is the start of the buffer in which the VAD structure was read (for example, the pointer returned by IntWinVadMapShortVad). The buffer should be large enough for the requested field to be inside it.
[in]field_The name of the field. This is the same name that would be used for the WIN_KM_FIELD macro.
Returns
The first dword of the field_ value inside the _MMVAD_SHORT structure.

Definition at line 114 of file winvad.c.

Referenced by IntWinVadFetchVadFromMemory().

◆ VadShortPtrSize

#define VadShortPtrSize (   ptr_,
  field_ 
)    gGuest.Guest64 ? VadShortQword(ptr_, field_) : VadShortDword(ptr_, field_)

Reads a guest pointer from a VAD short buffer.

This is useful for reading _MMVAD_SHORT fields that have the size of a guest pointer (GUEST_STATE.WordSize). This means that it will read either a DWORD or a QWORD.

Parameters
[in]ptr_The pointer to the base of the VAD. This is the start of the buffer in which the VAD structure was read (for example, the pointer returned by IntWinVadMapShortVad). The buffer should be large enough for the requested field to be inside it.
[in]field_The name of the field. This is the same name that would be used for the WIN_KM_FIELD macro.
Returns
The first DWORD or QWORD of the field_ value inside the _MMVAD_SHORT structure.

Definition at line 139 of file winvad.c.

Referenced by IntWinVadFetchVadFromMemory().

◆ VadShortQword

#define VadShortQword (   ptr_,
  field_ 
)    *VAD_SHORT_FIELD_PTR(QWORD, ptr_, field_)

Reads a qword from a VAD short buffer.

This is useful for reading _MMVAD_SHORT fields that have a size of a QWORD.

Parameters
[in]ptr_The pointer to the base of the VAD. This is the start of the buffer in which the VAD structure was read (for example, the pointer returned by IntWinVadMapShortVad). The buffer should be large enough for the requested field to be inside it.
[in]field_The name of the field. This is the same name that would be used for the WIN_KM_FIELD macro.
Returns
The first qword of the field_ value inside the _MMVAD_SHORT structure.

Definition at line 126 of file winvad.c.

Referenced by IntWinVadFetchVadFromMemory().

◆ VadShortWord

#define VadShortWord (   ptr_,
  field_ 
)    *VAD_SHORT_FIELD_PTR(WORD, ptr_, field_)

Reads a word from a VAD short buffer.

This is useful for reading _MMVAD_SHORT fields that have a size of a WORD.

Parameters
[in]ptr_The pointer to the base of the VAD. This is the start of the buffer in which the VAD structure was read (for example, the pointer returned by IntWinVadMapShortVad). The buffer should be large enough for the requested field to be inside it.
[in]field_The name of the field. This is the same name that would be used for the WIN_KM_FIELD macro.
Returns
The first word of the field_ value inside the _MMVAD_SHORT structure.

Definition at line 102 of file winvad.c.

Function Documentation

◆ IntWinVadAdjustRange()

static INTSTATUS IntWinVadAdjustRange ( VAD Vad,
QWORD  NewStartPage,
QWORD  NewEndPage 
)
static

Modifies the range of pages owned by a VAD.

This can happen when the guest deletes part of a VAD. In that case we remove the VAD_PAGE structures allocated for that range and we shrink the VAD.VadPages array and will adjust VAD.PageCount, VAD.StartPage, and VAD.EndPage.

The [NewStartPage, NewEndPage] range is inclusive. All the pages that are not in this range will be removed. The range must be included in the current [VAD.StartPage, VAD.EndPage] range.

Parameters
[in,out]VadThe VAD to adjust.
[in]NewStartPageThe new VAD.StartPage value.
[out]NewEndPageThe new VAD.EndPage value.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INSUFFICIENT_RESOURCESif the new VAD.VadPages array can not be allocated.

Definition at line 695 of file winvad.c.

Referenced by IntWinVadHandleDeleteGeneric().

◆ IntWinVadCreateObject()

static INTSTATUS IntWinVadCreateObject ( WIN_PROCESS_OBJECT Process,
QWORD  VadGva,
VAD **  Vad,
BOOLEAN  StaticScan 
)
static

Creates and initializes a VAD structure.

The VAD is initialized using IntWinVadFetchVadFromMemory. If the type of the VAD is VadImageMap the path of the image will be obtained with IntWinVadFetchImageName. If the type is not VadNone, or VadImageMap, or VadWriteWatch, the VAD is ignored.

Parameters
[in]ProcessThe process that owns the VAD.
[in]VadGvaThe guest virtual address of the _MMVAD structure.
[out]VadOn success, and if the VAD is not ignored, will contain a pointer to the allocated and initialized VAD structure. The caller must free this VAD and release any resources held by it using IntWinVadDestroyObject.
[in]StaticScanTrue if this VAD was discovered by a static scan, instead of being discovered when it was created.
Return values
INT_STATUS_SUCCESSin case of success. This is the only case in which Vad will not point to NULL.
INT_STATUS_NOT_NEEDED_HINTif the VAD is ignored.
INT_STATUS_INSUFFICIENT_RESOURCESif not enough memory is available.

Definition at line 1585 of file winvad.c.

Referenced by IntWinVadHandleInsertGeneric(), and IntWinVadProcImportMainModuleVad().

◆ IntWinVadDestroyObject()

void IntWinVadDestroyObject ( VAD **  Vad)

Frees a VAD and all the resources held by it.

This will remove any pending IntSwapMemReadData transactions, will remove all the VAD_PAGE structures for the VAD, and if this VAD maps a module, that module will be unloaded, as well as dereferencing the WINUM_PATH cache entry.

Parameters
[in,out]VadHolds a pointer to the VAD to be destroyed. On return, this will point to NULL.

Definition at line 285 of file winvad.c.

Referenced by IntWinProcRemoveProcess(), IntWinVadHandleDeleteGeneric(), IntWinVadHandleInsertGeneric(), and IntWinVadRbTreeNodeFree().

◆ IntWinVadDump()

BOOLEAN IntWinVadDump ( VAD const *  Vad,
void *  Context 
)

Prints a VAD structure.

Parameters
[in]VadPointer to the structure to be printed.
[in]ContextIgnored.
Return values
Falseif Vad is NULL; otherwise True.

Definition at line 1706 of file winvad.c.

Referenced by IntWinProcDump(), and IntWinProcDumpVads().

◆ IntWinVadFetchByRange()

INTSTATUS IntWinVadFetchByRange ( QWORD  VadRoot,
QWORD  StartPage,
QWORD  EndPage,
VAD Vad 
)

Fetches and returns a VAD object containing the range represented by [StartPage, EndPage].

Note: The VAD is just completed with the relevant information, there's no need to call IntWinVadDestroyObject on the returned VAD.

Parameters
[in]VadRootThe vad root from where to start the search. It is read from the guest, as the VadRoot field in the EPROCESS structure.
[in]StartPageThe page which represents the start of the range that must be contained in the returned VAD.
[in]EndPageThe page which represents the end of the range that must be contained in the returned VAD.
[out]VadThe returned VAD object.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETER_1If the given VadRoot is equal to 0.
INT_STATUS_INVALID_PARAMETER_4If the given VAD object is NULL.
INT_STATUS_NOT_FOUNDIf there is no such VAD in the tree represented by the given root such that it contains [StartPage, EndPage].

Definition at line 3877 of file winvad.c.

Referenced by IntWinDpiValidateThreadStart(), and IntWinStackHandleUserStackPagedOut().

◆ IntWinVadFetchImageName()

static INTSTATUS IntWinVadFetchImageName ( VAD Vad)
static

Reads the path of the image file mapped by a _MMVAD_LONG structure.

IntSwapMemReadData is used to read the path, so it will not be available until IntWinVadHandleFilePathInMemory will be invoked.

Parameters
[in,out]VadThe VAD for which to read the image name. This must already be initialized by IntWinVadFetchVadFromMemory.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value

Definition at line 1478 of file winvad.c.

Referenced by IntWinVadCreateObject().

◆ IntWinVadFetchVadFromMemory()

static INTSTATUS IntWinVadFetchVadFromMemory ( QWORD  VadGva,
VAD Vad,
BOOLEAN  FailOnCorruptRange 
)
static

Reads a _MMVAD structure from the Windows kernel and creates a corresponding VAD structure.

This function does not initialize any fields related to the optional VAD.Path field. For that, the IntWinVadFetchImageName function must be used.

Parameters
[in]VadGvaThe guest virtual address of the _MMVAD structure.
[out]VadOn success, will be initialized with the relevant information about the VAD, except the Path.
[in]FailOnCorruptRangeExit with an error if the range described by StartPage and EndPage is not a valid range (EndPage must not be less than StartPage).
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INSUFFICIENT_RESOURCESif the VAD structure could not be mapped.
INT_STATUS_INVALID_DATA_STATEif FailOnCorruptRange is TRUE, and the range described by StartPage and EndPage is not valid.

Definition at line 1375 of file winvad.c.

Referenced by IntWinVadCreateObject(), IntWinVadFetchByRange(), IntWinVadFindNodeInGuestSpace(), IntWinVadInOrderRecursiveTraversal(), IntWinVadIsInTree(), and IntWinVadShortDump().

◆ IntWinVadFindAndUpdateIfNecessary()

VAD* IntWinVadFindAndUpdateIfNecessary ( WIN_PROCESS_OBJECT Process,
QWORD  StartHint,
QWORD  LengthHint 
)

Searches for a VAD in the Introcore VAD tree. If no VAD is found, or if the found one does not fully contain the searched range, it will re-scan the guest tree in order to find a matching VAD. If the VAD is taken from the guest, it is inserted in the VAD tree of the given process.

Parameters
[in]ProcessThe process for which the search is done.
[in]StartHintThe start page of the range by which to search for the VAD.
[in]LengthHintThe length of the range by which to search for the VAD. The last page in the range will be StartHint + LengthHint -1, rounded down to page size.
Returns
The found VAD structure, or the newly created VAD structure. NULL if the VAD is not found neither in the Introcore tree, nor the guest tree.

Definition at line 2122 of file winvad.c.

Referenced by IntExceptGetVictimProcess(), and IntWinProcHandleCopyMemory().

◆ IntWinVadFindByBase()

static PVAD IntWinVadFindByBase ( PWIN_PROCESS_OBJECT  Process,
QWORD  Base 
)
static

Finds a VAD by the start of the virtual address range it represents.

The [StartPage, EndPage] range is inclusive.

Parameters
[in]ProcessThe process that owns the VAD tree in which the search is done.
[in]BaseThe base of the virtual address range.
Returns
A pointer to a VAD that starts with Base, or NULL if no VAD is found.

Definition at line 666 of file winvad.c.

◆ IntWinVadFindByRange()

static VAD* IntWinVadFindByRange ( PWIN_PROCESS_OBJECT  Process,
QWORD  StartPage,
QWORD  EndPage 
)
static

Finds a VAD by the range it maps.

The [StartPage, EndPage] range is inclusive.

Parameters
[in]ProcessThe process that owns the VAD tree in which the search is done.
[in]StartPageThe first page in the searched range.
[in]EndPageThe last page in the searched range.
Returns
A pointer to a VAD that matches the given guest virtual address range, or NULL if no VAD is found.

Definition at line 629 of file winvad.c.

Referenced by IntWinVadFindAndUpdateIfNecessary(), IntWinVadHandleDeleteGeneric(), IntWinVadHandleInsertGeneric(), and IntWinVadHandleProtectGeneric().

◆ IntWinVadFindByVa()

VAD* IntWinVadFindByVa ( WIN_PROCESS_OBJECT Process,
QWORD  Va 
)

Finds a VAD that contains a given guest virtual address.

Parameters
[in]ProcessThe process that owns the VAD tree in which the search is done.
[in]VaThe VA for which the search is done.
Returns
A pointer to a VAD that contains the given guest virtual address, or NULL if no VAD is found.

Definition at line 602 of file winvad.c.

Referenced by IntWinVadHandleCommit().

◆ IntWinVadFindNodeInGuestSpace()

QWORD IntWinVadFindNodeInGuestSpace ( QWORD  VadRoot,
QWORD  StartPage,
QWORD  EndPage,
DWORD  Level,
QWORD  OldStartPage,
BOOLEAN  LastBranchRight 
)

Searches for a VAD node inside a guest VAD tree.

This performs an in-order recursive traversal of the guest VAD tree.

The [StartPage, EndPage] range is inclusive.

Parameters
[in]VadRootThe root of the VAD tree. This is usually the value of the VadRoot field of an _EPROCESS structure.
[in]StartPageThe first page of the searched VAD.
[in]EndPageThe last page of the searched VAD.
[in]LevelThe level for which this function is invoked. Should be 0 when starting a new search.
[in]OldStartPageThe start page for the VAD at the previous level. Should be 0 when starting a new search.
[in]LastBranchRightTrue if the last branch taken was the right one. Should be False when starting a new search.
Returns
The guest virtual address of the searched VAD, or 0 if no VAD was found.

Definition at line 1825 of file winvad.c.

Referenced by DbgVadFind(), IntWinVadFetchByRange(), IntWinVadHandleProtectGeneric(), IntWinVadProcImportMainModuleVad(), and IntWinVadRescanVad().

◆ IntWinVadHandleDeleteGeneric()

static INTSTATUS IntWinVadHandleDeleteGeneric ( WIN_PROCESS_OBJECT Process,
QWORD  StartPage,
QWORD  EndPage,
DWORD  Level 
)
static

Handles the deletion of a VAD or of memory range from a VAD.

This is the common handler for these changes and it should be invoked after the OS-specific handler gathers the needed information from the guest.

The [StartPage, EndPage] range is inclusive.

The function will attempt to find a VAD by the provided range. If no VAD is found nothing is done. This is expected since we ignore certain VAD types, but we may still receive deletion events for them.

When a VAD is found there are 4 possible cases:

  • VAD.StartPage and VAD.EndPage match the provided StartPage and EndPage: this means that the entire VAD is deleted - we handle this by removing the VAD node from the WIN_PROCESS_OBJECT.VadTree and by destroying the VAD itself with IntWinVadDestroyObject.
  • VAD.StartPage matches StartPage, but VAD.EndPage is higher than EndPage: this means that a lower sub-range of the VAD is deleted - this is handled by adjusting the VAD range with IntWinVadAdjustRange.
  • VAD.EndPage matches EndPage, but VAD.StartPage is lower than StartPage: this means that an upper sub-range of the VAD is deleted, similar to the previous case - we handle this in the same way, with IntWinVadAdjustRange.
  • VAD.StartPage and VAD.EndPage are both contained inside the VAD: meaning that an internal sub-range is deleted - this is not supported or expected, as VADs can not be split by the Windows kernel. This is usually a a sign that we missed a VAD transition somewhere. In this case we pause the guest, re-import the VAD tree with IntWinVadReimportProcessTree and re-try the deletion. This is the only case in which this function is recursive and it is the reason for which we only allow for Level to be 0 or 1. If this fails, Introcore will try to break into a debugger.

Due to the way IntWinVadFindByRange works, we will always be in a case in which [StartPage, EndPage] are included inside the VAD, and we can not expect for StartPage to be lower than VAD.StartPage, or EndPage to be higher than VAD.EndPage.

Parameters
[in,out]ProcessThe process that owns the deleted VAD.
[in]StartPageThe start of the deleted memory range.
[in]EndPageThe last page in the deleted memory range.
[in]LevelThe number of times this function recursed. Should be 0 when invoked to delete a range. If Level is higher than 1 the function bails out.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_4if Level is greater or equal to 2.
INT_STATUS_INVALID_PARAMETER_2if End page is less than StartPage.

Definition at line 2419 of file winvad.c.

Referenced by IntWinVadHandleDeleteVaRange(), IntWinVadHandleFinishVadDeletion(), and IntWinVadHandleInsertGeneric().

◆ IntWinVadHandleFilePathInMemory()

static INTSTATUS IntWinVadHandleFilePathInMemory ( VAD Context,
QWORD  Cr3,
QWORD  VirtualAddress,
QWORD  PhysicalAddress,
void *  Data,
DWORD  DataSize,
DWORD  Flags 
)
static

Handles the swap-in of a file path taken from a Windows VAD structure.

This is the IntSwapMemReadData callback set by IntWinVadFetchImageName for the path to the image mapped by a long VAD. After this function returns, VAD.PathSwapHandle will be set to NULL.

Parameters
[in]ContextThe VAD from which the path is obtained.
[in]Cr3The CR3 in which the swap-in was made. Ignored.
[in]VirtualAddressThe guest virtual address from which Data is read. Ignored.
[in]PhysicalAddressThe guest physical address to which VirtualAddress translates to. Ignored.
[in]DataData obtained from the guest. This will be the path.
[in]DataSizeThe size of the Data buffer.
[in]FlagsIgnored.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value

Definition at line 1308 of file winvad.c.

Referenced by IntWinVadFetchImageName().

◆ IntWinVadHandleInsertGeneric()

static INTSTATUS IntWinVadHandleInsertGeneric ( WIN_PROCESS_OBJECT Process,
QWORD  VadAddress,
BOOLEAN  StaticScan,
VAD **  Vad 
)
static

Handles the insertion of a VAD into a process VAD tree.

This is the common handler for these changes and it should be invoked after the OS-specific handler gathers the needed information from the guest.

If WIN_PROCESS_OBJECT.MonitorVad is False we do not insert the VAD in the VAD tree and do not monitor it. This can happen when we initially protect a process, but after we obtain its main module path we decide to remove that protection.

When importing an entire VAD tree we may race with the guest: some threads may be freeing memory in the process while we import the tree. The main problem with this is that if parts of that freed memory are reused, when a VAD is created we will fail to insert it into our VAD tree because it overlaps with an existing one. The solution is to delete any overlapping VADs. Note that protecting a freed VAD should have no impact because if that memory is not reused we will only place a hook on their corresponding page table entries, which should not have an impact as those will be unused until the VAs are reallocated, in which case we will delete the old hooks anyway. In theory, for each page in a new VAD there can be an overlapping VAD, so we try to insert the new VAD as many times as there are pages in it.

If needed, the VAD is monitored using IntWinVadHandleProtectGeneric.

Parameters
[in,out]ProcessThe process that owns the VAD.
[in]VadAddressThe guest virtual address of the _MMVAD structure.
[in]StaticScanTrue if this VAD was discovered by a memory scan instead of being discovered when it was created.
[out]VadOn success, will contain a pointer to the new VAD structure. May be NULL.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 2566 of file winvad.c.

Referenced by IntWinVadHandleCommit(), IntWinVadHandleInsert(), IntWinVadHandleInsertMap(), IntWinVadHandleInsertPrivate(), IntWinVadHandleProtectGeneric(), IntWinVadRescanVad(), and IntWinVadStaticInsertNodeIntoProcess().

◆ IntWinVadHandlePageExecution()

static INTSTATUS IntWinVadHandlePageExecution ( VAD_PAGE Context,
void const *  Hook,
QWORD  Address,
INTRO_ACTION Action 
)
static

Handles execution attempts from a page owned by a monitored VAD.

This is the EPT handler set by IntWinVadHandleProtectGeneric for protected VADs.

It uses IntWinVadIsExecSuspicious to decide if the code the guest attempted to execute is malicious or not. If the execution should be blocked and the PROC_OPT_KILL_ON_EXPLOIT protection flag is set for the current process, the process will be killed by injecting a #UD in its context and Action will be set to introGuestRetry, not introGuestNotAllowed. This is because we want the instruction to be retried by the guest, so that the invalid opcode exception can be delivered for the RIP that generated the violation. If the flag is not set, the execution will be blocked by skipping the current instruction. This means that for pages with malicious instructions the guest will generate one exit for every instruction. This can cause serious performance problems.

If the execution is allowed the hook is removed. Since we analyze multiple instructions in the page this is OK, as on the following exits the same code will be analyzed again.

While the process could have an exception handler set and catch the EXCEPTION_ILLEGAL_INSTRUCTION that will be forwarded by the kernel to the process, this is not a problem, as the page will still be hooked and further attempts of executing from it will end up back here - essentially blocking the execution even if the #UD does not kill the process.

However, there is an issue with this blocking mechanism. The probability of it happening seems extremely low, but at least theoretically this chain of events is possible:

  1. the guest tries to execute code from a monitored page.
  2. an EPT violation is triggered.
  3. we conclude that the page is malicious and we block the attempt by injecting an #UD and setting Action to introGuestRetry.
  4. the #UD is not injected, as an interrupt with a higher priority is waiting to be injected, so the hypervisor injects that.
  5. the injected interrupt is handled by the guest kernel, then the interrupted user mode thread resumes execution from the same RIP that previously generated and EPT violation, causing us to go back to step 1.

In theory, it is possible for step 3 to happen each and every time, causing an infinite loop and making the guest look like it hanged.

Just because IntInjectExceptionInGuest succeeded,it does not mean that the exception will actually be injected now, as other exceptions, with a higher priority, may be waiting to be injected. After the guest resumes execution we will be notified about this via the PFUNC_IntEventInjectionCallback mechanism. This does not mean that the execution attempt will succeed, as the guest will be retrying the same instruction and we will handle it again. But it can generate multiple alerts for the same action, and that can be confusing. So we keep a list of injected #UDs, identified by: the process CR3, the RIP from which the guest attempted the execution, the guest virtual address of the _ETHREAD structure for the thread that attempted the execution. See udlist.c for details about this list. On an execution attempt, before trying to analyze the code and before sending an alert, we check if we already tried to inject an #UD for the current context. If there is a previously failed injection we try it again, as the code could not have been modified in the meantime. When the injection succeeds, the entry is removed from the list.

Since shared memory pages can be executable, this poses a problem, as this callback will be invoked for each process that is protected with the PROC_OPT_PROT_EXPLOIT option. This is problematic for a series of reasons: first, we want to send only one alert for the process that actually tried to execute from that page; second, we want to kill only the process that actually attempted the execution. However, we can't simply ignore the invocations done for processes that are not the current process, because if the page is clean we will end up removing the hook only for the current process, but the execution permissions in the EPT will remain unchanged, as multiple processes will have hooked it. In this case we want to analyze the page for every process and remove the hook as needed. However, in order to send the alert only once and to kill only the current process (if needed), the action block action will be taken only for the current process. Due to the way IntWinVadIsExecSuspicious works, the execution attempt will be logged more than once.

This becomes a bit more problematic when the page is shared between processes that are protected and processes that are not protected. If a process that is not protected attempts the execution we allow the action, but it will still trigger a EPT violation for every instruction in that page, which can slow down the guest.

Parameters
[in]ContextThe page for which this callback was invoked.
[in]HookThe hook for which this callback was invoked. Ignored.
[in]AddressThe guest physical address from which the guest attempted the execution.
[out]ActionThe action to be taken.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value

Definition at line 1040 of file winvad.c.

Referenced by IntWinVadHandleProtectGeneric().

◆ IntWinVadHandleProtectGeneric()

static INTSTATUS IntWinVadHandleProtectGeneric ( WIN_PROCESS_OBJECT Process,
QWORD  StartPage,
QWORD  EndPage,
DWORD  VmProtection,
BOOLEAN  AtInsertion 
)
static

Handles a VAD protection change.

This is the common handler for these changes and it should be invoked after the OS-specific handlers gathers the needed information from the guest.

It will update every page in the [StartPage, EndPage] range (the range is inclusive). The VAD_PAGE.RangeStart for each of these pages will be set to the minimum between the current RangeStart and the supplied StartPage; the VAD_PAGE.RangeEnd for each of these paged will be set to the maximum between the current RangeEnd and the supplied EndPage, in order to keep the ranges as large as possible.

If the guest adds the execution rights for these pages, we hook them against executions; if the right is removed we remove our hooks.

Parameters
[in]ProcessThe process for which the change is done.
[in]StartPageThe start of the modified range.
[in]EndPageThe end of the modified range.
[in]VmProtectionThe Windows memory protection constant used for this range. See https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants
[in]AtInsertionTrue if this function is called as a result of a new VAD being inserted in the guest VAD tree; False in all other situations (for example, as a result of a VirtualProtect call). This is used to determine if we should ignore this change, because a user mode program may request a protection change after a VAD is allocated, but if the NoChange flag is set, the kernel will ignore that request.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_MIXif EndPage is lower than StartPage.
INT_STATUS_INVALID_PARAMETER_2if StartPage is not inside the VAD.
INT_STATUS_INVALID_PARAMETER_3if EndPage is not inside the VAD.
INT_STATUS_NOT_INITIALIZED_HINTif the VAD is not found neither in our tree, nor in the guest tree. This is not a problem, as user mode code can request protection changes for invalid address ranges.
INT_STATUS_NOT_NEEDED_HINTif this is a huge VAD, or a mapped executable file, or an attempt to change the protection for a VAD that has the NoChange flag set.
INT_STATUS_INSUFFICIENT_RESOURCESif not enough memory is available.

Definition at line 2161 of file winvad.c.

Referenced by IntWinVadHandleCommit(), IntWinVadHandleInsertGeneric(), and IntWinVadHandleVirtualProtect().

◆ IntWinVadImportProcessTree()

INTSTATUS IntWinVadImportProcessTree ( WIN_PROCESS_OBJECT Process)

Scans the guest VAD tree and imports the nodes into our VAD tree.

Parameters
[in,out]ProcessThe process for which the scan is done. On success, WIN_PROCESS_OBJECT.VadTree will be populated wit the relevant VADs.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1if Process is NULL.
INT_STATUS_NOT_NEEDED_HINTif the process VAD root is not yet initialized. This means that the process does not have any VADs yet, and we will detect all the VADs we need dynamically when they are created.

Definition at line 2768 of file winvad.c.

Referenced by IntWinProcChangeProtectionFlags(), and IntWinVadReimportProcessTree().

◆ IntWinVadInOrderRecursiveTraversal()

INTSTATUS IntWinVadInOrderRecursiveTraversal ( QWORD  VadNodeGva,
DWORD  Level,
PFUNC_WinVadTraversalCallback  Callback,
void *  Context 
)

Traverses a guest VAD tree.

This function is recursive and will call itself for every node in the tree, starting from VadNodeGva. The tree is traversed in order. Recursion is stopped after we go past level 64.

Parameters
[in]VadNodeGvaThe guest virtual address of the node for which this function was called. When starting a new traversal this should be the root of the tree.
[in]LevelThe level for which this function is called. It is used in order to know when to stop the traversal, for trees that seem to have more levels than we can handle. Should be 0 when starting a new search.
[in]CallbackCallback to be invoked for every node in the tree. Errors returned by this callback are not propagated back to the caller.
[in]ContextOptional context to be passed to Callback each time it is invoked.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1if VadNodeGva is not a valid kernel pointer.
INT_STATUS_INVALID_PARAMETER_3if Callback is NULL.

Definition at line 1920 of file winvad.c.

Referenced by DbgDumpVadRoot(), and IntWinVadImportProcessTree().

◆ IntWinVadIsExecSuspicious()

static INTSTATUS IntWinVadIsExecSuspicious ( WIN_PROCESS_OBJECT Process,
QWORD  VirtualAddress,
QWORD  PhysicalAddress,
INTRO_ACTION Action 
)
static

Handle code execution from a memory page.

This function will determine if the instruction execution inside the indicated page is caused by an exploit or not. The main indicators we look after are:

  1. The code location. If the executed instructions are located on the stack, we will generate an alert;
  2. The stack location. If the stack has been pivoted (RSP points outside the known stack), we will generate an alert.
  3. The code behavior. We will emulate instructions starting with VirtualAddress and see if they behave like a shellcode. In addition to these, if 1, 2 & 3 all deem the action legitimate, we will asynchronously request the AV engines to scan the page too. If the AV engines trigger a detection, we won't be able to block the exploit, however, since the detection would be thrown after the code has executed.
Parameters
[in]ProcessThe process which owns the page.
[in]VirtualAddressThe executed virtual address.
[in]PhysicalAddressThe executed physical address (VirtualAddress translates to it).
[in]ActionDesired action.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
  1. Check if the ESP points inside the (known) actual (current) stack;
  2. Check if the address is on the current stack;
  3. Check if the page contains shellcode.

Definition at line 788 of file winvad.c.

Referenced by IntWinVadHandlePageExecution().

◆ IntWinVadIsInTree()

BOOLEAN IntWinVadIsInTree ( const VAD Vad)

Checks if a VAD is inserted in a guest VAD tree.

This function checks that the node for the provided VAD has a valid parent, and that the parent it points to has the VAD either as the Left, or as the Right child.

Parameters
[in]VadThe VAD that will be checked.
Return values
Trueif the VAD is inserted in a tree.
Falseif the VAD is not inserted in a tree.

Definition at line 3437 of file winvad.c.

Referenced by IntModBlockHandlePreInjection(), and IntWinModHandlePreInjection().

◆ IntWinVadIsProbablyDominoJava()

static BOOLEAN IntWinVadIsProbablyDominoJava ( VAD const *  Vad)
static

Checks if a VAD is used by Domino Java.

Java IBM Domino VADs are ignored if their type is Private, protection is VAD_PROT_EXECUTE_READWRITE and the j9jit.dll is already loaded in the current process (the WIN_PROCESS_OBJECT.IsDominoJava flag is set).

Parameters
[in]VadThe VAD structure to check.
Returns
True if the VAD is probably used by Domino Java; False if it is not used.

Definition at line 175 of file winvad.c.

Referenced by IntWinVadHandlePageExecution().

◆ IntWinVadIsProbablyNaCl()

static BOOLEAN IntWinVadIsProbablyNaCl ( VAD const *  Vad)
static

Checks if a VAD is used by the Chrome's NaCl mechanism.

Parameters
[in]VadThe VAD structure to check.
Returns
True if the VAD is probably used by NaCl; False if it is not used.

Definition at line 158 of file winvad.c.

Referenced by IntWinVadHandleInsertGeneric(), and IntWinVadHandleProtectGeneric().

◆ IntWinVadMapShortVad()

static BYTE* IntWinVadMapShortVad ( QWORD  Gva)
static

Maps a _MMVAD_SHORT structure inside Introcore.

This maps the minimum size needed for Introcore to properly parse the VAD. This size is defined by CAMI, see winKmFieldVadShortSize.

Parameters
[in]GvaGuest virtual address to map. No checks are done on this address.
Returns
A pointer to a memory area that contains the mapped VAD. IntVirtMemUnmap should be used to unmap this when it is no longer needed. Internally, IntVirtMemMap is used to map the VAD. If it fails, this function will return NULL.

Definition at line 33 of file winvad.c.

Referenced by IntWinVadFetchVadFromMemory().

◆ IntWinVadProcessInit()

void IntWinVadProcessInit ( WIN_PROCESS_OBJECT Process)

Initializes a WIN_PROCESS_OBJECT.VadTree.

This will call RbPreInit and RbInit for the tree and set IntWinVadRbTreeNodeFree as the RBTREE.NodeFree function and IntWinVadRbTreeNodeCompare as the RBTREE.NodeCompare function.

Parameters
[in,out]ProcessThe process for which the VAD tree will be initialized.

Definition at line 462 of file winvad.c.

Referenced by IntWinProcCreateProcessObject().

◆ IntWinVadProcImportMainModuleVad()

INTSTATUS IntWinVadProcImportMainModuleVad ( WIN_PROCESS_OBJECT Process)

Imports the VAD that describes the main module of a process.

Parameters
[in,out]ProcessThe process that owns the VAD.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1if Process is NULL.

Definition at line 3816 of file winvad.c.

Referenced by IntWinProcCreateProcessObject().

◆ IntWinVadRbTreeNodeCompare()

static int IntWinVadRbTreeNodeCompare ( RBNODE const *  Left,
RBNODE const *  Right 
)
static

The node compare callback used by the WIN_PROCESS_OBJECT.VadTree tree.

This compares the ranges that two VADs map.

Parameters
[in]LeftFirst node to compare.
[in]RightSecond node to compare.
Return values
-1if the range of the Left VAD is lower in memory than that of the Right VAD.
1if the range of the Left VAD is higher in memory than tat of the Left VAD.
0in all other cases. This means that the VADs overlap in some way, but a process can not have overlapping VADs, so this means that the Left and Right VADs are the same.

Definition at line 356 of file winvad.c.

Referenced by IntWinVadProcessInit().

◆ IntWinVadRbTreeNodeCompareBases()

static int IntWinVadRbTreeNodeCompareBases ( RBNODE const *  Node,
void *  Key 
)
static

Custom compare function for a VAD RBTREE. This will compare a VAD start page with a given guest virtual address.

Parameters
[in]NodeNode to be compared.
[in]KeyKey to compare against. In this case, the key is a guest virtual address.
Return values
0if Key is the same as the VAD.StartPage.
-1if the Key is lower in memory than the start of the memory range mapped by the VAD.
1if the Key is higher in memory than the end of the memory range mapped by the VAD.

Definition at line 427 of file winvad.c.

Referenced by IntWinVadFindByBase().

◆ IntWinVadRbTreeNodeCompareVa()

static int IntWinVadRbTreeNodeCompareVa ( RBNODE const *  Node,
void *  Key 
)
static

Custom compare function for a VAD RBTREE. This will compare VADs against a given guest virtual address.

Parameters
[in]NodeNode to be compared.
[in]KeyKey to compare against. In this case, the key is a guest virtual address.
Return values
0if Key is inside the memory range mapped by the VAD.
-1if the Key is lower in memory than the start of the memory range mapped by the VAD.
1if the Key is higher in memory than the end of the memory range mapped by the VAD.

Definition at line 393 of file winvad.c.

Referenced by IntWinVadFindByVa().

◆ IntWinVadRbTreeNodeFree()

static void IntWinVadRbTreeNodeFree ( RBNODE Node)
static

The node free callback used by the WIN_PROCESS_OBJECT.VadTree tree.

Parameters
[in,out]NodePointer to the node to be freed.

Definition at line 340 of file winvad.c.

Referenced by IntWinVadProcessInit().

◆ IntWinVadReimportProcessTree()

static INTSTATUS IntWinVadReimportProcessTree ( WIN_PROCESS_OBJECT Process)
static

Re-scans and re-imports the VAD tree of a process.

This will remove all entries in the current tree and re-create it.

Parameters
[in,out]ProcessThe process for which the re-import is done.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value

Definition at line 2385 of file winvad.c.

Referenced by IntWinVadHandleDeleteGeneric().

◆ IntWinVadRemoveAllPages()

static INTSTATUS IntWinVadRemoveAllPages ( VAD Vad)
static

Removes all pages from a VAD.

This unhooks and frees all the entries in the VAD.VadPages array and frees the array itself at the end.

Parameters
[in,out]VadThe VAD for which the pages will be removed.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value

Definition at line 253 of file winvad.c.

Referenced by IntWinVadDestroyObject(), and IntWinVadRemoveRanges().

◆ IntWinVadRemoveProcessTree()

INTSTATUS IntWinVadRemoveProcessTree ( WIN_PROCESS_OBJECT Process)

Removes the VAD tree from a process.

Parameters
[in,out]ProcessThe process for which the tree is removed.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1if Process is NULL.

Definition at line 1351 of file winvad.c.

Referenced by IntWinProcChangeProtectionFlags(), and IntWinVadReimportProcessTree().

◆ IntWinVadRemoveRange()

static INTSTATUS IntWinVadRemoveRange ( VAD Vad,
QWORD  StartPage,
QWORD  EndPage 
)
static

Removes a memory range from a VAD.

This will remove the execution hook for all the pages in the given range, and will free the VAD_PAGE structures for the given range. The [StartPage, EndPage] range is inclusive.

Errors encountered while unhooking the pages are logged, but are not propagated back to the caller.

Parameters
[in,out]VadThe VAD for which the range is removed.
[in]StartPageThe first page in the VAD.
[in]EndPageThe last page in the VAD.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_NOT_NEEDED_HINTif there are no pages allocated for this VAD.

Definition at line 198 of file winvad.c.

Referenced by IntWinVadHandlePageExecution(), and IntWinVadRemoveAllPages().

◆ IntWinVadRemoveRanges()

static BOOLEAN IntWinVadRemoveRanges ( VAD Vad,
void *  Context 
)
static

Removes all pages from a VAD.

This is simply a wrapper over IntWinVadRemoveAllPages. We needed a wrapper in order to have the right type for RbWalkInorderTree.

Parameters
[in,out]VadThe VAD for which the pages will be removed.
[in]ContextIgnored.
Return values
Falseif Vad is NULL; otherwise True.

Definition at line 1781 of file winvad.c.

Referenced by IntWinVadStopExploitMonitor().

◆ IntWinVadRescanVad()

static PVAD IntWinVadRescanVad ( WIN_PROCESS_OBJECT Process,
QWORD  StartPage,
QWORD  EndPage 
)
static

Searches for a VAD inside the guest tree and inserts it into our VAD tree.

The [StartPage, EndPage] range is inclusive.

Since the guest is running while we're searching for the VAD, sometimes, modifications will take place inside the tree exactly when we're parsing it. This means that we could end up not finding this range, because, for example, a node above our searched node was removed. This can easily be mitigated by attempting several times to search for the VAD - usually, the VAD will be found in the second attempt. We limit this search to 1000 tries.

Parameters
[in,out]ProcessThe process for which the search is done.
[in]StartPageThe first page of the searched VAD.
[in]EndPageThe last page of the searched VAD.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value

Definition at line 2058 of file winvad.c.

Referenced by IntWinVadFindAndUpdateIfNecessary().

◆ IntWinVadShortDump()

INTSTATUS IntWinVadShortDump ( QWORD  VadNodeGva,
DWORD  Level,
void *  Context 
)

Prints a _MMVAD_SHORT structure.

Parameters
[in]VadNodeGvaThe guest virtual address of the _MMVAD_SHORT structure.
[in]LevelThe level at which the node is located inside the VAD tree.
[in]ContextIgnored.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value

Definition at line 1659 of file winvad.c.

Referenced by DbgDumpVadRoot().

◆ IntWinVadStaticInsertNodeIntoProcess()

static INTSTATUS IntWinVadStaticInsertNodeIntoProcess ( QWORD  VadNodeGva,
DWORD  Level,
WIN_PROCESS_OBJECT Process 
)
static

Inserts a VAD found by a memory scan inside a Introcore process VAD tree.

Parameters
[in]VadNodeGvaThe guest virtual address of the VAD node in the guest VAD tree.
[in]LevelThe level at which the node is found.
[in,out]ProcessThe process that owns the VAD.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1if VadNodeGva is not a valid kernel pointer.
INT_STATUS_NOT_NEEDED_HINTif WIN_PROCESS_OBJECT.MonitorVad is False. While walking the guest VAD tree, we may decide to remove the protection of this process, based on the process main module, in which case we no longer care about the VADs.

Definition at line 2718 of file winvad.c.

Referenced by IntWinVadImportProcessTree().

◆ IntWinVadStopExploitMonitor()

void IntWinVadStopExploitMonitor ( WIN_PROCESS_OBJECT Process)

Disables the exploit monitoring for a process.

Parameters
[in,out]ProcessThe process for which to stop the exploit protection.

Definition at line 1811 of file winvad.c.

Referenced by IntWinProcChangeProtectionFlags().

◆ IntWinVadVadProtectionToIntroProtection()

static DWORD IntWinVadVadProtectionToIntroProtection ( WIN_VAD_PROT  VadProtection)
static

Converts Windows VAD protection rights to Introcore protection rights.

Parameters
[in]VadProtectionThe VAD protection rights.
Returns
Introcore protection rights. This will be a combination of PROT_READ, PROT_WRITE, and PROT_EXEC. For unknown VAD protection rights, the value returned is 0.

Definition at line 522 of file winvad.c.

Referenced by IntWinVadFetchVadFromMemory().

◆ IntWinVadVadProtectionToVmProtection()

static DWORD IntWinVadVadProtectionToVmProtection ( WIN_VAD_PROT  VadProtection)
static

Converts Windows VAD protection rights to a Windows memory protection constant.

Parameters
[in]VadProtectionThe VAD protection rights.
Returns
One of the Windows memory protection constants. See https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants

Definition at line 562 of file winvad.c.

Referenced by IntWinVadHandleInsertGeneric().

◆ IntWinVadVmProtectionToIntroProtection()

static DWORD IntWinVadVmProtectionToIntroProtection ( DWORD  VmProtection)
static

Converts Windows memory protection constants to Introcore protection flags.

Parameters
[in]VmProtectionA Windows memory protection constant. See https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants
Returns
Introcore protection rights. This will be a combination of PROT_READ, PROT_WRITE, and PROT_EXEC. If VmProtection is WIN_MM_PAGE_NOACCESS the return value is 0.

Definition at line 481 of file winvad.c.

Referenced by IntWinVadHandleProtectGeneric().

◆ IntWinVadWalkTree()

INTSTATUS IntWinVadWalkTree ( PWIN_PROCESS_OBJECT  Process,
PFUNC_RbTreeWalkCallback  Callback 
)

Walks the VAD tree of a process.

Parameters
[in]ProcessThe process for which the walk is done.
[in]CallbackCallback to be invoked for each node in the tree. If the callback returns False, the walk is stopped. No context is passed to Callback.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_1is Process is NULL.
INT_STATUS_INVALID_PARAMETER_2is Callback is NULL.

Definition at line 2025 of file winvad.c.

Referenced by IntWinProcDump(), and IntWinProcDumpVads().