Bitdefender Hypervisor Memory Introspection
exceptions.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
9 
10 #include "exceptions.h"
11 #include "codeblocks.h"
12 #include "crc32.h"
13 #include "decoder.h"
14 #include "hook.h"
15 #include "winpe.h"
16 #include "winthread.h"
17 #include "lixmm.h"
18 #include "serializers.h"
19 
23 static QWORD gUsedRips[255] = {0};
24 
26 
34 static BYTE *gValueBuffer = NULL;
35 
38 
41 
45 typedef struct _CB_CACHE
46 {
52 
54 
56 
69 
71 #define CB_CACHE_FLG_RETURN 0x1
72 #define CB_CACHE_FLG_ORIGINAL 0x2
74 
75 
76 void
78  _In_ QWORD Gva
79  )
88 {
89  if (IN_RANGE_LEN(gCodeBlocksOriginalCache.Rip, Gva & PAGE_MASK, PAGE_SIZE))
90  {
91  memzero(&gCodeBlocksOriginalCache, sizeof(gCodeBlocksOriginalCache));
92  }
93 
94  if (IN_RANGE_LEN(gCodeBlocksReturnCache.Rip, Gva & PAGE_MASK, PAGE_SIZE))
95  {
96  memzero(&gCodeBlocksReturnCache, sizeof(gCodeBlocksReturnCache));
97  }
98 }
99 
100 
101 void
103  _In_ QWORD Cr3
104  )
113 {
114  if (gCodeBlocksOriginalCache.Cr3 == Cr3)
115  {
116  memzero(&gCodeBlocksOriginalCache, sizeof(gCodeBlocksOriginalCache));
117  }
118 
119  if (gCodeBlocksReturnCache.Cr3 == Cr3)
120  {
121  memzero(&gCodeBlocksReturnCache, sizeof(gCodeBlocksReturnCache));
122  }
123 }
124 
125 
126 __nonnull() static DWORD
128  _In_ const BYTE *Buffer,
129  _In_ DWORD Length,
130  _In_ const SIG_VALUE_CODE *Sig,
131  _In_ DWORD IndexPattern
132  )
144 {
145  DWORD ret = SIG_NOT_FOUND;
146  BOOLEAN matched = TRUE;
147 
148  if (IndexPattern + Length > Sig->Length)
149  {
150  return SIG_NOT_FOUND;
151  }
152 
153  for (DWORD i = 0; i < Length; i++)
154  {
155  if (Sig->Object[i + IndexPattern] != 0x100 &&
156  Sig->Object[i + IndexPattern] != Buffer[i])
157  {
158  matched = FALSE;
159  break;
160  }
161  }
162 
163  if (matched)
164  {
165  ret = SIG_FOUND;
166  }
167 
168  return ret;
169 }
170 
171 
172 static void
174  _In_ LIST_HEAD *ListHead
175  )
181 {
182  LIST_ENTRY *list = ListHead->Flink;
183  while (list != ListHead)
184  {
185  KM_EXCEPTION *pException = CONTAINING_RECORD(list, KM_EXCEPTION, Link);
186  list = list->Flink;
187 
188  IntExceptErase(pException, IC_TAG_EXKM);
189  }
190 }
191 
192 
193 static void
195  _In_ LIST_HEAD *ListHead
196  )
202 {
203  LIST_ENTRY *list = ListHead->Flink;
204  while (list != ListHead)
205  {
206  KUM_EXCEPTION *pException = CONTAINING_RECORD(list, KUM_EXCEPTION, Link);
207  list = list->Flink;
208 
209  IntExceptErase(pException, IC_TAG_EXKU);
210  }
211 }
212 
213 
214 static void
216  _In_ LIST_HEAD *ListHead
217  )
223 {
224  LIST_ENTRY *list = ListHead->Flink;
225  while (list != ListHead)
226  {
227  UM_EXCEPTION *pException = CONTAINING_RECORD(list, UM_EXCEPTION, Link);
228  list = list->Flink;
229 
230  IntExceptErase(pException, IC_TAG_EXUM);
231  }
232 }
233 
234 
235 static void
237  _In_ LIST_HEAD *ListHead
238  )
244 {
245  LIST_ENTRY *list = ListHead->Flink;
246  while (list != ListHead)
247  {
248  UM_EXCEPTION_GLOB *pException = CONTAINING_RECORD(list, UM_EXCEPTION_GLOB, Link);
249  list = list->Flink;
250 
251  IntExceptErase(pException, IC_TAG_EXUM);
252  }
253 }
254 
255 
256 INTSTATUS
258  void
259  )
269 {
270  if (!gGuest.Exceptions)
271  {
273  }
274 
277 
278  for (DWORD i = 0; i < EXCEPTION_TABLE_SIZE; i++)
279  {
281  }
282 
286 
287  for (DWORD i = 0; i < EXCEPTION_TABLE_SIZE; i++)
288  {
290  }
291 
294 
295  for (DWORD i = 0; i < EXCEPTION_TABLE_SIZE; i++)
296  {
298  }
299 
304 
306 
308  {
309  if (!pSignature->AlertSignature)
310  {
311  IntExceptErase(pSignature, IC_TAG_ESIG);
312  }
313  }
314 
316  {
317  if (!pSignature->AlertSignature)
318  {
319  IntExceptErase(pSignature, IC_TAG_ESIG);
320  }
321  }
322 
324  {
325  if (!pSignature->AlertSignature)
326  {
327  IntExceptErase(pSignature, IC_TAG_ESIG);
328  }
329  }
330 
332  {
333  if (!pSignature->AlertSignature)
334  {
335  IntExceptErase(pSignature, IC_TAG_ESIG);
336  }
337  }
338 
340  {
341  if (!pSignature->AlertSignature)
342  {
343  IntExceptErase(pSignature, IC_TAG_ESIG);
344  }
345  }
346 
348  {
349  if (!pSignature->AlertSignature)
350  {
351  IntExceptErase(pSignature, IC_TAG_ESIG);
352  }
353  }
354 
356  {
357  if (!pSignature->AlertSignature)
358  {
359  IntExceptErase(pSignature, IC_TAG_ESIG);
360  }
361  }
362 
364  {
365  if (!pSignature->AlertSignature)
366  {
367  IntExceptErase(pSignature, IC_TAG_ESIG);
368  }
369  }
370 
374 
376 
377  return INT_STATUS_SUCCESS;
378 }
379 
380 
381 INTSTATUS
383  void
384  )
393 {
394  if (!gGuest.Exceptions)
395  {
397  }
398 
403 
405  {
406  if (pSignature->AlertSignature)
407  {
408  IntExceptErase(pSignature, IC_TAG_ESIG);
409  }
410  }
411 
413  {
414  if (pSignature->AlertSignature)
415  {
416  IntExceptErase(pSignature, IC_TAG_ESIG);
417  }
418  }
419 
421  {
422  if (pSignature->AlertSignature)
423  {
424  IntExceptErase(pSignature, IC_TAG_ESIG);
425  }
426  }
427 
429  {
430  if (pSignature->AlertSignature)
431  {
432  IntExceptErase(pSignature, IC_TAG_ESIG);
433  }
434  }
435 
436  return INT_STATUS_SUCCESS;
437 }
438 
439 
440 INTSTATUS
442  void
443  )
452 {
453  EXCEPTIONS *pExceptions = HpAllocWithTag(sizeof(*pExceptions), IC_TAG_EXCP);
454  if (!pExceptions)
455  {
457  }
458 
460  if (!gValueBuffer)
461  {
462  HpFreeAndNullWithTag(&pExceptions, IC_TAG_EXCP);
464  }
465 
469 
473 
474  InitializeListHead(&pExceptions->GlobUserExceptions);
475 
476  for (DWORD i = 0; i < EXCEPTION_TABLE_SIZE; i++)
477  {
478  InitializeListHead(&pExceptions->KernelExceptions[i]);
479  InitializeListHead(&pExceptions->UserExceptions[i]);
480  InitializeListHead(&pExceptions->KernelUserExceptions[i]);
481  }
482 
487 
490 
494 
495  InitializeListHead(&pExceptions->CbSignatures);
496  InitializeListHead(&pExceptions->ExportSignatures);
497  InitializeListHead(&pExceptions->ValueSignatures);
499  InitializeListHead(&pExceptions->IdtSignatures);
503 
504  pExceptions->Loaded = FALSE;
505 
506  gGuest.Exceptions = pExceptions;
507 
508  return INT_STATUS_SUCCESS;
509 }
510 
511 
512 INTSTATUS
514  void
515  )
525 {
526  INTSTATUS status = INT_STATUS_SUCCESS;
527 
528  if (!gGuest.Exceptions)
529  {
531  }
532 
533  status = IntExceptRemove();
534  if (!INT_SUCCESS(status))
535  {
536  return status;
537  }
538 
539  status = IntExceptAlertRemove();
540  if (!INT_SUCCESS(status))
541  {
542  return status;
543  }
544 
546 
547  if (gValueBuffer)
548  {
550  }
551 
552  memzero(&gCodeBlocksOriginalCache, sizeof(gCodeBlocksOriginalCache));
553  memzero(&gCodeBlocksReturnCache, sizeof(gCodeBlocksReturnCache));
554 
555  memzero(gUsedRips, sizeof(gUsedRips));
556 
557  return INT_STATUS_SUCCESS;
558 }
559 
560 
561 static INTSTATUS
563  _In_ KERNEL_DRIVER *Driver,
565  )
577 {
578  INTSTATUS status;
579  IMAGE_DATA_DIRECTORY dir = {0};
580  IMAGE_SECTION_HEADER section;
581 
582  Victim->Object.BaseAddress = Driver->BaseVa;
583  Victim->ProtectionFlag = Driver->ProtectionFlag;
584 
585  if (Driver->BaseVa == gGuest.KernelVa)
586  {
587  Victim->Object.NameHash = kmExcNameKernel;
588  }
589  else if (0 == wstrcasecmp(Driver->Name, u"hal.dll") ||
590  0 == wstrcasecmp(Driver->Name, u"halmacpi.dll") ||
591  0 == wstrcasecmp(Driver->Name, u"halacpi.dll"))
592  {
593  Victim->Object.NameHash = kmExcNameHal;
594  }
595  else
596  {
597  // NOTE: Keep the name hash here (we don't except based on path!)
598  Victim->Object.NameHash = Driver->NameHash;
599  }
600 
601  status = IntPeGetSectionHeaderByRva(Driver->BaseVa,
602  Driver->Win.MzPeHeaders,
603  (DWORD)(Victim->Ept.Gva - Driver->BaseVa),
604  &section);
605  if (!INT_SUCCESS(status))
606  {
607  ERROR("[ERROR] Failed getting the section header of the write address 0x%016llx in module 0x%016llx: 0x%08x\n",
608  Victim->Ept.Gva, Driver->BaseVa, status);
609  TRACE("[EXCEPTIONS] Will continue to check exceptions anyway...\n");
610  }
611  else
612  {
613  memcpy(Victim->Object.Module.SectionName, section.Name, 8);
614 
615  if ((section.Characteristics & IMAGE_SCN_CNT_CODE) ||
617  {
618  Victim->ZoneFlags |= ZONE_LIB_CODE;
619  }
620  else
621  {
622  Victim->ZoneFlags |= ZONE_LIB_DATA;
623  }
624  }
625 
626  // NOTE: If more types are added, be careful where you put the code. When parsing directories, we exit at
627  // the first one found. Hopefully a zone can't be both in the resources section & imports, or in both
628  // imports & exports, etc.
629 
630  status = IntPeGetDirectory(Driver->BaseVa, Driver->Win.MzPeHeaders, IMAGE_DIRECTORY_ENTRY_IAT, &dir);
631  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
632  {
633  ERROR("[ERROR] Failed getting IAT from driver 0x%016llx: 0x%08x\n", Driver->BaseVa, status);
634  }
635  else if (status != INT_STATUS_NOT_FOUND)
636  {
637  if (Victim->Ept.Gva >= Driver->BaseVa + dir.VirtualAddress &&
638  Victim->Ept.Gva < Driver->BaseVa + dir.VirtualAddress + dir.Size)
639  {
640  Victim->ZoneFlags |= ZONE_LIB_IMPORTS;
641  return INT_STATUS_SUCCESS;
642  }
643  }
644 
645  status = IntPeGetDirectory(Driver->BaseVa, Driver->Win.MzPeHeaders, IMAGE_DIRECTORY_ENTRY_EXPORT, &dir);
646  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
647  {
648  ERROR("[ERROR] Failed getting EAT from driver 0x%016llx: 0x%08x\n", Driver->BaseVa, status);
649  }
650  else if (status != INT_STATUS_NOT_FOUND)
651  {
652  if (Victim->Ept.Gva >= Driver->BaseVa + dir.VirtualAddress &&
653  Victim->Ept.Gva < Driver->BaseVa + dir.VirtualAddress + dir.Size)
654  {
655  Victim->ZoneFlags |= ZONE_LIB_EXPORTS;
656  return INT_STATUS_SUCCESS;
657  }
658  }
659 
660  status = IntPeGetDirectory(Driver->BaseVa, Driver->Win.MzPeHeaders, IMAGE_DIRECTORY_ENTRY_RESOURCE, &dir);
661  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
662  {
663  ERROR("[ERROR] Failed getting imports from driver 0x%016llx: 0x%08x\n", Driver->BaseVa, status);
664  }
665  else if (status != INT_STATUS_NOT_FOUND)
666  {
667  if (Victim->Ept.Gva >= Driver->BaseVa + dir.VirtualAddress &&
668  Victim->Ept.Gva < Driver->BaseVa + dir.VirtualAddress + dir.Size)
669  {
670  Victim->ZoneFlags |= ZONE_LIB_RESOURCES;
671  return INT_STATUS_SUCCESS;
672  }
673  }
674 
675  return INT_STATUS_SUCCESS;
676 }
677 
678 
679 static INTSTATUS
681  _In_ KERNEL_DRIVER *Driver,
683  )
694 {
695  QWORD gva = Victim->Ept.Gva;
696 
697  Victim->Object.BaseAddress = Driver->BaseVa;
698  Victim->ProtectionFlag = Driver->ProtectionFlag;
699 
700  if (Victim->Object.BaseAddress == gGuest.KernelVa)
701  {
702  Victim->Object.NameHash = kmExcNameKernel;
703  }
704  else
705  {
706  // Important: Keep the name hash here (we don't except based on path!)
707  Victim->Object.NameHash = Driver->NameHash;
708  }
709 
710  if (IN_RANGE_LEN(gva, Driver->Lix.CoreLayout.Base, Driver->Lix.CoreLayout.TextSize))
711  {
712  memcpy(Victim->Object.Module.SectionName, "text", sizeof("text"));
713  Victim->ZoneFlags |= ZONE_LIB_CODE;
714  }
715  else if (IN_RANGE(gva,
716  Driver->Lix.CoreLayout.Base + Driver->Lix.CoreLayout.TextSize,
717  Driver->Lix.CoreLayout.Base + Driver->Lix.CoreLayout.RoSize))
718  {
719  memcpy(Victim->Object.Module.SectionName, "text_ro", sizeof("text_ro"));
720  Victim->ZoneFlags |= ZONE_LIB_DATA;
721  }
722  else if (!Driver->Lix.Initialized &&
723  IN_RANGE_LEN(gva, Driver->Lix.InitLayout.Base, Driver->Lix.InitLayout.TextSize))
724  {
725  memcpy(Victim->Object.Module.SectionName, "init", sizeof("init"));
726  Victim->ZoneFlags |= ZONE_LIB_CODE;
727  }
728  else if (!Driver->Lix.Initialized &&
729  IN_RANGE(gva,
730  Driver->Lix.InitLayout.Base + Driver->Lix.InitLayout.TextSize,
731  Driver->Lix.InitLayout.Base + Driver->Lix.InitLayout.RoSize))
732  {
733  memcpy(Victim->Object.Module.SectionName, "init_ro", sizeof("init_ro"));
734  Victim->ZoneFlags |= ZONE_LIB_DATA;
735  }
736 
737  return INT_STATUS_SUCCESS;
738 }
739 
740 
741 INTSTATUS
743  _In_opt_ void *Context,
744  _In_ QWORD Gpa,
745  _In_ QWORD Gva,
746  _In_ INTRO_OBJECT_TYPE Type,
747  _In_ DWORD ZoneFlags,
749  )
791 {
792  INTSTATUS status;
793  OPERAND_VALUE operandValue = { 0 };
794 
795  if (ZoneFlags == 0)
796  {
798  }
799 
800  if (Victim == NULL)
801  {
803  }
804 
805  Victim->Ept.Gva = Gva;
806  Victim->Ept.Gpa = Gpa;
807  Victim->ZoneType = exceptionZoneEpt;
808  Victim->ZoneFlags = ZoneFlags;
809 
810  // See if this a SSDT write or a SSDT relocation (first field in KeServiceDescriptorTable),
811  // but only on 32 bit systems
812  if (!gGuest.Guest64 &&
814  ((Victim->Ept.Gva >= gWinGuest->Ssdt &&
815  Victim->Ept.Gva < gWinGuest->Ssdt + gWinGuest->NumberOfServices * 4ull) ||
816  (Victim->Ept.Gva == gWinGuest->KeServiceDescriptorTable)))
817  {
818  Victim->Object.Type = introObjectTypeSsdt;
819  }
820  else
821  {
822  Victim->Object.Type = Type;
823  }
824 
825  switch (Victim->Object.Type)
826  {
827  case introObjectTypeSsdt:
829  {
830  ERROR("[ERROR] Writes of type %d are not supported on guests %d\n",
831  Victim->Object.Type, gGuest.OSType);
833  }
834 
835  Victim->ProtectionFlag = INTRO_OPT_PROT_KM_NT;
836  Victim->Object.Module.Module = Context;
837 
838  // We are on Windows since we verified before
839  IntExceptWinGetVictimDriver(Context, Victim);
840 
841  break;
842 
845  Victim->Object.Module.Module = Context;
846 
848  {
849  IntExceptWinGetVictimDriver(Context, Victim);
850  }
851  else if (gGuest.OSType == introGuestLinux)
852  {
853  IntExceptLixGetVictimDriver(Context, Victim);
854  }
855 
856  break;
857 
860  {
861  ERROR("[ERROR] Writes of type %d are not supported on guests %d\n",
862  Victim->Object.Type, gGuest.OSType);
864  }
865 
866  Victim->Object.DriverObject = Context;
867  Victim->Object.BaseAddress = ((PWIN_DRIVER_OBJECT)Context)->DriverObjectGva;
868  Victim->Object.NameHash = ((PWIN_DRIVER_OBJECT)Context)->NameHash;
869  break;
870 
873  {
874  ERROR("[ERROR] Writes of type %d are not supported on guests %d\n",
875  Victim->Object.Type, gGuest.OSType);
877  }
878 
879  Victim->Object.DriverObject = Context;
880  Victim->Object.BaseAddress = ((WIN_DRIVER_OBJECT *)Context)->DriverObjectGva;
881  Victim->Object.NameHash = ((WIN_DRIVER_OBJECT *)Context)->NameHash;
882 
883  break;
884 
886  {
887  WIN_PROCESS_MODULE *pModule = Context;
888  IMAGE_SECTION_HEADER section;
889 
891  {
892  ERROR("[ERROR] Writes of type %d are not supported on guests %d\n",
893  Victim->Object.Type, gGuest.OSType);
895  }
896 
897  Victim->Object.BaseAddress = pModule->VirtualBase;
898  Victim->Object.Library.Module = Context;
899  Victim->Object.WinProc = pModule->Subsystem->Process;
900 
901  if (pModule->Cache && (pModule->Cache->Info.IatRva != 0) && (pModule->Cache->Info.IatSize != 0) &&
902  (Gva - pModule->VirtualBase >= pModule->Cache->Info.IatRva) &&
903  (Gva - pModule->VirtualBase < (QWORD)pModule->Cache->Info.IatRva + pModule->Cache->Info.IatSize))
904  {
905  Victim->ZoneFlags |= ZONE_LIB_IMPORTS;
906  }
907 
908  if (pModule->Cache && (pModule->Cache->Info.EatRva != 0) && (pModule->Cache->Info.EatSize != 0) &&
909  (Gva - pModule->VirtualBase >= pModule->Cache->Info.EatRva) &&
910  (Gva - pModule->VirtualBase < (QWORD)pModule->Cache->Info.EatRva + pModule->Cache->Info.EatSize))
911  {
912  Victim->ZoneFlags |= ZONE_LIB_EXPORTS;
913  }
914 
915  if (pModule->Cache && pModule->Cache->Headers)
916  {
917  status = IntPeGetSectionHeaderByRva(pModule->VirtualBase, pModule->Cache->Headers,
918  (DWORD)(Victim->Ept.Gva - pModule->VirtualBase), &section);
919  if (INT_SUCCESS(status))
920  {
921  memcpy(Victim->Object.Library.SectionName, section.Name, 8);
922 
923  if ((section.Characteristics & IMAGE_SCN_CNT_CODE) ||
925  {
926  Victim->ZoneFlags |= ZONE_LIB_CODE;
927  }
928  else
929  {
930  Victim->ZoneFlags |= ZONE_LIB_DATA;
931  }
932  }
933  }
934 
935  Victim->Object.NameHash = pModule->Path->NameHash;
936  Victim->Object.NameWide = pModule->Path->Name; // Module names are saved as WCHAR
937 
938  break;
939  }
940 
942  {
943  Victim->Object.BaseAddress = Victim->Ept.Gva; // actual written address
944  Victim->Object.NameHash = kmExcNameHal;
945 
946  break;
947  }
948 
950  {
951  Victim->Object.NameHash = kmExcNameHal;
952 
953  break;
954  }
955 
957  {
958  Victim->Object.BaseAddress = Gva & PAGE_MASK;
959 
960  if (NULL == Context)
961  {
962  break;
963  }
964 
966  {
967  WIN_PROCESS_OBJECT *pProc = (WIN_PROCESS_OBJECT *)Context;
968 
969  Victim->Object.NameHash = pProc->NameHash;
970  Victim->Object.Name = pProc->Name;
971 
972  Victim->Object.Process = pProc;
973  }
974 
975  break;
976  }
977 
979  {
980  Victim->Object.BaseAddress = Gva & PAGE_MASK;
981 
983  {
984  WIN_PROCESS_OBJECT *pProc = (WIN_PROCESS_OBJECT *)Context;
985  QWORD tibBase = 0;
986 
987  Victim->ExecInfo.StackBase = 0;
988  Victim->ExecInfo.StackLimit = 0;
989  Victim->ExecInfo.Rsp = gVcpu->Regs.Rsp;
990  Victim->ExecInfo.Length = gVcpu->Instruction.Length;
991 
992  status = IntWinThrGetCurrentStackBaseAndLimit(&tibBase, &Victim->ExecInfo.StackBase,
993  &Victim->ExecInfo.StackLimit);
994  if (!INT_SUCCESS(status))
995  {
996  WARNING("[WARNING] IntWinThrGetCurrentStackBaseAndLimit failed with status: 0x%08x\n", status);
997  }
998 
999  Victim->Object.NameHash = pProc->NameHash;
1000  Victim->Object.Name = pProc->Name;
1001 
1002  Victim->Object.Process = pProc;
1003  }
1004  else
1005  {
1006  LIX_TASK_OBJECT *pTask = (LIX_TASK_OBJECT *)Context;
1007  LIX_VMA *pVma = IntLixMmFindVmaByRange(pTask, gVcpu->Regs.Rip);
1008  if (pVma == NULL)
1009  {
1010  Victim->ExecInfo.StackBase = 0;
1011  Victim->ExecInfo.StackLimit = 0;
1012 
1013  WARNING("[WARNING] IntLixMmFindVmaByRange failed for GVA 0x%016llx\n", gVcpu->Regs.Rip);
1014  }
1015  else
1016  {
1017  Victim->ExecInfo.StackBase = pVma->Start;
1018  Victim->ExecInfo.StackLimit = pVma->End;
1019  }
1020 
1021  Victim->ExecInfo.Rsp = gVcpu->Regs.Rsp;
1022  Victim->ExecInfo.Length = gVcpu->Instruction.Length;
1023 
1024  Victim->Object.NameHash = pTask->CommHash;
1025 
1026  if (pTask->Path)
1027  {
1028  Victim->Object.Name = pTask->Path->Name;
1029  }
1030  else
1031  {
1032  Victim->Object.Name = pTask->Comm;
1033  }
1034 
1035  Victim->Object.Process = pTask;
1036  }
1037 
1038  break;
1039  }
1040 
1041  case introObjectTypeVdso:
1043  {
1044  if (!IS_KERNEL_POINTER_LIX(Gva))
1045  {
1046  Victim->Object.LixProc = IntLixTaskGetCurrent(gVcpu->Index);
1047  }
1048 
1049  Victim->ZoneFlags |= ZONE_LIB_CODE;
1050  Victim->Object.BaseAddress = Gva & PAGE_MASK;
1051  break;
1052  }
1053 
1054  case introObjectTypeIdt:
1055  {
1056  // We send the real IDT base through the context
1057  Victim->Object.BaseAddress = *(QWORD *)Context;
1058  Victim->Object.Name = "IDT";
1059 
1060  break;
1061  }
1062 
1065  case introObjectTypeAcl:
1067  {
1068  Victim->Object.Process = Context;
1069  Victim->Object.Name = ((WIN_PROCESS_OBJECT *)Context)->Name;
1070  Victim->Object.NameHash = ((WIN_PROCESS_OBJECT *)Context)->NameHash;
1071  Victim->Object.BaseAddress = Gva & PAGE_MASK;
1072 
1073  break;
1074  }
1075 
1077  {
1078  break;
1079  }
1080 
1081  default:
1082  WARNING("[WARNING] Shouldn't reach here (for now). Type is %d (original %d)...\n", Victim->Object.Type, Type);
1083  return INT_STATUS_NOT_SUPPORTED;
1084  }
1085 
1086  if (Victim->Object.Type != introObjectTypeUmGenericNxZone &&
1087  Victim->Object.Type != introObjectTypeHalHeap &&
1088  Victim->Object.Type != introObjectTypeSudExec &&
1089  (Victim->Object.Type != introObjectTypeVeAgent || (Victim->ZoneFlags & ZONE_WRITE) != 0))
1090  {
1091  if (!(ZONE_READ & Victim->ZoneFlags))
1092  {
1093  DWORD writeSize = gVcpu->Instruction.Operands[0].Size;
1094 
1095  if (writeSize > sizeof(Victim->WriteInfo.OldValue) || writeSize == 0)
1096  {
1097  ERROR("[ERROR] Accessed size is too large or 0: 0x%x\n", writeSize);
1098  return INT_STATUS_NOT_SUPPORTED;
1099  }
1100 
1101  status = IntVirtMemRead(Gva, writeSize, 0, Victim->WriteInfo.OldValue, NULL);
1102  if (!INT_SUCCESS(status))
1103  {
1104  WARNING("[WARNING] IntVirtMemRead failed for GVA 0x%016llx: 0x%08x\n", Gva, status);
1105  Victim->WriteInfo.OldValue[0] = 0xbaddead;
1106  }
1107 
1109  &gVcpu->Regs,
1110  NULL,
1111  &operandValue);
1112  if (!INT_SUCCESS(status))
1113  {
1114  WARNING("[WARNING] Failed getting operands for instruction %s: 0x%08x\n",
1115  gVcpu->Instruction.Mnemonic, status);
1117 
1118  Victim->WriteInfo.NewValue[0] = 0xbaddead;
1119  Victim->WriteInfo.AccessSize = gVcpu->AccessSize;
1120  }
1121  else
1122  {
1123  memcpy(Victim->WriteInfo.NewValue, operandValue.Value.QwordValues, operandValue.Size);
1124  Victim->WriteInfo.AccessSize = operandValue.Size;
1125  }
1126  }
1127  else
1128  {
1129  if (gVcpu->AccessSize > sizeof(Victim->ReadInfo.Value) || gVcpu->AccessSize == 0)
1130  {
1131  ERROR("[ERROR] Accessed size is too large or 0: 0x%x\n", gVcpu->AccessSize);
1132  return INT_STATUS_NOT_SUPPORTED;
1133  }
1134 
1135  status = IntKernVirtMemRead(Gva, gVcpu->AccessSize, &Victim->ReadInfo.Value[0], NULL);
1136  if (!INT_SUCCESS(status))
1137  {
1138  Victim->ReadInfo.Value[0] = 0xbaddead;
1139  }
1140 
1141  Victim->ReadInfo.AccessSize = gVcpu->AccessSize;
1142  }
1143  }
1144 
1145  // At this point, override every status possible
1146  return INT_STATUS_SUCCESS;
1147 }
1148 
1149 
1150 static INTSTATUS
1152  _In_ void *Exception,
1153  _In_ void *Originator,
1154  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
1155  _Inout_ DWORD SignatureCount,
1156  _In_ EXCEPTION_TYPE ExceptionType
1157  )
1176 {
1177  INTSTATUS status;
1178 
1179  DWORD lastChecked = 0;
1180 
1181  DWORD startOffset, endOffset, totalSize, csType;
1182  void *pCode = NULL;
1183 
1184  BOOLEAN requires64BitSig = gGuest.Guest64;
1185  BOOLEAN execute = FALSE;
1186  BYTE level = (ExceptionType == exceptionTypeKm || ExceptionType == exceptionTypeKmUm) ? cbLevelNormal : cbLevelMedium;
1187 
1188  QWORD rip, cr3;
1189 
1190  void *pHookObject = NULL;
1191  CB_CACHE *pCodeBlocksCache;
1192  BYTE cacheFlags;
1193 
1194  status = IntGetCurrentMode(IG_CURRENT_VCPU, &csType);
1195  if (!INT_SUCCESS(status))
1196  {
1197  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
1198  return status;
1199  }
1200 
1201  if ((csType != IG_CS_TYPE_32B) && (csType != IG_CS_TYPE_64B))
1202  {
1203  ERROR("[ERROR] Unsupported CS type: %d\n", csType);
1204  return INT_STATUS_NOT_SUPPORTED;
1205  }
1206 
1207  switch (ExceptionType)
1208  {
1209  case exceptionTypeKm:
1210  {
1211  EXCEPTION_KM_ORIGINATOR *pKmOrig = Originator;
1212 
1213  if (((KM_EXCEPTION *)Exception)->Flags & EXCEPTION_KM_FLG_RETURN_DRV)
1214  {
1215  rip = pKmOrig->Return.Rip;
1216  cacheFlags = CB_CACHE_FLG_RETURN;
1217  }
1218  else
1219  {
1220  rip = pKmOrig->Original.Rip;
1221  cacheFlags = CB_CACHE_FLG_ORIGINAL;
1222  }
1223 
1224  cr3 = gGuest.Mm.SystemCr3;
1225 
1226  break;
1227  }
1228 
1229  case exceptionTypeKmUm:
1230  {
1231  EXCEPTION_KM_ORIGINATOR *pKmOrig = Originator;
1232 
1233  if (((KUM_EXCEPTION *)Exception)->Flags & EXCEPTION_KM_FLG_RETURN_DRV)
1234  {
1235  rip = pKmOrig->Return.Rip;
1236  cacheFlags = CB_CACHE_FLG_RETURN;
1237  }
1238  else
1239  {
1240  rip = pKmOrig->Original.Rip;
1241  cacheFlags = CB_CACHE_FLG_ORIGINAL;
1242  }
1243 
1244  cr3 = gGuest.Mm.SystemCr3;
1245 
1246  break;
1247  }
1248 
1249  case exceptionTypeUmGlob:
1250  case exceptionTypeUm:
1251  {
1252  EXCEPTION_UM_ORIGINATOR *pUmOrig = Originator;
1253 
1254  rip = pUmOrig->Rip;
1255  execute = pUmOrig->Execute;
1256  cacheFlags = CB_CACHE_FLG_ORIGINAL;
1257 
1259  {
1260  if (pUmOrig->WinLib != NULL)
1261  {
1262  pHookObject = pUmOrig->WinLib->HookObject;
1263  }
1264 
1265  cr3 = pUmOrig->WinProc->Cr3;
1266 
1267  requires64BitSig = requires64BitSig && !pUmOrig->WinProc->Wow64Process;
1268  }
1269  else if (gGuest.OSType == introGuestLinux)
1270  {
1271  pHookObject = pUmOrig->LixProc->HookObject;
1272  cr3 = pUmOrig->LixProc->Cr3;
1273  }
1274  else
1275  {
1276  return INT_STATUS_NOT_SUPPORTED;
1277  }
1278 
1279  if (cr3 != gVcpu->Regs.Cr3)
1280  {
1281  LOG("[INFO] Special case where process cr3 %llx != VCPU cr3 %llx\n", cr3, gVcpu->Regs.Cr3);
1282  cr3 = gVcpu->Regs.Cr3;
1283 
1284  // Don't use keep a cache for these writes (when should we invalidate it, after all?)
1285  pHookObject = NULL;
1286  }
1287 
1288  break;
1289  }
1290 
1291  default:
1292  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
1293  return INT_STATUS_NOT_SUPPORTED;
1294  }
1295 
1296  // In case we get a invalid RIP, we can't extract any code blocks. This is just a sanity check
1297  // since it shouldn't happen (we always have the current RIP from the VCPU. And if the return rip is 0, then
1298  // an exception with EXCEPTION_KM_FLG_RETURN_DRV won't match).
1299  if (0 == rip)
1300  {
1302  }
1303 
1304  // Make sure the totalSize is 2 * EXCEPTION_CODEBLOCKS_OFFSET, and to remain in the same page. Eg:
1305  // RipOffset = 0xf31 => [0xc00, 0xfff]
1306  // RipOffset = 0x123 => [0x000, 0x3ff]
1307  // RipOffset = 0x523 => [0x323, 0x722]
1308  //
1309  // But for a EXECUTE violation, get from here on.
1310 
1311  startOffset = endOffset = rip & PAGE_OFFSET;
1312 
1313  if (!execute)
1314  {
1315  if (startOffset > EXCEPTION_CODEBLOCKS_OFFSET)
1316  {
1317  if (endOffset + EXCEPTION_CODEBLOCKS_OFFSET < PAGE_SIZE)
1318  {
1319  startOffset -= EXCEPTION_CODEBLOCKS_OFFSET;
1320  endOffset += EXCEPTION_CODEBLOCKS_OFFSET - 1;
1321  }
1322  else
1323  {
1324  startOffset = PAGE_SIZE - (EXCEPTION_CODEBLOCKS_OFFSET * 2);
1325  endOffset = PAGE_SIZE - 1;
1326  }
1327  }
1328  else
1329  {
1330  startOffset = 0;
1331  endOffset = (EXCEPTION_CODEBLOCKS_OFFSET * 2) - 1;
1332  }
1333  }
1334  else
1335  {
1336  endOffset += EXCEPTION_CODEBLOCKS_OFFSET - 1;
1337  }
1338 
1339  totalSize = endOffset - startOffset;
1340 
1341  // This shouldn't happen since we only extract from the same page, but let's be sure
1342  if (totalSize > PAGE_SIZE && !execute)
1343  {
1344  totalSize = PAGE_SIZE;
1345  }
1346 
1347  if (cacheFlags & CB_CACHE_FLG_ORIGINAL)
1348  {
1349  pCodeBlocksCache = &gCodeBlocksOriginalCache;
1350  }
1351  else if (cacheFlags & CB_CACHE_FLG_RETURN)
1352  {
1353  pCodeBlocksCache = &gCodeBlocksReturnCache;
1354  }
1355  else
1356  {
1357  ERROR("[ERROR] Invalid codeblocks cache flag %d...\n", cacheFlags);
1358  return INT_STATUS_NOT_SUPPORTED;
1359  }
1360 
1361  // If the current RIP is from a hooked region, we can re-use the cache because it will remain identically
1362  // (code blocks) until it's written; when the page is written, we'll invalidate the codeblocks cache. (this
1363  // cache is valid for multiple exits).
1364  // If the condition is not met, the 'event-id' cache will be used (this cache is valid for one exit).
1365  if ((PAGE_FRAME_NUMBER(pCodeBlocksCache->Rip) == PAGE_FRAME_NUMBER(rip)) &&
1366  my_llabs((long long)(pCodeBlocksCache->Rip) - (long long)(rip)) < 0x50 &&
1367  NULL != IntHookObjectFindRegion(rip, pHookObject, IG_EPT_HOOK_WRITE))
1368  {
1369  if (pCodeBlocksCache->Rip == rip &&
1370  pCodeBlocksCache->CsType == csType &&
1371  pCodeBlocksCache->Cr3 == cr3)
1372  {
1373  goto _skip_getting_codeblocks;
1374  }
1375 
1376  pCodeBlocksCache->EventId = gEventId;
1377  pCodeBlocksCache->Rip = rip;
1378  pCodeBlocksCache->CsType = csType;
1379  pCodeBlocksCache->Cr3 = cr3;
1380  pCodeBlocksCache->Count = totalSize / sizeof(DWORD);
1381  }
1382  else
1383  {
1384  if (pCodeBlocksCache->EventId == gEventId &&
1385  pCodeBlocksCache->Rip == rip &&
1386  pCodeBlocksCache->CsType == csType)
1387  {
1388  goto _skip_getting_codeblocks;
1389  }
1390 
1391  pCodeBlocksCache->EventId = gEventId;
1392  pCodeBlocksCache->Rip = rip;
1393  pCodeBlocksCache->CsType = csType;
1394  pCodeBlocksCache->Cr3 = cr3;
1395  pCodeBlocksCache->Count = totalSize / sizeof(DWORD);
1396  }
1397 
1398  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, totalSize, cr3, 0, &pCode);
1399  if (!INT_SUCCESS(status))
1400  {
1401  if (execute)
1402  {
1403  WARNING("[WARNING] Failed to map range [0x%016llx - 0x%016llx], try to map range [0x%016llx - 0x%016llx]\n",
1404  (rip & PAGE_MASK) + startOffset, (rip & PAGE_MASK) + startOffset + totalSize,
1405  (rip & PAGE_MASK) + startOffset, (rip & PAGE_MASK) + startOffset + (PAGE_SIZE - startOffset));
1406  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, PAGE_SIZE - startOffset, cr3, 0, &pCode);
1407  if (!INT_SUCCESS(status))
1408  {
1409  pCodeBlocksCache->EventId = 0;
1410 
1411  ERROR("[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", rip & PAGE_MASK, status);
1412 
1413  goto _clean_and_leave;
1414  }
1415 
1416  totalSize = PAGE_SIZE - startOffset;
1417  }
1418  else
1419  {
1420  pCodeBlocksCache->EventId = 0;
1421 
1422  ERROR("[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", rip & PAGE_MASK, status);
1423 
1424  goto _clean_and_leave;
1425  }
1426  }
1427 
1428  status = IntFragExtractCodeBlocks(pCode, totalSize, csType, level,
1429  &pCodeBlocksCache->Count, pCodeBlocksCache->CodeBlocks);
1430  if (!INT_SUCCESS(status) && INT_STATUS_NOT_FOUND != status)
1431  {
1432  pCodeBlocksCache->EventId = 0;
1433  ERROR("[ERROR] Failed extracting blocks from VA 0x%016llx: 0x%08x\n", rip, status);
1434  goto _clean_and_leave;
1435  }
1436  else if (INT_STATUS_NOT_FOUND == status)
1437  {
1438  // If we didn't manage to extract codeblocks, we can't verify anything.
1439  pCodeBlocksCache->Count = 0;
1441 
1442  goto _clean_and_leave;
1443  }
1444 
1445 _skip_getting_codeblocks:
1447  {
1448  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
1449  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
1450  {
1451  continue;
1452  }
1453 
1454  // Since everything is ordered, it's safely to do it like this
1455  for (DWORD i = lastChecked; i < SignatureCount; i++)
1456  {
1457  if (Signatures[i].Field.Type != signatureTypeCodeBlocks)
1458  {
1459  break;
1460  }
1461 
1462  if (Signatures[i].Value != pSig->Id.Value)
1463  {
1464  continue;
1465  }
1466 
1467  // We found a signature. Make sure it matches the architecture & everything else
1468  if ((requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_64)) ||
1469  (!requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_32)))
1470  {
1471  break;
1472  }
1473 
1474  if ((pSig->Flags & SIGNATURE_FLG_CB_MEDIUM) && level != cbLevelMedium)
1475  {
1476  break;
1477  }
1478 
1479  status = IntFragMatchSignature(pCodeBlocksCache->CodeBlocks, pCodeBlocksCache->Count, pSig);
1480  if (status == INT_STATUS_SIGNATURE_MATCHED)
1481  {
1482  goto _clean_and_leave;
1483  }
1484 
1485  // so the next time we will search from this signature forward only
1486  lastChecked = i + 1;
1487 
1488  // no point in searching anymore (only one will match)
1489  break;
1490  }
1491  }
1492 
1493  // if we get here, the we didn't match anything
1495 
1496 _clean_and_leave:
1497  if (NULL != pCode)
1498  {
1499  IntVirtMemUnmap(&pCode);
1500  }
1501 
1502  return status;
1503 }
1504 
1505 
1506 static INTSTATUS
1508  _In_ void *Exception,
1509  _In_ void *Originator,
1510  _In_ EXCEPTION_VICTIM_ZONE *Victim,
1511  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
1512  _In_ DWORD SignaturesCount,
1513  _In_ EXCEPTION_TYPE ExceptionType
1514  )
1533 {
1534  INTSTATUS status;
1535 
1536  DWORD lastChecked = 0;
1537 
1538  DWORD csType;
1539  BYTE *pCodePattern = NULL;
1540  BYTE *pCodePatternBuffer = NULL;
1541  BYTE level = (ExceptionType == exceptionTypeKm) ? cbLevelNormal : cbLevelMedium;
1542 
1543  BOOLEAN requires64BitSig = gGuest.Guest64;
1544  QWORD rip, cr3;
1545 
1546  QWORD oldGva = 0;
1547 
1548  status = IntGetCurrentMode(IG_CURRENT_VCPU, &csType);
1549  if (!INT_SUCCESS(status))
1550  {
1551  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
1552  return status;
1553  }
1554 
1555  if ((csType != IG_CS_TYPE_32B) && (csType != IG_CS_TYPE_64B))
1556  {
1557  ERROR("[ERROR] Unsupported CS type: %d\n", csType);
1558  return INT_STATUS_NOT_SUPPORTED;
1559  }
1560 
1561  switch (ExceptionType)
1562  {
1563  case exceptionTypeKm:
1564  case exceptionTypeKmUm:
1565  {
1566  EXCEPTION_KM_ORIGINATOR *pKmOrig = Originator;
1567 
1568  if (((KM_EXCEPTION *)Exception)->Flags & EXCEPTION_KM_FLG_RETURN_DRV)
1569  {
1570  rip = pKmOrig->Return.Rip;
1571  }
1572  else
1573  {
1574  rip = pKmOrig->Original.Rip;
1575  }
1576 
1577  cr3 = gGuest.Mm.SystemCr3;
1578 
1579  break;
1580  }
1581 
1582  case exceptionTypeUmGlob:
1583  case exceptionTypeUm:
1584  {
1585  EXCEPTION_UM_ORIGINATOR *pUmOrig = Originator;
1586 
1587  rip = pUmOrig->Rip;
1588 
1590  {
1591  if (pUmOrig->PcType == INT_PC_VIOLATION_DPI_HEAP_SPRAY ||
1593  {
1594  cr3 = Victim->Object.WinProc->Cr3;
1595  requires64BitSig = requires64BitSig && !Victim->Object.WinProc->Wow64Process;
1596  break;
1597  }
1598 
1599  cr3 = pUmOrig->WinProc->Cr3;
1600 
1601  requires64BitSig = requires64BitSig && !pUmOrig->WinProc->Wow64Process;
1602  }
1603  else if (gGuest.OSType == introGuestLinux)
1604  {
1605  cr3 = pUmOrig->LixProc->Cr3;
1606  }
1607  else
1608  {
1609  return INT_STATUS_NOT_SUPPORTED;
1610  }
1611 
1612  if (cr3 != gVcpu->Regs.Cr3)
1613  {
1614  LOG("[INFO] Special case where process cr3 %llx != VCPU cr3 %llx\n", cr3, gVcpu->Regs.Cr3);
1615  cr3 = gVcpu->Regs.Cr3;
1616  }
1617 
1618  break;
1619  }
1620 
1621  default:
1622  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
1623  return INT_STATUS_NOT_SUPPORTED;
1624  }
1625 
1626  if (0 == rip)
1627  {
1629  }
1630 
1632  {
1633  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
1634  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
1635  {
1636  continue;
1637  }
1638 
1639  // Since everything is ordered, it's safely to do it like this
1640  for (DWORD i = lastChecked; i < SignaturesCount; i++)
1641  {
1642  QWORD gva;
1643  DWORD pageRemaining;
1644  QWORD alignedGva;
1645 
1646  if (Signatures[i].Field.Type != signatureTypeValueCode)
1647  {
1648  break;
1649  }
1650 
1651  if (Signatures[i].Value != pSig->Id.Value)
1652  {
1653  continue;
1654  }
1655 
1656  // We found a signature. Make sure it matches the architecture & everything else
1657  if ((requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_64)) ||
1658  (!requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_32)))
1659  {
1660  break;
1661  }
1662 
1663  if ((pSig->Flags & SIGNATURE_FLG_CB_MEDIUM) && level != cbLevelMedium)
1664  {
1665  break;
1666  }
1667 
1668  // Match only the first page
1669  gva = rip + pSig->Offset;
1670  pageRemaining = (DWORD)PAGE_REMAINING(gva);
1671  alignedGva = gva & PAGE_MASK;
1672 
1673  // New map only if the page changes
1674  if ((oldGva != alignedGva) || NULL == pCodePattern)
1675  {
1676  oldGva = alignedGva;
1677 
1678  // Unmap the old page
1679  if (NULL != pCodePattern)
1680  {
1681  IntVirtMemUnmap(&pCodePattern);
1682  }
1683 
1684  status = IntVirtMemMap(alignedGva, PAGE_SIZE, cr3, 0, &pCodePattern);
1685  if (!INT_SUCCESS(status))
1686  {
1687  WARNING("[WARNING] IntVirtMemMap failed for address %llx: 0x%08x\n", alignedGva, status);
1688  continue;
1689  }
1690  }
1691 
1692  pCodePattern = (BYTE *)(((QWORD)pCodePattern & PAGE_MASK) | gva % PAGE_SIZE);
1693 
1694  if (SIG_NOT_FOUND == IntExceptExtendedPatternMatch(pCodePattern, MIN(pageRemaining, pSig->Length), pSig, 0))
1695  {
1696  // so the next time we will search from this signature forward only
1697  lastChecked = i + 1;
1698 
1699  // no point in searching anymore (only one will match)
1700  break;
1701  }
1702 
1703  // Match next pages if is necessary
1704  if (pageRemaining >= pSig->Length)
1705  {
1707  goto _clean_and_leave;
1708  }
1709 
1710  gva += pageRemaining;
1711 
1712  pCodePatternBuffer = HpAllocWithTag(pSig->Length - pageRemaining, IC_TAG_EXCP);
1713  if (NULL == pCodePatternBuffer)
1714  {
1716  goto _clean_and_leave;
1717  }
1718 
1719  status = IntVirtMemRead(gva, pSig->Length - pageRemaining, cr3, pCodePatternBuffer, NULL);
1720  if (!INT_SUCCESS(status))
1721  {
1722  ERROR("[ERROR] IntVirtMemMap failed for address %llx: 0x%08x\n", gva, status);
1723  continue;
1724  }
1725 
1726  if (SIG_NOT_FOUND == IntExceptExtendedPatternMatch(pCodePatternBuffer, pSig->Length - pageRemaining,
1727  pSig, pageRemaining))
1728  {
1729  HpFreeAndNullWithTag(&pCodePatternBuffer, IC_TAG_EXCP);
1730 
1731  // so the next time we will search from this signature forward only
1732  lastChecked = i + 1;
1733 
1734  // no point in searching anymore (only one will match)
1735  break;
1736  }
1737 
1738  HpFreeAndNullWithTag(&pCodePatternBuffer, IC_TAG_EXCP);
1739 
1741  goto _clean_and_leave;
1742  }
1743  }
1744 
1745  // if we get here, the we didn't match anything
1747 
1748 _clean_and_leave:
1749 
1750  if (NULL != pCodePattern)
1751  {
1752  IntVirtMemUnmap(&pCodePattern);
1753  }
1754 
1755  return status;
1756 }
1757 
1758 
1759 static INTSTATUS
1761  _In_ void *Exception,
1762  _In_ void *Originator,
1763  _In_ EXCEPTION_VICTIM_ZONE *Victim,
1764  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
1765  _In_ DWORD SignaturesCount,
1766  _In_ EXCEPTION_TYPE ExceptionType
1767  )
1783 {
1784  INTSTATUS status = INT_STATUS_SUCCESS;
1785  EXCEPTION_UM_ORIGINATOR *pOriginator = Originator;
1786  BYTE *pBuffer = NULL;
1787  BOOLEAN requires64BitSig = gGuest.Guest64;
1788  DWORD size = 0;
1789  DWORD lastChecked = 0;
1790 
1791  UNREFERENCED_PARAMETER(Exception);
1792 
1793  if ((Victim->ZoneType == exceptionZoneEpt) ||
1794  (Victim->ZoneType == exceptionZoneMsr))
1795  {
1796  if (Victim->WriteInfo.AccessSize > sizeof(Victim->WriteInfo.NewValue))
1797  {
1798  ERROR("[ERROR] Access size too large or 0: %d\n", Victim->WriteInfo.AccessSize);
1799  return INT_STATUS_NOT_SUPPORTED;
1800  }
1801 
1802  pBuffer = (BYTE *)&Victim->WriteInfo.NewValue;
1803  size = Victim->WriteInfo.AccessSize;
1804  }
1805  else if (Victim->ZoneType == exceptionZoneProcess &&
1806  NULL == Victim->Injection.Buffer)
1807  {
1808  QWORD gva = pOriginator->SourceVA;
1809  QWORD cr3 = 0;
1810 
1811  size = Victim->Injection.Length;
1812 
1813  if (NULL == gValueBuffer || size > gValueBufferSize)
1814  {
1815  TRACE("[EXCEPTIONS] Must realloc old buffer %p with size %d to size %d\n",
1817 
1818  // Maybe it failed at a previous allocation
1819  if (gValueBuffer)
1820  {
1822  }
1823 
1825  if (NULL == gValueBuffer)
1826  {
1828  }
1829 
1830  gValueBufferSize = size;
1831  }
1832 
1833  pBuffer = gValueBuffer;
1834 
1836  {
1837  cr3 = pOriginator->WinProc->Cr3;
1838  }
1839  else if (gGuest.OSType == introGuestLinux)
1840  {
1841  cr3 = pOriginator->LixProc->Cr3;
1842  }
1843  else
1844  {
1845  return INT_STATUS_NOT_SUPPORTED;
1846  }
1847 
1848  // Safe: buf is allocated dynamically to match the read size.
1849  status = IntVirtMemRead(gva, size, cr3, pBuffer, NULL);
1850  if (!INT_SUCCESS(status))
1851  {
1852  ERROR("[ERROR] IntVirtMemRead failed for gva %llx, cr3 %llx with size %d: %08x\n", gva, cr3, size, status);
1853  return status;
1854  }
1855 
1856  Victim->Injection.Buffer = gValueBuffer;
1857  Victim->Injection.BufferSize = gValueBufferSize;
1858  }
1859  else if (Victim->ZoneType == exceptionZoneProcess &&
1860  NULL != Victim->Injection.Buffer)
1861  {
1862  pBuffer = Victim->Injection.Buffer;
1863  size = Victim->Injection.BufferSize;
1864  }
1865  else if (Victim->ZoneType == exceptionZoneIntegrity)
1866  {
1867  if (Victim->Object.Type == introObjectTypeIdt ||
1868  Victim->Object.Type == introObjectTypeSudIntegrity)
1869  {
1870  pBuffer = (BYTE *)&Victim->WriteInfo.NewValue;
1871  size = Victim->WriteInfo.AccessSize;
1872  }
1873  else if (Victim->Object.Type == introObjectTypeSecDesc ||
1874  Victim->Object.Type == introObjectTypeAcl)
1875  {
1876  pBuffer = Victim->Integrity.Buffer;
1877  size = Victim->Integrity.BufferSize;
1878  }
1879  else
1880  {
1881  return INT_STATUS_NOT_SUPPORTED;
1882  }
1883  }
1884  else if (Victim->ZoneType == exceptionZonePc)
1885  {
1886  // Nothing to do here ...
1887  }
1888  else
1889  {
1890  return INT_STATUS_NOT_SUPPORTED;
1891  }
1892 
1893  switch (ExceptionType)
1894  {
1895  case exceptionTypeKm:
1896  case exceptionTypeKmUm:
1897  break;
1898 
1899  case exceptionTypeUmGlob:
1900  case exceptionTypeUm:
1901  if (gGuest.OSType == introGuestWindows && requires64BitSig)
1902  {
1903  requires64BitSig = !pOriginator->WinProc->Wow64Process;
1904  }
1905 
1906  break;
1907 
1908  default:
1909  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
1910  return INT_STATUS_NOT_SUPPORTED;
1911  }
1912 
1914  {
1915  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
1916  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
1917  {
1918  continue;
1919  }
1920 
1921  // Since everything is ordered, it's safely to do it like this
1922  for (DWORD i = lastChecked; i < SignaturesCount; i++)
1923  {
1924  SIG_VALUE_HASH *pSigHash = NULL;
1925  DWORD matchedCount = 0;
1926 
1927  if (Signatures[i].Field.Type != signatureTypeValue)
1928  {
1929  break;
1930  }
1931 
1932  if (Signatures[i].Value != pSig->Id.Value)
1933  {
1934  continue;
1935  }
1936 
1937  // We found a signature. Make sure it matches the architecture & everything else
1938  if ((requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_64)) ||
1939  (!requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_32)))
1940  {
1941  break;
1942  }
1943 
1944  pSigHash = (SIG_VALUE_HASH *)pSig->Object;
1945  for (DWORD j = 0; j < pSig->ListsCount; j++)
1946  {
1947  BOOLEAN match = FALSE;
1948 
1949  if (pSig->Flags & SIGNATURE_FLG_VALUE_CLI)
1950  {
1951  char *pCommandLine = NULL;
1952 
1954  {
1955  pCommandLine = pOriginator->WinProc->CommandLine;
1956  }
1957  else if (gGuest.OSType == introGuestLinux)
1958  {
1959  pCommandLine = pOriginator->LixProc->CmdLine;
1960  }
1961  else
1962  {
1963  break;
1964  }
1965 
1966  if (pCommandLine == NULL)
1967  {
1969  }
1970 
1971  // This case will include Offset > wstrlen(pCli) and Size > wstrlen(pCommandLine) because we cast
1972  // Offset and Size (WORD -> DWORD) so we'll not have an overflow
1973  if (((QWORD)pSigHash[j].Offset + (DWORD)pSigHash[j].Size) > strlen(pCommandLine))
1974  {
1975  continue;
1976  }
1977 
1978  match = (pSigHash[j].Hash == Crc32Compute(pCommandLine + pSigHash[j].Offset,
1979  pSigHash[j].Size,
1981  }
1982  else
1983  {
1984  if (Victim->ZoneType == exceptionZonePc || pBuffer == NULL)
1985  {
1986  continue;
1987  }
1988 
1989  // This case will include Offset >size and Size > size because we cast Offset and Size
1990  // (WORD -> DWORD) so we'll not have an overflow
1991  if (((DWORD)pSigHash[j].Offset + (DWORD)pSigHash[j].Size) > size)
1992  {
1993  continue;
1994  }
1995 
1996  match = (pSigHash[j].Hash == Crc32Compute(pBuffer + pSigHash[j].Offset,
1997  pSigHash[j].Size,
1999  }
2000 
2001  if (match)
2002  {
2003  matchedCount++;
2004 
2005  if (matchedCount >= pSig->Score)
2006  {
2008  }
2009  }
2010 
2011  }
2012 
2013  // so the next time we will search from this signature forward only
2014  lastChecked = i + 1;
2015 
2016  // no point in searching anymore (only one will match)
2017  break;
2018  }
2019  }
2020 
2021  // if we get here, the we didn't match anything
2023 }
2024 
2025 
2026 static INTSTATUS
2028  _In_ void *Exception,
2029  _In_ void *Originator,
2031  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2032  _In_ DWORD SignaturesCount,
2033  _In_ EXCEPTION_TYPE ExceptionType
2034  )
2053 {
2054  WIN_PROCESS_MODULE *pModule;
2055  DWORD accessSize;
2056  DWORD lastChecked = 0;
2057  BOOLEAN requires64BitSig = gGuest.Guest64;
2058  QWORD gva;
2059 
2060  UNREFERENCED_PARAMETER(Exception);
2061 
2062  switch(ExceptionType)
2063  {
2064  case exceptionTypeUm:
2065  {
2066  EXCEPTION_UM_ORIGINATOR *pOriginator = Originator;
2067  if (gGuest.OSType == introGuestWindows && requires64BitSig)
2068  {
2069  if (Victim->ZoneType == exceptionZoneProcess)
2070  {
2071  requires64BitSig = !Victim->Object.WinProc->Wow64Process;
2072  }
2073  else
2074  {
2075  requires64BitSig = !pOriginator->WinProc->Wow64Process;
2076  }
2077  }
2078  break;
2079  }
2080 
2081  case exceptionTypeKmUm:
2082  requires64BitSig = gGuest.Guest64;
2083  break;
2084 
2085  default:
2086  WARNING("[WARNING] Unsupported exception type (%d) for export signature\n", ExceptionType);
2088  }
2089 
2090  if (Victim->ZoneType == exceptionZoneEpt)
2091  {
2092  gva = Victim->Ept.Gva;
2093  accessSize = Victim->WriteInfo.AccessSize;
2094  }
2095  else if (Victim->ZoneType == exceptionZoneProcess)
2096  {
2097  gva = Victim->Injection.Gva;
2098  accessSize = Victim->Injection.Length;
2099  }
2100  else
2101  {
2102  return INT_STATUS_NOT_SUPPORTED;
2103  }
2104 
2105  pModule = Victim->Object.Library.Module;
2106 
2107  // We must return an error since this injection was for a module-only modification
2108  if (NULL == pModule)
2109  {
2111  }
2112 
2113  if (NULL == pModule->Cache || !pModule->Cache->ExportDirRead)
2114  {
2116  }
2117 
2118  if (Victim->Object.Library.Export == NULL)
2119  {
2120  Victim->Object.Library.Export = IntWinUmCacheGetExportFromRange(pModule, gva, 0x20);
2121  }
2122 
2124  {
2125  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
2126  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
2127  {
2128  continue;
2129  }
2130 
2131  if (pSig->LibraryNameHash != umExcNameAny && pModule->Path->NameHash != pSig->LibraryNameHash)
2132  {
2133  continue;
2134  }
2135 
2136  // Since everything is ordered, it's safely to do it like this
2137  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2138  {
2139  SIG_EXPORT_HASH *pSigHash;
2140 
2141  if (Signatures[i].Field.Type != signatureTypeExport)
2142  {
2143  break;
2144  }
2145 
2146  if (Signatures[i].Value != pSig->Id.Value)
2147  {
2148  continue;
2149  }
2150 
2151  // We found a signature. Make sure it matches the architecture & everything else
2152  if ((requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_64)) ||
2153  (!requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_32)))
2154  {
2155  break;
2156  }
2157 
2158  pSigHash = (SIG_EXPORT_HASH *)pSig->Object;
2159  for (DWORD j = 0; j < pSig->ListsCount; j++)
2160  {
2161  DWORD offset;
2162  BOOLEAN found = FALSE;
2163 
2164  if (pSigHash[j].Hash == umExcNameAny)
2165  {
2167  }
2168 
2169  if (Victim->Object.Library.Export == NULL &&
2170  pSigHash[i].Hash == umExcNameNone)
2171  {
2173  }
2174 
2175  // Only check the exceptions which match any name if we didn't found an export
2176  if (Victim->Object.Library.Export == NULL)
2177  {
2178  continue;
2179  }
2180 
2181  for (DWORD export = 0; export < Victim->Object.Library.Export->NumberOfOffsets; export++)
2182  {
2183  if (pSigHash[j].Hash == Victim->Object.Library.Export->NameHashes[export])
2184  {
2185  found = TRUE;
2186  break;
2187  }
2188  }
2189 
2190  if (!found)
2191  {
2192  continue;
2193  }
2194 
2195  // Verify that the write is inside the allowed zone or that delta is 0 (match any length)
2196  offset = (DWORD)(gva - pModule->VirtualBase) - Victim->Object.Library.Export->Rva;
2197  if (pSigHash[j].Delta != 0 &&
2198  (offset + accessSize - 1 > pSigHash[j].Delta))
2199  {
2200  continue;
2201  }
2202 
2204  }
2205 
2206  // so the next time we will search from this signature forward only
2207  lastChecked = i + 1;
2208 
2209  // no point in searching anymore (only one will match)
2210  break;
2211  }
2212  }
2213 
2215 }
2216 
2217 
2218 static INTSTATUS
2220  _In_ void *Exception,
2221  _In_ void *Originator,
2223  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2224  _In_ DWORD SignaturesCount,
2225  _In_ EXCEPTION_TYPE ExceptionType
2226  )
2241 {
2242  UNREFERENCED_PARAMETER(Originator);
2243  UNREFERENCED_PARAMETER(Exception);
2244 
2245  DWORD lastChecked = 0;
2246  BYTE idtEntry;
2247 
2248  if (ExceptionType != exceptionTypeKm)
2249  {
2251  }
2252  switch (Victim->Object.Type)
2253  {
2254  case introObjectTypeIdt:
2255  if (Victim->ZoneType == exceptionZoneIntegrity)
2256  {
2257  idtEntry = (BYTE)(Victim->Integrity.Offset /
2259  }
2260  else
2261  {
2262  idtEntry = (BYTE)((Victim->Ept.Gva - Victim->Object.BaseAddress) /
2264  }
2265  break;
2266 
2268  idtEntry = (BYTE)Victim->Integrity.InterruptObjIndex;
2269  break;
2270 
2271  default:
2272  return INT_STATUS_NOT_SUPPORTED;
2273  }
2274 
2275  lastChecked = 0;
2277  {
2278  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
2279  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
2280  {
2281  continue;
2282  }
2283 
2284  // Since everything is ordered, it's safely to do it like this
2285  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2286  {
2287  if (Signatures[i].Field.Type != signatureTypeIdt)
2288  {
2289  break;
2290  }
2291 
2292  if (Signatures[i].Value != pSig->Id.Value)
2293  {
2294  continue;
2295  }
2296 
2297  // We found a signature. Make sure it matches the architecture & everything else
2298  if ((gGuest.Guest64 && !(pSig->Flags & SIGNATURE_FLG_64)) ||
2299  (!gGuest.Guest64 && !(pSig->Flags & SIGNATURE_FLG_32)))
2300  {
2301  break;
2302  }
2303 
2304  if (pSig->Entry == idtEntry)
2305  {
2307  }
2308 
2309  // so the next time we will search from this signature forward only
2310  lastChecked = i + 1;
2311 
2312  // no point in searching anymore (only one will match)
2313  break;
2314  }
2315  }
2316 
2317  // if we get here, the we didn't match anything
2319 }
2320 
2321 
2322 static INTSTATUS
2324  _In_ void *Exception,
2325  _In_ void *Originator,
2326  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2327  _In_ DWORD SignaturesCount,
2328  _In_ EXCEPTION_TYPE ExceptionType
2329  )
2343 {
2344  UNREFERENCED_PARAMETER(Exception);
2345 
2346  EXCEPTION_UM_ORIGINATOR *pOriginator = NULL;
2347  DWORD mask = 0;
2348  DWORD lastChecked = 0;
2349 
2350  if (ExceptionType == exceptionTypeKm)
2351  {
2352  return INT_STATUS_NOT_SUPPORTED;
2353  }
2354 
2355  pOriginator = Originator;
2356 
2357  mask = pOriginator->PcType;
2358 
2359  lastChecked = 0;
2361  {
2362  if ((gGuest.OSType == introGuestWindows && (pSignature->Flags & SIGNATURE_FLG_LINUX)) ||
2363  (gGuest.OSType == introGuestLinux && !(pSignature->Flags & SIGNATURE_FLG_LINUX)))
2364  {
2365  continue;
2366  }
2367 
2368  // Since everything is ordered, it's safely to do it like this
2369  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2370  {
2371  if (Signatures[i].Field.Type != signatureTypeProcessCreation)
2372  {
2373  break;
2374  }
2375 
2376  if (Signatures[i].Value != pSignature->Id.Value)
2377  {
2378  continue;
2379  }
2380 
2381  // We found a signature. Make sure it matches the architecture & everything else
2382  if ((gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_64)) ||
2383  (!gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_32)))
2384  {
2385  break;
2386  }
2387 
2388  if ((~(pSignature->CreateMask) & mask) == 0)
2389  {
2391  }
2392 
2393  // so the next time we will search from this signature forward only
2394  lastChecked = i + 1;
2395 
2396  // no point in searching anymore (only one will match)
2397  break;
2398  }
2399  }
2400 
2401  // if we get here, the we didn't match anything
2403 }
2404 
2405 
2406 static INTSTATUS
2408  _In_ void *Exception,
2409  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2410  _In_ DWORD SignaturesCount
2411  )
2423 {
2424  UNREFERENCED_PARAMETER(Exception);
2425 
2426  DWORD lastChecked = 0;
2427 
2428  lastChecked = 0;
2430  {
2431  if ((gGuest.OSType == introGuestWindows && (pSignature->Flags & SIGNATURE_FLG_LINUX)) ||
2432  (gGuest.OSType == introGuestLinux && !(pSignature->Flags & SIGNATURE_FLG_LINUX)))
2433  {
2434  continue;
2435  }
2436 
2437  // Since everything is ordered, it's safely to do it like this
2438  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2439  {
2440  if (Signatures[i].Field.Type != signatureTypeVersionOs)
2441  {
2442  break;
2443  }
2444 
2445  if (Signatures[i].Value != pSignature->Id.Value)
2446  {
2447  continue;
2448  }
2449 
2450  // We found a signature. Make sure it matches the architecture & everything else
2451  if ((gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_64)) ||
2452  (!gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_32)))
2453  {
2454  break;
2455  }
2456 
2458  {
2459  if (pSignature->Minimum.Value <= gGuest.OSVersion &&
2460  pSignature->Maximum.Value >= gGuest.OSVersion)
2461  {
2463  }
2464  }
2465  else if (gGuest.OSType == introGuestLinux)
2466  {
2467  BOOLEAN matchMax = FALSE;
2468  BOOLEAN matchMin = FALSE;
2469 
2470  if (pSignature->Minimum.Version <= gLixGuest->Version.Version)
2471  {
2472  if (pSignature->Minimum.Version < gLixGuest->Version.Version)
2473  {
2474  matchMin = TRUE;
2475  goto _check_min_os_done;
2476  }
2477 
2478  if (pSignature->Minimum.Patch <= gLixGuest->Version.Patch)
2479  {
2480  if (pSignature->Minimum.Patch < gLixGuest->Version.Patch)
2481  {
2482  matchMin = TRUE;
2483  goto _check_min_os_done;
2484  }
2485 
2486  if (pSignature->Minimum.Sublevel <= gLixGuest->Version.Sublevel)
2487  {
2488  if (pSignature->Minimum.Sublevel < gLixGuest->Version.Sublevel)
2489  {
2490  matchMin = TRUE;
2491  goto _check_min_os_done;
2492  }
2493 
2494  if (pSignature->Minimum.Backport <= gLixGuest->Version.Backport)
2495  {
2496  matchMin = TRUE;
2497  }
2498  }
2499  }
2500  }
2501 
2502 _check_min_os_done:
2503  if (!matchMin)
2504  {
2505  goto _check_max_os_done;
2506  }
2507 
2508  if (pSignature->Maximum.Version >= gLixGuest->Version.Version)
2509  {
2510  if (pSignature->Maximum.Version > gLixGuest->Version.Version)
2511  {
2512  matchMax = TRUE;
2513  goto _check_max_os_done;
2514  }
2515 
2516  if (pSignature->Maximum.Patch >= gLixGuest->Version.Patch)
2517  {
2518  if (pSignature->Maximum.Patch > gLixGuest->Version.Patch)
2519  {
2520  matchMax = TRUE;
2521  goto _check_max_os_done;
2522  }
2523 
2524  if (pSignature->Maximum.Sublevel >= gLixGuest->Version.Sublevel)
2525  {
2526  if (pSignature->Maximum.Sublevel > gLixGuest->Version.Sublevel)
2527  {
2528  matchMax = TRUE;
2529  goto _check_max_os_done;
2530  }
2531 
2532  if (pSignature->Maximum.Backport >= gLixGuest->Version.Backport)
2533  {
2534  matchMax = TRUE;
2535  }
2536  }
2537  }
2538  }
2539 
2540 _check_max_os_done:
2541  if (matchMin && matchMax)
2542  {
2544  }
2545  }
2546 
2547  // so the next time we will search from this signature forward only
2548  lastChecked = i + 1;
2549 
2550  // no point in searching anymore (only one will match)
2551  break;
2552  }
2553  }
2554 
2555  // if we get here, the we didn't match anything
2557 }
2558 
2559 
2560 static INTSTATUS
2562  _In_ void *Exception,
2563  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2564  _In_ DWORD SignaturesCount
2565  )
2577 {
2578  UNREFERENCED_PARAMETER(Exception);
2579 
2580  DWORD lastChecked = 0;
2581 
2582  lastChecked = 0;
2584  {
2585  if ((gGuest.OSType == introGuestWindows && (pSignature->Flags & SIGNATURE_FLG_LINUX)) ||
2586  (gGuest.OSType == introGuestLinux && !(pSignature->Flags & SIGNATURE_FLG_LINUX)))
2587  {
2588  continue;
2589  }
2590 
2591  // Since everything is ordered, it's safely to do it like this
2592  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2593  {
2594  BOOLEAN matchMax;
2595  BOOLEAN matchMin;
2596 
2597  if (Signatures[i].Field.Type != signatureTypeVersionIntro)
2598  {
2599  break;
2600  }
2601 
2602  if (Signatures[i].Value != pSignature->Id.Value)
2603  {
2604  continue;
2605  }
2606 
2607  // We found a signature. Make sure it matches the architecture & everything else
2608  if ((gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_64)) ||
2609  (!gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_32)))
2610  {
2611  break;
2612  }
2613 
2614  matchMax = FALSE;
2615  matchMin = FALSE;
2616 
2617  if (pSignature->Minimum.Major <= IntHviVersion.VersionInfo.Major)
2618  {
2619  if (pSignature->Minimum.Major < IntHviVersion.VersionInfo.Major)
2620  {
2621  matchMin = TRUE;
2622  goto _check_min_done;
2623  }
2624 
2625  if (pSignature->Minimum.Minor <= IntHviVersion.VersionInfo.Minor)
2626  {
2627  if (pSignature->Minimum.Minor < IntHviVersion.VersionInfo.Minor)
2628  {
2629  matchMin = TRUE;
2630  goto _check_min_done;
2631  }
2632 
2633  if (pSignature->Minimum.Revision <= IntHviVersion.VersionInfo.Revision)
2634  {
2635  if (pSignature->Minimum.Revision < IntHviVersion.VersionInfo.Revision)
2636  {
2637  matchMin = TRUE;
2638  goto _check_min_done;
2639  }
2640 
2641  if (pSignature->Minimum.Build <= IntHviVersion.VersionInfo.Build)
2642  {
2643  matchMin = TRUE;
2644  }
2645  }
2646  }
2647  }
2648 
2649 _check_min_done:
2650 
2651  if (!matchMin)
2652  {
2653  goto _check_max_done;
2654  }
2655 
2656  if (pSignature->Maximum.Major >= IntHviVersion.VersionInfo.Major)
2657  {
2658  if (pSignature->Maximum.Major > IntHviVersion.VersionInfo.Major)
2659  {
2660  matchMax = TRUE;
2661  goto _check_max_done;
2662  }
2663 
2664  if (pSignature->Maximum.Minor >= IntHviVersion.VersionInfo.Minor)
2665  {
2666  if (pSignature->Maximum.Minor > IntHviVersion.VersionInfo.Minor)
2667  {
2668  matchMax = TRUE;
2669  goto _check_max_done;
2670  }
2671 
2672  if (pSignature->Maximum.Revision >= IntHviVersion.VersionInfo.Revision)
2673  {
2674  if (pSignature->Maximum.Revision > IntHviVersion.VersionInfo.Revision)
2675  {
2676  matchMax = TRUE;
2677  goto _check_max_done;
2678  }
2679 
2680  if (pSignature->Maximum.Build >= IntHviVersion.VersionInfo.Build)
2681  {
2682  matchMax = TRUE;
2683  }
2684  }
2685  }
2686  }
2687 
2688 _check_max_done:
2689  if (matchMax && matchMin)
2690  {
2692  }
2693 
2694  // so the next time we will search from this signature forward only
2695  lastChecked = i + 1;
2696 
2697  // no point in searching anymore (only one will match)
2698  break;
2699  }
2700  }
2701 
2702  // if we get here, the we didn't match anything
2704 }
2705 
2706 
2707 static BOOLEAN
2709  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2710  _In_ DWORD Count,
2712  )
2722 {
2723  for (DWORD index = 0; index < Count; index++)
2724  {
2725  if ((EXCEPTION_SIGNATURE_TYPE)(Signatures[index].Field.Type) == Type)
2726  {
2727  return TRUE;
2728  }
2729  }
2730 
2731  return FALSE;
2732 }
2733 
2734 
2735 static INTSTATUS
2737  _In_ void *Exception,
2738  _In_ void *Originator,
2739  _In_ EXCEPTION_VICTIM_ZONE *Victim,
2740  _In_ EXCEPTION_TYPE ExceptionType,
2741  _Out_ INTRO_ACTION_REASON *Reason
2742  )
2756 {
2757 
2758  INTSTATUS status = INT_STATUS_SUCCESS;
2759  EXCEPTION_SIGNATURE_ID *pId = NULL;
2760  DWORD count = 0;
2761  DWORD index;
2762 
2763  // The caller will set the beta flag if needed.
2764  *Reason = introReasonAllowed;
2765 
2766  switch (ExceptionType)
2767  {
2768  case exceptionTypeKm:
2769  count = ((KM_EXCEPTION *)Exception)->SigCount;
2770  pId = ((KM_EXCEPTION *)Exception)->Signatures;
2771 
2772  break;
2773 
2774  case exceptionTypeKmUm:
2775  count = ((KUM_EXCEPTION *)Exception)->SigCount;
2776  pId = ((KUM_EXCEPTION *)Exception)->Signatures;
2777 
2778  break;
2779 
2780  case exceptionTypeUm:
2781  count = ((UM_EXCEPTION *)Exception)->SigCount;
2782  pId = ((UM_EXCEPTION *)Exception)->Signatures;
2783 
2784  // An injection that modifies a dll MUST have a export signature
2785  if (NULL != Victim->Object.Library.Module &&
2786  Victim->ZoneType == exceptionZoneProcess &&
2788  !(Victim->ZoneFlags & ZONE_MODULE_LOAD))
2789  {
2790  *Reason = introReasonExportNotMatched;
2792  }
2793 
2794  break;
2795 
2796  case exceptionTypeUmGlob:
2797  count = ((UM_EXCEPTION_GLOB *)Exception)->SigCount;
2798  pId = ((UM_EXCEPTION_GLOB *)Exception)->Signatures;
2799 
2800 
2801  // An injection that modifies a dll MUST have a export signature
2802  if (NULL != Victim->Object.Library.Module &&
2803  Victim->ZoneType == exceptionZoneProcess &&
2805  !(Victim->ZoneFlags & ZONE_MODULE_LOAD))
2806  {
2807  *Reason = introReasonExportNotMatched;
2809  }
2810 
2811  break;
2812 
2813  default:
2814  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
2815  return INT_STATUS_NOT_SUPPORTED;
2816  }
2817 
2818  if (0 == count)
2819  {
2821  }
2822 
2823  index = 0;
2824  while (index < count)
2825  {
2826  switch (pId[index].Field.Type)
2827  {
2829  {
2830  status = IntExceptVerifyVersionOsSignature(Exception, &pId[index], count - index);
2831  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2832  {
2834  return status;
2835  }
2836 
2837  break;
2838  }
2839 
2841  {
2842  status = IntExceptVerifyVersionIntroSignature(Exception, &pId[index], count - index);
2843  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2844  {
2846  return status;
2847  }
2848 
2849  break;
2850  }
2851 
2853  {
2854  status = IntExceptVerifyProcessCreationSignature(Exception,
2855  Originator,
2856  &pId[index],
2857  count - index,
2858  ExceptionType);
2859  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2860  {
2862  return status;
2863  }
2864 
2865  break;
2866  }
2867 
2868 
2869  case signatureTypeExport:
2870  {
2871  status = IntExceptVerifyExportSig(Exception,
2872  Originator,
2873  Victim,
2874  &pId[index],
2875  count - index,
2876  ExceptionType);
2877  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2878  {
2879  *Reason = introReasonExportNotMatched;
2880  return status;
2881  }
2882 
2883  break;
2884  }
2885 
2886  case signatureTypeValue:
2887  {
2888  status = IntExceptVerifyValueSig(Exception,
2889  Originator,
2890  Victim,
2891  &pId[index],
2892  count - index,
2893  ExceptionType);
2894  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2895  {
2896  *Reason = introReasonValueNotMatched;
2897  return status;
2898  }
2899 
2900  break;
2901  }
2902 
2903  case signatureTypeIdt:
2904  {
2905  status = IntExceptVerifyIdtSignature(Exception,
2906  Originator,
2907  Victim,
2908  &pId[index],
2909  count - index,
2910  ExceptionType);
2911  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2912  {
2913  *Reason = introReasonIdtNotMatched;
2914  return status;
2915  }
2916 
2917  break;
2918  }
2919 
2921  {
2922  status = IntExceptVerifyValueCodeSig(Exception,
2923  Originator,
2924  Victim,
2925  &pId[index],
2926  count - index,
2927  ExceptionType);
2928  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2929  {
2931  return status;
2932  }
2933 
2934  break;
2935  }
2936 
2938  {
2939  status = IntExceptVerifyCodeBlocksSig(Exception, Originator, &pId[index], count - index, ExceptionType);
2940  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2941  {
2943  return status;
2944  }
2945 
2946  break;
2947  }
2948 
2949  default:
2950  {
2951  ERROR("[ERROR] Should not reach here. Type is %d ...\n", pId[index].Field.Type);
2952  return INT_STATUS_NOT_SUPPORTED;
2953  }
2954 
2955  }
2956 
2957  if (!INT_SUCCESS(status))
2958  {
2959  ERROR("[ERROR] IntExceptVerifySignature failed for signature type %d with status: 0x%08x\n",
2960  pId[index].Field.Type, status);
2961  *Reason = introReasonInternalError;
2962 
2963  return status;
2964  }
2965 
2966  index++;
2967  while (index < count && pId[index].Field.Type == pId[index - 1].Field.Type)
2968  {
2969  index++;
2970  }
2971  }
2972 
2974 }
2975 
2976 
2977 void
2979  _In_ void *Originator,
2980  _In_ EXCEPTION_VICTIM_ZONE *Victim,
2981  _In_ BOOLEAN KernelMode,
2982  _In_ BOOLEAN ReturnDrv
2983  )
2992 {
2993  INTSTATUS status;
2994 
2995  DWORD startOffset, endOffset, totalSize, i, csType;
2996  BOOLEAN execute = FALSE;
2997  BYTE *pCode = NULL;
2998 
2999  QWORD rip;
3000 
3001  if (NULL == Originator)
3002  {
3003  return;
3004  }
3005 
3006  status = IntGetCurrentMode(IG_CURRENT_VCPU, &csType);
3007  if (!INT_SUCCESS(status))
3008  {
3009  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
3010  return;
3011  }
3012 
3013  if ((csType != IG_CS_TYPE_32B) && (csType != IG_CS_TYPE_64B))
3014  {
3015  ERROR("[ERROR] Unsupported CS type: %d\n", csType);
3016  return;
3017  }
3018 
3019  if (KernelMode)
3020  {
3021  if (ReturnDrv)
3022  {
3023  rip = ((EXCEPTION_KM_ORIGINATOR *)Originator)->Return.Rip;
3024  }
3025  else
3026  {
3027  rip = ((EXCEPTION_KM_ORIGINATOR *)Originator)->Original.Rip;
3028  }
3029  }
3030  else
3031  {
3032  rip = ((EXCEPTION_UM_ORIGINATOR *)Originator)->Rip;
3033  execute = ((EXCEPTION_UM_ORIGINATOR *)Originator)->Execute;
3034  }
3035 
3036  if (0 == rip)
3037  {
3038  return;
3039  }
3040 
3041  // See if we dumped this already
3042  for (i = 0; i < ARRAYSIZE(gUsedRips); i++)
3043  {
3044  if (gUsedRips[i] == rip)
3045  {
3046  return;
3047  }
3048  }
3049 
3050  // Now add it to the list, if we can
3051  for (i = 0; i < ARRAYSIZE(gUsedRips); i++)
3052  {
3053  if (gUsedRips[i] == 0)
3054  {
3055  gUsedRips[i] = rip;
3056  break;
3057  }
3058  }
3059 
3060  // Make sure the totalSize is 2 * EXCEPTION_CODEBLOCKS_OFFSET, and to remain in the same page. Eg:
3061  // RipOffset = 0xf31 => [0xc00, 0xfff]
3062  // RipOffset = 0x123 => [0x000, 0x3ff]
3063  // RipOffset = 0x523 => [0x323, 0x722]
3064 
3065  startOffset = endOffset = rip & PAGE_OFFSET;
3066 
3067  if (!execute)
3068  {
3069  // endOffset = MIN(endOffset + EXCEPTION_CODEBLOCKS_OFFSET, PAGE_SIZE - 1);
3070  // startOffset = MIN(0, (int)(endOffset - EXCEPTION_CODEBLOCKS_OFFSET));
3071 
3072  if (startOffset > EXCEPTION_CODEBLOCKS_OFFSET)
3073  {
3074  if (endOffset + EXCEPTION_CODEBLOCKS_OFFSET < PAGE_SIZE)
3075  {
3076  startOffset -= EXCEPTION_CODEBLOCKS_OFFSET;
3077  endOffset += EXCEPTION_CODEBLOCKS_OFFSET - 1;
3078  }
3079  else
3080  {
3081  startOffset = PAGE_SIZE - (EXCEPTION_CODEBLOCKS_OFFSET * 2);
3082  endOffset = PAGE_SIZE - 1;
3083  }
3084 
3085  }
3086  else
3087  {
3088  startOffset = 0;
3089  endOffset = (EXCEPTION_CODEBLOCKS_OFFSET * 2) - 1;
3090  }
3091  }
3092  else
3093  {
3094  endOffset += EXCEPTION_CODEBLOCKS_OFFSET - 1;
3095  }
3096 
3097  totalSize = endOffset - startOffset;
3098 
3099  if (KernelMode)
3100  {
3101  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, totalSize, gGuest.Mm.SystemCr3, 0, &pCode);
3102  }
3103  else
3104  {
3105  QWORD cr3 = 0;
3106 
3108  {
3109  cr3 = ((EXCEPTION_UM_ORIGINATOR *)Originator)->WinProc->Cr3;
3110  }
3111  else if (gGuest.OSType == introGuestLinux)
3112  {
3113  cr3 = ((EXCEPTION_UM_ORIGINATOR *)Originator)->LixProc->Cr3;
3114  }
3115 
3116  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, totalSize, cr3, 0, &pCode);
3117  if (!INT_SUCCESS(status) && execute)
3118  {
3119  WARNING("[WARNING] Failed to map range [0x%016llx - 0x%016llx], try to map range [0x%016llx - 0x%016llx]\n",
3120  (rip & PAGE_MASK) + startOffset, (rip & PAGE_MASK) + startOffset + totalSize,
3121  (rip & PAGE_MASK) + startOffset, (rip & PAGE_MASK) + startOffset + (PAGE_SIZE - startOffset));
3122 
3123  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, PAGE_SIZE - startOffset, cr3, 0, &pCode);
3124  if (INT_SUCCESS(status))
3125  {
3126  totalSize = PAGE_SIZE - startOffset;
3127  }
3128  }
3129  }
3130 
3131  if (!INT_SUCCESS(status) && (Victim->ZoneFlags & ZONE_DEP_EXECUTION) == 0)
3132  {
3133  ERROR("[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", rip & PAGE_MASK, status);
3134  goto _clean_and_leave;
3135  }
3136  else if (!INT_SUCCESS(status))
3137  {
3138  WARNING("[WARNING] Failed mapping VA 0x%016llx to host: 0x%08x\n", rip & PAGE_MASK, status);
3139  goto _clean_and_leave;
3140  }
3141 
3142  status = IntFragDumpBlocks(pCode,
3143  (rip & PAGE_MASK) + startOffset,
3144  totalSize,
3145  csType,
3146  KernelMode ? cbLevelNormal : cbLevelMedium,
3147  rip,
3148  KernelMode ? ReturnDrv : FALSE);
3149 
3150  IntDumpBuffer(pCode, (rip & PAGE_MASK) + startOffset, totalSize, 16, sizeof(BYTE), TRUE, TRUE);
3151 
3152  if (!INT_SUCCESS(status))
3153  {
3154  WARNING("[WARNING] Failed extracting blocks from VA 0x%016llx: 0x%08x\n", rip, status);
3155  goto _clean_and_leave;
3156  }
3157 
3158 _clean_and_leave:
3159  if (NULL != pCode)
3160  {
3161  IntVirtMemUnmap(&pCode);
3162  }
3163 }
3164 
3165 
3166 INTSTATUS
3168  _In_ void *Victim,
3169  _In_ void *Originator,
3170  _In_ void *Exception,
3171  _In_ EXCEPTION_TYPE ExceptionType,
3172  _Out_ INTRO_ACTION *Action,
3173  _Out_ INTRO_ACTION_REASON *Reason
3174  )
3194 {
3195  INTSTATUS status;
3196  BOOLEAN feedbackException, linuxException;
3197 
3198  switch (ExceptionType)
3199  {
3200  case exceptionTypeKm:
3201  feedbackException = (((KM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_FEEDBACK) != 0;
3202  linuxException = (((KM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_LINUX) != 0;
3203  break;
3204 
3205  case exceptionTypeUm:
3206  feedbackException = (((UM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_FEEDBACK) != 0;
3207  linuxException = (((UM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_LINUX) != 0;
3208  break;
3209 
3210  case exceptionTypeUmGlob:
3211  feedbackException = (((UM_EXCEPTION_GLOB *)Exception)->Flags & EXCEPTION_FLG_FEEDBACK) != 0;
3212  linuxException = (((UM_EXCEPTION_GLOB *)Exception)->Flags & EXCEPTION_FLG_LINUX) != 0;
3213  break;
3214 
3215  case exceptionTypeKmUm:
3216  feedbackException = (((KUM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_FEEDBACK) != 0;
3217  linuxException = (((KUM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_LINUX) != 0;
3218  break;
3219 
3220  default:
3221  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
3222  return INT_STATUS_NOT_SUPPORTED;
3223  }
3224 
3225  if ((linuxException && (gGuest.OSType != introGuestLinux)) ||
3226  (!linuxException && (gGuest.OSType == introGuestLinux)))
3227  {
3229  }
3230 
3231  // 1. Check if the exception is matching at type, flags, and name.
3232  switch (ExceptionType)
3233  {
3234  case exceptionTypeKm:
3235  status = IntExceptKernelMatchVictim(Victim, Originator, Exception);
3236  break;
3237 
3238  case exceptionTypeUm:
3239  case exceptionTypeUmGlob:
3240  status = IntExceptUserMatchVictim(Victim, Originator, Exception, ExceptionType);
3241  break;
3242 
3243  case exceptionTypeKmUm:
3244  status = IntExceptKernelUserMatchVictim(Victim, Originator, Exception);
3245  break;
3246 
3247  default:
3248  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
3249  return INT_STATUS_NOT_SUPPORTED;
3250  }
3251 
3252  if (status == INT_STATUS_EXCEPTION_NOT_MATCHED)
3253  {
3254  // In this case don't overwrite the Action and Reason. If another exception was found and it failed
3255  // at extra checks or signature, then return that action&reason. Anyway, if no exception matched, then
3256  // we can safely return the default values (introGuestNotAllowed, introReasonNoException).
3257  return status;
3258  }
3259  else if (status == INT_STATUS_EXCEPTION_ALLOW)
3260  {
3261  *Action = introGuestAllowed;
3262  *Reason = feedbackException ? introReasonAllowedFeedback : introReasonAllowed;
3263  }
3264  else
3265  {
3266  ERROR("[ERROR] IntExceptMatchVictim `%d` failed: 0x%08x. Will ignore this exception!\n",
3267  ExceptionType, status);
3268 
3269  *Action = introGuestNotAllowed;
3270  *Reason = introReasonInternalError;
3271 
3272  return status;
3273  }
3274 
3275  // 2. Do we have any extra thing to verify (like the imports, exports, etc.) ?
3276  switch (ExceptionType)
3277  {
3278  case exceptionTypeKm:
3279  status = IntExceptKernelVerifyExtra(Victim, Originator, Exception);
3280  break;
3281 
3282  case exceptionTypeUm:
3283  status = IntExceptUserVerifyExtra(Victim, Originator, Exception);
3284  break;
3285 
3286  case exceptionTypeUmGlob:
3287  status = IntExceptUserVerifyExtraGlobMatch(Victim, Originator, Exception);
3288  break;
3289 
3290  case exceptionTypeKmUm:
3291  status = IntExceptKernelUserVerifyExtra(Victim, Originator, Exception);
3292  break;
3293 
3294  default:
3295  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
3296  return INT_STATUS_NOT_SUPPORTED;
3297  }
3298 
3299  if (status == INT_STATUS_EXCEPTION_CHECKS_FAILED)
3300  {
3301  *Action = introGuestNotAllowed;
3302 
3303  // Checks have more priority than exception searching. But not more than signatures!
3304  if (*Reason != introReasonSignatureNotMatched)
3305  {
3306  *Reason = introReasonExtraChecksFailed;
3307  }
3308 
3310  }
3311  else if (status == INT_STATUS_EXCEPTION_CHECKS_OK)
3312  {
3313  *Action = introGuestAllowed;
3314  *Reason = feedbackException ? introReasonAllowedFeedback : introReasonAllowed;
3315  }
3316  else
3317  {
3318  ERROR("[ERROR] IntExceptVerfiyExtra Type: `%d` failed: 0x%08x. Will ignore this exception!\n",
3319  ExceptionType, status);
3320 
3321  *Action = introGuestNotAllowed;
3322  *Reason = introReasonInternalError;
3323 
3324  return status;
3325  }
3326 
3327  // 3. Check the signature
3328  status = IntExceptVerifySignature(Exception, Originator, Victim, ExceptionType, Reason);
3329  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
3330  {
3331  // Signatures have the most priority. We overwrite the action every time.
3332  *Action = introGuestNotAllowed;
3333 
3335  }
3336  else if (status == INT_STATUS_SIGNATURE_MATCHED)
3337  {
3338  *Action = introGuestAllowed;
3339  *Reason = feedbackException ? introReasonAllowedFeedback : introReasonAllowed;
3340  }
3341  else
3342  {
3343  ERROR("[ERROR] IntExceptVerifySignature failed: 0x%08x. Will ignore this exception!\n", status);
3344 
3345  *Action = introGuestNotAllowed;
3346  *Reason = introReasonInternalError;
3347 
3348  return status;
3349  }
3350 
3351  // If we get to this point, then allow the action
3353 }
3354 
3355 
3356 void
3358  _In_ EXCEPTION_VICTIM_ZONE *Victim,
3359  _In_ void *Originator,
3360  _In_ EXCEPTION_TYPE Type,
3361  _Out_ INTRO_ACTION *Action,
3362  _Out_ INTRO_ACTION_REASON *Reason,
3363  _In_ INTRO_EVENT_TYPE EventClass
3364  )
3378 {
3379  INTSTATUS status;
3380  static BOOLEAN showNotLoadedWarning = TRUE;
3381 
3382  UNREFERENCED_PARAMETER(EventClass);
3383 
3384  if (Action != NULL)
3385  {
3386  *Action = introGuestNotAllowed;
3387  }
3388 
3389  if (Reason != NULL)
3390  {
3391  *Reason = introReasonInternalError;
3392  }
3393 
3394  if (NULL == Victim)
3395  {
3396  ERROR("[ERROR] The 'Victim' argument for exceptions mechanism is invalid!\n");
3397  return;
3398  }
3399 
3400  if (NULL == Originator)
3401  {
3402  ERROR("[ERROR] The 'Originator' argument for exceptions mechanism is invalid!\n");
3403  return;
3404  }
3405 
3406  if (NULL == Action)
3407  {
3408  ERROR("[ERROR] The 'Action' argument for exceptions mechanism is invalid!\n");
3409  return;
3410  }
3411 
3412  if (NULL == Reason)
3413  {
3414  ERROR("[ERROR] The 'Reason' argument for exceptions mechanism is invalid!\n");
3415  return;
3416  }
3417 
3418  // Default values. If beta is enabled, let the caller handle that
3419  *Action = introGuestNotAllowed;
3420  *Reason = introReasonNoException;
3421 
3422  if (NULL == gGuest.Exceptions || !gGuest.Exceptions->Loaded)
3423  {
3424  if (showNotLoadedWarning)
3425  {
3426  LOG("**************************************************\n");
3427  LOG("************Exceptions are not loaded*************\n");
3428  LOG("**************************************************\n");
3429 
3430  showNotLoadedWarning = FALSE;
3431  }
3432 
3433  *Action = introGuestAllowed;
3435  return;
3436  }
3437 
3438  switch(Type)
3439  {
3440  case exceptionTypeKm:
3441  status = IntExceptKernel(Victim, Originator, Action, Reason);
3442  break;
3443  case exceptionTypeUm:
3444  status = IntExceptUser(Victim, Originator, Action, Reason);
3445  break;
3446  case exceptionTypeKmUm:
3447  status = IntExceptKernelUser(Victim, Originator, Action, Reason);
3448  break;
3449 
3450  default:
3451  ERROR("[ERROR] Invalid exception type (%d)...\n", Type);
3452  return;
3453  }
3454 
3455  if (status != INT_STATUS_EXCEPTION_NOT_MATCHED && !INT_SUCCESS(status))
3456  {
3457  ERROR("[ERROR] IntExcept failed for type %d with status: 0x%08x . Will ignore this exception!\n", Type, status);
3458  }
3459 
3460  switch(Type)
3461  {
3462  case exceptionTypeKm:
3463  IntExceptKernelLogInformation(Victim, Originator, *Action, *Reason);
3464  break;
3465  case exceptionTypeUm:
3466  IntExceptUserLogInformation(Victim, Originator, *Action, *Reason);
3467  break;
3468 
3469  case exceptionTypeKmUm:
3470  IntExceptKernelUserLogInformation(Victim, Originator, *Action, *Reason);
3471  break;
3472 
3473  default:
3474  ERROR("[ERROR] Invalid exception type (%d)...\n", Type);
3475  break;
3476  }
3477 
3478  // IntSerializeException(Victim, Originator, Type, *Action, *Reason, EventClass);
3479 
3480  if (Victim->ZoneType == exceptionZoneEpt)
3481  {
3482  IntExceptInvCbCacheByGva(Victim->Ept.Gva);
3483  }
3484  else if (Victim->ZoneType == exceptionZoneIntegrity)
3485  {
3486  IntExceptInvCbCacheByGva(Victim->Integrity.StartVirtualAddress);
3487  }
3488 }
WINUM_PATH * Path
Module path.
Definition: winummodule.h:62
#define IMAGE_SCN_MEM_EXECUTE
Definition: winpe.h:472
The range-identifier used for value-code signature.
Definition: exceptions.h:78
PCHAR CommandLine
The command line with which the process was created (can be NULL).
Definition: winprocess.h:114
BOOLEAN ExportDirRead
True if the exports directory has been read.
Definition: winumcache.h:101
#define _In_opt_
Definition: intro_sal.h:16
INTSTATUS IntExceptKernel(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
This function iterates through exception lists and tries to find an exception that matches the origin...
void IntExcept(EXCEPTION_VICTIM_ZONE *Victim, void *Originator, EXCEPTION_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason, INTRO_EVENT_TYPE EventClass)
This function is the entry point for the exception mechanism.
Definition: exceptions.c:3357
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
#define DESCRIPTOR_SIZE_32
Definition: processor.h:101
#define for_each_version_os_signature(_ex_head, _var_name)
Definition: exceptions.h:1084
#define INT_STATUS_EXCEPTION_NOT_MATCHED
Definition: introstatus.h:406
INTSTATUS IntExceptMatchException(void *Victim, void *Originator, void *Exception, EXCEPTION_TYPE ExceptionType, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
This function tries to find a exception for the current violation..
Definition: exceptions.c:3167
INTSTATUS IntPeGetSectionHeaderByRva(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD GuestRva, IMAGE_SECTION_HEADER *SectionHeader)
Given a relative virtual address, return the section header which describes the section the RVA lies ...
Definition: winpe.c:707
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
#define CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
DWORD Count
The number of the code-blocks.
Definition: exceptions.c:48
QWORD Cr3
The CR3 for this process.
Definition: lixprocess.h:70
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
INTSTATUS IntExceptKernelVerifyExtra(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, UM_EXCEPTION *Exception)
This function is used as an extra step in exception mechanism.
The creation of a process was attempted while the parent had its heap sprayed.
Definition: intro_types.h:1666
#define IC_TAG_EXCP
Exception structure.
Definition: memtags.h:22
INTSTATUS IntWinThrGetCurrentStackBaseAndLimit(QWORD *TibBase, QWORD *StackBase, QWORD *StackLimit)
Obtains the stack base, stack limit and TIB address of the current thread.
Definition: winthread.c:321
#define INT_STATUS_EXCEPTION_CHECKS_FAILED
Definition: introstatus.h:411
An internal error occurred (no memory, pages not present, etc.).
Definition: intro_types.h:195
The exception ID. The layout consists of the exception type and the unique identifier of the exceptio...
Definition: exceptions.h:238
The value hash is for the process command line (valid only for value signature).
Definition: exceptions.h:711
Kernel module (ntoskrnl.exe, hal.dll, etc.).
Definition: intro_types.h:238
uint8_t BYTE
Definition: intro_types.h:47
static INTSTATUS IntExceptWinGetVictimDriver(KERNEL_DRIVER *Driver, EXCEPTION_VICTIM_ZONE *Victim)
This function get the information from KERNEL_DRIVER and fill the information required by EXCEPTION_V...
Definition: exceptions.c:562
Describe a export signature hash.
Definition: exceptions.h:387
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
Definition: winguest.c:37
LIST_HEAD KernelUserExceptions[EXCEPTION_TABLE_SIZE]
Array of linked lists used for kernel-user mode exceptions.
Definition: exceptions.h:108
LIST_HEAD ValueCodeSignatures
Linked list used for value-code signatures.
Definition: exceptions.h:133
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
DWORD IatSize
Size of the imports table.
Definition: winumcache.h:88
DWORD Index
The VCPU number.
Definition: guests.h:172
DWORD Crc32Compute(const void *Buffer, size_t Size, DWORD InitialCrc)
Computes the CRC for a byte array.
Definition: crc32.c:103
#define _In_
Definition: intro_sal.h:21
Describe a kernel-user mode exception.
Definition: exceptions.h:275
INTSTATUS IntPeGetDirectory(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD DirectoryEntry, IMAGE_DATA_DIRECTORY *Directory)
Validate & return the indicated image data directory.
Definition: winpe.c:552
The signature is valid only on 64 bit systems/processes.
Definition: exceptions.h:706
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
Fast IO Dispatch (Windows only).
Definition: intro_types.h:236
An interrupt object from KPRCB.
Definition: intro_types.h:274
LIST_HEAD NoNameKernelExceptions
Linked list used for kernel-mode exceptions that don&#39;t have a valid originator (-).
Definition: exceptions.h:97
#define PAGE_REMAINING(addr)
Definition: pgtable.h:163
Infinity hook modifications of WMI_LOGGER_CONTEXT.GetCpuClock.
Definition: intro_types.h:264
Describes a value signature.
Definition: exceptions.h:415
INTSTATUS IntExceptKernelUserVerifyExtra(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, UM_EXCEPTION *Exception)
This function is used as an extra step in exception mechanism.
#define for_each_process_creation_signature(_ex_head, _var_name)
Definition: exceptions.h:1088
void IntExceptInvCbCacheByCr3(QWORD Cr3)
Invalidate the cache used for code blocks for a given CR3.
Definition: exceptions.c:102
static void IntExceptRemoveUmGlobListExceptions(LIST_HEAD *ListHead)
This function removes and frees all entries from a user-mode glob exceptions list.
Definition: exceptions.c:236
DWORD Build
Definition: exceptions.h:141
static INTSTATUS IntExceptVerifyVersionIntroSignature(void *Exception, EXCEPTION_SIGNATURE_ID *Signatures, DWORD SignaturesCount)
This function checks if the version of the introspection is in the minimum-maximum range...
Definition: exceptions.c:2561
#define ZONE_LIB_RESOURCES
Used for the resources section (usually .rsrc inside a driver or dll).
Definition: exceptions.h:726
User-mode exception.
Definition: exceptions.h:60
User-mode non executable zone.
Definition: intro_types.h:247
LIST_HEAD GenericUserExceptions
Linked list used for user-mode exceptions that have a generic originator(*).
Definition: exceptions.h:91
#define INTRO_OPT_PROT_KM_NT
Enable kernel image protection (Windows only).
Definition: intro_types.h:408
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
LIST_HEAD ExportSignatures
Linked list used for export signatures.
Definition: exceptions.h:131
LIST_HEAD ProcessCreationAlertExceptions
Linked list used for process-creation exceptions that are added from alert.
Definition: exceptions.h:122
long long my_llabs(long long value)
Definition: introcrt.c:600
The exception sends a feedback alert.
Definition: exceptions.h:595
UINT32 VirtualAddress
Definition: winpe.h:98
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
INTSTATUS IntFragExtractCodeBlocks(BYTE *Buffer, DWORD MaxBufferSize, IG_CS_TYPE CsType, CB_EXTRACT_LEVEL ExtractLevel, DWORD *HashesCount, DWORD *Hashes)
Extract a block of code-block hashes from the given code buffer.
Definition: codeblocks.c:746
DWORD CsType
The CS type.
Definition: exceptions.c:49
#define PAGE_OFFSET
Definition: pgtable.h:32
The action was not allowed because there was no reason to allow it.
Definition: intro_types.h:183
#define ARRAYSIZE(A)
Definition: introdefs.h:101
The modified object is inside an EPT hook.
Definition: exceptions.h:746
#define INT_STATUS_SIGNATURE_MATCHED
Definition: introstatus.h:401
LIST_HEAD VersionIntroSignatures
Linked list used for introspection version signatures.
Definition: exceptions.h:136
#define INT_STATUS_EXCEPTION_CHECKS_OK
Definition: introstatus.h:396
Describe a user-mode glob exception.
Definition: exceptions.h:336
LIST_HEAD ProcessCreationSignatures
Linked list used for process-creation signatures.
Definition: exceptions.h:137
LIST_HEAD IdtSignatures
Linked list used for IDT signatures.
Definition: exceptions.h:134
static INTSTATUS IntExceptVerifyIdtSignature(void *Exception, void *Originator, PEXCEPTION_VICTIM_ZONE Victim, EXCEPTION_SIGNATURE_ID *Signatures, DWORD SignaturesCount, EXCEPTION_TYPE ExceptionType)
This function checks if the modified IDT entry matches the entry from the given exception.
Definition: exceptions.c:2219
#define IntExceptErase(Ptr, Tag)
Frees an exception or a signature buffer and removes it from the list it is currently in...
Definition: exceptions.h:1384
#define ERROR(fmt,...)
Definition: glue.h:62
#define CB_CACHE_FLG_ORIGINAL
Indicates that the gCodeBlocksOriginalCache should be used.
Definition: exceptions.c:73
LIST_HEAD UserAlertExceptions
Linked list used for user-mode exceptions that are added from alert.
Definition: exceptions.h:124
Describes a user-mode originator.
Definition: exceptions.h:994
LIX_TASK_PATH * Path
The path of the file executed.
Definition: lixprocess.h:50
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
static CB_CACHE gCodeBlocksOriginalCache
Cache for code blocks extracted from an originator.
Definition: exceptions.c:62
The name can be any string.
Definition: exceptions.h:687
The range-identifier used for idt signature.
Definition: exceptions.h:77
LIST_HEAD UserExceptions[EXCEPTION_TABLE_SIZE]
Array of linked lists used for user-mode exceptions.
Definition: exceptions.h:109
int INTSTATUS
The status data type.
Definition: introstatus.h:24
struct _WINUM_MODULE_CACHE::@242 Info
__pure INTSTATUS IntFragMatchSignature(const DWORD *Hashes, DWORD CodeBlocksCount, const SIG_CODEBLOCKS *ExceptionSignature)
Match a block of code-block hashes against a list of code-block exception signatures.
Definition: codeblocks.c:912
DWORD OSVersion
Os version.
Definition: guests.h:281
QWORD gEventId
The ID of the current event.
Definition: glue.c:55
QWORD Rip
The RIP from which the write came from.
Definition: exceptions.c:47
BOOLEAN Loaded
True if the exceptions are loaded.
Definition: exceptions.h:146
DWORD CodeBlocks[PAGE_SIZE/sizeof(DWORD)]
The code-blocks array.
Definition: exceptions.c:51
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
DWORD NameHash
Name hash, as used by the exceptions module.
Definition: winprocess.h:101
DWORD NumberOfServices
The number of entries in the SSDT.
Definition: winguest.h:819
The exception is valid only for Linux.
Definition: exceptions.h:603
static DWORD gValueBufferSize
The size, in bytes, of the gValueBuffer buffer.
Definition: exceptions.c:37
#define ONE_KILOBYTE
Definition: introdefs.h:89
LIST_HEAD KernelAlertExceptions
Linked list used for kernel-mode exceptions that are added from alert.
Definition: exceptions.h:126
DWORD EatRva
RVA of the exports table.
Definition: winumcache.h:84
INTSTATUS IntExceptUserVerifyExtra(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, UM_EXCEPTION *Exception)
This function is used as an extra step in exception mechanism that verify the initialization flags of...
#define CB_CACHE_FLG_RETURN
Indicated that the gCodeBlocksReturnCache cache should be used.
Definition: exceptions.c:71
void IntExceptKernelUserLogInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-user mode violation and dumps the code-blocks.
WORD Minor
Minor version.
Definition: intro_types.h:2403
Integrity protection of SharedUserData region.
Definition: intro_types.h:273
Describes a kernel-mode originator.
Definition: exceptions.h:943
User-mode exception that accepts glob content.
Definition: exceptions.h:62
#define IC_TAG_ESIG
Exception signatures structures.
Definition: memtags.h:26
Codeblocks were extracted at a medium level.
Definition: exceptions.h:708
#define for_each_idt_signature(_ex_head, _var_name)
Definition: exceptions.h:1082
The range-identifier used for value signature.
Definition: exceptions.h:76
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
struct _CB_CACHE CB_CACHE
Describes a code-blocks cache entry.
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
Definition: guests.h:88
QWORD VirtualBase
Guest virtual address of the loaded module.
Definition: winummodule.h:34
Process ACL (SACL/DACL) was modified.
Definition: intro_types.h:272
INTSTATUS IntExceptUninit(void)
This function removes and frees all exceptions and signatures.
Definition: exceptions.c:513
The range-identifier used for process creation signature.
Definition: exceptions.h:74
#define MIN(a, b)
Definition: introdefs.h:146
static INTSTATUS IntExceptVerifySignature(void *Exception, void *Originator, EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_TYPE ExceptionType, INTRO_ACTION_REASON *Reason)
Iterates all signatures from the given exception and call the suitable function for that signature ty...
Definition: exceptions.c:2736
WIN_PROCESS_OBJECT * WinProc
The windows process that&#39;s modifying the memory (always present).
Definition: exceptions.h:1007
INTRO_PC_VIOLATION_TYPE PcType
Valid if the current violation is DPI Process Creation Violation.
Definition: exceptions.h:1041
DWORD CommHash
The CRC32 checksum of the Comm field.
Definition: lixprocess.h:65
struct _EXCEPTION_KM_ORIGINATOR::@63 Return
WORD Build
Build number.
Definition: intro_types.h:2401
void * IntHookObjectFindRegion(QWORD Gva, void *HookObject, BYTE HookType)
Searches for a region of hooked memory inside the provided hook object.
Definition: hook_object.c:424
QWORD SourceVA
The GVA from where the injection is.
Definition: exceptions.h:1020
QWORD Start
Start of the memory described by the VMA.
Definition: lixmm.h:19
The name is missing.
Definition: exceptions.h:692
#define LOG(fmt,...)
Definition: glue.h:61
32-bit selector.
Definition: glueiface.h:187
char * CmdLine
The process command line.
Definition: lixprocess.h:48
Describes a kernel driver.
Definition: drivers.h:30
DWORD Wow64Process
TRUE if this is a 32 bit process on a 64 bit OS.
Definition: winprocess.h:125
INTSTATUS IntFragDumpBlocks(PBYTE Buffer, QWORD StartAddress, DWORD MaxBufferSize, IG_CS_TYPE CsType, CB_EXTRACT_LEVEL ExtractLevel, QWORD Rip, BOOLEAN ReturnRip)
Dumps code-blocks that can then be used to generate an exception signature.
Definition: codeblocks.c:1293
DWORD AccessSize
The size of the memory access. Valid only for EPT exits.
Definition: guests.h:103
static CB_CACHE gCodeBlocksReturnCache
Cache for code blocks extracted from a return originator.
Definition: exceptions.c:68
#define PAGE_FRAME_NUMBER(addr)
Definition: pgtable.h:181
static BOOLEAN IntExceptSignaturesHasType(EXCEPTION_SIGNATURE_ID *Signatures, DWORD Count, EXCEPTION_SIGNATURE_TYPE Type)
This function checks if any signature from an signature-array has the given type. ...
Definition: exceptions.c:2708
Exposes the functions used to provide Windows Threads related support.
QWORD Cr3
Process PDBR. Includes PCID.
Definition: winprocess.h:98
Token privileges.
Definition: intro_types.h:266
INTSTATUS IntGetCurrentMode(DWORD CpuNumber, DWORD *Mode)
Read the current CS type.
Definition: introcpu.c:977
LIST_HEAD CbSignatures
Linked list used for codeblocks signatures.
Definition: exceptions.h:130
enum _INTRO_OBJECT_TYPE INTRO_OBJECT_TYPE
The type of the object protected by an EPT hook.
#define SIG_FOUND
Signals that a signature matched.
Definition: patsig.h:15
#define _Inout_
Definition: intro_sal.h:20
The range-identifier used for export signature.
Definition: exceptions.h:75
struct _CB_CACHE * PCB_CACHE
TIMER_FRIENDLY void IntDumpInstruction(INSTRUX *Instruction, QWORD Rip)
This function dumps a given instruction (textual disassembly).
Definition: dumper.c:583
LIST_HEAD KernelUserAlertExceptions
Linked list used for kernel-user mode exceptions that are added from alert.
Definition: exceptions.h:128
#define ZONE_LIB_CODE
Used for a generic code zone.
Definition: exceptions.h:723
LIX_VMA * IntLixMmFindVmaByRange(const LIX_TASK_OBJECT *Process, QWORD Address)
Finds if a memory address inside a process is being protected and returns the corresponding LIX_VMA s...
Definition: lixmm.c:699
#define for_each_value_signature(_ex_head, _var_name)
Definition: exceptions.h:1078
#define INITIAL_CRC_VALUE
Definition: introdefs.h:221
Hal interrupt controller.
Definition: intro_types.h:253
EXCEPTIONS * Exceptions
The exceptions that are currently loaded.
Definition: guests.h:392
Describes an operand value.
Definition: decoder.h:50
#define IS_KERNEL_POINTER_LIX(p)
Definition: lixguest.h:11
static INTSTATUS IntExceptVerifyValueSig(void *Exception, void *Originator, EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_SIGNATURE_ID *Signatures, DWORD SignaturesCount, EXCEPTION_TYPE ExceptionType)
This function checks if the hash of the modified zone from the originator matches the hash from the g...
Definition: exceptions.c:1760
#define INT_STATUS_NOT_INITIALIZED
Definition: introstatus.h:266
#define SIG_NOT_FOUND
Signals that a signature was not matched.
Definition: patsig.h:13
QWORD QwordValues[ND_MAX_REGISTER_SIZE/8]
Definition: decoder.h:57
#define EXCEPTION_CODEBLOCKS_OFFSET
The maximum offset for codeblocks extraction.
Definition: exceptions.h:53
#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
The modified object is inside an integrity hook.
Definition: exceptions.h:749
DWORD Hash
The hash of the modified zone.
Definition: exceptions.h:380
QWORD EventId
The current event ID.
Definition: exceptions.c:53
#define for_each_version_intro_signature(_ex_head, _var_name)
Definition: exceptions.h:1086
LIX_TASK_OBJECT * LixProc
The Linux process that&#39;s modifying the memory (always present).
Definition: exceptions.h:1008
LIST_HEAD KernelFeedbackExceptions
Linked list used for kernel-mode exceptions that have the feedback flag.
Definition: exceptions.h:115
#define IC_TAG_EXKM
Kernel exceptions structures.
Definition: memtags.h:23
#define IN_RANGE(x, start, end)
Definition: introdefs.h:167
Holds information about a driver object.
Definition: windrvobj.h:13
#define memzero(a, s)
Definition: introcrt.h:35
QWORD End
End of the memory described by the VMA.
Definition: lixmm.h:20
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
CHAR Name[IMAGE_BASE_NAME_LEN]
Process base name.
Definition: winprocess.h:108
The name is the operating system kernel name.
Definition: exceptions.h:642
enum _EXCEPTION_TYPE EXCEPTION_TYPE
The type of an exception.
The signature is valid only on 32 bit systems/processes.
Definition: exceptions.h:705
INTSTATUS IntExceptAlertRemove(void)
This function removes and frees all exceptions and signatures that have been added from alert...
Definition: exceptions.c:382
void IntExceptUserLogInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a user-mode violation, dumps the code-blocks and the injection buffer...
#define IN_RANGE_LEN(x, start, len)
Definition: introdefs.h:175
static INTSTATUS IntExceptVerifyValueCodeSig(void *Exception, void *Originator, EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_SIGNATURE_ID *Signatures, DWORD SignaturesCount, EXCEPTION_TYPE ExceptionType)
This function checks if the opcodes from the originator&#39;s RIP match the opcodes pattern from the give...
Definition: exceptions.c:1507
#define TRUE
Definition: intro_types.h:30
QWORD Ssdt
Guest virtual address of the SSDT structure inside the kernel.
Definition: winguest.h:818
union _OPERAND_VALUE::@22 Value
The actual operand value.
Describe a value signature hash.
Definition: exceptions.h:376
TIMER_FRIENDLY void IntDumpBuffer(const void *Buffer, QWORD Gva, DWORD Length, DWORD RowLength, DWORD ElementLength, BOOLEAN LogHeader, BOOLEAN DumpAscii)
This function dumps a given buffer in a user friendly format.
Definition: dumper.c:48
#define TRACE(fmt,...)
Definition: glue.h:58
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
This includes instructions until codeInsBt.
Definition: codeblocks.h:16
static void IntExceptRemoveUmListExceptions(LIST_HEAD *ListHead)
This function removes and frees all entries from a user-mode exceptions list.
Definition: exceptions.c:215
The range-identifier used for version operating system signature.
Definition: exceptions.h:72
#define INT_STATUS_INVALID_PARAMETER_5
Definition: introstatus.h:74
INTSTATUS IntExceptKernelUser(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
This function iterates through exception lists and tries to find an exception that matches the origin...
struct _EXCEPTIONS::@26 Version
Loaded exceptions binary version.
Describes the internal exceptions data.
Definition: exceptions.h:86
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:283
void IntExceptKernelLogInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-mode violation and dumps the code-blocks.
INTSTATUS IntExceptUserVerifyExtraGlobMatch(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, UM_EXCEPTION_GLOB *Exception)
This function is used as an extra step in exception mechanism that verify the initialization flags of...
Kernel-mode exception.
Definition: exceptions.h:61
struct _WIN_PROCESS_OBJECT * Process
The process object related to this subsystem.
Definition: winprocess.h:56
void * HookObject
Module hook object.
Definition: winummodule.h:68
#define DESCRIPTOR_SIZE_64
Definition: processor.h:102
INT_VERSION_INFO IntHviVersion
The version of the introcore library.
Definition: introcore.c:27
LIST_HEAD KernelUserFeedbackExceptions
Linked list used for kernel-user mode exceptions that have the feedback flag.
Definition: exceptions.h:117
QWORD Cr3
The CR3 of the process from which the write came from.
Definition: exceptions.c:50
void IntExceptDumpSignatures(void *Originator, EXCEPTION_VICTIM_ZONE *Victim, BOOLEAN KernelMode, BOOLEAN ReturnDrv)
Dump code blocks from the originator&#39;s RIP.
Definition: exceptions.c:2978
WORD Major
Major version.
Definition: intro_types.h:2404
The modified object is a MSR.
Definition: exceptions.h:747
struct _INT_VERSION_INFO::@339 VersionInfo
Structured version information.
#define WARNING(fmt,...)
Definition: glue.h:60
The exception will take into consideration the return driver.
Definition: exceptions.h:614
#define ZONE_LIB_EXPORTS
Used for the exports of a dll, driver, etc.
Definition: exceptions.h:722
DWORD Size
The operand size.
Definition: decoder.h:60
static void InitializeListHead(LIST_ENTRY *ListHead)
Definition: introlists.h:69
static BYTE * gValueBuffer
Pre-allocated buffer used to match value signatures.
Definition: exceptions.c:34
#define PAGE_SIZE
Definition: common.h:70
Describes the modified zone.
Definition: exceptions.h:893
INTSTATUS IntExceptInit(void)
This function allocates the exceptions data and initialize the exception lists and the signature list...
Definition: exceptions.c:441
#define IC_TAG_EXUM
User exceptions structures.
Definition: memtags.h:25
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
char * Name
The path base name.
Definition: lixprocess.h:27
#define IMAGE_DIRECTORY_ENTRY_EXPORT
Definition: winpe.h:20
This includes instructions until codeInsFlags.
Definition: codeblocks.h:17
DWORD NameHash
The CRC32 hash of the name. Used for fast matching.
Definition: winumpath.h:23
Describe a kernel-mode exception.
Definition: exceptions.h:253
Describe a user-mode exception.
Definition: exceptions.h:308
Executions inside the SharedUserData region.
Definition: intro_types.h:267
The Virtualization exception agent injected inside the guest.
Definition: intro_types.h:259
uint32_t DWORD
Definition: intro_types.h:49
static INTSTATUS IntExceptLixGetVictimDriver(KERNEL_DRIVER *Driver, EXCEPTION_VICTIM_ZONE *Victim)
Fills an EXCEPTION_VICTIM_ZONE with the relevant information from a KERNEL_DRIVER.
Definition: exceptions.c:680
#define EXCEPTION_TABLE_SIZE
Definition: exceptions.h:49
UINT32 Characteristics
Definition: winpe.h:92
LIST_HEAD GlobUserExceptions
Linked list used for user-mode exceptions that contains glob content.
Definition: exceptions.h:105
User-mode library.
Definition: intro_types.h:248
DWORD Hash
The hash of the modified function name.
Definition: exceptions.h:390
static INTSTATUS IntExceptVerifyExportSig(void *Exception, void *Originator, EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_SIGNATURE_ID *Signatures, DWORD SignaturesCount, EXCEPTION_TYPE ExceptionType)
Checks if the modified library from the originator matches the library from the given exception...
Definition: exceptions.c:2027
char gExcLogLine[2 *ONE_KILOBYTE]
The exception log line.
Definition: exceptions.c:40
DWORD EatSize
Size of the exports table.
Definition: winumcache.h:85
#define INT_STATUS_INVALID_PARAMETER_6
Definition: introstatus.h:77
The exception file was not loaded (there are no exceptions).
Definition: intro_types.h:193
enum _INTRO_ACTION INTRO_ACTION
Event actions.
LIST_HEAD ProcessCreationExceptions
Linked list used for process creations exceptions.
Definition: exceptions.h:110
#define IMAGE_SCN_CNT_CODE
Definition: winpe.h:425
QWORD Rip
The RIP from where the call to the exported function came.
Definition: exceptions.h:950
LIST_HEAD GenericKernelExceptions
Linked list used for kernel-mode exceptions that have a generic originator (*).
Definition: exceptions.h:89
The action was allowed, but it has the BETA flag (Introcore is in log-only mode). ...
Definition: intro_types.h:185
Describes a code-blocks cache entry.
Definition: exceptions.c:45
WCHAR * Name
The name of the module contained in the path.
Definition: winumpath.h:18
INTSTATUS IntExceptGetVictimEpt(void *Context, QWORD Gpa, QWORD Gva, INTRO_OBJECT_TYPE Type, DWORD ZoneFlags, EXCEPTION_VICTIM_ZONE *Victim)
Fills an EXCEPTION_VICTIM_ZONE with relevant information from an EPT violation.
Definition: exceptions.c:742
#define IMAGE_DIRECTORY_ENTRY_RESOURCE
Definition: winpe.h:22
static DWORD IntExceptExtendedPatternMatch(const BYTE *Buffer, DWORD Length, const SIG_VALUE_CODE *Sig, DWORD IndexPattern)
Try to match the given buffer with the given signature.
Definition: exceptions.c:127
__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 ZONE_LIB_DATA
Definition: exceptions.h:724
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
LIST_HEAD ValueSignatures
Linked list used for value signatures.
Definition: exceptions.h:132
char Comm[LIX_COMM_SIZE]
The short name of the executable.
Definition: lixprocess.h:44
Self mapping index in PDBR.
Definition: intro_types.h:254
QWORD KeServiceDescriptorTable
Guest virtual address of the KeServiceDescriptorTable variable.
Definition: winguest.h:817
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
static void IntExceptRemoveKmListExceptions(LIST_HEAD *ListHead)
This function removes and frees all entries from a kernel-mode exceptions list.
Definition: exceptions.c:173
The modified object is inside a process.
Definition: exceptions.h:750
WINUM_MODULE_CACHE * Cache
Module headers cache.
Definition: winummodule.h:63
#define IMAGE_DIRECTORY_ENTRY_IAT
Definition: winpe.h:33
INTSTATUS IntVirtMemRead(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer, DWORD *RetLength)
Reads data from a guest virtual memory range.
Definition: introcore.c:627
The signature is valid only on Linux.
Definition: exceptions.h:713
SSDT (Windows only).
Definition: intro_types.h:235
LIST_HEAD NoNameKernelUserExceptions
Linked list used for kernel-user mode exceptions that don&#39;t have a valid originator (-)...
Definition: exceptions.h:102
WIN_PROCESS_MODULE * WinLib
The windows library that&#39;s modifying the memory (if that&#39;s the case).
Definition: exceptions.h:1014
#define for_each_cb_signature(_ex_head, _var_name)
Definition: exceptions.h:1074
Introspection version info.
Definition: intro_types.h:2396
DWORD Type
Contains a type of signature (EXCEPTION_SIGNATURE_TYPE).
Definition: exceptions.h:243
LIST_HEAD ProcessCreationFeedbackExceptions
Linked list used for process-creation exceptions that have the feedback flag.
Definition: exceptions.h:119
#define for_each_value_code_signature(_ex_head, _var_name)
Definition: exceptions.h:1080
static INTSTATUS IntExceptVerifyVersionOsSignature(void *Exception, EXCEPTION_SIGNATURE_ID *Signatures, DWORD SignaturesCount)
This function checks if the version of the guest operating system is in the minimum-maximum range...
Definition: exceptions.c:2407
LIST_HEAD UserFeedbackExceptions
Linked list used for user-mode exceptions that have the feedback flag.
Definition: exceptions.h:113
The thread which created the process has started execution on some suspicious code.
Definition: intro_types.h:1672
Virtual SYSCALL (user-mode, Linux-only).
Definition: intro_types.h:257
struct _EXCEPTION_KM_ORIGINATOR::@64 Original
Definition: lixmm.h:14
int wstrcasecmp(const WCHAR *buf1, const WCHAR *buf2)
Definition: introcrt.c:98
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
LIST_HEAD KernelExceptions[EXCEPTION_TABLE_SIZE]
Array of linked lists used for kernel-mode exceptions.
Definition: exceptions.h:107
#define ZONE_READ
Used for read violation.
Definition: exceptions.h:735
#define ZONE_DEP_EXECUTION
Used for executions inside DEP zones.
Definition: exceptions.h:730
WINUM_CACHE_EXPORT * IntWinUmCacheGetExportFromRange(WIN_PROCESS_MODULE *Module, QWORD Gva, DWORD Length)
Tries to find an export in the range [Gva - Length, Gva].
Definition: winumcache.c:225
struct _EXCEPTION_SIGNATURE_ID::@27 Field
#define IC_TAG_EXKU
Kernel-User mode exceptions structures.
Definition: memtags.h:24
The action was blocked because no exception signature matched.
Definition: intro_types.h:187
Virtual dynamic shared object (user-mode, Linux-only).
Definition: intro_types.h:256
The range-identifier used for codeblocks signature.
Definition: exceptions.h:79
#define INT_STATUS_NOT_INITIALIZED_HINT
Definition: introstatus.h:320
LIST_HEAD GenericKernelUserExceptions
Linked list used for kernel-user mode exceptions that have a generic originator(*).
Definition: exceptions.h:94
INTSTATUS IntExceptRemove(void)
This function removes and frees all exceptions and signatures that have been added from exception bin...
Definition: exceptions.c:257
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
Kernel-User mode exception.
Definition: exceptions.h:63
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
INTSTATUS IntDecGetWrittenValueFromInstruction(PINSTRUX Instrux, PIG_ARCH_REGS Registers, PBYTE MemoryValue, OPERAND_VALUE *WrittenValue)
Decode a written value from a memory write instruction.
Definition: decoder.c:1861
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
LIX_TASK_OBJECT * IntLixTaskGetCurrent(DWORD CpuNumber)
Finds the task that is currently running on the given CPU.
Definition: lixprocess.c:858
UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]
Definition: winpe.h:79
enum _INTRO_EVENT_TYPE INTRO_EVENT_TYPE
Event classes.
struct _WIN_DRIVER_OBJECT * PWIN_DRIVER_OBJECT
64-bit selector.
Definition: glueiface.h:188
INTSTATUS IntExceptKernelUserMatchVictim(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, KUM_EXCEPTION *Exception)
This function checks if the exception matches the originator and the modified zone.
static INTSTATUS IntExceptVerifyCodeBlocksSig(void *Exception, void *Originator, EXCEPTION_SIGNATURE_ID *Signatures, DWORD SignatureCount, EXCEPTION_TYPE ExceptionType)
This function checks if the code blocks from the originator RIP match the code blocks from the given ...
Definition: exceptions.c:1151
#define ZONE_LIB_IMPORTS
Used for the imports of a dll, driver, etc.
Definition: exceptions.h:721
void * HookObject
The HookObject used for EPT hooks set inside this process&#39;s memory space.
Definition: lixprocess.h:92
Used for process-creation violations.
Definition: exceptions.h:752
INTSTATUS IntExceptUserMatchVictim(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, void *Exception, EXCEPTION_TYPE ExceptionType)
This function checks if the exception matches the originator and the modified zone.
PWIN_PROCESS_SUBSYSTEM Subsystem
Module subsystem.
Definition: winummodule.h:60
The range-identifier used for version introspection signature.
Definition: exceptions.h:73
BYTE Version
The version field of the version string.
Definition: lixguest.h:487
DWORD IatRva
RVA of the imports table.
Definition: winumcache.h:87
void IntExceptInvCbCacheByGva(QWORD Gva)
Invalidate the cache used for code blocks for a given guest virtual address.
Definition: exceptions.c:77
#define ZONE_MODULE_LOAD
Used for exceptions for double agent.
Definition: exceptions.h:731
Process security descriptor pointer.
Definition: intro_types.h:271
BYTE * Headers
A buffer containing the MZ/PE headers of this module.
Definition: winumcache.h:97
Write-access hook.
Definition: glueiface.h:299
#define PAGE_MASK
Definition: pgtable.h:35
#define ZONE_WRITE
Used for write violation.
Definition: exceptions.h:734
WORD Revision
Revision.
Definition: intro_types.h:2402
static INTSTATUS IntExceptVerifyProcessCreationSignature(void *Exception, void *Originator, EXCEPTION_SIGNATURE_ID *Signatures, DWORD SignaturesCount, EXCEPTION_TYPE ExceptionType)
Checks if the DPI mask of the newly created process match the DPI mask from the given exception...
Definition: exceptions.c:2323
INTSTATUS IntExceptUser(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
This function iterates through exception lists and tries to find an exception that matches the origin...
static void IntExceptRemoveKernelUserListExceptions(LIST_HEAD *ListHead)
This function removes and frees all entries from a kernel-user mode exceptions list.
Definition: exceptions.c:194
LIST_HEAD NoNameUserExceptions
Linked list used for user-mode exceptions that don&#39;t have a valid originator (-). ...
Definition: exceptions.h:99
QWORD Rip
Where the write/exec came.
Definition: exceptions.h:1019
The name is the operating system HAL name (valid only for windows).
Definition: exceptions.h:643
#define INT_STATUS_SIGNATURE_NOT_FOUND
Definition: introstatus.h:416
static QWORD gUsedRips[255]
Cache of RIPs from which code blocks were already dumped.
Definition: exceptions.c:23
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:30
#define for_each_export_signature(_ex_head, _var_name)
Definition: exceptions.h:1076
#define INT_STATUS_EXCEPTION_ALLOW
Definition: introstatus.h:391
INTSTATUS IntExceptKernelMatchVictim(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, KM_EXCEPTION *Exception)
This function checks if the exception matches the originator and the modified zone.
#define FALSE
Definition: intro_types.h:34
This structure describes a running process inside the guest.
Definition: winprocess.h:83
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
enum _EXCEPTION_SIGNATURE_TYPE EXCEPTION_SIGNATURE_TYPE
The identifier that describes a range of signatures.
The exception (and signature, where&#39;s the case) matched, but the extra checks failed.
Definition: intro_types.h:191
LIST_HEAD VersionOsSignatures
Linked list used for operating system version signatures.
Definition: exceptions.h:135