Bitdefender Hypervisor Memory Introspection
windrvobj.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "windrvobj.h"
6 #include "windrv_protected.h"
7 #include "alerts.h"
8 #include "crc32.h"
9 #include "decoder.h"
10 #include "hook.h"
11 #include "winpe.h"
12 
14 static LIST_HEAD gWinDriverObjects = LIST_HEAD_INIT(gWinDriverObjects);
15 
16 static INTSTATUS
18  _Inout_ WIN_DRIVER_OBJECT *DriverObject
19  );
20 
21 static INTSTATUS
23  _Inout_ WIN_DRIVER_OBJECT *DriverObject
24  );
25 
26 
27 BOOLEAN
29  _In_ QWORD DriverObjectAddress
30  )
50 {
51  INTSTATUS status;
52  PBYTE pObject, pModule;
53  BOOLEAN valid;
54  VA_TRANSLATION translation;
55 
56  valid = FALSE;
57 
58  pObject = NULL;
59  pModule = NULL;
60 
61  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, DriverObjectAddress))
62  {
63  return FALSE;
64  }
65 
66  status = IntVirtMemMap(DriverObjectAddress,
67  WIN_KM_FIELD(DrvObj, Size),
69  0,
70  &pObject);
71  if (!INT_SUCCESS(status))
72  {
73  return FALSE;
74  }
75 
76  if (gGuest.Guest64)
77  {
78  DRIVER_OBJECT64 const *pDrvObj = (DRIVER_OBJECT64 *)pObject;
79  INTRO_PE_INFO peInfo = {0};
80 
81  if (pDrvObj->Type != DRIVER_OBJECT_TYPE)
82  {
83  goto cleanup_and_exit;
84  }
85 
86  if (pDrvObj->Size != WIN_KM_FIELD(DrvObj, Size))
87  {
88  goto cleanup_and_exit;
89  }
90 
91  if (pDrvObj->DriverStart % PAGE_SIZE != 0)
92  {
93  goto cleanup_and_exit;
94  }
95 
96  // Try to translate the driver start, in order to see if it leads to a valid address.
97  status = IntTranslateVirtualAddressEx(pDrvObj->DriverStart, gGuest.Mm.SystemCr3, TRFLG_NONE, &translation);
98  if (!INT_SUCCESS(status))
99  {
100  goto cleanup_and_exit;
101  }
102 
103  if (!(translation.Flags & PT_P))
104  {
105  goto cleanup_and_exit;
106  }
107 
108  if (translation.Flags & PT_US)
109  {
110  goto cleanup_and_exit;
111  }
112 
113  if (translation.Flags & PT_PCD)
114  {
115  // We shouldn't touch non-cacheable pages.
116  goto cleanup_and_exit;
117  }
118 
119  status = IntPhysMemMap(translation.PhysicalAddress, PAGE_SIZE, 0, &pModule);
120  if (!INT_SUCCESS(status))
121  {
122  goto cleanup_and_exit;
123  }
124 
125  status = IntPeValidateHeader(pDrvObj->DriverStart, pModule, PAGE_SIZE, &peInfo, 0);
126  if (!INT_SUCCESS(status))
127  {
128  ERROR("[ERROR] IntPeValidateHeader failed: 0x%08x\n", status);
129  goto cleanup_and_exit;
130  }
131 
132  if (peInfo.SizeOfImage != pDrvObj->DriverSize)
133  {
134  goto cleanup_and_exit;
135  }
136 
137  if (peInfo.EntryPoint != (pDrvObj->DriverInit - pDrvObj->DriverStart))
138  {
139  goto cleanup_and_exit;
140  }
141  }
142  else
143  {
144  DRIVER_OBJECT32 const *pDrvObj = (DRIVER_OBJECT32 *)pObject;
145  INTRO_PE_INFO peInfo = {0};
146 
147  if (pDrvObj->Type != DRIVER_OBJECT_TYPE)
148  {
149  goto cleanup_and_exit;
150  }
151 
152  if (pDrvObj->Size != WIN_KM_FIELD(DrvObj, Size))
153  {
154  goto cleanup_and_exit;
155  }
156 
157  if (pDrvObj->DriverStart % PAGE_SIZE != 0)
158  {
159  goto cleanup_and_exit;
160  }
161 
162  // Try to translate the driver start, in order to see if it leads to a valid address.
163  status = IntTranslateVirtualAddressEx(pDrvObj->DriverStart, gGuest.Mm.SystemCr3, TRFLG_NONE, &translation);
164  if (!INT_SUCCESS(status))
165  {
166  goto cleanup_and_exit;
167  }
168 
169  if (!(translation.Flags & PT_P))
170  {
171  goto cleanup_and_exit;
172  }
173 
174  if (translation.Flags & PT_US)
175  {
176  goto cleanup_and_exit;
177  }
178 
179  if (translation.Flags & PT_PCD)
180  {
181  // We shouldn't touch non-cacheable pages.
182  goto cleanup_and_exit;
183  }
184 
185  status = IntPhysMemMap(translation.PhysicalAddress, PAGE_SIZE, 0, &pModule);
186  if (!INT_SUCCESS(status))
187  {
188  goto cleanup_and_exit;
189  }
190 
191  status = IntPeValidateHeader(pDrvObj->DriverStart, pModule, PAGE_SIZE, &peInfo, 0);
192  if (!INT_SUCCESS(status))
193  {
194  ERROR("[ERROR] IntPeValidateHeader failed: 0x%08x\n", status);
195  goto cleanup_and_exit;
196  }
197 
198  if (peInfo.SizeOfImage != pDrvObj->DriverSize)
199  {
200  goto cleanup_and_exit;
201  }
202 
203  if (peInfo.EntryPoint != (pDrvObj->DriverInit - pDrvObj->DriverStart))
204  {
205  goto cleanup_and_exit;
206  }
207  }
208 
209  valid = TRUE;
210 
211 cleanup_and_exit:
212  if (NULL != pObject)
213  {
214  IntVirtMemUnmap(&pObject);
215  }
216 
217  if (NULL != pModule)
218  {
219  IntPhysMemUnmap(&pModule);
220  }
221 
222  return valid;
223 }
224 
225 
226 INTSTATUS
228  _In_ QWORD GuestAddress,
229  _In_ BOOLEAN StaticDetected,
230  _Out_opt_ PWIN_DRIVER_OBJECT *DriverObject
231  )
250 {
251  PWIN_DRIVER_OBJECT pDrvObj;
252  KERNEL_DRIVER *pKm;
253  INTSTATUS status;
254  DWORD driverNameLen;
255  QWORD driverNameAddress;
256 
257  driverNameAddress = 0;
258  driverNameLen = 0;
259 
260  pDrvObj = IntWinDrvObjFindByDrvObj(GuestAddress);
261  if (pDrvObj)
262  {
263  WARNING("[WARNING] Driver object at 0x%016llx is already present as \"%s\", will ignore\n",
264  GuestAddress, utf16_for_log(pDrvObj->Name));
265  if (NULL != DriverObject)
266  {
267  *DriverObject = pDrvObj;
268  }
270  }
271 
272  pDrvObj = HpAllocWithTag(sizeof(*pDrvObj), IC_TAG_DOBJ);
273  if (NULL == pDrvObj)
274  {
276  }
277 
278  // Start filling in driver object info.
279  pDrvObj->DriverObjectGva = GuestAddress;
280  pDrvObj->Aligned = !StaticDetected;
281 
282  status = IntTranslateVirtualAddress(GuestAddress, gGuest.Mm.SystemCr3, &pDrvObj->DriverObjectGpa);
283  if (!INT_SUCCESS(status))
284  {
285  ERROR("[ERROR] Failed translating GVA 0x%016llx: 0x%08x\n", GuestAddress, status);
286  pDrvObj->DriverObjectGpa = 0;
287  }
288 
289  // Read the driver name length
290  if (!gGuest.Guest64)
291  {
292  status = IntKernVirtMemFetchDword(GuestAddress + OFFSET_OF(DRIVER_OBJECT32,
293  DriverName.Length), &driverNameLen);
294  }
295  else
296  {
297  status = IntKernVirtMemFetchDword(GuestAddress + OFFSET_OF(DRIVER_OBJECT64,
298  DriverName.Length), &driverNameLen);
299  }
300  if (!INT_SUCCESS(status))
301  {
302  goto cleanup_and_exit;
303  }
304 
305  // Read the driver name address
306  if (!gGuest.Guest64)
307  {
308  status = IntKernVirtMemFetchWordSize(GuestAddress + OFFSET_OF(DRIVER_OBJECT32,
309  DriverName.Buffer), &driverNameAddress);
310  }
311  else
312  {
313  status = IntKernVirtMemFetchWordSize(GuestAddress + OFFSET_OF(DRIVER_OBJECT64,
314  DriverName.Buffer), &driverNameAddress);
315  }
316  if (!INT_SUCCESS(status))
317  {
318  goto cleanup_and_exit;
319  }
320 
321  driverNameLen = (driverNameLen & 0xFFFF);
322 
323  // Validate driver name length.
324  if ((driverNameLen < 2) || (driverNameLen >= 256))
325  {
326  // To small or to long, we ignore it.
327  goto cleanup_and_exit;
328  }
329 
330  // driverNameLen + 2 OK - we just checked above to see if its below 256.
331  pDrvObj->Name = HpAllocWithTag(driverNameLen + 2ull, IC_TAG_DRNU);
332  if (NULL == pDrvObj->Name)
333  {
335  goto cleanup_and_exit;
336  }
337 
338  // Read the driver name
339  status = IntKernVirtMemRead(driverNameAddress, driverNameLen, pDrvObj->Name, NULL);
340  if (!INT_SUCCESS(status))
341  {
342  ERROR("[ERROR] Failed reading the driver name: 0x%08x\n", status);
343  goto cleanup_and_exit;
344  }
345 
346  pDrvObj->NameLen = driverNameLen / 2;
347 
348  // Lowercase the name
349  strlower_utf16(pDrvObj->Name, pDrvObj->NameLen);
350 
351  // Helps us on exceptions
352  pDrvObj->NameHash = Crc32Wstring(pDrvObj->Name, INITIAL_CRC_VALUE);
353 
354  // Read the owner driver
355  if (!gGuest.Guest64)
356  {
357  pDrvObj->Owner = 0;
358  status = IntKernVirtMemFetchWordSize(GuestAddress + OFFSET_OF(DRIVER_OBJECT32, DriverStart), &pDrvObj->Owner);
359  }
360  else
361  {
362  status = IntKernVirtMemFetchWordSize(GuestAddress + OFFSET_OF(DRIVER_OBJECT64, DriverStart), &pDrvObj->Owner);
363  }
364  if (!INT_SUCCESS(status))
365  {
366  ERROR("[ERROR] Failed reading the driver start: 0x%08x\n", status);
367  goto cleanup_and_exit;
368  }
369 
370  // Now get the pointer to the fast I/O dispatch table, if any.
371  if (!gGuest.Guest64)
372  {
373  pDrvObj->FastIOTableAddress = 0;
374  status = IntKernVirtMemFetchWordSize(GuestAddress + OFFSET_OF(DRIVER_OBJECT32, FastIoDispatch),
375  &pDrvObj->FastIOTableAddress);
376  }
377  else
378  {
379  status = IntKernVirtMemFetchWordSize(GuestAddress + OFFSET_OF(DRIVER_OBJECT64, FastIoDispatch),
380  &pDrvObj->FastIOTableAddress);
381  }
382  if (!INT_SUCCESS(status))
383  {
384  ERROR("[ERROR] IntKernVirtMemFetchQword failed: 0x%08x\n", status);
385  }
386 
387  pKm = IntDriverFindByAddress(pDrvObj->Owner);
388  if (NULL != pKm)
389  {
390  pKm->Win.DriverObject = pDrvObj;
391  }
392 
393  InsertTailList(&gWinDriverObjects, &pDrvObj->Link);
394 
395  // Once the object is allocated and added to the list, we can activate protection on it.
396  if (IntWinDrvObjIsProtected(pDrvObj))
397  {
398  // Protect the driver object, together with the fast I/O dispatch table.
399  status = IntWinDrvObjProtect(pDrvObj);
400  if (!INT_SUCCESS(status))
401  {
402  ERROR("[ERROR] IntWinHookDriverObject failed: 0x%08x\n", status);
403  }
404  }
405 
406  status = INT_STATUS_SUCCESS;
407 
408 cleanup_and_exit:
409  if (!INT_SUCCESS(status))
410  {
411  IntWinDrvObjRemove(pDrvObj);
412  }
413 
414  if (NULL != DriverObject)
415  {
416  *DriverObject = pDrvObj;
417  }
418 
419  return status;
420 }
421 
422 
425  _In_ QWORD Gva
426  )
434 {
435  LIST_ENTRY *list = gWinDriverObjects.Flink;
436  while (list != &gWinDriverObjects)
437  {
439 
440  if (pDrvObj->DriverObjectGva == Gva)
441  {
442  return pDrvObj;
443  }
444 
445  list = list->Flink;
446  }
447 
448  return NULL;
449 }
450 
451 
454  _In_ QWORD Owner
455  )
463 {
464  LIST_ENTRY *list = gWinDriverObjects.Flink;
465  while (list != &gWinDriverObjects)
466  {
468 
469  if (pDrvObj->Owner == Owner)
470  {
471  return pDrvObj;
472  }
473 
474  list = list->Flink;
475  }
476 
477  return NULL;
478 }
479 
480 
481 static INTSTATUS
483  _In_ EXCEPTION_VICTIM_ZONE const *Victim,
484  _In_ EXCEPTION_KM_ORIGINATOR const *Originator,
485  _In_ INTRO_ACTION Action,
487  )
498 {
499  INTSTATUS status;
500  PEVENT_EPT_VIOLATION pEptViol;
501  IG_ARCH_REGS const *regs;
502 
503  regs = &gVcpu->Regs;
504 
505  pEptViol = &gAlert.Ept;
506  memzero(pEptViol, sizeof(*pEptViol));
507 
508  pEptViol->Header.Action = Action;
509  pEptViol->Header.Reason = Reason;
510  pEptViol->Header.MitreID = idRootkit;
511 
513 
515 
516  IntAlertEptFillFromKmOriginator(Originator, pEptViol);
517  IntAlertEptFillFromVictimZone(Victim, pEptViol);
518 
520 
521  IntAlertFillCodeBlocks(Originator->Original.Rip, regs->Cr3, FALSE, &pEptViol->CodeBlocks);
522  IntAlertFillExecContext(0, &pEptViol->ExecContext);
523 
524  IntAlertFillVersionInfo(&pEptViol->Header);
525 
526  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
527  if (!INT_SUCCESS(status))
528  {
529  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
530  }
531 
532  return status;
533 }
534 
535 
536 static INTSTATUS
538  _In_ EXCEPTION_VICTIM_ZONE const *Victim,
539  _In_ EXCEPTION_KM_ORIGINATOR const *Originator,
540  _In_ INTRO_ACTION Action,
542  )
553 {
554  INTSTATUS status;
556 
557  pIntViol = &gAlert.Integrity;
558  memzero(pIntViol, sizeof(*pIntViol));
559 
560  pIntViol->BaseAddress = Victim->Integrity.StartVirtualAddress;
561  pIntViol->VirtualAddress = Victim->Integrity.StartVirtualAddress + Victim->Integrity.Offset;
562  pIntViol->Victim.Type = Victim->Object.Type;
563  pIntViol->Size = Victim->Integrity.TotalLength;
564 
565  // we can't know from what CPU the write was, but we know where the integrity check failed
566  pIntViol->Header.CpuContext.Valid = FALSE;
567 
569  pIntViol->Header.Flags |= ALERT_FLAG_ASYNC;
570 
571  pIntViol->Header.Action = Action;
572  pIntViol->Header.Reason = Reason;
573  pIntViol->Header.MitreID = idRootkit;
574 
575  memcpy(pIntViol->Victim.Name, VICTIM_DRIVER_OBJECT, sizeof(VICTIM_DRIVER_OBJECT));
576 
577  IntAlertFillWriteInfo(Victim, &pIntViol->WriteInfo);
578 
579  IntAlertFillWinKmModule(Originator->Original.Driver, &pIntViol->Originator.Module);
580 
581  IntAlertFillDriverObject((PWIN_DRIVER_OBJECT)Victim->Object.DriverObject, &pIntViol->Victim.DriverObject);
582 
584 
586 
587  IntAlertFillVersionInfo(&pIntViol->Header);
588 
589  status = IntNotifyIntroEvent(introEventIntegrityViolation, pIntViol, sizeof(*pIntViol));
590  if (!INT_SUCCESS(status))
591  {
592  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
593  }
594 
595  return INT_STATUS_SUCCESS;
596 }
597 
598 
599 static INTSTATUS
601  _Inout_ WIN_DRIVER_OBJECT *Context,
602  _In_ HOOK_GPA const *Hook,
603  _In_ QWORD Address,
604  _Out_ INTRO_ACTION *Action
605  )
627 {
628  INTSTATUS status;
629  EXCEPTION_VICTIM_ZONE victim;
630  EXCEPTION_KM_ORIGINATOR originator;
631 
632  WIN_DRIVER_OBJECT *pDrvObj = Context;
633  HOOK_GVA const *pGva = Hook->Header.ParentHook;
634  QWORD gva = pGva->GvaPage + (Address & PAGE_OFFSET);
635  OPERAND_VALUE writtenValue = {0};
636 
637  BOOLEAN exitAfterInformation = FALSE;
638  BOOLEAN fastIoPtrWritten = FALSE;
639  BOOLEAN fastIoWrite = FALSE;
640  BOOLEAN fastIoUpdated = FALSE;
641  QWORD gpa;
642  KERNEL_DRIVER *pKm;
643 
645 
646  IG_ARCH_REGS *regs = &gVcpu->Regs;
647  INSTRUX *pInstrux = &gVcpu->Instruction;
648 
649  // Check to see if the Fast I/O dispatch pointer is being written. If it is, hook the new
650  // Fast I/O dispatch table.
651  if (gGuest.Guest64)
652  {
653  if ((gva >= pDrvObj->DriverObjectGva + OFFSET_OF(DRIVER_OBJECT64, FastIoDispatch)) &&
654  (gva < pDrvObj->DriverObjectGva + OFFSET_OF(DRIVER_OBJECT64, FastIoDispatch) + 8))
655  {
656  fastIoPtrWritten = TRUE;
657  }
658  }
659  else
660  {
661  if ((gva >= pDrvObj->DriverObjectGva + OFFSET_OF(DRIVER_OBJECT32, FastIoDispatch)) &&
662  (gva < pDrvObj->DriverObjectGva + OFFSET_OF(DRIVER_OBJECT32, FastIoDispatch) + 4))
663  {
664  fastIoPtrWritten = TRUE;
665  }
666  }
667 
668  if (fastIoPtrWritten)
669  {
670  status = IntDecGetWrittenValueFromInstruction(pInstrux, regs, NULL, &writtenValue);
671  if (!INT_SUCCESS(status))
672  {
673  ERROR("[ERROR] IntDecGetWrittenValueFromInstruction failed: 0x%08x\n", status);
674 
676 
677  goto cleanup_and_exit;
678  }
679 
680  if ((0 != writtenValue.Value.QwordValues[0]) &&
682  {
683  ERROR("[ERROR] [DRVOBJ] Fast I/O dispatch table of driver object '%s' not in kernel: 0x%016llx\n",
684  utf16_for_log(pDrvObj->Name), writtenValue.Value.QwordValues[0]);
685 
686  status = INT_STATUS_NOT_SUPPORTED;
687 
688  goto cleanup_and_exit;
689  }
690 
691  if (pDrvObj->FastIOTableAddress != 0)
692  {
693  goto _block_fastio_reloc;
694  }
695 
696  TRACE("[DRVOBJ] Fast I/O dispatch table of driver object '%s' has been written: 0x%016llx\n",
697  utf16_for_log(pDrvObj->Name), writtenValue.Value.QwordValues[0]);
698 
699  status = IntWinDrvObjUnprotectFastIoDispatch(pDrvObj);
700  if (!INT_SUCCESS(status))
701  {
702  ERROR("[ERROR] IntWinDrvObjUnprotectFastIoDispatch failed: 0x%08x\n", status);
703  }
704 
705  // Update new entry.
706  pDrvObj->FastIOTableAddress = writtenValue.Value.QwordValues[0];
707 
708  if (0 != pDrvObj->FastIOTableAddress)
709  {
710  status = IntWinDrvObjProtectFastIoDispatch(pDrvObj);
711  if (!INT_SUCCESS(status))
712  {
713  ERROR("[ERROR] IntWinDrvObjHookFastIODispatch failed: 0x%08x\n", status);
714  }
715  }
716 
717  *Action = introGuestAllowed;
718 
719  status = INT_STATUS_SUCCESS;
720 
721  fastIoUpdated = TRUE;
722 
723  goto cleanup_and_exit;
724  }
725 
726 _block_fastio_reloc:
728 
730  if (!INT_SUCCESS(status))
731  {
732  WARNING("[WARNING] IntTranslateVirtualAddress failed: 0x%08x\n", status);
733  }
734  else if (gpa != pDrvObj->DriverObjectGpa)
735  {
736  WARNING("[WARNING] The driver object Gpa 0x%016llx is different from actual Gpa 0x%016llx!\n",
737  pDrvObj->DriverObjectGpa, gpa);
738  pDrvObj->DriverObjectGpa = gpa;
739  }
740 
741  pKm = IntDriverFindByAddress(pDrvObj->Owner);
742  if (NULL != pKm && NULL == pKm->Win.DriverObject)
743  {
744  pKm->Win.DriverObject = pDrvObj;
745  }
746 
747  memzero(&victim, sizeof(victim));
748  memzero(&originator, sizeof(originator));
749 
750  // By default we do not allow this
751  *Action = introGuestNotAllowed;
752  reason = introReasonUnknown;
753  exitAfterInformation = FALSE;
754 
755  if (pDrvObj->FastIOTableAddress &&
756  gva >= pDrvObj->FastIOTableAddress &&
757  gva < pDrvObj->FastIOTableAddress + WIN_KM_FIELD(DrvObj, FiodispSize))
758  {
759  fastIoWrite = TRUE;
760  }
761 
762  status = IntExceptKernelGetOriginator(&originator, 0);
763  if (INT_STATUS_EXCEPTION_BLOCK == status)
764  {
765  reason = introReasonNoException;
766  exitAfterInformation = TRUE;
767  }
768  else if (!INT_SUCCESS(status))
769  {
770  reason = introReasonInternalError;
771  exitAfterInformation = TRUE;
772  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
773  }
774 
775  status = IntExceptGetVictimEpt(pDrvObj,
776  Address,
777  gva,
779  ZONE_WRITE,
780  &victim);
781  if (!INT_SUCCESS(status))
782  {
783  reason = introReasonInternalError;
784  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
785  exitAfterInformation = TRUE;
786  }
787 
788  if (exitAfterInformation)
789  {
790  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
791  }
792  else
793  {
794  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
795  }
796 
798 
800  {
801  IntWinDrvObjSendEptAlert(&victim, &originator, *Action, reason);
802  }
803 
804 cleanup_and_exit:
806 
807  if (*Action == introGuestAllowed &&
808  !fastIoUpdated &&
809  fastIoPtrWritten)
810  {
811  status = IntWinDrvObjUnprotectFastIoDispatch(pDrvObj);
812  if (!INT_SUCCESS(status))
813  {
814  ERROR("[ERROR] IntWinDrvObjUnprotectFastIoDispatch failed with status: 0x%08x\n", status);
815  return status;
816  }
817 
818  pDrvObj->FastIOTableAddress = gGuest.Guest64 ? writtenValue.Value.QwordValues[0] :
819  writtenValue.Value.DwordValues[0];
820 
821  if (pDrvObj->FastIOTableAddress != 0)
822  {
823  status = IntWinDrvObjProtectFastIoDispatch(pDrvObj);
824  if (!INT_SUCCESS(status))
825  {
826  ERROR("[ERROR] IntWinDrvObjUnprotectFastIoDispatch failed with status: 0x%08x\n", status);
827  return status;
828  }
829  }
830  }
831 
832  return status;
833 }
834 
835 
836 static INTSTATUS
838  _Inout_ INTEGRITY_REGION *IntegrityRegion
839  )
850 {
851 #define NAMEHASH_FLTMGR 0x4283398b
852  EXCEPTION_VICTIM_ZONE victim;
853  EXCEPTION_KM_ORIGINATOR originator;
854  INTSTATUS status;
855  DWORD offset;
856  BOOLEAN recalculate = FALSE;
857 
858  if (IntegrityRegion->Type != introObjectTypeDriverObject &&
859  IntegrityRegion->Type != introObjectTypeFastIoDispatch)
860  {
861  ERROR("[ERROR] Invalid integrity region type: %d\n", IntegrityRegion->Type);
863  }
864 
866 
867  offset = 0;
868  status = INT_STATUS_SUCCESS;
869 
870  while (offset < IntegrityRegion->Length)
871  {
874  const QWORD fioDispOffset = WIN_KM_FIELD(DrvObj, Fiodisp);
875 
876  memzero(&victim, sizeof(victim));
877  memzero(&originator, sizeof(originator));
878 
879  status = IntExceptGetVictimIntegrity(IntegrityRegion, &offset, &victim);
880  if (status == INT_STATUS_NOT_FOUND)
881  {
882  // We are done with the modifications, so exit
883  status = INT_STATUS_SUCCESS;
884  break;
885  }
886  else if (!INT_SUCCESS(status))
887  {
888  ERROR("[ERROR] Failed getting integrity zone: 0x%08x\n", status);
889  break;
890  }
891 
892  status = IntExceptGetOriginatorFromModification(&victim, &originator);
893  if (status == INT_STATUS_EXCEPTION_ALLOW)
894  {
895  // In case of something that can't be excepted (like the size field, etc.)
896  action = introGuestAllowed;
897  goto _do_action;
898  }
899  else if (status == INT_STATUS_EXCEPTION_BLOCK)
900  {
901  // Or something that it's wrong (like the size filed being too big, etc.)
902  status = INT_STATUS_SUCCESS;
903  reason = introReasonInternalError;
904 
905  IntExceptKernelLogInformation(&victim, &originator, action, reason);
906 
907  goto _do_action;
908  }
909  else if (!INT_SUCCESS(status))
910  {
911  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
912  break;
913  }
914 
915  if (((gGuest.Guest64 &&
916  victim.Integrity.Offset + fioDispOffset == OFFSET_OF(DRIVER_OBJECT64, DriverUnload)) ||
917  (!gGuest.Guest64 &&
918  victim.Integrity.Offset + fioDispOffset == OFFSET_OF(DRIVER_OBJECT32, DriverUnload))) &&
919  (originator.Original.NameHash == NAMEHASH_FLTMGR))
920  {
921  action = introGuestAllowed;
922  goto _do_action;
923  }
924 
925  IntExcept(&victim, &originator, exceptionTypeKm, &action, &reason, introEventIntegrityViolation);
926 
927 _do_action:
928  if (IntPolicyCoreTakeAction(INTRO_OPT_PROT_KM_DRVOBJ, &action, &reason))
929  {
930  IntWinDrvObjSendIntegrityAlert(&victim, &originator, action, reason);
931  }
932 
934 
935  if (action == introGuestAllowed)
936  {
937  recalculate = TRUE;
938 
939  if (IntegrityRegion->Type == introObjectTypeDriverObject && victim.Integrity.Offset == 0)
940  {
941  WIN_DRIVER_OBJECT *pDrvObj = victim.Object.DriverObject;
942 
943  status = IntWinDrvObjUnprotectFastIoDispatch(pDrvObj);
944  if (!INT_SUCCESS(status))
945  {
946  ERROR("[ERROR] IntWinDrvObjUnprotectFastIoDispatch failed with status: 0x%08x\n", status);
947  goto _cleanup_and_exit;
948  }
949 
950  if (gGuest.Guest64)
951  {
952  pDrvObj->FastIOTableAddress = victim.WriteInfo.NewValue[0];
953  }
954  else
955  {
956  pDrvObj->FastIOTableAddress = (DWORD)(victim.WriteInfo.NewValue[0]);
957  }
958 
959  if (pDrvObj->FastIOTableAddress != 0)
960  {
961  status = IntWinDrvObjProtectFastIoDispatch(pDrvObj);
962  if (!INT_SUCCESS(status))
963  {
964  ERROR("[ERROR] IntWinDrvObjUnprotectFastIoDispatch failed with status: 0x%08x\n", status);
965  goto _cleanup_and_exit;
966  }
967  }
968  }
969  }
970  else if (action == introGuestNotAllowed)
971  {
972  QWORD original = 0;
973 
974  if (gGuest.Guest64)
975  {
976  original = *(QWORD *)((PBYTE)IntegrityRegion->OriginalContent + victim.Integrity.Offset);
977  }
978  else
979  {
980  original = *(DWORD *)((PBYTE)IntegrityRegion->OriginalContent + victim.Integrity.Offset);
981  }
982 
983  IntPauseVcpus();
984 
985  // No need to use IntVirtMemSafeWrite, as this is a protected region.
986  status = IntKernVirtMemWrite(IntegrityRegion->Gva + victim.Integrity.Offset, gGuest.WordSize, &original);
987 
988  IntResumeVcpus();
989 
990  if (!INT_SUCCESS(status))
991  {
992  ERROR("[ERROR] IntKernVirtMemWrite failed for gva 0x%016llx: 0x%08x\n",
993  IntegrityRegion->Gva + victim.Integrity.Offset, status);
994  goto _cleanup_and_exit;
995  }
996  }
997  }
998 
999  if (recalculate)
1000  {
1001  IntIntegrityRecalculate(IntegrityRegion);
1002  }
1003 
1004 _cleanup_and_exit:
1006 
1007  return status;
1008 
1009 #undef NAMEHASH_FLTMGR
1010 }
1011 
1012 
1013 static INTSTATUS
1015  _Inout_ WIN_DRIVER_OBJECT *DriverObject
1016  )
1025 {
1026  INTSTATUS status;
1027 
1028  if (!DriverObject->FiodispProtected)
1029  {
1031  }
1032 
1033  TRACE("[DRVOBJ] Removing protection on Fast I/OP dispatch on driver object '%s' at %llx...\n",
1034  utf16_for_log(DriverObject->Name), DriverObject->FastIOTableAddress);
1035 
1036  if (DriverObject->FiodispIntegrityObject != NULL)
1037  {
1038  status = IntIntegrityRemoveRegion(DriverObject->FiodispIntegrityObject);
1039  if (!INT_SUCCESS(status))
1040  {
1041  ERROR("[ERROR] Failed removing the integrity region from structure at address 0x%016llx: 0x%08x\n",
1042  DriverObject->FastIOTableAddress, status);
1043  }
1044  DriverObject->FiodispIntegrityObject = NULL;
1045  }
1046 
1047  DriverObject->FiodispProtected = FALSE;
1048 
1049  return INT_STATUS_SUCCESS;
1050 }
1051 
1052 
1053 static INTSTATUS
1055  _Inout_ WIN_DRIVER_OBJECT *DriverObject
1056  )
1069 {
1070  INTSTATUS status;
1071 
1072  if (0 == DriverObject->FastIOTableAddress)
1073  {
1075  }
1076 
1077  TRACE("[DRVOBJ] Adding protection on Fast I/O dispatch for driver object '%s' at 0x%016llx (integrity)\n",
1078  utf16_for_log(DriverObject->Name), DriverObject->FastIOTableAddress);
1079 
1080  status = IntIntegrityAddRegion(DriverObject->FastIOTableAddress,
1081  WIN_KM_FIELD(DrvObj, FiodispSize),
1083  DriverObject,
1085  TRUE,
1086  &DriverObject->FiodispIntegrityObject);
1087  if (!INT_SUCCESS(status))
1088  {
1089  ERROR("[ERROR] IntIntegrityAddRegion failed: 0x%08x\n", status);
1090  return status;
1091  }
1092 
1093  DriverObject->FiodispProtected = TRUE;
1094 
1095  return INT_STATUS_SUCCESS;
1096 }
1097 
1098 
1099 INTSTATUS
1101  _Inout_ WIN_DRIVER_OBJECT *DriverObject
1102  )
1114 {
1115  INTSTATUS status;
1116 
1117  if (NULL == DriverObject)
1118  {
1120  }
1121 
1122  if (!DriverObject->DrvobjProtected)
1123  {
1125  }
1126 
1127  TRACE("[DRVOBJ] Removing protection on driver object '%s' at %llx...\n",
1128  utf16_for_log(DriverObject->Name), DriverObject->DriverObjectGva);
1129 
1130  status = IntWinDrvObjUnprotectFastIoDispatch(DriverObject);
1131  if (!INT_SUCCESS(status))
1132  {
1133  ERROR("[ERROR] IntWinDrvObjFiodispUnHook failed: 0x%08x\n", status);
1134  }
1135 
1136  if (DriverObject->DrvobjIntegrityObject != NULL)
1137  {
1138  status = IntIntegrityRemoveRegion(DriverObject->DrvobjIntegrityObject);
1139  if (!INT_SUCCESS(status))
1140  {
1141  ERROR("[ERROR] Failed removing the integrity region from structure at address 0x%016llx: 0x%08x\n",
1142  DriverObject->DriverObjectGva, status);
1143  }
1144  DriverObject->DrvobjIntegrityObject = NULL;
1145  }
1146 
1147  if (DriverObject->DrvobjHookObject != NULL)
1148  {
1149  status = IntHookObjectDestroy((HOOK_OBJECT_DESCRIPTOR **)&DriverObject->DrvobjHookObject, 0);
1150  if (!INT_SUCCESS(status))
1151  {
1152  ERROR("[ERROR] Failed removing the hook from structure at address 0x%016llx: 0x%08x\n",
1153  DriverObject->FastIOTableAddress, status);
1154  }
1155  }
1156 
1157  DriverObject->DrvobjProtected = FALSE;
1158 
1159  return INT_STATUS_SUCCESS;
1160 }
1161 
1162 
1163 INTSTATUS
1165  _Inout_ WIN_DRIVER_OBJECT *DriverObject
1166  )
1178 {
1179  INTSTATUS status;
1180 
1181  if (DriverObject == NULL)
1182  {
1184  }
1185 
1186  status = IntWinDrvObjProtectFastIoDispatch(DriverObject);
1187  if (!INT_SUCCESS(status))
1188  {
1189  ERROR("[ERROR] IntWinHookFastIODispatch failed: 0x%08x\n", status);
1190  }
1191 
1192  // If the protection is already activated, then we can hook the driver object since the pool size is a whole page
1193  if (!DriverObject->Aligned)
1194  {
1195  TRACE("[DRVOBJ] Adding protection on driver object '%s' at %llx (integrity)...\n",
1196  utf16_for_log(DriverObject->Name), DriverObject->DriverObjectGva);
1197 
1198  status = IntIntegrityAddRegion(DriverObject->DriverObjectGva + WIN_KM_FIELD(DrvObj, Fiodisp),
1199  WIN_KM_FIELD(DrvObj, Size) - WIN_KM_FIELD(DrvObj, Fiodisp),
1201  DriverObject,
1203  TRUE,
1204  &DriverObject->DrvobjIntegrityObject);
1205  if (!INT_SUCCESS(status))
1206  {
1207  ERROR("[ERROR] IntIntegrityAddRegion failed: 0x%08x\n", status);
1208  return status;
1209  }
1210  }
1211  else
1212  {
1213  TRACE("[DRVOBJ] Adding protection on driver object '%s' at %llx (ept)...\n",
1214  utf16_for_log(DriverObject->Name), DriverObject->DriverObjectGva);
1215 
1216  status = IntHookObjectCreate(introObjectTypeDriverObject, 0, &DriverObject->DrvobjHookObject);
1217  if (!INT_SUCCESS(status))
1218  {
1219  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
1220  return status;
1221  }
1222 
1223  status = IntHookObjectHookRegion(DriverObject->DrvobjHookObject,
1224  0,
1225  DriverObject->DriverObjectGva + WIN_KM_FIELD(DrvObj, Fiodisp),
1226  WIN_KM_FIELD(DrvObj, Size) - WIN_KM_FIELD(DrvObj, Fiodisp),
1229  DriverObject,
1230  0,
1231  NULL);
1232  if (!INT_SUCCESS(status))
1233  {
1234  ERROR("[ERROR] IntHookObjectHookRegion failed: 0x%08x\n", status);
1235  return status;
1236  }
1237  }
1238 
1239  DriverObject->DrvobjProtected = TRUE;
1240 
1241  return INT_STATUS_SUCCESS;
1242 }
1243 
1244 
1245 INTSTATUS
1247  _In_ QWORD DriverObjectAddress
1248  )
1257 {
1258  INTSTATUS status;
1259  LIST_ENTRY *list;
1260  BOOLEAN bFound;
1261  QWORD drvObjGpa;
1262 
1263  bFound = FALSE;
1264 
1265  status = IntTranslateVirtualAddress(DriverObjectAddress, gGuest.Mm.SystemCr3, &drvObjGpa);
1266  if (!INT_SUCCESS(status))
1267  {
1268  ERROR("[ERROR] IntTranslateVirtualAddress failed for GVA 0x%016llx: 0x%08x\n", DriverObjectAddress, status);
1269  drvObjGpa = 0;
1270  }
1271 
1272  list = gWinDriverObjects.Flink;
1273  while (list != &gWinDriverObjects)
1274  {
1276  list = list->Flink;
1277 
1278  // Search the driver corresponding to this pool
1279  if ((drvObjGpa != 0 && drvObjGpa + WIN_KM_FIELD(DrvObj, AllocationGap) == drvObj->DriverObjectGpa) ||
1280  (DriverObjectAddress + WIN_KM_FIELD(DrvObj, AllocationGap) == drvObj->DriverObjectGva))
1281 
1282  {
1283  TRACE("[DRVOBJ] Removing driver object at 0x%016llx\n", drvObj->DriverObjectGva);
1284 
1285  RemoveEntryList(&drvObj->Link);
1286 
1287  status = IntWinDrvObjRemove(drvObj);
1288  if (!INT_SUCCESS(status))
1289  {
1290  ERROR("[ERROR] IntWinDrvObjRemoveDriverObject failed: 0x%08x\n", status);
1291  }
1292 
1293  bFound = TRUE;
1294 
1295  // There can be more GVAs pointing to this gpa, so don't break!
1296  }
1297  else if (DriverObjectAddress == drvObj->FastIOTableAddress)
1298  {
1299  TRACE("[DRVOBJ] Removing Fast I/O dispatch at 0x%016llx\n", drvObj->FastIOTableAddress);
1300 
1301  status = IntWinDrvObjUnprotectFastIoDispatch(drvObj);
1302  if (!INT_SUCCESS(status))
1303  {
1304  ERROR("[ERROR] IntWinDrvObjUnprotectFastIoDispatch failed: 0x%08x\n", status);
1305  }
1306 
1307  bFound = TRUE;
1308 
1309  // If we have multiple driver objects, remove all the hooks!
1310  }
1311  }
1312 
1313  if (!bFound)
1314  {
1315  return INT_STATUS_NOT_FOUND;
1316  }
1317 
1318  return INT_STATUS_SUCCESS;
1319 }
1320 
1321 
1322 static void
1324  _Inout_ WIN_DRIVER_OBJECT *DriverObject
1325  )
1333 {
1334  if (NULL != DriverObject->Name)
1335  {
1336  HpFreeAndNullWithTag(&DriverObject->Name, IC_TAG_DRNU);
1337  }
1338 
1339  HpFreeAndNullWithTag(&DriverObject, IC_TAG_DOBJ);
1340 }
1341 
1342 
1343 INTSTATUS
1345  _Inout_ WIN_DRIVER_OBJECT *DriverObject
1346  )
1357 {
1358  KERNEL_DRIVER *pKmDriver;
1359  INTSTATUS status;
1360 
1361  if (NULL == DriverObject)
1362  {
1364  }
1365 
1366  pKmDriver = IntDriverFindByAddress(DriverObject->Owner);
1367  if (NULL != pKmDriver)
1368  {
1369  pKmDriver->Win.DriverObject = NULL;
1370  }
1371 
1372  status = IntWinDrvObjUnprotect(DriverObject);
1373  if (!INT_SUCCESS(status))
1374  {
1375  ERROR("[ERROR] IntWinDrvObjUnprotect failed: 0x%08x\n", status);
1376  }
1377 
1378  IntWinDrvObjFreeDriverObject(DriverObject);
1379 
1380  return status;
1381 }
1382 
1383 
1384 INTSTATUS
1386  void
1387  )
1393 {
1394  INTSTATUS status;
1395 
1396  TRACE("[DRVOBJ] Updating driver objects protections...\n");
1397 
1398  for (LIST_ENTRY *list = gWinDriverObjects.Flink; list != &gWinDriverObjects; list = list->Flink)
1399  {
1401  const PROTECTED_MODULE_INFO *pProtInfo;
1402 
1403  pProtInfo = IntWinDrvObjIsProtected(pDrvObj);
1404  if (!pDrvObj->DrvobjProtected && (NULL != pProtInfo))
1405  {
1406  status = IntWinDrvObjProtect(pDrvObj);
1407  if (!INT_SUCCESS(status))
1408  {
1409  ERROR("[ERROR] IntWinDrvObjProtect failed for '%s': 0x%08x\n",
1410  utf16_for_log(pDrvObj->Name), status);
1411  }
1412  }
1413  else if (pDrvObj->DrvobjProtected && (NULL == pProtInfo))
1414  {
1415  status = IntWinDrvObjUnprotect(pDrvObj);
1416  if (!INT_SUCCESS(status))
1417  {
1418  ERROR("[ERROR] IntWinDrvObjUnprotect failed for '%s': 0x%08x\n",
1419  utf16_for_log(pDrvObj->Name), status);
1420  }
1421  }
1422  }
1423 
1424  return INT_STATUS_SUCCESS;
1425 }
1426 
1427 
1428 INTSTATUS
1430  void
1431  )
1439 {
1440  INTSTATUS status;
1441 
1442  LIST_ENTRY *list = gWinDriverObjects.Flink;
1443  while (list != &gWinDriverObjects)
1444  {
1446 
1447  list = list->Flink;
1448 
1449  RemoveEntryList(&pDrvObj->Link);
1450 
1451  status = IntWinDrvObjRemove(pDrvObj);
1452  if (!INT_SUCCESS(status))
1453  {
1454  ERROR("[ERROR] IntWinDrvObjRemoveDriverObject failed: 0x%08x\n", status);
1455  }
1456  }
1457 
1458  return INT_STATUS_SUCCESS;
1459 }
Measures kernel mode exceptions checks.
Definition: stats.h:51
#define IC_TAG_DOBJ
Driver Object List Entry.
Definition: memtags.h:13
LIST_ENTRY Link
Entry inside the gWinDriverObjects list.
Definition: windrvobj.h:16
QWORD DriverObjectGva
The guest virtual address of the guest _DRIVER_OBJECT represented by this structure.
Definition: windrvobj.h:18
QWORD PhysicalAddress
The physical address to which VirtualAddress translates to.
Definition: introcore.h:107
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
INTRO_CODEBLOCKS CodeBlocks
Code blocks extracted for the alert.
Definition: intro_types.h:1263
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
#define CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
PWIN_DRIVER_OBJECT IntWinDrvObjFindByOwnerAddress(QWORD Owner)
Finds a driver object in the gWinDriverObjects list by the base of the kernel module that owns it...
Definition: windrvobj.c:453
#define INTRO_OPT_PROT_KM_DRVOBJ
Enable driver object & fast I/O dispatch protection.
Definition: intro_types.h:425
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
QWORD IntAlertCoreGetFlags(QWORD ProtectionFlag, INTRO_ACTION_REASON Reason)
Returns the flags for an alert.
Definition: alerts.c:366
const PROTECTED_MODULE_INFO * IntWinDrvObjIsProtected(const WIN_DRIVER_OBJECT *DriverObject)
Get the protected module information for a kernel driver object.
An internal error occurred (no memory, pages not present, etc.).
Definition: intro_types.h:195
BOOLEAN IntPolicyCoreForceBetaIfNeeded(QWORD Flag, INTRO_ACTION *Action)
Checks if a forced action should be taken even if the log-only mode is active.
Definition: introcore.c:2803
The _DRIVER_OBJECT structure used by 64-bit guests.
Definition: wddefs.h:255
#define OFFSET_OF(Type, Member)
Definition: introlists.h:33
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
Definition: introcore.c:699
INTSTATUS IntHookObjectDestroy(HOOK_OBJECT_DESCRIPTOR **Object, DWORD Flags)
Destroy an entire hook object. All regions belonging to this object will be removed.
Definition: hook_object.c:357
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
#define _In_
Definition: intro_sal.h:21
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1199
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
BOOLEAN IntPolicyCoreTakeAction(QWORD Flag, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Returns the action that should be taken for a core introspection option.
Definition: introcore.c:2693
Fast IO Dispatch (Windows only).
Definition: intro_types.h:236
WIN_KERNEL_DRIVER Win
Valid only for Windows guests.
Definition: drivers.h:70
static INTSTATUS IntWinDrvObjHandleWrite(WIN_DRIVER_OBJECT *Context, HOOK_GPA const *Hook, QWORD Address, INTRO_ACTION *Action)
Handles writes done over a protected driver object.
Definition: windrvobj.c:600
#define STATS_EXIT(id)
Definition: stats.h:160
Event structure for integrity violations on monitored structures.
Definition: intro_types.h:1572
INTSTATUS IntIntegrityAddRegion(QWORD VirtualAddress, DWORD Length, INTRO_OBJECT_TYPE Type, void *Context, PFUNC_IntegrityViolationCallback Callback, BOOLEAN CopyContent, void **Descriptor)
Creates an INTEGRITY_REGION object and adds it to the gIntegrityRegions list.
Definition: integrity.c:91
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define DRIVER_OBJECT_TYPE
The type of a _DRIVER_OBJECT structure.
Definition: wddefs.h:37
#define PT_PCD
Definition: pgtable.h:87
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
Definition: introcore.c:2355
INTRO_OBJECT_TYPE Type
Definition: intro_types.h:1589
Exposes the types, constants and functions used to describe protected Windows Kernel modules and driv...
#define PAGE_OFFSET
Definition: pgtable.h:32
struct _EVENT_INTEGRITY_VIOLATION::@304 Victim
#define PT_US
Definition: pgtable.h:85
QWORD DriverInit
Definition: wddefs.h:269
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
INTSTATUS IntWinDrvObjProtect(WIN_DRIVER_OBJECT *DriverObject)
Protects a driver object and its fast IO dispatch table, if one exists.
Definition: windrvobj.c:1164
#define ALERT_FLAG_ASYNC
If set, the alert was generated in an async manner.
Definition: intro_types.h:675
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
INTSTATUS IntKernVirtMemFetchWordSize(QWORD GuestVirtualAddress, void *Data)
Reads a guest pointer from the guest kernel memory.
Definition: introcore.c:847
INTSTATUS IntWinDrvObjUnprotect(WIN_DRIVER_OBJECT *DriverObject)
Deactivates protection for a driver object and its fast IO dispatch structure.
Definition: windrvobj.c:1100
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD GvaPage
Guest virtual page base address, aligned to 4K.
Definition: hook_gva.h:32
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
DWORD Offset
The offset of the modification.
Definition: exceptions.h:803
#define TRFLG_NONE
No special options.
Definition: introcore.h:82
Rootkit.
Definition: intro_types.h:1144
Describes a kernel-mode originator.
Definition: exceptions.h:943
INTSTATUS IntWinDrvObjUninit(void)
Removes all the driver objects in the gWinDriverObjects.
Definition: windrvobj.c:1429
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
Definition: introcore.c:2320
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
Definition: alerts.c:492
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
Definition: guests.h:88
EVENT_EPT_VIOLATION Ept
Definition: alerts.h:16
DWORD DriverSize
Definition: wddefs.h:240
Describes a kernel driver.
Definition: drivers.h:30
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
BOOLEAN IntWinDrvObjIsValidDriverObject(QWORD DriverObjectAddress)
Checks if a guest memory area contains a valid _DRIVER_OBJECT structure.
Definition: windrvobj.c:28
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1217
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
EXCEPTION_VICTIM_OBJECT Object
The modified object.
Definition: exceptions.h:895
The _DRIVER_OBJECT structure used by 32-bit guests.
Definition: wddefs.h:233
INTSTATUS IntAlertFillCodeBlocks(QWORD Rip, QWORD Cr3, BOOLEAN Execute, INTRO_CODEBLOCKS *CodeBlocks)
Fills the code blocks pattern for an alert.
Definition: alerts.c:71
void IntAlertEptFillFromKmOriginator(const EXCEPTION_KM_ORIGINATOR *Originator, EVENT_EPT_VIOLATION *EptViolation)
Fills kernel mode originator information inside an EPT alert.
Definition: alerts.c:832
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
#define _Inout_
Definition: intro_sal.h:20
INTSTATUS IntIntegrityRecalculate(INTEGRITY_REGION *IntegrityRegion)
Recalculates the hash and reads the original content again for a given region.
Definition: integrity.c:242
static INTSTATUS IntWinDrvObjSendEptAlert(EXCEPTION_VICTIM_ZONE const *Victim, EXCEPTION_KM_ORIGINATOR const *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Sends an introEventEptViolation alert for a protected driver object.
Definition: windrvobj.c:482
QWORD Flags
The entry that maps VirtualAddress to PhysicalAddress, together with all the control bits...
Definition: introcore.h:119
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
Definition: introcore.c:829
static LIST_HEAD gWinDriverObjects
List of all the loaded Windows driver objects.
Definition: windrvobj.c:14
void IntAlertFillWriteInfo(const EXCEPTION_VICTIM_ZONE *Victim, INTRO_WRITE_INFO *WriteInfo)
Fills the write information for an alert.
Definition: alerts.c:521
#define _Out_opt_
Definition: intro_sal.h:30
#define INITIAL_CRC_VALUE
Definition: introdefs.h:221
#define INT_STATUS_EXCEPTION_BLOCK
Definition: introstatus.h:421
DWORD Size
The size of the modified memory area.
Definition: intro_types.h:1618
Describes an operand value.
Definition: decoder.h:50
static void IntWinDrvObjFreeDriverObject(WIN_DRIVER_OBJECT *DriverObject)
Frees a driver object.
Definition: windrvobj.c:1323
void IntAlertEptFillFromVictimZone(const EXCEPTION_VICTIM_ZONE *Victim, EVENT_EPT_VIOLATION *EptViolation)
Fills the victim information inside an EPT alert.
Definition: alerts.c:868
QWORD FastIOTableAddress
The guest virtual address of the _FAST_IO_DISPATCH structure used by this driver object. May be 0.
Definition: windrvobj.h:27
QWORD QwordValues[ND_MAX_REGISTER_SIZE/8]
Definition: decoder.h:57
#define STATS_ENTER(id)
Definition: stats.h:153
WIN_DRIVER_OBJECT * DriverObject
Used when a driver object / fastio dispatch table is modified.
Definition: exceptions.h:870
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
Definition: intro_types.h:1196
uint8_t * PBYTE
Definition: intro_types.h:47
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Definition: glue.c:1042
INTSTATUS IntWinDrvObjUpdateProtection(void)
Updates the protection for all the driver objects in the gWinDriverObjects list.
Definition: windrvobj.c:1385
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
Holds information about a driver object.
Definition: windrvobj.h:13
#define memzero(a, s)
Definition: introcrt.h:35
#define PT_P
Definition: pgtable.h:83
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
Definition: guests.h:290
INTSTATUS IntExceptGetVictimEpt(void *Context, QWORD Gpa, QWORD Gva, INTRO_OBJECT_TYPE Type, DWORD ZoneFlags, EXCEPTION_VICTIM_ZONE *Victim)
Fills an EXCEPTION_VICTIM_ZONE with relevant information from an EPT violation.
Definition: exceptions.c:742
unsigned long long QWORD
Definition: intro_types.h:53
DWORD NameHash
Hash of the Name.
Definition: windrvobj.h:34
QWORD DriverSize
Definition: wddefs.h:263
QWORD Owner
Guest virtual address of the kernel module that owns this driver object.
Definition: windrvobj.h:38
void * ParentHook
The parent hook. For a GPA hook, for example, a GVA hook or a PagedHook will be the parent hook...
Definition: hook.h:73
#define NAMEHASH_FLTMGR
INTRO_MODULE Module
The module that modified the monitored region.
Definition: intro_types.h:1578
INTSTATUS IntWinDrvObjRemove(WIN_DRIVER_OBJECT *DriverObject)
Removes a driver object and updates its owner module.
Definition: windrvobj.c:1344
INTSTATUS IntTranslateVirtualAddress(QWORD Gva, QWORD Cr3, QWORD *PhysicalAddress)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1999
HOOK_HEADER Header
The hook header.
Definition: hook_gva.h:20
int strlower_utf16(WCHAR *buf, size_t len)
Definition: introcrt.c:28
QWORD VirtualAddress
The guest virtual address which was modified.
Definition: intro_types.h:1616
#define TRUE
Definition: intro_types.h:30
static INTSTATUS IntWinDrvObjHandleModification(INTEGRITY_REGION *IntegrityRegion)
Handles writes done over a protected driver object.
Definition: windrvobj.c:837
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1574
union _OPERAND_VALUE::@22 Value
The actual operand value.
#define IS_KERNEL_POINTER_WIN(is64, p)
Checks if a guest virtual address resides inside the Windows kernel address space.
Definition: wddefs.h:76
DWORD DriverStart
Definition: wddefs.h:239
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...
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
#define TRACE(fmt,...)
Definition: glue.h:58
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.
Kernel-mode exception.
Definition: exceptions.h:61
INTSTATUS IntWinDrvObjRemoveFromAddress(QWORD DriverObjectAddress)
Frees and removes protection for a driver object by its address.
Definition: windrvobj.c:1246
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
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
INTSTATUS IntTranslateVirtualAddressEx(QWORD Gva, QWORD Cr3, DWORD Flags, VA_TRANSLATION *Translation)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1863
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
Definition: intro_types.h:1309
#define WARNING(fmt,...)
Definition: glue.h:60
static INTSTATUS IntWinDrvObjProtectFastIoDispatch(WIN_DRIVER_OBJECT *DriverObject)
Deactivates the protection for the fast IO dispatch structure of a driver object. ...
Definition: windrvobj.c:1054
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
Definition: intro_types.h:84
#define PAGE_SIZE
Definition: common.h:70
DWORD Crc32Wstring(const WCHAR *String, DWORD InitialCrc)
Computes the CRC for a NULL-terminated wide char string.
Definition: crc32.c:226
Describes the modified zone.
Definition: exceptions.h:893
struct _EXCEPTION_VICTIM_ZONE::@58::@60 WriteInfo
#define WIN_KM_FIELD(Structure, Field)
Macro used to access kernel mode fields inside the WIN_OPAQUE_FIELDS structure.
Definition: winguest.h:740
WCHAR Name[ALERT_PATH_MAX_LEN]
NULL-terminated string with a human readable description of the modified object.
Definition: intro_types.h:1591
void IntAlertFillDriverObject(const WIN_DRIVER_OBJECT *DriverObject, INTRO_DRVOBJ *EventDrvObj)
Saves driver object information inside an alert. Available only for Windows guests.
Definition: alerts.c:592
uint32_t DWORD
Definition: intro_types.h:49
DWORD EntryPoint
Entry point (RVA).
Definition: winpe.h:601
BOOLEAN Valid
Set to True if the information in the structure is valid, False otherwise.
Definition: intro_types.h:965
INTSTATUS IntPeValidateHeader(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD ImageBaseBufferSize, INTRO_PE_INFO *PeInfo, QWORD Cr3)
Validates a PE header.
Definition: winpe.c:131
static INTSTATUS IntWinDrvObjUnprotectFastIoDispatch(WIN_DRIVER_OBJECT *DriverObject)
Deactivates the protection for the fast IO dispatch structure of a driver object. ...
Definition: windrvobj.c:1014
enum _INTRO_ACTION INTRO_ACTION
Event actions.
INTSTATUS IntIntegrityRemoveRegion(void *Descriptor)
Removes an integrity region from the gIntegrityRegions list.
Definition: integrity.c:313
PWCHAR Name
NULL-terminated wide-char string containing the name of the driver, as taken from the guest driver ob...
Definition: windrvobj.h:30
INTRO_WRITE_INFO WriteInfo
Definition: intro_types.h:1607
DWORD DwordValues[ND_MAX_REGISTER_SIZE/4]
Definition: decoder.h:56
#define IntDbgEnterDebugger()
Definition: introcore.h:381
__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
QWORD Cr3
The value of the guest CR3 register when the event was generated.
Definition: intro_types.h:970
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
void IntAlertFillWinProcessByCr3(QWORD ProcessCr3, INTRO_PROCESS *EventProcess)
Saves information about a Windows process inside an alert. The process is searched by its kernel CR3...
Definition: alerts.c:756
BOOLEAN Aligned
True if the driver object allocation is page aligned.
Definition: windrvobj.h:66
Encapsulates a protected Windows kernel module.
Definition: winguest.h:126
PWIN_DRIVER_OBJECT IntWinDrvObjFindByDrvObj(QWORD Gva)
Finds a driver object in the gWinDriverObjects list by its guest virtual address. ...
Definition: windrvobj.c:424
EVENT_INTEGRITY_VIOLATION Integrity
Definition: alerts.h:23
struct _EXCEPTION_KM_ORIGINATOR::@64 Original
struct _EVENT_INTEGRITY_VIOLATION::@302 Originator
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1194
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
KERNEL_DRIVER * IntDriverFindByAddress(QWORD Gva)
Returns the driver in which Gva resides.
Definition: drivers.c:164
QWORD BaseAddress
The guest virtual address at which the monitored integrity region starts.
Definition: intro_types.h:1614
#define LIST_HEAD_INIT(Name)
Definition: introlists.h:39
INTSTATUS IntHookObjectHookRegion(void *Object, QWORD Cr3, QWORD Gla, SIZE_T Length, BYTE Type, void *Callback, void *Context, DWORD Flags, HOOK_REGION_DESCRIPTOR **Region)
Hook a contiguous region of virtual memory inside the provided virtual address space.
Definition: hook_object.c:132
#define VICTIM_DRIVER_OBJECT
Printable name used for introObjectTypeDriverObject objects.
Definition: intro_types.h:745
__must_check INTSTATUS IntPhysMemMap(QWORD PhysAddress, DWORD Length, DWORD Flags, void **HostPtr)
Maps a guest physical address inside Introcore VA space.
Definition: glue.c:338
INTSTATUS 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...
DWORD DriverInit
Definition: wddefs.h:246
Encapsulates information about a virtual to physical memory translation.
Definition: introcore.h:102
char * utf16_for_log(const WCHAR *WString)
Converts a UTF-16 to a UTF-8 string to be used inside logging macros.
Definition: introcore.c:2845
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1197
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
INTSTATUS IntDecGetWrittenValueFromInstruction(PINSTRUX Instrux, PIG_ARCH_REGS Registers, PBYTE MemoryValue, OPERAND_VALUE *WrittenValue)
Decode a written value from a memory write instruction.
Definition: decoder.c:1861
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
Sent for integrity violation alerts. See EVENT_INTEGRITY_VIOLATION.
Definition: intro_types.h:92
EXCEPTION_VICTIM_INTEGRITY Integrity
Valid if the modified zone is Integrity.
Definition: exceptions.h:908
Holds register state.
Definition: glueiface.h:30
DWORD SizeOfImage
Size of the image.
Definition: winpe.h:599
Event structure for EPT violations.
Definition: intro_types.h:1215
#define IC_TAG_DRNU
Guest loaded module name buffer (Unicode)
Definition: memtags.h:11
BOOLEAN DrvobjProtected
True if the driver object structure is protected.
Definition: windrvobj.h:55
PWIN_DRIVER_OBJECT DriverObject
The driver object.
Definition: windriver.h:36
void IntAlertFillWinKmModule(const KERNEL_DRIVER *Driver, INTRO_MODULE *EventModule)
Saves kernel module information inside an alert.
Definition: alerts.c:617
static INTSTATUS IntWinDrvObjSendIntegrityAlert(EXCEPTION_VICTIM_ZONE const *Victim, EXCEPTION_KM_ORIGINATOR const *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Sends an introEventIntegrityViolation alert for a protected driver object.
Definition: windrvobj.c:537
Write-access hook.
Definition: glueiface.h:299
INTSTATUS IntPhysMemUnmap(void **HostPtr)
Unmaps an address previously mapped with IntPhysMemMap.
Definition: glue.c:396
INTSTATUS IntExceptKernelGetOriginator(EXCEPTION_KM_ORIGINATOR *Originator, DWORD Options)
This function is used to get the information about the kernel-mode originator.
INTSTATUS IntAlertFillExecContext(QWORD Cr3, INTRO_EXEC_CONTEXT *ExecContext)
Fills the current execution context.
Definition: alerts.c:31
#define ZONE_WRITE
Used for write violation.
Definition: exceptions.h:734
INTSTATUS IntHookObjectCreate(DWORD ObjectType, QWORD Cr3, void **Object)
Create a new hook object.
Definition: hook_object.c:81
void IntExcept(EXCEPTION_VICTIM_ZONE *Victim, void *Originator, EXCEPTION_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason, INTRO_EVENT_TYPE EventClass)
This function is the entry point for the exception mechanism.
Definition: exceptions.c:3357
QWORD DriverStart
Definition: wddefs.h:262
INTSTATUS IntWinDrvObjCreateFromAddress(QWORD GuestAddress, BOOLEAN StaticDetected, PWIN_DRIVER_OBJECT *DriverObject)
Creates a new driver object.
Definition: windrvobj.c:227
#define INT_STATUS_EXCEPTION_ALLOW
Definition: introstatus.h:391
INTRO_DRVOBJ DriverObject
The modified driver object. Valid only if Type is introObjectTypeDriverObject.
Definition: intro_types.h:1597
DWORD NameHash
The namehash of the originator return driver.
Definition: exceptions.h:947
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
DWORD NameLen
The length, in characters, of Name, not including the NULL-terminator.
Definition: windrvobj.h:32