Bitdefender Hypervisor Memory Introspection
slack.c File Reference

Handles in-guest memory allocations. More...

#include "slack.h"
#include "guests.h"
#include "winpe.h"
#include "alerts.h"

Go to the source code of this file.

Data Structures

struct  _SLACK_SPACE
 

Macros

#define for_each_slack(_var_name)   list_for_each(gSlackAllocations, SLACK_SPACE, _var_name)
 

Typedefs

typedef struct _SLACK_SPACE SLACK_SPACE
 
typedef struct _SLACK_SPACEPSLACK_SPACE
 

Functions

static INTSTATUS IntSlackSendIntegrityAlert (QWORD VirtualAddress, DWORD Size, BYTE Value)
 Sends an integrity alert if the slack buffer not 0-filled/NOP-filled. More...
 
static INTSTATUS IntSlackAllocWindows (BOOLEAN Pageable, QWORD ModuleBase, DWORD Size, QWORD *Buffer, QWORD SecHint)
 Allocate memory inside the guest. More...
 
static INTSTATUS IntSlackAllocLinux (DWORD Size, QWORD *Buffer)
 Allocate slack space on Linux. More...
 
INTSTATUS IntSlackAlloc (QWORD ModuleBase, BOOLEAN Pageable, DWORD Size, QWORD *Buffer, QWORD SecHint)
 Allocate slack inside the guest. More...
 
INTSTATUS IntSlackFree (QWORD Buffer)
 Free slack space. More...
 
void IntSlackUninit (void)
 Uninit the slack system. Must be called only during uninit. More...
 

Variables

static LIST_HEAD gSlackAllocations = LIST_HEAD_INIT(gSlackAllocations)
 

Detailed Description

Handles in-guest memory allocations.

This module deals with in-guest memory allocations. However, it can only allocate guest memory inside the padding area located at the end of MZ/PE sections (Windows) or inside the first 2 pages of the kernel image (Linux). We call this unused space "slack". Generally, this is available because sections rarely use the entire last page, but, because section alignment is usually equal to the size of a page (4K), this leaves some unused space we can claim. For example, if the .text section of the NT image has a virtual size of 0x329838 bytes, this leaves 0x1000 - 0x838 = 0x7C8 (1992) bytes unused inside the last page of the section. (assuming regular 0x1000 section alignment). This is more than enough for our current use-cases. NOTE: Patch-guard protects the sections slack space (it should be filled with zeros). Because of this, when allocating slack space and writing data inside it, make sure you use memcloak in order to hide the written contents, so as to when PatchGuard reads that area, zeros are returned instead.

Definition in file slack.c.

Macro Definition Documentation

◆ for_each_slack

#define for_each_slack (   _var_name)    list_for_each(gSlackAllocations, SLACK_SPACE, _var_name)

Definition at line 56 of file slack.c.

Referenced by IntSlackAllocWindows(), IntSlackFree(), and IntSlackUninit().

Typedef Documentation

◆ PSLACK_SPACE

typedef struct _SLACK_SPACE * PSLACK_SPACE

◆ SLACK_SPACE

typedef struct _SLACK_SPACE SLACK_SPACE

One slack allocation.

Function Documentation

◆ IntSlackAlloc()

INTSTATUS IntSlackAlloc ( QWORD  ModuleBase,
BOOLEAN  Pageable,
DWORD  Size,
QWORD Buffer,
QWORD  SecHint 
)

Allocate slack inside the guest.

Please see the description of the IntSlackAllocWindows function for Windows, and IntSlackAllocLinux for Linux. This function is just a wrapper for them.

Parameters
[in]PageableIf true, the slack space can be allocated inside a pageable section.
[in]ModuleBaseThe kernel module in which we wish to allocate slack space.
[in]SizeSize to be allocated.
[out]BufferWill contain, upon successful return, the guest virtual address of the allocated slack buffer inside the given module.
[in]SecHintOptional section hint - if provided (non-zero), slack will be allocated inside the given section (note that this is a section name, not index).
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails or if enough slack space was not found inside the given module.

Definition at line 437 of file slack.c.

