Bitdefender Hypervisor Memory Introspection
winhal.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "drivers.h"
6 #include "winhal.h"
7 #include "alerts.h"
8 #include "decoder.h"
9 #include "hook.h"
10 #include "winpe.h"
11 
12 #define HAL_HEAP_PROT_PAGES_EXEC 0x20
13 
14 static WIN_HAL_DATA gHalData = { 0 };
16 
17 
18 static void
20  _In_ EXCEPTION_VICTIM_ZONE const *Victim,
21  _In_ EXCEPTION_KM_ORIGINATOR const *Originator,
22  _In_ INTRO_ACTION Action,
24  )
33 {
34  INTSTATUS status;
35  PEVENT_EPT_VIOLATION pEptViol;
36  PIG_ARCH_REGS regs;
37 
38  regs = &gVcpu->Regs;
39 
40  pEptViol = &gAlert.Ept;
41  memzero(pEptViol, sizeof(*pEptViol));
42 
43  pEptViol->Header.Action = Action;
44  pEptViol->Header.Reason = Reason;
45  pEptViol->Header.MitreID = idRootkit;
46 
48 
49  IntAlertEptFillFromKmOriginator(Originator, pEptViol);
50  IntAlertEptFillFromVictimZone(Victim, pEptViol);
51 
53 
55 
56  IntAlertFillCodeBlocks(Originator->Original.Rip, regs->Cr3, FALSE, &pEptViol->CodeBlocks);
57  IntAlertFillExecContext(0, &pEptViol->ExecContext);
58 
59  IntAlertFillVersionInfo(&pEptViol->Header);
60 
61  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
62  if (!INT_SUCCESS(status))
63  {
64  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
65  }
66 }
67 
68 
69 static INTSTATUS
71  _Inout_ KERNEL_DRIVER *Context,
72  _In_ HOOK_GPA const *Hook,
73  _In_ QWORD Address,
74  _Out_ INTRO_ACTION *Action
75  )
89 {
90  EXCEPTION_VICTIM_ZONE victim;
91  EXCEPTION_KM_ORIGINATOR originator;
92  INTSTATUS status;
93  INTRO_ACTION_REASON reason;
94  BOOLEAN exitAfterInformation;
95 
96  if (NULL == Context)
97  {
99  }
100 
102 
103  memzero(&victim, sizeof(victim));
104  memzero(&originator, sizeof(originator));
105 
106  // By default we do not allow this
107  *Action = introGuestNotAllowed;
108  reason = introReasonUnknown;
109  exitAfterInformation = FALSE;
110 
111  status = IntExceptKernelGetOriginator(&originator, 0);
112  if (status == INT_STATUS_EXCEPTION_BLOCK)
113  {
114  reason = introReasonNoException;
115  exitAfterInformation = TRUE;
116  }
117  else if (!INT_SUCCESS(status))
118  {
119  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
120  reason = introReasonInternalError;
121  exitAfterInformation = TRUE;
122  }
123 
124  status = IntExceptGetVictimEpt(Context,
125  Address,
126  IntHookGetGlaFromGpaHook(Hook, Address),
128  ZONE_WRITE,
129  &victim);
130  if (!INT_SUCCESS(status))
131  {
132  reason = introReasonInternalError;
133  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
134  exitAfterInformation = TRUE;
135  }
136 
137  if (exitAfterInformation)
138  {
139  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
140  }
141  else
142  {
143  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
144  }
145 
147 
149  {
150  IntWinHalSendAlert(&victim, &originator, *Action, reason);
151  }
152 
154 
155  return status;
156 }
157 
158 
159 static INTSTATUS
161  _In_opt_ void *Context,
162  _Inout_ HOOK_GPA *Hook,
163  _In_ QWORD Address,
164  _Out_ INTRO_ACTION *Action
165  )
180 {
181  INTSTATUS status;
182  QWORD gva;
183  EXCEPTION_KM_ORIGINATOR originator;
184  EXCEPTION_VICTIM_ZONE victim;
185  INTRO_ACTION_REASON reason;
186  PBYTE memoryArea;
187  DWORD memAreaLength;
188  DWORD csType;
189  DWORD instructionStart;
190  BOOLEAN foundVMCALL;
191  BYTE buffer[1] = { 0xC3 };
192  BOOLEAN exitAfterInformation = FALSE;
193 
194  UNREFERENCED_PARAMETER(Context);
195 
196  gva = IntHookGetGlaFromGpaHook(Hook, Address);
197  memoryArea = NULL;
198  memAreaLength = 0;
199  foundVMCALL = FALSE;
200  *Action = introGuestNotAllowed;
201  reason = introReasonNoException;
202 
203  LOG("[HAL] Code from hal heap (GVA 0x%016llx --- GPA 0x%016llx) has been executed from 0x%016llx.\n",
204  gva, Address, gVcpu->Regs.Rip
205  );
206 
207  status = IntGetCurrentMode(gVcpu->Index, &csType);
208  if (!INT_SUCCESS(status))
209  {
210  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
211  }
212 
213  // When there are multiple processors, IPIs are sent between them and real mode execution may occur.
214  // for now, allow these executions
215  // Also check cs type. If it's 16 bits it is probably the AP bootloader.
216  if ((gVcpu->Regs.Cr0 & CR0_PE) == 0 || csType == IG_CS_TYPE_16B)
217  {
218  TRACE("[HAL] Real mode execution detected.\n");
219  IntHookRemoveChain(Hook);
220  *Action = introGuestRetry;
221  return INT_STATUS_SUCCESS;
222  }
223 
224  // Allocate 2 pages, but only scan one. avoid problems with instructions spanned over 2 pages.
225  memoryArea = HpAllocWithTag(2 * PAGE_SIZE, IC_TAG_HAL_HEAP);
226  if (NULL == memoryArea)
227  {
228  goto no_vmcall;
229  }
230 
231  status = IntKernVirtMemRead(gva & PAGE_MASK, 2 * PAGE_SIZE, memoryArea, &memAreaLength);
232  if ((!INT_SUCCESS(status)) && (0 == memAreaLength))
233  {
234  WARNING("[WARNING] IntKernVirtMemRead failed: %08x\n", status);
236  goto no_vmcall;
237  }
238 
239  memAreaLength = MIN(memAreaLength, PAGE_SIZE);
240 
241  instructionStart = Address & PAGE_OFFSET;
242 
243  while (instructionStart < memAreaLength)
244  {
245  INSTRUX instrux;
246 
247  status = IntDecDecodeInstructionFromBuffer(memoryArea + instructionStart,
248  memAreaLength - instructionStart, csType, &instrux);
249  if (!INT_SUCCESS(status))
250  {
251  instructionStart++;
252  continue;
253  }
254 
255  if (ND_INS_VMCALL == instrux.Instruction)
256  {
257  foundVMCALL = TRUE;
258  break;
259  }
260 
261  instructionStart += instrux.Length;
262  }
263 
265 
266  // We found a VMCALL, suppose it is the hypercall page. disable the hook on this specific page.
267  if (foundVMCALL)
268  {
269  LOG("[HAL] Page %llx (physical %llx) seems to be the hypercall page. Will stop monitoring it...\n",
270  gva, Address);
271  IntHookRemoveChain(Hook);
272  *Action = introGuestRetry;
273  return INT_STATUS_SUCCESS;
274  }
275 
276 no_vmcall:
277  memzero(&victim, sizeof(victim));
278  memzero(&originator, sizeof(originator));
279 
281 
282  status = IntExceptKernelGetOriginator(&originator, 0);
283  if (status == INT_STATUS_EXCEPTION_BLOCK)
284  {
285  reason = introReasonNoException;
286  exitAfterInformation = TRUE;
287  }
288  else if (!INT_SUCCESS(status))
289  {
290  ERROR("[ERROR] IntExceptKernelGetOriginator failed: %08x\n", status);
291  reason = introReasonInternalError;
292  exitAfterInformation = TRUE;
293  }
294 
295  status = IntExceptGetVictimEpt(Hook, Address, gva, introObjectTypeHalHeap, ZONE_EXECUTE, &victim);
296  if (!INT_SUCCESS(status))
297  {
298  ERROR("[ERROR] IntExceptGetVictimEpt failed: %08x\n", status);
299  reason = introReasonInternalError;
300  exitAfterInformation = TRUE;
301  }
302 
303  if (exitAfterInformation)
304  {
305  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
306  }
307  else
308  {
309  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
310  }
311 
313 
315  {
316  EVENT_EPT_VIOLATION *pEptViol = &gAlert.Ept;
317  memzero(pEptViol, sizeof(*pEptViol));
318 
319  pEptViol->Header.Action = *Action;
320  pEptViol->Header.Reason = reason;
321  pEptViol->Header.MitreID = idExploitRemote;
322 
324 
325  pEptViol->Violation = INTRO_EPT_EXECUTE;
326  pEptViol->HookStartPhysical = Hook->GpaPage;
327  pEptViol->HookStartVirtual = gva & PAGE_MASK;
328  pEptViol->VirtualPage = gva & PAGE_MASK;
329  pEptViol->Offset = Address & PAGE_OFFSET;
330  pEptViol->Victim.Type = introObjectTypeHalHeap;
331  pEptViol->ZoneTypes = ZONE_EXECUTE;
332 
334 
335  IntAlertEptFillFromKmOriginator(&originator, pEptViol);
336 
337  // Do not fill code blocks, as there are not enough instructions (no code should normally be there)
338 
340  IntAlertFillVersionInfo(&pEptViol->Header);
342 
343  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
344  if (!INT_SUCCESS(status))
345  {
346  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
347  }
348  }
349 
351 
352  if (introGuestNotAllowed == *Action)
353  {
354  // Inject a ret instruction and let it execute
355  status = IntKernVirtMemWrite(gva, sizeof(buffer), buffer);
356  if (INT_SUCCESS(status))
357  {
358  LOG("[HAL] Injecting ret instruction @ GVA 0x%016llx\n", gva);
359  *Action = introGuestAllowed;
360  reason = introReasonAllowed;
361  }
362  else
363  {
364  ERROR("[ERROR] Could not inject ret! Status: %08x\n", status);
365  *Action = introGuestNotAllowed;
366  reason = introReasonNoException;
367  }
368  }
370  {
371  // Remove the hook if it was excepted. If we don't do this we will have an exit for every instruction in this
372  // chunk and we will have to except it every time.
373  IntHookRemoveChain(Hook);
374  *Action = introGuestRetry;
375  }
376 
377  return INT_STATUS_SUCCESS;
378 }
379 
380 
381 static INTSTATUS
383  _Inout_ PINTEGRITY_REGION IntegrityRegion
384  )
394 {
395  INTSTATUS status = INT_STATUS_SUCCESS;
396  BYTE const *pOriginal = NULL;
397  PBYTE pPage = NULL;
398  BOOLEAN bOnePage = FALSE;
399  INTRO_ACTION action;
400  INTRO_ACTION_REASON reason;
402 
403  pOriginal = IntegrityRegion->OriginalContent;
404  action = introGuestNotAllowed;
405  reason = introReasonUnknown;
406 
407  bOnePage =
408  (((IntegrityRegion->Gva + IntegrityRegion->Length - 1) & PAGE_MASK) == (IntegrityRegion->Gva & PAGE_MASK));
409 
410  status = IntVirtMemMap(IntegrityRegion->Gva, IntegrityRegion->Length, gGuest.Mm.SystemCr3, 0, &pPage);
411  if (!INT_SUCCESS(status))
412  {
413  ERROR("[ERROR] Failed to map GVA 0x%016llx: 0x%x\n", IntegrityRegion->Gva, status);
414  goto _cleanup_and_exit;
415  }
416 
417  for (DWORD offset = 0; offset < IntegrityRegion->Length; offset += gGuest.WordSize)
418  {
419  EXCEPTION_VICTIM_ZONE victim;
420  EXCEPTION_KM_ORIGINATOR originator;
421  QWORD originalValue = 0;
422  QWORD newValue = 0;
423 
424  if (gGuest.Guest64)
425  {
426  originalValue = *(QWORD *)((size_t)pOriginal + (size_t)offset);
427  newValue = *(QWORD *)((size_t)pPage + (size_t)offset);
428  }
429  else
430  {
431  originalValue = *(DWORD *)((size_t)pOriginal + (size_t)offset);
432  newValue = *(DWORD *)((size_t)pPage + (size_t)offset);
433  }
434 
435  if (newValue != originalValue)
436  {
437  DWORD currentOffset = offset;
438 
439  memzero(&victim, sizeof(victim));
440 
441  memzero(&originator, sizeof(originator));
442 
443  status = IntExceptGetVictimIntegrity(IntegrityRegion, &currentOffset, &victim);
444  if (!INT_SUCCESS(status))
445  {
446  ERROR("[ERROR] IntExceptGetVictimIntegrity failed: 0x%08x\n", status);
447  }
448 
449  status = IntExceptGetOriginatorFromModification(&victim, &originator);
450  if (!INT_SUCCESS(status))
451  {
452  TRACE("[INFO] IntExceptGetOriginatorFromModification failed: 0x%08x\n", status);
453  if (status == INT_STATUS_EXCEPTION_BLOCK)
454  {
455  action = introGuestNotAllowed;
456  reason = introReasonNoException;
457  }
458 
459  // don't propagate the error
460  status = INT_STATUS_SUCCESS;
461  }
462 
463  LOG("[INTEGRITY VIOLATION] HalDispatchTable modification at 0x%016llx : 0x%x "
464  "(index %d). New Value = 0x%016llx, Old Value = 0x%016llx\n",
465  IntegrityRegion->Gva, offset, offset / gGuest.WordSize, newValue, originalValue);
466 
467  if (isBeta)
468  {
469  LOG("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (B) ROOTKIT ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n");
470  }
471  else
472  {
473  LOG("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ROOTKIT ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n");
474  }
475 
476  if (!isBeta)
477  {
478  // restore the contents atomically
479  if (gGuest.Guest64)
480  {
481  _InterlockedExchange64((INT64 *)(pPage + offset), originalValue);
482  }
483  else
484  {
485  _InterlockedExchange((INT32 *)(pPage + offset), (INT32)originalValue);
486  }
487 
488  // This is needed because on multiple pages, pPage is not really a map to guest memory, it is
489  // memory copied from a GVA to an allocated HVA, so modifications on this will not reflect on
490  // guest if we don't write it explicitly
491  if (!bOnePage)
492  {
493  IntKernVirtMemWrite(IntegrityRegion->Gva + offset, gGuest.WordSize, pPage + offset);
494  }
495  }
496  else
497  {
498  action = introGuestAllowed;
499  // The action will be BETA detected, it will be allowed by default, so there is no use of
500  // specifying it in the reason while the BETA flag is specified in the alert.
501  reason = introReasonAllowed;
502 
503  // we let the modifications happen if BETA alerts are enabled and we don't want to SPAM the same
504  // alert every time
505  status = IntIntegrityRecalculate(IntegrityRegion);
506  if (!INT_SUCCESS(status))
507  {
508  ERROR("[ERROR] IntIntegrityRecalculate failed: 0x%x\n", status);
509  status = INT_STATUS_SUCCESS; // don't propagate this error
510  }
511  }
512 
513  // send one alert for every modified pointer
514  {
516 
517  memzero(pIntViolation, sizeof(*pIntViolation));
518 
519  pIntViolation->Header.Action = action;
520  pIntViolation->Header.Reason = reason;
521  pIntViolation->Header.MitreID = idExploitPrivEsc;
522 
524  pIntViolation->Header.Flags |= ALERT_FLAG_ASYNC;
525 
526  pIntViolation->Header.CpuContext.Valid = FALSE;
527 
529 
531 
532  IntAlertFillWinKmModule(originator.Original.Driver, &pIntViolation->Originator.Module);
533 
534  memcpy(pIntViolation->Victim.Name, VICTIM_HAL_DISPATCH_TABLE, sizeof(VICTIM_HAL_DISPATCH_TABLE));
535 
536  pIntViolation->WriteInfo.Size = gGuest.WordSize;
537  pIntViolation->WriteInfo.OldValue[0] = originalValue;
538  pIntViolation->WriteInfo.NewValue[0] = newValue;
539 
540  pIntViolation->Size = gGuest.WordSize;
541  pIntViolation->BaseAddress = IntegrityRegion->Gva;
542  pIntViolation->VirtualAddress = IntegrityRegion->Gva + offset;
543 
544  IntAlertFillVersionInfo(&pIntViolation->Header);
545 
546  IntNotifyIntroEvent(introEventIntegrityViolation, pIntViolation, sizeof(*pIntViolation));
547  }
548  }
549  }
550 
551 _cleanup_and_exit:
552  if (NULL != pPage)
553  {
554  IntVirtMemUnmap(&pPage);
555  }
556 
557  return status;
558 }
559 
560 
561 INTSTATUS
563  void
564  )
577 {
578  INTSTATUS status;
579  QWORD hookAddrStart, hookAddrEnd;
580 
581  if (gHalData.HalHeapExecHook != NULL)
582  {
584  }
585 
586  // The HalHeap is not initialized, no need to hook it.
587  if (0 == gHalData.HalHeapAddress)
588  {
590  }
591 
592  TRACE("[HAL] Adding Hal Heap hook at %llx...\n", gHalData.HalHeapAddress);
593 
594  hookAddrStart = gHalData.HalHeapAddress;
595  hookAddrEnd = hookAddrStart + gHalData.HalHeapSize;
596 
598  if (!INT_SUCCESS(status))
599  {
600  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
601  return status;
602  }
603 
604  for (QWORD gva = hookAddrStart; gva < hookAddrEnd; gva += PAGE_SIZE)
605  {
606  BYTE r, w, x;
607  QWORD gpa = 0;
608 
609  status = IntTranslateVirtualAddress(gva, gGuest.Mm.SystemCr3, &gpa);
610  if (!INT_SUCCESS(status))
611  {
612  WARNING("[WARNING] Cannot protect hal heap page 0x%016llx\n", gva);
613  continue;
614  }
615 
616  status = IntGetEPTPageProtection(gGuest.UntrustedEptIndex, gpa, &r, &w, &x);
617  if (!INT_SUCCESS(status))
618  {
619  WARNING("[WARNING] Cannot protect hal heap page 0x%016llx (GPA 0x%016llx)\n", gva, gpa);
620  continue;
621  }
622 
623  if (gpa < PAGE_SIZE)
624  {
625  WARNING("[WARNING] Will not protect hal heap page 0x%016llx because it translates to physical page 0\n",
626  gva);
627  continue;
628  }
629 
630  status = IntHookObjectHookRegion(gHalData.HalHeapExecHook,
631  0,
632  gva,
633  PAGE_SIZE,
636  NULL,
637  0,
638  NULL);
639 
640  if (!INT_SUCCESS(status))
641  {
642  ERROR("[ERROR] IntHookObjectHookRegion failed: %08x Region (0x%016llx, 0x%016llx)\n",
643  status, gva, gva + PAGE_SIZE);
644  }
645  else
646  {
647  TRACE("[HAL] Hooking region (0x%016llx, 0x%016llx) against executions\n", gva, gva + PAGE_SIZE);
648  }
649  }
650 
651  return INT_STATUS_SUCCESS;
652 }
653 
654 
655 INTSTATUS
657  void
658  )
664 {
665  INTSTATUS status;
666 
667  if (gHalData.HalHeapExecHook == NULL)
668  {
670  }
671 
672  TRACE("[HAL] Removing Hal Heap hook...\n");
673 
675 
676  return status;
677 }
678 
679 
680 INTSTATUS
682  void
683  )
691 {
692  INTSTATUS status;
693 
694  if (gHalData.HalIntCtrlWriteHook != NULL)
695  {
697  }
698 
699  if (0 == gHalData.HalIntCtrlAddress)
700  {
702  }
703 
704  TRACE("[HAL] Adding Hal Interrupt Controller hook at %llx...\n", gHalData.HalIntCtrlAddress);
705 
707  if (!INT_SUCCESS(status))
708  {
709  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
710  return status;
711  }
712 
714  0,
715  gHalData.HalIntCtrlAddress,
716  WIN_KM_FIELD(Ungrouped, HalIntCtrlType),
719  gHalData.OwnerHalModule,
720  0,
721  NULL);
722  if (!INT_SUCCESS(status))
723  {
724  ERROR("[ERROR] IntHookObjectHookRegion failed: 0x%08x\n", status);
725  return status;
726  }
727 
728  return status;
729 }
730 
731 
732 INTSTATUS
734  void
735  )
741 {
742  INTSTATUS status;
743 
744  if (gHalData.HalIntCtrlWriteHook == NULL)
745  {
747  }
748 
749  TRACE("[HAL] Removing Hal Interrupt Controller hook...\n");
750 
752 
753  return status;
754 }
755 
756 
757 INTSTATUS
759  void
760  )
768 {
769  INTSTATUS status;
770 
771  if (gHalData.HalDispatchIntegrityHook != NULL)
772  {
774  }
775 
776  if (0 == gHalData.HalDispatchTableAddress)
777  {
779  }
780 
781  TRACE("[HAL] Adding HalDispatchTable hook at %llx...\n", gHalData.HalDispatchTableAddress);
782 
784  gHalData.HalDispatchTableSize,
786  NULL,
788  TRUE,
789  &gHalData.HalDispatchIntegrityHook);
790  if (!INT_SUCCESS(status))
791  {
792  ERROR("[ERROR] IntIntegrityAddRegion failed: 0x%x\n", status);
793  return status;
794  }
795 
796  return INT_STATUS_SUCCESS;
797 }
798 
799 
800 INTSTATUS
802  void
803  )
809 {
810  INTSTATUS status;
811 
812  if (gHalData.HalDispatchIntegrityHook == NULL)
813  {
815  }
816 
817  TRACE("[HAL] Removing Hal Dispatch Table hook...\n");
818 
820  if (!INT_SUCCESS(status))
821  {
822  ERROR("[ERROR] IntIntegrityRemoveRegion failed with status: 0x%08X\n", status);
823  return status;
824  }
825 
826  gHalData.HalDispatchIntegrityHook = NULL;
827 
828  return status;
829 }
830 
831 
832 static BOOLEAN
834  _In_ QWORD CheckedAddress,
835  _In_ QWORD HalHeap
836  )
851 {
852 #define MAX_INT_CTRL_TYPE_OFFSET (gGuest.Guest64 ? 0xf0 : 0x6c)
853 #define MIN_INT_CTRL_TYPE_OFFSET (gGuest.Guest64 ? 0xc0 : 0x60)
854 #define MAX_INT_CTRL_COUNT 20
855 
856  INTSTATUS status;
857  QWORD functionPointer;
858  QWORD functionOffset;
859 
860  QWORD initialInterruptController = 0;
861  QWORD halFunction = 0;
862  QWORD entriesOutsideTheHalHeap = 0;
863 
864  QWORD maxInterruptControllerCount = MAX_INT_CTRL_COUNT;
865  BOOLEAN isListEntry = FALSE;
866 
867  // 1. First structure is a LIST_ENTRY structure.
868  // All checked systems have at least 2 available controllers - we now have to validate that we actually
869  // have a list.
870  initialInterruptController = CheckedAddress;
871  while (maxInterruptControllerCount)
872  {
873  status = IntKernVirtMemRead(initialInterruptController, gGuest.WordSize, &initialInterruptController, NULL);
874  if (!INT_SUCCESS(status))
875  {
876  return FALSE;
877  }
878 
879  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, initialInterruptController))
880  {
881  return FALSE;
882  }
883 
884  if (initialInterruptController < HalHeap)
885  {
886  // Sometimes the ListHead is not situated on the HalHeap itself - we are only going to allow 1 entry
887  // outside the Hal Heap.
888  entriesOutsideTheHalHeap++;
889  }
890 
891  if (CheckedAddress == initialInterruptController && entriesOutsideTheHalHeap <= 1)
892  {
893  isListEntry = TRUE;
894  break;
895  }
896 
897  maxInterruptControllerCount--;
898  }
899 
900  if (!isListEntry)
901  {
902  return FALSE;
903  }
904 
905  // 2. At offset WordSize * 4 starts an area of pointers to functions in hal.dll or nt, mixed with 0's
906  // The list of functions spans until the type (2).
907  BOOLEAN foundFunctions = FALSE;
908  for (functionPointer = CheckedAddress + 4ull * gGuest.WordSize;
909  functionPointer <= CheckedAddress + MAX_INT_CTRL_TYPE_OFFSET;
910  functionPointer += gGuest.WordSize)
911  {
912  status = IntKernVirtMemRead(functionPointer, gGuest.WordSize, &halFunction, NULL);
913  if (!INT_SUCCESS(status))
914  {
915  return FALSE;
916  }
917 
918  if (0 == halFunction)
919  {
920  foundFunctions = TRUE;
921  continue;
922  }
923 
924  // 3. The type must be 2
925  if (foundFunctions && (2 == (DWORD)halFunction))
926  {
927  break;
928  }
929 
930  if (((halFunction < gHalData.OwnerHalModule->BaseVa) ||
931  (halFunction > gHalData.OwnerHalModule->BaseVa + gHalData.OwnerHalModule->Size)) &&
932  ((halFunction < gGuest.KernelVa) || (halFunction > gGuest.KernelVa + gGuest.KernelSize)))
933  {
934  return FALSE;
935  }
936 
937  foundFunctions = TRUE;
938  }
939 
940  if (!foundFunctions || 2 != (DWORD)halFunction)
941  {
942  return FALSE;
943  }
944 
945  functionOffset = functionPointer - CheckedAddress;
946  if (functionOffset < MIN_INT_CTRL_TYPE_OFFSET || functionOffset > MAX_INT_CTRL_TYPE_OFFSET)
947  {
948  return FALSE;
949  }
950 
951  WIN_KM_FIELD(Ungrouped, HalIntCtrlType) = (DWORD)functionOffset;
952 
953  return TRUE;
954 
955 #undef MAX_INT_CTRL_COUNT
956 #undef MAX_INT_CTRL_TYPE_OFFSET
957 #undef MIN_INT_CTRL_TYPE_OFFSET
958 }
959 
960 
961 static INTSTATUS
963  _In_ QWORD HalHeap,
964  _In_ QWORD HalHeapSize,
965  _Out_ QWORD *HalInterruptController
966  )
980 {
981  INTSTATUS status;
982  IMAGE_SECTION_HEADER dataSec = { 0 };
983  DWORD nrSec = 0;
984  QWORD halIntCtrlGva = 0;
985  void *dataSectionMem = NULL;
986 
988  ".data", 1, gGuest.Mm.SystemCr3, &dataSec, &nrSec);
989  if (!INT_SUCCESS(status) || nrSec == 0)
990  {
991  ERROR("[ERROR] IntPeGetSectionHeadersByName failed: 0x%08x, number of sections: %d\n", status, nrSec);
992  // status may be a succesful one, but if no sections were found we return an error status to signal that
993  // HalInterruptController is not valid
994  status = INT_STATUS_NOT_FOUND;
995  goto exit;
996  }
997 
998  if (dataSec.Misc.VirtualSize < gGuest.WordSize || dataSec.Misc.VirtualSize > ONE_MEGABYTE)
999  {
1000  ERROR("[ERROR] Invalid data section size:%x\n", dataSec.Misc.VirtualSize);
1001  status = INT_STATUS_NOT_FOUND;
1002  goto exit;
1003  }
1004 
1005  status = IntVirtMemMap(gHalData.OwnerHalModule->BaseVa + dataSec.VirtualAddress, dataSec.Misc.VirtualSize,
1006  gGuest.Mm.SystemCr3, 0, &dataSectionMem);
1007  if (!INT_SUCCESS(status))
1008  {
1009  ERROR("[ERROR] IntVirtMemMap failed: 0x%08x\n", status);
1010 
1011  status = INT_STATUS_NOT_FOUND;
1012  goto exit;
1013  }
1014 
1015  for (DWORD offset = 0; offset <= dataSec.Misc.VirtualSize - gGuest.WordSize; offset += gGuest.WordSize)
1016  {
1017  halIntCtrlGva = gGuest.Guest64 ? *(QWORD*)((QWORD)dataSectionMem + offset) :
1018  *(DWORD*)((QWORD)dataSectionMem + offset);
1019 
1020  if (halIntCtrlGva < HalHeap || halIntCtrlGva >= HalHeap + HalHeapSize)
1021  {
1022  continue;
1023  }
1024 
1025  if (IntWinHalIsIntController(halIntCtrlGva, HalHeap))
1026  {
1027  *HalInterruptController = halIntCtrlGva;
1028  status = INT_STATUS_SUCCESS;
1029  goto exit;
1030  }
1031  }
1032 
1033  status = INT_STATUS_NOT_FOUND;
1034 
1035 exit:
1036  if (dataSectionMem)
1037  {
1038  IntVirtMemUnmap(&dataSectionMem);
1039  }
1040 
1041  return status;
1042 }
1043 
1044 
1045 static INTSTATUS
1047  _Out_ QWORD *HalHeapBaseAddress,
1048  _Out_ QWORD *HalInterruptController
1049  )
1068 {
1069  INTSTATUS status;
1070  DWORD nrSec = 0;
1071  DWORD pteTableIndex = 0;
1072  QWORD ptePhysicalAddress = 0;
1073  QWORD ptPhysicalAddress = 0;
1074  QWORD halHeapStart = 0;
1075  QWORD deviceAddressCount = 0;
1076  VA_TRANSLATION halHeapStartTranslation = { 0 };
1077  IMAGE_SECTION_HEADER dataSec = { 0 };
1078  QWORD fallbackHalHeapVA = 0;
1079  QWORD halInterruptController = 0;
1080  QWORD *pt = NULL;
1081  void *dataSectionMem = NULL;
1082 
1083 #define HAL_HEAP_ORIGINAL 0xFFFFFFFFF0000000
1084 #define MASK_DEVICE_ADDRESS_FEC 0x00000000fec00000
1085 #define MASK_DEVICE_ADDRESS_FED 0x00000000fed00000
1086 #define MASK_DEVICE_ADDRESS_FEE 0x00000000fee00000
1087 #define HAL_HEAP_PHYSICAL_ADDRESS 0x1000
1088 
1090  ".data", 1, gGuest.Mm.SystemCr3, &dataSec, &nrSec);
1091  if (!INT_SUCCESS(status) || nrSec == 0)
1092  {
1093  ERROR("[ERROR] IntPeGetSectionHeadersByName failed: 0x%08x, number of sections: %d\n", status, nrSec);
1094  goto exit;
1095  }
1096 
1097  if (dataSec.Misc.VirtualSize < gGuest.WordSize || dataSec.Misc.VirtualSize > ONE_MEGABYTE)
1098  {
1099  ERROR("[ERROR] Invalid data section size:%x\n", dataSec.Misc.VirtualSize);
1100  status = INT_STATUS_UNSUCCESSFUL;
1101  goto exit;
1102  }
1103 
1104  status = IntVirtMemMap(gHalData.OwnerHalModule->BaseVa + dataSec.VirtualAddress, dataSec.Misc.VirtualSize,
1105  gGuest.Mm.SystemCr3, 0, &dataSectionMem);
1106  if (!INT_SUCCESS(status))
1107  {
1108  ERROR("[ERROR] IntVirtMemMap failed: 0x%08x\n", status);
1109  goto exit;
1110  }
1111 
1112  for (DWORD offset = 0; offset <= dataSec.Misc.VirtualSize - gGuest.WordSize; offset += gGuest.WordSize)
1113  {
1114  halHeapStart = gGuest.Guest64 ? *(QWORD*)((QWORD)dataSectionMem + offset) :
1115  *(DWORD*)((QWORD)dataSectionMem + offset);
1116 
1117  halHeapStart = halHeapStart & HAL_HEAP_ORIGINAL;
1118 
1119  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, halHeapStart))
1120  {
1121  continue;
1122  }
1123 
1124  status = IntTranslateVirtualAddressEx(halHeapStart, gGuest.Mm.SystemCr3, 0, &halHeapStartTranslation);
1125  if (!INT_SUCCESS(status))
1126  {
1127  continue;
1128  }
1129 
1130  if (0 == halHeapStartTranslation.MappingsCount)
1131  {
1132  continue;
1133  }
1134 
1135  // Here we obtain the physical address of the PT (PT[0])
1136  pteTableIndex = halHeapStartTranslation.MappingsCount - 1;
1137  ptePhysicalAddress = halHeapStartTranslation.MappingsTrace[pteTableIndex];
1138  ptPhysicalAddress = ptePhysicalAddress & PHYS_PAGE_MASK;
1139 
1140  // From what I`ve seen, even on KASLR Hal Heap OSes (newer than RS2) the Hal Heap is always mapped to PA 0x1000.
1141  // In theory we could use this to find the Hal Heap but it`s safer to look for mapped devices and keep
1142  // this as a fallback mechanism only.
1143  if (HAL_HEAP_PHYSICAL_ADDRESS == halHeapStartTranslation.PhysicalAddress)
1144  {
1145  fallbackHalHeapVA = halHeapStartTranslation.VirtualAddress;
1146  }
1147 
1148  status = IntPhysMemMap(ptPhysicalAddress, PAGE_SIZE, 0, &pt);
1149  if (!INT_SUCCESS(status))
1150  {
1151  continue;
1152  }
1153 
1154  // Now we are going to look for mapped devices. The PT used to translate the HalHeap VA has other PTEs that map
1155  // physical devices (0xfee00XXX, 0xfec00XXX, 0xfed00XXX, etc.), so we are going to look for them. Below there
1156  // are some PTEs dumped from WinDbg (they illustrate the PTEs that map physical devices).
1157  //
1158  // ffffd07b`d92000a0 80000000`00016863 80000000`fee0087b <- Physicall device
1159  // ffffd07b`d92000b0 80000000`00018863 80000000`fec0081b <- Physicall device
1160  // ffffd07b`d92000c0 80000000`00019863 80000000`0001c863
1161  // ffffd07b`d92000d0 80000000`0001d863 80000000`fed0081b <- Physicall device
1162  deviceAddressCount = 0;
1163  for (DWORD i = 0; i < 512; i++)
1164  {
1165  if (!pt[i])
1166  {
1167  continue;
1168  }
1169 
1170  if ((pt[i] & PHYS_PAGE_MASK) == MASK_DEVICE_ADDRESS_FEE)
1171  {
1172  deviceAddressCount++;
1173  }
1174 
1175  if ((pt[i] & PHYS_PAGE_MASK) == MASK_DEVICE_ADDRESS_FEC)
1176  {
1177  deviceAddressCount++;
1178  }
1179 
1180  if ((pt[i] & PHYS_PAGE_MASK) == MASK_DEVICE_ADDRESS_FED)
1181  {
1182  deviceAddressCount++;
1183  }
1184  }
1185 
1186  status = IntPhysMemUnmap(&pt);
1187  if (!INT_SUCCESS(status))
1188  {
1189  continue;
1190  }
1191 
1192  // If there are at least 2 mapped physical devices, try to find the interrupt controller to validate
1193  // our candidate address.
1194  if (deviceAddressCount >= 2)
1195  {
1196  status = IntWinHalFindInterruptController(halHeapStartTranslation.VirtualAddress,
1198  &halInterruptController);
1199  if (!INT_SUCCESS(status))
1200  {
1201  continue;
1202  }
1203 
1204  TRACE("[HAL] Found HalInterruptController at 0x%016llx\n", halInterruptController);
1205 
1206  *HalHeapBaseAddress = halHeapStartTranslation.VirtualAddress;
1207  *HalInterruptController = halInterruptController;
1208 
1209  goto exit;
1210  }
1211  }
1212 
1213  if (fallbackHalHeapVA)
1214  {
1215  WARNING("[WARNING] We could not find the Hal Heap using the mapped devices - fallback using PA:0x1000 "
1216  "VA:%llx\n", fallbackHalHeapVA);
1217 
1219  &halInterruptController);
1220  if (INT_SUCCESS(status))
1221  {
1222  TRACE("[HAL] Found HalInterruptController at 0x%016llx\n", halInterruptController);
1223 
1224  *HalHeapBaseAddress = fallbackHalHeapVA;
1225  *HalInterruptController = halInterruptController;
1226 
1227  goto exit;
1228  }
1229  else
1230  {
1231  ERROR("[ERROR] We could not find the Hal Heap using the fallback VA\n");
1232  }
1233  }
1234  else
1235  {
1236  ERROR("[ERROR] We could not find the Hal Heap using the mapped devices and there is no fallback address\n");
1237  }
1238 
1239  status = INT_STATUS_NOT_FOUND;
1240 
1241 exit:
1242  if (dataSectionMem)
1243  {
1244  IntVirtMemUnmap(&dataSectionMem);
1245  }
1246 
1247 #undef HAL_HEAP_ORIGINAL
1248 #undef MASK_DEVICE_ADDRESS_FEC
1249 #undef MASK_DEVICE_ADDRESS_FED
1250 #undef MASK_DEVICE_ADDRESS_FEE
1251 #undef HAL_HEAP_PHYSICAL_ADDRESS
1252 
1253  return status;
1254 }
1255 
1256 
1257 INTSTATUS
1259  void
1260  )
1270 {
1271  INTSTATUS status;
1272 
1273  status = IntPeFindKernelExport("HalDispatchTable", &gHalData.HalDispatchTableAddress);
1274  if (!INT_SUCCESS(status))
1275  {
1276  ERROR("[ERROR] IntPeFindKernelExport failed for 'HalDispatchTable': 0x%x\n", status);
1277  return status;
1278  }
1279 
1280  // Starting from 20H1, the Hal Heap and Hal Interrupt controller have been moved to the nt itself on x64 versions
1281  // of Windows.
1283  {
1284  gHalData.OwnerHalModule = gGuest.KernelDriver;
1285  }
1286  else
1287  {
1288  gHalData.OwnerHalModule = IntDriverFindByName(u"hal.dll");
1289  }
1290 
1291  if (NULL == gHalData.OwnerHalModule)
1292  {
1293  ERROR("[ERROR] Could not find the module containing the Hal\n");
1294  return INT_STATUS_NOT_FOUND;
1295  }
1296 
1298 
1299  TRACE("[HAL] Found HalDispatchTable at %llx, size %d\n",
1300  gHalData.HalDispatchTableAddress, gHalData.HalDispatchTableSize);
1301 
1302  // RS2 x64 made the hal heap ASLR compatible
1303  // RS2 x86 still maps the hal heap at the same Virtual Address.
1305  {
1306  QWORD halHeap = 0;
1307  QWORD halInterruptController = 0;
1308  status = IntWinHalFindHalHeapAndInterruptController(&halHeap, &halInterruptController);
1309  if (!INT_SUCCESS(status))
1310  {
1311  LOG("[HAL] Unable to find the HAL heap\n");
1312  goto _skip_hal_heap;
1313  }
1314 
1315  gHalData.HalHeapAddress = halHeap;
1316  gHalData.HalIntCtrlAddress = halInterruptController;
1317  }
1318  else
1319  {
1321  }
1322 
1324 
1325  TRACE("[HAL] Found HalHeap at %llx, size %d\n", gHalData.HalHeapAddress, gHalData.HalHeapSize);
1326 
1328  {
1329  TRACE("[HAL] Hal Intterrupt Controller does not exist on Windows version %d!\n", gGuest.OSVersion);
1330  goto _skip_hal_heap;
1331  }
1332 
1333  if (!gHalData.HalIntCtrlAddress)
1334  {
1335  QWORD halInterruptController = 0;
1336  status = IntWinHalFindInterruptController(gHalData.HalHeapAddress, gHalData.HalHeapSize,
1337  &halInterruptController);
1338  if (!INT_SUCCESS(status))
1339  {
1340  ERROR("[ERROR] Could not find Hal Interrupt Controller!\n");
1341  goto _skip_hal_heap;
1342  }
1343 
1344  gHalData.HalIntCtrlAddress = halInterruptController;
1345  TRACE("[HAL] Found HalInterruptController at 0x%016llx\n", gHalData.HalIntCtrlAddress);
1346  }
1347 
1348 _skip_hal_heap:
1349  // Enable protections, if needed.
1351  {
1353  if (!INT_SUCCESS(status))
1354  {
1355  ERROR("[ERROR] IntWinHalHookHalDispatchTable failed: 0x%08x\n", status);
1356  return status;
1357  }
1358  }
1359 
1361  {
1362  status = IntWinHalProtectHalHeapExecs();
1363  if (!INT_SUCCESS(status))
1364  {
1365  ERROR("[ERROR] IntWinHalHookHalHeapExecs failed: 0x%08x\n", status);
1366  return status;
1367  }
1368  }
1369 
1371  {
1372  status = IntWinHalProtectHalIntCtrl();
1373  if (!INT_SUCCESS(status))
1374  {
1375  ERROR("[ERROR] IntWinHalHookHalIntCtrl failed: 0x%08x\n", status);
1376  return status;
1377  }
1378  }
1379 
1380  return status;
1381 }
1382 
1383 
1384 INTSTATUS
1386  void
1387  )
1396 {
1397  INTSTATUS status;
1398 
1400  {
1402  if (!INT_SUCCESS(status))
1403  {
1404  ERROR("[ERROR] IntWinHalHookHalDispatchTable failed: 0x%08x\n", status);
1405  return status;
1406  }
1407  }
1408  else
1409  {
1411  }
1412 
1414  {
1415  status = IntWinHalProtectHalHeapExecs();
1416  if (!INT_SUCCESS(status))
1417  {
1418  ERROR("[ERROR] IntWinHalHookHalHeapExecs failed: 0x%08x\n", status);
1419  return status;
1420  }
1421  }
1422  else
1423  {
1425  }
1426 
1428  {
1429  status = IntWinHalProtectHalIntCtrl();
1430  if (!INT_SUCCESS(status))
1431  {
1432  ERROR("[ERROR] IntWinHalHookHalIntCtrl failed: 0x%08x\n", status);
1433  return status;
1434  }
1435  }
1436  else
1437  {
1439  }
1440 
1441  return INT_STATUS_SUCCESS;
1442 }
1443 
1444 void
1446  void
1447  )
1451 {
1453 
1455 
1457 }
Measures kernel mode exceptions checks.
Definition: stats.h:51
Execute access.
Definition: intro_types.h:698
#define WIN_HAL_HEAP_BASE_32
The base address of the HAL heap on 32-bit kernels.
Definition: wddefs.h:67
#define _In_opt_
Definition: intro_sal.h:16
INTSTATUS IntWinHalUnprotectHalHeapExecs(void)
Deactivates the HAL heap execution protection.
Definition: winhal.c:656
QWORD PhysicalAddress
The physical address to which VirtualAddress translates to.
Definition: introcore.h:107
struct _EXCEPTION_KM_ORIGINATOR::@63 Original
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:1145
static int64_t _InterlockedExchange64(int64_t volatile *Target, int64_t Value)
Definition: intrinsics.h:592
_Bool BOOLEAN
Definition: intro_types.h:58
#define _Out_
Definition: intro_sal.h:22
#define VICTIM_HAL_DISPATCH_TABLE
Printable name used for introObjectTypeHalDispatchTable objects.
Definition: intro_types.h:679
#define HAL_HEAP_PROT_PAGES_EXEC
The number of HAL heap pages to protect against executions.
Definition: winhal.c:12
long long INT64
Definition: intro_types.h:45
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
DWORD Size
The size of the access.
Definition: intro_types.h:896
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
uint8_t BYTE
Definition: intro_types.h:47
INTSTATUS IntHookRemoveChain(PHOOK_GPA HookGpa)
Removes a hook chain, starting with the given GPA hook.
Definition: hook.c:105
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
BYTE Violation
The type of the access. It must be one of the IG_EPT_HOOK_TYPE values.
Definition: intro_types.h:1147
static INTSTATUS IntWinHalFindHalHeapAndInterruptController(QWORD *HalHeapBaseAddress, QWORD *HalInterruptController)
Attempts to find the Hal Heap and the Hal Interrupt Controller address within the ...
Definition: winhal.c:1046
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
DWORD Index
The VCPU number.
Definition: guests.h:172
#define _In_
Definition: intro_sal.h:21
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1088
INTSTATUS IntPeFindKernelExport(const char *Name, QWORD *ExportGva)
Find an export inside the NT kernel image.
Definition: winpe.c:1723
INTSTATUS IntWinHalUpdateProtection(void)
Updates any of the HAL protections.
Definition: winhal.c:1385
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:207
#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
WIN_KERNEL_DRIVER Win
Valid only for Windows guests.
Definition: drivers.h:70
QWORD NewValue[8]
The written value. Only the first Size bytes are valid.
Definition: intro_types.h:895
#define STATS_EXIT(id)
Definition: stats.h:148
DWORD KernelSize
The size of the kernel.
Definition: guests.h:280
Event structure for integrity violations on monitored structures.
Definition: intro_types.h:1450
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
static void IntWinHalSendAlert(EXCEPTION_VICTIM_ZONE const *Victim, EXCEPTION_KM_ORIGINATOR const *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Sends an introEventEptViolation for HAL alerts.
Definition: winhal.c:19
QWORD BaseVa
The guest virtual address of the kernel module that owns this driver object.
Definition: drivers.h:41
QWORD HookStartPhysical
The start of the monitored guest physical memory area for which this alert was generated.
Definition: intro_types.h:1152
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
struct _EVENT_EPT_VIOLATION::@277 Victim
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1087
INTRO_OBJECT_TYPE Type
Definition: intro_types.h:1462
#define PAGE_OFFSET
Definition: pgtable.h:32
The action was not allowed because there was no reason to allow it.
Definition: intro_types.h:183
int32_t INT32
Definition: intro_types.h:44
QWORD IntHookGetGlaFromGpaHook(HOOK_GPA const *Hook, QWORD Address)
Gets the GLA from a GPA hook.
Definition: hook.c:279
#define MASK_DEVICE_ADDRESS_FEE
PBYTE MzPeHeaders
The driver`s MZ/PE headers (cached internally).
Definition: windriver.h:34
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
#define ONE_MEGABYTE
Definition: introdefs.h:90
#define ALERT_FLAG_ASYNC
If set, the alert was generated in an async manner.
Definition: intro_types.h:637
KERNEL_DRIVER * Driver
The driver that&#39;s modifying the memory.
Definition: exceptions.h:903
INTSTATUS IntPeGetSectionHeadersByName(QWORD ImageBase, BYTE *ImageBaseBuffer, PCHAR Name, DWORD NumberOfSectionHeadersAllocated, QWORD Cr3, IMAGE_SECTION_HEADER *SectionHeaders, DWORD *NumberOfSectionHeadersFilled)
Return all the section headers matching the indicated Name.
Definition: winpe.c:917
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
#define PHYS_PAGE_MASK
Definition: pgtable.h:38
#define INTRO_OPT_PROT_KM_HAL_HEAP_EXEC
Enable execution prevention on the Hal Heap when it is not ASLR&#39;d (Windows only). ...
Definition: intro_types.h:415
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD Size
The size of the kernel module that owns this driver object.
Definition: drivers.h:43
DWORD OSVersion
Os version.
Definition: guests.h:277
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
Rootkit.
Definition: intro_types.h:1033
Describes a kernel-mode originator.
Definition: exceptions.h:897
#define WIN_HAL_HEAP_BASE_64
The base address of the HAL heap on 64-bit kernels.
Definition: wddefs.h:68
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
Definition: alerts.c:492
#define MIN(a, b)
Definition: introdefs.h:146
QWORD HookStartVirtual
The start of the monitored guest virtual memory area for which this alert was generated.
Definition: intro_types.h:1150
EVENT_EPT_VIOLATION Ept
Definition: alerts.h:16
#define WIN_BUILD_10_20H1
Definition: wddefs.h:61
INTSTATUS IntWinHalCreateHalData(void)
Initializes gHalData.
Definition: winhal.c:1258
#define HAL_DISPATCH_TABLE_PTR_COUNT
The number of entries inside the hal dispatch table.
Definition: wddefs.h:1165
#define LOG(fmt,...)
Definition: glue.h:61
Describes a kernel driver.
Definition: drivers.h:30
KERNEL_DRIVER * IntDriverFindByName(const void *Name)
Searches for a driver by its name.
Definition: drivers.c:266
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1106
BOOLEAN IntPolicyCoreIsOptionBeta(QWORD Flag)
Checks if one of the kernel protection options is in log-only mode.
Definition: introcore.c:2603
QWORD ZoneTypes
The types of the accessed memory area.
Definition: intro_types.h:1158
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1084
void * HalIntCtrlWriteHook
The HAL interrupt controller write hook object.
Definition: winhal.h:33
INTSTATUS IntAlertFillCodeBlocks(QWORD Rip, QWORD Cr3, BOOLEAN Execute, INTRO_CODEBLOCKS *CodeBlocks)
Fills the code blocks pattern for an alert.
Definition: alerts.c:71
DWORD MappingsCount
The number of entries inside the MappingsTrace and MappingsEntries arrays.
Definition: introcore.h:123
INTSTATUS IntGetCurrentMode(DWORD CpuNumber, DWORD *Mode)
Read the current CS type.
Definition: introcpu.c:977
void IntAlertEptFillFromKmOriginator(const EXCEPTION_KM_ORIGINATOR *Originator, EVENT_EPT_VIOLATION *EptViolation)
Fills kernel mode originator information inside an EPT alert.
Definition: alerts.c:832
INTSTATUS IntWinHalProtectHalDispatchTable(void)
Activates the HAL dispatch table protection.
Definition: winhal.c:758
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
static INTSTATUS IntWinHalFindInterruptController(QWORD HalHeap, QWORD HalHeapSize, QWORD *HalInterruptController)
Attempts to find the Hal Interrupt Controller address within the .data section of Hal...
Definition: winhal.c:962
#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 WIN_HAL_DATA gHalData
The HAL information.
Definition: winhal.c:15
DWORD HalHeapSize
The size of the HAL heap.
Definition: winhal.h:20
#define CR0_PE
Definition: processor.h:30
#define INT_STATUS_EXCEPTION_BLOCK
Definition: introstatus.h:421
Hal interrupt controller.
Definition: intro_types.h:250
DWORD Size
The size of the modified memory area.
Definition: intro_types.h:1483
void IntAlertEptFillFromVictimZone(const EXCEPTION_VICTIM_ZONE *Victim, EVENT_EPT_VIOLATION *EptViolation)
Fills the victim information inside an EPT alert.
Definition: alerts.c:868
static INTSTATUS IntWinHalHandleDispatchTableWrite(PINTEGRITY_REGION IntegrityRegion)
Handles modifications done to the HAL dispatch table.
Definition: winhal.c:382
#define STATS_ENTER(id)
Definition: stats.h:141
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
Definition: intro_types.h:1085
uint8_t * PBYTE
Definition: intro_types.h:47
#define INT_STATUS_UNSUCCESSFUL
Definition: introstatus.h:335
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Definition: glue.c:1042
#define ZONE_EXECUTE
Used for execute violation.
Definition: exceptions.h:700
#define memzero(a, s)
Definition: introcrt.h:35
#define INTRO_OPT_PROT_KM_HAL_INT_CTRL
Enable Hal Interrupt Controller write protection.
Definition: intro_types.h:417
void * HalDispatchIntegrityHook
The HAL dispatch table integrity hook object.
Definition: winhal.h:35
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
Definition: guests.h:286
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
QWORD Current
The currently used options.
Definition: guests.h:232
static INTSTATUS IntWinHalHandleHalIntCtrlWrite(KERNEL_DRIVER *Context, HOOK_GPA const *Hook, QWORD Address, INTRO_ACTION *Action)
Handles writes done over the HAL interrupt controller.
Definition: winhal.c:70
union _IMAGE_SECTION_HEADER::@209 Misc
INTRO_MODULE Module
The module that modified the translation.
Definition: intro_types.h:1456
struct _EVENT_INTEGRITY_VIOLATION::@295 Victim
INTSTATUS IntTranslateVirtualAddress(QWORD Gva, QWORD Cr3, QWORD *PhysicalAddress)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1999
static int32_t _InterlockedExchange(int32_t volatile *Target, int32_t Value)
Definition: intrinsics.h:571
QWORD VirtualAddress
The guest virtual address which was modified.
Definition: intro_types.h:1481
#define TRUE
Definition: intro_types.h:30
UINT32 VirtualAddress
Definition: winpe.h:85
INTSTATUS IntDecDecodeInstructionFromBuffer(PBYTE Buffer, size_t BufferSize, IG_CS_TYPE CsType, void *Instrux)
Decode an instruction from the provided buffer.
Definition: decoder.c:308
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1452
#define IS_KERNEL_POINTER_WIN(is64, p)
Checks if a guest virtual address resides inside the Windows kernel address space.
Definition: wddefs.h:76
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
static BOOLEAN IntWinHalIsIntController(QWORD CheckedAddress, QWORD HalHeap)
Checks if a guest memory range is the HAL interrupt controller.
Definition: winhal.c:833
#define MASK_DEVICE_ADDRESS_FED
INTSTATUS IntWinHalProtectHalHeapExecs(void)
Hooks the HAL heap against execution.
Definition: winhal.c:562
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:279
void IntExceptKernelLogInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-mode violation and dumps the code-blocks.
Kernel-mode exception.
Definition: exceptions.h:62
void IntAlertFillWinProcessCurrent(INTRO_PROCESS *EventProcess)
Saves information about the current Windows process inside an alert.
Definition: alerts.c:781
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
Definition: guests.h:363
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:1191
#define INT_STATUS_ALREADY_INITIALIZED_HINT
Definition: introstatus.h:323
#define MASK_DEVICE_ADDRESS_FEC
#define WARNING(fmt,...)
Definition: glue.h:60
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
Definition: intro_types.h:84
#define PAGE_SIZE
Definition: common.h:53
QWORD HalHeapAddress
The guest virtual address of the HAL heap.
Definition: winhal.h:16
Describes the modified zone.
Definition: exceptions.h:847
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
INTSTATUS IntWinHalUnprotectHalIntCtrl(void)
Deactivates the HAL interrupt controller write protection.
Definition: winhal.c:733
#define WIN_KM_FIELD(Structure, Field)
Macro used to access kernel mode fields inside the WIN_OPAQUE_FIELDS structure.
Definition: winguest.h:726
WCHAR Name[ALERT_PATH_MAX_LEN]
NULL-terminated string with a human readable description of the modified object.
Definition: intro_types.h:1464
uint32_t DWORD
Definition: intro_types.h:49
UINT32 VirtualSize
Definition: winpe.h:83
DWORD HalDispatchTableSize
The size of the HAL dispatch table.
Definition: winhal.h:25
KERNEL_DRIVER * OwnerHalModule
The hal.dll kernel module or ntoskrnl.exe.
Definition: winhal.h:28
BOOLEAN Valid
Set to True if the information in the structure is valid, False otherwise.
Definition: intro_types.h:879
QWORD HalDispatchTableAddress
The guest virtual address of the HAL dispatch table.
Definition: winhal.h:23
enum _INTRO_ACTION INTRO_ACTION
Event actions.
#define WIN_BUILD_10_RS2
Definition: wddefs.h:55
QWORD OldValue[8]
The original value. Only the first Size bytes are valid.
Definition: intro_types.h:894
INTSTATUS IntIntegrityRemoveRegion(void *Descriptor)
Removes an integrity region from the gIntegrityRegions list.
Definition: integrity.c:313
INTRO_WRITE_INFO WriteInfo
The original and the new value.
Definition: intro_types.h:1477
INTSTATUS IntGetEPTPageProtection(DWORD EptIndex, QWORD Gpa, BYTE *Read, BYTE *Write, BYTE *Execute)
Definition: glue.c:659
DWORD Offset
The offset inside the page where the violation took place.
Definition: intro_types.h:1156
__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
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:370
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:48
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
void IntWinHalUninit(void)
Frees any resources held by gHalData and removes all the HAL protections.
Definition: winhal.c:1445
#define IC_TAG_HAL_HEAP
Page in Hal Heap.
Definition: memtags.h:97
Hal dispatch table.
Definition: intro_types.h:249
Exploitation for Privilege Escalation.
Definition: intro_types.h:1037
QWORD MappingsTrace[MAX_TRANSLATION_DEPTH]
Contains the physical address of each entry within the translation tables.
Definition: introcore.h:111
EVENT_INTEGRITY_VIOLATION Integrity
Definition: alerts.h:23
#define HAL_HEAP_ORIGINAL
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1083
QWORD VirtualAddress
The translated virtual address.
Definition: introcore.h:105
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
QWORD HalIntCtrlAddress
The guest virtual address of the HAL interrupt controller.
Definition: winhal.h:18
QWORD BaseAddress
The guest virtual address at which the monitored integrity region starts.
Definition: intro_types.h:1479
struct _EVENT_INTEGRITY_VIOLATION::@294 Originator
#define MAX_INT_CTRL_TYPE_OFFSET
QWORD VirtualPage
The guest virtual page in which the access was made.
Definition: intro_types.h:1154
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
__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...
#define INT_STATUS_NOT_INITIALIZED_HINT
Definition: introstatus.h:320
Encapsulates information about a virtual to physical memory translation.
Definition: introcore.h:102
KERNEL_DRIVER * KernelDriver
Points to the driver object that describes the kernel image.
Definition: guests.h:381
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1086
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:57
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
#define INTRO_OPT_PROT_KM_HAL_DISP_TABLE
Enable HDT (Hal Dispatch Table) protection (Windows only).
Definition: intro_types.h:398
Sent for integrity violation alerts. See EVENT_INTEGRITY_VIOLATION.
Definition: intro_types.h:92
#define HAL_HEAP_PHYSICAL_ADDRESS
Holds register state.
Definition: glueiface.h:30
Event structure for EPT violations.
Definition: intro_types.h:1104
Execute-access hook.
Definition: glueiface.h:300
Hal information.
Definition: winhal.h:13
void IntAlertFillWinKmModule(const KERNEL_DRIVER *Driver, INTRO_MODULE *EventModule)
Saves kernel module information inside an alert.
Definition: alerts.c:617
Exploitation of Remote Services.
Definition: intro_types.h:1048
void * HalHeapExecHook
The HAL heap execution hook object.
Definition: winhal.h:31
Write-access hook.
Definition: glueiface.h:299
INTSTATUS IntPhysMemUnmap(void **HostPtr)
Unmaps an address previously mapped with IntPhysMemMap.
Definition: glue.c:396
#define PAGE_MASK
Definition: pgtable.h:35
DWORD UntrustedEptIndex
The EPTP index of the untrusted EPT.
Definition: guests.h:393
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:698
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:267
static INTSTATUS IntWinHalHandleHalHeapExec(void *Context, HOOK_GPA *Hook, QWORD Address, INTRO_ACTION *Action)
Handles execution attempts from the HAL heap.
Definition: winhal.c:160
INTSTATUS IntHookObjectCreate(DWORD ObjectType, QWORD Cr3, void **Object)
Create a new hook object.
Definition: hook_object.c:81
#define WIN_BUILD_8
Definition: wddefs.h:50
INTSTATUS IntWinHalProtectHalIntCtrl(void)
Protects the HAL interrupt controller against writes.
Definition: winhal.c:681
16-bit selector.
Definition: glueiface.h:186
void IntExcept(EXCEPTION_VICTIM_ZONE *Victim, void *Originator, EXCEPTION_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason, INTRO_EVENT_TYPE EventClass)
This function is the entry point for the exception mechanism.
Definition: exceptions.c:3317
#define MAX_INT_CTRL_COUNT
INTRO_OBJECT_TYPE Type
The type of the accessed memory area.
Definition: intro_types.h:1119
#define FALSE
Definition: intro_types.h:34
INTSTATUS IntWinHalUnprotectHalDispatchTable(void)
Deactivates the HAL dispatch table protection.
Definition: winhal.c:801