Bitdefender Hypervisor Memory Introspection
exceptions_krnusr.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 
17 
18 extern char gExcLogLine[2 * ONE_KILOBYTE];
19 
20 
21 static void
24  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
25  _In_ INTRO_ACTION Action,
27  )
36 {
37  KERNEL_DRIVER *pDriver = NULL;
38  KERNEL_DRIVER *pRetDriver = NULL;
39  DWORD modNameAlignment;
40  char *l;
41  int ret, rem;
42  char instr[ND_MIN_BUF_SIZE];
43 
44  pDriver = Originator->Original.Driver;
45  pRetDriver = Originator->Return.Driver;
46 
47  modNameAlignment = 0;
48  l = gExcLogLine;
49  rem = sizeof(gExcLogLine);
50 
51  if (Originator->Instruction)
52  {
53  NDSTATUS ndstatus = NdToText(Originator->Instruction, Originator->Original.Rip, sizeof(instr), instr);
54  if (!ND_SUCCESS(ndstatus))
55  {
56  memcpy(instr, EXPORT_NAME_UNKNOWN, sizeof(EXPORT_NAME_UNKNOWN));
57  }
58  }
59  else
60  {
61  memcpy(instr, EXCEPTION_NO_INSTRUCTION, sizeof(EXCEPTION_NO_INSTRUCTION));
62  }
63 
64  ret = IntExceptPrintWinKmModInfo(pDriver, "Originator-> Module: ", l, rem, modNameAlignment);
65  rem -= ret;
66  l += ret;
67 
68  ret = snprintf(l, rem, ", RIP %0*llx", gGuest.WordSize * 2, Originator->Original.Rip);
69 
70  if (ret < 0 || ret >= rem)
71  {
72  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
73  }
74  else
75  {
76  rem -= ret;
77  l += ret;
78  }
79 
80  if (Originator->Original.Section[0] != 0)
81  {
82  ret = snprintf(l, rem, " (%s)", Originator->Original.Section);
83 
84  if (ret < 0 || ret >= rem)
85  {
86  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
87  }
88  else
89  {
90  rem -= ret;
91  l += ret;
92  }
93  }
94 
95  if (instr[0] != 0)
96  {
97  ret = snprintf(l, rem, ", Instr: %s", instr);
98 
99  if (ret < 0 || ret >= rem)
100  {
101  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
102  }
103  else
104  {
105  rem -= ret;
106  l += ret;
107  }
108  }
109 
110  ret = snprintf(l, rem, ", IsInjection: %s %s",
111  (Originator->Injection.User || Originator->Injection.Kernel) ? "yes" : "no",
112  Originator->Injection.User ? "(user-mode)" :
113  Originator->Injection.Kernel ? "(kernel-mode)" : "");
114 
115  if (ret < 0 || ret >= rem)
116  {
117  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
118  }
119  else
120  {
121  rem -= ret;
122  l += ret;
123  }
124 
125  LOG("%s\n", gExcLogLine);
126 
127  if (Originator->Return.Driver && Originator->Original.Rip != Originator->Return.Rip)
128  {
129  l = gExcLogLine;
130  rem = sizeof(gExcLogLine);
131 
132  ret = IntExceptPrintWinKmModInfo(pRetDriver, "Return -> Module: ", l, rem, modNameAlignment);
133  rem -= ret;
134  l += ret;
135 
136  ret = snprintf(l, rem, ", RIP %0*llx", gGuest.WordSize * 2, Originator->Return.Rip);
137 
138  if (ret < 0 || ret >= rem)
139  {
140  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
141  }
142  else
143  {
144  rem -= ret;
145  l += ret;
146  }
147 
148  if (Originator->Return.Section[0] != 0)
149  {
150  ret = snprintf(l, rem, "(%s)", Originator->Return.Section);
151 
152  if (ret < 0 || ret >= rem)
153  {
154  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
155  }
156  else
157  {
158  rem -= ret;
159  l += ret;
160  }
161  }
162 
163  LOG("%s\n", gExcLogLine);
164  }
165 
166  if (Originator->Process.Process != NULL)
167  {
168  l = gExcLogLine;
169  rem = sizeof(gExcLogLine);
170 
172  {
173  ret = IntExceptPrintWinProcInfo(Originator->Process.WinProc, "Originator Process: ", l, rem, 0);
174  }
175  else if (gGuest.OSType == introGuestLinux)
176  {
177  ret = IntExceptPrintLixTaskInfo(Originator->Process.LixProc, "Originator Process: ", l, rem, 0);
178  }
179 
180  rem -= ret;
181  l += ret;
182 
183  LOG("%s\n", gExcLogLine);
184  }
185 
186  if (Victim->Object.Type == introObjectTypeUmModule)
187  {
188  l = gExcLogLine;
189  rem = sizeof(gExcLogLine);
190 
191  ret = IntExceptPrintWinProcInfo(Victim->Object.Library.WinMod->Subsystem->Process, "Process: ",
192  l, rem, 0);
193  rem -= ret;
194  l += ret;
195 
196  LOG("%s\n", gExcLogLine);
197 
198  l = gExcLogLine;
199  rem = sizeof(gExcLogLine);
200 
201  WINUM_CACHE_EXPORT *pExport = NULL;
202 
203  ret = IntExceptPrintWinModInfo(Victim->Object.Library.WinMod, "Victim -> Module: ", l, rem, modNameAlignment);
204  if (ret < 0 || ret >= rem)
205  {
206  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
207  }
208  else
209  {
210  rem -= ret;
211  l += ret;
212  }
213 
214  if (Victim->Object.Library.Export == NULL)
215  {
216  pExport = IntWinUmCacheGetExportFromRange(Victim->Object.Library.WinMod, Victim->Ept.Gva, 0x20);
217  }
218  else
219  {
220  pExport = Victim->Object.Library.Export;
221  }
222 
223  if (pExport != NULL)
224  {
225  ret = snprintf(l, rem, ", Exports (%u) : [", pExport->NumberOfOffsets);
226  if (ret < 0 || ret >= rem)
227  {
228  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
229  }
230  else
231  {
232  rem -= ret;
233  l += ret;
234  }
235 
236  for (DWORD export = 0; export < pExport->NumberOfOffsets; export++)
237  {
238  if (export == pExport->NumberOfOffsets - 1)
239  {
240  ret = snprintf(l, rem, "'%s'", pExport->Names[export]);
241  }
242  else
243  {
244  ret = snprintf(l, rem, "'%s',", pExport->Names[export]);
245  }
246 
247  if (ret < 0 || ret >= rem)
248  {
249  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
250  }
251  else
252  {
253  rem -= ret;
254  l += ret;
255  }
256 
257  }
258 
259  ret = snprintf(l, rem, "], Delta: +%02x, ",
260  (DWORD)(Victim->Ept.Gva - Victim->Object.Library.WinMod->VirtualBase - pExport->Rva));
261  if (ret < 0 || ret >= rem)
262  {
263  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
264  }
265  else
266  {
267  rem -= ret;
268  l += ret;
269  }
270  }
271 
272  ret = snprintf(l, rem, ", Address: (%0*llx, %0*llx)",
273  gGuest.WordSize * 2, Victim->Ept.Gva,
274  gGuest.WordSize * 2, Victim->Ept.Gpa);
275  if (ret < 0 || ret >= rem)
276  {
277  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
278  }
279  else
280  {
281  rem -= ret;
282  l += ret;
283  }
284 
285  ret = snprintf(l, rem, ", WriteInfo: (%u, %016llx -> %016llx)",
286  Victim->WriteInfo.AccessSize,
287  Victim->WriteInfo.OldValue[0],
288  Victim->WriteInfo.NewValue[0]);
289  if (ret < 0 || ret >= rem)
290  {
291  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
292  }
293  else
294  {
295  rem -= ret;
296  l += ret;
297  }
298 
299  if (Victim->ZoneFlags)
300  {
301  ret = snprintf(l, rem, ", Flags:%s%s%s%s%s (0x%llx)",
302  (Victim->ZoneFlags & ZONE_LIB_IMPORTS) ? " IMPORTS" : "",
303  (Victim->ZoneFlags & ZONE_LIB_EXPORTS) ? " EXPORTS" : "",
304  (Victim->ZoneFlags & ZONE_LIB_CODE) ? " CODE" : "",
305  (Victim->ZoneFlags & ZONE_LIB_DATA) ? " DATA" : "",
306  (Victim->ZoneFlags & ZONE_LIB_RESOURCES) ? " RSRC" : "",
307  (unsigned long long)Victim->ZoneFlags);
308  if (ret < 0 || ret >= rem)
309  {
310  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
311  }
312  else
313  {
314  rem -= ret;
315  l += ret;
316  }
317  }
318 
319  LOG("%s\n", gExcLogLine);
320  }
321 
322  if (Action == introGuestNotAllowed)
323  {
324  l = gExcLogLine;
325  rem = sizeof(gExcLogLine);
326 
327  ret = snprintf(l, rem, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%sROOTKIT (kernel-user mode) ",
328  Victim->Object.Library.WinMod->Subsystem->Process->BetaDetections ? " (B) " : " ");
329  if (ret < 0 || ret >= rem)
330  {
331  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
332  }
333  else
334  {
335  rem -= ret;
336  l += ret;
337  }
338 
339  switch (Reason)
340  {
342  ret = snprintf(l, rem, "(no sig)");
343  break;
345  ret = snprintf(l, rem, "(no exc)");
346  break;
348  ret = snprintf(l, rem, "(extra)");
349  break;
351  ret = snprintf(l, rem, "(error)");
352  break;
354  ret = snprintf(l, rem, "(value)");
355  break;
357  ret = snprintf(l, rem, "(export)");
358  break;
360  ret = snprintf(l, rem, "(value code)");
361  break;
363  ret = snprintf(l, rem, "(idt)");
364  break;
366  ret = snprintf(l, rem, "(version os)");
367  break;
369  ret = snprintf(l, rem, "(version intro)");
370  break;
372  ret = snprintf(l, rem, "(process creation)");
373  break;
374  case introReasonUnknown:
375  ret = snprintf(l, rem, "(unknown)");
376  break;
377  default:
378  ret = snprintf(l, rem, "(%d)", Reason);
379  break;
380  }
381 
382  if (ret < 0 || ret >= rem)
383  {
384  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
385  }
386  else
387  {
388  rem -= ret;
389  l += ret;
390  }
391 
392  snprintf(l, rem, " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
393 
394  LOG("%s\n\n", gExcLogLine);
395  }
396  for (DWORD t = 0; t < Originator->StackTrace.NumberOfTraces; t++)
397  {
398  if (NULL != Originator->StackTrace.Traces[t].ReturnModule)
399  {
400  LOG("[STACK TRACE] [at 0x%016llx] returning to [%s at 0x%016llx]\n",
401  Originator->StackTrace.Traces[t].CurrentRip,
402  utf16_for_log(((KERNEL_DRIVER *)Originator->StackTrace.Traces[t].ReturnModule)->Name),
403  Originator->StackTrace.Traces[t].ReturnAddress);
404  }
405  else
406  {
407  LOG("[STACK TRACE] [at 0x%016llx]\n", Originator->StackTrace.Traces[t].CurrentRip);
408  }
409  }
410 }
411 
412 
413 void
415  _In_ EXCEPTION_VICTIM_ZONE *Victim,
416  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
417  _In_ INTRO_ACTION Action,
419  )
428 {
429  if ((introGuestNotAllowed != Action) && (introReasonAllowedFeedback != Reason))
430  {
431  return;
432  }
433 
435  {
436  IntExceptKernelUserLogWindowsInformation(Victim, Originator, Action, Reason);
437  }
438  else if (gGuest.OSType == introGuestLinux)
439  {
440  return;
441  }
442 
443  if (!(Victim->ZoneFlags & ZONE_INTEGRITY))
444  {
445  IntExceptDumpSignatures(Originator, Victim, TRUE, FALSE);
446  IntExceptDumpSignatures(Originator, Victim, TRUE, TRUE);
447  }
448 
449 }
450 
451 
452 static __inline BOOLEAN
454  _In_ EXCEPTION_VICTIM_ZONE *Victim,
455  _In_ KUM_EXCEPTION *Exception
456  )
465 {
466  BOOLEAN match = FALSE;
467 
468  if ((Exception->Flags & EXCEPTION_FLG_READ) &&
469  (Victim->ZoneFlags & ZONE_READ))
470  {
471  match = TRUE;
472  }
473 
474  if ((Exception->Flags & EXCEPTION_FLG_EXECUTE) &&
475  (Victim->ZoneFlags & ZONE_EXECUTE))
476  {
477  match = TRUE;
478  }
479 
480  if ((Exception->Flags & EXCEPTION_FLG_WRITE) &&
481  (Victim->ZoneFlags & ZONE_WRITE))
482  {
483  match = TRUE;
484  }
485 
486  return match;
487 }
488 
489 
490 static __inline BOOLEAN
492  _In_ KUM_EXCEPTION *Exception
493  )
501 {
502  BOOLEAN match = FALSE;
503 
504  if ((Exception->Flags & EXCEPTION_FLG_32) &&
505  (Exception->Flags & EXCEPTION_FLG_64))
506  {
507  match = TRUE;
508  }
509  else if ((Exception->Flags & EXCEPTION_FLG_64) &&
510  gGuest.Guest64)
511  {
512  match = TRUE;
513  }
514  else if ((Exception->Flags & EXCEPTION_FLG_32) &&
515  !gGuest.Guest64)
516  {
517  match = TRUE;
518  }
519 
520  return match;
521 }
522 
523 
524 static __inline BOOLEAN
526  _In_ EXCEPTION_VICTIM_ZONE *Victim,
527  _In_ KUM_EXCEPTION *Exception
528  )
537 {
538  if (Exception->Victim.NameHash == umExcNameAny ||
539  Exception->Victim.NameHash == Victim->Object.NameHash)
540  {
541  return TRUE;
542  }
543 
544  return FALSE;
545 }
546 
547 
548 static __inline BOOLEAN
550  _In_ EXCEPTION_VICTIM_ZONE *Victim,
551  _In_ KUM_EXCEPTION *Exception
552  )
562 {
563  if (Exception->Victim.ProcessHash == umExcNameAny)
564  {
565  return TRUE;
566  }
567  else
568  {
570  {
571  return (Exception->Victim.ProcessHash == Victim->Object.Library.WinMod->Subsystem->Process->NameHash);
572  }
573  else
574  {
575  WARNING("[WARNING] Not supported for Linux guest!\n");
576  }
577  }
578 
579  return FALSE;
580 }
581 
582 
583 static __inline BOOLEAN
585  _In_ EXCEPTION_VICTIM_ZONE *Victim,
586  _In_ KUM_EXCEPTION *Exception
587  )
596 {
597  switch (Exception->Type)
598  {
599  case kumObjAny:
600  return TRUE;
601 
602  case kumObjModule:
603  if (Victim->Object.Type == introObjectTypeUmModule)
604  {
605  return TRUE;
606  }
607  break;
608 
609  case kumObjModuleImports:
610  if ((Victim->Object.Type == introObjectTypeUmModule) &&
611  (Victim->ZoneFlags & ZONE_LIB_IMPORTS))
612  {
613  return TRUE;
614  }
615  break;
616 
617  case kumObjModuleExports:
618  if ((Victim->Object.Type == introObjectTypeUmModule) &&
619  (Victim->ZoneFlags & ZONE_LIB_EXPORTS))
620  {
621  return TRUE;
622  }
623  break;
624 
625  default:
626  LOG("[ERROR] This is a corruption in the update/exception. Type = %d!\n", Exception->Type);
627  break;
628  }
629 
630  return FALSE;
631 }
632 
633 
634 INTSTATUS
636  _In_ EXCEPTION_VICTIM_ZONE *Victim,
637  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
638  _In_ KUM_EXCEPTION *Exception
639  )
660 {
661  BOOLEAN match = FALSE;
662 
663  // If the current write is due to an injection but the exception doesn't have any of the
664  // kernel/user injection flags then don't match it.
665  if ((Originator->Injection.User || Originator->Injection.Kernel) &&
666  (Exception->Flags & (EXCEPTION_KUM_FLG_KERNEL | EXCEPTION_KUM_FLG_USER)) == 0)
667  {
669  }
670 
671  // If the current write is not due to an injection but the exception has any of the
672  // kernel/user injection flags then don't match it.
673  if ((!Originator->Injection.User && !Originator->Injection.Kernel) &&
674  (Exception->Flags & (EXCEPTION_KUM_FLG_KERNEL | EXCEPTION_KUM_FLG_USER)) != 0)
675  {
677  }
678 
679  // Finally match the kernel/user injection flags if needed.
680  if (((Exception->Flags & EXCEPTION_KUM_FLG_KERNEL) && Originator->Injection.User) ||
681  ((Exception->Flags & EXCEPTION_KUM_FLG_USER) && Originator->Injection.Kernel))
682  {
684  }
685 
686  if (!IntExceptKernelUserMatchZoneFlags(Victim, Exception))
687  {
689  }
690 
691  if (!IntExceptKernelUserMatchArch(Exception))
692  {
694  }
695 
696  if (!IntExceptKernelUserMatchNameHash(Victim, Exception))
697  {
699  }
700 
701  if (!IntExceptKernelUserMatchProcessHash(Victim, Exception))
702  {
704  }
705 
706  if (!IntExceptKernelUserMatchObjectType(Victim, Exception))
707  {
709  }
710 
711  if ((Exception->Flags & EXCEPTION_KM_FLG_NON_DRIVER) &&
712  (Originator->Original.Driver != NULL))
713  {
715  }
716 
717  if (Exception->Flags & EXCEPTION_FLG_INIT)
718  {
719  match = FALSE;
720 
721  // a. On integrity zones, this is all we can check
722  if ((Victim->ZoneType == exceptionZoneIntegrity) &&
723  (Victim->WriteInfo.OldValue[0] == 0))
724  {
725  match = TRUE;
726  }
727  // b. Kernel's INIT section writes
728  else if ((Exception->Flags & EXCEPTION_KM_FLG_RETURN_DRV) &&
729  (Originator->Return.NameHash == kmExcNameKernel))
730  {
731  // match anything that starts with init/INIT
733  {
734  match = 0 == memcmp(Originator->Return.Section, "INIT", 4);
735  }
736  else
737  {
738  match = 0 == memcmp(Originator->Return.Section, "init", 4);
739  }
740  }
741  else if (Originator->Original.NameHash == kmExcNameKernel)
742  {
743  // match anything that starts with init/INIT
745  {
746  match = 0 == memcmp(Originator->Original.Section, "INIT", 4);
747  }
748  else
749  {
750  match = 0 == memcmp(Originator->Original.Section, "init", 4);
751  }
752  }
753  // c. RIP is in EntryPoint
754  else if (Originator->IsEntryPoint)
755  {
756  match = TRUE;
757  }
758  // d. Old value was 0
759  else if (Victim->WriteInfo.OldValue[0] == 0)
760  {
761  match = TRUE;
762  }
763 
764  if (!match)
765  {
767  }
768  }
769 
770  // If we get here, then allow the action. Anyway, the extra checks & signatures mechanism will actually allow it
772 }
773 
774 
775 INTSTATUS
777  _In_ EXCEPTION_VICTIM_ZONE *Victim,
778  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
779  _Out_ INTRO_ACTION *Action,
780  _Out_ INTRO_ACTION_REASON *Reason
781  )
798 {
800  BOOLEAN sameRip = FALSE;
801  DWORD hash = INITIAL_CRC_VALUE;
802  BYTE id;
803 
804  if (NULL == Victim)
805  {
807  }
808 
809  if (NULL == Originator)
810  {
812  }
813 
814  if (NULL == Action)
815  {
817  }
818 
819  if (NULL == Reason)
820  {
822  }
823 
824  *Action = introGuestNotAllowed;
825  *Reason = introReasonNoException;
826 
827  // In some cases the Old/New values are the same - allow them by default.
828  if (__unlikely(Victim->ZoneType == exceptionZoneEpt && !!(Victim->ZoneFlags & ZONE_WRITE) &&
829  !memcmp(Victim->WriteInfo.OldValue, Victim->WriteInfo.NewValue,
830  MIN(Victim->WriteInfo.AccessSize, sizeof(Victim->WriteInfo.NewValue)))))
831  {
832  *Action = introGuestAllowed;
833  *Reason = introReasonSameValue;
834 
836  }
837 
838  if (Originator->Injection.User)
839  {
841  {
842  hash = Originator->Process.WinProc->NameHash;
843  }
844  else if (gGuest.OSType == introGuestLinux)
845  {
846  hash = Originator->Process.LixProc->CommHash;
847  }
848  else
849  {
850  ERROR("[ERROR] Unsupported guest type '%d'! Abort ...\n", gGuest.OSType);
852  }
853  }
854  else
855  {
856  if (Originator->Injection.Kernel)
857  {
858  hash = Originator->Return.NameHash;
859  }
860  else
861  {
862  hash = Originator->Original.NameHash;
863  }
864  }
865 
867  {
868  if (((pEx->Flags & EXCEPTION_KUM_FLG_KERNEL) && Originator->Injection.User) ||
869  ((pEx->Flags & EXCEPTION_KUM_FLG_USER) && Originator->Injection.Kernel))
870  {
871  continue;
872  }
873 
874  if (pEx->Originator.NameHash == kumExcNameAny)
875  {
876  // For now, we do not support exceptions from the alert that has originator kmExcNameAny.
877  // If an exception from the alert has no originator, kumExcNameNone will be used as the exception originator
878  goto _match_ex_alert;
879  }
880 
881  if (!Originator->Injection.User &&
882  Originator->Original.NameHash == INITIAL_CRC_VALUE &&
883  pEx->Originator.NameHash == kumExcNameNone)
884  {
885  goto _match_ex_alert;
886  }
887 
888  if (pEx->Originator.NameHash > hash)
889  {
890  break;
891  }
892  else if (pEx->Originator.NameHash != hash)
893  {
894  continue;
895  }
896 
897 _match_ex_alert:
898  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKmUm, Action, Reason);
899  if (status == INT_STATUS_EXCEPTION_ALLOW)
900  {
901  return status;
902  }
903  }
904 
905  if (!Originator->Injection.User && Originator->Original.NameHash == INITIAL_CRC_VALUE)
906  {
907  // Check the no name exceptions, and skip the generic ones
909  {
910  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKmUm, Action, Reason);
911  if (status == INT_STATUS_EXCEPTION_ALLOW)
912  {
913  return status;
914  }
915  }
916  }
917  else
918  {
919  // Check the generic exceptions (all of them, since originator matches anything)
921  {
922  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKmUm, Action, Reason);
923  if (status == INT_STATUS_EXCEPTION_ALLOW)
924  {
925  return status;
926  }
927  }
928  }
929 
930  if (Originator->Injection.Kernel &&
931  Originator->Original.Driver &&
932  Originator->Return.Driver &&
933  Originator->Original.Rip == Originator->Return.Rip)
934  {
935  // Don't check by RIP since it may be in different sections
936  sameRip = TRUE;
937  }
938 
939  if (hash != INITIAL_CRC_VALUE)
940  {
941  id = EXCEPTION_TABLE_ID(hash);
942 
944  {
945  if (((pEx->Flags & EXCEPTION_KUM_FLG_KERNEL) && Originator->Injection.User) ||
946  ((pEx->Flags & EXCEPTION_KUM_FLG_USER) && Originator->Injection.Kernel))
947  {
948  continue;
949  }
950 
951  // Here we only check exceptions by the name, so that cannot be missing.
952  // And the return flag must be missing.
953  if ((pEx->Flags & EXCEPTION_KUM_FLG_KERNEL) &&
954  (pEx->Originator.NameHash == INITIAL_CRC_VALUE ||
955  ((pEx->Flags & EXCEPTION_KM_FLG_RETURN_DRV) &&
956  !sameRip)))
957  {
958  continue;
959  }
960 
961  // Every list is ordered, so break when we got to a hash bigger than ours
962  if (pEx->Originator.NameHash > hash)
963  {
964  break;
965  }
966  else if (pEx->Originator.NameHash != hash)
967  {
968  continue;
969  }
970 
971  // The EXCEPTION_KM_FLG_RETURN_DRV will be deleted, so do the same verification again
972  if ((pEx->Flags & EXCEPTION_FLG_RETURN) && !sameRip)
973  {
974  continue;
975  }
976 
977  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKmUm, Action, Reason);
978  if (status == INT_STATUS_EXCEPTION_ALLOW)
979  {
980  return status;
981  }
982  }
983 
984  if (sameRip)
985  {
986  // No point in doing the same thing again
987  goto _beta_exceptions;
988  }
989  }
990 
991  // Try and match the original driver by name
992  if (!Originator->Injection.User && Originator->Return.NameHash != INITIAL_CRC_VALUE)
993  {
994  id = EXCEPTION_TABLE_ID(Originator->Return.NameHash);
996  {
997  if (pEx->Flags & EXCEPTION_KUM_FLG_USER)
998  {
999  continue;
1000  }
1001 
1002  // Here we only check exceptions by the name, so that cannot be missing
1003  // And the return flag must be set
1004  if (pEx->Originator.NameHash == INITIAL_CRC_VALUE ||
1005  (0 == (pEx->Flags & EXCEPTION_KM_FLG_RETURN_DRV)))
1006  {
1007  continue;
1008  }
1009 
1010  // Every list is ordered, so break when we got to a hash bigger than ours
1011  if (pEx->Originator.NameHash > Originator->Return.NameHash)
1012  {
1013  break;
1014  }
1015  else if (pEx->Originator.NameHash != Originator->Return.NameHash)
1016  {
1017  continue;
1018  }
1019 
1020  // The EXCEPTION_KM_FLG_RETURN_DRV will be deleted, so do the same verification again
1021  if (0 == (pEx->Flags & EXCEPTION_FLG_RETURN))
1022  {
1023  continue;
1024  }
1025 
1026  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKmUm, Action, Reason);
1027  if (status == INT_STATUS_EXCEPTION_ALLOW)
1028  {
1029  return status;
1030  }
1031  }
1032  }
1033 
1034 _beta_exceptions:
1036  {
1037  if (((pEx->Flags & EXCEPTION_KUM_FLG_KERNEL) && Originator->Injection.User) ||
1038  ((pEx->Flags & EXCEPTION_KUM_FLG_USER) && Originator->Injection.Kernel))
1039  {
1040  continue;
1041  }
1042 
1043  if (pEx->Originator.NameHash == kmExcNameAny)
1044  {
1045  goto _match_ex;
1046  }
1047 
1048  if (!Originator->Injection.User &&
1049  Originator->Original.NameHash == INITIAL_CRC_VALUE &&
1050  pEx->Originator.NameHash == kumExcNameNone)
1051  {
1052  goto _match_ex;
1053  }
1054 
1055  if (pEx->Flags & EXCEPTION_FLG_RETURN)
1056  {
1057  if (!Originator->Injection.User && pEx->Originator.NameHash != Originator->Return.NameHash)
1058  {
1059  continue;
1060  }
1061  }
1062  else
1063  {
1064  if (!Originator->Injection.User && pEx->Originator.NameHash != Originator->Original.NameHash)
1065  {
1066  continue;
1067  }
1068 
1069  if (Originator->Injection.User)
1070  {
1072  {
1073  if (pEx->Originator.NameHash != Originator->Process.WinProc->NameHash)
1074  {
1075  continue;
1076  }
1077  }
1078  else if (gGuest.OSType == introGuestLinux)
1079  {
1080  if (pEx->Originator.NameHash != Originator->Process.LixProc->CommHash)
1081  {
1082  continue;
1083  }
1084  }
1085  }
1086  }
1087 _match_ex:
1088  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKmUm, Action, Reason);
1089  if (status == INT_STATUS_EXCEPTION_ALLOW)
1090  {
1091  return status;
1092  }
1093  }
1094 
1095  return status;
1096 }
1097 
1098 
1099 INTSTATUS
1101  _In_ EXCEPTION_VICTIM_ZONE *Victim,
1102  _In_ EXCEPTION_UM_ORIGINATOR *Originator,
1103  _In_ UM_EXCEPTION *Exception
1104  )
1114 {
1115  UNREFERENCED_PARAMETER(Victim);
1116  UNREFERENCED_PARAMETER(Originator);
1117  UNREFERENCED_PARAMETER(Exception);
1118 
1120 }
#define EXCEPTION_NO_INSTRUCTION
Definition: exceptions.h:30
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
#define INT_STATUS_EXCEPTION_NOT_MATCHED
Definition: introstatus.h:406
#define __unlikely(x)
Definition: common.h:64
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
An internal error occurred (no memory, pages not present, etc.).
Definition: intro_types.h:195
uint8_t BYTE
Definition: intro_types.h:47
int IntExceptPrintWinProcInfo(WIN_PROCESS_OBJECT *Process, char *Header, char *Line, int MaxLength, DWORD NameAlignment)
Print the data from the provided WIN_PROCESS_OBJECT.
LIST_HEAD KernelUserExceptions[EXCEPTION_TABLE_SIZE]
Array of linked lists used for kernel-user mode exceptions.
Definition: exceptions.h:108
#define _In_
Definition: intro_sal.h:21
Describe a kernel-user mode exception.
Definition: exceptions.h:275
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.
The name can be any string.
Definition: exceptions.h:640
#define ZONE_LIB_RESOURCES
Used for the resources section (usually .rsrc inside a driver or dll).
Definition: exceptions.h:726
DWORD NumberOfOffsets
Number of symbols pointing to the exported RVA.
Definition: winumcache.h:27
The exception will take into consideration the return driver/dll.
Definition: exceptions.h:601
The modified object is inside an EPT hook.
Definition: exceptions.h:746
#define INT_STATUS_EXCEPTION_CHECKS_OK
Definition: introstatus.h:396
int IntExceptPrintWinModInfo(WIN_PROCESS_MODULE *Module, char *Header, char *Line, int MaxLength, DWORD NameAlignment)
Print the data from the provided WIN_PROCESS_MODULE.
The exception is valid only for read violation.
Definition: exceptions.h:605
#define ERROR(fmt,...)
Definition: glue.h:62
The exception is valid only if the write comes due to an injection from user-mode.
Definition: exceptions.h:629
static void IntExceptKernelUserLogWindowsInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-user mode violation (windows guest).
Describes a user-mode originator.
Definition: exceptions.h:994
The name can be any string.
Definition: exceptions.h:687
INTSTATUS IntExceptMatchException(void *Victim, void *Originator, void *Exception, EXCEPTION_TYPE ExceptionType, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
This function tries to find a exception for the current violation..
Definition: exceptions.c:3167
int INTSTATUS
The status data type.
Definition: introstatus.h:24
The exception will match only for the init phase of a driver/process.
Definition: exceptions.h:599
#define ONE_KILOBYTE
Definition: introdefs.h:89
Describes a kernel-mode originator.
Definition: exceptions.h:943
The modified object is any with the modified name.
Definition: exceptions.h:193
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
The exception is valid only for write violation.
Definition: exceptions.h:606
#define MIN(a, b)
Definition: introdefs.h:146
#define LOG(fmt,...)
Definition: glue.h:61
Describes a kernel driver.
Definition: drivers.h:30
#define ZONE_INTEGRITY
Used for integrity zone.
Definition: exceptions.h:738
static __inline BOOLEAN IntExceptKernelUserMatchObjectType(EXCEPTION_VICTIM_ZONE *Victim, KUM_EXCEPTION *Exception)
Checks if the zone-type of the current exception matches the object-type of the victim.
LIST_HEAD KernelUserAlertExceptions
Linked list used for kernel-user mode exceptions that are added from alert.
Definition: exceptions.h:128
#define ZONE_LIB_CODE
Used for a generic code zone.
Definition: exceptions.h:723
#define INITIAL_CRC_VALUE
Definition: introdefs.h:221
EXCEPTIONS * Exceptions
The exceptions that are currently loaded.
Definition: guests.h:392
The modified object is inside an integrity hook.
Definition: exceptions.h:749
static __inline BOOLEAN IntExceptKernelUserMatchArch(KUM_EXCEPTION *Exception)
Checks if the architecture-flags of the current exception match the architecture-flags of the origina...
#define ZONE_EXECUTE
Used for execute violation.
Definition: exceptions.h:736
The exception is valid only for execute violation.
Definition: exceptions.h:607
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
Definition: guests.h:290
INTSTATUS IntExceptKernelUserVerifyExtra(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, UM_EXCEPTION *Exception)
This function is used as an extra step in exception mechanism.
The name is the operating system kernel name.
Definition: exceptions.h:642
#define TRUE
Definition: intro_types.h:30
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
The exception is valid only if the write comes due to an injection from kernel-mode.
Definition: exceptions.h:631
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...
#define for_each_kum_exception(_ex_head, _var_name)
Definition: exceptions.h:1068
static __inline BOOLEAN IntExceptKernelUserMatchProcessHash(EXCEPTION_VICTIM_ZONE *Victim, KUM_EXCEPTION *Exception)
Checks if the exception process name-hash of the current exception matches the process name-hash of t...
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
Definition: guests.h:367
LIST_HEAD KernelUserFeedbackExceptions
Linked list used for kernel-user mode exceptions that have the feedback flag.
Definition: exceptions.h:117
char gExcLogLine[2 *ONE_KILOBYTE]
The exception log line.
Definition: exceptions.c:40
#define WARNING(fmt,...)
Definition: glue.h:60
The exception will take into consideration the return driver.
Definition: exceptions.h:614
#define ZONE_LIB_EXPORTS
Used for the exports of a dll, driver, etc.
Definition: exceptions.h:722
The modified object is inside the process module&#39;s EAT.
Definition: exceptions.h:196
Describes the modified zone.
Definition: exceptions.h:893
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
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.
The name can be any string.
Definition: exceptions.h:666
The modified object is inside the process module&#39;s IAT.
Definition: exceptions.h:195
Describe a user-mode exception.
Definition: exceptions.h:308
DWORD Rva
The RVA of this export.
Definition: winumcache.h:23
uint32_t DWORD
Definition: intro_types.h:49
The name is missing.
Definition: exceptions.h:670
User-mode library.
Definition: intro_types.h:248
enum _INTRO_ACTION INTRO_ACTION
Event actions.
int IntExceptPrintWinKmModInfo(KERNEL_DRIVER *Module, char *Header, char *Line, int MaxLength, DWORD NameAlignment)
Print the information about the provided KERNEL_DRIVER (windows guest).
static __inline BOOLEAN IntExceptKernelUserMatchNameHash(EXCEPTION_VICTIM_ZONE *Victim, KUM_EXCEPTION *Exception)
Checks if the exception name-hash of the current exception matches the name-hash of the victim...
The action was allowed, but it has the BETA flag (Introcore is in log-only mode). ...
Definition: intro_types.h:185
#define ZONE_LIB_DATA
Definition: exceptions.h:724
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
static __inline BOOLEAN IntExceptKernelUserMatchZoneFlags(EXCEPTION_VICTIM_ZONE *Victim, KUM_EXCEPTION *Exception)
Checks if the zone-flags of the current exception match the zone flags of the victim.
LIST_HEAD NoNameKernelUserExceptions
Linked list used for kernel-user mode exceptions that don&#39;t have a valid originator (-)...
Definition: exceptions.h:102
#define EXCEPTION_TABLE_ID(H)
Definition: exceptions.h:50
#define ZONE_READ
Used for read violation.
Definition: exceptions.h:735
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
The action was blocked because no exception signature matched.
Definition: intro_types.h:187
PCHAR Names[MAX_OFFSETS_PER_NAME]
The names pointing to this RVA. Each name will point inside the Names structure inside WINUM_CACHE_EX...
Definition: winumcache.h:31
void IntExceptDumpSignatures(void *Originator, EXCEPTION_VICTIM_ZONE *Victim, BOOLEAN KernelMode, BOOLEAN ReturnDrv)
Dump code blocks from the originator&#39;s RIP.
Definition: exceptions.c:2978
LIST_HEAD GenericKernelUserExceptions
Linked list used for kernel-user mode exceptions that have a generic originator(*).
Definition: exceptions.h:94
char * utf16_for_log(const WCHAR *WString)
Converts a UTF-16 to a UTF-8 string to be used inside logging macros.
Definition: introcore.c:2845
int IntExceptPrintLixTaskInfo(const LIX_TASK_OBJECT *Task, char *Header, char *Line, int MaxLength, DWORD NameAlignment)
Print the information about the provided LIX_TASK_OBJECT.
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
Kernel-User mode exception.
Definition: exceptions.h:63
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
#define ZONE_LIB_IMPORTS
Used for the imports of a dll, driver, etc.
Definition: exceptions.h:721
The original RIP is outside a driver and it returns into a driver (which is the originator name)...
Definition: exceptions.h:612
The exception is valid only on 32 bit systems/process.
Definition: exceptions.h:596
#define EXPORT_NAME_UNKNOWN
Definition: exceptions.h:34
#define ZONE_WRITE
Used for write violation.
Definition: exceptions.h:734
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
#define INT_STATUS_EXCEPTION_ALLOW
Definition: introstatus.h:391
#define FALSE
Definition: intro_types.h:34
The exception (and signature, where&#39;s the case) matched, but the extra checks failed.
Definition: intro_types.h:191
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68
The modified object is inside the process modules.
Definition: exceptions.h:194