Bitdefender Hypervisor Memory Introspection
introcpu.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "introcpu.h"
6 #include "guests.h"
7 #include "lixprocess.h"
8 #include "winprocesshp.h"
9 
10 
13  _In_ QWORD CpuNumber,
14  _Out_ QWORD *Efer
15  )
25 {
26  INTSTATUS status;
27  IG_QUERY_MSR readMsr = {0};
28 
29  if (NULL == Efer)
30  {
32  }
33 
34  readMsr.MsrId = IG_IA32_EFER;
35 
36  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
37  if (!INT_SUCCESS(status))
38  {
39  return status;
40  }
41 
42  *Efer = readMsr.Value;
43 
44  return INT_STATUS_SUCCESS;
45 }
46 
47 
50  _In_ DWORD CpuNumber,
51  _Out_ QWORD *Rip
52  )
67 {
68  if (Rip == NULL)
69  {
71  }
72 
73  if (IG_CURRENT_VCPU == CpuNumber)
74  {
75  CpuNumber = gVcpu->Index;
76  }
77 
78  if (__likely((gVcpu->EventId == gEventId) && (gVcpu->Index == CpuNumber)))
79  {
80  *Rip = gVcpu->Regs.Rip;
81  }
82  else
83  {
84  IG_ARCH_REGS regs;
85  INTSTATUS status;
86 
87  status = IntGetGprs(CpuNumber, &regs);
88  if (!INT_SUCCESS(status))
89  {
90  ERROR("[ERROR] : IntGetGprs, status = 0x%08x\n", status);
91  return status;
92  }
93 
94  *Rip = regs.Rip;
95  }
96 
97  return INT_STATUS_SUCCESS;
98 }
99 
100 
101 INTSTATUS
103  _In_ DWORD CpuNumber,
104  _Out_ QWORD *Base,
105  _Out_opt_ WORD *Limit
106  )
117 {
118  INTSTATUS status;
119  IG_ARCH_REGS regs;
120 
121  if (Base == NULL)
122  {
124  }
125 
126  status = IntGetAllRegisters(CpuNumber, &regs);
127  if (!INT_SUCCESS(status))
128  {
129  ERROR("[ERROR] IntGetAllRegisters failed: 0x%08x\n", status);
130  return status;
131  }
132 
133  *Base = regs.IdtBase;
134 
135  if (NULL != Limit)
136  {
137  *Limit = (WORD)regs.IdtLimit;
138  }
139 
140  return INT_STATUS_SUCCESS;
141 }
142 
143 
144 INTSTATUS
146  _In_ DWORD CpuNumber,
147  _In_ DWORD Entry,
148  _Out_ QWORD *Handler
149  )
160 {
161  INTSTATUS status;
162  QWORD idtBase = 0;
163 
164  if (Handler == NULL)
165  {
167  }
168 
169  status = IntIdtFindBase(CpuNumber, &idtBase, NULL);
170  if (!INT_SUCCESS(status))
171  {
172  ERROR("[ERROR] IntIdtFindBase failed: 0x%08x\n", status);
173  return status;
174  }
175 
176  if (gGuest.Guest64)
177  {
178  INTERRUPT_GATE gate;
179 
180  status = IntKernVirtMemRead(idtBase + Entry * sizeof(gate), sizeof(gate), &gate, NULL);
181  if (!INT_SUCCESS(status))
182  {
183  return status;
184  }
185 
186  *Handler = ((QWORD) gate.Offset_63_32 << 32) | ((QWORD) gate.Offset_31_16 << 16) | ((QWORD) gate.Offset_15_0);
187  }
188  else
189  {
190  INTERRUPT_GATE32 gate;
191 
192  status = IntKernVirtMemRead(idtBase + Entry * sizeof(gate), sizeof(gate), &gate, NULL);
193  if (!INT_SUCCESS(status))
194  {
195  return status;
196  }
197 
198  *Handler = ((QWORD) gate.Offset_31_16 << 16) | ((QWORD) gate.Offset_15_0);
199  }
200 
201  return INT_STATUS_SUCCESS;
202 }
203 
204 
205 INTSTATUS
207  _In_ DWORD CpuNumber,
208  _Out_ QWORD *GdtBase,
209  _Out_opt_ WORD *GdtLimit
210  )
221 {
222  INTSTATUS status;
223  IG_ARCH_REGS regs;
224 
225  if (GdtBase == NULL)
226  {
228  }
229 
231  (void *)(size_t)CpuNumber,
232  &regs,
233  sizeof(IG_ARCH_REGS));
234  if (!INT_SUCCESS(status))
235  {
236  ERROR("[ERROR] : IntQueryGuestInfo failed for IG_QUERY_INFO_CLASS_REGISTER_STATE, status = 0x%08x\n", status);
237  return status;
238  }
239 
240  *GdtBase = regs.GdtBase;
241 
242  if (NULL != GdtLimit)
243  {
244  *GdtLimit = (WORD)regs.GdtLimit;
245  }
246 
247  return INT_STATUS_SUCCESS;
248 }
249 
250 
251 INTSTATUS
253  _In_ DWORD CpuNumber,
254  _Out_ QWORD *FsValue
255  )
265 {
266  INTSTATUS status;
267  IG_QUERY_MSR readMsr = {0};
268 
269  if (FsValue == NULL)
270  {
272  }
273 
274  readMsr.MsrId = IG_IA32_FS_BASE;
275 
276  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
277  if (!INT_SUCCESS(status))
278  {
279  return status;
280  }
281 
282  *FsValue = readMsr.Value;
283 
284  return INT_STATUS_SUCCESS;
285 }
286 
287 
288 INTSTATUS
290  _In_ DWORD CpuNumber,
291  _Out_ QWORD *GsValue
292  )
302 {
303  INTSTATUS status;
304  IG_QUERY_MSR readMsr = {0};
305 
306  if (GsValue == NULL)
307  {
309  }
310 
311  readMsr.MsrId = IG_IA32_GS_BASE;
312 
313  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
314  if (!INT_SUCCESS(status))
315  {
316  return status;
317  }
318 
319  *GsValue = readMsr.Value;
320 
321  return INT_STATUS_SUCCESS;
322 }
323 
324 
325 static INTSTATUS
327  _In_ DWORD CpuNumber,
328  _Out_ QWORD *GsValue
329  )
339 {
340  INTSTATUS status;
341  IG_QUERY_MSR readMsr = { 0 };
342 
343  if (GsValue == NULL)
344  {
346  }
347 
348  readMsr.MsrId = IG_IA32_KERNEL_GS_BASE;
349 
350  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
351  if (!INT_SUCCESS(status))
352  {
353  return status;
354  }
355 
356  *GsValue = readMsr.Value;
357 
358  return INT_STATUS_SUCCESS;
359 }
360 
361 
362 INTSTATUS
364  _In_ DWORD CpuNumber,
365  _Out_ QWORD *Cr0Value
366  )
380 {
381  if (Cr0Value == NULL)
382  {
384  }
385 
386  if (IG_CURRENT_VCPU == CpuNumber)
387  {
388  CpuNumber = gVcpu->Index;
389  }
390 
391  if ((gVcpu->EventId == gEventId) && (gVcpu->Index == CpuNumber))
392  {
393  *Cr0Value = gVcpu->Regs.Cr0;
394  }
395  else
396  {
397  IG_ARCH_REGS regs;
398  INTSTATUS status;
399 
400  status = IntGetGprs(CpuNumber, &regs);
401  if (!INT_SUCCESS(status))
402  {
403  ERROR("[ERROR] IntGetGprs failed: 0x%08x\n", status);
404  return status;
405  }
406 
407  *Cr0Value = regs.Cr0;
408  }
409 
410  return INT_STATUS_SUCCESS;
411 }
412 
413 
414 INTSTATUS
416  _In_ DWORD CpuNumber,
417  _Out_ QWORD *Cr3Value
418  )
432 {
433  if (Cr3Value == NULL)
434  {
436  }
437 
438  if (IG_CURRENT_VCPU == CpuNumber)
439  {
440  CpuNumber = gVcpu->Index;
441  }
442 
443  if (__likely((gVcpu->EventId == gEventId) && (gVcpu->Index == CpuNumber)))
444  {
445  *Cr3Value = gVcpu->Regs.Cr3;
446  }
447  else
448  {
449  IG_ARCH_REGS regs;
450  INTSTATUS status;
451 
452  status = IntGetGprs(CpuNumber, &regs);
453  if (!INT_SUCCESS(status))
454  {
455  ERROR("[ERROR] IntGetGprs failed: 0x%08x\n", status);
456  return status;
457  }
458 
459  *Cr3Value = regs.Cr3;
460  }
461 
462  return INT_STATUS_SUCCESS;
463 }
464 
465 
466 INTSTATUS
468  _In_ DWORD CpuNumber,
469  _Out_ QWORD *Cr4Value
470  )
484 {
485  if (Cr4Value == NULL)
486  {
488  }
489 
490  if (IG_CURRENT_VCPU == CpuNumber)
491  {
492  CpuNumber = gVcpu->Index;
493  }
494 
495  if (__likely((gVcpu->EventId == gEventId) && (gVcpu->Index == CpuNumber)))
496  {
497  *Cr4Value = gVcpu->Regs.Cr4;
498  }
499  else
500  {
501  IG_ARCH_REGS regs;
502  INTSTATUS status;
503 
504  status = IntGetGprs(CpuNumber, &regs);
505  if (!INT_SUCCESS(status))
506  {
507  ERROR("[ERROR] IntGetGprs failed: 0x%08x\n", status);
508  return status;
509  }
510 
511  *Cr4Value = regs.Cr4;
512  }
513 
514  return INT_STATUS_SUCCESS;
515 }
516 
517 
518 INTSTATUS
520  _In_ DWORD CpuNumber,
521  _Out_ QWORD *Cr8Value
522  )
536 {
537  if (Cr8Value == NULL)
538  {
540  }
541 
542  if (IG_CURRENT_VCPU == CpuNumber)
543  {
544  CpuNumber = gVcpu->Index;
545  }
546 
547  if ((gVcpu->EventId == gEventId) && (gVcpu->Index == CpuNumber))
548  {
549  *Cr8Value = gVcpu->Regs.Cr8;
550  }
551  else
552  {
553  IG_ARCH_REGS regs;
554  INTSTATUS status;
555 
556  status = IntGetGprs(CpuNumber, &regs);
557  if (!INT_SUCCESS(status))
558  {
559  ERROR("[ERROR] IntGetGprs failed: 0x%08x\n", status);
560  return status;
561  }
562 
563  *Cr8Value = regs.Cr8;
564  }
565 
566  return INT_STATUS_SUCCESS;
567 }
568 
569 
570 INTSTATUS
572  _In_ DWORD CpuNumber,
573  _Out_opt_ QWORD *SysCs,
574  _Out_opt_ QWORD *SysEip,
575  _Out_opt_ QWORD *SysEsp
576  )
587 {
588  INTSTATUS status;
589  IG_QUERY_MSR readMsr = {0};
590 
591  if (SysCs != NULL)
592  {
593  readMsr.MsrId = IG_IA32_SYSENTER_CS;
594 
595  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
596  if (!INT_SUCCESS(status))
597  {
598  return status;
599  }
600 
601  *SysCs = readMsr.Value;
602  }
603 
604  if (SysEip != NULL)
605  {
606  readMsr.MsrId = IG_IA32_SYSENTER_EIP;
607 
608  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
609  if (!INT_SUCCESS(status))
610  {
611  return status;
612  }
613 
614  *SysEip = readMsr.Value;
615  }
616 
617  if (SysEsp != NULL)
618  {
619  readMsr.MsrId = IG_IA32_SYSENTER_ESP;
620 
621  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
622  if (!INT_SUCCESS(status))
623  {
624  return status;
625  }
626 
627  *SysEsp = readMsr.Value;
628  }
629 
630  return INT_STATUS_SUCCESS;
631 }
632 
633 
634 INTSTATUS
636  _In_ DWORD CpuNumber,
637  _Out_opt_ QWORD *SysStar,
638  _Out_opt_ QWORD *SysLstar
639  )
649 {
650  INTSTATUS status;
651  IG_QUERY_MSR readMsr = {0};
652 
653  if (SysStar != NULL)
654  {
655  readMsr.MsrId = IG_IA32_STAR;
656 
657  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
658  if (!INT_SUCCESS(status))
659  {
660  return status;
661  }
662 
663  *SysStar = readMsr.Value;
664  }
665 
666  if (SysLstar != NULL)
667  {
668  readMsr.MsrId = IG_IA32_LSTAR;
669 
670  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
671  if (!INT_SUCCESS(status))
672  {
673  return status;
674  }
675 
676  *SysLstar = readMsr.Value;
677  }
678 
679  return INT_STATUS_SUCCESS;
680 }
681 
682 
683 INTSTATUS
685  _In_ DWORD CpuNumber,
686  _Out_ QWORD *DebugCtl
687  )
696 {
697  INTSTATUS status;
698  IG_QUERY_MSR readMsr = {0};
699 
700  if (DebugCtl == NULL)
701  {
703  }
704 
705  readMsr.MsrId = IG_IA32_DEBUGCTL;
706 
707  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_READ_MSR, (void *)(size_t)CpuNumber, &readMsr, sizeof(readMsr));
708  if (!INT_SUCCESS(status))
709  {
710  return status;
711  }
712 
713  *DebugCtl = readMsr.Value;
714 
715  return INT_STATUS_SUCCESS;
716 }
717 
718 
719 INTSTATUS
721  _In_ DWORD BuffersSize,
722  _Out_writes_(BuffersSize) QWORD *LbrFrom,
723  _Out_writes_(BuffersSize) QWORD *LbrTo
724  )
728 {
729  QWORD msrLbrTos, i;
730 
731  const DWORD cFrom[LBR_STACK_SIZE] =
732  {
737  };
738 
739  const DWORD cTo[LBR_STACK_SIZE] =
740  {
745  };
746 
747  if (BuffersSize == 0)
748  {
750  }
751 
752  if (LbrFrom == NULL)
753  {
755  }
756 
757  if (LbrTo == NULL)
758  {
760  }
761 
762  msrLbrTos = __readmsr(IG_IA32_LBR_TOS);
763 
764  for (i = 0; i < LBR_STACK_SIZE && i < BuffersSize; i++)
765  {
766  LbrFrom[i] = __readmsr(cFrom[msrLbrTos]);
767  LbrTo[i] = __readmsr(cTo[msrLbrTos]);
768  msrLbrTos = (msrLbrTos + 1) % LBR_STACK_SIZE;
769  }
770 
771  return INT_STATUS_SUCCESS;
772 }
773 
774 
775 INTSTATUS
777  _Out_ QWORD *LerFrom,
778  _Out_ QWORD *LerTo
779  )
783 {
784  if (LerFrom == NULL)
785  {
787  }
788 
789  if (LerTo == NULL)
790  {
792  }
793 
794  *LerFrom = __readmsr(MSR_LER_FROM_IP);
795  *LerTo = __readmsr(MSR_LER_TO_IP);
796 
797  return INT_STATUS_SUCCESS;
798 }
799 
800 
801 DWORD
803  void
804  )
812 {
813  INTSTATUS status;
814  DWORD cpuNumber = 0;
815 
816  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_CURRENT_TID, NULL, &cpuNumber, sizeof(DWORD));
817  if (!INT_SUCCESS(status))
818  {
819  IntBugCheck();
820  }
821 
822  return cpuNumber;
823 }
824 
825 
826 INTSTATUS
828  _In_ DWORD CpuNumber,
829  _Out_ PIG_ARCH_REGS Regs
830  )
845 {
846  INTSTATUS status = INT_STATUS_SUCCESS;
847  PIG_ARCH_REGS pRegs = Regs;
848 
849  if (IG_CURRENT_VCPU == CpuNumber)
850  {
851  CpuNumber = gVcpu->Index;
852  }
853 
854  if (__likely(CpuNumber == gVcpu->Index))
855  {
856  pRegs = &gVcpu->Regs;
857  }
858 
859  if (__likely((CpuNumber != gVcpu->Index) || (gVcpu->EventId != gEventId)))
860  {
862  (void *)(size_t)CpuNumber,
863  (PBYTE)pRegs,
864  sizeof(*pRegs));
865  if (!INT_SUCCESS(status))
866  {
867  CRITICAL("[ERROR] IntQueryGuestInfo failed: 0x%08x\n", status);
868  IntBugCheck();
869  }
870 
871  if (CpuNumber == gVcpu->Index)
872  {
874  }
875 
876  }
877 
878  // If this is probably a user CR3, load the kernel CR3 in our cache.
880  {
882  {
884  if (NULL != pProc)
885  {
886  pRegs->Cr3 = pProc->Cr3;
887  }
888  }
889  else if (__likely(introGuestLinux == gGuest.OSType))
890  {
891  pRegs->Cr3 = IntLixGetKernelCr3(pRegs->Cr3);
892  }
893  }
894 
895  if (__unlikely(Regs != pRegs))
896  {
897  memcpy(Regs, pRegs, sizeof(*Regs));
898  }
899 
900  return status;
901 }
902 
903 
904 INTSTATUS
906  _In_ DWORD CpuNumber,
907  _In_ PIG_ARCH_REGS Regs
908  )
924 {
925  if (IG_CURRENT_VCPU == CpuNumber)
926  {
927  CpuNumber = gVcpu->Index;
928  }
929 
930  if (__unlikely(Regs != &gVcpu->Regs))
931  {
932  if (__likely((gVcpu->EventId == gEventId) && (gVcpu->Index == CpuNumber)))
933  {
934  memcpy(&gVcpu->Regs, Regs, sizeof(*Regs));
935  }
936  else if (__unlikely(gVcpu->VeContext))
937  {
938  ERROR("[ERROR] Modifying the GPRs from #VE context, but the registers are not cached!\n");
940  }
941  }
942 
943  // DO NOT modify the registers if we're in #VE context. They will be propagated back inside the #VE info page
944  // without the need of a costly hypercall. If the registers cache is not set for the current VCPU (see the above
945  // else branch), we will cause a bug-check, as that is not normal.
946  if (gVcpu->VeContext)
947  {
948  return INT_STATUS_SUCCESS;
949  }
950 
952  (void *)(size_t)CpuNumber,
953  (PBYTE)Regs,
954  sizeof(IG_ARCH_REGS));
955 }
956 
957 
958 INTSTATUS
960  _In_ DWORD CpuNumber,
961  _Out_ DWORD *Ring
962  )
971 {
972  return IntQueryGuestInfo(IG_QUERY_INFO_CLASS_CS_RING, (void *)(size_t)CpuNumber, (PBYTE)Ring, sizeof(DWORD));
973 }
974 
975 
976 INTSTATUS
978  _In_ DWORD CpuNumber,
979  _Out_ DWORD *Mode
980  )
989 {
990  return IntQueryGuestInfo(IG_QUERY_INFO_CLASS_CS_TYPE, (void *)(size_t)CpuNumber, (PBYTE)Mode, sizeof(DWORD));
991 }
992 
993 
994 INTSTATUS
996  _In_ DWORD CpuNumber,
997  _Out_ PIG_SEG_REGS Regs
998  )
1007 {
1008  return IntQueryGuestInfo(IG_QUERY_INFO_CLASS_SEG_REGISTERS, (void *)(size_t)CpuNumber, (PBYTE)Regs,
1009  sizeof(IG_SEG_REGS));
1010 }
1011 
1012 
1013 INTSTATUS
1015  _Out_ DWORD *Size
1016  )
1024 {
1025  return IntQueryGuestInfo(IG_QUERY_INFO_CLASS_XSAVE_SIZE, (void *)(SIZE_T)IG_CURRENT_VCPU, Size, sizeof(*Size));
1026 }
1027 
1028 
1029 INTSTATUS
1031  _In_ DWORD CpuNumber,
1032  _Out_ QWORD *Xcr0Value
1033  )
1042 {
1043  return IntQueryGuestInfo(IG_QUERY_INFO_CLASS_GET_XCR0, (void *)(SIZE_T)CpuNumber, (PBYTE)Xcr0Value, sizeof(QWORD));
1044 }
1045 
1046 
1047 INTSTATUS
1049  _In_ DWORD CpuNumber,
1050  _Out_ XSAVE_AREA *XsaveArea
1051  )
1064 {
1065  DWORD size = 0;
1066  INTSTATUS status;
1067  IG_XSAVE_AREA *xsave;
1068 
1069  status = IntGetXsaveAreaSize(&size);
1070  if (!INT_SUCCESS(status))
1071  {
1072  ERROR("[ERROR] IntGetXsaveAreaSize failed: 0x%08x\n", status);
1073  return status;
1074  }
1075 
1076  // Right here, we can trust the size value returned by the HV.
1077  xsave = HpAllocWithTag(size, IC_TAG_XSAVE);
1078  if (NULL == xsave)
1079  {
1081  }
1082 
1083  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_XSAVE_AREA, (void *)(SIZE_T)CpuNumber, (BYTE *)xsave, size);
1084  if (!INT_SUCCESS(status))
1085  {
1087  return status;
1088  }
1089 
1090  XsaveArea->Size = size;
1091  XsaveArea->XsaveArea = xsave;
1092  return INT_STATUS_SUCCESS;
1093 }
1094 
1095 
1096 INTSTATUS
1098  _In_ DWORD CpuNumber,
1099  _In_ XSAVE_AREA *XsaveArea
1100  )
1109 {
1110  return IntQueryGuestInfo(IG_QUERY_INFO_CLASS_SET_XSAVE_AREA, (void *)(SIZE_T)CpuNumber,
1111  (PBYTE)XsaveArea->XsaveArea, XsaveArea->Size);
1112 }
1113 
1114 
1115 INTSTATUS
1117  _In_ DWORD CpuNumber,
1118  _Out_ QWORD *Pcr
1119  )
1132 {
1133  INTSTATUS status;
1134  QWORD efer;
1135 
1136  // Read the EFER.
1137  status = IntEferRead(CpuNumber, &efer);
1138  if (!INT_SUCCESS(status))
1139  {
1140  ERROR("[ERROR] IntEferRead failed: 0x%08x\n", status);
1141  return status;
1142  }
1143 
1144  // Get the kernel KPCR.
1145  if (efer & EFER_LMA)
1146  {
1147  QWORD gsbase;
1148 
1149  // 64 bit-mode, KPCR is in IA32_GS_BASE or IA32_KERNEL_GS_BASE.
1150  status = IntGsRead(CpuNumber, &gsbase);
1151  if (!INT_SUCCESS(status))
1152  {
1153  ERROR("[ERROR] IntGsRead failed: 0x%08x\n", status);
1154  return status;
1155  }
1156 
1157  // If the current IA32_GS_BASE doesn't point inside the kernel, read IA32_KERNEL_GS_BASE.
1158  if (0 == (gsbase & 0x8000000000000000))
1159  {
1160  WARNING("[WARNING][CPU %d] IA32_GS_BASE MSR does not point inside kernel (%llx)\n",
1161  gVcpu->Index, gsbase);
1162 
1163  status = IntKernelGsRead(CpuNumber, &gsbase);
1164  if (!INT_SUCCESS(status))
1165  {
1166  ERROR("[ERROR] IntKernelGsRead failed: 0x%08x\n", status);
1167  return status;
1168  }
1169 
1170  // If we still don't have the kernel GS, bail out.
1171  if (0 == (gsbase & 0x8000000000000000))
1172  {
1173  ERROR("[ERROR][CPU %d] IA32_KERNEL_GS_BASE MSR does not point inside kernel (%llx)\n",
1174  gVcpu->Index, gsbase);
1175  return INT_STATUS_NOT_FOUND;
1176  }
1177  }
1178 
1179  *Pcr = gsbase;
1180  }
1181  else
1182  {
1183  QWORD gdtbase;
1184  WORD gdtlimit;
1185  SEGMENT_DESCRIPTOR32 fsdesc;
1186 
1187  // Get the GDT base.
1188  status = IntGdtFindBase(CpuNumber, &gdtbase, &gdtlimit);
1189  if (!INT_SUCCESS(status))
1190  {
1191  ERROR("[ERROR] IntGdtFindBase failed: 0x%08x\n", status);
1192  return status;
1193  }
1194 
1195  // Make sure descriptor 0x30 is alright.
1196  if (0x30 + 8 > gdtlimit)
1197  {
1198  ERROR("[ERROR] Kernel FS points outside the GDT 0x%016llx:%x\n", gdtbase, gdtlimit);
1200  }
1201 
1202  // Read the descriptor.
1203  status = IntKernVirtMemRead(gdtbase + 0x30, sizeof(fsdesc), &fsdesc, NULL);
1204  if (!INT_SUCCESS(status))
1205  {
1206  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
1207  return status;
1208  }
1209 
1210  *Pcr = fsdesc.Base1 | (fsdesc.Base << 24);
1211  }
1212 
1213  return INT_STATUS_SUCCESS;
1214 }
1215 
1216 
1217 INTSTATUS
1219  _In_ DWORD CpuNumber,
1220  _Out_ PIG_ARCH_REGS Regs
1221  )
1231 {
1232  return IntQueryGuestInfo(IG_QUERY_INFO_CLASS_REGISTER_STATE, (void *)(size_t)CpuNumber, (PBYTE)Regs,
1233  sizeof(IG_ARCH_REGS));
1234 }
1235 
1236 
1237 INTSTATUS
1239  _In_ DWORD CpuNumber,
1240  _Out_ DWORD *EptpIndex
1241  )
1250 {
1251  INTSTATUS status;
1252 
1253  if (NULL == EptpIndex)
1254  {
1256  }
1257 
1258  status = IntQueryGuestInfo(IG_QUERY_INFO_CLASS_EPTP_INDEX, (void *)(size_t)CpuNumber,
1259  (void *)EptpIndex, sizeof(DWORD));
1260 
1261  // In case the IG_QUERY_INFO_CLASS_EPTP_INDEX is not supported, we will assume the current EPT is always 0.
1262  if (INT_STATUS_OPERATION_NOT_SUPPORTED == status)
1263  {
1264  *EptpIndex = 0;
1265  status = INT_STATUS_SUCCESS;
1266  }
1267 
1268  return status;
1269 }
1270 
1271 
1272 INTSTATUS
1274  _Out_ QWORD *MaxGpfn
1275  )
1285 {
1286  return IntQueryGuestInfo(IG_QUERY_INFO_CLASS_MAX_GPFN, NULL, (void *)MaxGpfn, sizeof(*MaxGpfn));
1287 }
INTSTATUS IntGetXcr0(DWORD CpuNumber, QWORD *Xcr0Value)
Get the value of the guest XCR0 register.
Definition: introcpu.c:1030
#define __unlikely(x)
Definition: common.h:64
Get the guest XCR0 value for a VCPU.
Definition: glueiface.h:276
WORD Offset_15_0
Definition: introcpu.h:19
#define _Out_
Definition: intro_sal.h:22
#define MSR_LBR_6_TO_IP
Definition: introcpu.h:106
#define IG_IA32_SYSENTER_ESP
Definition: glueiface.h:139
INTSTATUS IntGetMaxGpfn(QWORD *MaxGpfn)
Get the last physical page frame number accessible by the guest.
Definition: introcpu.c:1273
QWORD Value
The value of the MSR.
Definition: glueiface.h:213
static INTSTATUS IntKernelGsRead(DWORD CpuNumber, QWORD *GsValue)
Reads the IA32_KERNEL_GS_BASE guest MSR.
Definition: introcpu.c:326
Describes an XSAVE area format.
Definition: glueiface.h:93
INTSTATUS IntSetXsaveArea(DWORD CpuNumber, XSAVE_AREA *XsaveArea)
Sets the contents of the guest XSAVE area.
Definition: introcpu.c:1097
#define MSR_LBR_3_TO_IP
Definition: introcpu.h:103
#define MSR_LBR_6_FROM_IP
Definition: introcpu.h:89
#define MSR_LBR_C_FROM_IP
Definition: introcpu.h:95
uint8_t BYTE
Definition: intro_types.h:47
Segment descriptor for 32-bit systems.
Definition: introcpu.h:46
INTSTATUS IntGetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Get the current guest GPR state.
Definition: introcpu.c:827
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
DWORD Index
The VCPU number.
Definition: guests.h:172
#define _In_
Definition: intro_sal.h:21
#define IG_IA32_FS_BASE
Definition: glueiface.h:147
INTSTATUS IntCr8Read(DWORD CpuNumber, QWORD *Cr8Value)
Reads the value of the guest CR8.
Definition: introcpu.c:519
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
uint16_t WORD
Definition: intro_types.h:48
DWORD IntGetCurrentCpu(void)
Returns the current CPU number.
Definition: introcpu.c:802
INTSTATUS IntGetXsaveArea(DWORD CpuNumber, XSAVE_AREA *XsaveArea)
Get the contents of the guest XSAVE area.
Definition: introcpu.c:1048
#define IntEnterDebugger()
Definition: introcore.h:373
#define MSR_LER_TO_IP
Definition: introcpu.h:118
#define MSR_LBR_8_TO_IP
Definition: introcpu.h:108
#define MSR_LBR_C_TO_IP
Definition: introcpu.h:112
#define MSR_LBR_2_TO_IP
Definition: introcpu.h:102
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
Holds segment register state.
Definition: glueiface.h:64
#define IG_IA32_SYSENTER_EIP
Definition: glueiface.h:140
#define ERROR(fmt,...)
Definition: glue.h:62
Get the current privilege level for a VCPU. Buffer points to a IG_CS_RING enum.
Definition: glueiface.h:254
#define MSR_LBR_0_TO_IP
Definition: introcpu.h:100
#define MSR_LBR_4_TO_IP
Definition: introcpu.h:104
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD gEventId
The ID of the current event.
Definition: glue.c:55
INTSTATUS IntCr0Read(DWORD CpuNumber, QWORD *Cr0Value)
Reads the value of the guest CR0.
Definition: introcpu.c:363
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
INTSTATUS IntQueryGuestInfo(DWORD InfoClass, void *InfoParam, void *Buffer, DWORD BufferLength)
Definition: glue.c:226
#define MSR_LBR_A_TO_IP
Definition: introcpu.h:110
#define LBR_STACK_SIZE
Definition: introcpu.h:120
INTSTATUS IntIdtGetEntry(DWORD CpuNumber, DWORD Entry, QWORD *Handler)
Get the handler of an interrupt from the IDT.
Definition: introcpu.c:145
#define MSR_LBR_3_FROM_IP
Definition: introcpu.h:86
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
INTSTATUS IntSysenterRead(DWORD CpuNumber, QWORD *SysCs, QWORD *SysEip, QWORD *SysEsp)
Queries the IA32_SYSENTER_CS, IA32_SYSENTER_EIP, and IA32_SYSENTER_ESP guest MSRs.
Definition: introcpu.c:571
#define INT_STATUS_BUFFER_OVERFLOW
Definition: introstatus.h:200
#define _Out_writes_(expr)
Definition: intro_sal.h:28
INTSTATUS IntGsRead(DWORD CpuNumber, QWORD *GsValue)
Reads the IA32_GS_BASE guest MSR.
Definition: introcpu.c:289
#define MSR_LBR_4_FROM_IP
Definition: introcpu.h:87
DWORD Offset_63_32
Definition: introcpu.h:23
INTSTATUS IntLerRead(QWORD *LerFrom, QWORD *LerTo)
Definition: introcpu.c:776
static uint64_t __readmsr(uint32_t reg)
Definition: intrinsics.h:318
#define MSR_LBR_5_FROM_IP
Definition: introcpu.h:88
#define MSR_LER_FROM_IP
Definition: introcpu.h:117
BOOLEAN KptiActive
True if KPTI is enabled on this guest, False if it is not.
Definition: guests.h:291
The MSR query structure.
Definition: glueiface.h:210
QWORD Cr3
Process PDBR. Includes PCID.
Definition: winprocess.h:98
#define MSR_LBR_1_FROM_IP
Definition: introcpu.h:84
INTSTATUS IntLbrRead(DWORD BuffersSize, QWORD *LbrFrom, QWORD *LbrTo)
Definition: introcpu.c:720
INTSTATUS IntCr3Read(DWORD CpuNumber, QWORD *Cr3Value)
Reads the value of the guest CR3.
Definition: introcpu.c:415
#define MSR_LBR_9_TO_IP
Definition: introcpu.h:109
#define MSR_LBR_8_FROM_IP
Definition: introcpu.h:91
#define IG_IA32_KERNEL_GS_BASE
Definition: glueiface.h:149
#define _Out_opt_
Definition: intro_sal.h:30
Get the guest XSAVE area for a VCPU.
Definition: glueiface.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
uint8_t * PBYTE
Definition: intro_types.h:47
__noreturn void IntBugCheck(void)
Definition: glue.c:917
#define MSR_LBR_7_FROM_IP
Definition: introcpu.h:90
#define MSR_LBR_F_FROM_IP
Definition: introcpu.h:98
XSAVE area container.
Definition: introcpu.h:59
An 32-bit interrupt gate as defined by the Intel docs.
Definition: introcpu.h:31
INTSTATUS IntSetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Sets the values of the guest GPRs.
Definition: introcpu.c:905
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
Definition: guests.h:290
unsigned long long QWORD
Definition: intro_types.h:53
#define MSR_LBR_7_TO_IP
Definition: introcpu.h:107
#define MSR_LBR_B_FROM_IP
Definition: introcpu.h:94
#define MSR_LBR_A_FROM_IP
Definition: introcpu.h:93
QWORD IntLixGetKernelCr3(QWORD Cr3)
Transforms an user CR3 into a kernel CR3 on systems with KPTI enabled and active. ...
Definition: lixprocess.c:919
INTSTATUS IntFsRead(DWORD CpuNumber, QWORD *FsValue)
Reads the IA32_FS_BASE guest MSR.
Definition: introcpu.c:252
#define IG_IA32_STAR
Definition: glueiface.h:145
QWORD GdtBase
Definition: glueiface.h:58
#define IC_TAG_XSAVE
XSAVE area.
Definition: memtags.h:115
DWORD MsrId
The ID of the MSR, as defined by Intel.
Definition: glueiface.h:212
INTSTATUS IntSyscallRead(DWORD CpuNumber, QWORD *SysStar, QWORD *SysLstar)
Queries the IA32_STAR, and IA32_LSTAR guest MSRs.
Definition: introcpu.c:635
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
Get the current VCPU number.
Definition: glueiface.h:245
#define MSR_LBR_B_TO_IP
Definition: introcpu.h:111
QWORD IdtLimit
Definition: glueiface.h:57
#define IG_IA32_LSTAR
Definition: glueiface.h:146
An 64-bit interrupt gate as defined by the Intel docs.
Definition: introcpu.h:14
QWORD GdtLimit
Definition: glueiface.h:59
#define WARNING(fmt,...)
Definition: glue.h:60
#define MSR_LBR_5_TO_IP
Definition: introcpu.h:105
INTSTATUS IntGetXsaveAreaSize(DWORD *Size)
Get the size of the guest XSAVE area on the current CPU.
Definition: introcpu.c:1014
#define INT_STATUS_DATA_BUFFER_TOO_SMALL
Definition: introstatus.h:194
uint32_t DWORD
Definition: intro_types.h:49
INTSTATUS IntDebugCtlRead(DWORD CpuNumber, QWORD *DebugCtl)
Queries the IA32_DEBUGCTL guest MSR.
Definition: introcpu.c:684
Get the segment registers for the current VCPU. Buffer points to a IG_SEG_REGS structure.
Definition: glueiface.h:257
INTSTATUS IntCr4Read(DWORD CpuNumber, QWORD *Cr4Value)
Reads the value of the guest CR4.
Definition: introcpu.c:467
WORD Offset_31_16
Definition: introcpu.h:22
INTSTATUS IntRipRead(DWORD CpuNumber, QWORD *Rip)
Reads the value of the guest RIP.
Definition: introcpu.c:49
INTSTATUS IntGetAllRegisters(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Returns the entire guest register state. This will return the GPRs, control registers, and IDT and GDT base and limit. This also bypasses the cache used by IntGetGprs.
Definition: introcpu.c:1218
#define IG_IA32_GS_BASE
Definition: glueiface.h:148
#define MSR_LBR_E_FROM_IP
Definition: introcpu.h:97
#define IG_IA32_LBR_TOS
Definition: glueiface.h:150
INTSTATUS IntEferRead(QWORD CpuNumber, QWORD *Efer)
Reads the value of the guest IA32 EFER MSR.
Definition: introcpu.c:12
PWIN_PROCESS_OBJECT IntWinProcFindObjectByUserCr3(QWORD Cr3)
Finds a process by its user CR3.
Definition: winprocesshp.c:225
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
BOOLEAN VeContext
Set to True if we are in the context of the #VE agent.
Definition: guests.h:184
INTSTATUS IntGetCurrentRing(DWORD CpuNumber, DWORD *Ring)
Read the current protection level.
Definition: introcpu.c:959
Set the guest XSAVE area for a VCPU. This query is optional.
Definition: glueiface.h:273
Similar to IG_QUERY_INFO_CLASS_REGISTER_STATE, but will get only the general purpose registers...
Definition: glueiface.h:248
#define EFER_LMA
Definition: processor.h:94
#define MSR_LBR_9_FROM_IP
Definition: introcpu.h:92
Get the size of the guest XSAVE area for a VCPU.
Definition: glueiface.h:260
INTSTATUS IntIdtFindBase(DWORD CpuNumber, QWORD *Base, WORD *Limit)
Returns the IDT base and limit for a guest CPU.
Definition: introcpu.c:102
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
#define INT_STATUS_OPERATION_NOT_SUPPORTED
Definition: introstatus.h:122
#define MSR_LBR_D_FROM_IP
Definition: introcpu.h:96
Get the guest register state for a VCPU. Buffer points to a IG_ARCH_REGS structure.
Definition: glueiface.h:223
#define MSR_LBR_0_FROM_IP
Definition: introcpu.h:83
#define MSR_LBR_E_TO_IP
Definition: introcpu.h:114
#define MSR_LBR_1_TO_IP
Definition: introcpu.h:101
INTSTATUS IntGetCurrentEptIndex(DWORD CpuNumber, DWORD *EptpIndex)
Get the EPTP index of the currently loaded EPT.
Definition: introcpu.c:1238
#define __likely(x)
Definition: common.h:63
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define IG_IA32_DEBUGCTL
Definition: glueiface.h:151
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
INTSTATUS IntFindKernelPcr(DWORD CpuNumber, QWORD *Pcr)
Finds the address of the Windows kernel _KPCR.
Definition: introcpu.c:1116
#define CRITICAL(fmt,...)
Definition: glue.h:63
Holds register state.
Definition: glueiface.h:30
Get the value of a MSR for a VCPU. Buffer points to a IG_QUERY_MSR structure.
Definition: glueiface.h:226
INTSTATUS IntGdtFindBase(DWORD CpuNumber, QWORD *GdtBase, WORD *GdtLimit)
Returns the GDT base and limit for a guest CPU.
Definition: introcpu.c:206
INTSTATUS IntGetSegs(DWORD CpuNumber, PIG_SEG_REGS Regs)
Read the guest segment registers.
Definition: introcpu.c:995
Get the current EPTP index for the current VCPU.
Definition: glueiface.h:266
QWORD IdtBase
Definition: glueiface.h:56
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
#define MSR_LBR_D_TO_IP
Definition: introcpu.h:113
#define IG_IA32_SYSENTER_CS
Definition: glueiface.h:138
#define IG_IA32_EFER
Definition: glueiface.h:144
QWORD EventId
EventId for which VCPU_STATE.Regs is valid.
Definition: guests.h:97
Get the code segment type for a VCPU. Buffer points to a IG_CS_TYPE enum.
Definition: glueiface.h:251
#define MSR_LBR_2_FROM_IP
Definition: introcpu.h:85
size_t SIZE_T
Definition: intro_types.h:60
#define MSR_LBR_F_TO_IP
Definition: introcpu.h:115
This structure describes a running process inside the guest.
Definition: winprocess.h:83
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
INTSTATUS IntGetCurrentMode(DWORD CpuNumber, DWORD *Mode)
Read the current CS type.
Definition: introcpu.c:977
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68