Bitdefender Hypervisor Memory Introspection
hook_gpa.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_gpa.h"
7 #include "callbacks.h"
8 #include "introcpu.h"
9 #include "ptfilter.h"
10 
11 #ifdef INT_COMPILER_MSVC
12 #pragma warning(push)
13 #pragma warning(disable: 4204) // nonstandard extension used: non-constant aggregate initializer
14 #endif // INT_COMPILER_MSVC
15 
16 
19  _In_ QWORD GpaPage
20  )
32 {
33  HOOK_EPT_ENTRY *pEptEntry;
34  const DWORD id = GPA_EPT_ID(GpaPage);
35 
36  pEptEntry = IntHookGpaGetExistingEptEntry(GpaPage);
37  if (NULL != pEptEntry)
38  {
39  return pEptEntry;
40  }
41 
42  //
43  // No entry found for this GPA, allocate a new one.
44  // NOTE: If we see a page for the first time (it is not hooked), we can safely assume it is RWX.
45  //
46  pEptEntry = HpAllocWithTag(sizeof(*pEptEntry), IC_TAG_EPTE);
47  if (NULL == pEptEntry)
48  {
49  return NULL;
50  }
51 
52  pEptEntry->GpaPage = GpaPage;
53 
54  InsertTailList(&gHooks->GpaHooks.EptEntries[id], &pEptEntry->Link);
55 
56  return pEptEntry;
57 }
58 
59 
60 static INTSTATUS
62  _Inout_ HOOK_EPT_ENTRY *Entry
63  )
79 {
80  if (NULL != Entry->Spp)
81  {
83  }
84 
85  Entry->Spp = HpAllocWithTag(sizeof(*Entry->Spp), IC_TAG_SPPE);
86  if (NULL == Entry->Spp)
87  {
89  }
90 
91  // Initially, the SPP entry is considered non-writable.
92  Entry->Spp->OldSpp = 0;
93 
94  // If this isn't the first write hook on this page, make sure we reflect it inside the current SPP permissions
95  // and inside the 128B non-write areas.
96  if (Entry->WriteCount == 0)
97  {
98  Entry->Spp->CurSpp = 0x5555555555555555;
99  }
100  else
101  {
102  // This isn't the first write-hook on this page, but it is the first sub-page hook - this means that a previous
103  // write hook covers the entire page.
104  Entry->Spp->CurSpp = 0;
105 
106  for (DWORD i = 0; i < 32; i++)
107  {
108  Entry->Spp->SppCount[i] += Entry->WriteCount;
109  }
110  }
111 
112  return INT_STATUS_SUCCESS;
113 }
114 
115 
116 static void
118  _Inout_ LIST_ENTRY *List,
119  _In_ HOOK_GPA *Hook
120  )
131 {
132  if (0 == (Hook->Header.Flags & HOOK_FLG_HIGH_PRIORITY))
133  {
134  InsertTailList(List, &Hook->Link);
135  }
136  else
137  {
138  LIST_ENTRY *pivot = List->Flink;
139 
140  while (pivot != List)
141  {
142  HOOK_GPA *pHook = CONTAINING_RECORD(pivot, HOOK_GPA, Link);
143 
144  if (0 == (pHook->Header.Flags & HOOK_FLG_HIGH_PRIORITY))
145  {
146  pivot = pivot->Blink;
147  break;
148  }
149 
150  pivot = pivot->Flink;
151  }
152 
153  InsertAfterList(pivot, &Hook->Link);
154  }
155 }
156 
157 
160  _In_ QWORD GpaPage
161  )
169 {
170  const DWORD id = GPA_EPT_ID(GpaPage);
172 
173  while (list != &gHooks->GpaHooks.EptEntries[id])
174  {
175  HOOK_EPT_ENTRY *pEptEntry = CONTAINING_RECORD(list, HOOK_EPT_ENTRY, Link);
176  list = list->Flink;
177 
178  if (pEptEntry->GpaPage == GpaPage)
179  {
180  return pEptEntry;
181  }
182  }
183 
184  return NULL;
185 }
186 
187 
188 INTSTATUS
190  _In_ QWORD Gpa,
191  _In_ DWORD Length,
192  _In_ BYTE Type,
194  _In_opt_ void *Context,
195  _In_opt_ void *ParentHook,
196  _In_opt_ DWORD Flags,
197  _Out_opt_ HOOK_GPA **Hook
198  )
269 {
270  INTSTATUS status;
271  HOOK_GPA *pGpaHook;
272  HOOK_EPT_ENTRY *eptEntry;
273  DWORD hid;
274  BOOLEAN setr, setc, sets;
275 
276  if (NULL == Callback)
277  {
279  }
280 
281  if ((Gpa & PAGE_MASK) != ((Gpa + Length - 1) & PAGE_MASK))
282  {
284  }
285 
286  if (Length > PAGE_SIZE)
287  {
289  }
290 
291  if ((Type != IG_EPT_HOOK_READ) && (Type != IG_EPT_HOOK_WRITE) && (Type != IG_EPT_HOOK_EXECUTE))
292  {
294  }
295 
296  pGpaHook = NULL;
297  hid = GPA_HOOK_ID(Gpa);
298  Flags &= HOOK_FLG_GLOBAL_MASK;
299  setr = setc = sets = FALSE;
300 
301  pGpaHook = HpAllocWithTag(sizeof(*pGpaHook), IC_TAG_GPAH);
302  if (NULL == pGpaHook)
303  {
305  }
306 
307  pGpaHook->Header.Context = Context;
308  pGpaHook->Header.ParentHook = ParentHook;
309  pGpaHook->Header.Flags = Flags;
310  pGpaHook->Header.HookType = hookTypeGpa;
311  pGpaHook->Header.EptHookType = Type;
312 
313  pGpaHook->Callback = Callback;
314  pGpaHook->GpaPage = Gpa & PAGE_MASK;
315  pGpaHook->Length = (WORD)Length;
316  pGpaHook->Offset = Gpa & PAGE_OFFSET;
317 
318  // Get the EPT entry, in order to update the restrictions.
319  eptEntry = IntHookGpaGetEptEntry(Gpa & PHYS_PAGE_MASK);
320  if (NULL == eptEntry)
321  {
323  goto cleanup_and_exit;
324  }
325 
326  // Handle Sub-Page Protection. Note that by default, we won't allocate a SPP entry until a sub-page hook is placed.
327  if (gHooks->GpaHooks.SppEnabled && (IG_EPT_HOOK_WRITE == Type))
328  {
329  if ((Length < PAGE_SIZE_4K) && (NULL == eptEntry->Spp))
330  {
331  status = IntHookGpaGetSppEntry(eptEntry);
332  if (!INT_SUCCESS(status))
333  {
334  ERROR("[ERROR] IntHookGpaGetSppEntry failed: 0x%08x\n", status);
335  goto cleanup_and_exit;
336  }
337  }
338 
339  if (NULL != eptEntry->Spp)
340  {
341  DWORD i, low, high;
342 
343  // The low 128B chunk that is being hooked.
344  low = ROUND_DOWN((DWORD)pGpaHook->Offset, 128) >> 7;
345 
346  // The high 128B chunk that is being hooked (exclusive).
347  high = ROUND_UP((DWORD)(pGpaHook->Offset + pGpaHook->Length), 128) >> 7;
348 
349  for (i = low; i < high; i++)
350  {
351  if (0 == eptEntry->Spp->SppCount[i]++)
352  {
353  eptEntry->Spp->CurSpp &= ~(1ULL << (2 * i));
354  sets = TRUE;
355  }
356  }
357  }
358  }
359 
360  switch (Type)
361  {
362  case IG_EPT_HOOK_READ:
363  if (MAX_HOOK_COUNT == eptEntry->ReadCount)
364  {
365  CRITICAL("[ERROR] Read hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
367  goto cleanup_and_exit;
368  }
369 
370  setr = 0 == eptEntry->ReadCount++;
371  break;
372  case IG_EPT_HOOK_WRITE:
373  if (MAX_HOOK_COUNT == eptEntry->WriteCount)
374  {
375  CRITICAL("[ERROR] Write hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
377  goto cleanup_and_exit;
378  }
379 
380  setr = 0 == eptEntry->WriteCount++;
381  break;
382  case IG_EPT_HOOK_EXECUTE:
383  if (MAX_HOOK_COUNT == eptEntry->ExecuteCount)
384  {
385  CRITICAL("[ERROR] Execute hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
387  goto cleanup_and_exit;
388  }
389 
390  setr = 0 == eptEntry->ExecuteCount++;
391  break;
392  default:
393  break;
394  }
395 
396  // Paging structure hooks will be convertible - they will be delivered as #VE in the guest.
397  if (0 != (Flags & HOOK_PAGE_TABLE_FLAGS))
398  {
399  if (MAX_HOOK_COUNT == eptEntry->PtCount)
400  {
401  CRITICAL("[ERROR] Page table hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
403  goto cleanup_and_exit;
404  }
405 
406  eptEntry->PtCount++;
407 
409  {
410  if (MAX_HOOK_COUNT == eptEntry->ConvCount)
411  {
412  CRITICAL("[ERROR] Convertible hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
414  goto cleanup_and_exit;
415  }
416 
417  setc = 0 == eptEntry->ConvCount++;
418  }
419  else if (gHooks->GpaHooks.PtCacheEnabled)
420  {
421  status = IntPtiCacheRemove(Gpa);
422  if (!INT_SUCCESS(status))
423  {
424  ERROR("[ERROR] IntPtsInt3CacheRemove failed for 0x%016llx and this sucks\n", Gpa);
426  }
427 
428  if (IG_EPT_HOOK_WRITE == Type)
429  {
430  // Don't make the entry non-writable. Also, don't touch the SPP permissions.
431  setr = sets = FALSE;
432  }
433  }
434  }
435 
436  // Set the appropriate access rights.
437  if (setr)
438  {
440  pGpaHook->GpaPage,
441  0 == eptEntry->ReadCount,
442  0 == eptEntry->WriteCount,
443  0 == eptEntry->ExecuteCount);
444  if (!INT_SUCCESS(status))
445  {
446  ERROR("[ERROR] IntSetEPTPageProtection failed for GPA 0x%016llx: 0x%08x\n", pGpaHook->GpaPage, status);
447  goto cleanup_and_exit;
448  }
449  }
450 
451  if (setc)
452  {
453  status = IntSetEPTPageConvertible(gGuest.UntrustedEptIndex, pGpaHook->GpaPage, 0 != eptEntry->ConvCount);
454  if (!INT_SUCCESS(status))
455  {
456  ERROR("[ERROR] IntSetEPTConvertible failed for GPA 0x%016llx: 0x%08x\n", pGpaHook->GpaPage, status);
457  goto cleanup_and_exit;
458  }
459  }
460 
461  // Modify the SPP entry, if needed.
462  if (sets)
463  {
464  status = IntSetSPPPageProtection(pGpaHook->GpaPage, eptEntry->Spp->CurSpp);
465  if (!INT_SUCCESS(status))
466  {
467  ERROR("[ERROR] IntSetSPPPageProtection failed: 0x%08x\n", status);
468  goto cleanup_and_exit;
469  }
470  }
471 
472  if (0 == gHooks->GpaHooks.HooksCount++)
473  {
474  status = IntEnableEptNotifications();
475  if (!INT_SUCCESS(status))
476  {
477  goto cleanup_and_exit;
478  }
479  }
480 
481  // Insert the hook in the uncommitted hooks list.
482  if (IG_EPT_HOOK_READ == Type)
483  {
485  }
486  else if (IG_EPT_HOOK_WRITE == Type)
487  {
489  }
490  else
491  {
493  }
494 
495  if (NULL != Hook)
496  {
497  *Hook = pGpaHook;
498  }
499 
500  status = INT_STATUS_SUCCESS;
501 
502 cleanup_and_exit:
503  if (!INT_SUCCESS(status))
504  {
505  if (NULL != pGpaHook)
506  {
507  HpFreeAndNullWithTag(&pGpaHook, IC_TAG_GPAH);
508  }
509  }
510 
511  return status;
512 }
513 
514 
515 static INTSTATUS
517  _In_ HOOK_GPA *Hook
518  )
531 {
532  INTSTATUS status;
533  HOOK_EPT_ENTRY *eptEntry;
534  BOOLEAN setr, setc, sets;
535 
536  eptEntry = NULL;
537  setr = setc = sets = FALSE;
538 
539  eptEntry = IntHookGpaGetEptEntry(Hook->GpaPage);
540  if (NULL == eptEntry)
541  {
543  }
544 
545  // Removing hook - restore the correct access bits.
546  switch (Hook->Header.EptHookType)
547  {
548  case IG_EPT_HOOK_READ:
549  BUG_ON(0 == eptEntry->ReadCount);
550 
551  setr = 0 == --eptEntry->ReadCount;
552  break;
553  case IG_EPT_HOOK_WRITE:
554  BUG_ON(0 == eptEntry->WriteCount);
555 
556  setr = 0 == --eptEntry->WriteCount;
557  break;
558  case IG_EPT_HOOK_EXECUTE:
559  BUG_ON(0 == eptEntry->ExecuteCount);
560 
561  setr = 0 == --eptEntry->ExecuteCount;
562  break;
563  default:
564  break;
565  }
566 
567  if (0 != (Hook->Header.Flags & HOOK_PAGE_TABLE_FLAGS))
568  {
569  BUG_ON(0 == eptEntry->PtCount);
570 
571  eptEntry->PtCount--;
572 
574  {
575  BUG_ON(0 == eptEntry->ConvCount);
576 
577  setc = 0 == --eptEntry->ConvCount;
578  }
579  else if (gHooks->GpaHooks.PtCacheEnabled)
580  {
581  if (IG_EPT_HOOK_WRITE == Hook->Header.EptHookType)
582  {
583  // No need to modify EPT, as we left the entry writable.
584  setr = sets = FALSE;
585  }
586  }
587  }
588 
589  if (gHooks->GpaHooks.SppEnabled && (IG_EPT_HOOK_WRITE == Hook->Header.EptHookType))
590  {
591  if (NULL != eptEntry->Spp)
592  {
593  DWORD low, high;
594 
595  // The low 128B chunk that is being hooked.
596  low = ROUND_DOWN((DWORD)Hook->Offset, 128) >> 7;
597 
598  // The high 128B chunk that is being hooked (exclusive).
599  high = ROUND_UP((DWORD)(Hook->Offset + Hook->Length), 128) >> 7;
600 
601  for (DWORD i = low; i < high; i++)
602  {
603  if (0 == --eptEntry->Spp->SppCount[i])
604  {
605  eptEntry->Spp->CurSpp |= (1ULL << (2 * i));
606  sets = TRUE;
607  }
608  }
609  }
610  }
611 
612  if (setr)
613  {
614  // If no hooks are set for a particular EPT permission, it means that the page has that permission.
615  const BYTE r = eptEntry->ReadCount == 0;
616  const BYTE w = eptEntry->WriteCount == 0;
617  const BYTE x = eptEntry->ExecuteCount == 0;
618 
619  // Modify the rights.
621  Hook->GpaPage,
622  r,
623  w,
624  x);
625  if (!INT_SUCCESS(status))
626  {
627  ERROR("[ERROR] IntSetEPTPageProtection failed for GPA 0x%016llx: 0x%08x\n", Hook->GpaPage, status);
628  return status;
629  }
630  }
631 
632  if (setc)
633  {
634  // Modify the convertible flag.
635  status = IntSetEPTPageConvertible(gGuest.UntrustedEptIndex, Hook->GpaPage, 0 != eptEntry->ConvCount);
636  if (!INT_SUCCESS(status))
637  {
638  ERROR("[ERROR] IntSetEPTPageConvertible failed for GPA 0x%016llx: 0x%08x\n", Hook->GpaPage, status);
639  return status;
640  }
641  }
642 
643  if (sets)
644  {
645  status = IntSetSPPPageProtection(Hook->GpaPage, eptEntry->Spp->CurSpp);
646  if (!INT_SUCCESS(status))
647  {
648  ERROR("[ERROR] IntSetSPPPageProtection failed for GPA 0x%016llx: 0x%08x\n", Hook->GpaPage, status);
649  return status;
650  }
651  }
652 
653  if ((0 == eptEntry->WriteCount) && (NULL != eptEntry->Spp))
654  {
655  // The last write hook was removed, we can free the SPP entry as well.
656  HpFreeAndNullWithTag(&eptEntry->Spp, IC_TAG_SPPE);
657  }
658 
659  if (0 == GPA_REF_COUNT(eptEntry))
660  {
661  // All hooks were removed, there's no point in keeping this entry anymore
662  RemoveEntryList(&eptEntry->Link);
663  HpFreeAndNullWithTag(&eptEntry, IC_TAG_EPTE);
664  }
665 
666  return INT_STATUS_SUCCESS;
667 }
668 
669 
670 static INTSTATUS
672  _In_ HOOK_GPA *Hook,
673  _In_ DWORD Flags
674  )
689 {
690  if (0 != (Hook->Header.Flags & HOOK_FLG_REMOVE))
691  {
693  }
694 
695  Hook->Header.Flags |= HOOK_FLG_DISABLED | HOOK_FLG_REMOVE;
696 
697  if (Flags & HOOK_FLG_CHAIN_DELETE)
698  {
699  Hook->Header.Flags |= HOOK_FLG_CHAIN_DELETE;
700 
701  // No point inserting it into the removed queue, since it will ignore chain deleted hooks
702  gHooks->Dirty = TRUE;
703 
704  return INT_STATUS_SUCCESS;
705  }
706 
707  if (IG_EPT_HOOK_READ == Hook->Header.EptHookType)
708  {
709  QueueInsert(&gHooks->GpaHooks.RemovedHooksRead, &Hook->LinkRemoved);
710  }
711  else if (IG_EPT_HOOK_WRITE == Hook->Header.EptHookType)
712  {
713  QueueInsert(&gHooks->GpaHooks.RemovedHooksWrite, &Hook->LinkRemoved);
714  }
715  else if (IG_EPT_HOOK_EXECUTE == Hook->Header.EptHookType)
716  {
717  QueueInsert(&gHooks->GpaHooks.RemovedHooksExecute, &Hook->LinkRemoved);
718  }
719  else
720  {
721  ERROR("[ERROR] Invalid hook type %d for hook %p\n", Hook->Header.EptHookType, Hook);
723  }
724 
726 
727  gHooks->Dirty = TRUE;
728 
729  return INT_STATUS_SUCCESS;
730 }
731 
732 
733 INTSTATUS
735  _Inout_ HOOK_GPA **Hook,
736  _In_ DWORD Flags
737  )
753 {
754  INTSTATUS status;
755 
756  if (NULL == Hook)
757  {
759  }
760 
761  if (NULL == *Hook)
762  {
764  }
765 
766  Flags &= HOOK_FLG_GLOBAL_MASK;
767 
768  status = IntHookGpaRemoveHookInternal(*Hook, Flags);
769  if (!INT_SUCCESS(status))
770  {
771  ERROR("[ERROR] IntHookGpaRemoveHookInternal failed: 0x%08x\n", status);
772  }
773 
774  if (!(Flags & HOOK_FLG_CHAIN_DELETE))
775  {
776  *Hook = NULL;
777  }
778 
779  return INT_STATUS_SUCCESS;
780 }
781 
782 
783 static INTSTATUS
785  _In_ HOOK_GPA *Hook,
786  _In_ DWORD Flags
787  )
796 {
797  INTSTATUS status;
798 
799  UNREFERENCED_PARAMETER(Flags);
800 
801  // Restore old access rights on the page.
802  status = IntHookGpaSetNewPageProtection(Hook);
803  if (!INT_SUCCESS(status))
804  {
805  ERROR("[ERROR] IntHookGpaSetNewPageProtection failed: 0x%08x\n", status);
806  }
807 
808  if (0 >= --gHooks->GpaHooks.HooksCount)
809  {
810  status = IntDisableEptNotifications();
811  if (!INT_SUCCESS(status))
812  {
813  return status;
814  }
815  }
816 
817  RemoveEntryList(&Hook->Link);
818 
820 
821  return status;
822 }
823 
824 
825 INTSTATUS
827  _In_ HOOK_GPA **Hook,
828  _In_ DWORD Flags
829  )
842 {
843  INTSTATUS status;
844 
845  UNREFERENCED_PARAMETER(Flags);
846 
847  if (NULL == Hook)
848  {
850  }
851 
852  if (NULL == *Hook)
853  {
855  }
856 
857  Flags &= HOOK_FLG_GLOBAL_MASK;
858 
859  status = IntHookGpaDeleteHookInternal(*Hook, Flags);
860  if (!INT_SUCCESS(status))
861  {
862  ERROR("[ERROR] IntHookGpaDeleteHookInternal failed: 0x%08x\n", status);
863  }
864 
865  *Hook = NULL;
866 
867  return status;
868 }
869 
870 
871 INTSTATUS
873  void
874  )
884 {
885  // The order in which we remove hooks must be the following:
886  // 1. Read hooks
887  // 2. Write hooks
888  // 3. Execute hooks
889  // If we'd commit read hooks first, we may end up with inconsistent EPT rights -> Write & Execute,
890  // which may trigger EPT misconfiguration.
891  QUEUE_HEAD *hooksQueues[] =
892  {
896  };
897 
898  INTSTATUS status;
899 
901  {
902  return INT_STATUS_SUCCESS;
903  }
904 
905  // Iterate the list of removed hooks and actually delete the designated hooks.
906  for (DWORD i = 0; i < ARRAYSIZE(hooksQueues); i++)
907  {
908  QUEUE_HEAD *hooksQueue = hooksQueues[i];
909  QUEUE_ENTRY *queue;
910 
911  while ((queue = QueueRemove(hooksQueue)) != hooksQueue)
912  {
913  PHOOK_GPA pGpaHook = CONTAINING_RECORD(queue, HOOK_GPA, LinkRemoved);
914 
915  if (0 != (pGpaHook->Header.Flags & HOOK_FLG_CHAIN_DELETE))
916  {
917  // Chain delete requested - we won't commit this hook, we'll let it's parent decide its faith.
918  ERROR("[ERROR] Invalid hook state: %x (chain delete) for hook at GPA 0x%016llx\n",
919  pGpaHook->Header.Flags, pGpaHook->GpaPage);
920  continue;
921  }
922 
923  if (0 == (pGpaHook->Header.Flags & HOOK_FLG_REMOVE))
924  {
925  ERROR("[ERROR] Invalid hook state: %x for hook at GPA 0x%016llx\n",
926  pGpaHook->Header.Flags,
927  pGpaHook->GpaPage);
928 
930  }
931 
932  status = IntHookGpaDeleteHookInternal(pGpaHook, 0);
933  if (!INT_SUCCESS(status))
934  {
935  ERROR("[ERROR] IntHookGpaDeleteHookInternal failed: 0x%08x\n", status);
936  }
937  }
938  }
939 
941 
942  return INT_STATUS_SUCCESS;
943 }
944 
945 
946 INTSTATUS
948  _In_ HOOK_GPA *Hook
949  )
960 {
961  if (NULL == Hook)
962  {
964  }
965 
966  Hook->Header.Flags |= HOOK_FLG_DISABLED;
967 
968  return INT_STATUS_SUCCESS;
969 }
970 
971 
972 INTSTATUS
974  _In_ HOOK_GPA *Hook
975  )
989 {
990  if (NULL == Hook)
991  {
993  }
994 
995  Hook->Header.Flags &= ~HOOK_FLG_DISABLED;
996 
997  return INT_STATUS_SUCCESS;
998 }
999 
1000 
1001 INTSTATUS
1003  _In_ QWORD Gpa,
1004  _Out_ BYTE *Read,
1005  _Out_ BYTE *Write,
1006  _Out_ BYTE *Execute
1007  )
1019 {
1020  LIST_ENTRY *list;
1021  DWORD i, hid;
1022 
1023  LIST_HEAD *hooksLists[] =
1024  {
1028  };
1029 
1030  if (NULL == Read)
1031  {
1033  }
1034 
1035  if (NULL == Write)
1036  {
1038  }
1039 
1040  if (NULL == Execute)
1041  {
1043  }
1044 
1045  hid = GPA_HOOK_ID(Gpa);
1046 
1047  // Assume full rights.
1048  *Read = *Write = *Execute = 1;
1049 
1050  for (i = 0; i < ARRAYSIZE(hooksLists); i++)
1051  {
1052  LIST_HEAD *hooksList = &hooksLists[i][hid];
1053 
1054  list = hooksList->Flink;
1055 
1056  while (list != hooksList)
1057  {
1058  PHOOK_GPA p = CONTAINING_RECORD(list, HOOK_GPA, Link);
1059  list = list->Flink;
1060 
1061  // Skip/ignore removed hooks.
1062  if (0 != (p->Header.Flags & (HOOK_FLG_DISABLED | HOOK_FLG_REMOVE)))
1063  {
1064  continue;
1065  }
1066 
1067  if ((Gpa & PAGE_MASK) == p->GpaPage)
1068  {
1069  switch (i)
1070  {
1071  case 0:
1072  *Write = 0;
1073  break;
1074  case 1:
1075  *Read = 0;
1076  break;
1077  case 2:
1078  *Execute = 0;
1079  default:
1080  break;
1081  }
1082 
1083  break;
1084  }
1085  }
1086  }
1087 
1088  return INT_STATUS_SUCCESS;
1089 }
1090 
1091 
1092 INTSTATUS
1094  void
1095  )
1101 {
1102  INTSTATUS status;
1103 
1104  for (DWORD i = 0; i < GPA_HOOK_TABLE_SIZE; i++)
1105  {
1109  }
1110 
1114 
1115  for (DWORD i = 0; i < GPA_EPT_TABLE_SIZE; i++)
1116  {
1118  }
1119 
1120  // Get the untrusted EPT index.
1122  if (!INT_SUCCESS(status))
1123  {
1124 #ifdef USER_MODE
1126 #else
1128 #endif // INT_COMPILER_MSVC
1129 
1130  ERROR("[ERROR] IntGetCurrentEptIndex failed: 0x%08x. Will assume untrusted EPT index %d.\n",
1131  status, gGuest.UntrustedEptIndex);
1132  }
1133 
1134  // By default, assume the protected EPT index is an invalid one.
1136 
1138 
1139  // Check SPP support. We use the SPP feature if two conditions are met:
1140  // 1. The Get/Set SPP protection APIs are initialized inside the interface;
1141  // 2. The SPP feature is present & enabled for this guest.
1142  if (GlueIsSppApiAvailable())
1143  {
1145  }
1146 
1147  return INT_STATUS_SUCCESS;
1148 }
1149 
1150 
1151 void
1153  void
1154  )
1158 {
1159  DWORD i, j, count, count2;
1160  LIST_ENTRY *list, *table;
1161  BYTE r, w, x;
1162  const char *msg[3] = { "read", "write", "execute" };
1163 
1164  if (NULL == gHooks)
1165  {
1166  return;
1167  }
1168 
1169  for (j = 0; j < 3; j++)
1170  {
1171  NLOG("GPA %s hooks:\n", msg[j]);
1172 
1173  if (0 == j)
1174  {
1175  table = gHooks->GpaHooks.GpaHooksRead;
1176  }
1177  else if (1 == j)
1178  {
1179  table = gHooks->GpaHooks.GpaHooksWrite;
1180  }
1181  else
1182  {
1183  table = gHooks->GpaHooks.GpaHooksExecute;
1184  }
1185 
1186  count = 0;
1187 
1188  for (i = 0; i < GPA_HOOK_TABLE_SIZE; i++)
1189  {
1190  list = table[i].Flink;
1191 
1192  count2 = 0;
1193 
1194  while (list != &table[i])
1195  {
1196  PHOOK_GPA pHook = CONTAINING_RECORD(list, HOOK_GPA, Link);
1197 
1199 
1200  NLOG("%04d: %p GPA: 0x%016llx, Offset: %04x, Length: %04x, Type: %d, Flags: %08x, Parent: %p,"
1201  "Callback: %p, Context: %p, EPT: %c%c%c\n", count++,
1202  pHook, pHook->GpaPage, pHook->Offset, pHook->Length, pHook->Header.EptHookType,
1203  pHook->Header.Flags, pHook->Header.ParentHook, pHook->Callback, pHook->Header.Context,
1204  r ? 'R' : '-', w ? 'W' : '-', x ? 'X' : '-');
1205 
1206  list = list->Flink;
1207 
1208  count2++;
1209  }
1210 
1211  NLOG("===> Load of list %04d: %d\n", i, count2);
1212  }
1213  }
1214 
1215  count = 0;
1216 
1217  for (i = 0; i < 3; i++)
1218  {
1219  QUEUE_HEAD *hooksQueue;
1220  QUEUE_ENTRY *queue;
1221 
1222  if (0 == i)
1223  {
1224  hooksQueue = &gHooks->GpaHooks.RemovedHooksRead;
1225  }
1226  else if (1 == i)
1227  {
1228  hooksQueue = &gHooks->GpaHooks.RemovedHooksWrite;
1229  }
1230  else
1231  {
1232  hooksQueue = &gHooks->GpaHooks.RemovedHooksExecute;
1233  }
1234 
1235  queue = hooksQueue->Next;
1236 
1237  NLOG("Removed hooks list for '%s':\n", 0 == i ? "read" : 1 == i ? "write" : "execute");
1238 
1239  while (queue != hooksQueue)
1240  {
1241  PHOOK_GPA pHook = CONTAINING_RECORD(queue, HOOK_GPA, LinkRemoved);
1242 
1243  NLOG("%04d: %p GPA: 0x%016llx, Offset: %04x, Length: %04x, Flags: %08x, Parent: %p,"
1244  "Callback: %p, Context: %p\n", count++,
1245  pHook, pHook->GpaPage, pHook->Offset, pHook->Length, pHook->Header.Flags,
1246  pHook->Header.ParentHook, pHook->Callback, pHook->Header.Context);
1247 
1248  queue = queue->Next;
1249  }
1250  }
1251 }
1252 
1253 
1254 static INTSTATUS
1256  _In_ BOOLEAN Enable
1257  )
1270 {
1271  INTSTATUS status = INT_STATUS_SUCCESS;
1272 
1273  if (gHooks->GpaHooks.VeEnabled && Enable)
1274  {
1276  }
1277 
1278  if (!(gHooks->GpaHooks.VeEnabled || Enable))
1279  {
1281  }
1282 
1283  // Iterate all the pages and mark the PT hooks as convertible.
1284  for (DWORD i = 0; i < GPA_EPT_TABLE_SIZE; i++)
1285  {
1287  while (list != &gHooks->GpaHooks.EptEntries[i])
1288  {
1290 
1291  list = list->Flink;
1292 
1293  if (0 != p->PtCount)
1294  {
1295  BOOLEAN setc = FALSE;
1296  const QWORD gpa = p->GpaPage;
1297  TRACE("[HOOK] Marking GPA %llx as being %s (%c%c%c)\n", gpa, Enable ? "conv" : "non-conv",
1298  !p->ReadCount ? 'R' : '-', !p->WriteCount ? 'W' : '-', !p->ExecuteCount ? 'X' : '-');
1299 
1300  if (Enable)
1301  {
1302  if (MAX_HOOK_COUNT < (QWORD)p->ConvCount + (QWORD)p->PtCount)
1303  {
1304  CRITICAL("[ERROR] Convertible hook count exceeds the limit for page 0x%016llx!\n", p->GpaPage);
1306  }
1307 
1308  setc = 0 == p->ConvCount;
1309 
1310  p->ConvCount += p->PtCount;
1311  }
1312  else
1313  {
1314  BUG_ON(p->ConvCount < p->PtCount);
1315 
1316  p->ConvCount -= p->PtCount;
1317 
1318  setc = 0 == p->ConvCount;
1319  }
1320 
1321  if (setc)
1322  {
1323  status = IntSetEPTPageConvertible(gGuest.UntrustedEptIndex, gpa, Enable);
1324  if (!INT_SUCCESS(status))
1325  {
1326  ERROR("[ERROR] IntSetEPTPageConvertible failed: 0x%08x\n", status);
1327  }
1328  }
1329  }
1330  }
1331  }
1332 
1333  gHooks->GpaHooks.VeEnabled = Enable;
1334 
1335  return status;
1336 }
1337 
1338 
1339 static INTSTATUS
1341  _In_ BOOLEAN Enable
1342  )
1355 {
1356  INTSTATUS status = INT_STATUS_SUCCESS;
1357 
1358  if (gHooks->GpaHooks.PtCacheEnabled && Enable)
1359  {
1361  }
1362 
1363  if (!(gHooks->GpaHooks.PtCacheEnabled || Enable))
1364  {
1366  }
1367 
1368  // Iterate all the pages and mark the PT hooks as convertible.
1369  for (DWORD i = 0; i < GPA_EPT_TABLE_SIZE; i++)
1370  {
1372  while (list != &gHooks->GpaHooks.EptEntries[i])
1373  {
1375 
1376  list = list->Flink;
1377 
1378  if (0 != p->PtCount)
1379  {
1380  const QWORD gpa = p->GpaPage;
1381  TRACE("[HOOK] Marking GPA %llx as being %s (%c%c%c)\n", gpa, Enable ? "PT filtered" : "EPT hooked",
1382  !p->ReadCount ? 'R' : '-', Enable ? 'W' : '-', !p->ExecuteCount ? 'X' : '-');
1383 
1385  gpa, 0 == p->ReadCount, !!Enable, 0 == p->ExecuteCount);
1386  if (!INT_SUCCESS(status))
1387  {
1388  ERROR("[ERROR] IntSetEPTPageProtection failed: 0x%08x\n", status);
1389  }
1390  }
1391  }
1392  }
1393 
1394  // Safe to be here, since we don't return if IntSetEPTPageProtection returns errors.
1395  gHooks->GpaHooks.PtCacheEnabled = Enable;
1396 
1397  return status;
1398 }
1399 
1400 
1401 INTSTATUS
1403  void
1404  )
1408 {
1410 }
1411 
1412 
1413 INTSTATUS
1415  void
1416  )
1420 {
1422 }
1423 
1424 
1425 INTSTATUS
1427  void
1428  )
1432 {
1434 }
1435 
1436 
1437 INTSTATUS
1439  void
1440  )
1444 {
1446 }
1447 
1448 
1449 INTSTATUS
1451  _In_ DWORD EptIndex,
1452  _In_ QWORD Address,
1453  _Out_ BYTE *Read,
1454  _Out_ BYTE *Write,
1455  _Out_ BYTE *Execute
1456  )
1469 {
1470  const HOOK_EPT_ENTRY *pEpt;
1471 
1472  if (EptIndex != gGuest.UntrustedEptIndex)
1473  {
1474  ERROR("[ERROR] Only the Untrusted EPT is supported!\n");
1476  }
1477 
1478  pEpt = IntHookGpaGetExistingEptEntry(Address & PAGE_MASK);
1479  if (NULL != pEpt)
1480  {
1481  *Read = 0 == pEpt->ReadCount;
1482  *Write = 0 == pEpt->WriteCount;
1483  *Execute = 0 == pEpt->ExecuteCount;
1484  }
1485  else
1486  {
1487  *Read = *Write = *Execute = 1;
1488  }
1489 
1490  return INT_STATUS_SUCCESS;
1491 }
1492 
1493 
1494 INTSTATUS
1496  void
1497  )
1503 {
1504  INTSTATUS status = INT_STATUS_SUCCESS;
1505 
1506  // Iterate all the pages and mark the PT hooks as convertible.
1507  for (DWORD i = 0; i < GPA_EPT_TABLE_SIZE; i++)
1508  {
1510  while (list != &gHooks->GpaHooks.EptEntries[i])
1511  {
1512  BOOLEAN c;
1514 
1515  list = list->Flink;
1516 
1518  if (c)
1519  {
1520  LOG("!!!! Page 0x%016llx is convertible!\n", p->GpaPage);
1521  }
1522  else if (p->PtCount)
1523  {
1524  LOG("**** Page 0x%016llx is page table, but it is NOT convertible!\n", p->GpaPage);
1525  }
1526  }
1527  }
1528 
1529  return status;
1530 }
1531 #ifdef INT_COMPILER_MSVC
1532 #pragma warning(pop)
1533 #endif // INT_COMPILER_MSVC
#define _In_opt_
Definition: intro_sal.h:16
HOOK_SPP_ENTRY * Spp
SPP entry. Allocated only for write hooks that are less than a page in size.
Definition: hook_gpa.h:83
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
#define CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
#define ROUND_UP(what, to)
Definition: introdefs.h:158
#define MAX_HOOK_COUNT
Total number of hooks supported for each type.
Definition: hook_gpa.h:98
#define GPA_REF_COUNT(epte)
Definition: hook_gpa.h:93
#define GPA_HOOK_TABLE_SIZE
Size of the GPA hook hash.
Definition: hook_gpa.h:87
HOOK_HEADER Header
Hook header.
Definition: hook_gpa.h:43
DWORD ReadCount
Number of read EPT hooks.
Definition: hook_gpa.h:77
QUEUE_HEAD RemovedHooksExecute
List of removed execute hooks.
Definition: hook_gpa.h:112
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
INTSTATUS IntHookGpaEnablePtCache(void)
Enable PT filtering.
Definition: hook_gpa.c:1414
INTSTATUS IntGetEPTPageConvertible(DWORD EptIndex, QWORD Address, BOOLEAN *Convertible)
Definition: glue.c:1210
LIST_HEAD GpaHooksWrite[GPA_HOOK_TABLE_SIZE]
Hash table of write hooks.
Definition: hook_gpa.h:106
#define GPA_HOOK_ID(addr)
Definition: hook_gpa.h:88
uint8_t BYTE
Definition: intro_types.h:47
Read-access hook.
Definition: glueiface.h:298
#define _In_
Definition: intro_sal.h:21
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
uint16_t WORD
Definition: intro_types.h:48
INTSTATUS IntPtiCacheRemove(QWORD Gpa)
Remove a guest physical page from the PT filter cache.
Definition: ptfilter.c:1863
#define IntEnterDebugger()
Definition: introcore.h:373
Used by GPA hooks.
Definition: hook.h:17
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
void QueueInsert(QUEUE_HEAD *QueueHead, QUEUE_ENTRY *Element)
Definition: queue.h:52
#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
#define BUG_ON(cond)
Definition: introdefs.h:236
#define PAGE_OFFSET
Definition: pgtable.h:32
#define ARRAYSIZE(A)
Definition: introdefs.h:101
DWORD WriteCount
Number of write EPT hooks.
Definition: hook_gpa.h:78
BYTE EptHookType
The type of the hook in EPT (see IG_EPT_HOOK_TYPE)
Definition: hook.h:69
#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
#define PHYS_PAGE_MASK
Definition: pgtable.h:38
int INTSTATUS
The status data type.
Definition: introstatus.h:24
static INTSTATUS IntHookGpaDeleteHookInternal(HOOK_GPA *Hook, DWORD Flags)
Permanently delete a GPA hook.
Definition: hook_gpa.c:784
void QueueInitialize(QUEUE_HEAD *QueueHead)
Definition: queue.h:21
HOOK_STATE * gHooks
Global hooks state.
Definition: hook.c:8
INTSTATUS IntHookGpaRemoveHook(HOOK_GPA **Hook, DWORD Flags)
Remove a GPA hook.
Definition: hook_gpa.c:734
INTSTATUS IntHookGpaEnableVe(void)
Enable VE filtering.
Definition: hook_gpa.c:1402
INTSTATUS IntHookGpaCommitHooks(void)
Commit existing modified hooks.
Definition: hook_gpa.c:872
#define LOG(fmt,...)
Definition: glue.h:61
#define HOOK_FLG_HIGH_PRIORITY
If flag is set, the callback associated to this hook will have a higher priority than the others...
Definition: hook.h:54
INTSTATUS IntSetEPTPageProtection(DWORD EptIndex, QWORD Gpa, BYTE Read, BYTE Write, BYTE Execute)
Definition: glue.c:672
BYTE HookType
The type of the hook structure (see _HOOK_TYPE)
Definition: hook.h:68
static INTSTATUS IntEnableEptNotifications(void)
Definition: callbacks.h:91
static INTSTATUS IntHookGpaEnableDisablePtCache(BOOLEAN Enable)
Enable or disable the in guest PT filtering mechanism.
Definition: hook_gpa.c:1340
QUEUE_HEAD RemovedHooksWrite
List of removed write hooks.
Definition: hook_gpa.h:110
INTSTATUS IntHookGpaIsPageHooked(QWORD Gpa, BYTE *Read, BYTE *Write, BYTE *Execute)
Get the read, write and execute access for the given guest physical page.
Definition: hook_gpa.c:1002
LIST_HEAD GpaHooksRead[GPA_HOOK_TABLE_SIZE]
Hash table of read hooks.
Definition: hook_gpa.h:107
static INTSTATUS IntDisableEptNotifications(void)
Definition: callbacks.h:108
BOOLEAN SupportSPP
Set to True if support for SPP was detected.
Definition: guests.h:353
#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
DWORD SppCount[32]
Number of write hooks placed on each 128 bytes region within the page.
Definition: hook_gpa.h:64
#define _Out_opt_
Definition: intro_sal.h:30
#define INT_STATUS_ALREADY_INITIALIZED
Definition: introstatus.h:263
#define IG_CURRENT_VCPU
For APIs that take a VCPU number as a parameter, this can be used to specify that the current VCPU sh...
Definition: glueiface.h:324
INTSTATUS IntHookGpaDisableHook(HOOK_GPA *Hook)
Disable a GPA hook.
Definition: hook_gpa.c:947
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
static INTSTATUS IntHookGpaRemoveHookInternal(HOOK_GPA *Hook, DWORD Flags)
Remove a GPA hook.
Definition: hook_gpa.c:671
unsigned long long QWORD
Definition: intro_types.h:53
PHOOK_EPT_ENTRY IntHookGpaGetEptEntry(QWORD GpaPage)
Get the EPT entry associated with a physical page.
Definition: hook_gpa.c:18
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
WORD Offset
The offset within the page where the hook starts. 0-4095 valid.
Definition: hook_gpa.h:47
QWORD GpaPage
The page where the hook is set.
Definition: hook_gpa.h:46
#define TRUE
Definition: intro_types.h:30
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
QWORD CurSpp
Current SPP permissions.
Definition: hook_gpa.h:63
#define INVALID_EPTP_INDEX
Definition: glue.h:66
#define TRACE(fmt,...)
Definition: glue.h:58
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
QWORD GpaPage
Guest physical page address.
Definition: hook_gpa.h:75
struct _QUEUE * Next
Definition: queue.h:14
static void InsertAfterList(LIST_ENTRY *Pivot, LIST_ENTRY *Item)
Definition: introlists.h:169
INTSTATUS IntHookGpaGetEPTPageProtection(DWORD EptIndex, QWORD Address, BYTE *Read, BYTE *Write, BYTE *Execute)
Get the EPT page protection for the indicated guest physical address.
Definition: hook_gpa.c:1450
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
QUEUE_HEAD RemovedHooksRead
List of removed read hooks.
Definition: hook_gpa.h:111
#define INT_STATUS_ALREADY_INITIALIZED_HINT
Definition: introstatus.h:323
#define ROUND_DOWN(what, to)
Definition: introdefs.h:159
HOOK_GPA_STATE GpaHooks
GPA hooks state.
Definition: hook.h:92
LIST_HEAD EptEntries[GPA_EPT_TABLE_SIZE]
Hash table containing the EPT entries elements (HOOK_EPT_ENTRY).
Definition: hook_gpa.h:115
static void InitializeListHead(LIST_ENTRY *ListHead)
Definition: introlists.h:69
static INTSTATUS IntHookGpaSetNewPageProtection(HOOK_GPA *Hook)
Update EPT protection for a removed hook.
Definition: hook_gpa.c:516
#define PAGE_SIZE
Definition: common.h:53
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
PHOOK_EPT_ENTRY IntHookGpaGetExistingEptEntry(QWORD GpaPage)
Get the EPT entry associated with the provided guest physical page.
Definition: hook_gpa.c:159
INT64 HooksCount
Total number of hooks set.
Definition: hook_gpa.h:117
uint32_t DWORD
Definition: intro_types.h:49
static void IntHookGpaInsertHookInList(LIST_ENTRY *List, HOOK_GPA *Hook)
Insert the hook in the given list of hooks.
Definition: hook_gpa.c:117
INTSTATUS IntHookGpaDisableVe(void)
Disable VE filtering.
Definition: hook_gpa.c:1426
void IntHookGpaDump(void)
Dump the entire contents of the GPA hook system, listing each hook.
Definition: hook_gpa.c:1152
DWORD ProtectedEptIndex
The EPTP index of the trusted EPT.
Definition: guests.h:397
BOOLEAN SppEnabled
True if SPP support is present and enabled.
Definition: hook_gpa.h:122
DWORD PtCount
Number of PT hooks.
Definition: hook_gpa.h:80
DWORD ConvCount
Definition: hook_gpa.h:81
Definition: queue.h:10
WORD Length
The length, in bytes, of the hook. 1-4096 valid.
Definition: hook_gpa.h:48
INTSTATUS IntGetEPTPageProtection(DWORD EptIndex, QWORD Gpa, BYTE *Read, BYTE *Write, BYTE *Execute)
Definition: glue.c:659
#define IntDbgEnterDebugger()
Definition: introcore.h:381
LIST_ENTRY Link
List entry element.
Definition: hook_gpa.h:74
#define INT_STATUS_ARITHMETIC_OVERFLOW
Definition: introstatus.h:220
INTSTATUS IntHookGpaDisablePtCache(void)
Disable PT filtering.
Definition: hook_gpa.c:1438
INTSTATUS(* PFUNC_EptViolationCallback)(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
EPT callback handler.
Definition: hook_gpa.h:30
static INTSTATUS IntHookGpaGetSppEntry(HOOK_EPT_ENTRY *Entry)
Allocates a SPP entry for the given EPT hook.
Definition: hook_gpa.c:61
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:48
#define GPA_EPT_ID(addr)
Definition: hook_gpa.h:91
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:189
BOOLEAN VeEnabled
True if VE filtering is enabled.
Definition: hook_gpa.h:120
LIST_HEAD GpaHooksExecute[GPA_HOOK_TABLE_SIZE]
Hash table of execute hooks.
Definition: hook_gpa.h:108
INTSTATUS IntHookGpaInit(void)
Initialize the GPA hook system. This function should be called only once, during introspection init...
Definition: hook_gpa.c:1093
BOOLEAN PtCacheEnabled
True if the PT cache is active inside the guest.
Definition: hook_gpa.h:121
#define GPA_EPT_TABLE_SIZE
Size of the EPT entries hash.
Definition: hook_gpa.h:90
INTSTATUS IntHookGpaDeleteHook(HOOK_GPA **Hook, DWORD Flags)
Permanently delete a GPA hook.
Definition: hook_gpa.c:826
DWORD ExecuteCount
Number of execute EPT hooks.
Definition: hook_gpa.h:79
#define NLOG(fmt,...)
Definition: glue.h:43
INTSTATUS IntHookGpaEnableHook(HOOK_GPA *Hook)
Enable a GPA hook.
Definition: hook_gpa.c:973
PFUNC_EptViolationCallback Callback
The callback for this hook.
Definition: hook_gpa.h:50
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
struct _LIST_ENTRY * Blink
Definition: introlists.h:25
static INTSTATUS IntHookGpaEnableDisableVe(BOOLEAN Enable)
Enable or disable the VE filtering mechanism.
Definition: hook_gpa.c:1255
INTSTATUS IntHookGpaFindConvertible(void)
Displays all convertible pages.
Definition: hook_gpa.c:1495
QUEUE_ENTRY * QueueRemove(QUEUE_HEAD *QueueHead)
Definition: queue.h:39
#define CRITICAL(fmt,...)
Definition: glue.h:63
INTSTATUS IntGetCurrentEptIndex(DWORD CpuNumber, DWORD *EptpIndex)
Get the EPTP index of the currently loaded EPT.
Definition: introcpu.c:1238
#define IC_TAG_EPTE
EPT hook entry.
Definition: memtags.h:100
DWORD Flags
Generic flags. Check out EPT Hook flags.
Definition: hook.h:67
BOOLEAN HooksRemoved
True if hooks were removed, and we must do the cleanup..
Definition: hook_gpa.h:119
Execute-access hook.
Definition: glueiface.h:300
#define IC_TAG_GPAH
GPA hook.
Definition: memtags.h:34
#define HOOK_PAGE_TABLE_FLAGS
Any of these flags set indicates that we are dealing with a page table page.
Definition: hook.h:57
Write-access hook.
Definition: glueiface.h:299
#define PAGE_MASK
Definition: pgtable.h:35
BOOLEAN GlueIsSppApiAvailable(void)
Checks if the SPP APIs in GLUE_IFACE are implemented.
Definition: glue.c:705
#define PAGE_SIZE_4K
Definition: pgtable.h:10
DWORD UntrustedEptIndex
The EPTP index of the untrusted EPT.
Definition: guests.h:393
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
INTSTATUS IntSetEPTPageConvertible(DWORD EptIndex, QWORD Address, BOOLEAN Convertible)
Definition: glue.c:1226
#define IC_TAG_SPPE
SPP entry.
Definition: memtags.h:116
INTSTATUS IntSetSPPPageProtection(QWORD Gpa, QWORD Spp)
Definition: glue.c:695
#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 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