|
Bitdefender Hypervisor Memory Introspection
|
This file contains the integrity checking mechanism, consisting in checking certain guest regions every second to see if there were any modifications. More...
Go to the source code of this file.
Macros | |
| #define | for_each_region(_var_name) list_for_each(gIntegrityRegions, INTEGRITY_REGION, _var_name) |
| Useful macro for iterating through the list of INTEGRITY_REGION structures. More... | |
Functions | |
| static BOOLEAN | IntIntegrityIsOverlappedRegions (INTEGRITY_REGION *Descriptor) |
| Checks if an integrity region is overlapped with any of the integrity regions already in the list. More... | |
| INTSTATUS | IntIntegrityAddRegion (QWORD VirtualAddress, DWORD Length, INTRO_OBJECT_TYPE Type, void *Context, PFUNC_IntegrityViolationCallback Callback, BOOLEAN CopyContent, void **Descriptor) |
| Creates an INTEGRITY_REGION object and adds it to the gIntegrityRegions list. More... | |
| INTSTATUS | IntIntegrityRecalculate (INTEGRITY_REGION *IntegrityRegion) |
| Recalculates the hash and reads the original content again for a given region. More... | |
| INTSTATUS | IntIntegrityRemoveRegion (void *Descriptor) |
| Removes an integrity region from the gIntegrityRegions list. More... | |
| INTSTATUS | IntIntegrityDeleteRegion (void *Descriptor) |
| Marks the given integrity region for deletion. It will be removed after calling all the integrity callbacks. More... | |
| TIMER_FRIENDLY INTSTATUS | IntIntegrityCheckAll (void) |
| The function which is called once every second and checks all the integrity regions. More... | |
| void | IntIntegrityDump (void) |
| Dumps all the INTEGRITY_REGION structures from gIntegrityRegions. Used mainly for debugging. More... | |
| INTSTATUS | IntIntegrityUninit (void) |
| Uninits the integrity mechanism by removing every integrity region from the list. More... | |
Variables | |
| static LIST_HEAD | gIntegrityRegions = LIST_HEAD_INIT(gIntegrityRegions) |
| The global list of integrity regions, represented by INTEGRITY_REGION structures. More... | |
This file contains the integrity checking mechanism, consisting in checking certain guest regions every second to see if there were any modifications.
The integrity mechanism makes sure that certain in-guest regions are not modified during guest execution. The mechanism is triggered once every second through the timer callback. The main need for this mechanism is the problem that we can hook synchronously against writes (e.g. we are notified exactly at the moment of the write, through an EPT violation) only with a length of 4Kb, which is the page size. Thus, structures which are shorter than the page size, and reside in places that are written frequently, for example nt's .data section, cannot be protected through EPT. For this reason, integrity checks can significantly improve performance, by asynchronously checking once every second the integrity of a structure, meaning that we check to see if any byte of the structure was modified. The main disadvantage of this mechanism is that we don't have much information about the possible malicious modification, as we detect the modification asynchronously, after the write has been done. Some protected structures through the integrity mechanism are the Hal Dispatch Table, the Interrupt Descriptor Table, the WMI_LOGGER_CONTEXT used for Circular Kernel Logging (the GetCpuClock function which can be overwritten through infinity hook), as well as static detected drivers, where the allocation could not be intercepted by the introspection engine, thus the page size allocation could not be enforced.
Definition in file integrity.c.
| #define for_each_region | ( | _var_name | ) | list_for_each(gIntegrityRegions, INTEGRITY_REGION, _var_name) |
Useful macro for iterating through the list of INTEGRITY_REGION structures.
Definition at line 44 of file integrity.c.
Referenced by IntIntegrityCheckAll(), IntIntegrityDump(), IntIntegrityIsOverlappedRegions(), and IntIntegrityUninit().
| INTSTATUS IntIntegrityAddRegion | ( | QWORD | VirtualAddress, |
| DWORD | Length, | ||
| INTRO_OBJECT_TYPE | Type, | ||
| void * | Context, | ||
| PFUNC_IntegrityViolationCallback | Callback, | ||
| BOOLEAN | CopyContent, | ||
| void ** | Descriptor | ||
| ) |
Creates an INTEGRITY_REGION object and adds it to the gIntegrityRegions list.
This function will create the INTEGRITY_REGION object based on the given parameters and will append it to the gIntegrityRegions list, meaning that once every second, when the timer is called, the integrity mechanism will check the added integrity region and will call the given callback if the current computed hash of the region is not the same as the hash from the time when the region was added, or when a recalculation has been issued on the given region. Basically, the mechanism will check every second if any bit of the given region, starting from VirtualAddress and having Length bytes, has been modified, and will call the given Callback if any modification has been detected. Note that the mechanism can be used only for protecting kernel regions, and user-space virtual addresses will cause this function to fail.
| [in] | VirtualAddress | The guest virtual address which describes the start of the region. |
| [in] | Length | The number of bytes which are desired to be protected through integrity. |
| [in] | Type | The INTRO_OBJECT_TYPE which associates the integrity region with the protected object. |
| [in] | Context | An user-provided context which will be saved in the INTEGRITY_REGION structure (e.g. for protecting a field from EPROCESS one may decide to provide the WIN_PROCESS_OBJECT structure associated with that EPROCESS). |
| [in] | Callback | The callback which is called by the integrity mechanism in case of any modification being detected in the given region. |
| [in] | CopyContent | Set this parameter to TRUE if one needs the original content of the given region to be saved in the INTEGRITY_REGION structure. This is useful for re-writing the original content in the Callback function once it decides that the current state of the region seems to be malicious. |
| [out] | Descriptor | The returned INTEGRITY_REGION object. |
| INT_STATUS_SUCCESS | On success. |
| INT_STATUS_INVALID_PARAMETER_1 | If the given virtual address is not a kernel pointer. |
| INT_STATUS_INVALID_PARAMETER_2 | If the length of the region is 0. |
| INT_STATUS_INSUFFICIENT_RESOURCES | If any allocation fails due to lack of resources. |
Definition at line 91 of file integrity.c.
Referenced by IntWinDrvObjProtect(), IntWinDrvObjProtectFastIoDispatch(), IntWinHalProtectHalDispatchTable(), IntWinIdtProtectOnCpuIntegrity(), IntWinInfHookProtect(), and IntWinInfHookSiloWmiPtrIntegrityCallback().
| TIMER_FRIENDLY INTSTATUS IntIntegrityCheckAll | ( | void | ) |
The function which is called once every second and checks all the integrity regions.
This function is called every second and will check all INTEGRITY_REGION previously added through calls to IntIntegrityAddRegion. It will call the provided callbacks associated to the regions if any modification was detected and a callback has been provided. After all the callbacks are called for the regions which are not marked for deletion (due to calls to IntIntegrityDeleteRegion from within an integrity callback), those latter regions will be removed through calls to IntIntegrityRemoveRegion.
| INT_STATUS_SUCCESS | On success or if there is nothing to be done as the protection is not activated. |
Definition at line 377 of file integrity.c.
Referenced by IntHandleTimer().
| INTSTATUS IntIntegrityDeleteRegion | ( | void * | Descriptor | ) |
Marks the given integrity region for deletion. It will be removed after calling all the integrity callbacks.
This function should be called when deleting an integrity region from an integrity callback, as opposed to IntIntegrityRemoveRegion. This will ensure that the list is kept properly and then remove the deleted regions after all (non-deleted) callbacks are called.
| [in] | Descriptor | The integrity region as returned by IntIntegrityAddRegion or provided as a parameter in a callback. |
| INT_STATUS_SUCCESS | On success. |
Definition at line 348 of file integrity.c.
Referenced by IntWinInfHookSiloWmiPtrIntegrityCallback().
| void IntIntegrityDump | ( | void | ) |
Dumps all the INTEGRITY_REGION structures from gIntegrityRegions. Used mainly for debugging.
Definition at line 486 of file integrity.c.
|
static |
Checks if an integrity region is overlapped with any of the integrity regions already in the list.
While this function is used for a purely informative purpose, it is pretty useful in order to avoid double protection for various regions through integrity. Even if overlapping regions are not a problem for the mechanism, they are indicating that a misuse of the integrity mechanism was made, and there is probably a bug in the code which calls the mechanism.
| [in] | Descriptor | The INTEGRITY_REGION which is checked to not be overlapped with the other regions in the list. |
| TRUE | If there is any INTEGRITY_REGION in gIntegrityRegions that overlaps with the current region. |
| FALSE | If the current INTEGRITY_REGION passed by the Descriptor parameter does not overlap with any of the regions in the gIntegrityRegions list. |
Definition at line 48 of file integrity.c.
Referenced by IntIntegrityAddRegion().
| INTSTATUS IntIntegrityRecalculate | ( | INTEGRITY_REGION * | IntegrityRegion | ) |
Recalculates the hash and reads the original content again for a given region.
The main use of this function is when a modification was detected inside the region described by the given INTEGRITY_REGION, the given callback was called, but the callback decides that the modification is not malicious, and the modification should be ignored in further checks done by the integrity mechanism. For this purpose, the callback will call this function, which will re-compute the hash of the given region, with the current modified values which are in the guest, and copies the current content to the OriginalContent field if the integrity region was added with the CopyContent parameter of IntIntegrityAddRegion set to TRUE. Failure to call this function in the above mentioned case will result in the integrity mechanism calling the associated Callback every second, as it will see that certain parts of the region are modified with respect to the time when the integrity region was added through a call to IntIntegrityAddRegion. This is not desired, especially when beta alerts are activated, or when one might use the integrity mechanism for various initialization purposes (e.g. initialize some protection only when some field in a given structure was written, a good example for this use case would be the infinity hook protection in wininfinityhook.c).
| [in] | IntegrityRegion | The INTEGRITY_REGION object for which the recalculation is desired. |
| INT_STATUS_SUCCESS | On success. |
Definition at line 242 of file integrity.c.
Referenced by IntWinDrvObjHandleModification(), IntWinHalHandleDispatchTableWrite(), IntWinIdtHandleModification(), IntWinInfHookGetCpuClockIntegrityCallback(), and IntWinInfHookSiloWmiPtrIntegrityCallback().
| INTSTATUS IntIntegrityRemoveRegion | ( | void * | Descriptor | ) |
Removes an integrity region from the gIntegrityRegions list.
This function will remove an integrity region object, which was previously added with IntIntegrityAddRegion. Note: One should not call this function from within an integrity callback associated to an INTEGRITY_REGION, but rather should call IntIntegrityDeleteRegion for this purpose which will only mark the region for deletion. This function should be called when uninitializing an integrity protection.
| [in] | Descriptor | The integrity region object as returned by IntIntegrityAddRegion. |
| INT_STATUS_SUCCESS | On success. |
Definition at line 313 of file integrity.c.
Referenced by IntIntegrityCheckAll(), IntIntegrityUninit(), IntWinDrvObjUnprotect(), IntWinDrvObjUnprotectFastIoDispatch(), IntWinHalUnprotectHalDispatchTable(), IntWinIdtUnprotectOnCpuIntergity(), and IntWinInfHookUnprotect().
| INTSTATUS IntIntegrityUninit | ( | void | ) |
Uninits the integrity mechanism by removing every integrity region from the list.
Note that an error is issued for every region in the list, since the caller which adds the region through IntIntegrityAddRegion is responsible to remove it when removing the protection on the desired structure. The fact that the protection is not removed is considered an error, and the caller should always remove the returned integrity regions when they are not needed anymore.
| INT_STATUS_SUCCESS | On success. |
Definition at line 503 of file integrity.c.
Referenced by IntGuestUninit().
|
static |
The global list of integrity regions, represented by INTEGRITY_REGION structures.
Definition at line 39 of file integrity.c.