Bitdefender Hypervisor Memory Introspection
winsecdesc.c File Reference
#include "introcore.h"
#include "winsecdesc.h"
#include "guests.h"
#include "hook.h"
#include "alerts.h"
#include "gpacache.h"
#include "kernvm.h"
#include "crc32.h"

Go to the source code of this file.

Macros

#define INT_MAX_ACE_COUNT   1820
 The maximum number of ACEs that are allowed within a single ACL. "The maximum size of an ACL is 64 kilobytes (KB), or approximately 1,820 ACEs." https://docs.microsoft.com/en-us/troubleshoot/windows-server/windows-security/error-add-user-to-security-permissions. More...
 
#define INT_SID_CHAR_SIZE   512
 
#define INT_MAX_SUB_AUTHORITY_COUT   30
 

Functions

 STATIC_ASSERT (sizeof(ACL)==sizeof(QWORD), "Sizeof of ACL is not a QWORD")
 We are using the EXCEPTION_VICTIM_ZONE.WriteInfo to send the New/Old SACL/DACL. More...
 
 STATIC_ASSERT (INTRO_SECURITY_DESCRIPTOR_SIZE >(sizeof(SECURITY_DESCRIPTOR)+2 *sizeof(ACL)), "INTRO_SECURITY_DESCRIPTOR_SIZE is too small")
 Make sure the buffer is big enough - at least for the headers. More...
 
static char * IntWinSDGetAceTypeName (BYTE AceTypeValue)
 This function obtains the printable name for a given ACE type. More...
 
INTSTATUS IntWinSDFindAcls (DWORD BufferSize, BYTE *SecurityDescriptorBuffer, DWORD *ReadSize, ACL **Sacl, ACL **Dacl)
 This function looks for the Sacl/Dacl within the SecurityDescriptorBuffer and makes sure they are within the buffer range. More...
 
static BOOLEAN IntWinSDIsAceInsideAcl (ACL *Acl, ACE_HEADER *Ace)
 This function checks whether the ACE fits inside the ACL (the ACL structure must be obtained using IntWinSDFindAcls). More...
 
static BOOLEAN IntWinSDIsAceInsideBuffer (BYTE *Buffer, DWORD BufferSize, ACE_HEADER *Ace)
 This function checks whether the ACE fits inside the given buffer. More...
 
INTSTATUS IntWinSDReadSecDesc (QWORD SecurityDescriptorGva, DWORD BufferSize, BYTE *SecurityDescriptorBuffer, DWORD *ReadSize, ACL **Sacl, ACL **Dacl)
 This function reads the ACLs (along with the ACEs) from the given GVA and returns the data using the provided buffer and the Sacl/Dacl pointers. This function will read the SECURITY_DESCRIPTOR structure that acts as a header, the SACL header and then use the SACL size to find the DACL. If an attacker were to alter the SACL/DACL size such that it will not fit in the given buffer, the function will fail with INT_STATUS_DATA_BUFFER_TOO_SMALL - check the returned Sacl/Dacl values. More...
 
static void IntWinSDDumpAclEntries (ACL *Acl, BOOLEAN IsSacl, BYTE *SecurityDescriptorBuffer, DWORD BufferSize)
 This function dumps the access control entries (ACE) for a given access control list (ACL). More...
 
static void IntWinSDDumpSecDesc (WIN_PROCESS_OBJECT *Process, BYTE *SecurityDescriptorBuffer, DWORD BufferSize, BOOLEAN Original)
 This function dumps the security descriptor for a given process. More...
 
static INTSTATUS IntWinSDGatherAcl (WIN_PROCESS_OBJECT *Process)
 This function gathers the 2 ACLs (SACL/DACL) and stores them in the WIN_PROCESS_OBJECT structure of the given process (the data will later be used for integrity checks and DPI). More...
 
static INTSTATUS IntWinSDFetchSecDescAddress (WIN_PROCESS_OBJECT *Process, QWORD *SecurityDescriptorAddressGva)
 This function reads the security descriptor address for the given process using the GPA cache. More...
 
