Bitdefender Hypervisor Memory Introspection
hook_ptm.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 #include "hook_ptm.h"
7 #include "vecore.h"
8 
9 
13 typedef struct _INVOCATION_CONTEXT
14 {
16  void *Context;
19 
20 
21 
22 static INTSTATUS
24  _In_opt_ void *Context,
25  _In_ void *Hook,
26  _In_ QWORD Address,
27  _Out_ INTRO_ACTION *Action
28  )
44 {
45  INTSTATUS status;
46  PHOOK_PTM_TABLE pPt;
47  DWORD i, offset;
48  LIST_HEAD localCallbacksList;
49  LIST_ENTRY *list;
50 #define LOCAL_BUF_SIZE 4
51  INVOCATION_CONTEXT lc[LOCAL_BUF_SIZE] = { 0 }; // First 4 callbacks won't need heap allocations.
52 
54 
55 
56  if (Context == NULL)
57  {
59  }
60 
61  if (Action == NULL)
62  {
64  }
65 
66  status = INT_STATUS_SUCCESS;
67  i = 0;
68  InitializeListHead(&localCallbacksList);
69 
70  *Action = introGuestAllowed;
71 
72  pPt = (PHOOK_PTM_TABLE)Context;
73 
75 
76  offset = gGuest.PaeEnabled ? (Address & 0xFFF) >> 3 : (Address & 0xFFF) >> 2;
77 
78  // If this entry is not monitored, update the #VE cache.
79  if ((gGuest.Mm.Mode == PAGING_4_LEVEL_MODE) && IsListEmpty(&pPt->Entries[offset]))
80  {
81  // No hooks on this entry, add it in the cache. Also, add the next 7 entries, if needed,
82  // for spatial & time locality. It seems that experimentally, at least on a RS5 x64, there's no improvement
83  // from 8 to 16 entries cached at once.
84  for (DWORD k = 0; k < 8 && k + offset < pPt->EntriesCount; k++)
85  {
86  if (IsListEmpty(&pPt->Entries[offset + k]))
87  {
88  status = IntVeUpdateCacheEntry(Address + k * 8ull, FALSE);
89  if (!INT_SUCCESS(status))
90  {
91  ERROR("[ERROR] IntVeUpdateCacheEntry failed: 0x%08x\n", status);
92  }
93  }
94  }
95 
96  status = INT_STATUS_SUCCESS;
97  goto _stop_stats_and_exit;
98  }
99 
101 
102  list = pPt->Entries[offset].Flink;
103  while (list != &pPt->Entries[offset])
104  {
105  PINVOCATION_CONTEXT pIc = NULL;
106  PHOOK_PTM pPtm = CONTAINING_RECORD(list, HOOK_PTM, Link);
107 
108  list = list->Flink;
109 
110  if (i < LOCAL_BUF_SIZE)
111  {
112  pIc = &lc[i];
113  }
114  else
115  {
116  pIc = HpAllocWithTag(sizeof(*pIc), IC_TAG_INVC);
117  if (NULL == pIc)
118  {
120  break;
121  }
122  }
123 
124  pIc->Callback = pPtm->Callback;
125  pIc->Context = pPtm->Header.Context;
126 
127  InsertTailList(&localCallbacksList, &pIc->Link);
128 
129  i++;
130  }
131 
132  i = 0;
133  list = localCallbacksList.Flink;
134  while (list != &localCallbacksList)
135  {
136  INTSTATUS status2;
137  PINVOCATION_CONTEXT pIc = CONTAINING_RECORD(list, INVOCATION_CONTEXT, Link);
138 
139  list = list->Flink;
140 
141  status2 = pIc->Callback(pIc->Context, Hook, Address, Action);
142  if (!INT_SUCCESS(status2))
143  {
144  ERROR("[ERROR] Callback failed: 0x%08x\n", status2);
145 
146  if (INT_STATUS_ACCESS_DENIED == status2)
147  {
148  status = status2;
149  }
150  }
151 
152  RemoveEntryList(&pIc->Link);
153 
154  if (i >= LOCAL_BUF_SIZE)
155  {
157  }
158 
159  i++;
160  }
161 
162  // If any of the swap-in callbacks returned INT_STATUS_ACCESS_DENIED, than we will block this write.
163  if (INT_STATUS_ACCESS_DENIED == status)
164  {
165  TRACE("[PTM] Callback returned INT_STATUS_ACCESS_DENIED, will block the PT write.\n");
166  *Action = introGuestNotAllowed;
167  }
168 
169 _stop_stats_and_exit:
171 
172  if ((gGuest.KernelBetaDetections) && (*Action == introGuestNotAllowed))
173  {
174  *Action = introGuestAllowed;
175  }
176 
177  return INT_STATUS_SUCCESS;
178 }
179 
180 
181 static INTSTATUS
183  _In_ QWORD Gpa,
184  _In_ DWORD Flags,
185  _Out_ PHOOK_PTM_TABLE *PtHook
186  )
201 {
202  INTSTATUS status;
203  PHOOK_PTM_TABLE pPtHook;
204  DWORD hid, i, size;
205  LIST_ENTRY *list;
206 
207  if (NULL == PtHook)
208  {
210  }
211 
212  pPtHook = NULL;
213 
214  if (!!(Flags & HOOK_FLG_PAE_ROOT))
215  {
216  hid = PTM_PAE_ROOT_HOOK_ID(Gpa);
217  Gpa &= 0xFFFFFFE0;
218  }
219  else
220  {
221  hid = PTM_HOOK_ID(Gpa);
222  Gpa &= PHYS_PAGE_MASK;
223  }
224 
225  list = gHooks->PtmHooks.PtmHooks[hid].Flink;
226  while (list != &gHooks->PtmHooks.PtmHooks[hid])
227  {
228  pPtHook = CONTAINING_RECORD(list, HOOK_PTM_TABLE, Link);
229 
230  list = list->Flink;
231 
232  if (pPtHook->Gpa == Gpa)
233  {
234  break;
235  }
236 
237  pPtHook = NULL;
238  }
239 
240  if (NULL == pPtHook)
241  {
242  pPtHook = HpAllocWithTag(sizeof(*pPtHook), IC_TAG_PTPP);
243  if (NULL == pPtHook)
244  {
246  goto cleanup_and_exit;
247  }
248 
249  pPtHook->Header.ParentHook = NULL;
250  pPtHook->Header.Flags = Flags;
251  pPtHook->Header.HookType = hookTypePtmPt;
252  pPtHook->Header.Context = NULL;
253 
254  pPtHook->EntriesCount = (gGuest.PaeEnabled ? 512 : 1024);
255  pPtHook->RefCount = 0;
256  pPtHook->DelCount = 0;
257  pPtHook->Gpa = Gpa;
258 
259  pPtHook->Entries = HpAllocWithTag(sizeof(*pPtHook->Entries) * pPtHook->EntriesCount, IC_TAG_PTPA);
260  if (NULL == pPtHook->Entries)
261  {
263  goto cleanup_and_exit;
264  }
265 
266  for (i = 0; i < pPtHook->EntriesCount; i++)
267  {
268  InitializeListHead(&pPtHook->Entries[i]);
269  }
270 
271  size = !!(Flags & HOOK_FLG_PAE_ROOT) ? 0x20 : !!(Flags & HOOK_FLG_PT_UM_ROOT) ? PAGE_SIZE / 2 : PAGE_SIZE;
272 
273  status = IntHookGpaSetHook(Gpa, size, IG_EPT_HOOK_WRITE, IntHookPtmWriteCallback, pPtHook,
274  pPtHook, Flags, &pPtHook->GpaHook);
275  if (!INT_SUCCESS(status))
276  {
277  ERROR("[ERROR] IntHookGpaSetHook failed for gpa %llx: 0x%08x\n", Gpa, status);
278  goto cleanup_and_exit;
279  }
280 
281  // We must ensure that the page table is indeed hooked by the time this function returns. We do this by
282  // flushing EPT permissions (which may be cached by the integrator). Once IntFlushEPTPermissions returns,
283  // all EPT modifications are committed and the TLBs are invalidated.
284  status = IntFlushEPTPermissions();
285  if (!INT_SUCCESS(status))
286  {
287  ERROR("[ERROR] IntFlushEPTPermissions failed: 0x%08x\n", status);
288  goto cleanup_and_exit;
289  }
290 
291  pPtHook->GpaHookSet = TRUE;
292 
293  InsertTailList(&gHooks->PtmHooks.PtmHooks[hid], &pPtHook->Link);
294 
295  status = INT_STATUS_SUCCESS;
296 
297 cleanup_and_exit:
298  if (!INT_SUCCESS(status) && (NULL != pPtHook))
299  {
300  if (NULL != pPtHook->GpaHook)
301  {
302  IntHookGpaRemoveHook(&pPtHook->GpaHook, 0);
303  }
304 
305  if (NULL != pPtHook->Entries)
306  {
308  }
309 
311  }
312  }
313  else
314  {
315  status = INT_STATUS_SUCCESS;
316  }
317 
318  *PtHook = pPtHook;
319 
320  return status;
321 }
322 
323 
324 INTSTATUS
326  _In_ QWORD Address,
328  _In_ void *Context,
329  _In_ void *ParentHook,
330  _In_ DWORD Flags,
332  )
349 {
350  INTSTATUS status;
351  PHOOK_PTM pPtmHook;
352  PHOOK_PTM_TABLE pPtHook;
353  DWORD offset;
354 
355  if (NULL == Callback)
356  {
358  }
359 
360  pPtHook = NULL;
361 
362  Flags &= HOOK_FLG_GLOBAL_MASK;
363  gHooks->Dirty = TRUE;
364 
365  // Get the master page-table hook/manager.
366  status = IntHookPtmAddTable(Address, Flags, &pPtHook);
367  if (!INT_SUCCESS(status))
368  {
369  ERROR("[ERROR] IntHookPtmAddTable failed: 0x%08x\n", status);
370  return status;
371  }
372 
373  pPtmHook = HpAllocWithTag(sizeof(*pPtmHook), IC_TAG_PTPM);
374  if (NULL == pPtmHook)
375  {
377  }
378 
379  pPtmHook->Header.Context = Context;
380  pPtmHook->Header.ParentHook = ParentHook;
381  pPtmHook->Header.Flags = Flags;
382  pPtmHook->Header.HookType = hookTypePtm;
383 
384  pPtmHook->Callback = Callback;
385  pPtmHook->Address = Address;
386  pPtmHook->PtHook = pPtHook;
387 
388  // Add the Page Table Entry hook inside the Page Table hook.
389  offset = gGuest.PaeEnabled ? ((Address & 0xFFF) >> 3) : ((Address & 0xFFF) >> 2);
390 
391  if ((gGuest.Mm.Mode == PAGING_4_LEVEL_MODE) && IsListEmpty(&pPtHook->Entries[offset]))
392  {
393  // First hook established on Address, make sure we evict it from the cache.
394  status = IntVeUpdateCacheEntry(Address, TRUE);
395  if (!INT_SUCCESS(status))
396  {
397  ERROR("[ERROR] IntVeUpdateCacheEntry failed: 0x%08x\n", status);
398  }
399  }
400 
401  InsertTailList(&pPtHook->Entries[offset], &pPtmHook->Link);
402 
403  pPtHook->RefCount++;
404 
405  if (NULL != Hook)
406  {
407  *Hook = pPtmHook;
408  }
409 
410  return INT_STATUS_SUCCESS;
411 }
412 
413 
414 static INTSTATUS
418  )
428 {
429  INTSTATUS status;
430 
431  if (Hook->GpaHookSet)
432  {
433  status = IntHookGpaRemoveHook(&Hook->GpaHook, HOOK_FLG_CHAIN_DELETE);
434  if (!INT_SUCCESS(status))
435  {
436  ERROR("[ERROR] IntHookGpaRemoveHook failed: 0x%08x\n", status);
437  }
438 
439  Hook->GpaHookSet = FALSE;
440  }
441 
442  // We now mark the PT hook for removal.
443  Hook->Header.Flags |= (HOOK_FLG_DISABLED | HOOK_FLG_REMOVE);
444 
445  if (Flags & HOOK_FLG_CHAIN_DELETE)
446  {
447  Hook->Header.Flags |= HOOK_FLG_CHAIN_DELETE;
448  }
449 
450  RemoveEntryList(&Hook->Link);
451 
453 
454  return INT_STATUS_SUCCESS;
455 }
456 
457 
458 static INTSTATUS
462  )
477 {
478  INTSTATUS status;
479 
480  if (0 != (Hook->Header.Flags & HOOK_FLG_REMOVE))
481  {
483  }
484 
485  Flags &= HOOK_FLG_GLOBAL_MASK;
486 
487  Hook->Header.Flags |= (HOOK_FLG_DISABLED | HOOK_FLG_REMOVE);
488 
489  if (Flags & HOOK_FLG_CHAIN_DELETE)
490  {
491  Hook->Header.Flags |= HOOK_FLG_CHAIN_DELETE;
492  }
493 
494  RemoveEntryList(&Hook->Link);
495 
497 
498  // Decrement the ref count on the table hook.
499  Hook->PtHook->RefCount--;
500  Hook->PtHook->DelCount++;
501 
502  if (0 == Hook->PtHook->RefCount)
503  {
504  status = IntHookPtmRemoveTableHook(Hook->PtHook, HOOK_FLG_CHAIN_DELETE);
505  if (!INT_SUCCESS(status))
506  {
507  ERROR("[ERROR] IntHookPtmRemoveTableHook failed: 0x%08x\n", status);
508  }
509  }
510 
512 
513  gHooks->Dirty = TRUE;
514 
515  return INT_STATUS_SUCCESS;
516 }
517 
518 
519 INTSTATUS
523  )
538 {
539  INTSTATUS status;
540 
541  if (NULL == Hook)
542  {
544  }
545 
546  if (NULL == *Hook)
547  {
549  }
550 
551  status = IntHookPtmRemoveHookInternal(*Hook, Flags);
552  if (!INT_SUCCESS(status))
553  {
554  ERROR("[ERROR] IntHookPtmRemoveHookInternal failed: 0x%08x\n", status);
555  }
556 
557  if (!(Flags & HOOK_FLG_CHAIN_DELETE))
558  {
559  *Hook = NULL;
560  }
561 
562  return status;
563 }
564 
565 
566 static INTSTATUS
570  )
579 {
580  INTSTATUS status;
581 
582  UNREFERENCED_PARAMETER(Flags);
583 
584  RemoveEntryList(&Hook->Link);
585 
586  status = IntHookGpaDeleteHook(&Hook->GpaHook, 0);
587  if (!INT_SUCCESS(status))
588  {
589  ERROR("[ERROR] IntHookGpaDeleteHook failed: 0x%08x\n", status);
590  }
591 
592  HpFreeAndNullWithTag(&Hook->Entries, IC_TAG_PTPA);
593 
595 
596  return status;
597 }
598 
599 
600 static INTSTATUS
604  )
616 {
617  INTSTATUS status;
618 
619  UNREFERENCED_PARAMETER(Flags);
620 
621  status = INT_STATUS_SUCCESS;
622 
623  // Decrement the delete count. When it reaches zero, we'll actually gonna erase the entry.
624  Hook->PtHook->DelCount--;
625  if ((0 == Hook->PtHook->DelCount) && (0 == Hook->PtHook->RefCount))
626  {
627  status = IntHookPtmDeleteTableHook(Hook->PtHook, 0);
628  if (!INT_SUCCESS(status))
629  {
630  ERROR("[ERROR] IntHookPtmDeleteTableHook failed: 0x%08x\n", status);
631  }
632  }
633 
634  RemoveEntryList(&Hook->Link);
635 
637 
638  return status;
639 }
640 
641 
642 INTSTATUS
644  _In_ HOOK_PTM **Hook,
646  )
658 {
659  INTSTATUS status;
660 
661  UNREFERENCED_PARAMETER(Flags);
662 
663  if (NULL == Hook)
664  {
666  }
667 
668  if (NULL == *Hook)
669  {
671  }
672 
673  Flags &= HOOK_FLG_GLOBAL_MASK;
674 
675  status = IntHookPtmDeleteHookInternal(*Hook, Flags);
676  if (!INT_SUCCESS(status))
677  {
678  ERROR("[ERROR] IntHookPtmDeleteHookInternal failed: 0x%08x\n", status);
679  }
680 
681  *Hook = NULL;
682 
683  return status;
684 }
685 
686 
687 INTSTATUS
689  void
690  )
700 {
701  INTSTATUS status;
702  LIST_ENTRY *list;
703 
705  {
706  return INT_STATUS_SUCCESS;
707  }
708 
710  while (list != &gHooks->PtmHooks.RemovedPtmHooks)
711  {
713  list = list->Flink;
714 
715  if (0 != (p->Header.Flags & HOOK_FLG_CHAIN_DELETE))
716  {
717  // Chain delete requested - we won't commit this hook, we'll let it's parent decide its faith.
718  continue;
719  }
720 
721  if (0 != (p->Header.Flags & HOOK_FLG_REMOVE))
722  {
723  status = IntHookPtmDeleteHookInternal(p, 0);
724  if (!INT_SUCCESS(status))
725  {
726  ERROR("[ERROR] IntHookPtmDeleteHookInternal failed: 0x%08x\n", status);
727  }
728  }
729  else
730  {
731  ERROR("[ERROR] Invalid hook state: %x for hook at PTA 0x%016llx\n", p->Header.Flags, p->Address);
733  }
734  }
735 
736  // Handle table hooks.
738  while (list != &gHooks->PtmHooks.RemovedPtHooks)
739  {
741  list = list->Flink;
742 
743  if (0 != (p->Header.Flags & HOOK_FLG_CHAIN_DELETE))
744  {
745  // Chain delete requested - we won't commit this hook, we'll let it's parent decide its faith.
746  continue;
747  }
748 
749  if (0 != (p->Header.Flags & HOOK_FLG_REMOVE))
750  {
751  status = IntHookPtmDeleteTableHook(p, 0);
752  if (!INT_SUCCESS(status))
753  {
754  ERROR("[ERROR] IntHookGpaDeleteHook failed: 0x%08x\n", status);
755  }
756  }
757  else
758  {
759  ERROR("[ERROR] Invalid hook state: %x for hook at GPA 0x%016llx\n", p->Header.Flags, p->Gpa);
761  }
762  }
763 
765 
766  return INT_STATUS_SUCCESS;
767 }
768 
769 
770 INTSTATUS
772  void
773  )
779 {
780  for (DWORD i = 0; i < PTM_HOOK_TABLE_SIZE; i++)
781  {
783  }
784 
787 
788  return INT_STATUS_SUCCESS;
789 }
PHOOK_GPA GpaHook
The GPA hook set on this page-table.
Definition: hook_ptm.h:19
static INTSTATUS IntHookPtmDeleteHookInternal(PHOOK_PTM Hook, DWORD Flags)
Permanently delete a page-table hook handle.
Definition: hook_ptm.c:601
#define INT_STATUS_ACCESS_DENIED
Definition: introstatus.h:290
#define _In_opt_
Definition: intro_sal.h:16
LIST_ENTRY RemovedPtmHooks
List of removed page-table hooks (HOOK_PTM_TABLE).
Definition: hook_ptm.h:59
#define _Out_
Definition: intro_sal.h:22
#define CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
BOOLEAN Dirty
Set whenever hooks are added or removed.
Definition: hook.h:97
void * Context
User-defined data that will be supplied to the callback.
Definition: hook.h:74
PHOOK_PTM_TABLE PtHook
Definition: hook_ptm.h:42
struct _INVOCATION_CONTEXT INVOCATION_CONTEXT
#define IC_TAG_PTPP
Page Table Hook Manager page.
Definition: memtags.h:88
static INTSTATUS IntHookPtmAddTable(QWORD Gpa, DWORD Flags, PHOOK_PTM_TABLE *PtHook)
Add a new page-table to the monitored list.
Definition: hook_ptm.c:182
#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
#define PTM_PAE_ROOT_HOOK_ID(addr)
Definition: hook_ptm.h:50
static INTSTATUS IntHookPtmRemoveHookInternal(PHOOK_PTM Hook, DWORD Flags)
Remove a page-table hook handle.
Definition: hook_ptm.c:459
#define STATS_EXIT(id)
Definition: stats.h:160
#define PTM_HOOK_TABLE_SIZE
Definition: hook_ptm.h:48
#define IntEnterDebugger()
Definition: introcore.h:373
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
Used by the internal page monitor (used by PTS).
Definition: hook.h:21
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define HOOK_FLG_DISABLED
If flag is set, the hook is disabled, therefore ignored on EPT violations.
Definition: hook.h:46
static BOOLEAN IsListEmpty(const LIST_ENTRY *ListHead)
Definition: introlists.h:78
PHOOK_PTS Hook
The PTS hook associated with the modified address.
Definition: hook_pts.c:91
struct _HOOK_PTM_TABLE * PHOOK_PTM_TABLE
BOOLEAN KernelBetaDetections
True if the kernel protection is in beta (log-only) mode.
Definition: guests.h:303
Measures all the page table writes.
Definition: stats.h:46
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
INTSTATUS IntHookPtmInit(void)
Initialize the page-table hook system.
Definition: hook_ptm.c:771
#define PHYS_PAGE_MASK
Definition: pgtable.h:38
int INTSTATUS
The status data type.
Definition: introstatus.h:24
HOOK_STATE * gHooks
Global hooks state.
Definition: hook.c:8
HOOK_HEADER Header
Hook header - used by all memory hooks.
Definition: hook_ptm.h:16
INTSTATUS IntFlushEPTPermissions(void)
Definition: glue.c:1242
INTSTATUS IntHookPtmCommitHooks(void)
Commit the page-table hooks.
Definition: hook_ptm.c:688
static INTSTATUS IntHookPtmDeleteTableHook(PHOOK_PTM_TABLE Hook, DWORD Flags)
Permanently delete a page-table hook.
Definition: hook_ptm.c:567
INTSTATUS IntHookGpaSetHook(QWORD Gpa, DWORD Length, BYTE Type, PFUNC_EptViolationCallback Callback, void *Context, void *ParentHook, DWORD Flags, HOOK_GPA **Hook)
Places an EPT hook on the indicated memory range.
Definition: hook_gpa.c:193
#define IC_TAG_PTPM
Page Table Hook Manager entry.
Definition: memtags.h:87
LIST_ENTRY PtmHooks[PTM_HOOK_TABLE_SIZE]
Hash of monitored address spaces.
Definition: hook_ptm.h:58
INTSTATUS IntVeUpdateCacheEntry(QWORD Address, BOOLEAN Monitored)
Update an address inside the VE cache.
Definition: vecore.c:2799
#define HOOK_FLG_PT_UM_ROOT
If flag is set, the hook is set on the root paging structure, and only the low, user-mode entires are...
Definition: hook.h:52
#define IC_TAG_PTPA
Page Table Hook Manager array.
Definition: memtags.h:89
BYTE HookType
The type of the hook structure (see _HOOK_TYPE)
Definition: hook.h:68
#define _Inout_
Definition: intro_sal.h:20
#define HOOK_FLG_GLOBAL_MASK
Global flags must be defined here and must be handled by each hooks layer (even if it ignores them...
Definition: hook.h:35
#define _Out_opt_
Definition: intro_sal.h:30
#define STATS_ENTER(id)
Definition: stats.h:153
BOOLEAN PaeEnabled
True if Physical Address Extension is enabled.
Definition: guests.h:295
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
unsigned long long QWORD
Definition: intro_types.h:53
QWORD Address
Guest physical address of the monitored page-table entry.
Definition: hook_ptm.h:41
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
#define HOOK_FLG_CHAIN_DELETE
If flag is set, then we won&#39;t remove the hook on commit phase; we&#39;ll let the parent hook handle the d...
Definition: hook.h:48
HOOK_PTM_STATE PtmHooks
Page table monitoring (internal) state.
Definition: hook.h:94
DWORD EntriesCount
Definition: hook_ptm.h:24
#define TRUE
Definition: intro_types.h:30
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
#define TRACE(fmt,...)
Definition: glue.h:58
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
INTSTATUS IntHookGpaDeleteHook(HOOK_GPA **Hook, DWORD Flags)
Permanently delete a GPA hook.
Definition: hook_gpa.c:830
INTSTATUS IntHookPtmDeleteHook(HOOK_PTM **Hook, DWORD Flags)
Permanently delete a page-table hook handle.
Definition: hook_ptm.c:643
PFUNC_EptViolationCallback Callback
Modification callback, called whenever an entry inside this page-table is modified.
Definition: hook_ptm.h:44
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
4-level paging
Definition: introcore.h:71
static void InitializeListHead(LIST_ENTRY *ListHead)
Definition: introlists.h:69
INTSTATUS IntHookPtmSetHook(QWORD Address, PFUNC_EptViolationCallback Callback, void *Context, void *ParentHook, DWORD Flags, PHOOK_PTM *Hook)
Set a hook on a page-table.
Definition: hook_ptm.c:325
#define PAGE_SIZE
Definition: common.h:70
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
#define IC_TAG_INVC
Invocation context.
Definition: memtags.h:83
uint32_t DWORD
Definition: intro_types.h:49
LIST_ENTRY * Entries
A list of hooked entries. When a HOOK_PTS_ENTRY is created for entry at offset X, Entries[x] will con...
Definition: hook_ptm.h:27
enum _INTRO_ACTION INTRO_ACTION
Event actions.
DWORD DelCount
Number of delete requests. The entry will be deleted when this reaches 0.
Definition: hook_ptm.h:23
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
INTSTATUS(* PFUNC_EptViolationCallback)(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
EPT callback handler.
Definition: hook_gpa.h:30
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
LIST_ENTRY RemovedPtHooks
List of removed PTM hooks (HOOK_PTM).
Definition: hook_ptm.h:60
PFUNC_EptViolationCallback Callback
Write callback to be called for the modification.
Definition: hook_ptm.c:17
DWORD RefCount
Number of references - number of HOOK_PTM structures that point to this entry.
Definition: hook_ptm.h:22
QWORD Gpa
The page-table guest physical address.
Definition: hook_ptm.h:18
static INTSTATUS IntHookPtmWriteCallback(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Called whenever a monitored page-table is written.
Definition: hook_ptm.c:23
static INTSTATUS IntHookPtmRemoveTableHook(PHOOK_PTM_TABLE Hook, DWORD Flags)
Remove a page-table hook.
Definition: hook_ptm.c:415
#define PTM_HOOK_ID(addr)
Definition: hook_ptm.h:49
#define LOCAL_BUF_SIZE
LIST_ENTRY Link
List element entry.
Definition: hook_ptm.c:15
struct _INVOCATION_CONTEXT * PINVOCATION_CONTEXT
PAGING_MODE Mode
The paging mode used by the guest.
Definition: guests.h:221
LIST_ENTRY Link
List entry link.
Definition: hook_ptm.h:40
BOOLEAN GpaHookSet
Definition: hook_ptm.h:20
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
Used by an internal page monitored using PTM.
Definition: hook.h:22
INTSTATUS IntHookPtmRemoveHook(HOOK_PTM **Hook, DWORD Flags)
Remove a page-table hook handle.
Definition: hook_ptm.c:520
void * Context
Context to be passed to the Callback.
Definition: hook_ptm.c:16
DWORD Flags
Generic flags. Check out EPT Hook flags.
Definition: hook.h:67
HOOK_HEADER Header
Hook header - used by all memory hooks.
Definition: hook_ptm.h:39
Write-access hook.
Definition: glueiface.h:299
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
BOOLEAN HooksRemoved
True if hooks have been removed.
Definition: hook_ptm.h:61
LIST_ENTRY Link
List entry link.
Definition: hook_ptm.h:17
#define HOOK_FLG_REMOVE
If flag is set, the hook has been removed, and waits the next commit to be actually deleted...
Definition: hook.h:44
#define HOOK_FLG_PAE_ROOT
Definition: hook.h:50
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68