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  {
1066  Victim->Object.Process = Context;
1067  Victim->Object.Name = ((WIN_PROCESS_OBJECT *)Context)->Name;
1068  Victim->Object.NameHash = ((WIN_PROCESS_OBJECT *)Context)->NameHash;
1069  Victim->Object.BaseAddress = Gva & PAGE_MASK;
1070 
1071  break;
1072  }
1073 
1075  {
1076  break;
1077  }
1078 
1079  default:
1080  WARNING("[WARNING] Shouldn't reach here (for now). Type is %d (original %d)...\n", Victim->Object.Type, Type);
1081  return INT_STATUS_NOT_SUPPORTED;
1082  }
1083 
1084  if (Victim->Object.Type != introObjectTypeUmGenericNxZone &&
1085  Victim->Object.Type != introObjectTypeHalHeap &&
1086  Victim->Object.Type != introObjectTypeSharedUserData &&
1087  (Victim->Object.Type != introObjectTypeVeAgent || (Victim->ZoneFlags & ZONE_WRITE) != 0))
1088  {
1089  if (!(ZONE_READ & Victim->ZoneFlags))
1090  {
1091  DWORD writeSize = gVcpu->Instruction.Operands[0].Size;
1092 
1093  if (writeSize > sizeof(Victim->WriteInfo.OldValue) || writeSize == 0)
1094  {
1095  ERROR("[ERROR] Accessed size is too large or 0: 0x%x\n", writeSize);
1096  return INT_STATUS_NOT_SUPPORTED;
1097  }
1098 
1099  status = IntVirtMemRead(Gva, writeSize, 0, Victim->WriteInfo.OldValue, NULL);
1100  if (!INT_SUCCESS(status))
1101  {
1102  WARNING("[WARNING] IntVirtMemRead failed for GVA 0x%016llx: 0x%08x\n", Gva, status);
1103  Victim->WriteInfo.OldValue[0] = 0xbaddead;
1104  }
1105 
1107  &gVcpu->Regs,
1108  NULL,
1109  &operandValue);
1110  if (!INT_SUCCESS(status))
1111  {
1112  WARNING("[WARNING] Failed getting operands for instruction %s: 0x%08x\n",
1113  gVcpu->Instruction.Mnemonic, status);
1115 
1116  Victim->WriteInfo.NewValue[0] = 0xbaddead;
1117  Victim->WriteInfo.AccessSize = gVcpu->AccessSize;
1118  }
1119  else
1120  {
1121  memcpy(Victim->WriteInfo.NewValue, operandValue.Value.QwordValues, operandValue.Size);
1122  Victim->WriteInfo.AccessSize = operandValue.Size;
1123  }
1124  }
1125  else
1126  {
1127  if (gVcpu->AccessSize > sizeof(Victim->ReadInfo.Value) || gVcpu->AccessSize == 0)
1128  {
1129  ERROR("[ERROR] Accessed size is too large or 0: 0x%x\n", gVcpu->AccessSize);
1130  return INT_STATUS_NOT_SUPPORTED;
1131  }
1132 
1133  status = IntKernVirtMemRead(Gva, gVcpu->AccessSize, &Victim->ReadInfo.Value[0], NULL);
1134  if (!INT_SUCCESS(status))
1135  {
1136  Victim->ReadInfo.Value[0] = 0xbaddead;
1137  }
1138 
1139  Victim->ReadInfo.AccessSize = gVcpu->AccessSize;
1140  }
1141  }
1142 
1143  // At this point, override every status possible
1144  return INT_STATUS_SUCCESS;
1145 }
1146 
1147 
1148 static INTSTATUS
1150  _In_ void *Exception,
1151  _In_ void *Originator,
1152  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
1153  _Inout_ DWORD SignatureCount,
1154  _In_ EXCEPTION_TYPE ExceptionType
1155  )
1174 {
1175  INTSTATUS status;
1176 
1177  DWORD lastChecked = 0;
1178 
1179  DWORD startOffset, endOffset, totalSize, csType;
1180  void *pCode = NULL;
1181 
1182  BOOLEAN requires64BitSig = gGuest.Guest64;
1183  BOOLEAN execute = FALSE;
1184  BYTE level = (ExceptionType == exceptionTypeKm || ExceptionType == exceptionTypeKmUm) ? cbLevelNormal : cbLevelMedium;
1185 
1186  QWORD rip, cr3;
1187 
1188  void *pHookObject = NULL;
1189  CB_CACHE *pCodeBlocksCache;
1190  BYTE cacheFlags;
1191 
1192  status = IntGetCurrentMode(IG_CURRENT_VCPU, &csType);
1193  if (!INT_SUCCESS(status))
1194  {
1195  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
1196  return status;
1197  }
1198 
1199  if ((csType != IG_CS_TYPE_32B) && (csType != IG_CS_TYPE_64B))
1200  {
1201  ERROR("[ERROR] Unsupported CS type: %d\n", csType);
1202  return INT_STATUS_NOT_SUPPORTED;
1203  }
1204 
1205  switch (ExceptionType)
1206  {
1207  case exceptionTypeKm:
1208  {
1209  EXCEPTION_KM_ORIGINATOR *pKmOrig = Originator;
1210 
1211  if (((KM_EXCEPTION *)Exception)->Flags & EXCEPTION_KM_FLG_RETURN_DRV)
1212  {
1213  rip = pKmOrig->Return.Rip;
1214  cacheFlags = CB_CACHE_FLG_RETURN;
1215  }
1216  else
1217  {
1218  rip = pKmOrig->Original.Rip;
1219  cacheFlags = CB_CACHE_FLG_ORIGINAL;
1220  }
1221 
1222  cr3 = gGuest.Mm.SystemCr3;
1223 
1224  break;
1225  }
1226 
1227  case exceptionTypeKmUm:
1228  {
1229  EXCEPTION_KM_ORIGINATOR *pKmOrig = Originator;
1230 
1231  if (((KUM_EXCEPTION *)Exception)->Flags & EXCEPTION_KM_FLG_RETURN_DRV)
1232  {
1233  rip = pKmOrig->Return.Rip;
1234  cacheFlags = CB_CACHE_FLG_RETURN;
1235  }
1236  else
1237  {
1238  rip = pKmOrig->Original.Rip;
1239  cacheFlags = CB_CACHE_FLG_ORIGINAL;
1240  }
1241 
1242  cr3 = gGuest.Mm.SystemCr3;
1243 
1244  break;
1245  }
1246 
1247  case exceptionTypeUmGlob:
1248  case exceptionTypeUm:
1249  {
1250  EXCEPTION_UM_ORIGINATOR *pUmOrig = Originator;
1251 
1252  rip = pUmOrig->Rip;
1253  execute = pUmOrig->Execute;
1254  cacheFlags = CB_CACHE_FLG_ORIGINAL;
1255 
1257  {
1258  if (pUmOrig->WinLib != NULL)
1259  {
1260  pHookObject = pUmOrig->WinLib->HookObject;
1261  }
1262 
1263  cr3 = pUmOrig->WinProc->Cr3;
1264 
1265  requires64BitSig = requires64BitSig && !pUmOrig->WinProc->Wow64Process;
1266  }
1267  else if (gGuest.OSType == introGuestLinux)
1268  {
1269  pHookObject = pUmOrig->LixProc->HookObject;
1270  cr3 = pUmOrig->LixProc->Cr3;
1271  }
1272  else
1273  {
1274  return INT_STATUS_NOT_SUPPORTED;
1275  }
1276 
1277  if (cr3 != gVcpu->Regs.Cr3)
1278  {
1279  LOG("[INFO] Special case where process cr3 %llx != VCPU cr3 %llx\n", cr3, gVcpu->Regs.Cr3);
1280  cr3 = gVcpu->Regs.Cr3;
1281 
1282  // Don't use keep a cache for these writes (when should we invalidate it, after all?)
1283  pHookObject = NULL;
1284  }
1285 
1286  break;
1287  }
1288 
1289  default:
1290  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
1291  return INT_STATUS_NOT_SUPPORTED;
1292  }
1293 
1294  // In case we get a invalid RIP, we can't extract any code blocks. This is just a sanity check
1295  // since it shouldn't happen (we always have the current RIP from the VCPU. And if the return rip is 0, then
1296  // an exception with EXCEPTION_KM_FLG_RETURN_DRV won't match).
1297  if (0 == rip)
1298  {
1300  }
1301 
1302  // Make sure the totalSize is 2 * EXCEPTION_CODEBLOCKS_OFFSET, and to remain in the same page. Eg:
1303  // RipOffset = 0xf31 => [0xc00, 0xfff]
1304  // RipOffset = 0x123 => [0x000, 0x3ff]
1305  // RipOffset = 0x523 => [0x323, 0x722]
1306  //
1307  // But for a EXECUTE violation, get from here on.
1308 
1309  startOffset = endOffset = rip & PAGE_OFFSET;
1310 
1311  if (!execute)
1312  {
1313  if (startOffset > EXCEPTION_CODEBLOCKS_OFFSET)
1314  {
1315  if (endOffset + EXCEPTION_CODEBLOCKS_OFFSET < PAGE_SIZE)
1316  {
1317  startOffset -= EXCEPTION_CODEBLOCKS_OFFSET;
1318  endOffset += EXCEPTION_CODEBLOCKS_OFFSET - 1;
1319  }
1320  else
1321  {
1322  startOffset = PAGE_SIZE - (EXCEPTION_CODEBLOCKS_OFFSET * 2);
1323  endOffset = PAGE_SIZE - 1;
1324  }
1325  }
1326  else
1327  {
1328  startOffset = 0;
1329  endOffset = (EXCEPTION_CODEBLOCKS_OFFSET * 2) - 1;
1330  }
1331  }
1332  else
1333  {
1334  endOffset += EXCEPTION_CODEBLOCKS_OFFSET - 1;
1335  }
1336 
1337  totalSize = endOffset - startOffset;
1338 
1339  // This shouldn't happen since we only extract from the same page, but let's be sure
1340  if (totalSize > PAGE_SIZE && !execute)
1341  {
1342  totalSize = PAGE_SIZE;
1343  }
1344 
1345  if (cacheFlags & CB_CACHE_FLG_ORIGINAL)
1346  {
1347  pCodeBlocksCache = &gCodeBlocksOriginalCache;
1348  }
1349  else if (cacheFlags & CB_CACHE_FLG_RETURN)
1350  {
1351  pCodeBlocksCache = &gCodeBlocksReturnCache;
1352  }
1353  else
1354  {
1355  ERROR("[ERROR] Invalid codeblocks cache flag %d...\n", cacheFlags);
1356  return INT_STATUS_NOT_SUPPORTED;
1357  }
1358 
1359  // If the current RIP is from a hooked region, we can re-use the cache because it will remain identically
1360  // (code blocks) until it's written; when the page is written, we'll invalidate the codeblocks cache. (this
1361  // cache is valid for multiple exits).
1362  // If the condition is not met, the 'event-id' cache will be used (this cache is valid for one exit).
1363  if ((PAGE_FRAME_NUMBER(pCodeBlocksCache->Rip) == PAGE_FRAME_NUMBER(rip)) &&
1364  my_llabs((long long)(pCodeBlocksCache->Rip) - (long long)(rip)) < 0x50 &&
1365  NULL != IntHookObjectFindRegion(rip, pHookObject, IG_EPT_HOOK_WRITE))
1366  {
1367  if (pCodeBlocksCache->Rip == rip &&
1368  pCodeBlocksCache->CsType == csType &&
1369  pCodeBlocksCache->Cr3 == cr3)
1370  {
1371  goto _skip_getting_codeblocks;
1372  }
1373 
1374  pCodeBlocksCache->EventId = gEventId;
1375  pCodeBlocksCache->Rip = rip;
1376  pCodeBlocksCache->CsType = csType;
1377  pCodeBlocksCache->Cr3 = cr3;
1378  pCodeBlocksCache->Count = totalSize / sizeof(DWORD);
1379  }
1380  else
1381  {
1382  if (pCodeBlocksCache->EventId == gEventId &&
1383  pCodeBlocksCache->Rip == rip &&
1384  pCodeBlocksCache->CsType == csType)
1385  {
1386  goto _skip_getting_codeblocks;
1387  }
1388 
1389  pCodeBlocksCache->EventId = gEventId;
1390  pCodeBlocksCache->Rip = rip;
1391  pCodeBlocksCache->CsType = csType;
1392  pCodeBlocksCache->Cr3 = cr3;
1393  pCodeBlocksCache->Count = totalSize / sizeof(DWORD);
1394  }
1395 
1396  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, totalSize, cr3, 0, &pCode);
1397  if (!INT_SUCCESS(status))
1398  {
1399  if (execute)
1400  {
1401  WARNING("[WARNING] Failed to map range [0x%016llx - 0x%016llx], try to map range [0x%016llx - 0x%016llx]\n",
1402  (rip & PAGE_MASK) + startOffset, (rip & PAGE_MASK) + startOffset + totalSize,
1403  (rip & PAGE_MASK) + startOffset, (rip & PAGE_MASK) + startOffset + (PAGE_SIZE - startOffset));
1404  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, PAGE_SIZE - startOffset, cr3, 0, &pCode);
1405  if (!INT_SUCCESS(status))
1406  {
1407  pCodeBlocksCache->EventId = 0;
1408 
1409  ERROR("[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", rip & PAGE_MASK, status);
1410 
1411  goto _clean_and_leave;
1412  }
1413 
1414  totalSize = PAGE_SIZE - startOffset;
1415  }
1416  else
1417  {
1418  pCodeBlocksCache->EventId = 0;
1419 
1420  ERROR("[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", rip & PAGE_MASK, status);
1421 
1422  goto _clean_and_leave;
1423  }
1424  }
1425 
1426  status = IntFragExtractCodeBlocks(pCode, totalSize, csType, level,
1427  &pCodeBlocksCache->Count, pCodeBlocksCache->CodeBlocks);
1428  if (!INT_SUCCESS(status) && INT_STATUS_NOT_FOUND != status)
1429  {
1430  pCodeBlocksCache->EventId = 0;
1431  ERROR("[ERROR] Failed extracting blocks from VA 0x%016llx: 0x%08x\n", rip, status);
1432  goto _clean_and_leave;
1433  }
1434  else if (INT_STATUS_NOT_FOUND == status)
1435  {
1436  // If we didn't manage to extract codeblocks, we can't verify anything.
1437  pCodeBlocksCache->Count = 0;
1439 
1440  goto _clean_and_leave;
1441  }
1442 
1443 _skip_getting_codeblocks:
1445  {
1446  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
1447  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
1448  {
1449  continue;
1450  }
1451 
1452  // Since everything is ordered, it's safely to do it like this
1453  for (DWORD i = lastChecked; i < SignatureCount; i++)
1454  {
1455  if (Signatures[i].Field.Type != signatureTypeCodeBlocks)
1456  {
1457  break;
1458  }
1459 
1460  if (Signatures[i].Value != pSig->Id.Value)
1461  {
1462  continue;
1463  }
1464 
1465  // We found a signature. Make sure it matches the architecture & everything else
1466  if ((requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_64)) ||
1467  (!requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_32)))
1468  {
1469  break;
1470  }
1471 
1472  if ((pSig->Flags & SIGNATURE_FLG_CB_MEDIUM) && level != cbLevelMedium)
1473  {
1474  break;
1475  }
1476 
1477  status = IntFragMatchSignature(pCodeBlocksCache->CodeBlocks, pCodeBlocksCache->Count, pSig);
1478  if (status == INT_STATUS_SIGNATURE_MATCHED)
1479  {
1480  goto _clean_and_leave;
1481  }
1482 
1483  // so the next time we will search from this signature forward only
1484  lastChecked = i + 1;
1485 
1486  // no point in searching anymore (only one will match)
1487  break;
1488  }
1489  }
1490 
1491  // if we get here, the we didn't match anything
1493 
1494 _clean_and_leave:
1495  if (NULL != pCode)
1496  {
1497  IntVirtMemUnmap(&pCode);
1498  }
1499 
1500  return status;
1501 }
1502 
1503 
1504 static INTSTATUS
1506  _In_ void *Exception,
1507  _In_ void *Originator,
1508  _In_ EXCEPTION_VICTIM_ZONE *Victim,
1509  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
1510  _In_ DWORD SignaturesCount,
1511  _In_ EXCEPTION_TYPE ExceptionType
1512  )
1531 {
1532  INTSTATUS status;
1533 
1534  DWORD lastChecked = 0;
1535 
1536  DWORD csType;
1537  BYTE *pCodePattern = NULL;
1538  BYTE *pCodePatternBuffer = NULL;
1539  BYTE level = (ExceptionType == exceptionTypeKm) ? cbLevelNormal : cbLevelMedium;
1540 
1541  BOOLEAN requires64BitSig = gGuest.Guest64;
1542  QWORD rip, cr3;
1543 
1544  QWORD oldGva = 0;
1545 
1546  status = IntGetCurrentMode(IG_CURRENT_VCPU, &csType);
1547  if (!INT_SUCCESS(status))
1548  {
1549  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
1550  return status;
1551  }
1552 
1553  if ((csType != IG_CS_TYPE_32B) && (csType != IG_CS_TYPE_64B))
1554  {
1555  ERROR("[ERROR] Unsupported CS type: %d\n", csType);
1556  return INT_STATUS_NOT_SUPPORTED;
1557  }
1558 
1559  switch (ExceptionType)
1560  {
1561  case exceptionTypeKm:
1562  {
1563  EXCEPTION_KM_ORIGINATOR *pKmOrig = Originator;
1564 
1565  if (((KM_EXCEPTION *)Exception)->Flags & EXCEPTION_KM_FLG_RETURN_DRV)
1566  {
1567  rip = pKmOrig->Return.Rip;
1568  }
1569  else
1570  {
1571  rip = pKmOrig->Original.Rip;
1572  }
1573 
1574  cr3 = gGuest.Mm.SystemCr3;
1575 
1576  break;
1577  }
1578 
1579  case exceptionTypeUmGlob:
1580  case exceptionTypeUm:
1581  {
1582  EXCEPTION_UM_ORIGINATOR *pUmOrig = Originator;
1583 
1584  rip = pUmOrig->Rip;
1585 
1587  {
1588  if (pUmOrig->PcType == INT_PC_VIOLATION_DPI_HEAP_SPRAY ||
1590  {
1591  cr3 = Victim->Object.WinProc->Cr3;
1592  requires64BitSig = requires64BitSig && !Victim->Object.WinProc->Wow64Process;
1593  break;
1594  }
1595 
1596  cr3 = pUmOrig->WinProc->Cr3;
1597 
1598  requires64BitSig = requires64BitSig && !pUmOrig->WinProc->Wow64Process;
1599  }
1600  else if (gGuest.OSType == introGuestLinux)
1601  {
1602  cr3 = pUmOrig->LixProc->Cr3;
1603  }
1604  else
1605  {
1606  return INT_STATUS_NOT_SUPPORTED;
1607  }
1608 
1609  if (cr3 != gVcpu->Regs.Cr3)
1610  {
1611  LOG("[INFO] Special case where process cr3 %llx != VCPU cr3 %llx\n", cr3, gVcpu->Regs.Cr3);
1612  cr3 = gVcpu->Regs.Cr3;
1613  }
1614 
1615  break;
1616  }
1617 
1618  default:
1619  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
1620  return INT_STATUS_NOT_SUPPORTED;
1621  }
1622 
1623  if (0 == rip)
1624  {
1626  }
1627 
1629  {
1630  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
1631  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
1632  {
1633  continue;
1634  }
1635 
1636  // Since everything is ordered, it's safely to do it like this
1637  for (DWORD i = lastChecked; i < SignaturesCount; i++)
1638  {
1639  QWORD gva;
1640  DWORD pageRemaining;
1641  QWORD alignedGva;
1642 
1643  if (Signatures[i].Field.Type != signatureTypeValueCode)
1644  {
1645  break;
1646  }
1647 
1648  if (Signatures[i].Value != pSig->Id.Value)
1649  {
1650  continue;
1651  }
1652 
1653  // We found a signature. Make sure it matches the architecture & everything else
1654  if ((requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_64)) ||
1655  (!requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_32)))
1656  {
1657  break;
1658  }
1659 
1660  if ((pSig->Flags & SIGNATURE_FLG_CB_MEDIUM) && level != cbLevelMedium)
1661  {
1662  break;
1663  }
1664 
1665  // Match only the first page
1666  gva = rip + pSig->Offset;
1667  pageRemaining = (DWORD)PAGE_REMAINING(gva);
1668  alignedGva = gva & PAGE_MASK;
1669 
1670  // New map only if the page changes
1671  if ((oldGva != alignedGva) || NULL == pCodePattern)
1672  {
1673  oldGva = alignedGva;
1674 
1675  // Unmap the old page
1676  if (NULL != pCodePattern)
1677  {
1678  IntVirtMemUnmap(&pCodePattern);
1679  }
1680 
1681  status = IntVirtMemMap(alignedGva, PAGE_SIZE, cr3, 0, &pCodePattern);
1682  if (!INT_SUCCESS(status))
1683  {
1684  WARNING("[WARNING] IntVirtMemMap failed for address %llx: 0x%08x\n", alignedGva, status);
1685  continue;
1686  }
1687  }
1688 
1689  pCodePattern = (BYTE *)(((QWORD)pCodePattern & PAGE_MASK) | gva % PAGE_SIZE);
1690 
1691  if (SIG_NOT_FOUND == IntExceptExtendedPatternMatch(pCodePattern, MIN(pageRemaining, pSig->Length), pSig, 0))
1692  {
1693  // so the next time we will search from this signature forward only
1694  lastChecked = i + 1;
1695 
1696  // no point in searching anymore (only one will match)
1697  break;
1698  }
1699 
1700  // Match next pages if is necessary
1701  if (pageRemaining >= pSig->Length)
1702  {
1704  goto _clean_and_leave;
1705  }
1706 
1707  gva += pageRemaining;
1708 
1709  pCodePatternBuffer = HpAllocWithTag(pSig->Length - pageRemaining, IC_TAG_EXCP);
1710  if (NULL == pCodePatternBuffer)
1711  {
1713  goto _clean_and_leave;
1714  }
1715 
1716  status = IntVirtMemRead(gva, pSig->Length - pageRemaining, cr3, pCodePatternBuffer, NULL);
1717  if (!INT_SUCCESS(status))
1718  {
1719  ERROR("[ERROR] IntVirtMemMap failed for address %llx: 0x%08x\n", gva, status);
1720  continue;
1721  }
1722 
1723  if (SIG_NOT_FOUND == IntExceptExtendedPatternMatch(pCodePatternBuffer, pSig->Length - pageRemaining,
1724  pSig, pageRemaining))
1725  {
1726  HpFreeAndNullWithTag(&pCodePatternBuffer, IC_TAG_EXCP);
1727 
1728  // so the next time we will search from this signature forward only
1729  lastChecked = i + 1;
1730 
1731  // no point in searching anymore (only one will match)
1732  break;
1733  }
1734 
1735  HpFreeAndNullWithTag(&pCodePatternBuffer, IC_TAG_EXCP);
1736 
1738  goto _clean_and_leave;
1739  }
1740  }
1741 
1742  // if we get here, the we didn't match anything
1744 
1745 _clean_and_leave:
1746 
1747  if (NULL != pCodePattern)
1748  {
1749  IntVirtMemUnmap(&pCodePattern);
1750  }
1751 
1752  return status;
1753 }
1754 
1755 
1756 static INTSTATUS
1758  _In_ void *Exception,
1759  _In_ void *Originator,
1760  _In_ EXCEPTION_VICTIM_ZONE *Victim,
1761  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
1762  _In_ DWORD SignaturesCount,
1763  _In_ EXCEPTION_TYPE ExceptionType
1764  )
1780 {
1781  INTSTATUS status;
1782  DWORD lastChecked = 0;
1783  DWORD size;
1784  BYTE *buf;
1785  BOOLEAN requires64BitSig = gGuest.Guest64;
1786  EXCEPTION_UM_ORIGINATOR *pUmOrig = Originator;
1787 
1788  UNREFERENCED_PARAMETER(Exception);
1789 
1790  if ((Victim->ZoneType == exceptionZoneEpt) ||
1791  (Victim->ZoneType == exceptionZoneMsr))
1792  {
1793  if (Victim->WriteInfo.AccessSize > sizeof(Victim->WriteInfo.NewValue))
1794  {
1795  ERROR("[ERROR] Access size too large or 0: %d\n", Victim->WriteInfo.AccessSize);
1796  return INT_STATUS_NOT_SUPPORTED;
1797  }
1798 
1799  buf = (BYTE *)&Victim->WriteInfo.NewValue;
1800  size = Victim->WriteInfo.AccessSize;
1801  }
1802  else if (Victim->ZoneType == exceptionZoneProcess &&
1803  NULL == Victim->Injection.Buffer)
1804  {
1805  QWORD cr3, gva = pUmOrig->SourceVA;
1806 
1807  size = Victim->Injection.Length;
1808 
1809  if (NULL == gValueBuffer || size > gValueBufferSize)
1810  {
1811  TRACE("[EXCEPTIONS] Must realloc old buffer %p with size %d to size %d\n",
1813 
1814  // Maybe it failed at a previous allocation
1815  if (gValueBuffer)
1816  {
1818  }
1819 
1821  if (NULL == gValueBuffer)
1822  {
1824  }
1825 
1826  gValueBufferSize = size;
1827  }
1828 
1829  buf = gValueBuffer;
1830 
1832  {
1833  cr3 = pUmOrig->WinProc->Cr3;
1834  }
1835  else
1836  {
1837  cr3 = pUmOrig->LixProc->Cr3;
1838  }
1839 
1840  // Safe: buf is allocated dynamically to match the read size.
1841  status = IntVirtMemRead(gva, size, cr3, buf, NULL);
1842  if (!INT_SUCCESS(status))
1843  {
1844  ERROR("[ERROR] IntVirtMemRead failed for gva %llx, cr3 %llx with size %d: %08x\n",
1845  gva, cr3, size, status);
1846  return status;
1847  }
1848 
1849  Victim->Injection.Buffer = gValueBuffer;
1850  Victim->Injection.BufferSize = gValueBufferSize;
1851  }
1852  else if (Victim->ZoneType == exceptionZoneProcess &&
1853  NULL != Victim->Injection.Buffer)
1854  {
1855  buf = Victim->Injection.Buffer;
1856  size = Victim->Injection.BufferSize;
1857  }
1858  else if (Victim->ZoneType == exceptionZoneIntegrity)
1859  {
1860  if (Victim->Object.Type == introObjectTypeIdt)
1861  {
1862  buf = (BYTE *)&Victim->WriteInfo.NewValue;
1863  size = Victim->WriteInfo.AccessSize;
1864  }
1865  else
1866  {
1867  return INT_STATUS_NOT_SUPPORTED;
1868  }
1869  }
1870  else
1871  {
1872  return INT_STATUS_NOT_SUPPORTED;
1873  }
1874 
1875  switch (ExceptionType)
1876  {
1877  case exceptionTypeKm:
1878  break;
1879 
1880  case exceptionTypeUmGlob:
1881  case exceptionTypeUm:
1882  if (gGuest.OSType == introGuestWindows && requires64BitSig)
1883  {
1884  requires64BitSig = !pUmOrig->WinProc->Wow64Process;
1885  }
1886 
1887  break;
1888 
1889  default:
1890  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
1891  return INT_STATUS_NOT_SUPPORTED;
1892  }
1893 
1895  {
1896  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
1897  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
1898  {
1899  continue;
1900  }
1901 
1902  // Since everything is ordered, it's safely to do it like this
1903  for (DWORD i = lastChecked; i < SignaturesCount; i++)
1904  {
1905  DWORD matchedCount = 0;
1906  SIG_VALUE_HASH *pSigHash;
1907 
1908  if (Signatures[i].Field.Type != signatureTypeValue)
1909  {
1910  break;
1911  }
1912 
1913  if (Signatures[i].Value != pSig->Id.Value)
1914  {
1915  continue;
1916  }
1917 
1918  // We found a signature. Make sure it matches the architecture & everything else
1919  if ((requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_64)) ||
1920  (!requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_32)))
1921  {
1922  break;
1923  }
1924 
1925  pSigHash = (SIG_VALUE_HASH *)pSig->Object;
1926  for (DWORD j = 0; j < pSig->ListsCount; j++)
1927  {
1928  BOOLEAN match;
1929 
1930  if (pSig->Flags & SIGNATURE_FLG_VALUE_CLI)
1931  {
1932  char *pCli = NULL;
1933 
1935  {
1936  pCli = pUmOrig->WinProc->CommandLine;
1937  }
1938  else if (gGuest.OSType == introGuestLinux)
1939  {
1940  pCli = pUmOrig->LixProc->CmdLine;
1941  }
1942 
1943  if (pCli == NULL)
1944  {
1946  }
1947 
1948  // This case will include Offset > wstrlen(pCli) and Size > wstrlen(pCli) because we cast
1949  // Offset and Size (WORD -> DWORD) so we'll not have an overflow
1950  if (((QWORD)pSigHash[j].Offset + (DWORD)pSigHash[j].Size) > strlen(pCli))
1951  {
1952  continue;
1953  }
1954 
1955  match = (pSigHash[j].Hash == Crc32Compute(pCli + pSigHash[j].Offset,
1956  pSigHash[j].Size,
1958  }
1959  else
1960  {
1961  // This case will include Offset >size and Size > size because we cast Offset and Size
1962  // (WORD -> DWORD) so we'll not have an overflow
1963  if (((DWORD)pSigHash[j].Offset + (DWORD)pSigHash[j].Size) > size)
1964  {
1965  continue;
1966  }
1967  match = (pSigHash[j].Hash == Crc32Compute(buf + pSigHash[j].Offset,
1968  pSigHash[j].Size,
1970  }
1971 
1972  if (match)
1973  {
1974  matchedCount++;
1975 
1976  if (matchedCount >= pSig->Score)
1977  {
1979  }
1980  }
1981 
1982  }
1983 
1984  // so the next time we will search from this signature forward only
1985  lastChecked = i + 1;
1986 
1987  // no point in searching anymore (only one will match)
1988  break;
1989  }
1990  }
1991 
1992  // if we get here, the we didn't match anything
1994 }
1995 
1996 
1997 static INTSTATUS
1999  _In_ void *Exception,
2000  _In_ void *Originator,
2002  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2003  _In_ DWORD SignaturesCount,
2004  _In_ EXCEPTION_TYPE ExceptionType
2005  )
2024 {
2025  WIN_PROCESS_MODULE *pModule;
2026  DWORD accessSize;
2027  DWORD lastChecked = 0;
2028  BOOLEAN requires64BitSig = gGuest.Guest64;
2029  QWORD gva;
2030 
2031  UNREFERENCED_PARAMETER(Exception);
2032 
2033  switch(ExceptionType)
2034  {
2035  case exceptionTypeUm:
2036  {
2037  EXCEPTION_UM_ORIGINATOR *pOriginator = Originator;
2038  if (gGuest.OSType == introGuestWindows && requires64BitSig)
2039  {
2040  if (Victim->ZoneType == exceptionZoneProcess)
2041  {
2042  requires64BitSig = !Victim->Object.WinProc->Wow64Process;
2043  }
2044  else
2045  {
2046  requires64BitSig = !pOriginator->WinProc->Wow64Process;
2047  }
2048  }
2049  break;
2050  }
2051 
2052  case exceptionTypeKmUm:
2053  requires64BitSig = gGuest.Guest64;
2054  break;
2055 
2056  default:
2057  WARNING("[WARNING] Unsupported exception type (%d) for export signature\n", ExceptionType);
2059  }
2060 
2061  if (Victim->ZoneType == exceptionZoneEpt)
2062  {
2063  gva = Victim->Ept.Gva;
2064  accessSize = Victim->WriteInfo.AccessSize;
2065  }
2066  else if (Victim->ZoneType == exceptionZoneProcess)
2067  {
2068  gva = Victim->Injection.Gva;
2069  accessSize = Victim->Injection.Length;
2070  }
2071  else
2072  {
2073  return INT_STATUS_NOT_SUPPORTED;
2074  }
2075 
2076  pModule = Victim->Object.Library.Module;
2077 
2078  // We must return an error since this injection was for a module-only modification
2079  if (NULL == pModule)
2080  {
2082  }
2083 
2084  if (NULL == pModule->Cache || !pModule->Cache->ExportDirRead)
2085  {
2087  }
2088 
2089  if (Victim->Object.Library.Export == NULL)
2090  {
2091  Victim->Object.Library.Export = IntWinUmCacheGetExportFromRange(pModule, gva, 0x20);
2092  }
2093 
2095  {
2096  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
2097  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
2098  {
2099  continue;
2100  }
2101 
2102  if (pSig->LibraryNameHash != umExcNameAny && pModule->Path->NameHash != pSig->LibraryNameHash)
2103  {
2104  continue;
2105  }
2106 
2107  // Since everything is ordered, it's safely to do it like this
2108  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2109  {
2110  SIG_EXPORT_HASH *pSigHash;
2111 
2112  if (Signatures[i].Field.Type != signatureTypeExport)
2113  {
2114  break;
2115  }
2116 
2117  if (Signatures[i].Value != pSig->Id.Value)
2118  {
2119  continue;
2120  }
2121 
2122  // We found a signature. Make sure it matches the architecture & everything else
2123  if ((requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_64)) ||
2124  (!requires64BitSig && !(pSig->Flags & SIGNATURE_FLG_32)))
2125  {
2126  break;
2127  }
2128 
2129  pSigHash = (SIG_EXPORT_HASH *)pSig->Object;
2130  for (DWORD j = 0; j < pSig->ListsCount; j++)
2131  {
2132  DWORD offset;
2133  BOOLEAN found = FALSE;
2134 
2135  if (pSigHash[j].Hash == umExcNameAny)
2136  {
2138  }
2139 
2140  if (Victim->Object.Library.Export == NULL &&
2141  pSigHash[i].Hash == umExcNameNone)
2142  {
2144  }
2145 
2146  // Only check the exceptions which match any name if we didn't found an export
2147  if (Victim->Object.Library.Export == NULL)
2148  {
2149  continue;
2150  }
2151 
2152  for (DWORD export = 0; export < Victim->Object.Library.Export->NumberOfOffsets; export++)
2153  {
2154  if (pSigHash[j].Hash == Victim->Object.Library.Export->NameHashes[export])
2155  {
2156  found = TRUE;
2157  break;
2158  }
2159  }
2160 
2161  if (!found)
2162  {
2163  continue;
2164  }
2165 
2166  // Verify that the write is inside the allowed zone or that delta is 0 (match any length)
2167  offset = (DWORD)(gva - pModule->VirtualBase) - Victim->Object.Library.Export->Rva;
2168  if (pSigHash[j].Delta != 0 &&
2169  (offset + accessSize - 1 > pSigHash[j].Delta))
2170  {
2171  continue;
2172  }
2173 
2175  }
2176 
2177  // so the next time we will search from this signature forward only
2178  lastChecked = i + 1;
2179 
2180  // no point in searching anymore (only one will match)
2181  break;
2182  }
2183  }
2184 
2186 }
2187 
2188 
2189 static INTSTATUS
2191  _In_ void *Exception,
2192  _In_ void *Originator,
2194  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2195  _In_ DWORD SignaturesCount,
2196  _In_ EXCEPTION_TYPE ExceptionType
2197  )
2212 {
2213  UNREFERENCED_PARAMETER(Originator);
2214  UNREFERENCED_PARAMETER(Exception);
2215 
2216  DWORD lastChecked = 0;
2217  BYTE idtEntry;
2218 
2219  if (ExceptionType != exceptionTypeKm)
2220  {
2222  }
2223 
2224  if (Victim->ZoneType == exceptionZoneIntegrity)
2225  {
2226  idtEntry = (BYTE)(Victim->Integrity.Offset /
2228  }
2229  else
2230  {
2231  idtEntry = (BYTE)((Victim->Ept.Gva - Victim->Object.BaseAddress) /
2233  }
2234 
2235  lastChecked = 0;
2237  {
2238  if ((gGuest.OSType == introGuestWindows && (pSig->Flags & SIGNATURE_FLG_LINUX)) ||
2239  (gGuest.OSType == introGuestLinux && !(pSig->Flags & SIGNATURE_FLG_LINUX)))
2240  {
2241  continue;
2242  }
2243 
2244  // Since everything is ordered, it's safely to do it like this
2245  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2246  {
2247  if (Signatures[i].Field.Type != signatureTypeIdt)
2248  {
2249  break;
2250  }
2251 
2252  if (Signatures[i].Value != pSig->Id.Value)
2253  {
2254  continue;
2255  }
2256 
2257  // We found a signature. Make sure it matches the architecture & everything else
2258  if ((gGuest.Guest64 && !(pSig->Flags & SIGNATURE_FLG_64)) ||
2259  (!gGuest.Guest64 && !(pSig->Flags & SIGNATURE_FLG_32)))
2260  {
2261  break;
2262  }
2263 
2264  if (pSig->Entry == idtEntry)
2265  {
2267  }
2268 
2269  // so the next time we will search from this signature forward only
2270  lastChecked = i + 1;
2271 
2272  // no point in searching anymore (only one will match)
2273  break;
2274  }
2275  }
2276 
2277  // if we get here, the we didn't match anything
2279 }
2280 
2281 
2282 static INTSTATUS
2284  _In_ void *Exception,
2285  _In_ void *Originator,
2286  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2287  _In_ DWORD SignaturesCount,
2288  _In_ EXCEPTION_TYPE ExceptionType
2289  )
2303 {
2304  UNREFERENCED_PARAMETER(Exception);
2305 
2306  EXCEPTION_UM_ORIGINATOR *pOriginator = NULL;
2307  DWORD mask = 0;
2308  DWORD lastChecked = 0;
2309 
2310  if (ExceptionType == exceptionTypeKm)
2311  {
2312  return INT_STATUS_NOT_SUPPORTED;
2313  }
2314 
2315  pOriginator = Originator;
2316 
2317  mask = pOriginator->PcType;
2318 
2319  lastChecked = 0;
2321  {
2322  if ((gGuest.OSType == introGuestWindows && (pSignature->Flags & SIGNATURE_FLG_LINUX)) ||
2323  (gGuest.OSType == introGuestLinux && !(pSignature->Flags & SIGNATURE_FLG_LINUX)))
2324  {
2325  continue;
2326  }
2327 
2328  // Since everything is ordered, it's safely to do it like this
2329  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2330  {
2331  if (Signatures[i].Field.Type != signatureTypeProcessCreation)
2332  {
2333  break;
2334  }
2335 
2336  if (Signatures[i].Value != pSignature->Id.Value)
2337  {
2338  continue;
2339  }
2340 
2341  // We found a signature. Make sure it matches the architecture & everything else
2342  if ((gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_64)) ||
2343  (!gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_32)))
2344  {
2345  break;
2346  }
2347 
2348  if ((~(pSignature->CreateMask) & mask) == 0)
2349  {
2351  }
2352 
2353  // so the next time we will search from this signature forward only
2354  lastChecked = i + 1;
2355 
2356  // no point in searching anymore (only one will match)
2357  break;
2358  }
2359  }
2360 
2361  // if we get here, the we didn't match anything
2363 }
2364 
2365 
2366 static INTSTATUS
2368  _In_ void *Exception,
2369  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2370  _In_ DWORD SignaturesCount
2371  )
2383 {
2384  UNREFERENCED_PARAMETER(Exception);
2385 
2386  DWORD lastChecked = 0;
2387 
2388  lastChecked = 0;
2390  {
2391  if ((gGuest.OSType == introGuestWindows && (pSignature->Flags & SIGNATURE_FLG_LINUX)) ||
2392  (gGuest.OSType == introGuestLinux && !(pSignature->Flags & SIGNATURE_FLG_LINUX)))
2393  {
2394  continue;
2395  }
2396 
2397  // Since everything is ordered, it's safely to do it like this
2398  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2399  {
2400  if (Signatures[i].Field.Type != signatureTypeVersionOs)
2401  {
2402  break;
2403  }
2404 
2405  if (Signatures[i].Value != pSignature->Id.Value)
2406  {
2407  continue;
2408  }
2409 
2410  // We found a signature. Make sure it matches the architecture & everything else
2411  if ((gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_64)) ||
2412  (!gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_32)))
2413  {
2414  break;
2415  }
2416 
2418  {
2419  if (pSignature->Minimum.Value <= gGuest.OSVersion &&
2420  pSignature->Maximum.Value >= gGuest.OSVersion)
2421  {
2423  }
2424  }
2425  else if (gGuest.OSType == introGuestLinux)
2426  {
2427  BOOLEAN matchMax = FALSE;
2428  BOOLEAN matchMin = FALSE;
2429 
2430  if (pSignature->Minimum.Version <= gLixGuest->Version.Version)
2431  {
2432  if (pSignature->Minimum.Version < gLixGuest->Version.Version)
2433  {
2434  matchMin = TRUE;
2435  goto _check_min_os_done;
2436  }
2437 
2438  if (pSignature->Minimum.Patch <= gLixGuest->Version.Patch)
2439  {
2440  if (pSignature->Minimum.Patch < gLixGuest->Version.Patch)
2441  {
2442  matchMin = TRUE;
2443  goto _check_min_os_done;
2444  }
2445 
2446  if (pSignature->Minimum.Sublevel <= gLixGuest->Version.Sublevel)
2447  {
2448  if (pSignature->Minimum.Sublevel < gLixGuest->Version.Sublevel)
2449  {
2450  matchMin = TRUE;
2451  goto _check_min_os_done;
2452  }
2453 
2454  if (pSignature->Minimum.Backport <= gLixGuest->Version.Backport)
2455  {
2456  matchMin = TRUE;
2457  }
2458  }
2459  }
2460  }
2461 
2462 _check_min_os_done:
2463  if (!matchMin)
2464  {
2465  goto _check_max_os_done;
2466  }
2467 
2468  if (pSignature->Maximum.Version >= gLixGuest->Version.Version)
2469  {
2470  if (pSignature->Maximum.Version > gLixGuest->Version.Version)
2471  {
2472  matchMax = TRUE;
2473  goto _check_max_os_done;
2474  }
2475 
2476  if (pSignature->Maximum.Patch >= gLixGuest->Version.Patch)
2477  {
2478  if (pSignature->Maximum.Patch > gLixGuest->Version.Patch)
2479  {
2480  matchMax = TRUE;
2481  goto _check_max_os_done;
2482  }
2483 
2484  if (pSignature->Maximum.Sublevel >= gLixGuest->Version.Sublevel)
2485  {
2486  if (pSignature->Maximum.Sublevel > gLixGuest->Version.Sublevel)
2487  {
2488  matchMax = TRUE;
2489  goto _check_max_os_done;
2490  }
2491 
2492  if (pSignature->Maximum.Backport >= gLixGuest->Version.Backport)
2493  {
2494  matchMax = TRUE;
2495  }
2496  }
2497  }
2498  }
2499 
2500 _check_max_os_done:
2501  if (matchMin && matchMax)
2502  {
2504  }
2505  }
2506 
2507  // so the next time we will search from this signature forward only
2508  lastChecked = i + 1;
2509 
2510  // no point in searching anymore (only one will match)
2511  break;
2512  }
2513  }
2514 
2515  // if we get here, the we didn't match anything
2517 }
2518 
2519 
2520 static INTSTATUS
2522  _In_ void *Exception,
2523  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2524  _In_ DWORD SignaturesCount
2525  )
2537 {
2538  UNREFERENCED_PARAMETER(Exception);
2539 
2540  DWORD lastChecked = 0;
2541 
2542  lastChecked = 0;
2544  {
2545  if ((gGuest.OSType == introGuestWindows && (pSignature->Flags & SIGNATURE_FLG_LINUX)) ||
2546  (gGuest.OSType == introGuestLinux && !(pSignature->Flags & SIGNATURE_FLG_LINUX)))
2547  {
2548  continue;
2549  }
2550 
2551  // Since everything is ordered, it's safely to do it like this
2552  for (DWORD i = lastChecked; i < SignaturesCount; i++)
2553  {
2554  BOOLEAN matchMax;
2555  BOOLEAN matchMin;
2556 
2557  if (Signatures[i].Field.Type != signatureTypeVersionIntro)
2558  {
2559  break;
2560  }
2561 
2562  if (Signatures[i].Value != pSignature->Id.Value)
2563  {
2564  continue;
2565  }
2566 
2567  // We found a signature. Make sure it matches the architecture & everything else
2568  if ((gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_64)) ||
2569  (!gGuest.Guest64 && !(pSignature->Flags & SIGNATURE_FLG_32)))
2570  {
2571  break;
2572  }
2573 
2574  matchMax = FALSE;
2575  matchMin = FALSE;
2576 
2577  if (pSignature->Minimum.Major <= IntHviVersion.VersionInfo.Major)
2578  {
2579  if (pSignature->Minimum.Major < IntHviVersion.VersionInfo.Major)
2580  {
2581  matchMin = TRUE;
2582  goto _check_min_done;
2583  }
2584 
2585  if (pSignature->Minimum.Minor <= IntHviVersion.VersionInfo.Minor)
2586  {
2587  if (pSignature->Minimum.Minor < IntHviVersion.VersionInfo.Minor)
2588  {
2589  matchMin = TRUE;
2590  goto _check_min_done;
2591  }
2592 
2593  if (pSignature->Minimum.Revision <= IntHviVersion.VersionInfo.Revision)
2594  {
2595  if (pSignature->Minimum.Revision < IntHviVersion.VersionInfo.Revision)
2596  {
2597  matchMin = TRUE;
2598  goto _check_min_done;
2599  }
2600 
2601  if (pSignature->Minimum.Build <= IntHviVersion.VersionInfo.Build)
2602  {
2603  matchMin = TRUE;
2604  }
2605  }
2606  }
2607  }
2608 
2609 _check_min_done:
2610 
2611  if (!matchMin)
2612  {
2613  goto _check_max_done;
2614  }
2615 
2616  if (pSignature->Maximum.Major >= IntHviVersion.VersionInfo.Major)
2617  {
2618  if (pSignature->Maximum.Major > IntHviVersion.VersionInfo.Major)
2619  {
2620  matchMax = TRUE;
2621  goto _check_max_done;
2622  }
2623 
2624  if (pSignature->Maximum.Minor >= IntHviVersion.VersionInfo.Minor)
2625  {
2626  if (pSignature->Maximum.Minor > IntHviVersion.VersionInfo.Minor)
2627  {
2628  matchMax = TRUE;
2629  goto _check_max_done;
2630  }
2631 
2632  if (pSignature->Maximum.Revision >= IntHviVersion.VersionInfo.Revision)
2633  {
2634  if (pSignature->Maximum.Revision > IntHviVersion.VersionInfo.Revision)
2635  {
2636  matchMax = TRUE;
2637  goto _check_max_done;
2638  }
2639 
2640  if (pSignature->Maximum.Build >= IntHviVersion.VersionInfo.Build)
2641  {
2642  matchMax = TRUE;
2643  }
2644  }
2645  }
2646  }
2647 
2648 _check_max_done:
2649  if (matchMax && matchMin)
2650  {
2652  }
2653 
2654  // so the next time we will search from this signature forward only
2655  lastChecked = i + 1;
2656 
2657  // no point in searching anymore (only one will match)
2658  break;
2659  }
2660  }
2661 
2662  // if we get here, the we didn't match anything
2664 }
2665 
2666 
2667 static BOOLEAN
2669  _In_ EXCEPTION_SIGNATURE_ID *Signatures,
2670  _In_ DWORD Count,
2672  )
2682 {
2683  for (DWORD index = 0; index < Count; index++)
2684  {
2685  if ((EXCEPTION_SIGNATURE_TYPE)(Signatures[index].Field.Type) == Type)
2686  {
2687  return TRUE;
2688  }
2689  }
2690 
2691  return FALSE;
2692 }
2693 
2694 
2695 static INTSTATUS
2697  _In_ void *Exception,
2698  _In_ void *Originator,
2699  _In_ EXCEPTION_VICTIM_ZONE *Victim,
2700  _In_ EXCEPTION_TYPE ExceptionType,
2701  _Out_ INTRO_ACTION_REASON *Reason
2702  )
2716 {
2717 
2718  INTSTATUS status = INT_STATUS_SUCCESS;
2719  EXCEPTION_SIGNATURE_ID *pId = NULL;
2720  DWORD count = 0;
2721  DWORD index;
2722 
2723  // The caller will set the beta flag if needed.
2724  *Reason = introReasonAllowed;
2725 
2726  switch (ExceptionType)
2727  {
2728  case exceptionTypeKm:
2729  count = ((KM_EXCEPTION *)Exception)->SigCount;
2730  pId = ((KM_EXCEPTION *)Exception)->Signatures;
2731 
2732  break;
2733 
2734  case exceptionTypeKmUm:
2735  count = ((KUM_EXCEPTION *)Exception)->SigCount;
2736  pId = ((KUM_EXCEPTION *)Exception)->Signatures;
2737 
2738  break;
2739 
2740  case exceptionTypeUm:
2741  count = ((UM_EXCEPTION *)Exception)->SigCount;
2742  pId = ((UM_EXCEPTION *)Exception)->Signatures;
2743 
2744  // An injection that modifies a dll MUST have a export signature
2745  if (NULL != Victim->Object.Library.Module &&
2746  Victim->ZoneType == exceptionZoneProcess &&
2748  !(Victim->ZoneFlags & ZONE_MODULE_LOAD))
2749  {
2750  *Reason = introReasonExportNotMatched;
2752  }
2753 
2754  break;
2755 
2756  case exceptionTypeUmGlob:
2757  count = ((UM_EXCEPTION_GLOB *)Exception)->SigCount;
2758  pId = ((UM_EXCEPTION_GLOB *)Exception)->Signatures;
2759 
2760 
2761  // An injection that modifies a dll MUST have a export signature
2762  if (NULL != Victim->Object.Library.Module &&
2763  Victim->ZoneType == exceptionZoneProcess &&
2765  !(Victim->ZoneFlags & ZONE_MODULE_LOAD))
2766  {
2767  *Reason = introReasonExportNotMatched;
2769  }
2770 
2771  break;
2772 
2773  default:
2774  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
2775  return INT_STATUS_NOT_SUPPORTED;
2776  }
2777 
2778  if (0 == count)
2779  {
2781  }
2782 
2783  index = 0;
2784  while (index < count)
2785  {
2786  switch (pId[index].Field.Type)
2787  {
2789  {
2790  status = IntExceptVerifyVersionOsSignature(Exception, &pId[index], count - index);
2791  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2792  {
2794  return status;
2795  }
2796 
2797  break;
2798  }
2799 
2801  {
2802  status = IntExceptVerifyVersionIntroSignature(Exception, &pId[index], count - index);
2803  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2804  {
2806  return status;
2807  }
2808 
2809  break;
2810  }
2811 
2813  {
2814  status = IntExceptVerifyProcessCreationSignature(Exception,
2815  Originator,
2816  &pId[index],
2817  count - index,
2818  ExceptionType);
2819  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2820  {
2822  return status;
2823  }
2824 
2825  break;
2826  }
2827 
2828 
2829  case signatureTypeExport:
2830  {
2831  status = IntExceptVerifyExportSig(Exception,
2832  Originator,
2833  Victim,
2834  &pId[index],
2835  count - index,
2836  ExceptionType);
2837  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2838  {
2839  *Reason = introReasonExportNotMatched;
2840  return status;
2841  }
2842 
2843  break;
2844  }
2845 
2846  case signatureTypeValue:
2847  {
2848  status = IntExceptVerifyValueSig(Exception,
2849  Originator,
2850  Victim,
2851  &pId[index],
2852  count - index,
2853  ExceptionType);
2854  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2855  {
2856  *Reason = introReasonValueNotMatched;
2857  return status;
2858  }
2859 
2860  break;
2861  }
2862 
2863  case signatureTypeIdt:
2864  {
2865  status = IntExceptVerifyIdtSignature(Exception,
2866  Originator,
2867  Victim,
2868  &pId[index],
2869  count - index,
2870  ExceptionType);
2871  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2872  {
2873  *Reason = introReasonIdtNotMatched;
2874  return status;
2875  }
2876 
2877  break;
2878  }
2879 
2881  {
2882  status = IntExceptVerifyValueCodeSig(Exception,
2883  Originator,
2884  Victim,
2885  &pId[index],
2886  count - index,
2887  ExceptionType);
2888  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2889  {
2891  return status;
2892  }
2893 
2894  break;
2895  }
2896 
2898  {
2899  status = IntExceptVerifyCodeBlocksSig(Exception, Originator, &pId[index], count - index, ExceptionType);
2900  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
2901  {
2903  return status;
2904  }
2905 
2906  break;
2907  }
2908 
2909  default:
2910  {
2911  ERROR("[ERROR] Should not reach here. Type is %d ...\n", pId[index].Field.Type);
2912  return INT_STATUS_NOT_SUPPORTED;
2913  }
2914 
2915  }
2916 
2917  if (!INT_SUCCESS(status))
2918  {
2919  ERROR("[ERROR] IntExceptVerifySignature failed for signature type %d with status: 0x%08x\n",
2920  pId[index].Field.Type, status);
2921  *Reason = introReasonInternalError;
2922 
2923  return status;
2924  }
2925 
2926  index++;
2927  while (index < count && pId[index].Field.Type == pId[index - 1].Field.Type)
2928  {
2929  index++;
2930  }
2931  }
2932 
2934 }
2935 
2936 
2937 void
2939  _In_ void *Originator,
2940  _In_ EXCEPTION_VICTIM_ZONE *Victim,
2941  _In_ BOOLEAN KernelMode,
2942  _In_ BOOLEAN ReturnDrv
2943  )
2952 {
2953  INTSTATUS status;
2954 
2955  DWORD startOffset, endOffset, totalSize, i, csType;
2956  BOOLEAN execute = FALSE;
2957  BYTE *pCode = NULL;
2958 
2959  QWORD rip;
2960 
2961  if (NULL == Originator)
2962  {
2963  return;
2964  }
2965 
2966  status = IntGetCurrentMode(IG_CURRENT_VCPU, &csType);
2967  if (!INT_SUCCESS(status))
2968  {
2969  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
2970  return;
2971  }
2972 
2973  if ((csType != IG_CS_TYPE_32B) && (csType != IG_CS_TYPE_64B))
2974  {
2975  ERROR("[ERROR] Unsupported CS type: %d\n", csType);
2976  return;
2977  }
2978 
2979  if (KernelMode)
2980  {
2981  if (ReturnDrv)
2982  {
2983  rip = ((EXCEPTION_KM_ORIGINATOR *)Originator)->Return.Rip;
2984  }
2985  else
2986  {
2987  rip = ((EXCEPTION_KM_ORIGINATOR *)Originator)->Original.Rip;
2988  }
2989  }
2990  else
2991  {
2992  rip = ((EXCEPTION_UM_ORIGINATOR *)Originator)->Rip;
2993  execute = ((EXCEPTION_UM_ORIGINATOR *)Originator)->Execute;
2994  }
2995 
2996  if (0 == rip)
2997  {
2998  return;
2999  }
3000 
3001  // See if we dumped this already
3002  for (i = 0; i < ARRAYSIZE(gUsedRips); i++)
3003  {
3004  if (gUsedRips[i] == rip)
3005  {
3006  return;
3007  }
3008  }
3009 
3010  // Now add it to the list, if we can
3011  for (i = 0; i < ARRAYSIZE(gUsedRips); i++)
3012  {
3013  if (gUsedRips[i] == 0)
3014  {
3015  gUsedRips[i] = rip;
3016  break;
3017  }
3018  }
3019 
3020  // Make sure the totalSize is 2 * EXCEPTION_CODEBLOCKS_OFFSET, and to remain in the same page. Eg:
3021  // RipOffset = 0xf31 => [0xc00, 0xfff]
3022  // RipOffset = 0x123 => [0x000, 0x3ff]
3023  // RipOffset = 0x523 => [0x323, 0x722]
3024 
3025  startOffset = endOffset = rip & PAGE_OFFSET;
3026 
3027  if (!execute)
3028  {
3029  // endOffset = MIN(endOffset + EXCEPTION_CODEBLOCKS_OFFSET, PAGE_SIZE - 1);
3030  // startOffset = MIN(0, (int)(endOffset - EXCEPTION_CODEBLOCKS_OFFSET));
3031 
3032  if (startOffset > EXCEPTION_CODEBLOCKS_OFFSET)
3033  {
3034  if (endOffset + EXCEPTION_CODEBLOCKS_OFFSET < PAGE_SIZE)
3035  {
3036  startOffset -= EXCEPTION_CODEBLOCKS_OFFSET;
3037  endOffset += EXCEPTION_CODEBLOCKS_OFFSET - 1;
3038  }
3039  else
3040  {
3041  startOffset = PAGE_SIZE - (EXCEPTION_CODEBLOCKS_OFFSET * 2);
3042  endOffset = PAGE_SIZE - 1;
3043  }
3044 
3045  }
3046  else
3047  {
3048  startOffset = 0;
3049  endOffset = (EXCEPTION_CODEBLOCKS_OFFSET * 2) - 1;
3050  }
3051  }
3052  else
3053  {
3054  endOffset += EXCEPTION_CODEBLOCKS_OFFSET - 1;
3055  }
3056 
3057  totalSize = endOffset - startOffset;
3058 
3059  if (KernelMode)
3060  {
3061  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, totalSize, gGuest.Mm.SystemCr3, 0, &pCode);
3062  }
3063  else
3064  {
3065  QWORD cr3 = 0;
3066 
3068  {
3069  cr3 = ((EXCEPTION_UM_ORIGINATOR *)Originator)->WinProc->Cr3;
3070  }
3071  else if (gGuest.OSType == introGuestLinux)
3072  {
3073  cr3 = ((EXCEPTION_UM_ORIGINATOR *)Originator)->LixProc->Cr3;
3074  }
3075 
3076  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, totalSize, cr3, 0, &pCode);
3077  if (!INT_SUCCESS(status) && execute)
3078  {
3079  WARNING("[WARNING] Failed to map range [0x%016llx - 0x%016llx], try to map range [0x%016llx - 0x%016llx]\n",
3080  (rip & PAGE_MASK) + startOffset, (rip & PAGE_MASK) + startOffset + totalSize,
3081  (rip & PAGE_MASK) + startOffset, (rip & PAGE_MASK) + startOffset + (PAGE_SIZE - startOffset));
3082 
3083  status = IntVirtMemMap((rip & PAGE_MASK) + startOffset, PAGE_SIZE - startOffset, cr3, 0, &pCode);
3084  if (INT_SUCCESS(status))
3085  {
3086  totalSize = PAGE_SIZE - startOffset;
3087  }
3088  }
3089  }
3090 
3091  if (!INT_SUCCESS(status) && (Victim->ZoneFlags & ZONE_DEP_EXECUTION) == 0)
3092  {
3093  ERROR("[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n", rip & PAGE_MASK, status);
3094  goto _clean_and_leave;
3095  }
3096  else if (!INT_SUCCESS(status))
3097  {
3098  WARNING("[WARNING] Failed mapping VA 0x%016llx to host: 0x%08x\n", rip & PAGE_MASK, status);
3099  goto _clean_and_leave;
3100  }
3101 
3102  status = IntFragDumpBlocks(pCode,
3103  (rip & PAGE_MASK) + startOffset,
3104  totalSize,
3105  csType,
3106  KernelMode ? cbLevelNormal : cbLevelMedium,
3107  rip,
3108  KernelMode ? ReturnDrv : FALSE);
3109 
3110  IntDumpBuffer(pCode, (rip & PAGE_MASK) + startOffset, totalSize, 16, sizeof(BYTE), TRUE, TRUE);
3111 
3112  if (!INT_SUCCESS(status))
3113  {
3114  WARNING("[WARNING] Failed extracting blocks from VA 0x%016llx: 0x%08x\n", rip, status);
3115  goto _clean_and_leave;
3116  }
3117 
3118 _clean_and_leave:
3119  if (NULL != pCode)
3120  {
3121  IntVirtMemUnmap(&pCode);
3122  }
3123 }
3124 
3125 
3126 INTSTATUS
3128  _In_ void *Victim,
3129  _In_ void *Originator,
3130  _In_ void *Exception,
3131  _In_ EXCEPTION_TYPE ExceptionType,
3132  _Out_ INTRO_ACTION *Action,
3133  _Out_ INTRO_ACTION_REASON *Reason
3134  )
3154 {
3155  INTSTATUS status;
3156  BOOLEAN feedbackException, linuxException;
3157 
3158  switch (ExceptionType)
3159  {
3160  case exceptionTypeKm:
3161  feedbackException = (((KM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_FEEDBACK) != 0;
3162  linuxException = (((KM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_LINUX) != 0;
3163  break;
3164 
3165  case exceptionTypeUm:
3166  feedbackException = (((UM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_FEEDBACK) != 0;
3167  linuxException = (((UM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_LINUX) != 0;
3168  break;
3169 
3170  case exceptionTypeUmGlob:
3171  feedbackException = (((UM_EXCEPTION_GLOB *)Exception)->Flags & EXCEPTION_FLG_FEEDBACK) != 0;
3172  linuxException = (((UM_EXCEPTION_GLOB *)Exception)->Flags & EXCEPTION_FLG_LINUX) != 0;
3173  break;
3174 
3175  case exceptionTypeKmUm:
3176  feedbackException = (((KUM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_FEEDBACK) != 0;
3177  linuxException = (((KUM_EXCEPTION *)Exception)->Flags & EXCEPTION_FLG_LINUX) != 0;
3178  break;
3179 
3180  default:
3181  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
3182  return INT_STATUS_NOT_SUPPORTED;
3183  }
3184 
3185  if ((linuxException && (gGuest.OSType != introGuestLinux)) ||
3186  (!linuxException && (gGuest.OSType == introGuestLinux)))
3187  {
3189  }
3190 
3191  // 1. Check if the exception is matching at type, flags, and name.
3192  switch (ExceptionType)
3193  {
3194  case exceptionTypeKm:
3195  status = IntExceptKernelMatchVictim(Victim, Originator, Exception);
3196  break;
3197 
3198  case exceptionTypeUm:
3199  case exceptionTypeUmGlob:
3200  status = IntExceptUserMatchVictim(Victim, Originator, Exception, ExceptionType);
3201  break;
3202 
3203  case exceptionTypeKmUm:
3204  status = IntExceptKernelUserMatchVictim(Victim, Originator, Exception);
3205  break;
3206 
3207  default:
3208  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
3209  return INT_STATUS_NOT_SUPPORTED;
3210  }
3211 
3212  if (status == INT_STATUS_EXCEPTION_NOT_MATCHED)
3213  {
3214  // In this case don't overwrite the Action and Reason. If another exception was found and it failed
3215  // at extra checks or signature, then return that action&reason. Anyway, if no exception matched, then
3216  // we can safely return the default values (introGuestNotAllowed, introReasonNoException).
3217  return status;
3218  }
3219  else if (status == INT_STATUS_EXCEPTION_ALLOW)
3220  {
3221  *Action = introGuestAllowed;
3222  *Reason = feedbackException ? introReasonAllowedFeedback : introReasonAllowed;
3223  }
3224  else
3225  {
3226  ERROR("[ERROR] IntExceptMatchVictim `%d` failed: 0x%08x. Will ignore this exception!\n",
3227  ExceptionType, status);
3228 
3229  *Action = introGuestNotAllowed;
3230  *Reason = introReasonInternalError;
3231 
3232  return status;
3233  }
3234 
3235  // 2. Do we have any extra thing to verify (like the imports, exports, etc.) ?
3236  switch (ExceptionType)
3237  {
3238  case exceptionTypeKm:
3239  status = IntExceptKernelVerifyExtra(Victim, Originator, Exception);
3240  break;
3241 
3242  case exceptionTypeUm:
3243  status = IntExceptUserVerifyExtra(Victim, Originator, Exception);
3244  break;
3245 
3246  case exceptionTypeUmGlob:
3247  status = IntExceptUserVerifyExtraGlobMatch(Victim, Originator, Exception);
3248  break;
3249 
3250  case exceptionTypeKmUm:
3251  status = IntExceptKernelUserVerifyExtra(Victim, Originator, Exception);
3252  break;
3253 
3254  default:
3255  ERROR("[ERROR] Shouldn't reach here. Type is %d ...\n", ExceptionType);
3256  return INT_STATUS_NOT_SUPPORTED;
3257  }
3258 
3259  if (status == INT_STATUS_EXCEPTION_CHECKS_FAILED)
3260  {
3261  *Action = introGuestNotAllowed;
3262 
3263  // Checks have more priority than exception searching. But not more than signatures!
3264  if (*Reason != introReasonSignatureNotMatched)
3265  {
3266  *Reason = introReasonExtraChecksFailed;
3267  }
3268 
3270  }
3271  else if (status == INT_STATUS_EXCEPTION_CHECKS_OK)
3272  {
3273  *Action = introGuestAllowed;
3274  *Reason = feedbackException ? introReasonAllowedFeedback : introReasonAllowed;
3275  }
3276  else
3277  {
3278  ERROR("[ERROR] IntExceptVerfiyExtra Type: `%d` failed: 0x%08x. Will ignore this exception!\n",
3279  ExceptionType, status);
3280 
3281  *Action = introGuestNotAllowed;
3282  *Reason = introReasonInternalError;
3283 
3284  return status;
3285  }
3286 
3287  // 3. Check the signature
3288  status = IntExceptVerifySignature(Exception, Originator, Victim, ExceptionType, Reason);
3289  if (status == INT_STATUS_SIGNATURE_NOT_FOUND)
3290  {
3291  // Signatures have the most priority. We overwrite the action every time.
3292  *Action = introGuestNotAllowed;
3293 
3295  }
3296  else if (status == INT_STATUS_SIGNATURE_MATCHED)
3297  {
3298  *Action = introGuestAllowed;
3299  *Reason = feedbackException ? introReasonAllowedFeedback : introReasonAllowed;
3300  }
3301  else
3302  {
3303  ERROR("[ERROR] IntExceptVerifySignature failed: 0x%08x. Will ignore this exception!\n", status);
3304 
3305  *Action = introGuestNotAllowed;
3306  *Reason = introReasonInternalError;
3307 
3308  return status;
3309  }
3310 
3311  // If we get to this point, then allow the action
3313 }
3314 
3315 
3316 void
3318  _In_ EXCEPTION_VICTIM_ZONE *Victim,
3319  _In_ void *Originator,
3320  _In_ EXCEPTION_TYPE Type,
3321  _Out_ INTRO_ACTION *Action,
3322  _Out_ INTRO_ACTION_REASON *Reason,
3323  _In_ INTRO_EVENT_TYPE EventClass
3324  )
3338 {
3339  INTSTATUS status;
3340  static BOOLEAN showNotLoadedWarning = TRUE;
3341 
3342  UNREFERENCED_PARAMETER(EventClass);
3343 
3344  if (Action != NULL)
3345  {
3346  *Action = introGuestNotAllowed;
3347  }
3348 
3349  if (Reason != NULL)
3350  {
3351  *Reason = introReasonInternalError;
3352  }
3353 
3354  if (NULL == Victim)
3355  {
3356  ERROR("[ERROR] The 'Victim' argument for exceptions mechanism is invalid!\n");
3357  return;
3358  }
3359 
3360  if (NULL == Originator)
3361  {
3362  ERROR("[ERROR] The 'Originator' argument for exceptions mechanism is invalid!\n");
3363  return;
3364  }
3365 
3366  if (NULL == Action)
3367  {
3368  ERROR("[ERROR] The 'Action' argument for exceptions mechanism is invalid!\n");
3369  return;
3370  }
3371 
3372  if (NULL == Reason)
3373  {
3374  ERROR("[ERROR] The 'Reason' argument for exceptions mechanism is invalid!\n");
3375  return;
3376  }
3377 
3378  // Default values. If beta is enabled, let the caller handle that
3379  *Action = introGuestNotAllowed;
3380  *Reason = introReasonNoException;
3381 
3382  if (NULL == gGuest.Exceptions || !gGuest.Exceptions->Loaded)
3383  {
3384  if (showNotLoadedWarning)
3385  {
3386  LOG("**************************************************\n");
3387  LOG("************Exceptions are not loaded*************\n");
3388  LOG("**************************************************\n");
3389 
3390  showNotLoadedWarning = FALSE;
3391  }
3392 
3393  *Action = introGuestAllowed;
3395  return;
3396  }
3397 
3398  switch(Type)
3399  {
3400  case exceptionTypeKm:
3401  status = IntExceptKernel(Victim, Originator, Action, Reason);
3402  break;
3403  case exceptionTypeUm:
3404  status = IntExceptUser(Victim, Originator, Action, Reason);
3405  break;
3406 
3407  case exceptionTypeKmUm:
3408  status = IntExceptKernelUser(Victim, Originator, Action, Reason);
3409  break;
3410 
3411  default:
3412  ERROR("[ERROR] Invalid exception type (%d)...\n", Type);
3413  return;
3414  }
3415 
3416  if (status != INT_STATUS_EXCEPTION_NOT_MATCHED && !INT_SUCCESS(status))
3417  {
3418  ERROR("[ERROR] IntExcept failed for type %d with status: 0x%08x . Will ignore this exception!\n", Type, status);
3419  }
3420 
3421  switch(Type)
3422  {
3423  case exceptionTypeKm:
3424  IntExceptKernelLogInformation(Victim, Originator, *Action, *Reason);
3425  break;
3426  case exceptionTypeUm:
3427  IntExceptUserLogInformation(Victim, Originator, *Action, *Reason);
3428  break;
3429 
3430  case exceptionTypeKmUm:
3431  IntExceptKernelUserLogInformation(Victim, Originator, *Action, *Reason);
3432  break;
3433 
3434  default:
3435  ERROR("[ERROR] Invalid exception type (%d)...\n", Type);
3436  break;
3437  }
3438 
3439  // IntSerializeException(Victim, Originator, Type, *Action, *Reason, EventClass);
3440 
3441  if (Victim->ZoneType == exceptionZoneEpt)
3442  {
3443  IntExceptInvCbCacheByGva(Victim->Ept.Gva);
3444  }
3445  else if (Victim->ZoneType == exceptionZoneIntegrity)
3446  {
3447  IntExceptInvCbCacheByGva(Victim->Integrity.StartVirtualAddress);
3448  }
3449 }
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:79
PCHAR CommandLine
The command line with which the process was created (can be NULL).
Definition: winprocess.h:112
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:3317
struct _EXCEPTION_KM_ORIGINATOR::@63 Original
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:1016
#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:3127
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:682
#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:1531
#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:233
The value hash is for the process command line (valid only for value signature).
Definition: exceptions.h:676
Kernel module (ntoskrnl.exe, hal.dll, etc.)
Definition: intro_types.h:235
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:377
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
Definition: winguest.c:35
LIST_HEAD KernelUserExceptions[EXCEPTION_TABLE_SIZE]
Array of linked lists used for kernel-user mode exceptions.
Definition: exceptions.h:109
LIST_HEAD ValueCodeSignatures
Linked list used for value-code signatures.
Definition: exceptions.h:134
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:270
INTSTATUS IntPeGetDirectory(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD DirectoryEntry, IMAGE_DATA_DIRECTORY *Directory)
Validate & return the indicated image data directory.
Definition: winpe.c:527
The signature is valid only on 64 bit systems/processes.
Definition: exceptions.h:671
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:207
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
Fast IO Dispatch (Windows only)
Definition: intro_types.h:233
LIST_HEAD NoNameKernelExceptions
Linked list used for kernel-mode exceptions that don&#39;t have a valid originator (-).
Definition: exceptions.h:98
#define PAGE_REMAINING(addr)
Definition: pgtable.h:163
Infinity hook modifications of WMI_LOGGER_CONTEXT.GetCpuClock.
Definition: intro_types.h:261
Describes a value signature.
Definition: exceptions.h:405
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:1020
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:142
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:2521
#define ZONE_LIB_RESOURCES
Used for the resources section (usually .rsrc inside a driver or dll).
Definition: exceptions.h:691
User-mode exception.
Definition: exceptions.h:61
User-mode non executable zone.
Definition: intro_types.h:244
LIST_HEAD GenericUserExceptions
Linked list used for user-mode exceptions that have a generic originator(*).
Definition: exceptions.h:92
#define INTRO_OPT_PROT_KM_NT
Enable kernel image protection (Windows only).
Definition: intro_types.h:392
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
LIST_HEAD ExportSignatures
Linked list used for export signatures.
Definition: exceptions.h:132
LIST_HEAD ProcessCreationAlertExceptions
Linked list used for process-creation exceptions that are added from alert.
Definition: exceptions.h:123
long long my_llabs(long long value)
Definition: introcrt.c:600
The exception sends a feedback alert.
Definition: exceptions.h:585
struct _WINUM_MODULE_CACHE::@236 Info
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:710
#define INT_STATUS_SIGNATURE_MATCHED
Definition: introstatus.h:401
LIST_HEAD VersionIntroSignatures
Linked list used for introspection version signatures.
Definition: exceptions.h:137
#define INT_STATUS_EXCEPTION_CHECKS_OK
Definition: introstatus.h:396
Describe a user-mode glob exception.
Definition: exceptions.h:326
LIST_HEAD ProcessCreationSignatures
Linked list used for process-creation signatures.
Definition: exceptions.h:138
LIST_HEAD IdtSignatures
Linked list used for IDT signatures.
Definition: exceptions.h:135
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:2190
#define IntExceptErase(Ptr, Tag)
Frees an exception or a signature buffer and removes it from the list it is currently in...
Definition: exceptions.h:1316
#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:125
Describes a user-mode originator.
Definition: exceptions.h:933
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:652
The range-identifier used for idt signature.
Definition: exceptions.h:78
LIST_HEAD UserExceptions[EXCEPTION_TABLE_SIZE]
Array of linked lists used for user-mode exceptions.
Definition: exceptions.h:110
int INTSTATUS
The status data type.
Definition: introstatus.h:24
__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:277
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:147
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:99
DWORD NumberOfServices
The number of entries in the SSDT.
Definition: winguest.h:805
The exception is valid only for Linux.
Definition: exceptions.h:593
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:127
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:2240
Describes a kernel-mode originator.
Definition: exceptions.h:897
User-mode exception that accepts glob content.
Definition: exceptions.h:63
#define IC_TAG_ESIG
Exception signatures structures.
Definition: memtags.h:26
Codeblocks were extracted at a medium level.
Definition: exceptions.h:673
#define for_each_idt_signature(_ex_head, _var_name)
Definition: exceptions.h:1014
The range-identifier used for value signature.
Definition: exceptions.h:77
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:274
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
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:75
#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:2696
WIN_PROCESS_OBJECT * WinProc
The windows process that&#39;s modifying the memory (always present).
Definition: exceptions.h:946
INTRO_PC_VIOLATION_TYPE PcType
Valid if the current violation is DPI Process Creation Violation.
Definition: exceptions.h:980
DWORD CommHash
The CRC32 checksum of the Comm field.
Definition: lixprocess.h:65
WORD Build
Build number.
Definition: intro_types.h:2238
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:959
QWORD Start
Start of the memory described by the VMA.
Definition: lixmm.h:19
The name is missing.
Definition: exceptions.h:657
#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:123
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:1291
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:2668
Exposes the functions used to provide Windows Threads related support.
QWORD Cr3
Process PDBR. Includes PCID.
Definition: winprocess.h:96
Token privileges.
Definition: intro_types.h:263
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:131
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:76
struct _CB_CACHE * PCB_CACHE
TIMER_FRIENDLY void IntDumpInstruction(INSTRUX *Instruction, QWORD Rip)
This function dumps a given instruction (textual disassembly).
Definition: dumper.c:513
LIST_HEAD KernelUserAlertExceptions
Linked list used for kernel-user mode exceptions that are added from alert.
Definition: exceptions.h:129
#define ZONE_LIB_CODE
Used for a generic code zone.
Definition: exceptions.h:688
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:1010
#define INITIAL_CRC_VALUE
Definition: introdefs.h:221
Hal interrupt controller.
Definition: intro_types.h:250
EXCEPTIONS * Exceptions
The exceptions that are currently loaded.
Definition: guests.h:388
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:1757
#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:54
#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:713
DWORD Hash
The hash of the modified zone.
Definition: exceptions.h:370
QWORD EventId
The current event ID.
Definition: exceptions.c:53
#define for_each_version_intro_signature(_ex_head, _var_name)
Definition: exceptions.h:1018
LIX_TASK_OBJECT * LixProc
The Linux process that&#39;s modifying the memory (always present).
Definition: exceptions.h:947
LIST_HEAD KernelFeedbackExceptions
Linked list used for kernel-mode exceptions that have the feedback flag.
Definition: exceptions.h:116
#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:286
unsigned long long QWORD
Definition: intro_types.h:53
CHAR Name[IMAGE_BASE_NAME_LEN]
Process base name.
Definition: winprocess.h:106
The name is the operating system kernel name.
Definition: exceptions.h:628
enum _EXCEPTION_TYPE EXCEPTION_TYPE
The type of an exception.
The signature is valid only on 32 bit systems/processes.
Definition: exceptions.h:670
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:1505
#define TRUE
Definition: intro_types.h:30
QWORD Ssdt
Guest virtual address of the SSDT structure inside the kernel.
Definition: winguest.h:804
union _OPERAND_VALUE::@22 Value
The actual operand value.
Describe a value signature hash.
Definition: exceptions.h:366
#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:73
Executions inside the SharedUserData region.
Definition: intro_types.h:264
#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:87
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:279
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:62
struct _WIN_PROCESS_OBJECT * Process
The process object related to this subsystem.
Definition: winprocess.h:54
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:118
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:2938
WORD Major
Major version.
Definition: intro_types.h:2241
The modified object is a MSR.
Definition: exceptions.h:711
#define WARNING(fmt,...)
Definition: glue.h:60
The exception will take into consideration the return driver.
Definition: exceptions.h:604
#define ZONE_LIB_EXPORTS
Used for the exports of a dll, driver, etc.
Definition: exceptions.h:687
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:53
Describes the modified zone.
Definition: exceptions.h:847
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:248
Describe a user-mode exception.
Definition: exceptions.h:298
The Virtualization exception agent injected inside the guest.
Definition: intro_types.h:256
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:50
UINT32 Characteristics
Definition: winpe.h:92
LIST_HEAD GlobUserExceptions
Linked list used for user-mode exceptions that contains glob content.
Definition: exceptions.h:106
User-mode library.
Definition: intro_types.h:245
DWORD Hash
The hash of the modified function name.
Definition: exceptions.h:380
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:1998
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:111
#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:904
LIST_HEAD GenericKernelExceptions
Linked list used for kernel-mode exceptions that have a generic originator (*).
Definition: exceptions.h:90
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:689
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:370
LIST_HEAD ValueSignatures
Linked list used for value signatures.
Definition: exceptions.h:133
char Comm[LIX_COMM_SIZE]
The short name of the executable.
Definition: lixprocess.h:44
Self mapping index in PDBR.
Definition: intro_types.h:251
QWORD KeServiceDescriptorTable
Guest virtual address of the KeServiceDescriptorTable variable.
Definition: winguest.h:803
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:48
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:714
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:678
SSDT (Windows only)
Definition: intro_types.h:232
LIST_HEAD NoNameKernelUserExceptions
Linked list used for kernel-user mode exceptions that don&#39;t have a valid originator (-)...
Definition: exceptions.h:103
WIN_PROCESS_MODULE * WinLib
The windows library that&#39;s modifying the memory (if that&#39;s the case).
Definition: exceptions.h:953
#define for_each_cb_signature(_ex_head, _var_name)
Definition: exceptions.h:1006
Introspection version info.
Definition: intro_types.h:2233
DWORD Type
Contains a type of signature (EXCEPTION_SIGNATURE_TYPE).
Definition: exceptions.h:238
LIST_HEAD ProcessCreationFeedbackExceptions
Linked list used for process-creation exceptions that have the feedback flag.
Definition: exceptions.h:120
#define for_each_value_code_signature(_ex_head, _var_name)
Definition: exceptions.h:1012
TIMER_FRIENDLY void IntDumpBuffer(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
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:2367
LIST_HEAD UserFeedbackExceptions
Linked list used for user-mode exceptions that have the feedback flag.
Definition: exceptions.h:114
The thread which created the process has started execution on some suspicious code.
Definition: intro_types.h:1537
Virtual SYSCALL (user-mode, Linux-only)
Definition: intro_types.h:254
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:108
#define ZONE_READ
Used for read violation.
Definition: exceptions.h:699
#define ZONE_DEP_EXECUTION
Used for executions inside DEP zones.
Definition: exceptions.h:695
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:253
The range-identifier used for codeblocks signature.
Definition: exceptions.h:80
#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:95
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:64
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:57
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:856
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:1149
#define ZONE_LIB_IMPORTS
Used for the imports of a dll, driver, etc.
Definition: exceptions.h:686
void * HookObject
The HookObject used for EPT hooks set inside this process&#39;s memory space.
Definition: lixprocess.h:92
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:74
BYTE Version
The version field of the version string.
Definition: lixguest.h:484
struct _EXCEPTION_KM_ORIGINATOR::@62 Return
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:696
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:698
WORD Revision
Revision.
Definition: intro_types.h:2239
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:2283
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:100
QWORD Rip
Where the write/exec came.
Definition: exceptions.h:958
The name is the operating system HAL name (valid only for windows).
Definition: exceptions.h:629
#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:29
#define for_each_export_signature(_ex_head, _var_name)
Definition: exceptions.h:1008
#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.
struct _INT_VERSION_INFO::@327 VersionInfo
Structured version information.
#define FALSE
Definition: intro_types.h:34
This structure describes a running process inside the guest.
Definition: winprocess.h:81
#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:136