Bitdefender Hypervisor Memory Introspection
winumcache.c File Reference

This module manages module and exports caches. More...

#include "winumcache.h"
#include "crc32.h"
#include "guests.h"
#include "swapmem.h"
#include "winpe.h"
#include "winummodule.h"

Go to the source code of this file.

Functions

static void IntWinModCacheExportNodeFree (RBNODE *Node)
 RB tree free function. More...
 
static int IntWinModCacheExportNodeCompare (RBNODE *Left, RBNODE *Right)
 Compares two RB tree nodes, representing cached exports. More...
 
static int IntWinModCacheExportNodeCompareWithErorr (RBNODE *Node, void *Key)
 Checks if the provided key is inside the given RB tree node. More...
 
static BOOLEAN IntWinModCacheFixNamePointers (RBNODE *Node, void *Module)
 Fixes the names, lens and hashes inside the given RB node, provided the info inside the module. More...
 
WINUM_CACHE_EXPORTIntWinUmCacheGetExportFromRange (WIN_PROCESS_MODULE *Module, QWORD Gva, DWORD Length)
 Tries to find an export in the range [Gva - Length, Gva]. More...
 
WINUM_CACHE_EXPORTIntWinUmModCacheExportFind (WIN_PROCESS_MODULE *Module, DWORD Rva, DWORD ErrorRange)
 Tries to find an export in the range [Rva, Rva + ErrorRange]. More...
 
static INTSTATUS IntWinModCancelExportTransactions (WINUM_MODULE_CACHE *Cache)
 Cancels all pending swap transactions, in any process, for the provided Cache. More...
 
static INTSTATUS IntWinModHandleExportsInMemory (void *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)
 Called as soon as the exports section of a module is swapped in. More...
 
static BOOLEAN IntWinUmModMustCacheExports (DWORD NameHash)
 Checks of the exports of a module need to be cached. More...
 
static WINUM_MODULE_CACHEIntWinModCacheCreate (WIN_PROCESS_MODULE *Module)
 Creates an exports cache entry for the provided module. More...
 
static INTSTATUS IntWinUmModCacheFillExports (WIN_PROCESS_MODULE *Module)
 Fills the exports cache of the provided module with each exported symbol. More...
 
static INTSTATUS IntWinUmModCacheFillHeaders (WIN_PROCESS_MODULE *Module, BYTE *Headers)
 Fills MZ/PE headers information for the provided module. More...
 
static WINUM_MODULE_CACHEIntWinUmModCacheFetch (WIN_PROCESS_MODULE *Module)
 Returns the cache associated with the provided module. More...
 
void IntWinUmModCacheGet (WIN_PROCESS_MODULE *Module)
 Initializes the cache for the provided module. More...
 
static void IntWinUmCacheRemoveCache (WINUM_MODULE_CACHE *Cache)
 Removes a module cache. More...
 
