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  GpaPage &= PHYS_PAGE_MASK;
37 
38  pEptEntry = IntHookGpaGetExistingEptEntry(GpaPage);
39  if (NULL != pEptEntry)
40  {
41  return pEptEntry;
42  }
43 
44  //
45  // No entry found for this GPA, allocate a new one.
46  // NOTE: If we see a page for the first time (it is not hooked), we can safely assume it is RWX.
47  //
48  pEptEntry = HpAllocWithTag(sizeof(*pEptEntry), IC_TAG_EPTE);
49  if (NULL == pEptEntry)
50  {
51  return NULL;
52  }
53 
54  pEptEntry->GpaPage = GpaPage;
55 
56  InsertTailList(&gHooks->GpaHooks.EptEntries[id], &pEptEntry->Link);
57 
58  return pEptEntry;
59 }
60 
61 
62 static INTSTATUS
64  _Inout_ HOOK_EPT_ENTRY *Entry
65  )
81 {
82  if (NULL != Entry->Spp)
83  {
85  }
86 
87  Entry->Spp = HpAllocWithTag(sizeof(*Entry->Spp), IC_TAG_SPPE);
88  if (NULL == Entry->Spp)
89  {
91  }
92 
93  // Initially, the SPP entry is considered non-writable.
94  Entry->Spp->OldSpp = 0;
95 
96  // If this isn't the first write hook on this page, make sure we reflect it inside the current SPP permissions
97  // and inside the 128B non-write areas.
98  if (Entry->WriteCount == 0)
99  {
100  Entry->Spp->CurSpp = 0x5555555555555555;
101  }
102  else
103  {
104  // This isn't the first write-hook on this page, but it is the first sub-page hook - this means that a previous
105  // write hook covers the entire page.
106  Entry->Spp->CurSpp = 0;
107 
108  for (DWORD i = 0; i < 32; i++)
109  {
110  Entry->Spp->SppCount[i] += Entry->WriteCount;
111  }
112  }
113 
114  return INT_STATUS_SUCCESS;
115 }
116 
117 
118 static void
120  _Inout_ LIST_ENTRY *List,
121  _In_ HOOK_GPA *Hook
122  )
133 {
134  if (0 == (Hook->Header.Flags & HOOK_FLG_HIGH_PRIORITY))
135  {
136  InsertTailList(List, &Hook->Link);
137  }
138  else
139  {
140  LIST_ENTRY *pivot = List->Flink;
141 
142  while (pivot != List)
143  {
144  HOOK_GPA *pHook = CONTAINING_RECORD(pivot, HOOK_GPA, Link);
145 
146  if (0 == (pHook->Header.Flags & HOOK_FLG_HIGH_PRIORITY))
147  {
148  pivot = pivot->Blink;
149  break;
150  }
151 
152  pivot = pivot->Flink;
153  }
154 
155  InsertAfterList(pivot, &Hook->Link);
156  }
157 }
158 
159 
162  _In_ QWORD GpaPage
163  )
171 {
172  const DWORD id = GPA_EPT_ID(GpaPage);
174 
175  GpaPage &= PHYS_PAGE_MASK;
176 
177  while (list != &gHooks->GpaHooks.EptEntries[id])
178  {
179  HOOK_EPT_ENTRY *pEptEntry = CONTAINING_RECORD(list, HOOK_EPT_ENTRY, Link);
180  list = list->Flink;
181 
182  if (pEptEntry->GpaPage == GpaPage)
183  {
184  return pEptEntry;
185  }
186  }
187 
188  return NULL;
189 }
190 
191 
192 INTSTATUS
194  _In_ QWORD Gpa,
195  _In_ DWORD Length,
196  _In_ BYTE Type,
198  _In_opt_ void *Context,
199  _In_opt_ void *ParentHook,
200  _In_opt_ DWORD Flags,
201  _Out_opt_ HOOK_GPA **Hook
202  )
273 {
274  INTSTATUS status;
275  HOOK_GPA *pGpaHook;
276  HOOK_EPT_ENTRY *eptEntry;
277  DWORD hid;
278  BOOLEAN setr, setc, sets;
279 
280  if (NULL == Callback)
281  {
283  }
284 
285  if ((Gpa & PAGE_MASK) != ((Gpa + Length - 1) & PAGE_MASK))
286  {
288  }
289 
290  if (Length > PAGE_SIZE)
291  {
293  }
294 
295  if ((Type != IG_EPT_HOOK_READ) && (Type != IG_EPT_HOOK_WRITE) && (Type != IG_EPT_HOOK_EXECUTE))
296  {
298  }
299 
300  pGpaHook = NULL;
301  hid = GPA_HOOK_ID(Gpa);
302  Flags &= HOOK_FLG_GLOBAL_MASK;
303  setr = setc = sets = FALSE;
304 
305  pGpaHook = HpAllocWithTag(sizeof(*pGpaHook), IC_TAG_GPAH);
306  if (NULL == pGpaHook)
307  {
309  }
310 
311  pGpaHook->Header.Context = Context;
312  pGpaHook->Header.ParentHook = ParentHook;
313  pGpaHook->Header.Flags = Flags;
314  pGpaHook->Header.HookType = hookTypeGpa;
315  pGpaHook->Header.EptHookType = Type;
316 
317  pGpaHook->Callback = Callback;
318  pGpaHook->GpaPage = Gpa & PAGE_MASK;
319  pGpaHook->Length = (WORD)Length;
320  pGpaHook->Offset = Gpa & PAGE_OFFSET;
321 
322  // Get the EPT entry, in order to update the restrictions.
323  eptEntry = IntHookGpaGetEptEntry(Gpa);
324  if (NULL == eptEntry)
325  {
327  goto cleanup_and_exit;
328  }
329 
330  // Handle Sub-Page Protection. Note that by default, we won't allocate a SPP entry until a sub-page hook is placed.
331  if (gHooks->GpaHooks.SppEnabled && (IG_EPT_HOOK_WRITE == Type))
332  {
333  if ((Length < PAGE_SIZE_4K) && (NULL == eptEntry->Spp))
334  {
335  status = IntHookGpaGetSppEntry(eptEntry);
336  if (!INT_SUCCESS(status))
337  {
338  ERROR("[ERROR] IntHookGpaGetSppEntry failed: 0x%08x\n", status);
339  goto cleanup_and_exit;
340  }
341  }
342 
343  if (NULL != eptEntry->Spp)
344  {
345  DWORD i, low, high;
346 
347  // The low 128B chunk that is being hooked.
348  low = ROUND_DOWN((DWORD)pGpaHook->Offset, 128) >> 7;
349 
350  // The high 128B chunk that is being hooked (exclusive).
351  high = ROUND_UP((DWORD)(pGpaHook->Offset + pGpaHook->Length), 128) >> 7;
352 
353  for (i = low; i < high; i++)
354  {
355  if (0 == eptEntry->Spp->SppCount[i]++)
356  {
357  eptEntry->Spp->CurSpp &= ~(1ULL << (2 * i));
358  sets = TRUE;
359  }
360  }
361  }
362  }
363 
364  switch (Type)
365  {
366  case IG_EPT_HOOK_READ:
367  if (MAX_HOOK_COUNT == eptEntry->ReadCount)
368  {
369  CRITICAL("[ERROR] Read hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
371  goto cleanup_and_exit;
372  }
373 
374  setr = 0 == eptEntry->ReadCount++;
375  break;
376  case IG_EPT_HOOK_WRITE:
377  if (MAX_HOOK_COUNT == eptEntry->WriteCount)
378  {
379  CRITICAL("[ERROR] Write hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
381  goto cleanup_and_exit;
382  }
383 
384  setr = 0 == eptEntry->WriteCount++;
385  break;
386  case IG_EPT_HOOK_EXECUTE:
387  if (MAX_HOOK_COUNT == eptEntry->ExecuteCount)
388  {
389  CRITICAL("[ERROR] Execute hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
391  goto cleanup_and_exit;
392  }
393 
394  setr = 0 == eptEntry->ExecuteCount++;
395  break;
396  default:
397  break;
398  }
399 
400  // Paging structure hooks will be convertible - they will be delivered as #VE in the guest.
401  if (0 != (Flags & HOOK_PAGE_TABLE_FLAGS))
402  {
403  if (MAX_HOOK_COUNT == eptEntry->PtCount)
404  {
405  CRITICAL("[ERROR] Page table hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
407  goto cleanup_and_exit;
408  }
409 
410  eptEntry->PtCount++;
411 
413  {
414  if (MAX_HOOK_COUNT == eptEntry->ConvCount)
415  {
416  CRITICAL("[ERROR] Convertible hook count exceeds the limit for page 0x%016llx!\n", eptEntry->GpaPage);
418  goto cleanup_and_exit;
419  }
420 
421  setc = 0 == eptEntry->ConvCount++;
422  }
423  else if (gHooks->GpaHooks.PtCacheEnabled)
424  {
425  status = IntPtiCacheRemove(Gpa);
426  if (!INT_SUCCESS(status))
427  {
428  ERROR("[ERROR] IntPtsInt3CacheRemove failed for 0x%016llx and this sucks\n", Gpa);
430  }
431 
432  if (IG_EPT_HOOK_WRITE == Type)
433  {
434  // Don't make the entry non-writable. Also, don't touch the SPP permissions.
435  setr = sets = FALSE;
436  }
437  }
438  }
439 
440  // Set the appropriate access rights.
441  if (setr)
442  {
444  pGpaHook->GpaPage,
445  0 == eptEntry->ReadCount,
446  0 == eptEntry->WriteCount,
447  0 == eptEntry->ExecuteCount);
448  if (!INT_SUCCESS(status))
449  {
450  ERROR("[ERROR] IntSetEPTPageProtection failed for GPA 0x%016llx: 0x%08x\n", pGpaHook->GpaPage, status);
451  goto cleanup_and_exit;
452  }
453  }
454 
455  if (setc)
456  {
457  status = IntSetEPTPageConvertible(gGuest.UntrustedEptIndex, pGpaHook->GpaPage, 0 != eptEntry->ConvCount);
458  if (!INT_SUCCESS(status))
459  {
460  ERROR("[ERROR] IntSetEPTConvertible failed for GPA 0x%016llx: 0x%08x\n", pGpaHook->GpaPage, status);
461  goto cleanup_and_exit;
462  }
463  }
464 
465  // Modify the SPP entry, if needed.
466  if (sets)
467  {
468  status = IntSetSPPPageProtection(pGpaHook->GpaPage, eptEntry->Spp->CurSpp);
469  if (!INT_SUCCESS(status))
470  {
471  ERROR("[ERROR] IntSetSPPPageProtection failed: 0x%08x\n", status);
472  goto cleanup_and_exit;
473  }
474  }
475 
476  if (0 == gHooks->GpaHooks.HooksCount++)
477  {
478  status = IntEnableEptNotifications();
479  if (!INT_SUCCESS(status))
480  {
481  goto cleanup_and_exit;
482  }
483  }
484 
485  // Insert the hook in the uncommitted hooks list.
486  if (IG_EPT_HOOK_READ == Type)
487  {
489  }
490  else if (IG_EPT_HOOK_WRITE == Type)
491  {
493  }
494  else
495  {
497  }
498 
499  if (NULL != Hook)
500  {
501  *Hook = pGpaHook;
502  }
503 
504  status = INT_STATUS_SUCCESS;
505 
506 cleanup_and_exit:
507  if (!INT_SUCCESS(status))
508  {
509  if (NULL != pGpaHook)
510  {
511  HpFreeAndNullWithTag(&pGpaHook, IC_TAG_GPAH);
512  }
513  }
514 
515  return status;
516 }
517 
518 
519 static INTSTATUS
521  _In_ HOOK_GPA *Hook
522  )
535 {
536  INTSTATUS status;
537  HOOK_EPT_ENTRY *eptEntry;
538  BOOLEAN setr, setc, sets;
539 
540  eptEntry = NULL;
541  setr = setc = sets = FALSE;
542 
543  eptEntry = IntHookGpaGetEptEntry(Hook->GpaPage);
544  if (NULL == eptEntry)
545  {
547  }
548 
549  // Removing hook - restore the correct access bits.
550  switch (Hook->Header.EptHookType)
551  {
552  case IG_EPT_HOOK_READ:
553  BUG_ON(0 == eptEntry->ReadCount);
554 
555  setr = 0 == --eptEntry->ReadCount;
556  break;
557  case IG_EPT_HOOK_WRITE:
558  BUG_ON(0 == eptEntry->WriteCount);
559 
560  setr = 0 == --eptEntry->WriteCount;
561  break;
562  case IG_EPT_HOOK_EXECUTE:
563  BUG_ON(0 == eptEntry->ExecuteCount);
564 
565  setr = 0 == --eptEntry->ExecuteCount;
566  break;
567  default:
568  break;
569  }
570 
571  if (0 != (Hook->Header.Flags & HOOK_PAGE_TABLE_FLAGS))
572  {
573  BUG_ON(0 == eptEntry->PtCount);
574 
575  eptEntry->PtCount--;
576 
578  {
579  BUG_ON(0 == eptEntry->ConvCount);
580 
581  setc = 0 == --eptEntry->ConvCount;
582  }
583  else if (gHooks->GpaHooks.PtCacheEnabled)
584  {
585  if (IG_EPT_HOOK_WRITE == Hook->Header.EptHookType)
586  {
587  // No need to modify EPT, as we left the entry writable.
588  setr = sets = FALSE;
589  }
590  }
591  }
592 
593  if (gHooks->GpaHooks.SppEnabled && (IG_EPT_HOOK_WRITE == Hook->Header.EptHookType))
594  {
595  if (NULL != eptEntry->Spp)
596  {
597  DWORD low, high;
598 
599  // The low 128B chunk that is being hooked.
600  low = ROUND_DOWN((DWORD)Hook->Offset, 128) >> 7;
601 
602  // The high 128B chunk that is being hooked (exclusive).
603  high = ROUND_UP((DWORD)(Hook->Offset + Hook->Length), 128) >> 7;
604 
605  for (DWORD i = low; i < high; i++)
606  {
607  if (0 == --eptEntry->Spp->SppCount[i])
608  {
609  eptEntry->Spp->CurSpp |= (1ULL << (2 * i));
610  sets = TRUE;
611  }
612  }
613  }
614  }
615 
616  if (setr)
617  {
618  // If no hooks are set for a particular EPT permission, it means that the page has that permission.
619  const BYTE r = eptEntry->ReadCount == 0;
620  const BYTE w = eptEntry->WriteCount == 0;
621  const BYTE x = eptEntry->ExecuteCount == 0;
622 
623  // Modify the rights.
625  Hook->GpaPage,
626  r,
627  w,
628  x);
629  if (!INT_SUCCESS(status))
630  {
631  ERROR("[ERROR] IntSetEPTPageProtection failed for GPA 0x%016llx: 0x%08x\n", Hook->GpaPage, status);
632  return status;
633  }
634  }
635 
636  if (setc)
637  {
638  // Modify the convertible flag.
639  status = IntSetEPTPageConvertible(gGuest.UntrustedEptIndex, Hook->GpaPage, 0 != eptEntry->ConvCount);
640  if (!INT_SUCCESS(status))
641  {
642  ERROR("[ERROR] IntSetEPTPageConvertible failed for GPA 0x%016llx: 0x%08x\n", Hook->GpaPage, status);
643  return status;
644  }
645  }
646 
647  if (sets)
648  {
649  status = IntSetSPPPageProtection(Hook->GpaPage, eptEntry->Spp->CurSpp);
650  if (!INT_SUCCESS(status))
651  {
652  ERROR("[ERROR] IntSetSPPPageProtection failed for GPA 0x%016llx: 0x%08x\n", Hook->GpaPage, status);
653  return status;
654  }
655  }
656 
657  if ((0 == eptEntry->WriteCount) && (NULL != eptEntry->Spp))
658  {
659  // The last write hook was removed, we can free the SPP entry as well.
660  HpFreeAndNullWithTag(&eptEntry->Spp, IC_TAG_SPPE);
661  }
662 
663  if (0 == GPA_REF_COUNT(eptEntry))
664  {
665  // All hooks were removed, there's no point in keeping this entry anymore
666  RemoveEntryList(&eptEntry->Link);
667  HpFreeAndNullWithTag(&eptEntry, IC_TAG_EPTE);
668  }
669 
670  return INT_STATUS_SUCCESS;
671 }
672 
673 
674 static INTSTATUS
676  _In_ HOOK_GPA *Hook,
677  _In_ DWORD Flags
678  )
693 {
694  if (0 != (Hook->Header.Flags & HOOK_FLG_REMOVE))
695  {
697  }
698 
699  Hook->Header.Flags |= HOOK_FLG_DISABLED | HOOK_FLG_REMOVE;
700 
701  if (Flags & HOOK_FLG_CHAIN_DELETE)
702  {
703  Hook->Header.Flags |= HOOK_FLG_CHAIN_DELETE;
704 
705  // No point inserting it into the removed queue, since it will ignore chain deleted hooks
706  gHooks->Dirty = TRUE;
707 
708  return INT_STATUS_SUCCESS;
709  }
710 
711  if (IG_EPT_HOOK_READ == Hook->Header.EptHookType)
712  {
713  QueueInsert(&gHooks->GpaHooks.RemovedHooksRead, &Hook->LinkRemoved);
714  }
715  else if (IG_EPT_HOOK_WRITE == Hook->Header.EptHookType)
716  {
717  QueueInsert(&gHooks->GpaHooks.RemovedHooksWrite, &Hook->LinkRemoved);
718  }
719  else if (IG_EPT_HOOK_EXECUTE == Hook->Header.EptHookType)
720  {
721  QueueInsert(&gHooks->GpaHooks.RemovedHooksExecute, &Hook->LinkRemoved);
722  }
723  else
724  {
725  ERROR("[ERROR] Invalid hook type %d for hook %p\n", Hook->Header.EptHookType, Hook);
727  }
728 
730 
731  gHooks->Dirty = TRUE;
732 
733  return INT_STATUS_SUCCESS;
734 }
735 
736 
737 INTSTATUS
739  _Inout_ HOOK_GPA **Hook,
740  _In_ DWORD Flags
741  )
757 {
758  INTSTATUS status;
759 
760  if (NULL == Hook)
761  {
763  }
764 
765  if (NULL == *Hook)
766  {
768  }
769 
770  Flags &= HOOK_FLG_GLOBAL_MASK;
771 
772  status = IntHookGpaRemoveHookInternal(*Hook, Flags);
773  if (!INT_SUCCESS(status))
774  {
775  ERROR("[ERROR] IntHookGpaRemoveHookInternal failed: 0x%08x\n", status);
776  }
777 
778  if (!(Flags & HOOK_FLG_CHAIN_DELETE))
779  {
780  *Hook = NULL;
781  }
782 
783  return INT_STATUS_SUCCESS;
784 }
785 
786 
787 static INTSTATUS
789  _In_ HOOK_GPA *Hook,
790  _In_ DWORD Flags
791  )
800 {
801  INTSTATUS status;
802 
803  UNREFERENCED_PARAMETER(Flags);
804 
805  // Restore old access rights on the page.
806  status = IntHookGpaSetNewPageProtection(Hook);
807  if (!INT_SUCCESS(status))
808  {
809  ERROR("[ERROR] IntHookGpaSetNewPageProtection failed: 0x%08x\n", status);
810  }
811 
812  if (0 >= --gHooks->GpaHooks.HooksCount)
813  {
814  status = IntDisableEptNotifications();
815  if (!INT_SUCCESS(status))
816  {
817  return status;
818  }
819  }
820 
821  RemoveEntryList(&Hook->Link);
822 
824 
825  return status;
826 }
827 
828 
829 INTSTATUS
831  _In_ HOOK_GPA **Hook,
832  _In_ DWORD Flags
833  )
846 {
847  INTSTATUS status;
848 
849  UNREFERENCED_PARAMETER(Flags);
850 
851  if (NULL == Hook)
852  {
854  }
855 
856  if (NULL == *Hook)
857  {
859  }
860 
861  Flags &= HOOK_FLG_GLOBAL_MASK;
862 
863  status = IntHookGpaDeleteHookInternal(*Hook, Flags);
864  if (!INT_SUCCESS(status))
865  {
866  ERROR("[ERROR] IntHookGpaDeleteHookInternal failed: 0x%08x\n", status);
867  }
868 
869  *Hook = NULL;
870 
871  return status;
872 }
873 
874 
875 INTSTATUS
877  void
878  )
888 {
889  // The order in which we remove hooks must be the following:
890  // 1. Read hooks
891  // 2. Write hooks
892  // 3. Execute hooks
893  // If we'd commit read hooks first, we may end up with inconsistent EPT rights -> Write & Execute,
894  // which may trigger EPT misconfiguration.
895  QUEUE_HEAD *hooksQueues[] =
896  {
900  };
901 
902  INTSTATUS status;
903 
905  {
906  return INT_STATUS_SUCCESS;
907  }
908 
909  // Iterate the list of removed hooks and actually delete the designated hooks.
910  for (DWORD i = 0; i < ARRAYSIZE(hooksQueues); i++)
911  {
912  QUEUE_HEAD *hooksQueue = hooksQueues[i];
913  QUEUE_ENTRY *queue;
914 
915  while ((queue = QueueRemove(hooksQueue)) != hooksQueue)
916  {
917  PHOOK_GPA pGpaHook = CONTAINING_RECORD(queue, HOOK_GPA, LinkRemoved);
918 
919  if (0 != (pGpaHook->Header.Flags & HOOK_FLG_CHAIN_DELETE))
920  {
921  // Chain delete requested - we won't commit this hook, we'll let it's parent decide its faith.
922  ERROR("[ERROR] Invalid hook state: %x (chain delete) for hook at GPA 0x%016llx\n",
923  pGpaHook->Header.Flags, pGpaHook->GpaPage);
924  continue;
925  }
926 
927  if (0 == (pGpaHook->Header.Flags & HOOK_FLG_REMOVE))
928  {
929  ERROR("[ERROR] Invalid hook state: %x for hook at GPA 0x%016llx\n",
930  pGpaHook->Header.Flags,
931  pGpaHook->GpaPage);
932 
934  }
935 
936  status = IntHookGpaDeleteHookInternal(pGpaHook, 0);
937  if (!INT_SUCCESS(status))
938  {
939  ERROR("[ERROR] IntHookGpaDeleteHookInternal failed: 0x%08x\n", status);
940  }
941  }
942  }
943 
945 
946  return INT_STATUS_SUCCESS;
947 }
948 
949 
950 INTSTATUS
952  _In_ HOOK_GPA *Hook
953  )
964 {
965  if (NULL == Hook)
966  {
968  }
969 
970  Hook->Header.Flags |= HOOK_FLG_DISABLED;
971 
972  return INT_STATUS_SUCCESS;
973 }
974 
975 
976 INTSTATUS
978  _In_ HOOK_GPA *Hook
979  )
993 {
994  if (NULL == Hook)
995  {
997  }
998 
999  Hook->Header.Flags &= ~HOOK_FLG_DISABLED;
1000 
1001  return INT_STATUS_SUCCESS;
1002 }
1003 
1004 
1005 INTSTATUS
1007  _In_ QWORD Gpa,
1008  _Out_ BYTE *Read,
1009  _Out_ BYTE *Write,
1010  _Out_ BYTE *Execute
1011  )
1023 {
1024  LIST_ENTRY *list;
1025  DWORD i, hid;
1026 
1027  LIST_HEAD *hooksLists[] =
1028  {
1032  };
1033 
1034  if (NULL == Read)
1035  {
1037  }
1038 
1039  if (NULL == Write)
1040  {
1042  }
1043 
1044  if (NULL == Execute)
1045  {
1047  }
1048 
1049  hid = GPA_HOOK_ID(Gpa);
1050 
1051  // Assume full rights.
1052  *Read = *Write = *Execute = 1;
1053 
1054  for (i = 0; i < ARRAYSIZE(hooksLists); i++)
1055  {
1056  LIST_HEAD *hooksList = &hooksLists[i][hid];
1057 
1058  list = hooksList->Flink;
1059 
1060  while (list != hooksList)
1061  {
1062  PHOOK_GPA p = CONTAINING_RECORD(list, HOOK_GPA, Link);
1063  list = list->Flink;
1064 
1065  // Skip/ignore removed hooks.
1066  if (0 != (p->Header.Flags & (HOOK_FLG_DISABLED | HOOK_FLG_REMOVE)))
1067  {
1068  continue;
1069  }
1070 
1071  if ((Gpa & PAGE_MASK) == p->GpaPage)
1072  {
1073  switch (i)
1074  {
1075  case 0:
1076  *Write = 0;
1077  break;
1078  case 1:
1079  *Read = 0;
1080  break;
1081  case 2:
1082  *Execute = 0;
1083  default:
1084  break;
1085  }
1086 
1087  break;
1088  }
1089  }
1090  }
1091 
1092  return INT_STATUS_SUCCESS;
1093 }
1094 
1095 
1096 INTSTATUS
1098  void
1099  )
1105 {
1106  INTSTATUS status;
1107 
1108  for (DWORD i = 0; i < GPA_HOOK_TABLE_SIZE; i++)
1109  {
1113  }
1114 
1118 
1119  for (DWORD i = 0; i < GPA_EPT_TABLE_SIZE; i++)
1120  {
1122  }
1123 
1124  // Get the untrusted EPT index.
1126  if (!INT_SUCCESS(status))
1127  {
1128 #ifdef USER_MODE
1130 #else
1132 #endif // INT_COMPILER_MSVC
1133 
1134  ERROR("[ERROR] IntGetCurrentEptIndex failed: 0x%08x. Will assume untrusted EPT index %d.\n",
1135  status, gGuest.UntrustedEptIndex);
1136  }
1137 
1138  // By default, assume the protected EPT index is an invalid one.
1140 
1142 
1143  // Check SPP support. We use the SPP feature if two conditions are met:
1144  // 1. The Get/Set SPP protection APIs are initialized inside the interface;
1145  // 2. The SPP feature is present & enabled for this guest.
1146  if (GlueIsSppApiAvailable())
1147  {
1149  }
1150 
1151  return INT_STATUS_SUCCESS;
1152 }
1153 
1154 
1155 void
1157  void
1158  )
1162 {
1163  DWORD i, j, count, count2;
1164  LIST_ENTRY *list, *table;
1165  BYTE r, w, x;
1166  const char *msg[3] = { "read", "write", "execute" };
1167 
1168  if (NULL == gHooks)
1169  {
1170  return;
1171  }
1172 
1173  for (j = 0; j < 3; j++)
1174  {
1175  NLOG("GPA %s hooks:\n", msg[j]);
1176 
1177  if (0 == j)
1178  {
1179  table = gHooks->GpaHooks.GpaHooksRead;
1180  }
1181  else if (1 == j)
1182  {
1183  table = gHooks->GpaHooks.GpaHooksWrite;
1184  }
1185  else
1186  {
1187  table = gHooks->GpaHooks.GpaHooksExecute;
1188  }
1189 
1190  count = 0;
1191 
1192  for (i = 0; i < GPA_HOOK_TABLE_SIZE; i++)
1193  {
1194  list = table[i].Flink;
1195 
1196  count2 = 0;
1197 
1198  while (list != &table[i])
1199  {
1200  PHOOK_GPA pHook = CONTAINING_RECORD(list, HOOK_GPA, Link);
1201 
1203 
1204  NLOG("%04d: %p GPA: 0x%016llx, Offset: %04x, Length: %04x, Type: %d, Flags: %08x, Parent: %p,"
1205  "Callback: %p, Context: %p, EPT: %c%c%c\n", count++,
1206  pHook, pHook->GpaPage, pHook->Offset, pHook->Length, pHook->Header.EptHookType,
1207  pHook->Header.Flags, pHook->Header.ParentHook, pHook->Callback, pHook->Header.Context,
1208  r ? 'R' : '-', w ? 'W' : '-', x ? 'X' : '-');
1209 
1210  list = list->Flink;
1211 
1212  count2++;
1213  }
1214 
1215  NLOG("===> Load of list %04d: %d\n", i, count2);
1216  }
1217  }
1218 
1219  count = 0;
1220 
1221  for (i = 0; i < 3; i++)
1222  {
1223  QUEUE_HEAD *hooksQueue;
1224  QUEUE_ENTRY *queue;
1225 
1226  if (0 == i)
1227  {
1228  hooksQueue = &gHooks->GpaHooks.RemovedHooksRead;
1229  }
1230  else if (1 == i)
1231  {
1232  hooksQueue = &gHooks->GpaHooks.RemovedHooksWrite;
1233  }
1234  else
1235  {
1236  hooksQueue = &gHooks->GpaHooks.RemovedHooksExecute;
1237  }
1238 
1239  queue = hooksQueue->Next;
1240 
1241  NLOG("Removed hooks list for '%s':\n", 0 == i ? "read" : 1 == i ? "write" : "execute");
1242 
1243  while (queue != hooksQueue)
1244  {
1245  PHOOK_GPA pHook = CONTAINING_RECORD(queue, HOOK_GPA, LinkRemoved);
1246 
1247  NLOG("%04d: %p GPA: 0x%016llx, Offset: %04x, Length: %04x, Flags: %08x, Parent: %p,"
1248  "Callback: %p, Context: %p\n", count++,
1249  pHook, pHook->GpaPage, pHook->Offset, pHook->Length, pHook->Header.Flags,
1250  pHook->Header.ParentHook, pHook->Callback, pHook->Header.Context);
1251 
1252  queue = queue->Next;
1253  }
1254  }
1255 }
1256 
1257 
1258 static INTSTATUS
1260  _In_ BOOLEAN Enable
1261  )
1274 {
1275  INTSTATUS status = INT_STATUS_SUCCESS;
1276 
1277  if (gHooks->GpaHooks.VeEnabled && Enable)
1278  {
1280  }
1281 
1282  if (!(gHooks->GpaHooks.VeEnabled || Enable))
1283  {
1285  }
1286 
1287  // Iterate all the pages and mark the PT hooks as convertible.
1288  for (DWORD i = 0; i < GPA_EPT_TABLE_SIZE; i++)
1289  {
1291  while (list != &gHooks->GpaHooks.EptEntries[i])
1292  {
1294 
1295  list = list->Flink;
1296 
1297  if (0 != p->PtCount)
1298  {
1299  BOOLEAN setc = FALSE;
1300  const QWORD gpa = p->GpaPage;
1301  TRACE("[HOOK] Marking GPA %llx as being %s (%c%c%c)\n", gpa, Enable ? "conv" : "non-conv",
1302  !p->ReadCount ? 'R' : '-', !p->WriteCount ? 'W' : '-', !p->ExecuteCount ? 'X' : '-');
1303 
1304  if (Enable)
1305  {
1306  if (MAX_HOOK_COUNT < (QWORD)p->ConvCount + (QWORD)p->PtCount)
1307  {
1308  CRITICAL("[ERROR] Convertible hook count exceeds the limit for page 0x%016llx!\n", p->GpaPage);
1310  }
1311 
1312  setc = 0 == p->ConvCount;
1313 
1314  p->ConvCount += p->PtCount;
1315  }
1316  else
1317  {
1318  BUG_ON(p->ConvCount < p->PtCount);
1319 
1320  p->ConvCount -= p->PtCount;
1321 
1322  setc = 0 == p->ConvCount;
1323  }
1324 
1325  if (setc)
1326  {
1327  status = IntSetEPTPageConvertible(gGuest.UntrustedEptIndex, gpa, Enable);
1328  if (!INT_SUCCESS(status))
1329  {
1330  ERROR("[ERROR] IntSetEPTPageConvertible failed: 0x%08x\n", status);
1331  }
1332  }
1333  }
1334  }
1335  }
1336 
1337  gHooks->GpaHooks.VeEnabled = Enable;
1338 
1339  return status;
1340 }
1341 
1342 
1343 static INTSTATUS
1345  _In_ BOOLEAN Enable
1346  )
1359 {
1360  INTSTATUS status = INT_STATUS_SUCCESS;
1361 
1362  if (gHooks->GpaHooks.PtCacheEnabled && Enable)
1363  {
1365  }
1366 
1367  if (!(gHooks->GpaHooks.PtCacheEnabled || Enable))
1368  {
1370  }
1371 
1372  // Iterate all the pages and mark the PT hooks as convertible.
1373  for (DWORD i = 0; i < GPA_EPT_TABLE_SIZE; i++)
1374  {
1376  while (list != &gHooks->GpaHooks.EptEntries[i])
1377  {
1379 
1380  list = list->Flink;
1381 
1382  if (0 != p->PtCount)
1383  {
1384  const QWORD gpa = p->GpaPage;
1385  TRACE("[HOOK] Marking GPA %llx as being %s (%c%c%c)\n", gpa, Enable ? "PT filtered" : "EPT hooked",
1386  !p->ReadCount ? 'R' : '-', Enable ? 'W' : '-', !p->ExecuteCount ? 'X' : '-');
1387 
1389  gpa, 0 == p->ReadCount, !!Enable, 0 == p->ExecuteCount);
1390  if (!INT_SUCCESS(status))
1391  {
1392  ERROR("[ERROR] IntSetEPTPageProtection failed: 0x%08x\n", status);
1393  }
1394  }
1395  }
1396  }
1397 
1398  // Safe to be here, since we don't return if IntSetEPTPageProtection returns errors.
1399  gHooks->GpaHooks.PtCacheEnabled = Enable;
1400 
1401  return status;
1402 }
1403 
1404 
1405 INTSTATUS
1407  void
1408  )
1412 {
1414 }
1415 
1416 
1417 INTSTATUS
1419  void
1420  )
1424 {
1426 }
1427 
1428 
1429 INTSTATUS
1431  void
1432  )
1436 {
1438 }
1439 
1440 
1441 INTSTATUS
1443  void
1444  )
1448 {
1450 }
1451 
1452 
1453 INTSTATUS
1455  _In_ DWORD EptIndex,
1456  _In_ QWORD Address,
1457  _Out_ BYTE *Read,
1458  _Out_ BYTE *Write,
1459  _Out_ BYTE *Execute
1460  )
1473 {
1474  const HOOK_EPT_ENTRY *pEpt;
1475 
1476  if (EptIndex != gGuest.UntrustedEptIndex)
1477  {
1478  ERROR("[ERROR] Only the Untrusted EPT is supported!\n");
1480  }
1481 
1482  pEpt = IntHookGpaGetExistingEptEntry(Address & PAGE_MASK);
1483  if (NULL != pEpt)
1484  {
1485  *Read = 0 == pEpt->ReadCount;
1486  *Write = 0 == pEpt->WriteCount;
1487  *Execute = 0 == pEpt->ExecuteCount;
1488  }
1489  else
1490  {
1491  *Read = *Write = *Execute = 1;
1492  }
1493 
1494  return INT_STATUS_SUCCESS;
1495 }
1496 
1497 
1498 INTSTATUS
1500  void
1501  )
1507 {
1508  INTSTATUS status = INT_STATUS_SUCCESS;
1509 
1510  // Iterate all the pages and mark the PT hooks as convertible.
1511  for (DWORD i = 0; i < GPA_EPT_TABLE_SIZE; i++)
1512  {
1514  while (list != &gHooks->GpaHooks.EptEntries[i])
1515  {
1516  BOOLEAN c;
1518 
1519  list = list->Flink;
1520 
1522  if (c)
1523  {
1524  LOG("!!!! Page 0x%016llx is convertible!\n", p->GpaPage);
1525  }
1526  else if (p->PtCount)
1527  {
1528  LOG("**** Page 0x%016llx is page table, but it is NOT convertible!\n", p->GpaPage);
1529  }
1530  }
1531  }
1532 
1533  return status;
1534 }
1535 #ifdef INT_COMPILER_MSVC
1536 #pragma warning(pop)
1537 #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:1418
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:788
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:738
INTSTATUS IntHookGpaEnableVe(void)
Enable VE filtering.
Definition: hook_gpa.c:1406
INTSTATUS IntHookGpaCommitHooks(void)
Commit existing modified hooks.
Definition: hook_gpa.c:876
#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:1344
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:1006
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:357
#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:951
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:675
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:1454
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:520
#define PAGE_SIZE
Definition: common.h:70
#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:161
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:119
INTSTATUS IntHookGpaDisableVe(void)
Disable VE filtering.
Definition: hook_gpa.c:1430
void IntHookGpaDump(void)
Dump the entire contents of the GPA hook system, listing each hook.
Definition: hook_gpa.c:1156
DWORD ProtectedEptIndex
The EPTP index of the trusted EPT.
Definition: guests.h:401
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:1442
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:63
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
#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:193
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:1097
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:830
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:977
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:1259
INTSTATUS IntHookGpaFindConvertible(void)
Displays all convertible pages.
Definition: hook_gpa.c:1499
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:102
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:397
#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:118
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