Bitdefender Hypervisor Memory Introspection
hook.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "hook.h"
6 
7 
8 HOOK_STATE *gHooks = NULL;
9 
10 
13  void
14  )
30 {
31  INTSTATUS status;
32 
33  if (NULL == gHooks)
34  {
36  }
37 
38  if (!gHooks->Dirty)
39  {
41  }
42 
44 
45  status = IntHookObjectCommit();
46  if (!INT_SUCCESS(status))
47  {
48  ERROR("[ERROR] IntHookObjectCommit failed: 0x%08x\n", status);
49  goto cleanup_and_exit;
50  }
51 
52  status = IntHookGvaCommitHooks();
53  if (!INT_SUCCESS(status))
54  {
55  ERROR("[ERROR] IntHookGvaCommitHooks failed: 0x%08x\n", status);
56  goto cleanup_and_exit;
57  }
58 
59  status = IntHookPtsCommitHooks();
60  if (!INT_SUCCESS(status))
61  {
62  ERROR("[ERROR] IntHookPtsCommitHooks failed: 0x%08x\n", status);
63  goto cleanup_and_exit;
64  }
65 
66  status = IntHookPtmCommitHooks();
67  if (!INT_SUCCESS(status))
68  {
69  ERROR("[ERROR] IntHookPtmCommitHooks failed: 0x%08x\n", status);
70  goto cleanup_and_exit;
71  }
72 
73  status = IntHookGpaCommitHooks();
74  if (!INT_SUCCESS(status))
75  {
76  ERROR("[ERROR] IntHookGpaCommitHooks failed: 0x%08x\n", status);
77  goto cleanup_and_exit;
78  }
79 
80 #ifdef DEBUG_CHECK_HOOKS
82 #endif
83 
84 
85 cleanup_and_exit:
86  if (gHooks->GpaHooks.HooksRemoved || gHooks->GvaHooks.HooksRemoved ||
87  gHooks->PtsHooks.HooksRemoved || gHooks->Objects.ObjectsRemoved ||
88  gHooks->PtmHooks.HooksRemoved)
89  {
90  // There are hooks uncommitted. We don't want to reset the dirt marker,
91  // so we have a chance to commit them on next run.
92  }
93  else
94  {
95  gHooks->Dirty = FALSE;
96  }
97 
99 
100  return status;
101 }
102 
103 
104 INTSTATUS
106  _In_ PHOOK_GPA HookGpa
107  )
124 {
125  PHOOK_HEADER pHook;
126 
127  if (NULL == HookGpa)
128  {
130  }
131 
132  // Find the most upper level hook.
133  pHook = &HookGpa->Header;
134  while (pHook->ParentHook)
135  {
136  pHook = (PHOOK_HEADER)pHook->ParentHook;
137  }
138 
139  // Remove the most upper level hook.
140  switch (pHook->HookType)
141  {
142  case hookTypeGpa:
143  return IntHookGpaRemoveHook((HOOK_GPA **)&pHook, 0);
144 
145  case hookTypeGva:
146  return IntHookGvaRemoveHook((HOOK_GVA **)&pHook, 0);
147 
148  case hookTypePts:
149  return IntHookPtsRemoveHook((HOOK_PTS **)&pHook, 0);
150 
151  case hookTypePtm:
152  return IntHookPtmRemoveHook((HOOK_PTM **)&pHook, 0);
153 
154  case hookTypeRegion:
156 
157  default:
158  ERROR("[ERROR] Unknown hook type %d!\n", pHook->HookType);
160  }
161 }
162 
163 
164 INTSTATUS
166  void
167  )
178 {
179  INTSTATUS status;
180 
181  if (NULL != gHooks)
182  {
183  ERROR("[ERROR] Trying to do IntHookInit multiple times!\n");
185  }
186 
187  gHooks = HpAllocWithTag(sizeof(*gHooks), IC_TAG_HOOKS);
188  if (NULL == gHooks)
189  {
191  }
192 
193  status = IntHookGpaInit();
194  if (!INT_SUCCESS(status))
195  {
196  goto cleanup_and_exit;
197  }
198 
199  status = IntHookPtmInit();
200  if (!INT_SUCCESS(status))
201  {
202  goto cleanup_and_exit;
203  }
204 
205  status = IntHookPtsInit();
206  if (!INT_SUCCESS(status))
207  {
208  goto cleanup_and_exit;
209  }
210 
211  status = IntHookGvaInit();
212  if (!INT_SUCCESS(status))
213  {
214  goto cleanup_and_exit;
215  }
216 
217  status = IntHookObjectInit();
218  if (!INT_SUCCESS(status))
219  {
220  goto cleanup_and_exit;
221  }
222 
223  return INT_STATUS_SUCCESS;
224 
225 cleanup_and_exit:
227 
228  if (NULL != gHooks)
229  {
231  }
232 
233  return status;
234 }
235 
236 
237 INTSTATUS
239  void
240  )
250 {
251  INTSTATUS status;
252 
253  if (NULL == gHooks)
254  {
256  }
257 
258  status = IntHookCommitAllHooks();
259  if (!INT_SUCCESS(status))
260  {
261  ERROR("[ERROR] IntHookCommitAllHooks failed: 0x%08x\n", status);
262  }
263 
264  status = IntHookObjectUninit();
265  if (!INT_SUCCESS(status))
266  {
267  ERROR("[ERROR] IntHookObjectUninit: 0x%08x\n", status);
268  }
269 
271 
272  gHooks = NULL;
273 
274  return INT_STATUS_SUCCESS;
275 }
276 
277 
278 QWORD
280  _In_ HOOK_GPA const *Hook,
281  _In_ QWORD Address
282  )
303 {
304  HOOK_GVA const *pGva = Hook->Header.ParentHook;
305 
306  if ((NULL == pGva) || (pGva->Header.HookType != hookTypeGva))
307  {
308  ERROR("[ERROR] The GPA hook for address 0x%016llx does not point to a valid GVA hook: %p, type %d",
309  Hook->GpaPage, pGva, pGva ? pGva->Header.HookType : 0);
310  IntBugCheck();
311  }
312 
313  return pGva->GvaPage + (Address & 0xFFF);
314 }
INTSTATUS IntHookPtmRemoveHook(HOOK_PTM **Hook, DWORD Flags)
Remove a page-table hook handle.
Definition: hook_ptm.c:520
BOOLEAN Dirty
Set whenever hooks are added or removed.
Definition: hook.h:97
HOOK_GVA_STATE GvaHooks
GVA hooks state.
Definition: hook.h:93
#define _In_
Definition: intro_sal.h:21
INTSTATUS IntHookGpaRemoveHook(HOOK_GPA **Hook, DWORD Flags)
Remove a GPA hook.
Definition: hook_gpa.c:738
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
INTSTATUS IntHookInit(void)
Initialize the global hook system.
Definition: hook.c:165
#define STATS_EXIT(id)
Definition: stats.h:160
Used by GPA hooks.
Definition: hook.h:17
Used by the internal page monitor (used by PTS).
Definition: hook.h:21
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
Used by GVA hooks.
Definition: hook.h:18
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
INTSTATUS IntHookCommitAllHooks(void)
Commits all the hooks.
Definition: hook.c:12
An entire hook region, consisting of multiple GVA hooks.
Definition: hook.h:23
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD GvaPage
Guest virtual page base address, aligned to 4K.
Definition: hook_gva.h:32
INTSTATUS IntHookPtsCommitHooks(void)
Commit all PTS hook modifications.
Definition: hook_pts.c:2084
BOOLEAN ObjectsRemoved
True whenever an object has been removed.
Definition: hook_object.h:56
HOOK_STATE * gHooks
Global hooks state.
Definition: hook.c:8
INTSTATUS IntHookGpaInit(void)
Initialize the GPA hook system. This function should be called only once, during introspection init...
Definition: hook_gpa.c:1097
Measures the hook commits.
Definition: stats.h:42
BOOLEAN HooksRemoved
True if at least one hook has been removed since the last commit.
Definition: hook_gva.h:52
BYTE HookType
The type of the hook structure (see _HOOK_TYPE)
Definition: hook.h:68
#define INT_STATUS_ALREADY_INITIALIZED
Definition: introstatus.h:263
static void IntDbgCheckHooks(void)
Definition: debugger.c:182
#define STATS_ENTER(id)
Definition: stats.h:153
__noreturn void IntBugCheck(void)
Definition: glue.c:917
unsigned long long QWORD
Definition: intro_types.h:53
INTSTATUS IntHookObjectInit(void)
Initialize the hook object system.
Definition: hook_object.c:598
struct _HOOK_HEADER * PHOOK_HEADER
void * ParentHook
The parent hook. For a GPA hook, for example, a GVA hook or a PagedHook will be the parent hook...
Definition: hook.h:73
HOOK_HEADER Header
The hook header.
Definition: hook_gva.h:20
HOOK_PTM_STATE PtmHooks
Page table monitoring (internal) state.
Definition: hook.h:94
INTSTATUS IntHookObjectUninit(void)
Uninit the hook object system.
Definition: hook_object.c:614
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
INTSTATUS IntHookPtsRemoveHook(HOOK_PTS **Hook, DWORD Flags)
Remove a PTS hook.
Definition: hook_pts.c:1944
BOOLEAN HooksRemoved
True if any hook has been removed.
Definition: hook_pts.h:117
INTSTATUS IntHookGvaRemoveHook(HOOK_GVA **Hook, DWORD Flags)
Remove a GVA hook.
Definition: hook_gva.c:507
HOOK_GPA_STATE GpaHooks
GPA hooks state.
Definition: hook.h:92
INTSTATUS IntHookObjectRemoveRegion(HOOK_REGION_DESCRIPTOR **Region, DWORD Flags)
Remove a hooked region of memory.
Definition: hook_object.c:309
INTSTATUS IntHookPtmInit(void)
Initialize the page-table hook system.
Definition: hook_ptm.c:771
INTSTATUS IntHookGvaCommitHooks(void)
Commit all the modified GVA hooks.
Definition: hook_gva.c:657
QWORD IntHookGetGlaFromGpaHook(HOOK_GPA const *Hook, QWORD Address)
Gets the GLA from a GPA hook.
Definition: hook.c:279
INTSTATUS IntHookPtmCommitHooks(void)
Commit the page-table hooks.
Definition: hook_ptm.c:688
INTSTATUS IntHookRemoveChain(PHOOK_GPA HookGpa)
Removes a hook chain, starting with the given GPA hook.
Definition: hook.c:105
HOOK_OBJECT_STATE Objects
Object hooks state.
Definition: hook.h:96
INTSTATUS IntHookObjectCommit(void)
Commit removed hook objects and regions.
Definition: hook_object.c:525
INTSTATUS IntHookUninit(void)
Uninit the global hooks system.
Definition: hook.c:238
HOOK_PTS_STATE PtsHooks
PTS hooks state (public page-table monitoring).
Definition: hook.h:95
#define INT_STATUS_NOT_INITIALIZED_HINT
Definition: introstatus.h:320
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
Used by page-table hooks.
Definition: hook.h:19
#define IC_TAG_HOOKS
Global hook state.
Definition: memtags.h:74
BOOLEAN HooksRemoved
True if hooks were removed, and we must do the cleanup..
Definition: hook_gpa.h:119
INTSTATUS IntHookPtsInit(void)
Initializes the PTS hooks system.
Definition: hook_pts.c:2183
INTSTATUS IntHookGpaCommitHooks(void)
Commit existing modified hooks.
Definition: hook_gpa.c:876
INTSTATUS IntHookGvaInit(void)
Initialize the GVA hooks system.
Definition: hook_gva.c:714
BOOLEAN HooksRemoved
True if hooks have been removed.
Definition: hook_ptm.h:61
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281