void IntWinUmModCacheRelease (WINUM_MODULE_CACHE *Cache)
 Removes a module cache, if it was written (it's dirty). More...
 
INTSTATUS IntWinUmModCacheSetHeaders (WIN_PROCESS_MODULE *Module, BYTE *Headers)
 Sets the MZ/PE headers in the cache of a given module. More...
 
BOOLEAN IntWinUmCacheIsExportDirRead (WIN_PROCESS_MODULE *Module)
 Checks if the exports directory of the given module has been read. More...
 
void IntWinUmCacheUninit (void)
 Uninit the module cache system. This will remove all cache entries. Use this during Introcore uninit. More...
 

Variables

const DWORD gExportedDirsToCache []
 
LIST_HEAD gWinProcesses
 The list of all the processes inside the guest. More...
 
LIST_HEAD gWinUmCaches = LIST_HEAD_INIT(gWinUmCaches)
 

Detailed Description

This module manages module and exports caches.

Whenever a protected module is loaded, we will create a cache entry representing the module. Inside this cache entry, we will store information regarding the headers and the headers themselves. In addition, we will read and parse all the exports of the indicated module. Note that there is a single cache instance allocated for a given protected module, no matter how many times that module has been loaded, and no matter how many processes have loaded that module. When the first instance of a protected module is loaded, the cache is created and the exports read. Instances loaded after this will simply reference the already existing cache entry. The cache entries will be removed during uninit only. An exception to this mechanism are dirty caches. A cache is considered dirty if it was created from a module loaded by a process that was already created when Introcore was activated. In these cases, we cannot trust the contents of that particular cache, so we will mark it Dirty. Dirty caches are NOT re-used - this means that a Dirty cache is local and private to one module only, and it will be removed when that modules is unloaded. Caches created from freshly created process are NOT dirty, and they can be reused by all subsequent loaded modules.

Definition in file winumcache.c.

Function Documentation

◆ IntWinModCacheCreate()

static WINUM_MODULE_CACHE* IntWinModCacheCreate ( WIN_PROCESS_MODULE Module)
static

Creates an exports cache entry for the provided module.

Parameters
[in]ModuleThe module for which the exports cache will be created.
Returns
The newly created exports cache. NULL if a memory alloc fails.

Definition at line 674 of file winumcache.c.

Referenced by IntWinUmModCacheGet().

◆ IntWinModCacheExportNodeCompare()

static int IntWinModCacheExportNodeCompare ( RBNODE Left,
RBNODE Right 
)
static

Compares two RB tree nodes, representing cached exports.

This function will compare the RVAs of the two WINUM_CACHE_EXPORT structures described by Left and Right.

Parameters
[in]LeftThe left node.
[in]RightThe right node.
Returns
-1 if Left < Right, 0 if Left == Right, 1 if Left > Right.

Definition at line 71 of file winumcache.c.

Referenced by IntWinUmModCacheFillExports().

◆ IntWinModCacheExportNodeCompareWithErorr()

static int IntWinModCacheExportNodeCompareWithErorr ( RBNODE Node,
void *  Key 
)
static

Checks if the provided key is inside the given RB tree node.

The function checks if the provided key (first DWORD) is inside the given node, with a limit given by the second DWORD in the key argument. The node is a WINUM_CACHE_EXPORT structure, and the Rva field is used for comparison.

Parameters
[in]NodeThe RB tree node.
[in]KeyA tuple containing two DWORDs: the first DWORD is the value to find, while the second DWORD is the limit within the RB tree node.
Returns
-1 if the node is smaller than the key, 0 if they are equal, 1 if the node is larger.

Definition at line 103 of file winumcache.c.

Referenced by IntWinUmModCacheExportFind().

◆ IntWinModCacheExportNodeFree()

static void IntWinModCacheExportNodeFree ( RBNODE Node)
static

RB tree free function.

NOTE: Does nothing.

Parameters
[in,out]NodeThe RB tree node to be freed.

Definition at line 55 of file winumcache.c.

Referenced by IntWinUmModCacheFillExports().

◆ IntWinModCacheFixNamePointers()

static BOOLEAN IntWinModCacheFixNamePointers ( RBNODE Node,
void *  Module 
)
static

Fixes the names, lens and hashes inside the given RB node, provided the info inside the module.

Given Module, it will fix the Names, NameLens and NameHashes inside the WINUM_CACHE_EXPORT structure represented by the the Node argument based on the cache belonging to the module. It will also check if the memory related instructions (memcpy, memset, etc.) have been identified in the ntdll module, in which case the MemoryFuncsRead field inside the exports cache will be set.

Parameters
[in]NodeThe RB tree node, representing a WINUM_CACHE_EXPORT structure.
[in]ModuleThe module from which the cache will be used to fixup the names.
Returns
True.

Definition at line 141 of file winumcache.c.

Referenced by IntWinModHandleExportsInMemory().

◆ IntWinModCancelExportTransactions()

static INTSTATUS IntWinModCancelExportTransactions ( WINUM_MODULE_CACHE Cache)
static

Cancels all pending swap transactions, in any process, for the provided Cache.

Parameters
[in]CacheThe module cache whose transactions we wish to cancel.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 318 of file winumcache.c.

Referenced by IntWinModHandleExportsInMemory().

◆ IntWinModHandleExportsInMemory()

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

Called as soon as the exports section of a module is swapped in.

This function will initialize the cache structure for the exports of the given module. In addition, it will cancel all existing transactions for this module's exports, since they were already read (the exports are read a single time no matter how many instances of the associated module exist). The exports of the given module will be read and stored in a RB tree structure for easy & fast lookup. NOTE: At most WINUMCACHE_MAX_EXPORTS exports will be cached. This means that if a module has more than WINUMCACHE_MAX_EXPORTS exports, only the first WINUMCACHE_MAX_EXPORTS will be cached.

Parameters
[in]ContextThe context, representing the WIN_PROCESS_MODULE structure whose exports have just been swapped in.
[in]Cr3The virtual address space. Will usually be the current Cr3.
[in]VirtualAddressThe virtual address that of the first page of the exports.
[in]PhysicalAddressPhysical address of the first exports page.
[in]DataExports data buffer.
[in]DataSizeThe size of the read data.
[in]FlagsUnused.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_OBJECT_TYPEIf any malformation of the PE file or exports directory is detected.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails.

Definition at line 375 of file winumcache.c.

Referenced by IntWinUmModCacheFillExports().

◆ IntWinUmCacheGetExportFromRange()

WINUM_CACHE_EXPORT* IntWinUmCacheGetExportFromRange ( WIN_PROCESS_MODULE Module,
QWORD  Gva,
DWORD  Length 
)

Tries to find an export in the range [Gva - Length, Gva].

Given Module, it will try to find a valid export which lies at most Length bytes before the provided Gva.

Parameters
[in]ModuleThe module where the export is searched.
[in]GvaGva to start the search at.
[in]LengthMaximum number of bytes to search backwards to see if an export is found.
Returns
A pointer to the WINUM_CACHE_EXPORT structure, if an export is found, or NULL if no export is found.

Definition at line 225 of file winumcache.c.

Referenced by IntAlertEptFillFromVictimZone(), IntExceptGetVictimProcess(), IntExceptKernelUserLogWindowsInformation(), IntExceptUserLogWindowsInformation(), IntExceptVerifyExportSig(), and IntSerializeExport().

◆ IntWinUmCacheIsExportDirRead()

BOOLEAN IntWinUmCacheIsExportDirRead ( WIN_PROCESS_MODULE Module)

Checks if the exports directory of the given module has been read.

Returns
True if the exports dir has been read, or false otherwise.

Definition at line 1063 of file winumcache.c.

Referenced by IntAlertEptFillFromVictimZone().

◆ IntWinUmCacheRemoveCache()

static void IntWinUmCacheRemoveCache ( WINUM_MODULE_CACHE Cache)
static

Removes a module cache.

This function will permanently remove the cache entry. Care must be taken to ensure that no modules reference this cache structure (ie, all instances of the module for which this cache was created have unloaded).

Parameters
[in]CacheThe cache entry to be removed.

Definition at line 960 of file winumcache.c.

Referenced by IntWinUmCacheUninit(), and IntWinUmModCacheRelease().

◆ IntWinUmCacheUninit()

void IntWinUmCacheUninit ( void  )

Uninit the module cache system. This will remove all cache entries. Use this during Introcore uninit.

Definition at line 1082 of file winumcache.c.

Referenced by IntWinGuestUninit().

◆ IntWinUmModCacheExportFind()

WINUM_CACHE_EXPORT* IntWinUmModCacheExportFind ( WIN_PROCESS_MODULE Module,
DWORD  Rva,
DWORD  ErrorRange 
)

Tries to find an export in the range [Rva, Rva + ErrorRange].

Given Module, it will try to find a valid export which lies within the [Rva, Rva + ErrorRange] interval.

Parameters
[in]ModuleThe module where the export is searched.
[in]RvaRva to start the search at.
[in]ErrorRangeMaximum interval to search after the provided Rva.
Returns
A pointer to the WINUM_CACHE_EXPORT structure, if an export is found, or NULL if no export is found.

Definition at line 262 of file winumcache.c.

Referenced by IntWinThrHandleQueueApc(), and IntWinUmCacheGetExportFromRange().

◆ IntWinUmModCacheFetch()

static WINUM_MODULE_CACHE* IntWinUmModCacheFetch ( WIN_PROCESS_MODULE Module)
static

Returns the cache associated with the provided module.

This function will iterate the global list of caches, trying to find the cache associated with the provided module. NOTE: Dirty caches (those identified statically) are ignored.

Parameters
[in]ModuleThe module for which we wish to find a cache entry.
Returns
A pointer to a WINUM_MODULE_CACHE structure, if a module cache is found. NULL otherwise.

Definition at line 899 of file winumcache.c.

Referenced by IntWinUmModCacheGet().

◆ IntWinUmModCacheFillExports()

static INTSTATUS IntWinUmModCacheFillExports ( WIN_PROCESS_MODULE Module)
static

Fills the exports cache of the provided module with each exported symbol.

NOTE: Export sections larger than ONE_MEGABYTE will not be parsed.

Parameters
[in]ModuleThe module whose exports will be read & cached.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_ALREADY_INITIALIZED_HINTIf the exports of this module have already been cached.
INT_STATUS_NOT_NEEDED_HINTIf there's no need to cache the exports of this module.
INT_STATUS_NOT_SUPPORTEDIf the exports section exceeds ONE_MEGABYTE in size.

Definition at line 705 of file winumcache.c.

Referenced by IntWinUmModCacheSetHeaders().

◆ IntWinUmModCacheFillHeaders()

static INTSTATUS IntWinUmModCacheFillHeaders ( WIN_PROCESS_MODULE Module,
BYTE Headers 
)
static

Fills MZ/PE headers information for the provided module.

This function will allocate the headers page, it will validate the MZ/PE headers of this module, and it will fill some basic info inside the cache structure (such as IAT/EAT RVA). It will not read the exports.

Parameters
[in]ModuleThe module for which the headers info will be initialized.
[in]HeadersA pointer to a buffer containing the MZ/PE if the indicated module.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_ALREADY_INITIALIZED_HINTIf the headers have already been filled.

Definition at line 790 of file winumcache.c.

Referenced by IntWinUmModCacheSetHeaders().

◆ IntWinUmModCacheGet()

void IntWinUmModCacheGet ( WIN_PROCESS_MODULE Module)

Initializes the cache for the provided module.

If a cache already exists for the indicated module (because an instance of it has already been loaded), it will be used for this module as well. Otherwise, a new cache will be created for this module. If other instances of this module get loaded, they will be able to reuse the same cache structure.

Parameters
[in]ModuleThe module for which the cache is to be created.

Definition at line 936 of file winumcache.c.

Referenced by IntWinModHandleModulePathInMemory().

◆ IntWinUmModCacheRelease()

void IntWinUmModCacheRelease ( WINUM_MODULE_CACHE Cache)

Removes a module cache, if it was written (it's dirty).

NOTE: This function gets called when a module is unloaded. However, we will not destroy the cache, unless it is dirty (it has been loaded statically).

Parameters
[in]CacheThe cache to be removed if dirty.

Definition at line 1000 of file winumcache.c.

Referenced by IntWinModRemoveModule().

◆ IntWinUmModCacheSetHeaders()

INTSTATUS IntWinUmModCacheSetHeaders ( WIN_PROCESS_MODULE Module,
BYTE Headers 
)

Sets the MZ/PE headers in the cache of a given module.

Parameters
[in]ModuleThe module whose headers are to be set.
[in]HeadersBuffer containing the MZ/PE headers.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1025 of file winumcache.c.

Referenced by IntWinModHandleModuleHeadersInMemory().

◆ IntWinUmModMustCacheExports()

static BOOLEAN IntWinUmModMustCacheExports ( DWORD  NameHash)
static

Checks of the exports of a module need to be cached.

Parameters
[in]NameHashThe hash of the module to be checked. If the hash is in the gExportedDirsToCache array, its exports will be cached.
Returns
True if the exports of the indicated module should be cached. False otherwise.

Definition at line 649 of file winumcache.c.

Referenced by IntWinUmModCacheFillExports().

Variable Documentation

◆ gExportedDirsToCache

const DWORD gExportedDirsToCache[]
Initial value:
=
{
}
#define NAMEHASH_KERNELBASE
Definition: winummodule.h:13
#define NAMEHASH_WOW64CPU
Definition: winummodule.h:18
#define NAMEHASH_WININET
Definition: winummodule.h:21
#define NAMEHASH_NTDLL
Definition: winummodule.h:11
#define NAMEHASH_WS2_32
Definition: winummodule.h:20
#define NAMEHASH_WOW64
Definition: winummodule.h:16
#define NAMEHASH_USER32
Definition: winummodule.h:14
#define NAMEHASH_KERNEL32
Definition: winummodule.h:12
#define NAMEHASH_WOW64WIN
Definition: winummodule.h:17

The list of hashes for libraries we wish to cache.

Definition at line 36 of file winumcache.c.

Referenced by IntWinUmModMustCacheExports().

◆ gWinProcesses

LIST_HEAD gWinProcesses

The list of all the processes inside the guest.

Definition at line 11 of file winprocesshp.c.

◆ gWinUmCaches

LIST_HEAD gWinUmCaches = LIST_HEAD_INIT(gWinUmCaches)

Definition at line 51 of file winumcache.c.