Bitdefender Hypervisor Memory Introspection
introcore.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "introcore.h"
6 #include "debugger.h"
7 #include "guests.h"
8 #include "introapi.h"
9 #include "introcpu.h"
10 #include "gpacache.h"
11 #include "winprocess.h"
12 #include "lixprocess.h"
13 
14 #ifdef INT_COMPILER_MSVC
15 # include "../../autogen/ver.h"
16 #endif // INT_COMPILER_MSVC
17 
24 void *gLock = NULL;
25 
28 {
29  .VersionInfo =
30  {
31  .Build = INTRO_VERSION_BUILDNUMBER & 0xFFFF,
32  .Revision = INTRO_VERSION_REVISION,
33  .Minor = INTRO_VERSION_MINOR,
34  .Major = INTRO_VERSION_MAJOR
35  }
36 };
37 
44 
46 typedef struct _MULTI_PAGE_MAP
47 {
49  void *HostPtr;
50  void *OrigAlloc;
54 
57 
60 
63 
69 
74 {
75  0x0000000000000000, 0x00000000000000ff, 0x000000000000ff00, 0x000000000000ffff,
76  0x0000000000ff0000, 0x0000000000ff00ff, 0x0000000000ffff00, 0x0000000000ffffff,
77  0x00000000ff000000, 0x00000000ff0000ff, 0x00000000ff00ff00, 0x00000000ff00ffff,
78  0x00000000ffff0000, 0x00000000ffff00ff, 0x00000000ffffff00, 0x00000000ffffffff,
79  0x000000ff00000000, 0x000000ff000000ff, 0x000000ff0000ff00, 0x000000ff0000ffff,
80  0x000000ff00ff0000, 0x000000ff00ff00ff, 0x000000ff00ffff00, 0x000000ff00ffffff,
81  0x000000ffff000000, 0x000000ffff0000ff, 0x000000ffff00ff00, 0x000000ffff00ffff,
82  0x000000ffffff0000, 0x000000ffffff00ff, 0x000000ffffffff00, 0x000000ffffffffff,
83  0x0000ff0000000000, 0x0000ff00000000ff, 0x0000ff000000ff00, 0x0000ff000000ffff,
84  0x0000ff0000ff0000, 0x0000ff0000ff00ff, 0x0000ff0000ffff00, 0x0000ff0000ffffff,
85  0x0000ff00ff000000, 0x0000ff00ff0000ff, 0x0000ff00ff00ff00, 0x0000ff00ff00ffff,
86  0x0000ff00ffff0000, 0x0000ff00ffff00ff, 0x0000ff00ffffff00, 0x0000ff00ffffffff,
87  0x0000ffff00000000, 0x0000ffff000000ff, 0x0000ffff0000ff00, 0x0000ffff0000ffff,
88  0x0000ffff00ff0000, 0x0000ffff00ff00ff, 0x0000ffff00ffff00, 0x0000ffff00ffffff,
89  0x0000ffffff000000, 0x0000ffffff0000ff, 0x0000ffffff00ff00, 0x0000ffffff00ffff,
90  0x0000ffffffff0000, 0x0000ffffffff00ff, 0x0000ffffffffff00, 0x0000ffffffffffff,
91  0x00ff000000000000, 0x00ff0000000000ff, 0x00ff00000000ff00, 0x00ff00000000ffff,
92  0x00ff000000ff0000, 0x00ff000000ff00ff, 0x00ff000000ffff00, 0x00ff000000ffffff,
93  0x00ff0000ff000000, 0x00ff0000ff0000ff, 0x00ff0000ff00ff00, 0x00ff0000ff00ffff,
94  0x00ff0000ffff0000, 0x00ff0000ffff00ff, 0x00ff0000ffffff00, 0x00ff0000ffffffff,
95  0x00ff00ff00000000, 0x00ff00ff000000ff, 0x00ff00ff0000ff00, 0x00ff00ff0000ffff,
96  0x00ff00ff00ff0000, 0x00ff00ff00ff00ff, 0x00ff00ff00ffff00, 0x00ff00ff00ffffff,
97  0x00ff00ffff000000, 0x00ff00ffff0000ff, 0x00ff00ffff00ff00, 0x00ff00ffff00ffff,
98  0x00ff00ffffff0000, 0x00ff00ffffff00ff, 0x00ff00ffffffff00, 0x00ff00ffffffffff,
99  0x00ffff0000000000, 0x00ffff00000000ff, 0x00ffff000000ff00, 0x00ffff000000ffff,
100  0x00ffff0000ff0000, 0x00ffff0000ff00ff, 0x00ffff0000ffff00, 0x00ffff0000ffffff,
101  0x00ffff00ff000000, 0x00ffff00ff0000ff, 0x00ffff00ff00ff00, 0x00ffff00ff00ffff,
102  0x00ffff00ffff0000, 0x00ffff00ffff00ff, 0x00ffff00ffffff00, 0x00ffff00ffffffff,
103  0x00ffffff00000000, 0x00ffffff000000ff, 0x00ffffff0000ff00, 0x00ffffff0000ffff,
104  0x00ffffff00ff0000, 0x00ffffff00ff00ff, 0x00ffffff00ffff00, 0x00ffffff00ffffff,
105  0x00ffffffff000000, 0x00ffffffff0000ff, 0x00ffffffff00ff00, 0x00ffffffff00ffff,
106  0x00ffffffffff0000, 0x00ffffffffff00ff, 0x00ffffffffffff00, 0x00ffffffffffffff,
107  0xff00000000000000, 0xff000000000000ff, 0xff0000000000ff00, 0xff0000000000ffff,
108  0xff00000000ff0000, 0xff00000000ff00ff, 0xff00000000ffff00, 0xff00000000ffffff,
109  0xff000000ff000000, 0xff000000ff0000ff, 0xff000000ff00ff00, 0xff000000ff00ffff,
110  0xff000000ffff0000, 0xff000000ffff00ff, 0xff000000ffffff00, 0xff000000ffffffff,
111  0xff0000ff00000000, 0xff0000ff000000ff, 0xff0000ff0000ff00, 0xff0000ff0000ffff,
112  0xff0000ff00ff0000, 0xff0000ff00ff00ff, 0xff0000ff00ffff00, 0xff0000ff00ffffff,
113  0xff0000ffff000000, 0xff0000ffff0000ff, 0xff0000ffff00ff00, 0xff0000ffff00ffff,
114  0xff0000ffffff0000, 0xff0000ffffff00ff, 0xff0000ffffffff00, 0xff0000ffffffffff,
115  0xff00ff0000000000, 0xff00ff00000000ff, 0xff00ff000000ff00, 0xff00ff000000ffff,
116  0xff00ff0000ff0000, 0xff00ff0000ff00ff, 0xff00ff0000ffff00, 0xff00ff0000ffffff,
117  0xff00ff00ff000000, 0xff00ff00ff0000ff, 0xff00ff00ff00ff00, 0xff00ff00ff00ffff,
118  0xff00ff00ffff0000, 0xff00ff00ffff00ff, 0xff00ff00ffffff00, 0xff00ff00ffffffff,
119  0xff00ffff00000000, 0xff00ffff000000ff, 0xff00ffff0000ff00, 0xff00ffff0000ffff,
120  0xff00ffff00ff0000, 0xff00ffff00ff00ff, 0xff00ffff00ffff00, 0xff00ffff00ffffff,
121  0xff00ffffff000000, 0xff00ffffff0000ff, 0xff00ffffff00ff00, 0xff00ffffff00ffff,
122  0xff00ffffffff0000, 0xff00ffffffff00ff, 0xff00ffffffffff00, 0xff00ffffffffffff,
123  0xffff000000000000, 0xffff0000000000ff, 0xffff00000000ff00, 0xffff00000000ffff,
124  0xffff000000ff0000, 0xffff000000ff00ff, 0xffff000000ffff00, 0xffff000000ffffff,
125  0xffff0000ff000000, 0xffff0000ff0000ff, 0xffff0000ff00ff00, 0xffff0000ff00ffff,
126  0xffff0000ffff0000, 0xffff0000ffff00ff, 0xffff0000ffffff00, 0xffff0000ffffffff,
127  0xffff00ff00000000, 0xffff00ff000000ff, 0xffff00ff0000ff00, 0xffff00ff0000ffff,
128  0xffff00ff00ff0000, 0xffff00ff00ff00ff, 0xffff00ff00ffff00, 0xffff00ff00ffffff,
129  0xffff00ffff000000, 0xffff00ffff0000ff, 0xffff00ffff00ff00, 0xffff00ffff00ffff,
130  0xffff00ffffff0000, 0xffff00ffffff00ff, 0xffff00ffffffff00, 0xffff00ffffffffff,
131  0xffffff0000000000, 0xffffff00000000ff, 0xffffff000000ff00, 0xffffff000000ffff,
132  0xffffff0000ff0000, 0xffffff0000ff00ff, 0xffffff0000ffff00, 0xffffff0000ffffff,
133  0xffffff00ff000000, 0xffffff00ff0000ff, 0xffffff00ff00ff00, 0xffffff00ff00ffff,
134  0xffffff00ffff0000, 0xffffff00ffff00ff, 0xffffff00ffffff00, 0xffffff00ffffffff,
135  0xffffffff00000000, 0xffffffff000000ff, 0xffffffff0000ff00, 0xffffffff0000ffff,
136  0xffffffff00ff0000, 0xffffffff00ff00ff, 0xffffffff00ffff00, 0xffffffff00ffffff,
137  0xffffffffff000000, 0xffffffffff0000ff, 0xffffffffff00ff00, 0xffffffffff00ffff,
138  0xffffffffffff0000, 0xffffffffffff00ff, 0xffffffffffffff00, 0xffffffffffffffff,
139 };
140 
141 
142 static __forceinline BOOLEAN
144  void
145  )
151 {
152  int regs[4] = {0};
153 
154  __cpuid(regs, 1);
155 
156  if (regs[2] & (1 << 20))
157  {
158  return TRUE;
159  }
160 
161  return FALSE;
162 }
163 
164 
165 void
167  void
168  )
177 {
178  IntGlueReset();
179 }
180 
181 
182 //
183 // IntInit
184 //
185 INTSTATUS
187  _Inout_ GLUE_IFACE *GlueInterface,
188  _In_ UPPER_IFACE const *UpperInterface
189  )
206 {
207  INTSTATUS status;
208 
209  status = IntGlueInit(GlueInterface, UpperInterface);
210  if (!INT_SUCCESS(status))
211  {
212  return status;
213  }
214 
215  //
216  // Populate our part of the interface
217  //
218  GlueInterface->NewGuestNotification = IntNewGuestNotification;
219  GlueInterface->DisableIntro = IntDisableIntro;
220  GlueInterface->NotifyGuestPowerStateChange = IntNotifyGuestPowerStateChange;
221  GlueInterface->DebugProcessCommand = IntProcessDebugCommand;
222  GlueInterface->UpdateExceptions = IntUpdateExceptions;
223  GlueInterface->GetExceptionsVersion = IntGetExceptionsVersion;
224  GlueInterface->GetGuestInfo = IntGetGuestInfo;
225  GlueInterface->InjectProcessAgent = IntInjectProcessAgentInGuest;
226  GlueInterface->InjectFileAgent = IntInjectFileAgentInGuest;
227  GlueInterface->SetIntroAbortStatus = IntAbortEnableIntro;
228  GlueInterface->AddExceptionFromAlert = IntAddExceptionFromAlert;
229  GlueInterface->RemoveException = IntRemoveException;
230  GlueInterface->FlushAlertExceptions = IntFlushAlertExceptions;
231  GlueInterface->AddRemoveProtectedProcessUtf16 = IntAddRemoveProtectedProcessUtf16;
232  GlueInterface->AddRemoveProtectedProcessUtf8 = IntAddRemoveProtectedProcessUtf8;
233  GlueInterface->RemoveAllProtectedProcesses = IntRemoveAllProtectedProcesses;
234  GlueInterface->GetCurrentInstructionLength = IntGetCurrentInstructionLength;
235  GlueInterface->GetCurrentInstructionMnemonic = IntGetCurrentInstructionMnemonic;
236  GlueInterface->IterateVirtualAddressSpace = IntIterateVaSpace;
237  GlueInterface->ModifyDynamicOptions = IntModifyDynamicOptions;
238  GlueInterface->FlushGpaCache = IntFlushGpaCache;
239  GlueInterface->GetCurrentIntroOptions = IntGetCurrentIntroOptions;
240  GlueInterface->UpdateSupport = IntUpdateSupport;
241  GlueInterface->GetSupportVersion = IntGetSupportVersion;
242  GlueInterface->SetLogLevel = IntSetLogLevel;
243  GlueInterface->GetVersionString = IntGetVersionString;
244 
246 
247  LOG("IntroCore initialised: version %d.%d.%d, build %05d, changeset %s, built on %s %s from branch %s\n",
248  INTRO_VERSION_MAJOR, INTRO_VERSION_MINOR, INTRO_VERSION_REVISION, INTRO_VERSION_BUILDNUMBER,
249  INTRO_VERSION_CHANGESET, __DATE__, __TIME__, INTRO_VERSION_BRANCH);
250 
251  status = IntSpinLockInit(&gLock, "INTRO GLOCK");
252  if (!INT_SUCCESS(status))
253  {
254  ERROR("[ERROR] IntSpinLockInit failed: %08x\n", status);
255  return status;
256  }
257 
258  return INT_STATUS_SUCCESS;
259 }
260 
261 
262 //
263 // IntUninit
264 //
265 INTSTATUS
267  void
268  )
278 {
279  LIST_ENTRY *list;
280 
281  TRACE("[INFO] Unloading introspection library...\n");
282 
283  if (gGuest.Initialized)
284  {
286  if (!INT_SUCCESS(status))
287  {
288  ERROR("[ERROR] IntDisableIntro failed: 0x%08x\n", status);
289  }
290  }
291 
292  if (gLock)
293  {
295  }
296 
297  list = gMultiPageMaps.Flink;
298  while (list != &gMultiPageMaps)
299  {
301  list = list->Flink;
302 
304  RemoveEntryList(&pPage->Link);
306  }
307 
308  IntGlueReset();
309 
310  return INT_STATUS_SUCCESS;
311 }
312 
313 
314 static INTSTATUS
316  _In_ QWORD VirtualAddress,
317  _In_ DWORD Length,
318  _In_opt_ QWORD Cr3,
319  _When_(Write == TRUE, _In_reads_bytes_(Length))
320  _When_(Write == FALSE, _Out_writes_bytes_(Length))
321  void *Buffer,
322  _Out_opt_ DWORD *RetLength,
323  _In_ BOOLEAN Write
324  )
354 {
355  INTSTATUS status;
356  DWORD left = Length;
357  QWORD gva = VirtualAddress;
358  BYTE *buffer = Buffer;
359 
360  if (0 == Length)
361  {
363  }
364 
365  if (0 == Cr3)
366  {
367  status = IntCr3Read(IG_CURRENT_VCPU, &Cr3);
368  if (!INT_SUCCESS(status))
369  {
370  return status;
371  }
372  }
373 
374  do
375  {
376  DWORD size = MIN(left, PAGE_REMAINING(gva));
377  void *p;
378 
379  status = IntVirtMemMap(gva, size, Cr3, 0, &p);
380  if (!INT_SUCCESS(status))
381  {
382  goto cleanup_and_exit;
383  }
384 
385  if (__unlikely(Write))
386  {
387  memcpy(p, buffer, size);
388  }
389  else
390  {
391  memcpy(buffer, p, size);
392  }
393 
394  IntVirtMemUnmap(&p);
395 
396  gva += size;
397  left -= size;
398  buffer += size;
399  } while (gva < VirtualAddress + Length);
400 
401  status = INT_STATUS_SUCCESS;
402 
403 cleanup_and_exit:
404  if (RetLength != NULL)
405  {
406  *RetLength = Length - left;
407  }
408 
409  return status;
410 }
411 
412 
413 INTSTATUS
415  _In_ QWORD VirtualAddress,
416  _In_ DWORD Length,
417  _In_opt_ QWORD Cr3,
418  _In_ BYTE Value
419  )
420 {
421  INTSTATUS status;
422  DWORD left = Length;
423  QWORD gva = VirtualAddress;
424 
425  if (0 == Length)
426  {
428  }
429 
430  if (0 == Cr3)
431  {
432  status = IntCr3Read(IG_CURRENT_VCPU, &Cr3);
433  if (!INT_SUCCESS(status))
434  {
435  return status;
436  }
437  }
438 
439  do
440  {
441  DWORD size = MIN(left, PAGE_REMAINING(gva));
442  void *p;
443 
444  status = IntVirtMemMap(gva, size, Cr3, 0, &p);
445  if (!INT_SUCCESS(status))
446  {
447  return status;
448  }
449 
450  memset(p, Value, size);
451  IntVirtMemUnmap(&p);
452 
453  gva += size;
454  left -= size;
455  } while (gva < VirtualAddress + Length);
456 
457  return INT_STATUS_SUCCESS;
458 }
459 
460 
461 static INTSTATUS
463  _In_ QWORD PhysicalAddress,
464  _In_ DWORD Length,
465  _When_(Write == TRUE, _In_reads_bytes_(Length))
466  _When_(Write == FALSE, _Out_writes_bytes_(Length))
467  void *Buffer,
468  _Out_opt_ DWORD *RetLength,
469  _In_ BOOLEAN Write
470  )
497 {
498  INTSTATUS status;
499  DWORD left = Length;
500  QWORD gpa = PhysicalAddress;
501  BYTE *buffer = Buffer;
502 
503  if (0 == Length)
504  {
506  }
507 
508  while (gpa < PhysicalAddress + Length)
509  {
510  DWORD size = MIN(left, PAGE_REMAINING(gpa));
511  void *p;
512 
513  status = IntPhysMemMap(gpa, size, 0, &p);
514  if (!INT_SUCCESS(status))
515  {
516  goto cleanup_and_exit;
517  }
518 
519  if (__unlikely(Write))
520  {
521  memcpy(p, buffer, size);
522  }
523  else
524  {
525  memcpy(buffer, p, size);
526  }
527 
528  IntVirtMemUnmap(&p);
529 
530  gpa += size;
531  left -= size;
532  buffer += size;
533  }
534 
535  status = INT_STATUS_SUCCESS;
536 
537 cleanup_and_exit:
538  if (RetLength != NULL)
539  {
540  *RetLength = Length - left;
541  }
542 
543  return status;
544 }
545 
546 
547 static INTSTATUS
549  _In_ QWORD PhysicalAddress,
550  _In_ DWORD Length,
551  _Inout_updates_bytes_(Length) void *Buffer,
552  _Out_opt_ DWORD *RetLength,
553  _In_ BOOLEAN Write
554  )
579 {
580  INTSTATUS status;
581  void *p;
582  DWORD copiedSize = 0;
583 
584  if (PAGE_COUNT(PhysicalAddress, Length) > 1)
585  {
587  }
588 
589  if (0 == Length)
590  {
592  }
593 
594  status = IntPhysMemMap(PhysicalAddress, PAGE_REMAINING(PhysicalAddress), 0, &p);
595  if (!INT_SUCCESS(status))
596  {
597  TRACE("[ERROR] IntPhysMemMap failed: 0x%08x\n", status);
598  goto cleanup_and_exit;
599  }
600 
601  if (Write)
602  {
603  memcpy(p, Buffer, Length);
604  }
605  else
606  {
607  memcpy(Buffer, p, Length);
608  }
609 
610  copiedSize = Length;
611 
612  IntPhysMemUnmap(&p);
613 
614  status = INT_STATUS_SUCCESS;
615 
616 cleanup_and_exit:
617  if (RetLength != NULL)
618  {
619  *RetLength = copiedSize;
620  }
621 
622  return status;
623 }
624 
625 
626 INTSTATUS
628  _In_ QWORD Gva,
629  _In_ DWORD Length,
630  _In_opt_ QWORD Cr3,
631  _Out_writes_bytes_(Length) void *Buffer,
632  _Out_opt_ DWORD *RetLength
633  )
646 {
647  return IntVirtMemReadWrite(Gva, Length, Cr3, Buffer, RetLength, FALSE);
648 }
649 
650 
651 INTSTATUS
653  _In_ QWORD Gva,
654  _In_ DWORD Length,
655  _In_opt_ QWORD Cr3,
656  _In_reads_bytes_(Length) void *Buffer
657  )
668 {
669  return IntVirtMemReadWrite(Gva, Length, Cr3, Buffer, NULL, TRUE);
670 }
671 
672 
673 INTSTATUS
675  _In_ QWORD KernelGva,
676  _In_ DWORD Length,
677  _Out_writes_bytes_(Length) void *Buffer,
678  _Out_opt_ DWORD *RetLength
679  )
693 {
694  return IntVirtMemReadWrite(KernelGva, Length, gGuest.Mm.SystemCr3, Buffer, RetLength, FALSE);
695 }
696 
697 
698 INTSTATUS
700  _In_ QWORD KernelGva,
701  _In_ DWORD Length,
702  _In_reads_bytes_(Length) void *Buffer
703  )
715 {
716  return IntVirtMemReadWrite(KernelGva, Length, gGuest.Mm.SystemCr3, Buffer, NULL, TRUE);
717 }
718 
719 
720 INTSTATUS
722  _In_ QWORD PhysicalAddress,
723  _In_ DWORD Length,
724  _Out_writes_bytes_(Length) void *Buffer,
725  _Out_opt_ DWORD *RetLength
726  )
738 {
739  return IntPhysMemReadWrite(PhysicalAddress, Length, Buffer, RetLength, FALSE);
740 }
741 
742 
743 INTSTATUS
745  _In_ QWORD PhysicalAddress,
746  _In_ DWORD Length,
747  _In_reads_bytes_(Length) void *Buffer
748  )
758 {
759  return IntPhysMemReadWrite(PhysicalAddress, Length, Buffer, NULL, TRUE);
760 }
761 
762 
763 INTSTATUS
765  _In_ QWORD PhysicalAddress,
766  _In_ DWORD Length,
767  _Out_writes_bytes_(Length) void *Buffer,
768  _Out_opt_ DWORD *RetLength
769  )
783 {
784  return IntPhysMemReadWriteAnySize(PhysicalAddress, Length, Buffer, RetLength, FALSE);
785 }
786 
787 
788 INTSTATUS
790  _In_ QWORD PhysicalAddress,
791  _In_ DWORD Length,
792  _In_reads_bytes_(Length) void *Buffer
793  )
805 {
806  return IntPhysMemReadWriteAnySize(PhysicalAddress, Length, Buffer, NULL, TRUE);
807 }
808 
809 
810 INTSTATUS
812  _In_ QWORD GuestVirtualAddress,
813  _Out_ QWORD *Data
814  )
823 {
824  return IntKernVirtMemRead(GuestVirtualAddress, 8, Data, NULL);
825 }
826 
827 
828 INTSTATUS
830  _In_ QWORD GuestVirtualAddress,
831  _Out_ DWORD *Data
832  )
841 {
842  return IntKernVirtMemRead(GuestVirtualAddress, 4, Data, NULL);
843 }
844 
845 
846 INTSTATUS
848  _In_ QWORD GuestVirtualAddress,
849  _Out_ void *Data
850  )
860 {
861  return IntKernVirtMemRead(GuestVirtualAddress, gGuest.WordSize, Data, NULL);
862 }
863 
864 
865 INTSTATUS
867  _In_ QWORD GuestVirtualAddress,
868  _In_opt_ QWORD Cr3,
869  _Out_ QWORD *Data
870  )
881 {
882  return IntVirtMemRead(GuestVirtualAddress, 8, Cr3, Data, NULL);
883 }
884 
885 
886 INTSTATUS
888  _In_ QWORD GuestVirtualAddress,
889  _In_opt_ QWORD Cr3,
890  _Out_ DWORD *Data
891  )
902 {
903  return IntVirtMemRead(GuestVirtualAddress, 4, Cr3, Data, NULL);
904 }
905 
906 
907 INTSTATUS
909  _In_ QWORD GuestVirtualAddress,
910  _In_opt_ QWORD Cr3,
911  _Out_ void *Data
912  )
926 {
927  return IntVirtMemRead(GuestVirtualAddress, gGuest.WordSize, Cr3, Data, NULL);
928 }
929 
930 
931 INTSTATUS
933  _In_ QWORD GuestVirtualAddress,
934  _In_ QWORD Data
935  )
944 {
945  return IntKernVirtMemWrite(GuestVirtualAddress, 8, &Data);
946 }
947 
948 
949 INTSTATUS
951  _In_ QWORD GuestVirtualAddress,
952  _In_ DWORD Data
953  )
962 {
963  return IntKernVirtMemWrite(GuestVirtualAddress, 4, &Data);
964 }
965 
966 
967 INTSTATUS
969  _In_ QWORD GuestVirtualAddress,
970  _In_ QWORD Data
971  )
983 {
984  return IntKernVirtMemWrite(GuestVirtualAddress, gGuest.WordSize, &Data);
985 }
986 
987 
988 INTSTATUS
990  _In_ QWORD GuestVirtualAddress,
991  _In_opt_ QWORD Cr3,
992  _In_ QWORD Data
993  )
1004 {
1005  return IntVirtMemWrite(GuestVirtualAddress, 8, Cr3, &Data);
1006 }
1007 
1008 
1009 INTSTATUS
1011  _In_ QWORD GuestVirtualAddress,
1012  _In_opt_ QWORD Cr3,
1013  _In_ DWORD Data
1014  )
1025 {
1026  return IntVirtMemWrite(GuestVirtualAddress, 4, Cr3, &Data);
1027 }
1028 
1029 
1030 INTSTATUS
1032  _In_ QWORD GuestVirtualAddress,
1033  _In_opt_ QWORD Cr3,
1034  _In_ QWORD Data
1035  )
1047 {
1048  return IntVirtMemWrite(GuestVirtualAddress, gGuest.WordSize, Cr3, &Data);
1049 }
1050 
1051 
1052 INTSTATUS
1054  _In_ QWORD Gva,
1055  _In_ DWORD MaxLength,
1056  _In_opt_ QWORD Cr3,
1057  _Out_writes_z_(MaxLength) void *Buffer
1058  )
1072 {
1073  INTSTATUS status;
1074  PCHAR pBuf;
1075  QWORD chunk;
1076  DWORD i, j;
1077 
1078  if (NULL == Buffer)
1079  {
1081  }
1082 
1083  i = 0;
1084  chunk = 0;
1085 
1086  pBuf = (PCHAR)Buffer;
1087 
1088  // We will basically read 8 bytes at a time
1089  while (i < MaxLength)
1090  {
1091  // Read current chunk
1092  status = IntVirtMemRead(Gva + i, 8, Cr3, &chunk, NULL);
1093  if (!INT_SUCCESS(status))
1094  {
1095  return status;
1096  }
1097 
1098  // Check if we exceed maximum length, and if we have a NULL terminator
1099  for (j = 0; j < MIN(8u, MaxLength - i); j++)
1100  {
1101  pBuf[i++] = (CHAR)chunk;
1102  chunk >>= 8;
1103 
1104  if (pBuf[i - 1] == 0)
1105  {
1106  // Done! We found the NULL terminator
1107  return INT_STATUS_SUCCESS;
1108  }
1109  }
1110  }
1111 
1112  return INT_STATUS_NOT_FOUND;
1113 }
1114 
1115 
1116 static INTSTATUS
1118  _In_ QWORD Gpa,
1119  _Outptr_ void **HostPtr
1120  )
1131 {
1132  //
1133  // The reason for the #ifdef is that on Napoca, the fastmap is more than enough.
1134  // The speed-up of using the cache is less than 5%, so don't bother.
1135  //
1136 #ifdef USER_MODE
1137  if (__likely(gGuest.GpaCache))
1138  {
1139  return IntGpaCacheFindAndAdd(gGuest.GpaCache, Gpa, HostPtr);
1140  }
1141 #endif // USER_MODE
1142 
1143  return IntPhysMemMap(Gpa, PAGE_SIZE, 0, HostPtr);
1144 }
1145 
1146 
1147 static INTSTATUS
1149  _In_ QWORD Gpa,
1150  _Inout_ _At_(*HostPtr, _Post_null_) void **HostPtr
1151  )
1160 {
1161 #ifdef USER_MODE
1162  if (__likely(gGuest.GpaCache))
1163  {
1164  return IntGpaCacheRelease(gGuest.GpaCache, Gpa);
1165  }
1166 #else
1168 #endif // USER_MODE
1169 
1170  return IntPhysMemUnmap(HostPtr);
1171 }
1172 
1173 
1174 static INTSTATUS
1176  _In_ UINT32 Gva,
1177  _In_ UINT32 Cr3,
1178  _Out_ VA_TRANSLATION *Translation
1179  )
1192 {
1193  INTSTATUS status;
1194 
1195  UINT32 pdi = PD32_INDEX(Gva);
1196  UINT32 pti = PT32_INDEX(Gva);
1197 
1198  UINT32 pde, pte, pf;
1199  UINT32 *pd, *pt;
1200 
1201  pd = pt = NULL;
1202  pde = pte = 0;
1203 
1204  Translation->Pointer64 = FALSE;
1205 
1206  //
1207  // Fetch and handle PD entry.
1208  //
1209  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS32(Cr3), &pd);
1210  if (!INT_SUCCESS(status))
1211  {
1213  goto cleanup_and_exit;
1214  }
1215 
1216  pde = pd[pdi];
1217 
1218  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS32(Cr3) + 4ull * pdi;
1219  Translation->MappingsEntries[Translation->MappingsCount] = pde;
1220  Translation->MappingsCount++;
1221 
1222  if ((pde & PD_P) == 0)
1223  {
1225  goto cleanup_and_exit;
1226  }
1227 
1228  Translation->IsUser = Translation->IsUser && !!(pde & PT_US);
1229  Translation->IsWritable = Translation->IsWritable && !!(pde & PT_RW);
1230 
1231  // Check if this is a 4 MB page.
1232  if (0 != (pde & PD_PS))
1233  {
1234  // This is a 4 MB page, next table is in fact the physical address of the page
1235  Translation->Flags = pde;
1236  Translation->PageSize = PAGE_SIZE_4M;
1237 
1238  pf = (pde & 0xFFC00000) | ((pde & 0x003FE000) << 19);
1239  pf += (Gva & 0x3FFFFF);
1240 
1241  goto using_4m_page;
1242  }
1243 
1244 
1245  // Fetch & handle PT entry.
1246  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS32(pde), &pt);
1247  if (!INT_SUCCESS(status))
1248  {
1249  goto cleanup_and_exit;
1250  }
1251 
1252  pte = pt[pti];
1253 
1254  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS32(pde) + 4ull * pti;
1255  Translation->MappingsEntries[Translation->MappingsCount] = pte;
1256  Translation->MappingsCount++;
1257 
1258  Translation->Flags = pte;
1259  Translation->PageSize = PAGE_SIZE_4K;
1260 
1261  if ((pte & PD_P) == 0)
1262  {
1263  pf = 0;
1264  }
1265  else
1266  {
1267  Translation->IsUser = Translation->IsUser && !!(pte & PT_US);
1268  Translation->IsWritable = Translation->IsWritable && !!(pte & PT_RW);
1269 
1270  pf = CLEAN_PHYS_ADDRESS32(pte);
1271  pf += (Gva & 0xFFF);
1272  }
1273 
1274 using_4m_page:
1275  Translation->PhysicalAddress = pf;
1276 
1277  status = INT_STATUS_SUCCESS;
1278 
1279 cleanup_and_exit:
1280  if (NULL != pd)
1281  {
1283  }
1284 
1285  if (NULL != pt)
1286  {
1288  }
1289 
1290  return status;
1291 }
1292 
1293 
1294 static INTSTATUS
1296  _In_ UINT64 Gva,
1297  _In_ UINT64 Cr3,
1298  _Out_ VA_TRANSLATION *Translation
1299  )
1312 {
1313  INTSTATUS status;
1314 
1315  UINT32 pdpi = PDPPAE_INDEX(Gva);
1316  UINT32 pdi = PDPAE_INDEX(Gva);
1317  UINT32 pti = PTPAE_INDEX(Gva);
1318 
1319  UINT64 pdpe, pde, pte, pf;
1320  UINT64 *pdp, *pd, *pt;
1321 
1322  pdp = pd = pt = NULL;
1323  pdpe = pde = pte = 0;
1324 
1325  Translation->Pointer64 = TRUE;
1326 
1327  //
1328  // Fetch and handle the PDP entry.
1329  //
1330  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS32PAE(Cr3), &pdp);
1331  if (!INT_SUCCESS(status))
1332  {
1334  goto cleanup_and_exit_pae;
1335  }
1336 
1337  // CR3 is aligned only to 32 bytes, not 4096 bytes.
1338  pdp = (PQWORD)(((PBYTE)pdp) + (Cr3 & 0xFE0));
1339 
1340  // We get the PDPE from the PDP, which points to a PD
1341  pdpe = pdp[pdpi];
1342 
1343  Translation->MappingsTrace[Translation->MappingsCount] = (CLEAN_PHYS_ADDRESS32PAE_ROOT(Cr3)) + 8ull * pdpi;
1344  Translation->MappingsEntries[Translation->MappingsCount] = pdpe;
1345  Translation->MappingsCount++;
1346 
1347  pdp = (PQWORD)(((PBYTE)pdp) - (Cr3 & 0xFE0));
1348 
1349  if ((pdpe & PDP_P) == 0)
1350  {
1352  goto cleanup_and_exit_pae;
1353  }
1354 
1355  //
1356  // Fetch and handle PD entry.
1357  //
1358  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS32PAE(pdpe), &pd);
1359  if (!INT_SUCCESS(status))
1360  {
1362  goto cleanup_and_exit_pae;
1363  }
1364 
1365  pde = pd[pdi];
1366 
1367  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS32PAE(pdpe) + 8ull * pdi;
1368  Translation->MappingsEntries[Translation->MappingsCount] = pde;
1369  Translation->MappingsCount++;
1370 
1371  if ((pde & PD_P) == 0)
1372  {
1374  goto cleanup_and_exit_pae;
1375  }
1376 
1377  Translation->IsUser = Translation->IsUser && !!(pde & PT_US);
1378  Translation->IsWritable = Translation->IsWritable && !!(pde & PT_RW);
1379  Translation->IsExecutable = Translation->IsExecutable && !(pde & PT_XD);
1380 
1381  // Check if this is a 2 MB page.
1382  if (pde & PD_PS)
1383  {
1384  // This is a 2 MB page, next table is in fact the physical address of the page
1385  Translation->Flags = pde;
1386  Translation->PageSize = PAGE_SIZE_2M;
1387 
1388  pf = CLEAN_PHYS_ADDRESS32PAE(pde) & (~0x1FFFFFULL);
1389  pf += (Gva & 0x1FFFFF);
1390 
1391  goto using_2m_page_pae;
1392  }
1393 
1394  //
1395  // Fetch and handle PT entry.
1396  //
1398  if (!INT_SUCCESS(status))
1399  {
1400  goto cleanup_and_exit_pae;
1401  }
1402 
1403  pte = pt[pti];
1404 
1405  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS32PAE(pde) + 8ull * pti;
1406  Translation->MappingsEntries[Translation->MappingsCount] = pte;
1407  Translation->MappingsCount++;
1408 
1409  Translation->Flags = pte;
1410  Translation->PageSize = PAGE_SIZE_4K;
1411 
1412  if ((pte & PT_P) == 0)
1413  {
1414  pf = 0;
1415  }
1416  else
1417  {
1418  Translation->IsUser = Translation->IsUser && !!(pte & PT_US);
1419  Translation->IsWritable = Translation->IsWritable && !!(pte & PT_RW);
1420  Translation->IsExecutable = Translation->IsExecutable && !(pte & PT_XD);
1421 
1422  pf = CLEAN_PHYS_ADDRESS32PAE(pte);
1423  pf += (Gva & 0xFFF);
1424  }
1425 
1426 using_2m_page_pae:
1427  Translation->PhysicalAddress = pf;
1428 
1429  status = INT_STATUS_SUCCESS;
1430 
1431 cleanup_and_exit_pae:
1432  if (NULL != pdp)
1433  {
1435  }
1436 
1437  if (NULL != pd)
1438  {
1440  }
1441 
1442  if (NULL != pt)
1443  {
1445  }
1446 
1447  return status;
1448 }
1449 
1450 
1451 static INTSTATUS
1453  _In_ UINT64 Gva,
1454  _In_ UINT64 Cr3,
1455  _Out_ VA_TRANSLATION *Translation
1456  )
1469 {
1470  INTSTATUS status;
1471 
1472  UINT32 pml4i = PML4_INDEX(Gva);
1473  UINT32 pdpi = PDP_INDEX (Gva);
1474  UINT32 pdi = PD_INDEX (Gva);
1475  UINT32 pti = PT_INDEX (Gva);
1476 
1477  UINT64 pml4e, pdpe, pde, pte, pf; // entries values
1478  UINT64 *pml4, *pdp, *pd, *pt; // mapped pages
1479 
1480  pml4 = pdp = pd = pt = NULL;
1481  pml4e = pdpe = pde = pte = 0;
1482 
1483  Translation->Pointer64 = TRUE;
1484 
1485  // Fetch and handle the PML4 entry.
1486  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(Cr3), &pml4);
1487  if (!INT_SUCCESS(status))
1488  {
1490  goto cleanup_and_exit_4_level;
1491  }
1492 
1493  pml4e = pml4[pml4i];
1494 
1495  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(Cr3) + 8ull * pml4i;
1496  Translation->MappingsEntries[Translation->MappingsCount] = pml4e;
1497  Translation->MappingsCount++;
1498 
1499  if ((pml4e & PD_P) == 0)
1500  {
1502  goto cleanup_and_exit_4_level;
1503  }
1504 
1505  Translation->IsUser = Translation->IsUser && !!(pml4e & PT_US);
1506  Translation->IsWritable = Translation->IsWritable && !!(pml4e & PT_RW);
1507  Translation->IsExecutable = Translation->IsExecutable && !(pml4e & PT_XD);
1508 
1509  // Fetch and handle the PDP entry.
1510  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(pml4e), &pdp);
1511  if (!INT_SUCCESS(status))
1512  {
1514  goto cleanup_and_exit_4_level;
1515  }
1516 
1517  pdpe = pdp[pdpi];
1518 
1519  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(pml4e) + 8ull * pdpi;
1520  Translation->MappingsEntries[Translation->MappingsCount] = pdpe;
1521  Translation->MappingsCount++;
1522 
1523  if ((pdpe & PD_P) == 0)
1524  {
1526  goto cleanup_and_exit_4_level;
1527  }
1528 
1529  Translation->IsUser = Translation->IsUser && !!(pdpe & PT_US);
1530  Translation->IsWritable = Translation->IsWritable && !!(pdpe & PT_RW);
1531  Translation->IsExecutable = Translation->IsExecutable && !(pdpe & PT_XD);
1532 
1533  // Check if this is a 1 GB page.
1534  if (pdpe & PDP_PS)
1535  {
1536  // This is a 1 GB page, next table is in fact the physical address of the page
1537  Translation->Flags = pdpe;
1538  Translation->PageSize = PAGE_SIZE_1G;
1539 
1540  pf = CLEAN_PHYS_ADDRESS64(pdpe) & (~0x3FFFFFFFULL);
1541  pf += (Gva & 0x3FFFFFFF);
1542 
1543  goto using_1g_page_4_level;
1544  }
1545 
1546  // Fetch and handle the PD entry.
1547  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(pdpe), &pd);
1548  if (!INT_SUCCESS(status))
1549  {
1550  goto cleanup_and_exit_4_level;
1551  }
1552 
1553  pde = pd[pdi];
1554 
1555  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(pdpe) + 8ull * pdi;
1556  Translation->MappingsEntries[Translation->MappingsCount] = pde;
1557  Translation->MappingsCount++;
1558 
1559  if ((pde & PD_P) == 0)
1560  {
1562  goto cleanup_and_exit_4_level;
1563  }
1564 
1565  Translation->IsUser = Translation->IsUser && !!(pde & PT_US);
1566  Translation->IsWritable = Translation->IsWritable && !!(pde & PT_RW);
1567  Translation->IsExecutable = Translation->IsExecutable && !(pde & PT_XD);
1568 
1569  // Check if this is a 2 MB page.
1570  if (pde & PD_PS)
1571  {
1572  // This is a 2 MB page, next table is in fact the physical address of the page
1573  Translation->Flags = pde;
1574  Translation->PageSize = PAGE_SIZE_2M;
1575 
1576  pf = CLEAN_PHYS_ADDRESS64(pde) & (~0x1FFFFFULL);
1577  pf += (Gva & 0x1FFFFF);
1578 
1579  goto using_2m_page_4_level;
1580  }
1581 
1582  // Fetch and handle the PT entry.
1583  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(pde), &pt);
1584  if (!INT_SUCCESS(status))
1585  {
1586  goto cleanup_and_exit_4_level;
1587  }
1588 
1589  pte = pt[pti];
1590 
1591  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(pde) + 8ull * pti;
1592  Translation->MappingsEntries[Translation->MappingsCount] = pte;
1593  Translation->MappingsCount++;
1594 
1595  Translation->Flags = pte;
1596  Translation->PageSize = PAGE_SIZE_4K;
1597 
1598  if ((pte & PD_P) == 0)
1599  {
1600  // If the last page is not present, we will return success; The caller must check if the page is
1601  // present or not.
1602  pf = 0;
1603  }
1604  else
1605  {
1606  Translation->IsUser = Translation->IsUser && !!(pte & PT_US);
1607  Translation->IsWritable = Translation->IsWritable && !!(pte & PT_RW);
1608  Translation->IsExecutable = Translation->IsExecutable && !(pte & PT_XD);
1609 
1610  pf = CLEAN_PHYS_ADDRESS64(pte);
1611  pf += (Gva & 0xFFF);
1612  }
1613 
1614 using_1g_page_4_level:
1615 using_2m_page_4_level:
1616  Translation->PhysicalAddress = pf;
1617 
1618  status = INT_STATUS_SUCCESS;
1619 
1620 cleanup_and_exit_4_level:
1621  if (NULL != pml4)
1622  {
1624  }
1625 
1626  if (NULL != pdp)
1627  {
1629  }
1630 
1631  if (NULL != pd)
1632  {
1634  }
1635 
1636  if (NULL != pt)
1637  {
1639  }
1640 
1641  return status;
1642 }
1643 
1644 
1645 static INTSTATUS
1647  _In_ UINT64 Gva,
1648  _In_ UINT64 Cr3,
1649  _Out_ VA_TRANSLATION *Translation
1650  )
1663 {
1664  INTSTATUS status;
1665 
1666  UINT32 pml5i = PML5_INDEX(Gva);
1667  UINT32 pml4i = PML4_INDEX(Gva);
1668  UINT32 pdpi = PDP_INDEX(Gva);
1669  UINT32 pdi = PD_INDEX(Gva);
1670  UINT32 pti = PT_INDEX(Gva);
1671 
1672  UINT64 pml5e, pml4e, pdpe, pde, pte, pf; // entries values
1673  UINT64 *pml5, *pml4, *pdp, *pd, *pt; // mapped pages
1674 
1675  pml5 = pml4 = pdp = pd = pt = NULL;
1676  pml5e = pml4e = pdpe = pde = pte = 0;
1677 
1678  Translation->Pointer64 = TRUE;
1679 
1680  // Fetch and handle PML5 entry.
1681  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(Cr3), &pml5);
1682  if (!INT_SUCCESS(status))
1683  {
1684  goto cleanup_and_exit_5_level;
1685  }
1686 
1687  pml5e = pml5[pml5i];
1688 
1689  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(Cr3) + 8ull * pml5i;
1690  Translation->MappingsEntries[Translation->MappingsCount] = pml5e;
1691  Translation->MappingsCount++;
1692 
1693  if ((pml5e & PD_P) == 0)
1694  {
1696  goto cleanup_and_exit_5_level;
1697  }
1698 
1699  // Fetch and handle PML4 entry.
1700  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(pml5e), &pml4);
1701  if (!INT_SUCCESS(status))
1702  {
1703  goto cleanup_and_exit_5_level;
1704  }
1705 
1706  pml4e = pml4[pml4i];
1707 
1708  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(Cr3) + 8ull * pml4i;
1709  Translation->MappingsEntries[Translation->MappingsCount] = pml4e;
1710  Translation->MappingsCount++;
1711 
1712  if ((pml4e & PD_P) == 0)
1713  {
1715  goto cleanup_and_exit_5_level;
1716  }
1717 
1718  Translation->IsUser = Translation->IsUser && !!(pml4e & PT_US);
1719  Translation->IsWritable = Translation->IsWritable && !!(pml4e & PT_RW);
1720  Translation->IsExecutable = Translation->IsExecutable && !(pml4e & PT_XD);
1721 
1722  // Fetch and handle the PDP entry.
1723  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(pml4e), &pdp);
1724  if (!INT_SUCCESS(status))
1725  {
1726  goto cleanup_and_exit_5_level;
1727  }
1728 
1729  pdpe = pdp[pdpi];
1730 
1731  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(pml4e) + 8ull * pdpi;
1732  Translation->MappingsEntries[Translation->MappingsCount] = pdpe;
1733  Translation->MappingsCount++;
1734 
1735  if ((pdpe & PD_P) == 0)
1736  {
1738  goto cleanup_and_exit_5_level;
1739  }
1740 
1741  Translation->IsUser = Translation->IsUser && !!(pdpe & PT_US);
1742  Translation->IsWritable = Translation->IsWritable && !!(pdpe & PT_RW);
1743  Translation->IsExecutable = Translation->IsExecutable && !(pdpe & PT_XD);
1744 
1745  // Check if this is a 1 GB page.
1746  if (pdpe & PDP_PS)
1747  {
1748  // This is a 1 GB page, next table is in fact the physical address of the page
1749  Translation->Flags = pdpe;
1750  Translation->PageSize = PAGE_SIZE_1G;
1751 
1752  pf = CLEAN_PHYS_ADDRESS64(pdpe) & (~0x3FFFFFFFULL);
1753  pf += (Gva & 0x3FFFFFFF);
1754 
1755  goto using_1g_page_5_level;
1756  }
1757 
1758  // Fetch and handle the PD entry.
1759  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(pdpe), &pd);
1760  if (!INT_SUCCESS(status))
1761  {
1762  goto cleanup_and_exit_5_level;
1763  }
1764 
1765  pde = pd[pdi];
1766 
1767  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(pdpe) + 8ull * pdi;
1768  Translation->MappingsEntries[Translation->MappingsCount] = pde;
1769  Translation->MappingsCount++;
1770 
1771  if ((pde & PD_P) == 0)
1772  {
1774  goto cleanup_and_exit_5_level;
1775  }
1776 
1777  Translation->IsUser = Translation->IsUser && !!(pde & PT_US);
1778  Translation->IsWritable = Translation->IsWritable && !!(pde & PT_RW);
1779  Translation->IsExecutable = Translation->IsExecutable && !(pde & PT_XD);
1780 
1781  // Check if this is a 2 MB page.
1782  if (pde & PD_PS)
1783  {
1784  // This is a 2 MB page, next table is in fact the physical address of the page
1785  Translation->Flags = pde;
1786  Translation->PageSize = PAGE_SIZE_2M;
1787 
1788  pf = CLEAN_PHYS_ADDRESS64(pde) & (~0x1FFFFFULL);
1789  pf += (Gva & 0x1FFFFF);
1790 
1791  goto using_2m_page_5_level;
1792  }
1793 
1794  // Fetch and handle the PT entry.
1795  status = IntMapGpaForTranslation(CLEAN_PHYS_ADDRESS64(pde), &pt);
1796  if (!INT_SUCCESS(status))
1797  {
1798  goto cleanup_and_exit_5_level;
1799  }
1800 
1801  pte = pt[pti];
1802 
1803  Translation->MappingsTrace[Translation->MappingsCount] = CLEAN_PHYS_ADDRESS64(pde) + 8ull * pti;
1804  Translation->MappingsEntries[Translation->MappingsCount] = pte;
1805  Translation->MappingsCount++;
1806 
1807  Translation->Flags = pte;
1808  Translation->PageSize = PAGE_SIZE_4K;
1809 
1810  if ((pte & PD_P) == 0)
1811  {
1812  // If the last page is not present, we will return success; The caller must check if the page is
1813  // present or not.
1814  pf = 0;
1815  }
1816  else
1817  {
1818  Translation->IsUser = Translation->IsUser && !!(pte & PT_US);
1819  Translation->IsWritable = Translation->IsWritable && !!(pte & PT_RW);
1820  Translation->IsExecutable = Translation->IsExecutable && !(pte & PT_XD);
1821 
1822  pf = CLEAN_PHYS_ADDRESS64(pte);
1823  pf += (Gva & 0xFFF);
1824  }
1825 
1826 using_1g_page_5_level:
1827 using_2m_page_5_level:
1828  Translation->PhysicalAddress = pf;
1829 
1830  status = INT_STATUS_SUCCESS;
1831 
1832 cleanup_and_exit_5_level:
1833  if (NULL != pml5)
1834  {
1836  }
1837 
1838  if (NULL != pml4)
1839  {
1841  }
1842 
1843  if (NULL != pdp)
1844  {
1846  }
1847 
1848  if (NULL != pd)
1849  {
1851  }
1852 
1853  if (NULL != pt)
1854  {
1856  }
1857 
1858  return status;
1859 }
1860 
1861 
1862 INTSTATUS
1864  _In_ QWORD Gva,
1865  _In_ QWORD Cr3,
1866  _In_ DWORD Flags,
1867  _Out_ VA_TRANSLATION *Translation
1868  )
1889 {
1890  INTSTATUS status;
1891  BYTE pagingMode;
1892 
1893  if (Translation == NULL)
1894  {
1896  }
1897 
1898  memzero(Translation, sizeof(*Translation));
1899 
1900  if (__unlikely(0 != (Flags & TRFLG_MODE_MASK)))
1901  {
1902  switch (Flags & TRFLG_MODE_MASK)
1903  {
1904  case TRFLG_NORMAL_MODE:
1905  pagingMode = PAGING_NORMAL_MODE;
1906  break;
1907  case TRFLG_PAE_MODE:
1908  pagingMode = PAGING_PAE_MODE;
1909  break;
1910  case TRFLG_4_LEVEL_MODE:
1911  pagingMode = PAGING_4_LEVEL_MODE;
1912  break;
1913  case TRFLG_5_LEVEL_MODE:
1914  pagingMode = PAGING_5_LEVEL_MODE;
1915  break;
1916  default:
1918  }
1919  }
1920  else
1921  {
1922  if (__unlikely(gVcpu && !(gVcpu->Regs.Cr0 & CR0_PG)))
1923  {
1924  pagingMode = PAGING_NONE;
1925  }
1926  else
1927  {
1928  pagingMode = gGuest.Mm.Mode;
1929  }
1930  }
1931 
1932  Translation->VirtualAddress = Gva;
1933  Translation->Cr3 = Cr3;
1934  Translation->IsUser = Translation->IsWritable = Translation->IsExecutable = TRUE;
1935  Translation->PagingMode = pagingMode;
1936 
1937  if (pagingMode == PAGING_5_LEVEL_MODE)
1938  {
1939  status = IntTranslateVa64La57(Gva, Cr3, Translation);
1940  }
1941  else if (pagingMode == PAGING_4_LEVEL_MODE)
1942  {
1943  status = IntTranslateVa64(Gva, Cr3, Translation);
1944  }
1945  else if (pagingMode == PAGING_PAE_MODE)
1946  {
1947  status = IntTranslateVa32Pae(Gva, Cr3, Translation);
1948  }
1949  else if (pagingMode == PAGING_NORMAL_MODE)
1950  {
1951  status = IntTranslateVa32((UINT32)Gva, (UINT32)Cr3, Translation);
1952  }
1953  else
1954  {
1955  // The CPU is probably in real mode/without paging for the moment.
1956  Translation->PhysicalAddress = Gva;
1957 
1958  status = INT_STATUS_SUCCESS;
1959  }
1960 
1961  // Validate the caching attributes, if required.
1962  if (__unlikely((INT_STATUS_SUCCESS == status) && (0 != (Flags & TRFLG_CACHING_ATTR))))
1963  {
1964  // For now, we assume PAT is ALWAYS present & used.
1965 
1966  // Get the per-page caching attributes of this VA page.
1967  BYTE patIndex;
1968  IG_QUERY_MSR msr = {0};
1969 
1970  patIndex = 0;
1971 
1972  // Compute the PAT index.
1973  patIndex |= (Translation->Flags & PT_PAT) >> 5;
1974  patIndex |= (Translation->Flags & PT_PCD) >> 3;
1975  patIndex |= (Translation->Flags & PT_PWT) >> 3;
1976 
1977  // Read the PAT MSR.
1978  msr.MsrId = IG_IA32_PAT;
1979 
1981  (void *)(size_t)IG_CURRENT_VCPU,
1982  &msr,
1983  sizeof(IG_QUERY_MSR));
1984  if (!INT_SUCCESS(status))
1985  {
1986  Translation->CachingAttribute = IG_MEM_UNKNOWN;
1987  }
1988  else
1989  {
1990  Translation->CachingAttribute = (msr.Value >> (patIndex * 8)) & 0x7;
1991  }
1992  }
1993 
1994  return status;
1995 }
1996 
1997 
1998 INTSTATUS
2000  _In_ QWORD Gva,
2001  _In_opt_ QWORD Cr3,
2002  _Out_ QWORD *PhysicalAddress
2003  )
2023 {
2024  INTSTATUS status;
2025  VA_TRANSLATION translation = { 0 };
2026 
2027  if (NULL == PhysicalAddress)
2028  {
2030  }
2031 
2032  if (0 == Cr3)
2033  {
2034  status = IntCr3Read(IG_CURRENT_VCPU, &Cr3);
2035  if (!INT_SUCCESS(status))
2036  {
2037  ERROR("[ERROR] IntCr3Read failed: 0x%08x\n", status);
2038  return status;
2039  }
2040  }
2041 
2042  status = IntTranslateVirtualAddressEx(Gva, Cr3, TRFLG_NONE, &translation);
2043  if (!INT_SUCCESS(status))
2044  {
2045  return status;
2046  }
2047 
2048  if (0 == (translation.Flags & PT_P) && PAGING_NONE != translation.PagingMode)
2049  {
2051  }
2052 
2053  *PhysicalAddress = translation.PhysicalAddress;
2054 
2055  return INT_STATUS_SUCCESS;
2056 }
2057 
2058 
2059 __forceinline static INTSTATUS
2061  _In_ QWORD GuestVirtualAddress,
2062  _In_ DWORD Length,
2063  _In_opt_ QWORD Cr3,
2064  _Outptr_result_bytebuffer_(Length) void **HostPtr
2065  )
2080 {
2081  INTSTATUS status;
2082  void *pAlloc, *pAlignedAlloc;
2083  DWORD readSize = 0;
2084  MULTI_PAGE_MAP *pPage;
2085 
2086  pAlloc = HpAllocWithTag((size_t)Length + PAGE_SIZE, IC_TAG_MLMP);
2087  if (NULL == pAlloc)
2088  {
2090  }
2091 
2092  pAlignedAlloc = (void *)ALIGN_UP((SIZE_T)pAlloc, PAGE_SIZE_4K);
2093 
2094  // This will trigger a recursive call, but it's safe since form IntVirtMemRead it will
2095  // only map one page per call, and will not re-enter this function.
2096  status = IntVirtMemRead(GuestVirtualAddress, Length, Cr3, pAlignedAlloc, &readSize);
2097  if (!INT_SUCCESS(status))
2098  {
2100 
2101  return status;
2102  }
2103  else if (readSize != Length)
2104  {
2105  // Something went wrong without an error. IntKernVirtMemRead always returns an error when
2106  // a map fails, so this isn't the case.
2108 
2110  }
2111 
2112  pPage = HpAllocWithTag(sizeof(*pPage), IC_TAG_MLMP);
2113  if (NULL == pPage)
2114  {
2117  }
2118 
2119  pPage->Gva = GuestVirtualAddress;
2120  pPage->Length = Length;
2121  pPage->HostPtr = pAlignedAlloc;
2122  pPage->OrigAlloc = pAlloc;
2123 
2124  InsertTailList(&gMultiPageMaps, &pPage->Link);
2125 
2126  *HostPtr = pAlignedAlloc;
2127 
2128  return INT_STATUS_SUCCESS;
2129 }
2130 
2131 
2133 INTSTATUS
2135  _In_ QWORD Gva,
2136  _In_ DWORD Length,
2137  _In_opt_ QWORD Cr3,
2138  _In_ DWORD Flags,
2139  _Outptr_result_bytebuffer_(Length) void **HostPtr
2140  )
2158 {
2159  INTSTATUS status;
2160  VA_TRANSLATION translation;
2161  DWORD flags;
2162 
2163  UNREFERENCED_PARAMETER(Flags);
2164 
2165  if (0 == Length)
2166  {
2168  }
2169 
2170  if (0 == Cr3)
2171  {
2172  status = IntCr3Read(IG_CURRENT_VCPU, &Cr3);
2173  if (!INT_SUCCESS(status))
2174  {
2175  return status;
2176  }
2177  }
2178 
2179  if (__unlikely(PAGE_COUNT_4K(Gva, Length) > 1))
2180  {
2181  return IntVirtMemMapMultiPage(Gva, Length, Cr3, HostPtr);
2182  }
2183 
2184  status = IntTranslateVirtualAddressEx(Gva, Cr3, TRFLG_NONE, &translation);
2185  if (!INT_SUCCESS(status))
2186  {
2187  return status;
2188  }
2189 
2190  if (0 == (translation.Flags & PT_P) && PAGING_NONE != translation.PagingMode)
2191  {
2193  }
2194 
2195  flags = (translation.PageSize != PAGE_SIZE_4K) ? IG_PHYSMAP_NO_CACHE : 0;
2196 
2197  return IntPhysMemMap(translation.PhysicalAddress, Length, flags, HostPtr);
2198 }
2199 
2200 
2201 static BOOLEAN
2203  _Inout_ _At_(*HostPtr, _Post_null_) void **HostPtr
2204  )
2212 {
2213  list_for_each(gMultiPageMaps, MULTI_PAGE_MAP, pPage)
2214  {
2215  if (__unlikely(pPage->HostPtr == *HostPtr))
2216  {
2217  HpFreeAndNullWithTag(&pPage->OrigAlloc, IC_TAG_MLMP);
2218 
2219  RemoveEntryList(&pPage->Link);
2220 
2222 
2223  *HostPtr = NULL;
2224 
2225  return TRUE;
2226  }
2227  }
2228 
2229  return FALSE;
2230 }
2231 
2232 
2233 INTSTATUS
2235  _Inout_ _At_(*HostPtr, _Post_null_) void **HostPtr
2236  )
2245 {
2246  INTSTATUS status;
2247 
2248  if (__unlikely(IntVirtMemUnmapMultiPage(HostPtr)))
2249  {
2250  return INT_STATUS_SUCCESS;
2251  }
2252 
2253  status = IntPhysMemUnmap(HostPtr);
2254  if (!INT_SUCCESS(status))
2255  {
2256  ERROR("[ERROR] IntPhysMemUnmap failed for (%p %p): 0x%08x\n", HostPtr, *HostPtr, status);
2257  }
2258 
2259  return status;
2260 }
2261 
2262 
2263 INTSTATUS
2265  _In_ BYTE Vector,
2266  _In_ QWORD Cr2,
2267  _In_ DWORD ErrorCode,
2268  _In_ DWORD CpuNumber
2269  )
2287 {
2288  INTSTATUS status;
2289 
2290  if (CpuNumber >= gGuest.CpuCount)
2291  {
2293  }
2294 
2295  if (gGuest.VcpuArray[CpuNumber].Exception.Valid)
2296  {
2297  ERROR("[ERROR] An exception injection is already pending on CPU %d: vector %d, CR2 0x%016llx, "
2298  "error code 0x%08x",
2299  CpuNumber, gGuest.VcpuArray[CpuNumber].Exception.Vector, gGuest.VcpuArray[CpuNumber].Exception.Cr2,
2300  gGuest.VcpuArray[CpuNumber].Exception.ErrorCode);
2302  }
2303 
2304  status = IntInjectTrap(CpuNumber, Vector, ErrorCode, Cr2);
2305  if (!INT_SUCCESS(status))
2306  {
2307  return status;
2308  }
2309 
2310  gGuest.VcpuArray[CpuNumber].Exception.Valid = TRUE;
2311  gGuest.VcpuArray[CpuNumber].Exception.Vector = Vector;
2312  gGuest.VcpuArray[CpuNumber].Exception.Cr2 = Cr2;
2313  gGuest.VcpuArray[CpuNumber].Exception.ErrorCode = ErrorCode;
2314 
2315  return INT_STATUS_SUCCESS;
2316 }
2317 
2318 
2319 INTSTATUS
2321  void
2322  )
2335 {
2336  INTSTATUS status;
2337 
2338  if (gInsideDebugger)
2339  {
2340  return INT_STATUS_SUCCESS;
2341  }
2342 
2343  status = GluePauseVcpus();
2344  if (!INT_SUCCESS(status))
2345  {
2346  ERROR("[ERROR] GluePauseVcpus failed: 0x%08x\n", status);
2348  }
2349 
2350  return status;
2351 }
2352 
2353 
2354 INTSTATUS
2356  void
2357  )
2368 {
2369  INTSTATUS status;
2370 
2371  if (gInsideDebugger)
2372  {
2373  return INT_STATUS_SUCCESS;
2374  }
2375 
2376  status = GlueResumeVcpus();
2377  if (!INT_SUCCESS(status))
2378  {
2379  ERROR("[ERROR] GlueResumeVcpus failed: 0x%08x\n", status);
2381  }
2382 
2383  return status;
2384 }
2385 
2386 
2387 void
2389  _In_ PCHAR File,
2390  _In_ DWORD Line
2391  )
2400 {
2401  if (NULL != File)
2402  {
2403  LOG("[DEBUGGER] IntEnterDebugger called from %s:%d\n", File, Line);
2404  }
2405 
2407 }
2408 
2409 
2410 void
2412  _In_ PCHAR File,
2413  _In_ DWORD Line
2414  )
2423 {
2424  const char *commands[] =
2425  {
2426  "!processes", // Dump the processes
2427  "!stvad",
2428  "!modules_intro", // Dump the introspection drivers
2429  "!modules_guest", // Dump the guest modules
2430  "!hooks_gpa", // Dump the GPA hooks
2431  "!hooks_gva", // Dump the GVA hooks
2432  "!pts_dump", // Dump the PTS tree
2433  "!pfnlocks", // Dump the PFN locks
2434  "!transactions", // Dump the swap-in transactions
2435  "!stats", // Dump the performance stats.
2436  "!icache", // Dump the instruction cache content.
2437  };
2438 
2439  LOG("[CRITICAL] IntDbgEnterDebugger called from %s:%d\n", File, Line);
2440  LOG("Bug check generated! Dumps follow:\n");
2441 
2442  for (DWORD i = 0; i < ARRAYSIZE(commands); i++)
2443  {
2444  IntDbgProcessCommand(1, &commands[i]);
2445  }
2446 
2447  LOG("Bug check dump complete!\n");
2448 
2450 }
2451 
2452 
2453 BOOLEAN
2455  _In_z_ const CHAR *Pattern,
2456  _In_z_ const CHAR *String,
2457  _In_ DWORD Flags
2458  )
2471 {
2472  CHAR pat[255] = {0};
2473 
2474  if (Flags & INTRO_MATCH_TRUNCATED)
2475  {
2476  char *wild = strchr(Pattern, '*');
2477 
2478  if (wild && ((size_t)(wild - Pattern + 1) < sizeof(pat) - 1))
2479  {
2480  memcpy(pat, Pattern, (size_t)(wild - Pattern + 1));
2481 
2482  Pattern = pat;
2483  }
2484  }
2485 
2486  return glob_match_utf8(Pattern, String, TRUE, FALSE);
2487 }
2488 
2489 
2490 BOOLEAN
2492  _In_z_ const WCHAR *Pattern,
2493  _In_z_ const WCHAR *String,
2494  _In_ DWORD Flags
2495  )
2510 {
2511  CHAR pat[255];
2512  CHAR str[255];
2513 
2514  utf16toutf8(pat, Pattern, sizeof(pat));
2515  utf16toutf8(str, String, sizeof(str));
2516 
2517  return IntMatchPatternUtf8(pat, str, Flags);
2518 }
2519 
2520 
2521 INTSTATUS
2523  _In_ void const *Detour
2524  )
2539 {
2540  const char *func;
2541 
2542  UNREFERENCED_PARAMETER(Detour);
2543 
2545  {
2547  }
2548 
2549  func = gGuest.OSType == introGuestWindows ? "KiDisplayBlueScreen" : "panic";
2550 
2551  LOG("[INFO] Guest reached %s handler. Will attempt to uninit!\n", func);
2552 
2553  TRACE("[INFO] Will dump RIPs for all VCPUs\n");
2554  for (DWORD i = 0; i < gGuest.CpuCount; i++)
2555  {
2556  TRACE("[INFO][CPU %d] RIP @ 0x%016llx\n", i, gGuest.VcpuArray[i].Regs.Rip);
2557  }
2558 
2560 
2561  // Need this because, if we uninit on the same exit as this one, we'll end up calling
2562  // IntDetUninit -> we'll remove the jump back for the function and end up making the
2563  // current vcpu execute garbage code.
2565 }
2566 
2567 
2568 BOOLEAN
2570  _In_opt_ const void *Process,
2571  _In_ QWORD Flag
2572  )
2583 {
2584  if (Process == NULL)
2585  {
2586  return FALSE;
2587  }
2588 
2590  {
2591  return IntWinProcPolicyIsBeta(Process, Flag);
2592  }
2593  else if (gGuest.OSType == introGuestLinux)
2594  {
2595  return IntLixProcPolicyIsBeta(Process, Flag);
2596  }
2597 
2598  return FALSE;
2599 }
2600 
2601 
2602 BOOLEAN
2604  _In_ QWORD Flag
2605  )
2616 {
2618  {
2619  return TRUE;
2620  }
2621 
2622  return (gGuest.CoreOptions.Beta & Flag) != 0;
2623 }
2624 
2625 
2626 BOOLEAN
2628  _In_opt_ const void *Process,
2629  _In_ QWORD Flag
2630  )
2641 {
2642  if (Process == NULL)
2643  {
2644  return FALSE;
2645  }
2646 
2648  {
2649  return IntWinProcPolicyIsFeedback(Process, Flag);
2650  }
2651  else if (gGuest.OSType == introGuestLinux)
2652  {
2653  return IntLixProcPolicyIsFeedback(Process, Flag);
2654  }
2655 
2656  return FALSE;
2657 }
2658 
2659 
2660 QWORD
2662  _In_opt_ const void *Process
2663  )
2673 {
2674  if (NULL == Process)
2675  {
2676  return 0;
2677  }
2678 
2680  {
2681  return IntWinProcGetProtOption(Process);
2682  }
2683  else if (gGuest.OSType == introGuestLinux)
2684  {
2685  return IntLixProcGetProtOption(Process);
2686  }
2687 
2688  return 0;
2689 }
2690 
2691 
2692 BOOLEAN
2694  _In_ QWORD Flag,
2695  _Inout_ INTRO_ACTION *Action,
2697  )
2708 {
2709  if (gGuest.CoreOptions.Feedback & Flag)
2710  {
2711  *Action = introGuestAllowed;
2712  *Reason = introReasonAllowedFeedback;
2713 
2714  return TRUE;
2715  }
2716 
2717  if (*Action == introGuestNotAllowed && (IntPolicyCoreIsOptionBeta(Flag)))
2718  {
2719  //
2720  // Don't change the action here, since in the alert we must know the original action & reason. The
2721  // only thing we do, is return a TRUE so the alert gets sent and the ALERT_FLAG_BETA will be set
2722  // inside it.
2723  //
2724  return TRUE;
2725  }
2726 
2727  return *Action == introGuestNotAllowed || *Reason == introReasonAllowedFeedback;
2728 }
2729 
2730 
2731 BOOLEAN
2733  _In_ QWORD Flag,
2734  _In_ void const *Process,
2735  _Inout_ INTRO_ACTION *Action,
2737  )
2751 {
2752  if ((gGuest.CoreOptions.Feedback & IntPolicyGetProcProt(Process)) || IntPolicyProcIsFeedback(Process, Flag))
2753  {
2754  *Action = introGuestAllowed;
2755  *Reason = introReasonAllowedFeedback;
2756 
2757  return TRUE;
2758  }
2759 
2760  if (*Action == introGuestNotAllowed && (IntPolicyProcIsBeta(Process, Flag)))
2761  {
2762  // Don't change the action here, since in the alert we must know the original action & reason. The
2763  // only thing we do, is return a TRUE so the alert gets sent and the ALERT_FLAG_BETA will be set
2764  // inside it.
2765  return TRUE;
2766  }
2767 
2768  return *Action == introGuestNotAllowed || *Reason == introReasonAllowedFeedback;
2769 }
2770 
2771 
2772 BOOLEAN
2774  _In_ QWORD Flag,
2775  _In_ void *Process,
2776  _Inout_ INTRO_ACTION *Action
2777  )
2790 {
2791  if (*Action == introGuestNotAllowed && IntPolicyProcIsBeta(Process, Flag))
2792  {
2793  *Action = introGuestAllowed;
2794 
2795  return TRUE;
2796  }
2797 
2798  return FALSE;
2799 }
2800 
2801 
2802 BOOLEAN
2804  _In_ QWORD Flag,
2805  _Inout_ INTRO_ACTION *Action
2806  )
2816 {
2817  if (*Action == introGuestNotAllowed && (IntPolicyCoreIsOptionBeta(Flag)))
2818  {
2819  *Action = introGuestAllowed;
2820 
2821  return TRUE;
2822  }
2823 
2824  return FALSE;
2825 }
2826 
2827 
2828 BOOLEAN
2830  _In_ QWORD Flag
2831  )
2839 {
2840  return (gGuest.CoreOptions.Feedback & Flag) != 0;
2841 }
2842 
2843 
2844 char *
2846  _In_z_ const WCHAR *WString
2847  )
2861 {
2862  static char gLogBuffer[8][ONE_KILOBYTE];
2863  char *c;
2864 
2865  if (__unlikely(gCurLogBuffer >= ARRAYSIZE(gLogBuffer)))
2866  {
2867  ERROR("[ERROR] gCurLogBuffer = %d/%ld\n", gCurLogBuffer, ARRAYSIZE(gLogBuffer));
2868  return "";
2869  }
2870 
2871  c = utf16toutf8(gLogBuffer[gCurLogBuffer], WString, sizeof(gLogBuffer[0]));
2872 
2873  gCurLogBuffer++;
2874 
2875  return c;
2876 }
2877 
2878 
2879 INTSTATUS
2881  _In_ QWORD StrGva,
2882  _In_ DWORD MinimumLength,
2883  _In_ BOOLEAN AnsiOnly,
2884  _Inout_ char **String,
2885  _Out_opt_ DWORD *StringLength
2886  )
2905 {
2906  INTSTATUS status;
2907  DWORD strLen;
2908  QWORD gva;
2909  BOOLEAN found;
2910  char *str;
2911 
2913  {
2915  }
2917  {
2919  }
2920 
2921  if (0 == MinimumLength || PAGE_SIZE < MinimumLength)
2922  {
2924  }
2925 
2926  str = NULL;
2927 
2928  if (NULL != StringLength)
2929  {
2930  *StringLength = 0;
2931  }
2932 
2933  // In case the string splits in two pages
2934  strLen = 0;
2935  gva = StrGva;
2936  found = FALSE;
2937  do
2938  {
2939  int i = 0;
2940  DWORD remaining = PAGE_REMAINING(gva);
2941  char *p, *pStr;
2942 
2943  status = IntVirtMemMap(gva, remaining, gGuest.Mm.SystemCr3, 0, &pStr);
2944  if (!INT_SUCCESS(status))
2945  {
2946  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with size %x: 0x%08x\n",
2947  gva, remaining, status);
2948  return status;
2949  }
2950 
2951  p = pStr;
2952 
2953  if (AnsiOnly)
2954  {
2955  i = is_str_ansi(p, remaining, MinimumLength);
2956  }
2957  else
2958  {
2959  while ((DWORD)i < remaining && *p)
2960  {
2961  i++;
2962  p++;
2963  }
2964 
2965  if ((DWORD)i < MinimumLength)
2966  {
2967  i = -1;
2968  }
2969  }
2970 
2971  IntVirtMemUnmap(&pStr);
2972 
2973  // this is no string
2974  if (-1 == i)
2975  {
2976  break;
2977  }
2978 
2979  strLen += i;
2980 
2981  // found in this page
2982  if (i < (int)remaining && i > 0)
2983  {
2984  found = TRUE;
2985  break;
2986  }
2987 
2988  // go to the next page (will be aligned from now on)
2989  gva += remaining;
2990  } while ((gva & PAGE_MASK) - (StrGva & PAGE_MASK) == PAGE_SIZE);
2991 
2992  if (!found)
2993  {
2994  return INT_STATUS_NOT_FOUND;
2995  }
2996 
2997  // From now on we include the NULL terminator.
2998  strLen++;
2999 
3000  if (NULL == *String)
3001  {
3002  str = HpAllocWithTag(strLen, IC_TAG_NAME);
3003  if (NULL == str)
3004  {
3006  }
3007  }
3008  else
3009  {
3010  str = *String;
3011  }
3012 
3013  // This is fine, because we check in the beginning that the StrGva is a kernel pointer.
3014  status = IntKernVirtMemRead(StrGva, strLen, str, NULL);
3015  if (!INT_SUCCESS(status))
3016  {
3017  ERROR("[ERROR] IntKernVirtMemRead failed for gva 0x%016llx, length %x: 0x%08x\n", StrGva, strLen, status);
3018  goto _clean_leave;
3019  }
3020 
3021  // We just allocated strLen + 1, so we are guaranteed to have space for the NULL terminator.
3022  str[strLen - 1] = 0;
3023 
3024  *String = str;
3025 
3026  if (NULL != StringLength)
3027  {
3028  *StringLength = strLen;
3029  }
3030 
3031 _clean_leave:
3032  if (!INT_SUCCESS(status))
3033  {
3034  if (NULL != StringLength)
3035  {
3036  *StringLength = 0;
3037  }
3038 
3039  if (NULL != str)
3040  {
3042  }
3043  }
3044 
3045  return status;
3046 }
#define _In_opt_
Definition: intro_sal.h:16
#define INT_STATUS_PAGE_NOT_PRESENT
Indicates that a virtual address is not present.
Definition: introstatus.h:438
#define PT_XD
Definition: pgtable.h:92
QWORD PhysicalAddress
The physical address to which VirtualAddress translates to.
Definition: introcore.h:107
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
#define __unlikely(x)
Definition: common.h:64
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
#define CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
Exposes the types, constants and functions used to handle Windows processes events (creation...
INTSTATUS IntInit(GLUE_IFACE *GlueInterface, UPPER_IFACE const *UpperInterface)
Initializes introcore.
Definition: introcore.c:186
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
Definition: introcore.c:699
static INTSTATUS IntMapGpaForTranslation(QWORD Gpa, void **HostPtr)
Maps a guest physical address used for memory translation in Introcore address space.
Definition: introcore.c:1117
PAGING_MODE PagingMode
The paging mode used for this translation.
Definition: introcore.h:140
char * utf16toutf8(char *Destination, const WCHAR *Source, DWORD DestinationMaxLength)
Definition: introcrt.c:460
static QWORD IntLixProcGetProtOption(const LIX_TASK_OBJECT *Process)
Returns the introcore options related to user mode protection.
Definition: lixprocess.h:124
QWORD Value
The value of the MSR.
Definition: glueiface.h:213
#define ALIGN_UP(x, a)
Definition: introdefs.h:164
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
Definition: introcore.c:2355
INTSTATUS IntReadString(QWORD StrGva, DWORD MinimumLength, BOOLEAN AnsiOnly, char **String, DWORD *StringLength)
Reads a string from the guest kernel memory.
Definition: introcore.c:2880
uint8_t BYTE
Definition: intro_types.h:47
INTSTATUS IntProcessDebugCommand(void *GuestHandle, DWORD CpuNumber, DWORD Argc, CHAR *Argv[])
Executes a debugger command.
Definition: introapi.c:1260
BYTE Vector
The injected exception number.
Definition: guests.h:133
INTSTATUS GluePauseVcpus(void)
Definition: glue.c:481
#define CR0_PG
Definition: processor.h:40
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
#define PDP_P
Definition: pgtable.h:61
INTSTATUS IntVirtMemPatchWordSize(QWORD GuestVirtualAddress, QWORD Cr3, QWORD Data)
Writes a guest pointer inside the guest memory.
Definition: introcore.c:1031
#define _In_
Definition: intro_sal.h:21
INTSTATUS IntIterateVaSpace(void *GuestHandle, QWORD Cr3, PFUNC_VirtualAddressSpaceCallback Callback)
Iterates over the guest virtual address space.
Definition: introapi.c:881
void IntGlueReset(void)
Resets the global glue state (gIface. gUpIface, gIntHandle, gEventId, etc)
Definition: glue.c:77
INTSTATUS GlueResumeVcpus(void)
Definition: glue.c:490
#define CLEAN_PHYS_ADDRESS64(x)
Definition: pgtable.h:119
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
BOOLEAN glob_match_utf8(char const *Pattern, char const *String, BOOLEAN IgnoreCase, BOOLEAN Truncated)
Definition: introcrt.c:609
#define INT_STATUS_REMOVE_DETOUR_AND_SET_RIP
Definition: introstatus.h:426
#define PAGE_REMAINING(addr)
Definition: pgtable.h:163
INTSTATUS IntPhysicalMemRead(QWORD PhysicalAddress, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest physical memory range, but only for a single page.
Definition: introcore.c:721
void IntPreinit(void)
Initializes the global variables used throughout the project.
Definition: introcore.c:166
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
INTSTATUS IntKernVirtMemPatchWordSize(QWORD GuestVirtualAddress, QWORD Data)
Writes a guest pointer inside the guest kernel memory.
Definition: introcore.c:968
#define _Out_writes_bytes_(expr)
Definition: intro_sal.h:38
INTSTATUS IntGetExceptionsVersion(void *GuestHandle, WORD *MajorVersion, WORD *MinorVersion, DWORD *BuildNumber)
Get the current exceptions version.See PFUNC_IntGetExceptionsVersion for details. ...
Definition: introapi.c:1303
#define TRFLG_MODE_MASK
Mask used to isolate only the paging mode flags.
Definition: introcore.h:88
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
INTSTATUS IntVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD Cr3, QWORD *Data)
Reads 8 bytes from the guest memory.
Definition: introcore.c:866
INTSTATUS IntVirtMemFetchString(QWORD Gva, DWORD MaxLength, QWORD Cr3, void *Buffer)
Reads a NULL-terminated string from the guest.
Definition: introcore.c:1053
INTSTATUS IntGetSupportVersion(void *GuestHandle, DWORD *MajorVersion, DWORD *MinorVersion, DWORD *BuildNumber)
Get the current version of CAMI.
Definition: introapi.c:1212
BOOLEAN Initialized
True if this structure was initialized and can be used.
Definition: guests.h:289
QWORD Feedback
Options that will be forced to feedback only mode.
Definition: guests.h:255
Interface that exposes basic services to the introspection engines.
Definition: upperiface.h:262
static BOOLEAN IntLixProcPolicyIsFeedback(const LIX_TASK_OBJECT *Process, QWORD Flag)
Verifies whether a specific process protection flag is in feedback only mode or not for a Linux proce...
Definition: lixprocess.h:161
void IntEnterDebugger2(PCHAR File, DWORD Line)
Traps to a debugger.
Definition: introcore.c:2388
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
INTSTATUS IntGetGuestInfo(void *GuestHandle, GUEST_INFO *GuestInfo)
Get a description of the introspected guest.
Definition: introapi.c:930
#define PT_PCD
Definition: pgtable.h:87
static BOOLEAN IntWinProcPolicyIsFeedback(const WIN_PROCESS_OBJECT *Process, QWORD Flag)
Checks if the given process is protected with the provided flag (in feedback mode).
Definition: winprocess.h:411
#define PD_INDEX(a)
Definition: pgtable.h:97
#define PT32_INDEX(a)
Definition: pgtable.h:108
uint32_t UINT32
Definition: intro_types.h:39
#define ARRAYSIZE(A)
Definition: introdefs.h:101
BOOLEAN KernelBetaDetections
True if the kernel protection is in beta (log-only) mode.
Definition: guests.h:303
#define PT_US
Definition: pgtable.h:85
INTSTATUS IntAddExceptionFromAlert(void *GuestHandle, const void *Event, INTRO_EVENT_TYPE Type, BOOLEAN Exception, QWORD Context)
Adds an exception for an alert reported by introcore.See PFUNC_IntAddExceptionFromAlert for details...
Definition: introapi.c:1402
QWORD IntPolicyGetProcProt(const void *Process)
Gets the protection policy for a process.
Definition: introcore.c:2661
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
Definition: introcore.c:2134
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
#define PAGE_COUNT_4K(addr, bytes)
Definition: pgtable.h:174
#define _Outptr_
Definition: intro_sal.h:19
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
int INTSTATUS
The status data type.
Definition: introstatus.h:24
INTSTATUS IntDisableIntro(void *GuestHandle, QWORD Flags)
Disables and unloads the introspection engine.
Definition: introapi.c:176
BOOLEAN IntPolicyIsCoreOptionFeedback(QWORD Flag)
Checks if a core protection option is in feedback-only mode.
Definition: introcore.c:2829
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
INTSTATUS IntQueryGuestInfo(DWORD InfoClass, void *InfoParam, void *Buffer, DWORD BufferLength)
Definition: glue.c:226
INTSTATUS IntTranslateVirtualAddressEx(QWORD Gva, QWORD Cr3, DWORD Flags, VA_TRANSLATION *Translation)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1863
#define PAGE_COUNT(addr, bytes)
Definition: pgtable.h:189
#define ONE_KILOBYTE
Definition: introdefs.h:89
#define TRFLG_NONE
No special options.
Definition: introcore.h:82
INTSTATUS IntUpdateSupport(void *GuestHandle, PBYTE Buffer, DWORD Length)
Loads a new CAMI version.
Definition: introapi.c:1128
#define IG_IA32_PAT
Definition: glueiface.h:142
PVCPU_STATE VcpuArray
Array of the VCPUs assigned to this guest. The index in this array matches the VCPU number...
Definition: guests.h:372
PFUNC_IntEnterDebugger GlueEnterDebugger
The API used to break into the debugger.
Definition: glue.c:74
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
static INTSTATUS IntTranslateVa64(UINT64 Gva, UINT64 Cr3, VA_TRANSLATION *Translation)
Translates a guest virtual address when 4-level paging is used.
Definition: introcore.c:1452
INTSTATUS IntKernVirtMemPatchQword(QWORD GuestVirtualAddress, QWORD Data)
Writes 8 bytes in the guest kernel memory.
Definition: introcore.c:932
void * gIntHandle
The guest handle provided by the integrator at initialization.
Definition: glue.c:49
#define MIN(a, b)
Definition: introdefs.h:146
struct _MULTI_PAGE_MAP * PMULTI_PAGE_MAP
Interface used for communicating between the introspection engine and the integrator.
Definition: glueiface.h:2078
#define PML4_INDEX(a)
Definition: pgtable.h:95
WORD Build
Build number.
Definition: intro_types.h:2401
char * utf16_for_log(const WCHAR *WString)
Converts a UTF-16 to a UTF-8 string to be used inside logging macros.
Definition: introcore.c:2845
#define INTRO_MATCH_TRUNCATED
If set, matching functions like IntMatchPatternUtf8 will match up until the first wild char encounter...
Definition: introcore.h:13
LIST_ENTRY Link
Entry inside the gMultiPageMaps list.
Definition: introcore.c:48
#define PDPAE_INDEX(a)
Definition: pgtable.h:103
#define LOG(fmt,...)
Definition: glue.h:61
#define PAGE_SIZE_4M
Definition: pgtable.h:20
INTSTATUS IntSpinLockUnInit(void **SpinLock)
Definition: glue.c:823
QWORD Beta
Options that were forced to beta (log-only) mode.
Definition: guests.h:248
#define IC_TAG_MLMP
Multi-page mappings.
Definition: memtags.h:80
BOOLEAN gSse42Supported
Set to True if support for SSE 4.2 was detected.
Definition: crc32.c:99
INTSTATUS IntAddRemoveProtectedProcessUtf8(void *GuestHandle, const CHAR *FullPath, DWORD ProtectionMask, BOOLEAN Add, QWORD Context)
Toggles protection options for a process.
Definition: introapi.c:299
BOOLEAN IntPolicyProcForceBetaIfNeeded(QWORD Flag, void *Process, INTRO_ACTION *Action)
Checks if a forced action should be taken even if the process log-only mode is active.
Definition: introcore.c:2773
The MSR query structure.
Definition: glueiface.h:210
INTSTATUS IntUninit(void)
Disables and uninitializes Introcore.
Definition: introcore.c:266
INTSTATUS IntSetLogLevel(void *GuestHandle, IG_LOG_LEVEL LogLevel)
Sets the log level.
Definition: introapi.c:1571
INTSTATUS IntGuestUninitOnBugcheck(void const *Detour)
Prepares Introcore unload in case of a guest crash in order to clean up the code and data injected in...
Definition: introcore.c:2522
Holds information about page mappings that contain multiple pages.
Definition: introcore.c:46
static BOOLEAN IntWinProcPolicyIsBeta(const WIN_PROCESS_OBJECT *Process, QWORD Flag)
Checks if the given process is protected with the provided flag (in beta mode).
Definition: winprocess.h:391
INTSTATUS IntVirtMemPatchDword(QWORD GuestVirtualAddress, QWORD Cr3, DWORD Data)
Writes 4 bytes in the guest memory.
Definition: introcore.c:1010
INTSTATUS IntGpaCacheRelease(PGPA_CACHE Cache, QWORD Gpa)
Release a previously used cached entry.
Definition: gpacache.c:678
#define PT_RW
Definition: pgtable.h:84
No paging.
Definition: introcore.h:68
#define POLICY_KM_BETA_FLAGS
Aggregates all the flags that are affected by the INTRO_OPT_ENABLE_KM_BETA_DETECTIONS flag...
Definition: intro_types.h:650
const INT_VERSION_INFO IntHviVersion
The version of the introcore library.
Definition: introcore.c:27
#define _Inout_
Definition: intro_sal.h:20
int is_str_ansi(const char *Buffer, size_t MaxBufferSize, size_t MinSize)
Definition: introcrt.c:527
INTSTATUS IntNotifyGuestPowerStateChange(void *GuestHandle, IG_GUEST_POWER_STATE PowerState)
Handles guest power state transitions.
Definition: introapi.c:231
INTSTATUS IntInjectExceptionInGuest(BYTE Vector, QWORD Cr2, DWORD ErrorCode, DWORD CpuNumber)
Injects an exception inside the guest.
Definition: introcore.c:2264
INTSTATUS IntUpdateExceptions(void *GuestHandle, PBYTE Buffer, DWORD Length, DWORD Flags)
Loads a new exceptions version.See PFUNC_IntUpdateExceptions for details.
Definition: introapi.c:1352
static QWORD IntWinProcGetProtOption(const WIN_PROCESS_OBJECT *Process)
Get the protection type for the given process.
Definition: winprocess.h:375
5-level paging
Definition: introcore.h:72
INTSTATUS IntRemoveException(void *GuestHandle, QWORD Context)
Removes a custom exception added with GLUE_IFACE.AddExceptionFromAlert.See PFUNC_IntRemoveException f...
Definition: introapi.c:1452
QWORD Flags
The entry that maps VirtualAddress to PhysicalAddress, together with all the control bits...
Definition: introcore.h:119
#define CLEAN_PHYS_ADDRESS32PAE_ROOT(x)
Definition: pgtable.h:140
#define _Out_opt_
Definition: intro_sal.h:30
#define PDP_INDEX(a)
Definition: pgtable.h:96
BOOLEAN gAbortLoad
Set to True if introcore should abort the initialization process.
Definition: introcore.c:59
#define _Inout_updates_bytes_(expr)
Definition: intro_sal.h:33
The context of an error state.
Definition: intro_types.h:2415
INTSTATUS IntRemoveAllProtectedProcesses(void *GuestHandle)
Removes the protection policies for all processes.
Definition: introapi.c:522
#define INT_STATUS_ALREADY_INITIALIZED
Definition: introstatus.h:263
#define IS_KERNEL_POINTER_LIX(p)
Definition: lixguest.h:11
#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
INTSTATUS IntVirtMemFetchDword(QWORD GuestVirtualAddress, QWORD Cr3, DWORD *Data)
Reads 4 bytes from the guest memory.
Definition: introcore.c:887
INTSTATUS IntTranslateVirtualAddress(QWORD Gva, QWORD Cr3, QWORD *PhysicalAddress)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1999
#define IG_DISABLE_IGNORE_SAFENESS
Definition: glueiface.h:365
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
static INTSTATUS IntTranslateVa32Pae(UINT64 Gva, UINT64 Cr3, VA_TRANSLATION *Translation)
Translates a guest virtual address when 32-bit PAE paging is used.
Definition: introcore.c:1295
#define memzero(a, s)
Definition: introcrt.h:35
#define PT_P
Definition: pgtable.h:83
BOOLEAN IntPolicyProcIsBeta(const void *Process, QWORD Flag)
Checks if a process protection policy is in log-only mode.
Definition: introcore.c:2569
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
QWORD Current
The currently used options.
Definition: guests.h:236
#define CLEAN_PHYS_ADDRESS32PAE(x)
Definition: pgtable.h:133
INTSTATUS IntGetCurrentIntroOptions(void *GuestHandle, QWORD *IntroOptions)
Get the currently used introcore options.
Definition: introapi.c:1077
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
Definition: introcore.c:811
INTSTATUS IntFlushAlertExceptions(void *GuestHandle)
Removes all the custom exceptions added with GLUE_IFACE.AddExceptionFromAlert.See PFUNC_IntFlushAlert...
Definition: introapi.c:1499
BOOLEAN gInsideDebugger
Set to True when introcore is inside a debugger.
Definition: debugger.c:28
static INTSTATUS IntTranslateVa32(UINT32 Gva, UINT32 Cr3, VA_TRANSLATION *Translation)
Translates a guest virtual address when 32-bit paging is used.
Definition: introcore.c:1175
INTSTATUS IntVirtMemWrite(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer)
Writes data to a guest virtual memory range.
Definition: introcore.c:652
static BOOLEAN IntLixProcPolicyIsBeta(const LIX_TASK_OBJECT *Process, QWORD Flag)
Verifies whether a specific process protection flag is in beta mode or not for a Linux process...
Definition: lixprocess.h:141
void * GpaCache
The currently used GPA cache.
Definition: guests.h:403
#define TRUE
Definition: intro_types.h:30
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
#define IS_KERNEL_POINTER_WIN(is64, p)
Checks if a guest virtual address resides inside the Windows kernel address space.
Definition: wddefs.h:76
#define __must_check
Definition: introtypes.h:48
DWORD gCurLogBuffer
Used for utf16_for_log to support calling that function 8 times in a single macro.
Definition: glue.c:58
DWORD MsrId
The ID of the MSR, as defined by Intel.
Definition: glueiface.h:212
const QWORD gByteMaskToBitMask[256]
Converts a byte number to a mask having the bits in those bytes set.
Definition: introcore.c:73
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
#define TRACE(fmt,...)
Definition: glue.h:58
#define PML5_INDEX(a)
Definition: pgtable.h:94
INTSTATUS IntInjectProcessAgentInGuest(void *GuestHandle, DWORD AgentTag, PBYTE AgentContent, DWORD AgentSize, const CHAR *Name, const CHAR *Args)
Requests a process agent injection inside the guest.
Definition: introapi.c:585
#define INT_STATUS_INVALID_INTERNAL_STATE
Definition: introstatus.h:272
#define TRFLG_4_LEVEL_MODE
Hint that the paging mode is PAGING_4_LEVEL_MODE.
Definition: introcore.h:86
INTSTATUS IntDbgProcessCommand(DWORD Argc, const char *Argv[])
Definition: debugger.c:2857
BOOLEAN IntPolicyCoreForceBetaIfNeeded(QWORD Flag, INTRO_ACTION *Action)
Checks if a forced action should be taken even if the log-only mode is active.
Definition: introcore.c:2803
static INTSTATUS IntPhysMemReadWrite(QWORD PhysicalAddress, DWORD Length, void *Buffer, DWORD *RetLength, BOOLEAN Write)
Transfers memory between a guest physical memory range and Introcore, but only for a single memory pa...
Definition: introcore.c:548
#define TRFLG_PAE_MODE
Hint that the paging mode is PAGING_PAE_MODE.
Definition: introcore.h:85
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
Definition: guests.h:367
INTSTATUS IntKernVirtMemPatchDword(QWORD GuestVirtualAddress, DWORD Data)
Writes 4 bytes in the guest kernel memory.
Definition: introcore.c:950
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
32-bit paging with PAE
Definition: introcore.h:70
BOOLEAN IntPolicyCoreTakeAction(QWORD Flag, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Returns the action that should be taken for a core introspection option.
Definition: introcore.c:2693
QWORD Cr2
The Cr2. Valid only if Vector is 14 (Page Fault)
Definition: guests.h:135
char * PCHAR
Definition: intro_types.h:56
struct _INT_VERSION_INFO::@339 VersionInfo
Structured version information.
#define _Outptr_result_bytebuffer_(expr)
Definition: intro_sal.h:24
INTSTATUS IntPhysicalMemWrite(QWORD PhysicalAddress, DWORD Length, void *Buffer)
Writes data to a guest physical memory range, but only for a single page.
Definition: introcore.c:744
QWORD Gva
Guest virtual address to map.
Definition: introcore.c:51
INTSTATUS IntSpinLockInit(void **SpinLock, char *Name)
Definition: glue.c:813
unsigned long long UINT64
Definition: intro_types.h:40
4-level paging
Definition: introcore.h:71
DWORD CpuCount
The number of logical CPUs.
Definition: guests.h:279
#define PAGE_SIZE
Definition: common.h:70
LIST_HEAD gMultiPageMaps
List of all the currently valid multi page maps.
Definition: introcore.c:56
INTSTATUS IntGetCurrentInstructionLength(void *GuestHandle, DWORD CpuNumber, BYTE *Length)
Returns the length of the instruction at which the current guest RIP points.
Definition: introapi.c:729
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
INTSTATUS IntVirtMemFetchWordSize(QWORD GuestVirtualAddress, QWORD Cr3, void *Data)
Reads a guest pointer from the guest memory.
Definition: introcore.c:908
INTSTATUS IntVirtMemPatchQword(QWORD GuestVirtualAddress, QWORD Cr3, QWORD Data)
Writes 8 bytes in the guest memory.
Definition: introcore.c:989
#define PT_INDEX(a)
Definition: pgtable.h:98
INTSTATUS IntGetCurrentInstructionMnemonic(void *GuestHandle, DWORD CpuNumber, CHAR *Mnemonic)
Returns the mnemonic of the instruction at which the current guest RIP points.
Definition: introapi.c:806
#define __forceinline
Definition: introtypes.h:61
void * HostPtr
The virtual address to which Gva was mapped. Page aligned.
Definition: introcore.c:49
uint16_t WCHAR
Definition: intro_types.h:63
uint32_t DWORD
Definition: intro_types.h:49
static void __cpuid(int32_t info[4], int32_t level)
Definition: intrinsics.h:263
#define CLEAN_PHYS_ADDRESS32(x)
Definition: pgtable.h:126
BOOLEAN IntPolicyCoreIsOptionBeta(QWORD Flag)
Checks if one of the kernel protection options is in log-only mode.
Definition: introcore.c:2603
enum _INTRO_ACTION INTRO_ACTION
Event actions.
#define _At_(expr, arg)
Definition: intro_sal.h:23
#define IG_PHYSMAP_NO_CACHE
Signals that a physical mapping request should bypass any existing caches.
Definition: glueiface.h:368
#define _In_reads_bytes_(expr)
Definition: intro_sal.h:25
INTSTATUS IntInjectFileAgentInGuest(void *GuestHandle, PBYTE AgentContent, DWORD AgentSize, const CHAR *Name)
Drops a file on the guest hard disk.
Definition: introapi.c:658
#define PAGE_SIZE_2M
Definition: pgtable.h:15
#define PDPPAE_INDEX(a)
Definition: pgtable.h:102
#define IC_TAG_NAME
Object name.
Definition: memtags.h:56
struct _MULTI_PAGE_MAP MULTI_PAGE_MAP
Holds information about page mappings that contain multiple pages.
The action was allowed, but it has the BETA flag (Introcore is in log-only mode). ...
Definition: intro_types.h:185
#define TRFLG_5_LEVEL_MODE
Hint that the paging mode is PAGING_5_LEVEL_MODE.
Definition: introcore.h:87
#define IntDbgEnterDebugger()
Definition: introcore.h:381
INTSTATUS IntModifyDynamicOptions(void *GuestHandle, QWORD NewOptions)
Modifies the introcore options.
Definition: introapi.c:980
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
INTSTATUS IntAbortEnableIntro(void *GuestHandle, BOOLEAN Abort)
Abort the introcore loading process.
Definition: introapi.c:1545
#define INTRO_OPT_BUGCHECK_CLEANUP
Enable memory cleanup after an OS crash (Windows).
Definition: intro_types.h:466
INTSTATUS IntVirtMemSet(QWORD VirtualAddress, DWORD Length, QWORD Cr3, BYTE Value)
Definition: introcore.c:414
INTSTATUS IntAddRemoveProtectedProcessUtf16(void *GuestHandle, const WCHAR *FullPath, DWORD ProtectionMask, BOOLEAN Add, QWORD Context)
Toggles protection options for a process.
Definition: introapi.c:435
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
#define _In_z_
Definition: intro_sal.h:17
BOOLEAN IntPolicyProcIsFeedback(const void *Process, QWORD Flag)
Checks if a process protection policy is in feedback-only mode.
Definition: introcore.c:2627
static INTSTATUS IntPhysMemReadWriteAnySize(QWORD PhysicalAddress, DWORD Length, void *Buffer, DWORD *RetLength, BOOLEAN Write)
Transfers memory between a guest physical memory range and Introcore.
Definition: introcore.c:462
BOOLEAN IntPolicyProcTakeAction(QWORD Flag, void const *Process, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Returns the action that should be taken for a process protection option.
Definition: introcore.c:2732
#define _When_(expr, arg)
Definition: intro_sal.h:26
DWORD ErrorCode
The error code, for exceptions that have an error code.
Definition: guests.h:134
#define PT_PAT
Definition: pgtable.h:90
#define PTPAE_INDEX(a)
Definition: pgtable.h:104
Introspection version info.
Definition: intro_types.h:2396
QWORD PageSize
The page size used for this translation.
Definition: introcore.h:121
struct _VCPU_STATE::@80 Exception
The exception to be injected in guest.
#define PAGE_SIZE_1G
Definition: pgtable.h:25
INTSTATUS IntPhysicalMemWriteAnySize(QWORD PhysicalAddress, DWORD Length, void *Buffer)
Writes data to a guest physical memory range, regardless of how many pages it spans across...
Definition: introcore.c:789
INTSTATUS IntInjectTrap(DWORD CpuNumber, BYTE TrapNumber, DWORD ErrorCode, QWORD Cr2)
Definition: glue.c:1030
INTSTATUS IntGpaCacheFindAndAdd(PGPA_CACHE Cache, QWORD Gpa, void **Hva)
Search for an entry in the GPA cache, and add it, if it wasn&#39;t found.
Definition: gpacache.c:451
INTSTATUS IntNewGuestNotification(void *GuestHandle, QWORD Options, PBYTE UpdateBuffer, DWORD BufferLength)
Handles a new guest. It is essentially the Introcore entry point.
Definition: introapi.c:81
#define INT_STATUS_NO_MAPPING_STRUCTURES
Indicates that not all mapping structures of a virtual address are present.
Definition: introstatus.h:434
PAGING_MODE Mode
The paging mode used by the guest.
Definition: guests.h:221
#define PD32_INDEX(a)
Definition: pgtable.h:107
INTSTATUS IntCr3Read(DWORD CpuNumber, QWORD *Cr3Value)
Reads the value of the guest CR3.
Definition: introcpu.c:415
#define LIST_HEAD_INIT(Name)
Definition: introlists.h:39
DWORD Length
The size to map.
Definition: introcore.c:52
#define _Out_writes_z_(expr)
Definition: intro_sal.h:37
__must_check INTSTATUS IntPhysMemMap(QWORD PhysAddress, DWORD Length, DWORD Flags, void **HostPtr)
Maps a guest physical address inside Introcore VA space.
Definition: glue.c:338
INTSTATUS IntPhysicalMemReadAnySize(QWORD PhysicalAddress, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest physical memory range, regardless of how many pages it spans across...
Definition: introcore.c:764
#define PD_PS
Definition: pgtable.h:78
Encapsulates information about a virtual to physical memory translation.
Definition: introcore.h:102
#define __likely(x)
Definition: common.h:63
BOOLEAN Valid
True if the fields are valid; False if they are not.
Definition: guests.h:132
Unknown memory type.
Definition: glueiface.h:165
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
static INTSTATUS IntVirtMemMapMultiPage(QWORD GuestVirtualAddress, DWORD Length, QWORD Cr3, void **HostPtr)
Maps a guest kernel virtual memory range inside Introcore virtual address space regardless of the num...
Definition: introcore.c:2060
INTRO_ERROR_CONTEXT gErrorContext
Global storage for the error context used by GLUE_IFACE.NotifyIntrospectionErrorState.
Definition: introcore.c:43
static INTSTATUS IntUnmapGpaForTranslation(QWORD Gpa, void **HostPtr)
Unmaps an address that was previously mapped with IntMapGpaForTranslation.
Definition: introcore.c:1148
#define PD_P
Definition: pgtable.h:71
static BOOLEAN IntVirtMemUnmapMultiPage(void **HostPtr)
Unamps a memory range previously mapped with IntVirtMemMapMultiPage.
Definition: introcore.c:2202
32-bit paging
Definition: introcore.h:69
#define PT_PWT
Definition: pgtable.h:86
BOOLEAN BugCheckInProgress
Definition: guests.h:333
#define TRFLG_CACHING_ATTR
Obtain caching information from the guest&#39;s IA32_PAT MSR.
Definition: introcore.h:83
#define PDP_PS
Definition: pgtable.h:67
INTSTATUS IntVirtMemRead(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer, DWORD *RetLength)
Reads data from a guest virtual memory range.
Definition: introcore.c:627
Get the value of a MSR for a VCPU. Buffer points to a IG_QUERY_MSR structure.
Definition: glueiface.h:226
char CHAR
Definition: intro_types.h:56
unsigned long long * PQWORD
Definition: intro_types.h:53
static INTSTATUS IntVirtMemReadWrite(QWORD VirtualAddress, DWORD Length, QWORD Cr3, void *Buffer, DWORD *RetLength, BOOLEAN Write)
Transfers memory between a guest virtual memory range and Introcore.
Definition: introcore.c:315
#define list_for_each(_head, _struct_type, _var)
Definition: introlists.h:41
INTSTATUS IntFlushGpaCache(void *GuestHandle)
Flushed the introcore GPA cache.
Definition: introapi.c:1026
INTSTATUS IntKernVirtMemFetchWordSize(QWORD GuestVirtualAddress, void *Data)
Reads a guest pointer from the guest kernel memory.
Definition: introcore.c:847
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
Definition: introcore.c:829
void IntDbgEnterDebugger2(PCHAR File, DWORD Line)
Traps to a debugger and dumps the Introcore state.
Definition: introcore.c:2411
INTSTATUS IntPhysMemUnmap(void **HostPtr)
Unmaps an address previously mapped with IntPhysMemMap.
Definition: glue.c:396
#define PAGE_MASK
Definition: pgtable.h:35
#define PAGE_SIZE_4K
Definition: pgtable.h:10
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:271
INTSTATUS IntGlueInit(GLUE_IFACE const *GlueInterface, UPPER_IFACE const *UpperInterface)
Initializes the instances of GLUE_IFACE and UPPER_IFACE that will be used.
Definition: glue.c:101
#define TRFLG_NORMAL_MODE
Hint that the paging mode is PAGING_NORMAL_MODE.
Definition: introcore.h:84
BOOLEAN IntMatchPatternUtf8(const CHAR *Pattern, const CHAR *String, DWORD Flags)
Matches a pattern using glob match.
Definition: introcore.c:2454
INTSTATUS IntGetVersionString(DWORD FullStringSize, DWORD VersionStringSize, CHAR *FullString, CHAR *VersionString)
Get the version string information for the current guest.
Definition: introapi.c:1599
BOOLEAN IntMatchPatternUtf16(const WCHAR *Pattern, const WCHAR *String, DWORD Flags)
Matches a pattern using glob match.
Definition: introcore.c:2491
void * OrigAlloc
The original allocation, which may bot be page aligned.
Definition: introcore.c:50
static INTSTATUS IntTranslateVa64La57(UINT64 Gva, UINT64 Cr3, VA_TRANSLATION *Translation)
Translates a guest virtual address when 5-level paging is used.
Definition: introcore.c:1646
static BOOLEAN IsSse42Supported(void)
Checks if support for SSE 4.2 is present.
Definition: introcore.c:143
size_t SIZE_T
Definition: intro_types.h:60
#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
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
Definition: introcore.c:2320
void * gLock
A lock that ensures that all the events are serialized inside introcore.
Definition: introcore.c:24