Referenced by IntDetSetHook(), IntLixAgentAllocate(), IntMtblPatchInstruction(), IntSwapgsInstallHandler(), IntWinAgentInjectTrampoline(), and IntWinAgentSelectBootstrapAddress().

◆ IntSlackAllocLinux()

static INTSTATUS IntSlackAllocLinux ( DWORD  Size,
QWORD Buffer 
)
static

Allocate slack space on Linux.

On Linux we don't have space between sections since they aren't aligned. But we do have the first two pages where there should be hypercall_page and theoretically there should be enough space.

Parameters
[in]SizeSize of the buffer to be allocated.
[out]BufferGuest virtual address of the allocated buffer.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails or if enough slack space was not found inside the given module.

Definition at line 328 of file slack.c.

Referenced by IntSlackAlloc().

◆ IntSlackAllocWindows()

static INTSTATUS IntSlackAllocWindows ( BOOLEAN  Pageable,
QWORD  ModuleBase,
DWORD  Size,
QWORD Buffer,
QWORD  SecHint 
)
static

Allocate memory inside the guest.

This function will iterate through all the non-discardable, non-writable, executable sections of module pointed by ModuleBase, and it will search padding areas, between sections, after the virtual size of the given section. Inside this padding area, we can store Introcore specific data. NOTE: This function takes into considerations other code injections that may have been previously done. It will iterate through the list of currently allocated slacks, in order to ensure that it will never return an address that would lead to the corruption of already injected code/data chunks. NOTE: Slack space is a very limited resource (expect roughly a few kilobytes of it to be available inside the NT image, for example), so use it wisely. The main use-cases for the slack space are:

  1. Detour handlers. For each detours function, we place a very small filtering code inside the guest, which is capable of eliminating unwanted VM exits (for example, we don't do a VM exit if a VAD is being allocated inside an unprotected process);
  2. Agent trampoline code;
  3. Agent bootrstrap code. NOTE: Since the slack space is located at the end of sections (in the last page of a section), large allocations will always fail (for example, you could never allocate 4K of slack space). NOTE: Since we expect the slack space to be filled with zeros, this function will fail if it allocates a slack region which is not filled with zeros. Therefore, please make sure that any in-guest slack space is freed when unloading Introcore.
Parameters
[in]PageableIf true, the slack space can be allocated inside a pageable section.
[in]ModuleBaseThe kernel module in which we wish to allocate slack space.
[in]SizeSize to be allocated.
[out]BufferWill contain, upon successful return, the guest virtual address of the allocated slack buffer inside the given module.
[in]SecHintOptional section hint - if provided (non-zero), slack will be allocated inside the given section (note that this is a section name, not index).
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails or if enough slack space was not found inside the given module.

Definition at line 124 of file slack.c.

Referenced by IntSlackAlloc().

◆ IntSlackFree()

INTSTATUS IntSlackFree ( QWORD  Buffer)

Free slack space.

Will free the given buffer allocated inside a loaded modules' slack space.

Parameters
[in]BufferThe allocate slack address.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_FOUNDIf the given slack was not found among the valid allocations.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is used.

Definition at line 499 of file slack.c.

Referenced by IntDetRemoveHandler(), IntLixAgentFree(), IntWinAgentInjectTrampoline(), and IntWinAgentReleaseBootstrapAddress().

◆ IntSlackSendIntegrityAlert()

static INTSTATUS IntSlackSendIntegrityAlert ( QWORD  VirtualAddress,
DWORD  Size,
BYTE  Value 
)
static

Sends an integrity alert if the slack buffer not 0-filled/NOP-filled.

Parameters
[in]VirtualAddressThe beginning guest virtual address of the slack memory region.
[in]SizeThe size of the slack memory region.
[in]ValueThe first value that is not equal to zero.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 60 of file slack.c.

Referenced by IntSlackAllocLinux(), and IntSlackAllocWindows().

◆ IntSlackUninit()

void IntSlackUninit ( void  )

Uninit the slack system. Must be called only during uninit.

Definition at line 536 of file slack.c.

Referenced by IntGuestUninit().

Variable Documentation

◆ gSlackAllocations

LIST_HEAD gSlackAllocations = LIST_HEAD_INIT(gSlackAllocations)
static

Definition at line 54 of file slack.c.