Bitdefender Hypervisor Memory Introspection
exceptions_kern.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
10 
11 #include "exceptions.h"
12 #include "guests.h"
13 #include "lixstack.h"
14 #include "winpe.h"
15 #include "winstack.h"
16 #include "lixksym.h"
17 #include "crc32.h"
18 
19 
20 extern char gExcLogLine[2 * ONE_KILOBYTE];
21 
22 
23 static int
25  _In_ KERNEL_DRIVER *Driver,
26  _In_ char *Header,
27  _Out_ char *Line,
28  _In_ int MaxLength,
29  _In_opt_ DWORD NameAlignment
30  )
42 {
43  int ret, total = 0;
44 
45  if (NULL == Driver)
46  {
47  return snprintf(Line, MaxLength, "%s(%s)", Header, EXCEPTION_NO_NAME);
48  }
49 
50  if (*(char *)Driver->Name)
51  {
52  ret = snprintf(Line, MaxLength, "%s(%-*s", Header, NameAlignment, (char *)Driver->Name);
53  }
54  else
55  {
56  ret = snprintf(Line, MaxLength, "%s(%s", Header, EXCEPTION_NO_NAME);
57  }
58 
59  if (ret < 0 || ret >= MaxLength)
60  {
61  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
62  }
63  else
64  {
65  Line += ret;
66  total += ret;
67  MaxLength -= ret;
68  }
69 
70  ret = snprintf(Line, MaxLength, " [0x%08x], %016llx", Driver->NameHash, Driver->BaseVa);
71 
72  if (ret < 0 || ret >= MaxLength)
73  {
74  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
75  }
76  else
77  {
78  Line += ret;
79  total += ret;
80  MaxLength -= ret;
81  }
82 
83  ret = snprintf(Line, MaxLength, ")");
84 
85  if (ret < 0 || ret >= MaxLength)
86  {
87  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
88  }
89  else
90  {
91  Line += ret;
92  total += ret;
93  MaxLength -= ret;
94  }
95 
96  return total;
97 }
98 
99 
100 int
102  _In_ KERNEL_DRIVER *Module,
103  _In_ char *Header,
104  _Out_ char *Line,
105  _In_ int MaxLength,
106  _In_opt_ DWORD NameAlignment
107  )
119 {
120  int ret, total = 0;
121  WCHAR *wName;
122  char name[MAX_PATH];
123 
124  if (NULL == Module)
125  {
126  return snprintf(Line, MaxLength, "%s(%s)", Header, EXCEPTION_NO_NAME);
127  }
128 
129  wName = Module->Win.Path ? Module->Win.Path : Module->Name ? Module->Name : NULL;
130 
131  if (wName)
132  {
133  utf16toutf8(name, wName, sizeof(name));
134  }
135  else
136  {
137  memcpy(name, EXCEPTION_NO_NAME, sizeof(EXCEPTION_NO_NAME));
138  }
139 
140  if (NameAlignment)
141  {
142  ret = snprintf(Line, MaxLength, "%s(%-*s", Header, NameAlignment, name);
143  }
144  else
145  {
146  ret = snprintf(Line, MaxLength, "%s(%s", Header, name);
147  }
148 
149  if (ret < 0 || ret >= MaxLength)
150  {
151  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
152  }
153  else
154  {
155  Line += ret;
156  total += ret;
157  MaxLength -= ret;
158  }
159 
160  ret = snprintf(Line, MaxLength, " [0x%08x], %0*llx", Module->NameHash, gGuest.WordSize * 2, Module->BaseVa);
161 
162  if (ret < 0 || ret >= MaxLength)
163  {
164  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
165  }
166  else
167  {
168  Line += ret;
169  total += ret;
170  MaxLength -= ret;
171  }
172 
173  if (Module->Win.TimeDateStamp)
174  {
175  ret = snprintf(Line, MaxLength, ", VerInfo: %x:%llx", Module->Win.TimeDateStamp, Module->Size);
176 
177  if (ret < 0 || ret >= MaxLength)
178  {
179  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
180  }
181  else
182  {
183  Line += ret;
184  total += ret;
185  MaxLength -= ret;
186  }
187  }
188 
189  ret = snprintf(Line, MaxLength, ")");
190 
191  if (ret < 0 || ret >= MaxLength)
192  {
193  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
194  }
195  else
196  {
197  Line += ret;
198  total += ret;
199  MaxLength -= ret;
200  }
201 
202  return total;
203 }
204 
205 
206 static int
208  _In_ EXCEPTION_VICTIM_ZONE *Victim,
209  _In_ char *Header,
210  _Out_ char *Line,
211  _In_ int MaxLength
212  )
223 {
224  const char *msrName = NULL;
225  int ret = 0, total = 0;
226 
227  ret = snprintf(Line, MaxLength, "%s: (%08x", Header, Victim->Msr.Msr);
228 
229  if (ret < 0 || ret >= MaxLength)
230  {
231  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
232  }
233  else
234  {
235  MaxLength -= ret;
236  Line += ret;
237  total += ret;
238  }
239 
240  if (Victim->Msr.Msr == IG_IA32_SYSENTER_CS)
241  {
242  msrName = "SYSENTER_CS";
243  }
244  else if (Victim->Msr.Msr == IG_IA32_SYSENTER_ESP)
245  {
246  msrName = "SYSENTER_ESP";
247  }
248  else if (Victim->Msr.Msr == IG_IA32_SYSENTER_EIP)
249  {
250  msrName = "SYSENTER_EIP";
251  }
252  else if (Victim->Msr.Msr == IG_IA32_STAR)
253  {
254  msrName = "STAR";
255  }
256  else if (Victim->Msr.Msr == IG_IA32_LSTAR)
257  {
258  msrName = "LSTAR";
259  }
260 
261  if (msrName)
262  {
263  ret = snprintf(Line, MaxLength, ", %s", msrName);
264 
265  if (ret < 0 || ret >= MaxLength)
266  {
267  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
268  }
269  else
270  {
271  MaxLength -= ret;
272  Line += ret;
273  total += ret;
274  }
275  }
276 
277  ret = snprintf(Line, MaxLength, ")");
278 
279  if (ret < 0 || ret >= MaxLength)
280  {
281  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
282  }
283  else
284  {
285  MaxLength -= ret;
286  Line += ret;
287  total += ret;
288  }
289 
290  ret = snprintf(Line, MaxLength, ", WriteInfo: (%016llx -> %016llx)",
291  Victim->WriteInfo.OldValue[0],
292  Victim->WriteInfo.NewValue[0]);
293 
294  if (ret < 0 || ret >= MaxLength)
295  {
296  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
297  }
298  else
299  {
300  MaxLength -= ret;
301  Line += ret;
302  total += ret;
303  }
304 
305  if (Victim->Msr.NewDriverBase)
306  {
307  KERNEL_DRIVER *pMsrDrv = IntDriverFindByAddress(Victim->Msr.NewDriverBase);
308 
310  {
311  ret = IntExceptPrintWinKmModInfo(pMsrDrv, ", Module: ", Line, MaxLength, 0);
312 
313  if (ret < 0 || ret >= MaxLength)
314  {
315  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
316  }
317  else
318  {
319  MaxLength -= ret;
320  Line += ret;
321  total += ret;
322  }
323  }
324  else if (gGuest.OSType == introGuestLinux)
325  {
326  ret = IntExceptPrintLixKmDrvInfo(pMsrDrv, ", Module: ", Line, MaxLength, 0);
327 
328  if (ret < 0 || ret >= MaxLength)
329  {
330  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
331  }
332  else
333  {
334  MaxLength -= ret;
335  Line += ret;
336  total += ret;
337  }
338 
339  if (pMsrDrv == gGuest.KernelDriver)
340  {
341  char symbol[LIX_SYMBOL_NAME_LEN];
342 
343  INTSTATUS status = IntKsymFindByAddress(Victim->WriteInfo.NewValue[0],
344  sizeof(symbol),
345  symbol,
346  NULL,
347  NULL);
348  if (!INT_SUCCESS(status))
349  {
350  memcpy(symbol, EXCEPTION_NO_SYMBOL, sizeof(EXCEPTION_NO_SYMBOL));
351  }
352 
353  ret = snprintf(Line, MaxLength, ", %s", symbol);
354 
355  if (ret < 0 || ret >= MaxLength)
356  {
357  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
358  }
359  else
360  {
361  MaxLength -= ret;
362  Line += ret;
363  total += ret;
364  }
365  }
366  }
367  }
368 
369  return total;
370 }
371 
372 
373 static int
375  _In_ EXCEPTION_VICTIM_ZONE *Victim,
376  _In_ char *Header,
377  _Out_ char *Line,
378  _In_ int MaxLength
379  )
390 {
391  int ret = 0, total = 0;
392 
393  ret = snprintf(Line, MaxLength, "%s%u", Header, Victim->Cr.Cr);
394 
395  if (ret < 0 || ret >= MaxLength)
396  {
397  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
398  }
399  else
400  {
401  MaxLength -= ret;
402  Line += ret;
403  total += ret;
404  }
405 
406  if (Victim->Cr.Smep && Victim->Cr.Smap)
407  {
408  ret = snprintf(Line, MaxLength, ", (SMAP, SMEP)");
409 
410  if (ret < 0 || ret >= MaxLength)
411  {
412  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
413  }
414  else
415  {
416  MaxLength -= ret;
417  Line += ret;
418  total += ret;
419  }
420  }
421  else if (Victim->Cr.Smap)
422  {
423  ret = snprintf(Line, MaxLength, ", (SMEP)");
424 
425  if (ret < 0 || ret >= MaxLength)
426  {
427  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
428  }
429  else
430  {
431  MaxLength -= ret;
432  Line += ret;
433  total += ret;
434  }
435  }
436  else if (Victim->Cr.Smep)
437  {
438  ret = snprintf(Line, MaxLength, ", (SMAP)");
439 
440  if (ret < 0 || ret >= MaxLength)
441  {
442  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
443  }
444  else
445  {
446  MaxLength -= ret;
447  Line += ret;
448  total += ret;
449  }
450  }
451 
452  ret = snprintf(Line, MaxLength, ", WriteInfo: (%u, %016llx -> %016llx)",
453  Victim->WriteInfo.AccessSize,
454  Victim->WriteInfo.OldValue[0],
455  Victim->WriteInfo.NewValue[0]);
456 
457  if (ret < 0 || ret >= MaxLength)
458  {
459  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
460  }
461  else
462  {
463  MaxLength -= ret;
464  Line += ret;
465  total += ret;
466  }
467 
468  return total;
469 }
470 
471 
472 static int
474  _In_ EXCEPTION_VICTIM_ZONE *Victim,
475  _In_ char *Header,
476  _Out_ char *Line,
477  _In_ int MaxLength
478  )
489 {
490  int ret = 0, total = 0;
491  QWORD entry, entryNo;
492  char *prot;
493 
494  if (Victim->ZoneType == exceptionZoneIntegrity)
495  {
496  entry = Victim->Object.BaseAddress + Victim->Integrity.Offset;
497  entryNo = Victim->Integrity.Offset / (gGuest.Guest64 ? DESCRIPTOR_SIZE_64 : DESCRIPTOR_SIZE_32);
498  prot = "INTEGRITY";
499  }
500  else
501  {
502  entry = Victim->Ept.Gva;
503  entryNo = (Victim->Ept.Gva - Victim->Object.BaseAddress) /
505  prot = "EPT";
506  }
507 
508  ret = snprintf(Line, MaxLength, "%s (IDT Base Address: %llx, IDT Entry modified: %llu (0x%016llx) (%s)",
509  Header, Victim->Object.BaseAddress, entryNo, entry, prot);
510 
511  if (ret < 0 || ret >= MaxLength)
512  {
513  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
514  }
515  else
516  {
517  MaxLength -= ret;
518  Line += ret;
519  total += ret;
520  }
521 
522  ret = snprintf(Line, MaxLength, ", WriteInfo: (%u", Victim->WriteInfo.AccessSize);
523 
524  if (ret < 0 || ret >= MaxLength)
525  {
526  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
527  }
528  else
529  {
530  MaxLength -= ret;
531  Line += ret;
532  total += ret;
533  }
534 
535  for (DWORD i = 0; i * sizeof(Victim->WriteInfo.NewValue[0]) < Victim->WriteInfo.AccessSize; i++)
536  {
537  ret = snprintf(Line, MaxLength, ", %016llx -> 0x%016llx",
538  Victim->WriteInfo.OldValue[i],
539  Victim->WriteInfo.NewValue[i]);
540 
541  if (ret < 0 || ret >= MaxLength)
542  {
543  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
544  }
545  else
546  {
547  MaxLength -= ret;
548  Line += ret;
549  total += ret;
550  }
551  }
552 
553  ret = snprintf(Line, MaxLength, ")");
554 
555  if (ret < 0 || ret >= MaxLength)
556  {
557  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
558  }
559  else
560  {
561  MaxLength -= ret;
562  Line += ret;
563  total += ret;
564  }
565 
566  return total;
567 }
568 
569 
570 static int
572  _In_ EXCEPTION_VICTIM_ZONE *Victim,
573  _In_ char *Header,
574  _Out_ char *Line,
575  _In_ int MaxLength
576  )
587 {
588  const char *dtrName = NULL;
589  int ret = 0, total = 0;
590 
591  ret = snprintf(Line, MaxLength, "%s(", Header);
592 
593  if (ret < 0 || ret >= MaxLength)
594  {
595  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
596  }
597  else
598  {
599  MaxLength -= ret;
600  Line += ret;
601  total += ret;
602  }
603 
604  if (Victim->Dtr.Type == introObjectTypeIdtr)
605  {
606  dtrName = "IDTR";
607  }
608  else if (Victim->Dtr.Type == introObjectTypeGdtr)
609  {
610  dtrName = "GDTR";
611  }
612  else
613  {
614  dtrName = "Unknown";
615  }
616 
617  ret = snprintf(Line, MaxLength, "%s", dtrName);
618 
619  if (ret < 0 || ret >= MaxLength)
620  {
621  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
622  }
623  else
624  {
625  MaxLength -= ret;
626  Line += ret;
627  total += ret;
628  }
629 
630  ret = snprintf(Line, MaxLength, ")");
631 
632  if (ret < 0 || ret >= MaxLength)
633  {
634  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
635  }
636  else
637  {
638  MaxLength -= ret;
639  Line += ret;
640  total += ret;
641  }
642 
643  ret = snprintf(Line, MaxLength, ", WriteInfo: (%016llx -> %016llx)",
644  Victim->WriteInfo.OldValue[0],
645  Victim->WriteInfo.NewValue[0]);
646 
647  if (ret < 0 || ret >= MaxLength)
648  {
649  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
650  }
651  else
652  {
653  MaxLength -= ret;
654  Line += ret;
655  total += ret;
656  }
657 
658  ret = snprintf(Line, MaxLength, ", DtrLimit: (%04llx -> %04llx)",
659  Victim->WriteInfo.OldValue[1],
660  Victim->WriteInfo.NewValue[1]);
661 
662  if (ret < 0 || ret >= MaxLength)
663  {
664  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
665  }
666  else
667  {
668  MaxLength -= ret;
669  Line += ret;
670  total += ret;
671  }
672 
673  return total;
674 }
675 
676 
677 static void
679  _In_ EXCEPTION_VICTIM_ZONE *Victim,
680  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
681  _In_ INTRO_ACTION Action,
683  )
692 {
693  KERNEL_DRIVER *pDriver, *pRetDriver;
694  char symbol[LIX_SYMBOL_NAME_LEN];
695  DWORD modNameAlignment;
696  INTSTATUS status;
697  char *l;
698  int ret, rem;
699 
700  pDriver = Originator->Original.Driver;
701  pRetDriver = Originator->Return.Driver;
702 
703  modNameAlignment = 0;
704  if (Victim->Object.Type == introObjectTypeKmModule)
705  {
706  KERNEL_DRIVER *pModDriver = Victim->Object.Module.Module;
707 
708  if (pModDriver && pDriver && pRetDriver)
709  {
710  modNameAlignment = (DWORD)MIN(MAX_PATH, MAX(pModDriver->NameLength, pDriver->NameLength));
711  }
712 
713  if (pModDriver && pRetDriver)
714  {
715  if (modNameAlignment > 0)
716  {
717  modNameAlignment = (DWORD)MIN(MAX_PATH, MAX(pRetDriver->NameLength, modNameAlignment));
718  }
719  else
720  {
721  modNameAlignment = (DWORD)MIN(MAX_PATH, MAX(pModDriver->NameLength, pRetDriver->NameLength));
722  }
723  }
724  }
725 
726  l = gExcLogLine;
727  rem = sizeof(gExcLogLine);
728 
729  if (Victim->ZoneType == exceptionZoneIntegrity)
730  {
731  // No point in logging anything else, since the RIP is unknown
732  ret = IntExceptPrintLixKmDrvInfo(pDriver, "Originator-> Module: ", l, rem, modNameAlignment);
733  if (ret < 0 || ret >= rem)
734  {
735  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
736  }
737  else
738  {
739  rem -= ret;
740  l += ret;
741  }
742 
743  LOG("%s\n", gExcLogLine);
744  }
745  else
746  {
747  char instr[ND_MIN_BUF_SIZE];
748  LIX_TASK_OBJECT *pTask;
749 
750  if (Originator->Instruction)
751  {
752  NDSTATUS s = NdToText(Originator->Instruction, Originator->Original.Rip, sizeof(instr), instr);
753  if (!ND_SUCCESS(s))
754  {
755  memcpy(instr, EXPORT_NAME_UNKNOWN, sizeof(EXPORT_NAME_UNKNOWN));
756  }
757  }
758  else
759  {
760  memcpy(instr, EXCEPTION_NO_INSTRUCTION, sizeof(EXCEPTION_NO_INSTRUCTION));
761  }
762 
763  if (pDriver == gGuest.KernelDriver)
764  {
765  status = IntKsymFindByAddress(Originator->Original.Rip, sizeof(symbol), symbol, NULL, NULL);
766  if (!INT_SUCCESS(status))
767  {
768  memcpy(symbol, EXCEPTION_NO_SYMBOL, sizeof(EXCEPTION_NO_SYMBOL));
769  }
770  }
771  else
772  {
773  symbol[0] = 0;
774  }
775 
776  ret = IntExceptPrintLixKmDrvInfo(pDriver, "Originator-> Module: ", l, rem, modNameAlignment);
777  if (ret < 0 || ret >= rem)
778  {
779  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
780  }
781  else
782  {
783  rem -= ret;
784  l += ret;
785  }
786 
787  ret = snprintf(l, rem, ", RIP %016llx", Originator->Original.Rip);
788 
789  if (ret < 0 || ret >= rem)
790  {
791  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
792  }
793  else
794  {
795  rem -= ret;
796  l += ret;
797  }
798 
799  if (Originator->Original.Section[0] != 0)
800  {
801  ret = snprintf(l, rem, " (%s)", Originator->Original.Section);
802 
803  if (ret < 0 || ret >= rem)
804  {
805  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
806  }
807  else
808  {
809  rem -= ret;
810  l += ret;
811  }
812  }
813 
814  if (symbol[0] != 0)
815  {
816  ret = snprintf(l, rem, " (%s)", symbol);
817 
818  if (ret < 0 || ret >= rem)
819  {
820  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
821  }
822  else
823  {
824  rem -= ret;
825  l += ret;
826  }
827  }
828 
829  if (instr[0] != 0)
830  {
831  ret = snprintf(l, rem, ", Instr: %s", instr);
832 
833  if (ret < 0 || ret >= rem)
834  {
835  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
836  }
837  else
838  {
839  rem -= ret;
840  l += ret;
841  }
842  }
843 
845  if (NULL != pTask)
846  {
847  LIX_TASK_OBJECT *pParent = IntLixTaskFindByGva(pTask->Parent);
848 
849  ret = IntExceptPrintLixTaskInfo(pTask, ", Process: ", l, rem, 0);
850 
851  if (ret < 0 || ret >= rem)
852  {
853  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
854  }
855  else
856  {
857  rem -= ret;
858  l += ret;
859  }
860 
861  ret = IntExceptPrintLixTaskInfo(pParent, ", Parent: ", l, rem, 0);
862 
863  if (ret < 0 || ret >= rem)
864  {
865  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
866  }
867  else
868  {
869  rem -= ret;
870  l += ret;
871  }
872  }
873 
874  LOG("%s\n", gExcLogLine);
875 
876  // Log the return driver too, if we have one and the rip is different
877  if (pRetDriver && Originator->Original.Rip != Originator->Return.Rip)
878  {
879  l = gExcLogLine;
880  rem = sizeof(gExcLogLine);
881 
882  if (pRetDriver == gGuest.KernelDriver)
883  {
884  status = IntKsymFindByAddress(Originator->Return.Rip, sizeof(symbol), symbol, NULL, NULL);
885  if (!INT_SUCCESS(status))
886  {
887  memcpy(symbol, EXCEPTION_NO_SYMBOL, sizeof(EXCEPTION_NO_SYMBOL));
888  }
889  }
890  else
891  {
892  symbol[0] = 0;
893  }
894 
895  ret = IntExceptPrintLixKmDrvInfo(pRetDriver, "Return -> Module: ", l, rem, modNameAlignment);
896 
897  if (ret < 0 || ret >= rem)
898  {
899  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
900  }
901  else
902  {
903  rem -= ret;
904  l += ret;
905  }
906 
907  ret = snprintf(l, rem, ", RIP %016llx", Originator->Return.Rip);
908 
909  if (ret < 0 || ret >= rem)
910  {
911  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
912  }
913  else
914  {
915  rem -= ret;
916  l += ret;
917  }
918 
919  if (Originator->Return.Section[0] != 0)
920  {
921  ret = snprintf(l, rem, "(%s)", Originator->Return.Section);
922 
923  if (ret < 0 || ret >= rem)
924  {
925  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
926  }
927  else
928  {
929  rem -= ret;
930  l += ret;
931  }
932  }
933 
934  if (symbol[0] != 0)
935  {
936  ret = snprintf(l, rem, " (%s)", symbol);
937 
938  if (ret < 0 || ret >= rem)
939  {
940  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
941  }
942  else
943  {
944  rem -= ret;
945  l += ret;
946  }
947  }
948 
949  LOG("%s\n", gExcLogLine);
950  }
951  }
952 
953  l = gExcLogLine;
954  rem = sizeof(gExcLogLine);
955 
956  if (Victim->ZoneType == exceptionZoneMsr)
957  {
958  IntExceptPrintMsrInfo(Victim, "Victim -> Msr: ", l, rem);
959 
960  if (ret < 0 || ret >= rem)
961  {
962  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
963  }
964  else
965  {
966  rem -= ret;
967  l += ret;
968  }
969 
970  LOG("%s\n", gExcLogLine);
971  }
972  else if ((Victim->Object.Type == introObjectTypeKmModule) ||
973  (Victim->Object.Type == introObjectTypeVdso) ||
974  (Victim->Object.Type == introObjectTypeVsyscall))
975  {
976  pDriver = Victim->Object.Module.Module;
977 
978  if (pDriver)
979  {
980  ret = IntExceptPrintLixKmDrvInfo(pDriver, "Victim -> Module: ", l, rem, modNameAlignment);
981 
982  if (ret < 0 || ret >= rem)
983  {
984  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
985  }
986  else
987  {
988  rem -= ret;
989  l += ret;
990  }
991  }
992  else if (Victim->Object.Type == introObjectTypeVdso)
993  {
994  ret = snprintf(l, rem, "Victim -> Module: %*s", modNameAlignment, "[vdso]");
995 
996  if (ret < 0 || ret >= rem)
997  {
998  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
999  }
1000  else
1001  {
1002  rem -= ret;
1003  l += ret;
1004  }
1005  }
1006  else if (Victim->Object.Type == introObjectTypeVsyscall)
1007  {
1008  ret = snprintf(l, rem, "Victim -> Module: %*s", modNameAlignment, "[vsyscall]");
1009 
1010  if (ret < 0 || ret >= rem)
1011  {
1012  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1013  }
1014  else
1015  {
1016  rem -= ret;
1017  l += ret;
1018  }
1019  }
1020 
1021  ret = snprintf(l, rem, ", Address: (%0llx, %0llx)",
1022  Victim->Ept.Gva, Victim->Ept.Gpa);
1023 
1024  if (ret < 0 || ret >= rem)
1025  {
1026  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1027  }
1028  else
1029  {
1030  rem -= ret;
1031  l += ret;
1032  }
1033 
1034  if (pDriver == gGuest.KernelDriver)
1035  {
1036  status = IntKsymFindByAddress(Victim->Ept.Gva, sizeof(symbol), symbol, NULL, NULL);
1037  if (!INT_SUCCESS(status))
1038  {
1039  memcpy(symbol, EXCEPTION_NO_SYMBOL, sizeof(EXCEPTION_NO_SYMBOL));
1040  }
1041 
1042  ret = snprintf(l, rem, ", %s", symbol);
1043 
1044  if (ret < 0 || ret >= rem)
1045  {
1046  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1047  }
1048  else
1049  {
1050  rem -= ret;
1051  l += ret;
1052  }
1053  }
1054 
1055  ret = 0;
1056  if (Victim->ZoneFlags & ZONE_WRITE)
1057  {
1058  ret = snprintf(l, rem, ", WriteInfo: (%u, %016llx -> %016llx)", Victim->WriteInfo.AccessSize,
1059  Victim->WriteInfo.OldValue[0], Victim->WriteInfo.NewValue[0]);
1060  }
1061  else if (Victim->ZoneFlags & ZONE_READ)
1062  {
1063  ret = snprintf(l, rem, ", ReadInfo: (%u, %016llx)", Victim->ReadInfo.AccessSize, Victim->ReadInfo.Value[0]);
1064  }
1065 
1066  if (ret < 0 || ret >= rem)
1067  {
1068  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1069  }
1070  else
1071  {
1072  rem -= ret;
1073  l += ret;
1074  }
1075 
1076  if (Victim->ZoneFlags)
1077  {
1078  ret = snprintf(l, rem, ", Flags:%s%s%s%s%s (0x%llx)",
1079  (Victim->ZoneFlags & ZONE_LIB_IMPORTS) ? " IMPORTS" : "",
1080  (Victim->ZoneFlags & ZONE_LIB_EXPORTS) ? " EXPORTS" : "",
1081  (Victim->ZoneFlags & ZONE_LIB_CODE) ? " CODE" : "",
1082  (Victim->ZoneFlags & ZONE_LIB_DATA) ? " DATA" : "",
1083  (Victim->ZoneFlags & ZONE_LIB_RESOURCES) ? " RSRC" : "",
1084  (unsigned long long)Victim->ZoneFlags);
1085 
1086  if (ret < 0 || ret >= rem)
1087  {
1088  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1089  }
1090  else
1091  {
1092  rem -= ret;
1093  l += ret;
1094  }
1095  }
1096 
1097  LOG("%s\n", gExcLogLine);
1098  }
1099  else if (Victim->ZoneType == exceptionZoneCr)
1100  {
1101  ret = IntExceptPrintCrInfo(Victim, "Victim -> Cr", l, rem);
1102 
1103  if (ret < 0 || ret >= rem)
1104  {
1105  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1106  }
1107  else
1108  {
1109  rem -= ret;
1110  l += ret;
1111  }
1112 
1113  LOG("%s\n", gExcLogLine);
1114  }
1115  else if (Victim->Object.Type == introObjectTypeIdt)
1116  {
1117  ret = IntExceptPrintIdtInfo(Victim, "Victim -> Idt: ", l, rem);
1118 
1119  if (ret < 0 || ret >= rem)
1120  {
1121  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1122  }
1123  else
1124  {
1125  rem -= ret;
1126  l += ret;
1127  }
1128 
1129  LOG("%s\n", gExcLogLine);
1130  }
1131 
1132  if (Action == introGuestNotAllowed)
1133  {
1134  l = gExcLogLine;
1135  rem = sizeof(gExcLogLine);
1136 
1137  ret = snprintf(l, rem, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%sROOTKIT (kernel-mode) ",
1138  gGuest.KernelBetaDetections ? " (B) " : " ");
1139 
1140  if (ret < 0 || ret >= rem)
1141  {
1142  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1143  }
1144  else
1145  {
1146  rem -= ret;
1147  l += ret;
1148  }
1149 
1150  switch (Reason)
1151  {
1153  ret = snprintf(l, rem, "(no sig)");
1154  break;
1156  ret = snprintf(l, rem, "(no exc)");
1157  break;
1159  ret = snprintf(l, rem, "(extra)");
1160  break;
1162  ret = snprintf(l, rem, "(error)");
1163  break;
1165  ret = snprintf(l, rem, "(value)");
1166  break;
1168  ret = snprintf(l, rem, "(export)");
1169  break;
1171  ret = snprintf(l, rem, "(value code)");
1172  break;
1174  ret = snprintf(l, rem, "(idt)");
1175  break;
1177  ret = snprintf(l, rem, "(version os)");
1178  break;
1180  ret = snprintf(l, rem, "(version intro)");
1181  break;
1183  ret = snprintf(l, rem, "(process creation)");
1184  break;
1185  case introReasonUnknown:
1186  ret = snprintf(l, rem, "(unknown)");
1187  break;
1188  default:
1189  ret = snprintf(l, rem, "(%d)", Reason);
1190  break;
1191  }
1192 
1193  if (ret < 0 || ret >= rem)
1194  {
1195  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1196  }
1197  else
1198  {
1199  rem -= ret;
1200  l += ret;
1201  }
1202 
1203  snprintf(l, rem, " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
1204 
1205  if (ret < 0 || ret >= rem)
1206  {
1207  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1208  }
1209  else
1210  {
1211  rem -= ret;
1212  l += ret;
1213  }
1214 
1215  LOG("%s\n\n", gExcLogLine);
1216  }
1217 
1218  for (DWORD t = 0; t < Originator->StackTrace.NumberOfTraces; t++)
1219  {
1220  if (NULL != Originator->StackTrace.Traces[t].ReturnModule)
1221  {
1222 
1223  if (Originator->StackTrace.Traces[t].ReturnModule == gGuest.KernelDriver)
1224  {
1225  status = IntKsymFindByAddress(Originator->StackTrace.Traces[t].CurrentRip,
1226  sizeof(symbol),
1227  symbol,
1228  NULL,
1229  NULL);
1230  if (!INT_SUCCESS(status))
1231  {
1232  memcpy(symbol, EXCEPTION_NO_SYMBOL, sizeof(EXCEPTION_NO_SYMBOL));
1233  }
1234  }
1235  else
1236  {
1237  memcpy(symbol, EXCEPTION_NO_SYMBOL, sizeof(EXCEPTION_NO_SYMBOL));
1238  }
1239 
1240  LOG("[STACK TRACE] [at %llx] returning to [%s at %llx] %s",
1241  Originator->StackTrace.Traces[t].CurrentRip,
1242  (char *)((KERNEL_DRIVER *)Originator->StackTrace.Traces[t].ReturnModule)->Name,
1243  Originator->StackTrace.Traces[t].ReturnAddress, symbol);
1244  }
1245  else
1246  {
1247  LOG("[STACK TRACE] [at %llx]", Originator->StackTrace.Traces[t].CurrentRip);
1248  }
1249  }
1250 
1251 }
1252 
1253 
1254 static int
1256  _In_ WIN_DRIVER_OBJECT *DrvObj,
1257  _In_ char *Header,
1258  _Out_ char *Line,
1259  _In_ int MaxLength
1260  )
1271 {
1272  int ret, total = 0;
1273  char name[MAX_PATH];
1274 
1275  if (NULL == DrvObj)
1276  {
1277  return snprintf(Line, MaxLength, "%s(%s)", Header, EXCEPTION_NO_NAME);
1278  }
1279 
1280  utf16toutf8(name, DrvObj->Name, sizeof(name));
1281 
1282  ret = snprintf(Line, MaxLength, "%s(%s", Header, name);
1283 
1284  if (ret < 0 || ret >= MaxLength)
1285  {
1286  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
1287  }
1288  else
1289  {
1290  Line += ret;
1291  total += ret;
1292  MaxLength -= ret;
1293  }
1294 
1295  ret = snprintf(Line, MaxLength, " [0x%08x], %0*llx, %0llx",
1296  DrvObj->NameHash, gGuest.WordSize * 2, DrvObj->DriverObjectGva, DrvObj->DriverObjectGpa);
1297 
1298  if (ret < 0 || ret >= MaxLength)
1299  {
1300  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
1301  }
1302  else
1303  {
1304  Line += ret;
1305  total += ret;
1306  MaxLength -= ret;
1307  }
1308 
1309  if (DrvObj->FastIOTableAddress)
1310  {
1311  ret = snprintf(Line, MaxLength, ", %0*llx", gGuest.WordSize * 2, DrvObj->FastIOTableAddress);
1312 
1313  if (ret < 0 || ret >= MaxLength)
1314  {
1315  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
1316  }
1317  else
1318  {
1319  Line += ret;
1320  total += ret;
1321  MaxLength -= ret;
1322  }
1323  }
1324 
1325  ret = snprintf(Line, MaxLength, ")");
1326 
1327  if (ret < 0 || ret >= MaxLength)
1328  {
1329  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, MaxLength);
1330  }
1331  else
1332  {
1333  Line += ret;
1334  total += ret;
1335  MaxLength -= ret;
1336  }
1337 
1338  return total;
1339 }
1340 
1341 
1342 static void
1344  _In_ EXCEPTION_VICTIM_ZONE *Victim,
1345  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
1346  _In_ INTRO_ACTION Action,
1347  _In_ INTRO_ACTION_REASON Reason
1348  )
1357 {
1358  KERNEL_DRIVER *pDriver, *pRetDriver;
1359  DWORD modNameAlignment;
1360  char *l;
1361  int ret, rem;
1362 
1363  pDriver = Originator->Original.Driver;
1364  pRetDriver = Originator->Return.Driver;
1365 
1366  modNameAlignment = 0;
1367  if (Victim->Object.Type == introObjectTypeKmModule || Victim->Object.Type == introObjectTypeVeAgent)
1368  {
1369  KERNEL_DRIVER *pModDriver = Victim->Object.Module.Module;
1370 
1371  if (pModDriver && pDriver)
1372  {
1373  modNameAlignment = MIN(MAX_PATH, MAX(pModDriver->Win.PathLength, pDriver->Win.PathLength));
1374  }
1375 
1376  if (pModDriver && pRetDriver)
1377  {
1378  if (modNameAlignment > 0)
1379  {
1380  modNameAlignment = MIN(MAX_PATH, MAX(pRetDriver->Win.PathLength, modNameAlignment));
1381  }
1382  else
1383  {
1384  modNameAlignment = MIN(MAX_PATH, MAX(pModDriver->Win.PathLength, pRetDriver->Win.PathLength));
1385  }
1386  }
1387  }
1388 
1389  l = gExcLogLine;
1390  rem = sizeof(gExcLogLine);
1391 
1392  if (Victim->ZoneType == exceptionZoneIntegrity)
1393  {
1394  // For token privileges, security descriptor integrity detection and SharedUsedData integrity detection,
1395  // originator will always be invalid, there is no reason to just log a "Originator no name" line.
1396  if (Victim->Object.Type != introObjectTypeTokenPrivs &&
1397  Victim->Object.Type != introObjectTypeSecDesc &&
1398  Victim->Object.Type != introObjectTypeAcl &&
1399  Victim->Object.Type != introObjectTypeSudIntegrity)
1400  {
1401  // No point in logging anything else, since the RIP is unknown
1402  ret = IntExceptPrintWinKmModInfo(pDriver, "Originator-> Module: ", l, rem, 0);
1403 
1404  if (ret < 0 || ret >= rem)
1405  {
1406  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1407  }
1408  else
1409  {
1410  rem -= ret;
1411  l += ret;
1412  }
1413 
1414  LOG("%s\n", gExcLogLine);
1415  }
1416  }
1417  else
1418  {
1419  char instr[ND_MIN_BUF_SIZE];
1420 
1421  if (Originator->Instruction)
1422  {
1423  NDSTATUS ndstatus = NdToText(Originator->Instruction, Originator->Original.Rip, sizeof(instr), instr);
1424  if (!ND_SUCCESS(ndstatus))
1425  {
1426  memcpy(instr, EXPORT_NAME_UNKNOWN, sizeof(EXPORT_NAME_UNKNOWN));
1427  }
1428  }
1429  else
1430  {
1431  memcpy(instr, EXCEPTION_NO_INSTRUCTION, sizeof(EXCEPTION_NO_INSTRUCTION));
1432  }
1433 
1434  ret = IntExceptPrintWinKmModInfo(pDriver, "Originator-> Module: ", l, rem, modNameAlignment);
1435 
1436  if (ret < 0 || ret >= rem)
1437  {
1438  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1439  }
1440  else
1441  {
1442  rem -= ret;
1443  l += ret;
1444  }
1445 
1446  ret = snprintf(l, rem, ", RIP %0*llx", gGuest.WordSize * 2, Originator->Original.Rip);
1447 
1448  if (ret < 0 || ret >= rem)
1449  {
1450  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1451  }
1452  else
1453  {
1454  rem -= ret;
1455  l += ret;
1456  }
1457 
1458  if (Originator->Original.Section[0] != 0)
1459  {
1460  ret = snprintf(l, rem, " (%s)", Originator->Original.Section);
1461 
1462  if (ret < 0 || ret >= rem)
1463  {
1464  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1465  }
1466  else
1467  {
1468  rem -= ret;
1469  l += ret;
1470  }
1471  }
1472 
1473  if (instr[0] != 0)
1474  {
1475  ret = snprintf(l, rem, ", Instr: %s", instr);
1476 
1477  if (ret < 0 || ret >= rem)
1478  {
1479  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1480  }
1481  else
1482  {
1483  rem -= ret;
1484  l += ret;
1485  }
1486  }
1487 
1488  LOG("%s\n", gExcLogLine);
1489 
1490  if (Originator->Return.Driver && Originator->Original.Rip != Originator->Return.Rip)
1491  {
1492  l = gExcLogLine;
1493  rem = sizeof(gExcLogLine);
1494 
1495  ret = IntExceptPrintWinKmModInfo(pRetDriver, "Return -> Module: ", l, rem, modNameAlignment);
1496 
1497  if (ret < 0 || ret >= rem)
1498  {
1499  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1500  }
1501  else
1502  {
1503  rem -= ret;
1504  l += ret;
1505  }
1506 
1507  ret = snprintf(l, rem, ", RIP %0*llx", gGuest.WordSize * 2, Originator->Return.Rip);
1508 
1509  if (ret < 0 || ret >= rem)
1510  {
1511  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1512  }
1513  else
1514  {
1515  rem -= ret;
1516  l += ret;
1517  }
1518 
1519  if (Originator->Return.Section[0] != 0)
1520  {
1521  ret = snprintf(l, rem, "(%s)", Originator->Return.Section);
1522 
1523  if (ret < 0 || ret >= rem)
1524  {
1525  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1526  }
1527  else
1528  {
1529  rem -= ret;
1530  l += ret;
1531  }
1532  }
1533 
1534  LOG("%s\n", gExcLogLine);
1535  }
1536  }
1537 
1538  l = gExcLogLine;
1539  rem = sizeof(gExcLogLine);
1540 
1541  if (Victim->ZoneType == exceptionZoneMsr)
1542  {
1543  ret = IntExceptPrintMsrInfo(Victim, "Victim -> Msr: ", l, rem);
1544 
1545  if (ret < 0 || ret >= rem)
1546  {
1547  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1548  }
1549  else
1550  {
1551  rem -= ret;
1552  l += ret;
1553  }
1554 
1555  LOG("%s\n", gExcLogLine);
1556  }
1557  else if (Victim->Object.Type == introObjectTypeKmModule ||
1558  Victim->Object.Type == introObjectTypeSsdt ||
1559  Victim->Object.Type == introObjectTypeVeAgent)
1560  {
1561  pDriver = Victim->Object.Module.Module;
1562 
1563  ret = IntExceptPrintWinKmModInfo(pDriver, "Victim -> Module: ", l, rem, modNameAlignment);
1564 
1565  if (ret < 0 || ret >= rem)
1566  {
1567  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1568  }
1569  else
1570  {
1571  rem -= ret;
1572  l += ret;
1573  }
1574 
1575  ret = snprintf(l, rem, ", Address: (%0*llx, %0*llx)",
1576  gGuest.WordSize * 2, Victim->Ept.Gva,
1577  gGuest.WordSize * 2, Victim->Ept.Gpa);
1578  if (ret < 0 || ret >= rem)
1579  {
1580  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1581  }
1582  else
1583  {
1584  rem -= ret;
1585  l += ret;
1586  }
1587 
1588  if (Victim->ZoneFlags & ZONE_WRITE)
1589  {
1590  ret = snprintf(l, rem, ", WriteInfo: (%u, %016llx -> %016llx)", Victim->WriteInfo.AccessSize,
1591  Victim->WriteInfo.OldValue[0], Victim->WriteInfo.NewValue[0]);
1592  }
1593  else if (Victim->ZoneFlags & ZONE_READ)
1594  {
1595  ret = snprintf(l, rem, ", ReadInfo: (%u, %016llx)", Victim->ReadInfo.AccessSize, Victim->ReadInfo.Value[0]);
1596  }
1597 
1598  if (ret < 0 || ret >= rem)
1599  {
1600  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1601  }
1602  else
1603  {
1604  rem -= ret;
1605  l += ret;
1606  }
1607 
1608  if (Victim->ZoneFlags)
1609  {
1610  ret = snprintf(l, rem, ", Flags:%s%s%s%s%s (0x%llx)",
1611  (Victim->ZoneFlags & ZONE_LIB_IMPORTS) ? " IMPORTS" : "",
1612  (Victim->ZoneFlags & ZONE_LIB_EXPORTS) ? " EXPORTS" : "",
1613  (Victim->ZoneFlags & ZONE_LIB_CODE) ? " CODE" : "",
1614  (Victim->ZoneFlags & ZONE_LIB_DATA) ? " DATA" : "",
1615  (Victim->ZoneFlags & ZONE_LIB_RESOURCES) ? " RSRC" : "",
1616  (unsigned long long)Victim->ZoneFlags);
1617 
1618  if (ret < 0 || ret >= rem)
1619  {
1620  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1621  }
1622  else
1623  {
1624  rem -= ret;
1625  l += ret;
1626  }
1627  }
1628 
1629  LOG("%s\n", gExcLogLine);
1630  }
1631  else if ((Victim->Object.Type == introObjectTypeDriverObject) ||
1632  (Victim->Object.Type == introObjectTypeFastIoDispatch))
1633  {
1634  BOOLEAN fastIo = (Victim->Object.Type == introObjectTypeFastIoDispatch);
1635 
1636  if (fastIo)
1637  {
1638  ret = IntExceptPrintDrvObjInfo(Victim->Object.DriverObject, "Victim -> FastIo: ", l, rem);
1639  }
1640  else
1641  {
1642  ret = IntExceptPrintDrvObjInfo(Victim->Object.DriverObject, "Victim -> DrvObj: ", l, rem);
1643  }
1644 
1645  if (ret < 0 || ret >= rem)
1646  {
1647  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1648  }
1649  else
1650  {
1651  rem -= ret;
1652  l += ret;
1653  }
1654 
1655  pDriver = IntDriverFindByBase(Victim->Object.DriverObject->Owner);
1656  if (pDriver)
1657  {
1658  ret = IntExceptPrintWinKmModInfo(pDriver, ", Owner: ", l, rem, 0);
1659 
1660  if (ret < 0 || ret >= rem)
1661  {
1662  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1663  }
1664  else
1665  {
1666  rem -= ret;
1667  l += ret;
1668  }
1669  }
1670 
1671  ret = snprintf(l, rem, ", WriteInfo: (%u, %016llx -> %016llx)",
1672  Victim->WriteInfo.AccessSize,
1673  Victim->WriteInfo.OldValue[0],
1674  Victim->WriteInfo.NewValue[0]);
1675 
1676  if (ret < 0 || ret >= rem)
1677  {
1678  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1679  }
1680  else
1681  {
1682  rem -= ret;
1683  l += ret;
1684  }
1685 
1686  if (Victim->ZoneType == exceptionZoneIntegrity)
1687  {
1688  ret = snprintf(l, rem, ", INTEGRITY");
1689 
1690  if (ret < 0 || ret >= rem)
1691  {
1692  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1693  }
1694  else
1695  {
1696  rem -= ret;
1697  l += ret;
1698  }
1699  }
1700 
1701  LOG("%s\n", gExcLogLine);
1702  }
1703  else if (Victim->ZoneType == exceptionZoneCr)
1704  {
1705  ret = IntExceptPrintCrInfo(Victim, "Victim -> Cr", l, rem);
1706 
1707  if (ret < 0 || ret >= rem)
1708  {
1709  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1710  }
1711  else
1712  {
1713  rem -= ret;
1714  l += ret;
1715  }
1716 
1717  LOG("%s\n", gExcLogLine);
1718  }
1719  else if (Victim->Object.Type == introObjectTypeHalIntController)
1720  {
1721  LOG("Victim -> Hal interrupt controller: (%0*llx, %0*llx), WriteInfo: (%d, %016llx -> %016llx)\n",
1722  gGuest.WordSize * 2, Victim->Ept.Gva, gGuest.WordSize * 2, Victim->Ept.Gpa,
1723  Victim->WriteInfo.AccessSize,
1724  Victim->WriteInfo.OldValue[0], Victim->WriteInfo.NewValue[0]);
1725  }
1726  else if (Victim->Object.Type == introObjectTypeHalHeap)
1727  {
1728  LOG("Victim -> Hal heap execute: (%0*llx, %0*llx)\n",
1729  gGuest.WordSize * 2, Victim->Ept.Gva, gGuest.WordSize * 2, Victim->Ept.Gpa);
1730  }
1731  else if (Victim->Object.Type == introObjectTypeSudExec)
1732  {
1733  LOG("Victim -> SharedUserData execute: (%0*llx, %0*llx)\n",
1734  gGuest.WordSize * 2, Victim->Ept.Gva, gGuest.WordSize * 2, Victim->Ept.Gpa);
1735  }
1736  else if (Victim->Object.Type == introObjectTypeIdt)
1737  {
1738  ret = IntExceptPrintIdtInfo(Victim, "Victim -> Idt: ", l, rem);
1739 
1740  if (ret < 0 || ret >= rem)
1741  {
1742  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1743  }
1744  else
1745  {
1746  rem -= ret;
1747  l += ret;
1748  }
1749 
1750  LOG("%s\n", gExcLogLine);
1751  }
1752  else if (Victim->Object.Type == introObjectTypeSelfMapEntry)
1753  {
1754  LOG("Victim -> Self map entry: %s [0x%08x] (%016llx, %016llx), "
1755  "WriteInfo: (%d, %016llx -> %016llx), Index: %08x\n",
1756  Victim->Object.Name, Victim->Object.NameHash,
1757  Victim->Ept.Gva, Victim->Ept.Gpa,
1758  Victim->WriteInfo.AccessSize,
1759  Victim->WriteInfo.OldValue[0],
1760  Victim->WriteInfo.NewValue[0],
1762  }
1763  else if (Victim->Object.Type == introObjectTypeKmLoggerContext)
1764  {
1765  if (Victim->ZoneType == exceptionZoneIntegrity)
1766  {
1767  LOG("Victim -> Circular Kernel Context Logger (%016llx, %016llx), "
1768  "WriteInfo: (%d, %016llx -> %016llx), INTEGRITY\n",
1769  Victim->Integrity.StartVirtualAddress,
1770  Victim->Integrity.StartVirtualAddress + Victim->Integrity.TotalLength,
1771  Victim->WriteInfo.AccessSize,
1772  Victim->WriteInfo.OldValue[0],
1773  Victim->WriteInfo.NewValue[0]);
1774  }
1775  else
1776  {
1777  LOG("Victim -> Circular Kernel Context Logger (%016llx, %016llx), "
1778  "WriteInfo: (%d, %016llx -> %016llx), EPT\n",
1779  Victim->Ept.Gva, Victim->Ept.Gpa,
1780  Victim->WriteInfo.AccessSize,
1781  Victim->WriteInfo.OldValue[0],
1782  Victim->WriteInfo.NewValue[0]);
1783  }
1784  }
1785  else if (Victim->Object.Type == introObjectTypeHalPerfCounter)
1786  {
1787  LOG("Victim -> HalPerformanceCounter (%016llx, %016llx), "
1788  "WriteInfo: (%d, %016llx -> %016llx), INTEGRITY\n",
1789  Victim->Integrity.StartVirtualAddress,
1790  Victim->Integrity.StartVirtualAddress + Victim->Integrity.TotalLength,
1791  Victim->WriteInfo.AccessSize,
1792  Victim->WriteInfo.OldValue[0],
1793  Victim->WriteInfo.NewValue[0]);
1794  }
1795  else if (Victim->Object.Type == introObjectTypeGdtr ||
1796  Victim->Object.Type == introObjectTypeIdtr)
1797  {
1798  ret = IntExceptPrintDtrInfo(Victim, "Victim -> Dtr: ", l, rem);
1799 
1800  if (ret < 0 || ret >= rem)
1801  {
1802  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1803  }
1804  else
1805  {
1806  rem -= ret;
1807  l += ret;
1808  }
1809 
1810  LOG("%s\n", gExcLogLine);
1811  }
1812  else if (Victim->Object.Type == introObjectTypeTokenPrivs)
1813  {
1814  if (Victim->ZoneType == exceptionZoneIntegrity)
1815  {
1816  LOG("Victim -> Token privileges (%s [0x%08x] %d), WriteInfo: (Present: 0x%016llx, "
1817  "Enabled: 0x%016llx -> Present: 0x%016llx, Enabled: 0x%016llx), INTEGRITY\n",
1818  Victim->Object.WinProc->Name,
1819  Victim->Object.WinProc->NameHash,
1820  Victim->Object.WinProc->Pid,
1821  Victim->WriteInfo.OldValue[0],
1822  Victim->WriteInfo.OldValue[1],
1823  Victim->WriteInfo.NewValue[0],
1824  Victim->WriteInfo.NewValue[1]);
1825  }
1826  else
1827  {
1828  LOG("Victim -> Token privileges (%s [0x%08x] %d), WriteInfo: (%d, %016llx -> %016llx), EPT\n",
1829  Victim->Object.WinProc->Name,
1830  Victim->Object.WinProc->NameHash,
1831  Victim->Object.WinProc->Pid,
1832  Victim->WriteInfo.AccessSize,
1833  Victim->WriteInfo.OldValue[0],
1834  Victim->WriteInfo.NewValue[0]);
1835  }
1836  }
1837  else if (Victim->Object.Type == introObjectTypeSecDesc ||
1838  Victim->Object.Type == introObjectTypeAcl)
1839  {
1840  ACL oldSacl;
1841  ACL oldDacl;
1842  ACL newSacl;
1843  ACL newDacl;
1844  DWORD SDHeadersHash = 0;
1845 
1846  // #ACL is exactly QWORD size, so we going to use some WriteInfo values to store the SACL and DACL.
1847  // For both #introObjectTypeSecDesc and #introObjectTypeAcl we store the information as follows:
1848  // - OldValue[0] is the old SACL
1849  // - NewValue[0] is the new SACL
1850  // - OldValue[1] is the old DACL
1851  // - NewValue[1] is the new DACL
1852  // - AccessSize is the size of the new security descriptor buffer.
1853  //
1854  // For #introObjectTypeSecDesc:
1855  // - OldValue[2] is the old security descriptor pointer
1856  // - NewValue[2] is the new security descriptor pointer
1857 
1858  memcpy(&oldSacl, &Victim->WriteInfo.OldValue[0], sizeof(ACL));
1859  memcpy(&newSacl, &Victim->WriteInfo.NewValue[0], sizeof(ACL));
1860 
1861  memcpy(&oldDacl, &Victim->WriteInfo.OldValue[1], sizeof(ACL));
1862  memcpy(&newDacl, &Victim->WriteInfo.NewValue[1], sizeof(ACL));
1863 
1864  if (Victim->Integrity.Buffer)
1865  {
1866  SDHeadersHash = Crc32Compute(Victim->Integrity.Buffer,
1867  Victim->Integrity.BufferSize,
1869  }
1870 
1871  if (Victim->Object.Type == introObjectTypeSecDesc)
1872  {
1873  LOG("Victim -> Security descriptor pointer was modified for process (%s [0x%08x] %d), WriteInfo: "
1874  "(NewSdSize:%d, 0x%016llx -> 0x%016llx) New SD Hash:0x%x Old SACL "
1875  "AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x "
1876  "New SACL AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x "
1877  "Old DACL AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x "
1878  "New DACL AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x\n",
1879  Victim->Object.WinProc->Name,
1880  Victim->Object.WinProc->NameHash,
1881  Victim->Object.WinProc->Pid,
1882  Victim->Integrity.BufferSize,
1883  Victim->WriteInfo.OldValue[2],
1884  Victim->WriteInfo.NewValue[2],
1885  SDHeadersHash,
1886  oldSacl.AclSize, oldSacl.AceCount, oldSacl.AclRevision,
1887  newSacl.AclSize, newSacl.AceCount, newSacl.AclRevision,
1888  oldDacl.AclSize, oldDacl.AceCount, oldDacl.AclRevision,
1889  newDacl.AclSize, newDacl.AceCount, newDacl.AclRevision);
1890  }
1891  else
1892  {
1893  LOG("Victim -> ACL edited for process (%s [0x%08x] %d) NewSdSize:%d New SD Hash:0x%x "
1894  "Old SACL AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x "
1895  "New SACL AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x "
1896  "Old DACL AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x "
1897  "New DACL AclSize:0x%x, AceCount:0x%x, AclRevision:0x%x\n",
1898  Victim->Object.WinProc->Name,
1899  Victim->Object.WinProc->NameHash,
1900  Victim->Object.WinProc->Pid,
1901  Victim->Integrity.BufferSize,
1902  SDHeadersHash,
1903  oldSacl.AclSize, oldSacl.AceCount, oldSacl.AclRevision,
1904  newSacl.AclSize, newSacl.AceCount, newSacl.AclRevision,
1905  oldDacl.AclSize, oldDacl.AceCount, oldDacl.AclRevision,
1906  newDacl.AclSize, newDacl.AceCount, newDacl.AclRevision);
1907  }
1908  }
1909  else if (Victim->Object.Type == introObjectTypeSudIntegrity)
1910  {
1911  LOG("Victim -> SharedUserData (%s [0x%08x] 0x%016llx + 0x%08x), WriteInfo: (0x%016llx -> 0x%016llx 0x%08x)\n",
1912  Victim->Object.Name,
1913  Victim->Object.NameHash,
1914  Victim->Integrity.StartVirtualAddress,
1915  Victim->Integrity.Offset,
1916  Victim->WriteInfo.OldValue[0],
1917  Victim->WriteInfo.NewValue[0],
1918  Victim->WriteInfo.AccessSize);
1919  }
1920  else if (Victim->Object.Type == introObjectTypeInterruptObject)
1921  {
1922  LOG("Victim -> Interrupt Object (0x%016llx, entry %d) DispatchAddress: (0x%016llx -> 0x%016llx), "
1923  "ServiceRoutine: (0x%016llx -> 0x%016llx)",
1924  Victim->Integrity.StartVirtualAddress, Victim->Integrity.InterruptObjIndex,
1925  Victim->WriteInfo.OldValue[0], Victim->WriteInfo.NewValue[0],
1926  Victim->WriteInfo.OldValue[1], Victim->WriteInfo.NewValue[1]);
1927  }
1928 
1929  if (Action == introGuestNotAllowed)
1930  {
1931  l = gExcLogLine;
1932  rem = sizeof(gExcLogLine);
1933 
1934  ret = snprintf(l, rem, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%sROOTKIT (kernel-mode) ",
1935  gGuest.KernelBetaDetections ? " (B) " : " ");
1936 
1937  if (ret < 0 || ret >= rem)
1938  {
1939  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1940  }
1941  else
1942  {
1943  rem -= ret;
1944  l += ret;
1945  }
1946 
1947  switch (Reason)
1948  {
1950  ret = snprintf(l, rem, "(no sig)");
1951  break;
1953  ret = snprintf(l, rem, "(no exc)");
1954  break;
1956  ret = snprintf(l, rem, "(extra)");
1957  break;
1959  ret = snprintf(l, rem, "(error)");
1960  break;
1962  ret = snprintf(l, rem, "(value)");
1963  break;
1965  ret = snprintf(l, rem, "(export)");
1966  break;
1968  ret = snprintf(l, rem, "(value code)");
1969  break;
1971  ret = snprintf(l, rem, "(idt)");
1972  break;
1974  ret = snprintf(l, rem, "(version os)");
1975  break;
1977  ret = snprintf(l, rem, "(version intro)");
1978  break;
1980  ret = snprintf(l, rem, "(process creation)");
1981  break;
1982  case introReasonUnknown:
1983  ret = snprintf(l, rem, "(unknown)");
1984  break;
1985  default:
1986  ret = snprintf(l, rem, "(%d)", Reason);
1987  break;
1988  }
1989 
1990  if (ret < 0 || ret >= rem)
1991  {
1992  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
1993  }
1994  else
1995  {
1996  rem -= ret;
1997  l += ret;
1998  }
1999 
2000  ret = snprintf(l, rem, " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
2001 
2002  if (ret < 0 || ret >= rem)
2003  {
2004  ERROR("[ERROR] snprintf error: %d, size %d\n", ret, rem);
2005  }
2006  else
2007  {
2008  rem -= ret;
2009  l += ret;
2010  }
2011 
2012  LOG("%s\n\n", gExcLogLine);
2013  }
2014  for (DWORD t = 0; t < Originator->StackTrace.NumberOfTraces; t++)
2015  {
2016  if (NULL != Originator->StackTrace.Traces[t].ReturnModule)
2017  {
2018  LOG("[STACK TRACE] [at 0x%016llx] returning to [%s at 0x%016llx]\n",
2019  Originator->StackTrace.Traces[t].CurrentRip,
2020  utf16_for_log(((KERNEL_DRIVER *)Originator->StackTrace.Traces[t].ReturnModule)->Name),
2021  Originator->StackTrace.Traces[t].ReturnAddress);
2022  }
2023  else
2024  {
2025  LOG("[STACK TRACE] [at 0x%016llx]\n", Originator->StackTrace.Traces[t].CurrentRip);
2026  }
2027  }
2028 }
2029 
2030 
2031 void
2033  _In_ EXCEPTION_VICTIM_ZONE *Victim,
2034  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
2035  _In_ INTRO_ACTION Action,
2036  _In_ INTRO_ACTION_REASON Reason
2037  )
2046 {
2047  if ((introGuestNotAllowed != Action) && (introReasonAllowedFeedback != Reason))
2048  {
2049  return;
2050  }
2051 
2053  {
2054  IntExceptKernelLogWindowsInformation(Victim, Originator, Action, Reason);
2055  }
2056  else if (gGuest.OSType == introGuestLinux)
2057  {
2058  IntExceptKernelLogLinuxInformation(Victim, Originator, Action, Reason);
2059  }
2060 
2061  if (!(Victim->ZoneFlags & ZONE_INTEGRITY))
2062  {
2063  IntExceptDumpSignatures(Originator, Victim, TRUE, FALSE);
2064  IntExceptDumpSignatures(Originator, Victim, TRUE, TRUE);
2065  }
2066 }
2067 
2068 
2069 static BOOLEAN
2071  _In_ QWORD Rip
2072  )
2081 {
2082  for (DWORD i = 0; i < ARRAYSIZE(gLixGuest->MemoryFunctions); i++)
2083  {
2084  if (gLixGuest->MemoryFunctions[i].Start == 0 || gLixGuest->MemoryFunctions[i].End == 0)
2085  {
2086  continue;
2087  }
2088 
2089  if (Rip >= gLixGuest->MemoryFunctions[i].Start && Rip < gLixGuest->MemoryFunctions[i].End)
2090  {
2091  return TRUE;
2092  }
2093  }
2094 
2095  return FALSE;
2096 }
2097 
2098 
2099 static INTSTATUS
2101  _Out_ EXCEPTION_KM_ORIGINATOR *Originator
2102  )
2112 {
2113  INTSTATUS status;
2114  PIG_ARCH_REGS pRegs;
2115  KERNEL_DRIVER *pDriver;
2116  QWORD rip;
2117 
2118  pRegs = &gVcpu->Regs;
2119  Originator->StackTrace.Traces = Originator->StackElements;
2120 
2121  Originator->Original.Driver = IntDriverFindByAddress(pRegs->Rip);
2122 
2123  status = IntLixStackTraceGetReg(0, pRegs, ARRAYSIZE(Originator->StackElements), 0, &Originator->StackTrace);
2124  if (!INT_SUCCESS(status) && 0 == Originator->StackTrace.NumberOfTraces)
2125  {
2126  WARNING("[WARNING] Failed getting a stack trace: 0x%08x. Skip checking for exported functions!\n",
2127  status);
2128  }
2129 
2130  for (DWORD t = 0; t < Originator->StackTrace.NumberOfTraces; t++)
2131  {
2132  KERNEL_DRIVER *pRetMod = IntDriverFindByAddress(Originator->StackTrace.Traces[t].ReturnAddress);
2133  if (NULL == pRetMod)
2134  {
2135  continue;
2136  }
2137 
2138  Originator->Return.Driver = pRetMod;
2139  Originator->Return.Rip = Originator->StackTrace.Traces[t].ReturnAddress;
2140 
2141  break;
2142  }
2143 
2144  if (NULL == Originator->Return.Driver)
2145  {
2146  for (DWORD t = 0; t < Originator->StackTrace.NumberOfTraces; t++)
2147  {
2148  KERNEL_DRIVER *pRetMod = IntDriverFindByAddress(Originator->StackTrace.Traces[t].ReturnAddress);
2149  if (NULL == pRetMod)
2150  {
2151  continue;
2152  }
2153 
2154  // Skip mem* functions
2155  if (pRetMod == gGuest.KernelDriver &&
2156  IntExceptLixKernelIsMemoryFunc(Originator->StackTrace.Traces[t].ReturnAddress))
2157  {
2158  continue;
2159  }
2160 
2161  Originator->Return.Driver = pRetMod;
2162  Originator->Return.Rip = Originator->StackTrace.Traces[t].ReturnAddress;
2163 
2164  break;
2165  }
2166  }
2167 
2168  if (NULL == Originator->Original.Driver && NULL == Originator->Return.Driver)
2169  {
2170  // We have nothing to check, and we don't except this (yet?)
2171  return INT_STATUS_SUCCESS;
2172  }
2173 
2174  if (NULL != Originator->Original.Driver)
2175  {
2176  rip = Originator->Original.Rip;
2177  pDriver = Originator->Original.Driver;
2178 
2179  if (pDriver->BaseVa == gGuest.KernelVa)
2180  {
2181  Originator->Original.NameHash = kmExcNameKernel;
2182  }
2183  else
2184  {
2185  Originator->Original.NameHash = pDriver->NameHash;
2186  }
2187 
2188  IntLixDrvGetSecName(pDriver, rip, Originator->Original.Section);
2189  }
2190  else
2191  {
2192  Originator->Original.NameHash = INITIAL_CRC_VALUE;
2193  }
2194 
2195  if (NULL != Originator->Return.Driver)
2196  {
2197  rip = Originator->Return.Rip;
2198  pDriver = Originator->Return.Driver;
2199 
2200  if (pDriver->BaseVa == gGuest.KernelVa)
2201  {
2202  Originator->Return.NameHash = kmExcNameKernel;
2203  }
2204  else
2205  {
2206  Originator->Return.NameHash = pDriver->NameHash;
2207  }
2208 
2209  IntLixDrvGetSecName(pDriver, rip, Originator->Return.Section);
2210  }
2211  else
2212  {
2213  Originator->Return.NameHash = INITIAL_CRC_VALUE;
2214  }
2215 
2216  return INT_STATUS_SUCCESS;
2217 }
2218 
2219 
2220 static INTSTATUS
2222  _Out_ EXCEPTION_KM_ORIGINATOR *Originator,
2223  _In_ DWORD Options
2224  )
2238 {
2239  INTSTATUS status;
2240  KERNEL_DRIVER *pDriver, *pOriginalDriver;
2241 
2242  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
2243  DWORD currentTrace = 0;
2244  QWORD stackFrame = gGuest.Guest64 ? pRegs->Rsp : pRegs->Rbp;
2245  DWORD stackDepth;
2246 
2247  // Find the original driver that's modifying the memory
2248  Originator->Original.Driver = IntDriverFindByAddress(Originator->Original.Rip);
2249 
2250  stackDepth = (NULL == Originator->Original.Driver || !!(Options & EXCEPTION_KM_ORIGINATOR_OPT_FULL_STACK)) ? 3 : 1;
2251 
2252  // Reset the stack trace
2253  Originator->StackTrace.Traces = Originator->StackElements;
2254 
2255  status = IntWinStackTraceGet(stackFrame, pRegs->Rip, stackDepth, 0, &Originator->StackTrace);
2256  if (!INT_SUCCESS(status) && (Originator->StackTrace.NumberOfTraces == 0))
2257  {
2258  WARNING("[WARNING] Failed getting a stack trace: 0x%08x. Skip checking for exported functions!\n",
2259  status);
2260  }
2261 
2262  // This is a RIP that isn't inside any driver... We have special exceptions
2263  // for this case, so get the first return driver.
2264  if (NULL == Originator->Original.Driver)
2265  {
2266  DWORD t;
2267 
2268  for (t = 0; t < Originator->StackTrace.NumberOfTraces; t++)
2269  {
2270  if (NULL == Originator->StackTrace.Traces[t].ReturnModule)
2271  {
2272  continue;
2273  }
2274 
2275  Originator->Return.Driver = Originator->StackTrace.Traces[t].ReturnModule;
2276 
2277  Originator->Return.Rip = Originator->StackTrace.Traces[t].ReturnAddress;
2278 
2279  break;
2280  }
2281  }
2282  else
2283  {
2284  // They are the same, unless we will found otherwise
2285  Originator->Return.Driver = Originator->Original.Driver;
2286  }
2287 
2288  if (NULL == Originator->Original.Driver && NULL != Originator->Return.Driver)
2289  {
2290  TRACE("[WARNING] The RIP 0x%016llx is not inside any module, but it returns to one 0x%016llx "
2291  "(BaseVa 0x%016llx).\n",
2292  Originator->Original.Rip,
2293  Originator->Return.Rip,
2294  Originator->Return.Driver->BaseVa);
2295  }
2296  else if (NULL == Originator->Original.Driver && NULL == Originator->Return.Driver)
2297  {
2298  // We have nothing to check, and we don't except this (yet?)
2299  Originator->Original.NameHash = INITIAL_CRC_VALUE;
2300  Originator->Return.NameHash = INITIAL_CRC_VALUE;
2301  return INT_STATUS_SUCCESS;
2302  }
2303 
2304  pDriver = Originator->Return.Driver;
2305  pOriginalDriver = Originator->Original.Driver;
2306 
2307  do
2308  {
2309  IMAGE_SECTION_HEADER sectionHeader;
2310  DRIVER_EXPORT_CACHE_ENTRY *pCache = NULL;
2311 
2312  // Get the section header for the current RIP
2313  status = IntPeGetSectionHeaderByRva(pDriver->BaseVa,
2314  pDriver->Win.MzPeHeaders,
2315  (DWORD)(Originator->Return.Rip - pDriver->BaseVa),
2316  &sectionHeader);
2317  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
2318  {
2319  ERROR("[ERROR] Failed getting section details for Rip 0x%016llx: 0x%08x\n",
2320  Originator->Original.Rip, status);
2321  return status;
2322  }
2323  else if (status == INT_STATUS_NOT_FOUND)
2324  {
2325  WARNING("[WARNING] Rip 0x%016llx isn't inside any section. ModuleBase: 0x%016llx\n",
2326  Originator->Original.Rip, pDriver->BaseVa);
2327  if (0 == (Options & EXCEPTION_KM_ORIGINATOR_OPT_DO_NOT_BLOCK))
2328  {
2330  }
2331  else
2332  {
2333  break;
2334  }
2335  }
2336 
2337  // Will only happen once
2338  if (Originator->Original.Driver != NULL &&
2339  0 == Originator->Original.Section[0])
2340  {
2341  memcpy(Originator->Original.Section, sectionHeader.Name, sizeof(sectionHeader.Name));
2342  }
2343 
2344  memcpy(Originator->Return.Section, sectionHeader.Name, sizeof(sectionHeader.Name));
2345 
2346  // See if this is the verifier
2347  if (pDriver->BaseVa == gGuest.KernelVa &&
2348  0 == memcmp(Originator->Return.Section, "PAGEVRF", 7))
2349  {
2350  WARNING("[WARNING] The RIP is inside the kernel section %s, the VERIFIER is active...\n",
2351  Originator->Return.Section);
2352  }
2353 
2354  // See if the section is writable and not discardable or doesn't have the CODE or EXEC flags
2355  if (0 == (sectionHeader.Characteristics & IMAGE_SCN_CNT_CODE) &&
2356  0 == (sectionHeader.Characteristics & IMAGE_SCN_MEM_EXECUTE) &&
2357  0 != (sectionHeader.Characteristics & IMAGE_SCN_MEM_WRITE))
2358  {
2359  WARNING("[WARNING] Code executed from a section that doesn't contain code (RIP 0x%016llx). " \
2360  "Characteristics: 0x%08x, Name: %s\n",
2361  Originator->Return.Rip, sectionHeader.Characteristics, Originator->Return.Section);
2362  if (0 == (Options & EXCEPTION_KM_ORIGINATOR_OPT_DO_NOT_BLOCK))
2363  {
2365  }
2366  else
2367  {
2368  break;
2369  }
2370  }
2371  if (Originator->Return.Rip - pDriver->EntryPoint < PAGE_SIZE &&
2372  0 == memcmp(Originator->Return.Section, "INIT", 4))
2373  {
2374  Originator->IsEntryPoint = TRUE;
2375 
2376  // The entry point can be exported. This ensures that it won't go further (to IopInitializeDriver & co.)
2377  break;
2378  }
2379 
2380  if (0 == Originator->StackTrace.NumberOfTraces ||
2381  NULL == Originator->Original.Driver)
2382  {
2383  // There is no point in going further
2384  break;
2385  }
2386 
2387 
2388  // See if this RIP is inside an exported function
2389  pCache = IntDriverCacheExportFind(Originator->Return.Rip);
2390  if (pCache == NULL)
2391  {
2392  if (pDriver->BaseVa != gGuest.KernelVa)
2393  {
2394  status = IntPeFindExportByRva(pDriver->BaseVa,
2395  pDriver->Win.MzPeHeaders,
2396  (DWORD)(Originator->Return.Rip - pDriver->BaseVa));
2397  }
2398  else
2399  {
2400  status = IntPeFindExportByRvaInBuffer(pDriver->BaseVa,
2403  (DWORD)(Originator->Return.Rip - pDriver->BaseVa));
2404  }
2405 
2406  if (INT_STATUS_NOT_FOUND == status)
2407  {
2408  IntDriverCacheCreateUnknown(Originator->Return.Rip);
2409  break;
2410  }
2411  else if (!INT_SUCCESS(status))
2412  {
2413  // Don't compare the status to specific values since on XEN it will be different.
2414  // If a driver is calling a function in another driver, than assume that function is exported, in case
2415  // we had an error, which usually happens when the export directory is paged out.
2416  if (pDriver == Originator->StackTrace.Traces[currentTrace].ReturnModule)
2417  {
2418  break;
2419  }
2420  }
2421  else
2422  {
2423  IntDriverCacheCreateExport(Originator->Return.Rip);
2424  }
2425  }
2426  else
2427  {
2428  if (pCache->Type.Unknown)
2429  {
2430  break;
2431  }
2432  }
2433 
2434  // We are done analyzing current RIP, go further if needed
2435  if (NULL == Originator->StackTrace.Traces[currentTrace].ReturnModule)
2436  {
2437  WARNING("[WARNING] RIP 0x%016llx returning to an address that isn't inside a driver 0x%016llx. "
2438  "Block the attempt\n",
2439  Originator->Original.Rip,
2440  Originator->StackTrace.Traces[currentTrace].ReturnAddress);
2441 
2442  if (0 == (Options & EXCEPTION_KM_ORIGINATOR_OPT_DO_NOT_BLOCK))
2443  {
2445  }
2446  else
2447  {
2448  break;
2449  }
2450  }
2451  else
2452  {
2453  status = INT_STATUS_SUCCESS; // go to the next one
2454  }
2455 
2456  // If we had an error the we must get out now
2457  if (!INT_SUCCESS(status))
2458  {
2459  return status;
2460  }
2461 
2462  // Modify the Rip and Driver to the return address and analyze that too
2463  Originator->Return.Rip = Originator->StackTrace.Traces[currentTrace].ReturnAddress;
2464 
2465  pDriver = Originator->StackTrace.Traces[currentTrace].ReturnModule;
2466  if (NULL == pDriver)
2467  {
2468  return INT_STATUS_NOT_FOUND;
2469  }
2470 
2471  Originator->Return.Driver = pDriver;
2472 
2473  currentTrace++;
2474  } while (currentTrace < Originator->StackTrace.NumberOfTraces);
2475 
2476  // Now get the hashes
2477  if (pDriver->BaseVa == gGuest.KernelVa)
2478  {
2479  Originator->Return.NameHash = kmExcNameKernel;
2480  }
2481  else if (0 == wstrcasecmp(pDriver->Name, u"hal.dll") ||
2482  0 == wstrcasecmp(pDriver->Name, u"halmacpi.dll") ||
2483  0 == wstrcasecmp(pDriver->Name, u"halacpi.dll"))
2484  {
2485  Originator->Return.NameHash = kmExcNameHal;
2486  }
2487  else
2488  {
2489  Originator->Return.NameHash = pDriver->NameHash;
2490  }
2491 
2492  // In case we had one (there is at least one case [virtualbox] where we don't)
2493  if (pOriginalDriver)
2494  {
2495  if (pOriginalDriver->BaseVa == gGuest.KernelVa)
2496  {
2497  Originator->Original.NameHash = kmExcNameKernel;
2498  }
2499  else if (0 == wstrcasecmp(pOriginalDriver->Name, u"hal.dll") ||
2500  0 == wstrcasecmp(pOriginalDriver->Name, u"halmacpi.dll") ||
2501  0 == wstrcasecmp(pOriginalDriver->Name, u"halacpi.dll"))
2502  {
2503  Originator->Original.NameHash = kmExcNameHal;
2504  }
2505  else
2506  {
2507  Originator->Original.NameHash = pOriginalDriver->NameHash;
2508  }
2509  }
2510  else
2511  {
2512  Originator->Original.NameHash = INITIAL_CRC_VALUE;
2513  }
2514 
2515  return INT_STATUS_SUCCESS;
2516 }
2517 
2518 
2519 INTSTATUS
2521  _Out_ EXCEPTION_KM_ORIGINATOR *Originator,
2522  _In_ DWORD Options
2523  )
2534 {
2535  if (NULL == Originator)
2536  {
2538  }
2539 
2540  // Save the original RIP; the current RIP is the same until we found otherwise
2541  Originator->Original.Rip = gVcpu->Regs.Rip;
2542  Originator->Return.Rip = gVcpu->Regs.Rip;
2543 
2545  {
2546  Originator->Instruction = &gVcpu->Instruction;
2547  }
2548  else
2549  {
2550  Originator->Instruction = NULL;
2551  }
2552 
2554  {
2555  return IntExceptWinKernelGetOriginator(Originator, Options);
2556  }
2557  else if (gGuest.OSType == introGuestLinux)
2558  {
2559  return IntExceptLixKernelGetOriginator(Originator);
2560  }
2561 
2562  return INT_STATUS_NOT_SUPPORTED;
2563 }
2564 
2565 
2566 INTSTATUS
2568  _In_ EXCEPTION_VICTIM_ZONE *Victim,
2569  _Out_ EXCEPTION_KM_ORIGINATOR *Originator
2570  )
2589 {
2590  INTSTATUS status;
2591 
2592  if (NULL == Victim)
2593  {
2595  }
2596 
2597  if (NULL == Originator)
2598  {
2600  }
2601 
2603  {
2604  ERROR("[ERROR] Integrity alerts are not supported on guests %d\n", gGuest.OSType);
2605  return INT_STATUS_NOT_SUPPORTED;
2606  }
2607 
2608  Originator->IsIntegrity = TRUE;
2609 
2610  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, Victim->WriteInfo.NewValue[0]) &&
2611  (Victim->Object.Type == introObjectTypeFastIoDispatch))
2612  {
2613  if ((gGuest.Guest64 && FIELD_OFFSET(FAST_IO_DISPATCH64, SizeOfFastIoDispatch) == Victim->Integrity.Offset) ||
2614  (!gGuest.Guest64 && FIELD_OFFSET(FAST_IO_DISPATCH32, SizeOfFastIoDispatch) == Victim->Integrity.Offset))
2615  {
2616  if (Victim->WriteInfo.NewValue[0] < 0x60 || Victim->WriteInfo.NewValue[0] > 0x200)
2617  {
2618  WARNING("[WARNING] The new size 0x%016llx is too big...\n", Victim->WriteInfo.NewValue[0]);
2620  }
2621 
2623  }
2624 
2625  WARNING("[WARNING] Not writing on size field & writing non-pointer value: 0x%016llx\n",
2626  Victim->WriteInfo.NewValue[0]);
2627  }
2628 
2629  if (Victim->Object.Type == introObjectTypeDriverObject ||
2630  Victim->Object.Type == introObjectTypeFastIoDispatch ||
2631  Victim->Object.Type == introObjectTypeHalDispatchTable ||
2632  Victim->Object.Type == introObjectTypeKmLoggerContext ||
2633  Victim->Object.Type == introObjectTypeIdt ||
2634  Victim->Object.Type == introObjectTypeHalPerfCounter)
2635  {
2636  QWORD addr = 0;
2637 
2638  if (Victim->Object.Type == introObjectTypeIdt)
2639  {
2640  if (gGuest.Guest64)
2641  {
2642  IDT_ENTRY64 *pDescr = (IDT_ENTRY64 *)(Victim->WriteInfo.NewValue);
2643  addr = ((QWORD)pDescr->Offset63_32 << 32)
2644  | ((pDescr->Offset31_16 << 16) & 0xFFFF0000) | pDescr->Offset15_0;
2645  }
2646  else
2647  {
2648  IDT_ENTRY32 *pDescr = (IDT_ENTRY32 *)(Victim->WriteInfo.NewValue);
2649  addr = ((pDescr->Offset31_16 << 16) & 0xFFFF0000) | pDescr->Offset15_0;
2650  }
2651  }
2652  else
2653  {
2654  addr = Victim->WriteInfo.NewValue[0];
2655  }
2656 
2658  {
2659  Originator->Return.Driver = IntDriverFindByAddress(addr);
2660  }
2661 
2662  if (NULL == Originator->Return.Driver)
2663  {
2664  if (introObjectTypeIdt != Victim->Object.Type)
2665  {
2666  WARNING("[WARNING] Written value is not a kernel pointer or inside any driver: 0x%016llx\n", addr);
2668  }
2669 
2670  Originator->Return.NameHash = INITIAL_CRC_VALUE;
2671  }
2672  else if (Originator->Return.Driver->BaseVa == gGuest.KernelVa)
2673  {
2674  Originator->Return.NameHash = kmExcNameKernel;
2675  }
2676  else if (0 == wstrcasecmp(Originator->Return.Driver->Name, u"hal.dll") ||
2677  0 == wstrcasecmp(Originator->Return.Driver->Name, u"halmacpi.dll") ||
2678  0 == wstrcasecmp(Originator->Return.Driver->Name, u"halacpi.dll"))
2679  {
2680  Originator->Return.NameHash = kmExcNameHal;
2681  }
2682  else
2683  {
2684  Originator->Return.NameHash = Originator->Return.Driver->NameHash;
2685  }
2686 
2687  // And now, copy everything into the original field too
2688  Originator->Original.NameHash = Originator->Return.NameHash;
2689  Originator->Original.Driver = Originator->Return.Driver;
2690 
2691  status = INT_STATUS_SUCCESS;
2692  }
2693  else if (Victim->Object.Type == introObjectTypeInterruptObject)
2694  {
2695  QWORD addr = Victim->WriteInfo.NewValue[0];
2696 
2697  Originator->Return.Driver = IntDriverFindByAddress(addr);
2698 
2699  // First we need to verify if Dispatch address points in kernel.
2700  if (NULL == Originator->Return.Driver)
2701  {
2702  Originator->Return.NameHash = INITIAL_CRC_VALUE;
2703  }
2704  else if (Originator->Return.Driver->BaseVa == gGuest.KernelVa)
2705  {
2706  Originator->Return.NameHash = kmExcNameKernel;
2707  }
2708  else if (0 == wstrcasecmp(Originator->Return.Driver->Name, u"hal.dll") ||
2709  0 == wstrcasecmp(Originator->Return.Driver->Name, u"halmacpi.dll") ||
2710  0 == wstrcasecmp(Originator->Return.Driver->Name, u"halacpi.dll"))
2711  {
2712  Originator->Return.NameHash = kmExcNameHal;
2713  }
2714  else
2715  {
2716  Originator->Return.NameHash = Originator->Return.Driver->NameHash;
2717  }
2718 
2719  if (Originator->Return.NameHash == kmExcNameKernel)
2720  {
2721  // Now fill the Original from ServiceRoutine, since the return is in the kernel.
2722  addr = Victim->WriteInfo.NewValue[1];
2723 
2724  Originator->Original.Driver = IntDriverFindByAddress(addr);
2725 
2726  if (NULL == Originator->Original.Driver)
2727  {
2728  Originator->Original.NameHash = INITIAL_CRC_VALUE;
2729  }
2730  else if (Originator->Original.Driver->BaseVa == gGuest.KernelVa)
2731  {
2732  Originator->Original.NameHash = kmExcNameKernel;
2733  }
2734  else if (0 == wstrcasecmp(Originator->Original.Driver->Name, u"hal.dll") ||
2735  0 == wstrcasecmp(Originator->Original.Driver->Name, u"halmacpi.dll") ||
2736  0 == wstrcasecmp(Originator->Original.Driver->Name, u"halacpi.dll"))
2737  {
2738  Originator->Original.NameHash = kmExcNameHal;
2739  }
2740  else
2741  {
2742  Originator->Original.NameHash = Originator->Original.Driver->NameHash;
2743  }
2744  }
2745  else
2746  {
2747  Originator->Original.NameHash = Originator->Return.NameHash;
2748  Originator->Original.Driver = Originator->Return.Driver;
2749  }
2750 
2751  status = INT_STATUS_SUCCESS;
2752  }
2753  else
2754  {
2755  status = INT_STATUS_NOT_SUPPORTED;
2756  }
2757 
2758  return status;
2759 }
2760 
2761 
2762 INTSTATUS
2764  _In_ DTR *NewValue,
2765  _In_ DTR *OldValue,
2766  _In_ INTRO_OBJECT_TYPE Type,
2768  )
2782 {
2783  if (NULL == NewValue)
2784  {
2786  }
2787 
2788  if (NULL == OldValue)
2789  {
2791  }
2792 
2793  if (NULL == Victim)
2794  {
2796  }
2797 
2798  Victim->Object.Type = Type;
2799  Victim->ZoneType = exceptionZoneDtr;
2800 
2801  Victim->WriteInfo.NewValue[0] = NewValue->Base;
2802  Victim->WriteInfo.NewValue[1] = NewValue->Limit;
2803  Victim->Dtr.Type = Type;
2804  Victim->WriteInfo.OldValue[0] = OldValue->Base;
2805  Victim->WriteInfo.OldValue[1] = OldValue->Limit;
2806  Victim->WriteInfo.AccessSize = gGuest.WordSize + 2;
2807 
2808  Victim->ZoneFlags |= ZONE_WRITE;
2809 
2810  return INT_STATUS_SUCCESS;
2811 }
2812 
2813 
2814 INTSTATUS
2816  _In_ QWORD NewValue,
2817  _In_ QWORD OldValue,
2818  _In_ DWORD Msr,
2820  )
2832 {
2833  if (NULL == Victim)
2834  {
2836  }
2837 
2838  // Type is relevant only in EPT zone, where we don't know what zone it is. Here we know it's a MSR.
2839  Victim->Object.Type = 0;
2840  Victim->ZoneType = exceptionZoneMsr;
2841 
2842  Victim->WriteInfo.NewValue[0] = NewValue;
2843  Victim->Msr.Msr = Msr;
2844  Victim->WriteInfo.OldValue[0] = OldValue;
2845  Victim->WriteInfo.AccessSize = gGuest.WordSize;
2846 
2847  Victim->Msr.NewDriverBase = 0;
2848  Victim->ZoneFlags |= ZONE_WRITE;
2849 
2850  KERNEL_DRIVER *pDriver = IntDriverFindByAddress(NewValue);
2851  if (pDriver)
2852  {
2853  Victim->Msr.NewDriverBase = pDriver->BaseVa;
2854  }
2855 
2856  return INT_STATUS_SUCCESS;
2857 }
2858 
2859 
2860 INTSTATUS
2862  _In_ INTEGRITY_REGION *IntegrityRegion,
2863  _Inout_ DWORD *Offset,
2865  )
2885 {
2886  INTSTATUS status;
2887  BYTE *pPage, *pOriginal;
2888  DWORD i;
2889  BOOLEAN found;
2890 
2891  if (NULL == IntegrityRegion)
2892  {
2894  }
2895 
2896  if (NULL == Offset)
2897  {
2899  }
2900 
2901  if (NULL == Victim)
2902  {
2904  }
2905 
2907  {
2908  ERROR("[ERROR] Integrity alerts are not supported on guests %d\n", gGuest.OSType);
2909  return INT_STATUS_NOT_SUPPORTED;
2910  }
2911 
2912  pOriginal = IntegrityRegion->OriginalContent;
2913  found = FALSE;
2914 
2915  status = IntVirtMemMap(IntegrityRegion->Gva, IntegrityRegion->Length, gGuest.Mm.SystemCr3, 0, &pPage);
2916  if (!INT_SUCCESS(status))
2917  {
2918  ERROR("[ERROR] Failed mapping/reading at GVA 0x%016llx, with length %x: 0x%08x\n",
2919  IntegrityRegion->Gva, IntegrityRegion->Length, status);
2920  return status;
2921  }
2922 
2923  // Search for the first modification, starting at the given offset.
2924  for (i = *Offset; i < IntegrityRegion->Length; i++)
2925  {
2926  if (pPage[i] != pOriginal[i])
2927  {
2928  found = TRUE;
2929  break;
2930  }
2931  }
2932 
2933  if (!found)
2934  {
2935  status = INT_STATUS_NOT_FOUND;
2936  *Offset = IntegrityRegion->Length;
2937  goto _cleanup_and_leave;
2938  }
2939 
2940  // On idt, the offset at which the write occurred must be considered the start of the entry.
2941  // On x64, if a write occurs, let's say, at offset 15 inside the entry, we would wrongfully
2942  // take the offset to be equal to entry + 8, leading to possible misleading information, and
2943  // if it is the last entry, the modification might be deemed "outside the integrity region",
2944  // which should not occur.
2945  switch (IntegrityRegion->Type)
2946  {
2947  case introObjectTypeIdt:
2949  break;
2950  default:
2951  i = ALIGN_DOWN(i, gGuest.WordSize);
2952  break;
2953  }
2954 
2955  *Offset = i + gGuest.WordSize; // the next word
2956 
2957  Victim->ZoneType = exceptionZoneIntegrity;
2958  Victim->Object.Type = IntegrityRegion->Type;
2959  Victim->ZoneFlags |= ZONE_WRITE | ZONE_INTEGRITY;
2960 
2961  Victim->Integrity.StartVirtualAddress = IntegrityRegion->Gva;
2962  Victim->Integrity.TotalLength = IntegrityRegion->Length;
2963  Victim->Integrity.Offset = i;
2964 
2965  switch (IntegrityRegion->Type)
2966  {
2967  case introObjectTypeIdt:
2968  if (gGuest.Guest64)
2969  {
2970  Victim->WriteInfo.AccessSize = sizeof(IDT_ENTRY64);
2971  }
2972  else
2973  {
2974  Victim->WriteInfo.AccessSize = sizeof(IDT_ENTRY32);
2975  }
2976 
2977  *Offset += gGuest.WordSize;
2978  break;
2979 
2981  Victim->WriteInfo.AccessSize = 2 * gGuest.WordSize;
2982  break;
2983 
2984  default:
2985  Victim->WriteInfo.AccessSize = gGuest.WordSize;
2986  break;
2987  }
2988 
2989  // Don't exit if the access size has not filled the whole buffer. Note that for a region
2990  // with size 4, there might be a write at offset 1 of size gGuest.WordSize == 8. We should
2991  // fit in the buffer the interesting values, the ones in the integrity region which were
2992  // accessed at least.
2993  if (i + Victim->WriteInfo.AccessSize > IntegrityRegion->Length)
2994  {
2995  Victim->WriteInfo.AccessSize = IntegrityRegion->Length - i;
2996  }
2997 
2998  memcpy(Victim->WriteInfo.OldValue, pOriginal + i, Victim->WriteInfo.AccessSize);
2999  memcpy(Victim->WriteInfo.NewValue, pPage + i, Victim->WriteInfo.AccessSize);
3000 
3001  switch (IntegrityRegion->Type)
3002  {
3005  {
3006  WIN_DRIVER_OBJECT *pDrvObj = IntegrityRegion->Context;
3007 
3008  if (NULL == pDrvObj)
3009  {
3010  LOG("We must have a integrity context (a driver object)\n");
3012  goto _cleanup_and_leave;
3013  }
3014 
3015  Victim->Object.NameHash = pDrvObj->NameHash;
3016  Victim->Object.DriverObject = pDrvObj;
3017  Victim->Object.BaseAddress = pDrvObj->DriverObjectGva;
3018 
3019  break;
3020  }
3025  {
3026  break;
3027  }
3028  case introObjectTypeIdt:
3029  {
3030  Victim->Object.BaseAddress = IntegrityRegion->Gva;
3031  break;
3032  }
3033 
3034  default:
3035  LOG("Invalid integrity region type: %d\n", IntegrityRegion->Type);
3036  break;
3037  }
3038 
3039 _cleanup_and_leave:
3040  IntVirtMemUnmap(&pPage);
3041 
3042  return status;
3043 }
3044 
3045 
3046 INTSTATUS
3048  _In_ QWORD NewValue,
3049  _In_ QWORD OldValue,
3050  _In_ DWORD Cr,
3052  )
3066 {
3067  if (NULL == Victim)
3068  {
3070  }
3071 
3072  if (4 != Cr)
3073  {
3074  return INT_STATUS_NOT_SUPPORTED;
3075  }
3076 
3077  Victim->ZoneType = exceptionZoneCr;
3078  Victim->ZoneFlags |= ZONE_WRITE;
3079  Victim->Object.Type = (DWORD) -1;
3080 
3081  Victim->WriteInfo.NewValue[0] = NewValue;
3082  Victim->WriteInfo.OldValue[0] = OldValue;
3083  Victim->Cr.Cr = Cr;
3084 
3085  Victim->WriteInfo.AccessSize = sizeof(QWORD);
3086 
3087  Victim->Cr.Smap = ((OldValue & CR4_SMAP) != 0) && ((NewValue & CR4_SMAP) == 0);
3088  Victim->Cr.Smep = ((OldValue & CR4_SMEP) != 0) && ((NewValue & CR4_SMEP) == 0);
3089 
3090  return INT_STATUS_SUCCESS;
3091 }
3092 
3093 
3094 INTSTATUS
3096  _In_ EXCEPTION_VICTIM_ZONE *Victim,
3097  _In_ EXCEPTION_UM_ORIGINATOR *Originator,
3098  _In_ UM_EXCEPTION *Exception
3099  )
3109 {
3110  UNREFERENCED_PARAMETER(Victim);
3111  UNREFERENCED_PARAMETER(Originator);
3112  UNREFERENCED_PARAMETER(Exception);
3113 
3115 }
3116 
3117 
3118 INTSTATUS
3120  _In_ EXCEPTION_VICTIM_ZONE *Victim,
3121  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
3122  _In_ KM_EXCEPTION *Exception
3123  )
3144 {
3145  BOOLEAN match = FALSE;
3146 
3147  if ((Exception->Flags & EXCEPTION_FLG_READ) &&
3148  (Victim->ZoneFlags & ZONE_READ))
3149  {
3150  match = TRUE;
3151  }
3152 
3153  if ((Exception->Flags & EXCEPTION_FLG_EXECUTE) &&
3154  (Victim->ZoneFlags & ZONE_EXECUTE))
3155  {
3156  match = TRUE;
3157  }
3158 
3159  if ((Exception->Flags & EXCEPTION_FLG_WRITE) &&
3160  (Victim->ZoneFlags & ZONE_WRITE))
3161  {
3162  match = TRUE;
3163  }
3164 
3165  if (!match)
3166  {
3168  }
3169 
3170  if ((Exception->Flags & EXCEPTION_KM_FLG_INTEGRITY) &&
3171  (Victim->ZoneType != exceptionZoneIntegrity))
3172  {
3174  }
3175 
3176  if ((Exception->Flags & EXCEPTION_KM_FLG_NON_DRIVER) &&
3177  (Originator->Original.Driver != NULL))
3178  {
3180  }
3181 
3182  match = FALSE;
3183 
3184  if ((Exception->Flags & EXCEPTION_FLG_32) &&
3185  (Exception->Flags & EXCEPTION_FLG_64))
3186  {
3187  match = TRUE;
3188  }
3189  else if ((Exception->Flags & EXCEPTION_FLG_64) &&
3190  gGuest.Guest64)
3191  {
3192  match = TRUE;
3193  }
3194  else if ((Exception->Flags & EXCEPTION_FLG_32) &&
3195  !gGuest.Guest64)
3196  {
3197  match = TRUE;
3198  }
3199 
3200  if (!match)
3201  {
3203  }
3204 
3205  match = FALSE;
3206 
3207  if (Exception->VictimNameHash == kmExcNameAny ||
3208  Exception->VictimNameHash == Victim->Object.NameHash)
3209  {
3210  match = TRUE;
3211  }
3212  else if (Exception->VictimNameHash == kmExcNameOwn)
3213  {
3214  KERNEL_DRIVER *pDriver = (Exception->Flags & EXCEPTION_KM_FLG_RETURN_DRV) ?
3215  Originator->Return.Driver : Originator->Original.Driver;
3216 
3217  if (pDriver && gGuest.OSType == introGuestWindows)
3218  {
3219  if (Victim->Object.Type == introObjectTypeKmModule)
3220  {
3221  match = Victim->Object.BaseAddress == pDriver->BaseVa;
3222  }
3223  else if ((Victim->Object.Type == introObjectTypeDriverObject) ||
3224  (Victim->Object.Type == introObjectTypeFastIoDispatch))
3225  {
3226  // Do this check, since some drivers don't have a DriverObject
3227  if (Victim->Object.DriverObject && pDriver->Win.DriverObject)
3228  {
3229  // Also, check by Gpa since a driver object may be pointed from different Gva
3230  match = Victim->Object.DriverObject->DriverObjectGpa == pDriver->Win.DriverObject->DriverObjectGpa;
3231  }
3232  }
3233  }
3234  else if (pDriver && gGuest.OSType == introGuestLinux)
3235  {
3236  if (Victim->Object.Type == introObjectTypeKmModule)
3237  {
3238  match = Victim->Object.BaseAddress == pDriver->Lix.CoreLayout.Base;
3239  }
3240  }
3241  }
3242 
3243  if (!match)
3244  {
3246  }
3247 
3248  match = FALSE;
3249 
3250  switch (Exception->Type)
3251  {
3252  case kmObjAny:
3253  match = TRUE;
3254  break;
3255 
3256  case kmObjDriver:
3257  if (Victim->Object.Type == introObjectTypeKmModule)
3258  {
3259  match = TRUE;
3260  }
3261  break;
3262 
3263  case kmObjDriverImports:
3264  if ((Victim->Object.Type == introObjectTypeKmModule) &&
3265  (Victim->ZoneFlags & ZONE_LIB_IMPORTS))
3266  {
3267  match = TRUE;
3268  }
3269  break;
3270 
3271  case kmObjDriverExports:
3272  if ((Victim->Object.Type == introObjectTypeKmModule) &&
3273  (Victim->ZoneFlags & ZONE_LIB_EXPORTS))
3274  {
3275  match = TRUE;
3276  }
3277  break;
3278 
3279  case kmObjDriverCode:
3280  if ((Victim->Object.Type == introObjectTypeKmModule &&
3281  (Victim->ZoneFlags & ZONE_LIB_CODE)) ||
3282  Victim->Object.Type == introObjectTypeVsyscall ||
3283  Victim->Object.Type == introObjectTypeVdso)
3284  {
3285  match = TRUE;
3286  }
3287  break;
3288 
3289  case kmObjDriverData:
3290  if ((Victim->Object.Type == introObjectTypeKmModule) &&
3291  (Victim->ZoneFlags & ZONE_LIB_DATA))
3292  {
3293  match = TRUE;
3294  }
3295  break;
3296 
3297  case kmObjDriverResources:
3298  if ((Victim->Object.Type == introObjectTypeKmModule) &&
3299  (Victim->ZoneFlags & ZONE_LIB_RESOURCES))
3300  {
3301  match = TRUE;
3302  }
3303  break;
3304 
3305  case kmObjSsdt:
3306  if (Victim->Object.Type == introObjectTypeSsdt)
3307  {
3308  match = TRUE;
3309  }
3310  break;
3311 
3312  case kmObjDrvObj:
3313  if (Victim->Object.Type == introObjectTypeDriverObject)
3314  {
3315  match = TRUE;
3316  }
3317  break;
3318 
3319  case kmObjFastIo:
3320  if (Victim->Object.Type == introObjectTypeFastIoDispatch)
3321  {
3322  match = TRUE;
3323  }
3324  break;
3325 
3326  case kmObjMsr:
3327  if (Victim->ZoneType == exceptionZoneMsr)
3328  {
3329  match = TRUE;
3330  }
3331  break;
3332 
3333  case kmObjCr4:
3334  if (Victim->ZoneType == exceptionZoneCr)
3335  {
3336  match = TRUE;
3337  }
3338  break;
3339 
3340  case kmObjHalHeap:
3341  if ((Victim->ZoneType == exceptionZoneEpt) &&
3342  ((Victim->Object.Type == introObjectTypeHalIntController) ||
3343  (Victim->Object.Type == introObjectTypeHalHeap)))
3344  {
3345  match = TRUE;
3346  }
3347  break;
3348 
3349  case kmObjSudExec:
3350  if ((Victim->ZoneType == exceptionZoneEpt) &&
3351  (Victim->Object.Type == introObjectTypeSudExec))
3352  {
3353  match = TRUE;
3354  }
3355  break;
3356 
3357  case kmObjSelfMapEntry:
3358  if ((Victim->ZoneType == exceptionZoneEpt) &&
3359  (Victim->Object.Type == introObjectTypeSelfMapEntry))
3360  {
3361  match = TRUE;
3362  }
3363  break;
3364 
3365  case kmObjIdt:
3366  if ((Victim->ZoneType == exceptionZoneEpt ||
3367  Victim->ZoneType == exceptionZoneIntegrity) &&
3368  Victim->Object.Type == introObjectTypeIdt)
3369  {
3370  match = TRUE;
3371  }
3372  break;
3373 
3374  case kmObjIdtr:
3375  if ((Victim->ZoneType == exceptionZoneDtr) &&
3376  (Victim->Object.Type == introObjectTypeIdtr))
3377  {
3378  match = TRUE;
3379  }
3380  break;
3381 
3382  case kmObjGdtr:
3383  if ((Victim->ZoneType == exceptionZoneDtr) &&
3384  (Victim->Object.Type == introObjectTypeGdtr))
3385  {
3386  match = TRUE;
3387  }
3388  break;
3389 
3390  case kmObjLoggerCtx:
3391  if (Victim->Object.Type == introObjectTypeKmLoggerContext)
3392  {
3393  match = TRUE;
3394  }
3395  break;
3396 
3397  case kmObjTokenPrivs:
3398  if (Victim->Object.Type == introObjectTypeTokenPrivs)
3399  {
3400  match = TRUE;
3401  }
3402  break;
3403 
3404  case kmObjHalPerfCnt:
3405  if (Victim->Object.Type == introObjectTypeHalPerfCounter)
3406  {
3407  match = TRUE;
3408  }
3409  break;
3410 
3411  case kmObjSecDesc:
3412  if (Victim->Object.Type == introObjectTypeSecDesc)
3413  {
3414  match = TRUE;
3415  }
3416  break;
3417 
3418  case kmObjAcl:
3419  if (Victim->Object.Type == introObjectTypeAcl)
3420  {
3421  match = TRUE;
3422  }
3423  break;
3424 
3425  case kmObjSudModification:
3426  if (Victim->Object.Type == introObjectTypeSudIntegrity)
3427  {
3428  match = TRUE;
3429  }
3430  break;
3431 
3432  case kmObjInterruptObject:
3433  if (Victim->Object.Type == introObjectTypeInterruptObject)
3434  {
3435  match = TRUE;
3436  }
3437  break;
3438 
3439  default:
3440  LOG("[ERROR] This is a corruption in the update/exception. Type = %d!\n", Exception->Type);
3441  break;
3442  }
3443 
3444  if (!match)
3445  {
3447  }
3448 
3449  if (Exception->Flags & EXCEPTION_FLG_INIT)
3450  {
3451  match = FALSE;
3452 
3453  // a. On integrity zones, this is all we can check
3454  if ((Victim->ZoneType == exceptionZoneIntegrity) &&
3455  (Victim->WriteInfo.OldValue[0] == 0))
3456  {
3457  match = TRUE;
3458  }
3459  // b. Kernel's INIT section writes
3460  else if ((Exception->Flags & EXCEPTION_KM_FLG_RETURN_DRV) &&
3461  (Originator->Return.NameHash == kmExcNameKernel))
3462  {
3463  // match anything that starts with init/INIT
3465  {
3466  match = 0 == memcmp(Originator->Return.Section, "INIT", 4);
3467  }
3468  else
3469  {
3470  match = 0 == memcmp(Originator->Return.Section, "init", 4);
3471  }
3472  }
3473  else if (Originator->Original.NameHash == kmExcNameKernel)
3474  {
3475  // match anything that starts with init/INIT
3477  {
3478  match = 0 == memcmp(Originator->Original.Section, "INIT", 4);
3479  }
3480  else
3481  {
3482  match = 0 == memcmp(Originator->Original.Section, "init", 4);
3483  }
3484  }
3485  // c. RIP is in EntryPoint
3486  else if (Originator->IsEntryPoint)
3487  {
3488  match = TRUE;
3489  }
3490  // d. Old value was 0
3491  else if (Victim->WriteInfo.OldValue[0] == 0)
3492  {
3493  match = TRUE;
3494  }
3495 
3496  if (!match)
3497  {
3499  }
3500  }
3501 
3502  if (kmObjCr4 == Exception->Type)
3503  {
3504  // We don't care about the activation of these flags (we allow it). But the deactivation is another story...
3505  match = FALSE;
3506 
3507  if ((Exception->Flags & EXCEPTION_KM_FLG_SMAP) &&
3508  (Exception->Flags & EXCEPTION_KM_FLG_SMEP))
3509  {
3510  match = TRUE;
3511  }
3512  else if ((Exception->Flags & EXCEPTION_KM_FLG_SMAP) &&
3513  (Victim->Cr.Smap))
3514  {
3515  match = TRUE;
3516  }
3517  else if ((Exception->Flags & EXCEPTION_KM_FLG_SMEP) &&
3518  Victim->Cr.Smep)
3519  {
3520  match = TRUE;
3521  }
3522 
3523  if (!match)
3524  {
3526  }
3527  }
3528 
3529  // If we get here, then allow the action. Anyway, the extra checks & signatures mechanism will actually allow it
3531 }
3532 
3533 
3534 INTSTATUS
3536  _In_ EXCEPTION_VICTIM_ZONE *Victim,
3537  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
3538  _Out_ INTRO_ACTION *Action,
3539  _Out_ INTRO_ACTION_REASON *Reason
3540  )
3557 {
3559  BOOLEAN sameRip = FALSE;
3560  BYTE id;
3561 
3562  if (NULL == Victim)
3563  {
3565  }
3566 
3567  if (NULL == Originator)
3568  {
3570  }
3571 
3572  if (NULL == Action)
3573  {
3575  }
3576 
3577  if (NULL == Reason)
3578  {
3580  }
3581 
3582  *Action = introGuestNotAllowed;
3583  *Reason = introReasonNoException;
3584 
3585  // In some cases the Old/New values are the same - allow them by default.
3586  if (__unlikely(Victim->ZoneType == exceptionZoneEpt && !!(Victim->ZoneFlags & ZONE_WRITE) &&
3587  !memcmp(Victim->WriteInfo.OldValue, Victim->WriteInfo.NewValue,
3588  MIN(Victim->WriteInfo.AccessSize, sizeof(Victim->WriteInfo.NewValue)))))
3589  {
3590  *Action = introGuestAllowed;
3591  *Reason = introReasonSameValue;
3592 
3594  }
3595 
3597  {
3598  if (pEx->OriginatorNameHash == kmExcNameAny)
3599  {
3600  // For now, we do not support exceptions from the alert that has originator kmExcNameAny.
3601  // If an exception from the alert has no originator, kmExcNameNone will be used as the exception originator
3602  goto _match_ex_alert;
3603  }
3604 
3605  if (Originator->Original.NameHash == INITIAL_CRC_VALUE && pEx->OriginatorNameHash == kmExcNameNone)
3606  {
3607  goto _match_ex_alert;
3608  }
3609 
3610  if (pEx->OriginatorNameHash > Originator->Original.NameHash)
3611  {
3612  break;
3613  }
3614  else if (pEx->OriginatorNameHash != Originator->Original.NameHash)
3615  {
3616  continue;
3617  }
3618 
3619 _match_ex_alert:
3620  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKm, Action, Reason);
3621  if (status == INT_STATUS_EXCEPTION_ALLOW)
3622  {
3623  return status;
3624  }
3625  }
3626 
3627  if (Originator->Original.NameHash == INITIAL_CRC_VALUE)
3628  {
3629  // Check the no name exceptions, and skip the generic ones
3631  {
3632  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKm, Action, Reason);
3633  if (status == INT_STATUS_EXCEPTION_ALLOW)
3634  {
3635  return status;
3636  }
3637  }
3638  }
3639  else
3640  {
3641  // Check the generic exceptions (all of them, since originator matches anything)
3643  {
3644  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKm, Action, Reason);
3645  if (status == INT_STATUS_EXCEPTION_ALLOW)
3646  {
3647  return status;
3648  }
3649  }
3650  }
3651 
3652  if (Originator->Original.Driver && Originator->Return.Driver &&
3653  (Originator->Original.Rip == Originator->Return.Rip))
3654  {
3655  // Don't check by RIP since it may be in different sections
3656  sameRip = TRUE;
3657  }
3658 
3659  if (Originator->Original.NameHash != INITIAL_CRC_VALUE)
3660  {
3661  id = EXCEPTION_TABLE_ID(Originator->Original.NameHash);
3662 
3664  {
3665  // Here we only check exceptions by the name, so that cannot be missing.
3666  // And the return flag must be missing.
3667  if (pEx->OriginatorNameHash == INITIAL_CRC_VALUE ||
3668  ((pEx->Flags & EXCEPTION_KM_FLG_RETURN_DRV) &&
3669  !sameRip))
3670  {
3671  continue;
3672  }
3673 
3674  // Every list is ordered, so break when we got to a hash bigger than ours
3675  if (pEx->OriginatorNameHash > Originator->Original.NameHash)
3676  {
3677  break;
3678  }
3679  else if (pEx->OriginatorNameHash != Originator->Original.NameHash)
3680  {
3681  continue;
3682  }
3683 
3684  // The EXCEPTION_KM_FLG_RETURN_DRV will be deleted, so do the same verification again
3685  if ((pEx->Flags & EXCEPTION_FLG_RETURN) && !sameRip)
3686  {
3687  continue;
3688  }
3689 
3690  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKm, Action, Reason);
3691  if (status == INT_STATUS_EXCEPTION_ALLOW)
3692  {
3693  return status;
3694  }
3695  }
3696 
3697  if (sameRip)
3698  {
3699  // No point in doing the same thing again
3700  goto _beta_exceptions;
3701  }
3702  }
3703 
3704  // Try and match the original driver by name
3705  if (Originator->Return.NameHash != INITIAL_CRC_VALUE)
3706  {
3707  id = EXCEPTION_TABLE_ID(Originator->Return.NameHash);
3709  {
3710  // Here we only check exceptions by the name, so that cannot be missing
3711  // And the return flag must be set
3712  if (pEx->OriginatorNameHash == INITIAL_CRC_VALUE ||
3713  (0 == (pEx->Flags & EXCEPTION_KM_FLG_RETURN_DRV)))
3714  {
3715  continue;
3716  }
3717 
3718  // Every list is ordered, so break when we got to a hash bigger than ours
3719  if (pEx->OriginatorNameHash > Originator->Return.NameHash)
3720  {
3721  break;
3722  }
3723  else if (pEx->OriginatorNameHash != Originator->Return.NameHash)
3724  {
3725  continue;
3726  }
3727 
3728  // The EXCEPTION_KM_FLG_RETURN_DRV will be deleted, so do the same verification again
3729  if (0 == (pEx->Flags & EXCEPTION_FLG_RETURN))
3730  {
3731  continue;
3732  }
3733 
3734  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKm, Action, Reason);
3735  if (status == INT_STATUS_EXCEPTION_ALLOW)
3736  {
3737  return status;
3738  }
3739  }
3740  }
3741 
3742 _beta_exceptions:
3744  {
3745  if (pEx->OriginatorNameHash == kmExcNameAny)
3746  {
3747  goto _match_ex;
3748  }
3749 
3750  if (Originator->Original.NameHash == INITIAL_CRC_VALUE && pEx->OriginatorNameHash == kmExcNameNone)
3751  {
3752  goto _match_ex;
3753  }
3754 
3755  if (pEx->Flags & EXCEPTION_FLG_RETURN)
3756  {
3757  if (pEx->OriginatorNameHash != Originator->Return.NameHash)
3758  {
3759  continue;
3760  }
3761  }
3762  else
3763  {
3764  if (pEx->OriginatorNameHash != Originator->Original.NameHash)
3765  {
3766  continue;
3767  }
3768  }
3769 _match_ex:
3770  status = IntExceptMatchException(Victim, Originator, pEx, exceptionTypeKm, Action, Reason);
3771  if (status == INT_STATUS_EXCEPTION_ALLOW)
3772  {
3773  return status;
3774  }
3775  }
3776 
3777  return status;
3778 }
#define IMAGE_SCN_MEM_EXECUTE
Definition: winpe.h:472
WORD Offset15_0
Definition: processor.h:134
INTSTATUS IntExceptKernelGetOriginator(EXCEPTION_KM_ORIGINATOR *Originator, DWORD Options)
This function is used to get the information about the kernel-mode originator.
#define _In_opt_
Definition: intro_sal.h:16
#define EXCEPTION_NO_INSTRUCTION
Definition: exceptions.h:30
QWORD DriverObjectGva
The guest virtual address of the guest _DRIVER_OBJECT represented by this structure.
Definition: windrvobj.h:18
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 INT_STATUS_EXCEPTION_NOT_MATCHED
Definition: introstatus.h:406
#define __unlikely(x)
Definition: common.h:64
INTSTATUS IntPeGetSectionHeaderByRva(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD GuestRva, IMAGE_SECTION_HEADER *SectionHeader)
Given a relative virtual address, return the section header which describes the section the RVA lies ...
Definition: winpe.c:707
_Bool BOOLEAN
Definition: intro_types.h:58
static int IntExceptPrintDrvObjInfo(WIN_DRIVER_OBJECT *DrvObj, char *Header, char *Line, int MaxLength)
Print the information about the WIN_DRIVER_OBJECT.
#define _Out_
Definition: intro_sal.h:22
#define IG_IA32_SYSENTER_ESP
Definition: glueiface.h:139
char * utf16toutf8(char *Destination, const WCHAR *Source, DWORD DestinationMaxLength)
Definition: introcrt.c:460
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
An internal error occurred (no memory, pages not present, etc.).
Definition: intro_types.h:195
INTSTATUS IntExceptGetVictimMsr(QWORD NewValue, QWORD OldValue, DWORD Msr, EXCEPTION_VICTIM_ZONE *Victim)
This function is used to get the information about the MSR victim.
QWORD End
The end guest virtual address of ksym (exclusive).
Definition: lixguest.h:439
Kernel module (ntoskrnl.exe, hal.dll, etc.).
Definition: intro_types.h:238
uint8_t BYTE
Definition: intro_types.h:47
BYTE Unknown
Set if the function at this RIP is not exported.
Definition: drivers.h:20
INTSTATUS IntExceptGetVictimIntegrity(INTEGRITY_REGION *IntegrityRegion, DWORD *Offset, EXCEPTION_VICTIM_ZONE *Victim)
This function is used to get the information about the modified zone from the integrity region...
static int IntExceptPrintIdtInfo(EXCEPTION_VICTIM_ZONE *Victim, char *Header, char *Line, int MaxLength)
Print the information about the modified IDT entry.
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
Definition: winguest.c:37
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
DWORD Crc32Compute(const void *Buffer, size_t Size, DWORD InitialCrc)
Computes the CRC for a byte array.
Definition: crc32.c:103
The modified object is anything inside the HAL heap zone.
Definition: exceptions.h:167
#define _In_
Definition: intro_sal.h:21
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
Fast IO Dispatch (Windows only).
Definition: intro_types.h:236
An interrupt object from KPRCB.
Definition: intro_types.h:274
LIST_HEAD NoNameKernelExceptions
Linked list used for kernel-mode exceptions that don&#39;t have a valid originator (-).
Definition: exceptions.h:97
The name can be any string.
Definition: exceptions.h:640
INTSTATUS IntExceptGetVictimCr(QWORD NewValue, QWORD OldValue, DWORD Cr, EXCEPTION_VICTIM_ZONE *Victim)
This function is used to get the information about the CR victim.
Infinity hook modifications of WMI_LOGGER_CONTEXT.GetCpuClock.
Definition: intro_types.h:264
WIN_KERNEL_DRIVER Win
Valid only for Windows guests.
Definition: drivers.h:70
The modified object is only the driver&#39;s EAT.
Definition: exceptions.h:158
struct _IDT_ENTRY32 IDT_ENTRY32
INTSTATUS IntLixStackTraceGetReg(QWORD Cr3, PIG_ARCH_REGS Registers, DWORD MaxNumberOfTraces, QWORD Flags, STACK_TRACE *StackTrace)
Retrieves a Kernel stack backtrace based on the register values.
Definition: lixstack.c:225
#define ZONE_LIB_RESOURCES
Used for the resources section (usually .rsrc inside a driver or dll).
Definition: exceptions.h:726
QWORD Start
The start guest virtual address of ksym.
Definition: lixguest.h:438
The modified object represents an execution inside SharedUserData.
Definition: exceptions.h:176
INTSTATUS IntKsymFindByAddress(QWORD Gva, DWORD Length, char *SymName, QWORD *SymStart, QWORD *SymEnd)
Finds the symbol which is located at the given address.
Definition: lixksym.c:1283
QWORD BaseVa
The guest virtual address of the kernel module that owns this driver object.
Definition: drivers.h:41
The exception will take into consideration the return driver/dll.
Definition: exceptions.h:601
#define IMAGE_SCN_MEM_WRITE
Definition: winpe.h:474
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define EXCEPTION_NO_NAME
Definition: exceptions.h:28
#define ARRAYSIZE(A)
Definition: introdefs.h:101
WORD Offset31_16
Definition: processor.h:148
The modified object is inside an EPT hook.
Definition: exceptions.h:746
BOOLEAN KernelBetaDetections
True if the kernel protection is in beta (log-only) mode.
Definition: guests.h:303
WORD Offset31_16
Definition: processor.h:137
#define INT_STATUS_EXCEPTION_CHECKS_OK
Definition: introstatus.h:396
void IntDriverCacheCreateExport(const QWORD Rip)
Adds a new export entry to the gDriverExportCache.
Definition: drivers.c:432
static INTSTATUS IntExceptLixKernelGetOriginator(EXCEPTION_KM_ORIGINATOR *Originator)
This function is used to get the information about the kernel-mode originator (Linux guest)...
DWORD PathLength
The driver`s path length (number of WCHARS).
Definition: windriver.h:26
The modified object is HalPerformanceCounter.
Definition: exceptions.h:177
The exception is valid only for read violation.
Definition: exceptions.h:605
#define EXCEPTION_KM_ORIGINATOR_OPT_DO_NOT_BLOCK
Flag that can be passed to IntExceptKernelGetOriginator if the action should not be blocked...
Definition: exceptions.h:1053
PBYTE MzPeHeaders
The driver`s MZ/PE headers (cached internally).
Definition: windriver.h:34
QWORD Parent
Depends if this is a thread or a process.
Definition: lixprocess.h:57
#define IG_IA32_SYSENTER_EIP
Definition: glueiface.h:140
#define ERROR(fmt,...)
Definition: glue.h:62
Describes a user-mode originator.
Definition: exceptions.h:994
INTSTATUS IntPeFindExportByRvaInBuffer(QWORD ImageBase, BYTE *Buffer, DWORD BufferSize, DWORD Rva)
Check if the indicated Rva belongs to an exported function.
Definition: winpe.c:1223
INTSTATUS IntExceptGetVictimDtr(DTR *NewValue, DTR *OldValue, INTRO_OBJECT_TYPE Type, EXCEPTION_VICTIM_ZONE *Victim)
This function is used to get the information about the DTR victim.
The modified object is only the driver&#39;s data sections.
Definition: exceptions.h:160
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 _FAST_IO_DISPATCH structure used by 32-bit guests.
Definition: wddefs.h:280
LIX_MODULE_LAYOUT CoreLayout
The layout of the core section.
Definition: lixmodule.h:40
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
The exception will match only for the init phase of a driver/process.
Definition: exceptions.h:599
#define ONE_KILOBYTE
Definition: introdefs.h:89
LIST_HEAD KernelAlertExceptions
Linked list used for kernel-mode exceptions that are added from alert.
Definition: exceptions.h:126
The name is missing.
Definition: exceptions.h:644
#define MAX_PATH
The maximum size of a path (260 characters on windows).
Definition: winpe.h:579
INTSTATUS IntExceptGetOriginatorFromModification(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator)
This function is used for integrity violations to get the information about the kernel-mode originato...
Integrity protection of SharedUserData region.
Definition: intro_types.h:273
Describes a kernel-mode originator.
Definition: exceptions.h:943
The modified object is only the driver&#39;s IAT.
Definition: exceptions.h:174
DWORD Offset63_32
Definition: processor.h:138
int IntExceptPrintWinKmModInfo(KERNEL_DRIVER *Module, char *Header, char *Line, int MaxLength, DWORD NameAlignment)
Print the information about the provided KERNEL_DRIVER (windows guest).
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
Definition: guests.h:88
struct _DRIVER_EXPORT_CACHE_ENTRY::@23 Type
The exception is valid only for write violation.
Definition: exceptions.h:606
Process ACL (SACL/DACL) was modified.
Definition: intro_types.h:272
#define MIN(a, b)
Definition: introdefs.h:146
The modified object is anything inside the driver.
Definition: exceptions.h:157
An access control list.
Definition: wddefs.h:637
#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
DWORD NameHash
The hash of the name.
Definition: drivers.h:59
The modified object is a SharedUserData field.
Definition: exceptions.h:180
The modified object is IDTR/GDTR.
Definition: exceptions.h:751
Token privileges.
Definition: intro_types.h:266
enum _INTRO_OBJECT_TYPE INTRO_OBJECT_TYPE
The type of the object protected by an EPT hook.
#define _Inout_
Definition: intro_sal.h:20
The exception is valid only for CR4.SMEP write.
Definition: exceptions.h:616
static int IntExceptPrintMsrInfo(EXCEPTION_VICTIM_ZONE *Victim, char *Header, char *Line, int MaxLength)
Print the information about the modified MSR.
#define ZONE_LIB_CODE
Used for a generic code zone.
Definition: exceptions.h:723
#define INITIAL_CRC_VALUE
Definition: introdefs.h:221
#define INT_STATUS_EXCEPTION_BLOCK
Definition: introstatus.h:421
Hal interrupt controller.
Definition: intro_types.h:253
EXCEPTIONS * Exceptions
The exceptions that are currently loaded.
Definition: guests.h:392
#define IG_CURRENT_VCPU
For APIs that take a VCPU number as a parameter, this can be used to specify that the current VCPU sh...
Definition: glueiface.h:324
The modified object is inside an integrity hook.
Definition: exceptions.h:749
The exception is valid only for CR4.SMAP write.
Definition: exceptions.h:615
SIZE_T NameLength
The length of the Name. This is the number of characters in the Name buffer.
Definition: drivers.h:56
#define CR4_SMEP
Definition: processor.h:61
#define ZONE_EXECUTE
Used for execute violation.
Definition: exceptions.h:736
LIST_HEAD KernelFeedbackExceptions
Linked list used for kernel-mode exceptions that have the feedback flag.
Definition: exceptions.h:115
Holds information about a driver object.
Definition: windrvobj.h:13
CPU_STATE State
The state of this VCPU. Describes what action is the VCPU currently doing.
Definition: guests.h:173
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
unsigned long long QWORD
Definition: intro_types.h:53
The modified object is only the driver&#39;s code sections.
Definition: exceptions.h:159
Handling a LIDT or LGDT.
Definition: guests.h:26
The name is the operating system kernel name.
Definition: exceptions.h:642
DWORD NameHash
Hash of the Name.
Definition: windrvobj.h:34
DRIVER_EXPORT_CACHE_ENTRY * IntDriverCacheExportFind(const QWORD Rip)
Finds an entry inside the gDriverExportCache.
Definition: drivers.c:484
INTSTATUS IntExceptKernelMatchVictim(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, KM_EXCEPTION *Exception)
This function checks if the exception matches the originator and the modified zone.
#define IG_IA32_STAR
Definition: glueiface.h:145
Write protection over HalPerformanceCounter.
Definition: intro_types.h:268
#define TRUE
Definition: intro_types.h:30
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
static BOOLEAN IntExceptLixKernelIsMemoryFunc(QWORD Rip)
This function is used to check if the write has been made using any of "memcpy","__memcpy", "memset", "__memset", "memmove" function.
#define IS_KERNEL_POINTER_WIN(is64, p)
Checks if a guest virtual address resides inside the Windows kernel address space.
Definition: wddefs.h:76
#define EXCEPTION_KM_ORIGINATOR_OPT_FULL_STACK
Flag that can be passed to IntExceptKernelGetOriginator when the full stack is needed.
Definition: exceptions.h:1060
#define TRACE(fmt,...)
Definition: glue.h:58
WORD AclSize
Definition: wddefs.h:641
WORD AceCount
Definition: wddefs.h:642
Allow modification of it&#39;s own driver object.
Definition: exceptions.h:641
#define INT_STATUS_INVALID_INTERNAL_STATE
Definition: introstatus.h:272
The modified object is SSDT (valid only on windows x86).
Definition: exceptions.h:162
static int IntExceptPrintCrInfo(EXCEPTION_VICTIM_ZONE *Victim, char *Header, char *Line, int MaxLength)
Print the information about the modified CR.
The modified object is the self map entry inside PDBR.
Definition: exceptions.h:168
void * Name
The name of the driver.
Definition: drivers.h:54
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:283
struct _IDT_ENTRY64 IDT_ENTRY64
Kernel-mode exception.
Definition: exceptions.h:61
LIX_SYMBOL MemoryFunctions[5]
The guest virtual address of memcpy, __memcpy, memset, __memset, memmove.
Definition: lixguest.h:513
#define IG_IA32_LSTAR
Definition: glueiface.h:146
QWORD DriverObjectGpa
The guest physical address of the guest _DRIVER_OBJECT represented by this structure.
Definition: windrvobj.h:25
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
Definition: guests.h:367
INTSTATUS IntWinStackTraceGet(QWORD StackFrame, QWORD Rip, DWORD MaxNumberOfTraces, QWORD Flags, STACK_TRACE *StackTrace)
Get a kernel stack trace starting from the current stack pointer for 64 bit systems.
Definition: winstack.c:1164
#define DESCRIPTOR_SIZE_64
Definition: processor.h:102
void IntLixDrvGetSecName(KERNEL_DRIVER *Driver, QWORD Gva, CHAR *SectionName)
Get the section of the driver that contains the provided guest virtual address.
Definition: lixmodule.c:913
The modified object is a MSR.
Definition: exceptions.h:747
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.
LIX_KERNEL_MODULE Lix
Valid only for Linux guests.
Definition: drivers.h:71
#define WARNING(fmt,...)
Definition: glue.h:60
#define EXCEPTION_NO_SYMBOL
Definition: exceptions.h:31
The exception will take into consideration the return driver.
Definition: exceptions.h:614
#define ZONE_LIB_EXPORTS
Used for the exports of a dll, driver, etc.
Definition: exceptions.h:722
DWORD SelfMapIndex
The self map index.
Definition: guests.h:220
#define CR4_SMAP
Definition: processor.h:62
The modified object is the privileges field inside the nt!_TOKEN structure.
Definition: exceptions.h:175
The modified object is SMEP and/or SMAP bits of CR4.
Definition: exceptions.h:166
#define IDT_DESC_SIZE64
The size of a 64-bit interrupt descriptor.
Definition: wddefs.h:32
A descriptor table register. Valid for IDTR and GDTR.
Definition: introcpu.h:71
#define LIX_SYMBOL_NAME_LEN
The max length of the ksym as defined by Linux kernel.
Definition: lixguest.h:585
#define PAGE_SIZE
Definition: common.h:70
Describes the modified zone.
Definition: exceptions.h:893
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
The modified object is IDTR.
Definition: exceptions.h:170
Describe a kernel-mode exception.
Definition: exceptions.h:253
#define for_each_km_exception(_ex_head, _var_name)
Definition: exceptions.h:1066
static int IntExceptPrintLixKmDrvInfo(KERNEL_DRIVER *Driver, char *Header, char *Line, int MaxLength, DWORD NameAlignment)
Print the information about the provided KERNEL_DRIVER (Linux guest).
Describe a user-mode exception.
Definition: exceptions.h:308
uint16_t WCHAR
Definition: intro_types.h:63
Executions inside the SharedUserData region.
Definition: intro_types.h:267
The Virtualization exception agent injected inside the guest.
Definition: intro_types.h:259
uint32_t DWORD
Definition: intro_types.h:49
DWORD KernelBufferSize
The size of the KernelBuffer.
Definition: winguest.h:852
The exception is valid only for integrity zone.
Definition: exceptions.h:618
UINT32 Characteristics
Definition: winpe.h:92
The modified object is anything inside the driver&#39;s fast IO dispatch table.
Definition: exceptions.h:164
The modified object is any with the modified name.
Definition: exceptions.h:156
enum _INTRO_ACTION INTRO_ACTION
Event actions.
#define IMAGE_SCN_CNT_CODE
Definition: winpe.h:425
INTSTATUS IntExceptKernelVerifyExtra(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, UM_EXCEPTION *Exception)
This function is used as an extra step in exception mechanism.
LIST_HEAD GenericKernelExceptions
Linked list used for kernel-mode exceptions that have a generic originator (*).
Definition: exceptions.h:89
The action was allowed, but it has the BETA flag (Introcore is in log-only mode). ...
Definition: intro_types.h:185
#define MAX(a, b)
Definition: introdefs.h:151
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
Definition: introcore.c:2134
#define ZONE_LIB_DATA
Definition: exceptions.h:724
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
Self mapping index in PDBR.
Definition: intro_types.h:254
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
The _FAST_IO_DISPATCH structure used by 64-bit guests.
Definition: wddefs.h:315
The modified object is any IDT entry.
Definition: exceptions.h:169
char gExcLogLine[2 *ONE_KILOBYTE]
The exception log line.
Definition: exceptions.c:40
SSDT (Windows only).
Definition: intro_types.h:235
Hal dispatch table.
Definition: intro_types.h:252
KERNEL_DRIVER * IntDriverFindByBase(QWORD Gva)
Searches a driver object by its module base.
Definition: drivers.c:211
The modified object is an ACL (SACL/DACL) of a process.
Definition: exceptions.h:179
#define EXCEPTION_TABLE_ID(H)
Definition: exceptions.h:50
#define FIELD_OFFSET(type, field)
Definition: introdefs.h:239
Virtual SYSCALL (user-mode, Linux-only).
Definition: intro_types.h:257
static INTSTATUS IntExceptWinKernelGetOriginator(EXCEPTION_KM_ORIGINATOR *Originator, DWORD Options)
This function is used to get the information about the kernel-mode originator (windows guest)...
int wstrcasecmp(const WCHAR *buf1, const WCHAR *buf2)
Definition: introcrt.c:98
LIST_HEAD KernelExceptions[EXCEPTION_TABLE_SIZE]
Array of linked lists used for kernel-mode exceptions.
Definition: exceptions.h:107
INTSTATUS IntPeFindExportByRva(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD Rva)
Check if a RVA lies inside an exported function.
Definition: winpe.c:1103
KERNEL_DRIVER * IntDriverFindByAddress(QWORD Gva)
Returns the driver in which Gva resides.
Definition: drivers.c:164
#define ZONE_READ
Used for read violation.
Definition: exceptions.h:735
The modified object is WMI_LOGGER_CONTEXT.GetCpuClock used by InfinityHook (valid only on windows)...
Definition: exceptions.h:171
BYTE AclRevision
Definition: wddefs.h:639
static void IntExceptKernelLogLinuxInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-mode violation (Linux guest).
The action was blocked because no exception signature matched.
Definition: intro_types.h:187
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
Virtual dynamic shared object (user-mode, Linux-only).
Definition: intro_types.h:256
The modified object is an interrupt object from KPRCB.
Definition: exceptions.h:181
BYTE * KernelBuffer
A buffer containing the entire kernel image.
Definition: winguest.h:851
KERNEL_DRIVER * KernelDriver
Points to the driver object that describes the kernel image.
Definition: guests.h:385
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.
LIX_TASK_OBJECT * IntLixTaskFindByGva(QWORD TaskStruct)
Finds Linux process with the provided "task_struct" guest virtual address.
Definition: lixprocess.c:1025
The modified object is a CR.
Definition: exceptions.h:748
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
void IntDriverCacheCreateUnknown(const QWORD Rip)
Adds a new entry to the gDriverExportCache.
Definition: drivers.c:458
LIX_TASK_OBJECT * IntLixTaskGetCurrent(DWORD CpuNumber)
Finds the task that is currently running on the given CPU.
Definition: lixprocess.c:858
UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]
Definition: winpe.h:79
Describes an entry in the gDriverExportCache.
Definition: drivers.h:14
QWORD Base
The base GVA of the section.
Definition: lixmodule.h:19
#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
static void IntExceptKernelLogWindowsInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-mode violation (windows guest).
Holds register state.
Definition: glueiface.h:30
QWORD EntryPoint
The entry point of this driver.
Definition: drivers.h:45
PWIN_DRIVER_OBJECT DriverObject
The driver object.
Definition: windriver.h:36
The exception is valid only on 32 bit systems/process.
Definition: exceptions.h:596
#define EXPORT_NAME_UNKNOWN
Definition: exceptions.h:34
The modified object is anything inside the driver object.
Definition: exceptions.h:163
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...
#define IDT_DESC_SIZE32
The size of a 32-bit interrupt descriptor.
Definition: wddefs.h:31
The modified object is only the driver&#39;s resources sections.
Definition: exceptions.h:161
Process security descriptor pointer.
Definition: intro_types.h:271
#define ZONE_WRITE
Used for write violation.
Definition: exceptions.h:734
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
static int IntExceptPrintDtrInfo(EXCEPTION_VICTIM_ZONE *Victim, char *Header, char *Line, int MaxLength)
Print the information about the modified IDTR/GDTR.
The modified object is the security descriptor pointer of a process.
Definition: exceptions.h:178
The name is the operating system HAL name (valid only for windows).
Definition: exceptions.h:643
#define IG_IA32_SYSENTER_CS
Definition: glueiface.h:138
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:30
WORD Offset15_0
Definition: processor.h:144
The modified object is a MSR.
Definition: exceptions.h:165
#define INT_STATUS_EXCEPTION_ALLOW
Definition: introstatus.h:391
#define FALSE
Definition: intro_types.h:34
#define ALIGN_DOWN(x, a)
Definition: introdefs.h:165
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
Handling EPT violation.
Definition: guests.h:22