INTSTATUS IntWinSDProtectSecDesc (WIN_PROCESS_OBJECT *Process)
 This function saves the security descriptor address and ACLs into the WIN_PROCESS_OBJECT structure. More...
 
static INTSTATUS IntWinSDFetchSecDescValues (WIN_PROCESS_OBJECT *Process, QWORD *OldValue, QWORD *NewValue)
 This function obtains the original security descriptor value (from the WIN_PROCESS_OBJECT structure) and the current value (by reading the guest memory using GPA cache). More...
 
BOOLEAN IntWinSDIsSecDescPtrAltered (WIN_PROCESS_OBJECT *Process, WIN_PROCESS_OBJECT **VictimProcess, QWORD *OldValue, QWORD *NewValue)
 This function checks if the security descriptor pointer of a process has been altered or not. More...
 
BOOLEAN IntWinSDIsAclEdited (WIN_PROCESS_OBJECT *Process, DWORD BufferSize, BYTE *SecurityDescriptorBuffer, DWORD *ReadSize, ACL **NewSacl, ACL **NewDacl)
 This function reads the ACLs for the given process (returning the data using the provided buffer and the Sacl/Dacl pointers) and then compares the read data with the one stored within the WIN_PROCESS_OBJECT structure. More...
 
static INTSTATUS IntWinSDSendSecDescIntViolation (WIN_PROCESS_OBJECT *Process, WIN_PROCESS_OBJECT *Victim, QWORD OldValue, QWORD NewValue, BYTE *SecDescBuffer, DWORD SecDescSize, DWORD SecDescHash, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
 This function sends an integrity violation caused by a modified security descriptor pointer. More...
 
static INTSTATUS IntWinSDSendAclIntegrityViolation (WIN_PROCESS_OBJECT *Process, BYTE *SecDescBuffer, DWORD SecDescSize, DWORD SecDescHash, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
 This function sends an integrity violation caused by a modified ACL (SACL/DACL). More...
 
static void IntWinSDClearAclEnd (ACL *Acl, WORD CalculatedSize)
 This function clears the last bytes of the ACL in case the ACL size is greater than the sum of its ACEs. More...
 
static void IntWinSDProcessAcl (ACL *Acl)
 This function clears the SIDs that have more than one sub authority for a given ACL. More...
 
static INTSTATUS IntWinSDCheckSecDescIntegrity (WIN_PROCESS_OBJECT *Process)
 This function checks the integrity of the security descriptor for the given process. In case the security descriptor pointer has been altered, the VCPUs will be paused in order to restore the original value, the victim process will be found (in case there is one) and an alert will be sent. More...
 
static INTSTATUS IntWinSDCheckAclIntegrity (WIN_PROCESS_OBJECT *Process)
 This function checks the integrity of the ACLs (SACL/DACL) for the given process. In case the ACLs have been altered, the VCPUs will be paused in order to restore the original value and an alert will be sent. More...
 
TIMER_FRIENDLY INTSTATUS IntWinSDCheckIntegrity (void)
 This function checks the integrity of the security descriptor for all the processes inside gWinProcesses. More...
 

Variables

LIST_HEAD gWinProcesses
 The list of all the processes inside the guest. More...
 

Macro Definition Documentation

◆ INT_MAX_ACE_COUNT

#define INT_MAX_ACE_COUNT   1820

The maximum number of ACEs that are allowed within a single ACL. "The maximum size of an ACL is 64 kilobytes (KB), or approximately 1,820 ACEs." https://docs.microsoft.com/en-us/troubleshoot/windows-server/windows-security/error-add-user-to-security-permissions.

Definition at line 108 of file winsecdesc.c.

Referenced by IntWinSDDumpAclEntries(), and IntWinSDProcessAcl().

◆ INT_MAX_SUB_AUTHORITY_COUT

#define INT_MAX_SUB_AUTHORITY_COUT   30

Referenced by IntWinSDDumpAclEntries().

◆ INT_SID_CHAR_SIZE

#define INT_SID_CHAR_SIZE   512

Referenced by IntWinSDDumpAclEntries().

Function Documentation

◆ IntWinSDCheckAclIntegrity()

static INTSTATUS IntWinSDCheckAclIntegrity ( WIN_PROCESS_OBJECT Process)
static

This function checks the integrity of the ACLs (SACL/DACL) for the given process. In case the ACLs have been altered, the VCPUs will be paused in order to restore the original value and an alert will be sent.

Parameters
[in]ProcessThe process to be saved.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZED_HINTIf the SecurityDescriptor GVA is NULL.

Definition at line 1485 of file winsecdesc.c.

Referenced by IntWinSDCheckIntegrity().

◆ IntWinSDCheckIntegrity()

TIMER_FRIENDLY INTSTATUS IntWinSDCheckIntegrity ( void  )

This function checks the integrity of the security descriptor for all the processes inside gWinProcesses.

Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1656 of file winsecdesc.c.

Referenced by IntHandleTimer().

◆ IntWinSDCheckSecDescIntegrity()

static INTSTATUS IntWinSDCheckSecDescIntegrity ( WIN_PROCESS_OBJECT Process)
static

This function checks the integrity of the security descriptor for the given process. In case the security descriptor pointer has been altered, the VCPUs will be paused in order to restore the original value, the victim process will be found (in case there is one) and an alert will be sent.

Parameters
[in]ProcessThe process to be saved.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_SKIP_OTHER_CALLBACKSIf the security descriptor has been patched and there is no need for the ACL checks.

Definition at line 1293 of file winsecdesc.c.

Referenced by IntWinSDCheckIntegrity().

◆ IntWinSDClearAclEnd()

static void IntWinSDClearAclEnd ( ACL Acl,
WORD  CalculatedSize 
)
static

This function clears the last bytes of the ACL in case the ACL size is greater than the sum of its ACEs.

Parameters
[in,out]AclThe access control entry to be cleared (SACL/DACL).
[in]CalculatedSizeThe calculated size of the ACEs contained within the ACL.

Definition at line 1206 of file winsecdesc.c.

Referenced by IntWinSDProcessAcl().

◆ IntWinSDDumpAclEntries()

static void IntWinSDDumpAclEntries ( ACL Acl,
BOOLEAN  IsSacl,
BYTE SecurityDescriptorBuffer,
DWORD  BufferSize 
)
static

This function dumps the access control entries (ACE) for a given access control list (ACL).

Parameters
[in]AclThe ACL to dump the entries for.
[in]IsSaclTRUE is the ACL is Sacl, FALSE otherwise (Dacl) - used for logging.
[in]SecurityDescriptorBufferThe security descriptor buffer.
[in]BufferSizeThe size of the security descriptor buffer.

The size of the printable SID buffer.

The maximum number of sub authorities - empirically chosen value.

Definition at line 459 of file winsecdesc.c.

Referenced by IntWinSDDumpSecDesc().

◆ IntWinSDDumpSecDesc()

static void IntWinSDDumpSecDesc ( WIN_PROCESS_OBJECT Process,
BYTE SecurityDescriptorBuffer,
DWORD  BufferSize,
BOOLEAN  Original 
)
static

This function dumps the security descriptor for a given process.

Parameters
[in]ProcessThe process to dump the security descriptor for.
[in]SecurityDescriptorBufferThe security descriptor to be dumped.
[in]BufferSizeThe size of the security descriptor buffer.
[in]OriginalTRUE is the given security descriptor is the original one, FALSE otherwise (used only for logging).

Definition at line 577 of file winsecdesc.c.

Referenced by IntWinSDCheckAclIntegrity(), and IntWinSDCheckSecDescIntegrity().

◆ IntWinSDFetchSecDescAddress()

static INTSTATUS IntWinSDFetchSecDescAddress ( WIN_PROCESS_OBJECT Process,
QWORD SecurityDescriptorAddressGva 
)
static

This function reads the security descriptor address for the given process using the GPA cache.

Parameters
[in]ProcessThe process to read the security descriptor for.
[in]SecurityDescriptorAddressGvaThe security descriptor GVA.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_PAGE_NOT_PRESENTIf the GVA is not mapped/present using guest PTEs.

Definition at line 697 of file winsecdesc.c.

Referenced by IntWinSDFetchSecDescValues(), and IntWinSDProtectSecDesc().

◆ IntWinSDFetchSecDescValues()

static INTSTATUS IntWinSDFetchSecDescValues ( WIN_PROCESS_OBJECT Process,
QWORD OldValue,
QWORD NewValue 
)
static

This function obtains the original security descriptor value (from the WIN_PROCESS_OBJECT structure) and the current value (by reading the guest memory using GPA cache).

Parameters
[in]ProcessThe process to query the information for.
[out]OldValueThe original security descriptor value.
[out]NewValueThe current security descriptor value.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_PAGE_NOT_PRESENTIf the GVA is not mapped/present using guest PTEs.

Definition at line 793 of file winsecdesc.c.

Referenced by IntWinSDIsSecDescPtrAltered().

◆ IntWinSDFindAcls()

INTSTATUS IntWinSDFindAcls ( DWORD  BufferSize,
BYTE SecurityDescriptorBuffer,
DWORD ReadSize,
ACL **  Sacl,
ACL **  Dacl 
)

This function looks for the Sacl/Dacl within the SecurityDescriptorBuffer and makes sure they are within the buffer range.

Parameters
[in]BufferSizeThe size in bytes of the given buffer (SecurityDescriptorBuffer).
[in]SecurityDescriptorBufferThe buffer where the ACLs (along with the ACEs) are stored.
[out]ReadSizeThe size in bytes of the returned security descriptor.
[out]SaclPoints to the SACL header inside the SecurityDescriptorBuffer.
[out]DaclPoints to the DACL header inside the SecurityDescriptorBuffer.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_DATA_BUFFER_TOO_SMALLIf the Sacl/Dacl do not fit within the buffer.

Definition at line 202 of file winsecdesc.c.

Referenced by IntWinSDDumpSecDesc(), and IntWinSDReadSecDesc().

◆ IntWinSDGatherAcl()

static INTSTATUS IntWinSDGatherAcl ( WIN_PROCESS_OBJECT Process)
static

This function gathers the 2 ACLs (SACL/DACL) and stores them in the WIN_PROCESS_OBJECT structure of the given process (the data will later be used for integrity checks and DPI).

Parameters
[in,out]ProcessThe process to gather the ACLs for.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_NEEDED_HINTIf the SecurityDescriptor GVA is NULL.

Definition at line 634 of file winsecdesc.c.

Referenced by IntWinSDCheckAclIntegrity(), IntWinSDCheckSecDescIntegrity(), IntWinSDIsSecDescPtrAltered(), and IntWinSDProtectSecDesc().

◆ IntWinSDGetAceTypeName()

static char* IntWinSDGetAceTypeName ( BYTE  AceTypeValue)
static

This function obtains the printable name for a given ACE type.

Parameters
[in]AceTypeValueThe ACE type - found within the Security Descriptor.
Return values
Avalid ACE type name On success.
NULLIf the given ACE type value is invalid.

Definition at line 111 of file winsecdesc.c.

Referenced by IntWinSDDumpAclEntries().

◆ IntWinSDIsAceInsideAcl()

static BOOLEAN IntWinSDIsAceInsideAcl ( ACL Acl,
ACE_HEADER Ace 
)
static

This function checks whether the ACE fits inside the ACL (the ACL structure must be obtained using IntWinSDFindAcls).

Parameters
[in]AclThe Access Control List.
[in]AceThe Access Control Entry.
Return values
TRUEThe Ace fits inside the Acl.
FALSEThe Ace does NOT fit inside the Acl.

Definition at line 289 of file winsecdesc.c.

Referenced by IntWinSDProcessAcl().

◆ IntWinSDIsAceInsideBuffer()

static BOOLEAN IntWinSDIsAceInsideBuffer ( BYTE Buffer,
DWORD  BufferSize,
ACE_HEADER Ace 
)
static

This function checks whether the ACE fits inside the given buffer.

Parameters
[in]BufferThe buffer.
[in]BufferSizeThe size of the buffer.
[in]AceThe Access Control Entry.
Return values
TRUEThe Ace fits inside the buffer.
FALSEThe Ace does NOT fit inside the buffer.

Definition at line 326 of file winsecdesc.c.

Referenced by IntWinSDDumpAclEntries().

◆ IntWinSDIsAclEdited()

BOOLEAN IntWinSDIsAclEdited ( WIN_PROCESS_OBJECT Process,
DWORD  BufferSize,
BYTE SecurityDescriptorBuffer,
DWORD ReadSize,
ACL **  NewSacl,
ACL **  NewDacl 
)

This function reads the ACLs for the given process (returning the data using the provided buffer and the Sacl/Dacl pointers) and then compares the read data with the one stored within the WIN_PROCESS_OBJECT structure.

Parameters
[in]ProcessThe process the check the ACLs integrity for.
[in]BufferSizeThe size in bytes of the given buffer (SecurityDescriptorBuffer).
[out]SecurityDescriptorBufferThe buffer where the ACLs (along with the ACEs) will be stored.
[out]ReadSizeThe size in bytes of the returned security descriptor.
[out]NewSaclThe current SACL header.
[out]NewDaclThe current DACL header.
Return values
TRUEIf the ACLs have been modified.
FALSEIf the ACLs have NOT been modified.

Definition at line 916 of file winsecdesc.c.

Referenced by IntWinDpiValidateParentAclEdit(), and IntWinSDCheckAclIntegrity().

◆ IntWinSDIsSecDescPtrAltered()

BOOLEAN IntWinSDIsSecDescPtrAltered ( WIN_PROCESS_OBJECT Process,
WIN_PROCESS_OBJECT **  VictimProcess,
QWORD OldValue,
QWORD NewValue 
)

This function checks if the security descriptor pointer of a process has been altered or not.

Parameters
[in]ProcessThe process to query the information for.
[out]VictimProcessThe process where the security descriptor has been stolen from (it can be NULL if the security descriptor was not altered or it was altered but the source is not the security descriptor of a known process).
[out]OldValueThe original security descriptor value.
[out]NewValueThe current security descriptor value.
Return values
TRUEThe security descriptor has been altered.
FALSEThe security descriptor has NOT been altered.

Definition at line 829 of file winsecdesc.c.

Referenced by IntWinDpiValidateParentSecDesc(), and IntWinSDCheckSecDescIntegrity().

◆ IntWinSDProcessAcl()

static void IntWinSDProcessAcl ( ACL Acl)
static

This function clears the SIDs that have more than one sub authority for a given ACL.

Parameters
[in,out]AclThe access control entry to be processed (SACL/DACL).

Definition at line 1234 of file winsecdesc.c.

Referenced by IntWinSDCheckAclIntegrity(), and IntWinSDCheckSecDescIntegrity().

◆ IntWinSDProtectSecDesc()

INTSTATUS IntWinSDProtectSecDesc ( WIN_PROCESS_OBJECT Process)

This function saves the security descriptor address and ACLs into the WIN_PROCESS_OBJECT structure.

Parameters
[in]ProcessThe process to save the security descriptor for.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETER_1If the given Process is NULL.

Definition at line 750 of file winsecdesc.c.

Referenced by IntWinProcCreateProcessObject().

◆ IntWinSDReadSecDesc()

INTSTATUS IntWinSDReadSecDesc ( QWORD  SecurityDescriptorGva,
DWORD  BufferSize,
BYTE SecurityDescriptorBuffer,
DWORD ReadSize,
ACL **  Sacl,
ACL **  Dacl 
)

This function reads the ACLs (along with the ACEs) from the given GVA and returns the data using the provided buffer and the Sacl/Dacl pointers. This function will read the SECURITY_DESCRIPTOR structure that acts as a header, the SACL header and then use the SACL size to find the DACL. If an attacker were to alter the SACL/DACL size such that it will not fit in the given buffer, the function will fail with INT_STATUS_DATA_BUFFER_TOO_SMALL - check the returned Sacl/Dacl values.

Parameters
[in]SecurityDescriptorGvaThe GVA of the security descriptor.
[in]BufferSizeThe size in bytes of the given buffer (SecurityDescriptorBuffer).
[out]SecurityDescriptorBufferThe buffer where the ACLs (along with the ACEs) will be stored.
[out]ReadSizeThe size in bytes of the returned security descriptor.
[out]SaclPoints to the SACL header inside the SecurityDescriptorBuffer.
[out]DaclPoints to the DACL header inside the SecurityDescriptorBuffer.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_PAGE_NOT_PRESENTIf the given GVA is not mapped.
INT_STATUS_DATA_BUFFER_TOO_SMALLIf the security descriptor is larger than the provided buffer.

Definition at line 362 of file winsecdesc.c.

Referenced by IntWinDpiValidateParentSecDesc(), IntWinSDCheckAclIntegrity(), IntWinSDCheckSecDescIntegrity(), IntWinSDGatherAcl(), and IntWinSDIsAclEdited().

◆ IntWinSDSendAclIntegrityViolation()

static INTSTATUS IntWinSDSendAclIntegrityViolation ( WIN_PROCESS_OBJECT Process,
BYTE SecDescBuffer,
DWORD  SecDescSize,
DWORD  SecDescHash,
INTRO_ACTION  Action,
INTRO_ACTION_REASON  Reason 
)
static

This function sends an integrity violation caused by a modified ACL (SACL/DACL).

Parameters
[in]ProcessThe process that was found to have a modified security descriptor.
[in]SecDescBufferThe new security descriptor buffer.
[in]SecDescSizeThe new security descriptor buffer size.
[in]SecDescHashThe new security descriptor hash (computer after IntWinSDProcessAcl).
[in]ActionThe taken action (INTRO_ACTION).
[in]ReasonThe reason for the taken action (INTRO_ACTION_REASON).
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1131 of file winsecdesc.c.

Referenced by IntWinSDCheckAclIntegrity().

◆ IntWinSDSendSecDescIntViolation()

static INTSTATUS IntWinSDSendSecDescIntViolation ( WIN_PROCESS_OBJECT Process,
WIN_PROCESS_OBJECT Victim,
QWORD  OldValue,
QWORD  NewValue,
BYTE SecDescBuffer,
DWORD  SecDescSize,
DWORD  SecDescHash,
INTRO_ACTION  Action,
INTRO_ACTION_REASON  Reason 
)
static

This function sends an integrity violation caused by a modified security descriptor pointer.

Parameters
[in]ProcessThe process that was found to have a different security descriptor.
[in]VictimThe process from where the security descriptor pointer was stolen from (it can be NULL).
[in]OldValueThe old value of the security descriptor.
[in]NewValueThe new value of the security descriptor.
[in]SecDescBufferThe new security descriptor buffer.
[in]SecDescSizeThe new security descriptor buffer size.
[in]SecDescHashThe new security descriptor hash (computer after IntWinSDProcessAcl).
[in]ActionThe taken action (INTRO_ACTION).
[in]ReasonThe reason for the taken action (INTRO_ACTION_REASON).
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 1048 of file winsecdesc.c.

Referenced by IntWinSDCheckSecDescIntegrity().

◆ STATIC_ASSERT() [1/2]

STATIC_ASSERT ( sizeof(ACL = =sizeof(QWORD),
"Sizeof of ACL is not a QWORD  
)

We are using the EXCEPTION_VICTIM_ZONE.WriteInfo to send the New/Old SACL/DACL.

◆ STATIC_ASSERT() [2/2]

STATIC_ASSERT ( INTRO_SECURITY_DESCRIPTOR_SIZE  ,
(sizeof(SECURITY_DESCRIPTOR)+2 *sizeof(ACL))  ,
"INTRO_SECURITY_DESCRIPTOR_SIZE is too small"   
)

Make sure the buffer is big enough - at least for the headers.

Variable Documentation

◆ gWinProcesses

LIST_HEAD gWinProcesses

The list of all the processes inside the guest.

Definition at line 11 of file winprocesshp.c.