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 #include "swapmem.h"
12 
13 #define HAL_HEAP_PROT_PAGES_EXEC 0x20
14 
15 static WIN_HAL_DATA gHalData = { 0 };
17 
18 
19 static void
21  _In_ EXCEPTION_VICTIM_ZONE const *Victim,
22  _In_ EXCEPTION_KM_ORIGINATOR const *Originator,
23  _In_ INTRO_ACTION Action,
25  )
34 {
35  INTSTATUS status;
36  PEVENT_EPT_VIOLATION pEptViol;
37  PIG_ARCH_REGS regs;
38 
39  regs = &gVcpu->Regs;
40 
41  pEptViol = &gAlert.Ept;
42  memzero(pEptViol, sizeof(*pEptViol));
43 
44  pEptViol->Header.Action = Action;
45  pEptViol->Header.Reason = Reason;
46  pEptViol->Header.MitreID = idRootkit;
47 
49 
50  IntAlertEptFillFromKmOriginator(Originator, pEptViol);
51  IntAlertEptFillFromVictimZone(Victim, pEptViol);
52 
54 
56 
57  IntAlertFillCodeBlocks(Originator->Original.Rip, regs->Cr3, FALSE, &pEptViol->CodeBlocks);
58  IntAlertFillExecContext(0, &pEptViol->ExecContext);
59 
60  IntAlertFillVersionInfo(&pEptViol->Header);
61 
62  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
63  if (!INT_SUCCESS(status))
64  {
65  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
66  }
67 }
68 
69 
70 static INTSTATUS
72  _Inout_ KERNEL_DRIVER *Context,
73  _In_ HOOK_GPA const *Hook,
74  _In_ QWORD Address,
75  _Out_ INTRO_ACTION *Action
76  )
90 {
91  EXCEPTION_VICTIM_ZONE victim;
92  EXCEPTION_KM_ORIGINATOR originator;
93  INTSTATUS status;
94  INTRO_ACTION_REASON reason;
95  BOOLEAN exitAfterInformation;
96 
97  if (NULL == Context)
98  {
100  }
101 
103 
104  memzero(&victim, sizeof(victim));
105  memzero(&originator, sizeof(originator));
106 
107  // By default we do not allow this
108  *Action = introGuestNotAllowed;
109  reason = introReasonUnknown;
110  exitAfterInformation = FALSE;
111 
112  status = IntExceptKernelGetOriginator(&originator, 0);
113  if (status == INT_STATUS_EXCEPTION_BLOCK)
114  {
115  reason = introReasonNoException;
116  exitAfterInformation = TRUE;
117  }
118  else if (!INT_SUCCESS(status))
119  {
120  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
121  reason = introReasonInternalError;
122  exitAfterInformation = TRUE;
123  }
124 
125  status = IntExceptGetVictimEpt(Context,
126  Address,
127  IntHookGetGlaFromGpaHook(Hook, Address),
129  ZONE_WRITE,
130  &victim);
131  if (!INT_SUCCESS(status))
132  {
133  reason = introReasonInternalError;
134  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
135  exitAfterInformation = TRUE;
136  }
137 
138  if (exitAfterInformation)
139  {
140  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
141  }
142  else
143  {
144  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
145  }
146 
148 
150  {
151  IntWinHalSendAlert(&victim, &originator, *Action, reason);
152  }
153 
155 
156  return status;
157 }
158 
159 
160 static INTSTATUS
162  _In_opt_ void *Context,
163  _Inout_ HOOK_GPA *Hook,
164  _In_ QWORD Address,
165  _Out_ INTRO_ACTION *Action
166  )
181 {
182  INTSTATUS status;
183  QWORD gva;
184  EXCEPTION_KM_ORIGINATOR originator;
185  EXCEPTION_VICTIM_ZONE victim;
186  INTRO_ACTION_REASON reason;
187  PBYTE memoryArea;
188  DWORD memAreaLength;
189  DWORD csType;
190  DWORD instructionStart;
191  BOOLEAN foundVMCALL;
192  BYTE buffer[1] = { 0xC3 };
193  BOOLEAN exitAfterInformation = FALSE;
194 
195  UNREFERENCED_PARAMETER(Context);
196 
197  gva = IntHookGetGlaFromGpaHook(Hook, Address);
198  memoryArea = NULL;
199  memAreaLength = 0;
200  foundVMCALL = FALSE;
201  *Action = introGuestNotAllowed;
202  reason = introReasonNoException;
203 
204  LOG("[HAL] Code from hal heap (GVA 0x%016llx --- GPA 0x%016llx) has been executed from 0x%016llx.\n",
205  gva, Address, gVcpu->Regs.Rip
206  );
207 
208  status = IntGetCurrentMode(gVcpu->Index, &csType);
209  if (!INT_SUCCESS(status))
210  {
211  ERROR("[ERROR] IntGetCurrentMode failed: 0x%08x\n", status);
212  }
213 
214  // When there are multiple processors, IPIs are sent between them and real mode execution may occur.
215  // for now, allow these executions
216  // Also check cs type. If it's 16 bits it is probably the AP bootloader.
217  if ((gVcpu->Regs.Cr0 & CR0_PE) == 0 || csType == IG_CS_TYPE_16B)
218  {
219  TRACE("[HAL] Real mode execution detected.\n");
220  IntHookRemoveChain(Hook);
221  *Action = introGuestRetry;
222  return INT_STATUS_SUCCESS;
223  }
224 
225  // Allocate 2 pages, but only scan one. avoid problems with instructions spanned over 2 pages.
226  memoryArea = HpAllocWithTag(2 * PAGE_SIZE, IC_TAG_HAL_HEAP);
227  if (NULL == memoryArea)
228  {
229  goto no_vmcall;
230  }
231 
232  status = IntKernVirtMemRead(gva & PAGE_MASK, 2 * PAGE_SIZE, memoryArea, &memAreaLength);
233  if ((!INT_SUCCESS(status)) && (0 == memAreaLength))
234  {
235  WARNING("[WARNING] IntKernVirtMemRead failed: %08x\n", status);
237  goto no_vmcall;
238  }
239 
240  memAreaLength = MIN(memAreaLength, PAGE_SIZE);
241 
242  instructionStart = Address & PAGE_OFFSET;
243 
244  while (instructionStart < memAreaLength)
245  {
246  INSTRUX instrux;
247 
248  status = IntDecDecodeInstructionFromBuffer(memoryArea + instructionStart,
249  memAreaLength - instructionStart, csType, &instrux);
250  if (!INT_SUCCESS(status))
251  {
252  instructionStart++;
253  continue;
254  }
255 
256  if (ND_INS_VMCALL == instrux.Instruction)
257  {
258  foundVMCALL = TRUE;
259  break;
260  }
261 
262  instructionStart += instrux.Length;
263  }
264 
266 
267  // We found a VMCALL, suppose it is the hypercall page. disable the hook on this specific page.
268  if (foundVMCALL)
269  {
270  LOG("[HAL] Page %llx (physical %llx) seems to be the hypercall page. Will stop monitoring it...\n",
271  gva, Address);
272  IntHookRemoveChain(Hook);
273  *Action = introGuestRetry;
274  return INT_STATUS_SUCCESS;
275  }
276 
277 no_vmcall:
278  memzero(&victim, sizeof(victim));
279  memzero(&originator, sizeof(originator));
280 
282 
283  status = IntExceptKernelGetOriginator(&originator, 0);
284  if (status == INT_STATUS_EXCEPTION_BLOCK)
285  {
286  reason = introReasonNoException;
287  exitAfterInformation = TRUE;
288  }
289  else if (!INT_SUCCESS(status))
290  {
291  ERROR("[ERROR] IntExceptKernelGetOriginator failed: %08x\n", status);
292  reason = introReasonInternalError;
293  exitAfterInformation = TRUE;
294  }
295 
296  status = IntExceptGetVictimEpt(Hook, Address, gva, introObjectTypeHalHeap, ZONE_EXECUTE, &victim);
297  if (!INT_SUCCESS(status))
298  {
299  ERROR("[ERROR] IntExceptGetVictimEpt failed: %08x\n", status);
300  reason = introReasonInternalError;
301  exitAfterInformation = TRUE;
302  }
303 
304  if (exitAfterInformation)
305  {
306  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
307  }
308  else
309  {
310  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
311  }
312 
314 
316  {
317  EVENT_EPT_VIOLATION *pEptViol = &gAlert.Ept;
318  memzero(pEptViol, sizeof(*pEptViol));
319 
320  pEptViol->Header.Action = *Action;
321  pEptViol->Header.Reason = reason;
322  pEptViol->Header.MitreID = idExploitRemote;
323 
325 
326  IntAlertEptFillFromVictimZone(&victim, pEptViol);
327 
329 
330  IntAlertEptFillFromKmOriginator(&originator, pEptViol);
331 
332  // Do not fill code blocks, as there are not enough instructions (no code should normally be there)
333 
335  IntAlertFillVersionInfo(&pEptViol->Header);
337 
338  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
339  if (!INT_SUCCESS(status))
340  {
341  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
342  }
343  }
344 
346 
347  if (introGuestNotAllowed == *Action)
348  {
349  // Inject a ret instruction and let it execute
350  status = IntKernVirtMemWrite(gva, sizeof(buffer), buffer);
351  if (INT_SUCCESS(status))
352  {
353  LOG("[HAL] Injecting ret instruction @ GVA 0x%016llx\n", gva);
354  *Action = introGuestAllowed;
355  reason = introReasonAllowed;
356  }
357  else
358  {
359  ERROR("[ERROR] Could not inject ret! Status: %08x\n", status);
360  *Action = introGuestNotAllowed;
361  reason = introReasonNoException;
362  }
363  }
365  {
366  // Remove the hook if it was excepted. If we don't do this we will have an exit for every instruction in this
367  // chunk and we will have to except it every time.
368  IntHookRemoveChain(Hook);
369  *Action = introGuestRetry;
370  }
371 
372  return INT_STATUS_SUCCESS;
373 }
374 
375 
376 static INTSTATUS
378  _Inout_ PINTEGRITY_REGION IntegrityRegion
379  )
389 {
390  INTSTATUS status = INT_STATUS_SUCCESS;
391  BYTE const *pOriginal = NULL;
392  PBYTE pPage = NULL;
393  BOOLEAN bOnePage = FALSE;
394  INTRO_ACTION action;
395  INTRO_ACTION_REASON reason;
397 
398  pOriginal = IntegrityRegion->OriginalContent;
399  action = introGuestNotAllowed;
400  reason = introReasonUnknown;
401 
402  bOnePage =
403  (((IntegrityRegion->Gva + IntegrityRegion->Length - 1) & PAGE_MASK) == (IntegrityRegion->Gva & PAGE_MASK));
404 
405  status = IntVirtMemMap(IntegrityRegion->Gva, IntegrityRegion->Length, gGuest.Mm.SystemCr3, 0, &pPage);
406  if (!INT_SUCCESS(status))
407  {
408  ERROR("[ERROR] Failed to map GVA 0x%016llx: 0x%x\n", IntegrityRegion->Gva, status);
409  goto _cleanup_and_exit;
410  }
411 
412  for (DWORD offset = 0; offset < IntegrityRegion->Length; offset += gGuest.WordSize)
413  {
414  EXCEPTION_VICTIM_ZONE victim;
415  EXCEPTION_KM_ORIGINATOR originator;
416  QWORD originalValue = 0;
417  QWORD newValue = 0;
418 
419  if (gGuest.Guest64)
420  {
421  originalValue = *(QWORD *)((size_t)pOriginal + (size_t)offset);
422  newValue = *(QWORD *)((size_t)pPage + (size_t)offset);
423  }
424  else
425  {
426  originalValue = *(DWORD *)((size_t)pOriginal + (size_t)offset);
427  newValue = *(DWORD *)((size_t)pPage + (size_t)offset);
428  }
429 
430  if (newValue != originalValue)
431  {
432  DWORD currentOffset = offset;
433 
434  memzero(&victim, sizeof(victim));
435 
436  memzero(&originator, sizeof(originator));
437 
438  status = IntExceptGetVictimIntegrity(IntegrityRegion, &currentOffset, &victim);
439  if (!INT_SUCCESS(status))
440  {
441  ERROR("[ERROR] IntExceptGetVictimIntegrity failed: 0x%08x\n", status);
442  }
443 
444  status = IntExceptGetOriginatorFromModification(&victim, &originator);
445  if (!INT_SUCCESS(status))
446  {
447  TRACE("[INFO] IntExceptGetOriginatorFromModification failed: 0x%08x\n", status);
448  if (status == INT_STATUS_EXCEPTION_BLOCK)
449  {
450  action = introGuestNotAllowed;
451  reason = introReasonNoException;
452  }
453 
454  // don't propagate the error
455  status = INT_STATUS_SUCCESS;
456  }
457 
458  LOG("[INTEGRITY VIOLATION] HalDispatchTable modification at 0x%016llx : 0x%x "
459  "(index %d). New Value = 0x%016llx, Old Value = 0x%016llx\n",
460  IntegrityRegion->Gva, offset, offset / gGuest.WordSize, newValue, originalValue);
461 
462  if (isBeta)
463  {
464  LOG("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (B) ROOTKIT ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n");
465  }
466  else
467  {
468  LOG("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ROOTKIT ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n");
469  }
470 
471  if (!isBeta)
472  {
473  // restore the contents atomically
474  if (gGuest.Guest64)
475  {
476  _InterlockedExchange64((INT64 *)(pPage + offset), originalValue);
477  }
478  else
479  {
480  _InterlockedExchange((INT32 *)(pPage + offset), (INT32)originalValue);
481  }
482 
483  // This is needed because on multiple pages, pPage is not really a map to guest memory, it is
484  // memory copied from a GVA to an allocated HVA, so modifications on this will not reflect on
485  // guest if we don't write it explicitly
486  if (!bOnePage)
487  {
488  IntKernVirtMemWrite(IntegrityRegion->Gva + offset, gGuest.WordSize, pPage + offset);
489  }
490  }
491  else
492  {
493  action = introGuestAllowed;
494  // The action will be BETA detected, it will be allowed by default, so there is no use of
495  // specifying it in the reason while the BETA flag is specified in the alert.
496  reason = introReasonAllowed;
497 
498  // We let the modifications happen if BETA alerts are enabled and we don't want to SPAM the same
499  // alert every time.
500  status = IntIntegrityRecalculate(IntegrityRegion);
501  if (!INT_SUCCESS(status))
502  {
503  ERROR("[ERROR] IntIntegrityRecalculate failed: 0x%x\n", status);
504  status = INT_STATUS_SUCCESS; // don't propagate this error
505  }
506  }
507 
508  // send one alert for every modified pointer
509  {
511 
512  memzero(pIntViolation, sizeof(*pIntViolation));
513 
514  pIntViolation->Header.Action = action;
515  pIntViolation->Header.Reason = reason;
516  pIntViolation->Header.MitreID = idExploitPrivEsc;
517 
519  pIntViolation->Header.Flags |= ALERT_FLAG_ASYNC;
520 
521  pIntViolation->Header.CpuContext.Valid = FALSE;
522 
524 
526 
527  IntAlertFillWinKmModule(originator.Original.Driver, &pIntViolation->Originator.Module);
528 
529  memcpy(pIntViolation->Victim.Name, VICTIM_HAL_DISPATCH_TABLE, sizeof(VICTIM_HAL_DISPATCH_TABLE));
530 
531  pIntViolation->WriteInfo.Size = gGuest.WordSize;
532  pIntViolation->WriteInfo.OldValue[0] = originalValue;
533  pIntViolation->WriteInfo.NewValue[0] = newValue;
534 
535  pIntViolation->Size = gGuest.WordSize;
536  pIntViolation->BaseAddress = IntegrityRegion->Gva;
537  pIntViolation->VirtualAddress = IntegrityRegion->Gva + offset;
538 
539  IntAlertFillVersionInfo(&pIntViolation->Header);
540 
541  IntNotifyIntroEvent(introEventIntegrityViolation, pIntViolation, sizeof(*pIntViolation));
542  }
543  }
544  }
545 
546 _cleanup_and_exit:
547  if (NULL != pPage)
548  {
549  IntVirtMemUnmap(&pPage);
550  }
551 
552  return status;
553 }
554 
555 
556 static void
558  _In_ EXCEPTION_VICTIM_ZONE *Victim,
559  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
560  _In_ INTRO_ACTION Action,
562  )
571 {
572  INTSTATUS status;
574 
575  pIntViol = &gAlert.Integrity;
576  memzero(pIntViol, sizeof(*pIntViol));
577 
578  pIntViol->BaseAddress = Victim->Integrity.StartVirtualAddress;
579  pIntViol->VirtualAddress = Victim->Integrity.StartVirtualAddress + Victim->Integrity.Offset;
580  pIntViol->Victim.Type = Victim->Object.Type;
581  pIntViol->Size = Victim->Integrity.TotalLength;
582 
584 
585  // Force de-activation of ALERT_FLAG_NOT_RING0. We're always in ring0.
586  pIntViol->Header.Flags &= ~ALERT_FLAG_NOT_RING0;
587 
589  {
590  pIntViol->Header.Flags |= ALERT_FLAG_BETA;
591  }
592 
593  pIntViol->Header.Flags |= ALERT_FLAG_ASYNC;
594 
595  pIntViol->Header.Action = Action;
596  pIntViol->Header.Reason = Reason;
597  pIntViol->Header.MitreID = idRootkit;
598 
600 
601  IntAlertFillWriteInfo(Victim, &pIntViol->WriteInfo);
602 
603  IntAlertFillWinKmModule(Originator->Original.Driver, &pIntViol->Originator.Module);
604 
606 
607  // We can't know from what CPU the write was, but we know where the integrity check failed
608  pIntViol->Header.CpuContext.Valid = FALSE;
609 
611 
612  IntAlertFillVersionInfo(&pIntViol->Header);
613 
614  status = IntNotifyIntroEvent(introEventIntegrityViolation, pIntViol, sizeof(*pIntViol));
615  if (!INT_SUCCESS(status))
616  {
617  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
618  }
619 }
620 
621 
622 static INTSTATUS
624  _Inout_ INTEGRITY_REGION *IntegrityRegion
625  )
640 {
641  EXCEPTION_VICTIM_ZONE victim = { 0 };
642  EXCEPTION_KM_ORIGINATOR originator = { 0 };
643  INTSTATUS status;
644  DWORD offset = 0;
645  BOOLEAN exitAfterInformation = FALSE;
646  INTRO_ACTION_REASON reason;
647  INTRO_ACTION action;
648 
650 
651  action = introGuestNotAllowed;
652  reason = introReasonUnknown;
653 
654  status = IntExceptGetVictimIntegrity(IntegrityRegion, &offset, &victim);
655  if (!INT_SUCCESS(status))
656  {
657  ERROR("[ERROR] Failed getting integrity zone: 0x%08x\n", status);
658  reason = introReasonInternalError;
659  exitAfterInformation = TRUE;
660  }
661 
662  status = IntExceptGetOriginatorFromModification(&victim, &originator);
663  if (status == INT_STATUS_EXCEPTION_BLOCK)
664  {
665  reason = introReasonNoException;
666  exitAfterInformation = TRUE;
667  }
668  else if (!INT_SUCCESS(status))
669  {
670  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
671  reason = introReasonInternalError;
672  exitAfterInformation = TRUE;
673  }
674 
675  if (exitAfterInformation)
676  {
677  IntExceptKernelLogInformation(&victim, &originator, action, reason);
678  }
679  else
680  {
681  IntExcept(&victim, &originator, exceptionTypeKm, &action, &reason, introEventIntegrityViolation);
682  }
683 
685 
687  {
688  IntWinHalSendPerfCntIntegrityAlert(&victim, &originator, action, reason);
689  }
690 
692 
693  if (action == introGuestAllowed)
694  {
695  IntIntegrityRecalculate(IntegrityRegion);
696  }
697  else if (action == introGuestNotAllowed)
698  {
699  IntPauseVcpus();
700 
701  status = IntKernVirtMemWrite(gHalData.HalPerfCounterAddress + WIN_KM_FIELD(Ungrouped, HalPerfCntFunctionOffset),
703  IntegrityRegion->OriginalContent);
704  if (!INT_SUCCESS(status))
705  {
706  ERROR("[ERROR] IntKernVirtMemPatchWordSize failed: 0x%08x\n", status);
707  }
708 
709  IntResumeVcpus();
710  }
711 
712  return INT_STATUS_SUCCESS;
713 
714 }
715 
716 
717 INTSTATUS
719  void
720  )
733 {
734  INTSTATUS status;
735  QWORD hookAddrStart, hookAddrEnd;
736 
737  if (gHalData.HalHeapExecHook != NULL)
738  {
740  }
741 
742  // The HalHeap is not initialized, no need to hook it.
743  if (0 == gHalData.HalHeapAddress)
744  {
746  }
747 
748  TRACE("[HAL] Adding Hal Heap hook at %llx...\n", gHalData.HalHeapAddress);
749 
750  hookAddrStart = gHalData.HalHeapAddress;
751  hookAddrEnd = hookAddrStart + gHalData.HalHeapSize;
752 
754  if (!INT_SUCCESS(status))
755  {
756  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
757  return status;
758  }
759 
760  for (QWORD gva = hookAddrStart; gva < hookAddrEnd; gva += PAGE_SIZE)
761  {
762  BYTE r, w, x;
763  QWORD gpa = 0;
764 
765  status = IntTranslateVirtualAddress(gva, gGuest.Mm.SystemCr3, &gpa);
766  if (!INT_SUCCESS(status))
767  {
768  WARNING("[WARNING] Cannot protect hal heap page 0x%016llx\n", gva);
769  continue;
770  }
771 
772  status = IntGetEPTPageProtection(gGuest.UntrustedEptIndex, gpa, &r, &w, &x);
773  if (!INT_SUCCESS(status))
774  {
775  WARNING("[WARNING] Cannot protect hal heap page 0x%016llx (GPA 0x%016llx)\n", gva, gpa);
776  continue;
777  }
778 
779  if (gpa < PAGE_SIZE)
780  {
781  WARNING("[WARNING] Will not protect hal heap page 0x%016llx because it translates to physical page 0\n",
782  gva);
783  continue;
784  }
785 
786  status = IntHookObjectHookRegion(gHalData.HalHeapExecHook,
787  0,
788  gva,
789  PAGE_SIZE,
792  NULL,
793  0,
794  NULL);
795 
796  if (!INT_SUCCESS(status))
797  {
798  ERROR("[ERROR] IntHookObjectHookRegion failed: %08x Region (0x%016llx, 0x%016llx)\n",
799  status, gva, gva + PAGE_SIZE);
800  }
801  else
802  {
803  TRACE("[HAL] Hooking region (0x%016llx, 0x%016llx) against executions\n", gva, gva + PAGE_SIZE);
804  }
805  }
806 
807  return INT_STATUS_SUCCESS;
808 }
809 
810 
811 INTSTATUS
813  void
814  )
820 {
821  INTSTATUS status;
822 
823  if (gHalData.HalHeapExecHook == NULL)
824  {
826  }
827 
828  TRACE("[HAL] Removing Hal Heap hook...\n");
829 
831 
832  return status;
833 }
834 
835 
836 INTSTATUS
838  void
839  )
847 {
848  INTSTATUS status;
849 
850  if (gHalData.HalIntCtrlWriteHook != NULL)
851  {
853  }
854 
855  if (0 == gHalData.HalIntCtrlAddress)
856  {
858  }
859 
860  TRACE("[HAL] Adding Hal Interrupt Controller hook at %llx...\n", gHalData.HalIntCtrlAddress);
861 
863  if (!INT_SUCCESS(status))
864  {
865  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
866  return status;
867  }
868 
870  0,
871  gHalData.HalIntCtrlAddress,
872  WIN_KM_FIELD(Ungrouped, HalIntCtrlType),
875  gHalData.OwnerHalModule,
876  0,
877  NULL);
878  if (!INT_SUCCESS(status))
879  {
880  ERROR("[ERROR] IntHookObjectHookRegion failed: 0x%08x\n", status);
881  return status;
882  }
883 
884  return status;
885 }
886 
887 
888 INTSTATUS
890  void
891  )
897 {
898  INTSTATUS status;
899 
900  if (gHalData.HalIntCtrlWriteHook == NULL)
901  {
903  }
904 
905  TRACE("[HAL] Removing Hal Interrupt Controller hook...\n");
906 
908 
909  return status;
910 }
911 
912 
913 INTSTATUS
915  void
916  )
924 {
925  INTSTATUS status;
926 
927  if (gHalData.HalDispatchIntegrityHook != NULL)
928  {
930  }
931 
932  if (0 == gHalData.HalDispatchTableAddress)
933  {
935  }
936 
937  TRACE("[HAL] Adding HalDispatchTable hook at %llx...\n", gHalData.HalDispatchTableAddress);
938 
940  gHalData.HalDispatchTableSize,
942  NULL,
944  TRUE,
945  &gHalData.HalDispatchIntegrityHook);
946  if (!INT_SUCCESS(status))
947  {
948  ERROR("[ERROR] IntIntegrityAddRegion failed: 0x%x\n", status);
949  return status;
950  }
951 
952  return INT_STATUS_SUCCESS;
953 }
954 
955 
956 INTSTATUS
958  void
959  )
965 {
966  INTSTATUS status;
967 
968  if (gHalData.HalDispatchIntegrityHook == NULL)
969  {
971  }
972 
973  TRACE("[HAL] Removing Hal Dispatch Table hook...\n");
974 
976  if (!INT_SUCCESS(status))
977  {
978  ERROR("[ERROR] IntIntegrityRemoveRegion failed with status: 0x%08X\n", status);
979  return status;
980  }
981 
982  gHalData.HalDispatchIntegrityHook = NULL;
983 
984  return status;
985 }
986 
987 
988 INTSTATUS
990  void
991  )
1002 {
1003  INTSTATUS status;
1004 
1005  if (gHalData.HalPerfIntegrityObj != NULL)
1006  {
1008  }
1009 
1010  if (0 == gHalData.HalPerfCounterAddress)
1011  {
1013  }
1014 
1015  TRACE("[HAL] Adding HalPerformanceCounter hook at %llx...\n", gHalData.HalPerfCounterAddress);
1016 
1017  status = IntIntegrityAddRegion(gHalData.HalPerfCounterAddress + WIN_KM_FIELD(Ungrouped, HalPerfCntFunctionOffset),
1018  gGuest.WordSize,
1020  NULL,
1022  TRUE,
1023  &gHalData.HalPerfIntegrityObj);
1024  if (!INT_SUCCESS(status))
1025  {
1026  ERROR("[ERROR] IntIntegrityAddRegion failed: 0x%x\n", status);
1027  return status;
1028  }
1029 
1030  return INT_STATUS_SUCCESS;
1031 }
1032 
1033 
1034 INTSTATUS
1036  void
1037  )
1044 {
1045  INTSTATUS status;
1046 
1047  if (gHalData.HalPerfIntegrityObj == NULL)
1048  {
1050  }
1051 
1052  TRACE("[HAL] Removing HalPerformanceCounter hook...\n");
1053 
1054  status = IntIntegrityRemoveRegion(gHalData.HalPerfIntegrityObj);
1055  if (!INT_SUCCESS(status))
1056  {
1057  ERROR("[ERROR] IntIntegrityRemoveRegion failed: 0x%08X\n", status);
1058  return status;
1059  }
1060 
1061  gHalData.HalPerfIntegrityObj = NULL;
1062 
1063  return status;
1064 }
1065 
1066 
1067 static BOOLEAN
1069  _In_ QWORD CheckedAddress,
1070  _In_ QWORD HalHeap
1071  )
1086 {
1087 #define MAX_INT_CTRL_COUNT 20
1088 
1089  INTSTATUS status;
1090  QWORD functionPointer;
1091  QWORD functionOffset;
1092 
1093  QWORD initialInterruptController = 0;
1094  QWORD halFunction = 0;
1095  QWORD entriesOutsideTheHalHeap = 0;
1096 
1097  QWORD maxInterruptControllerCount = MAX_INT_CTRL_COUNT;
1098  BOOLEAN isListEntry = FALSE;
1099 
1100  // 1. First structure is a LIST_ENTRY structure.
1101  // All checked systems have at least 2 available controllers - we now have to validate that we actually
1102  // have a list.
1103  initialInterruptController = CheckedAddress;
1104  while (maxInterruptControllerCount)
1105  {
1106  status = IntKernVirtMemRead(initialInterruptController, gGuest.WordSize, &initialInterruptController, NULL);
1107  if (!INT_SUCCESS(status))
1108  {
1109  return FALSE;
1110  }
1111 
1112  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, initialInterruptController))
1113  {
1114  return FALSE;
1115  }
1116 
1117  if (initialInterruptController < HalHeap)
1118  {
1119  // Sometimes the ListHead is not situated on the HalHeap itself - we are only going to allow 1 entry
1120  // outside the Hal Heap.
1121  entriesOutsideTheHalHeap++;
1122  }
1123 
1124  if (CheckedAddress == initialInterruptController && entriesOutsideTheHalHeap <= 1)
1125  {
1126  isListEntry = TRUE;
1127  break;
1128  }
1129 
1130  maxInterruptControllerCount--;
1131  }
1132 
1133  if (!isListEntry)
1134  {
1135  return FALSE;
1136  }
1137 
1138  // 2. At offset WordSize * 4 starts an area of pointers to functions in hal.dll or nt, mixed with 0's
1139  // The list of functions spans until the type (2).
1140  BOOLEAN foundFunctions = FALSE;
1141  for (functionPointer = CheckedAddress + 4ull * gGuest.WordSize;
1142  functionPointer <= CheckedAddress + WIN_KM_FIELD(Ungrouped, HalIntCtrlTypeMaxOffset);
1143  functionPointer += gGuest.WordSize)
1144  {
1145  status = IntKernVirtMemRead(functionPointer, gGuest.WordSize, &halFunction, NULL);
1146  if (!INT_SUCCESS(status))
1147  {
1148  return FALSE;
1149  }
1150 
1151  if (0 == halFunction)
1152  {
1153  foundFunctions = TRUE;
1154  continue;
1155  }
1156 
1157  // 3. The type must be 2
1158  if (foundFunctions && (2 == (DWORD)halFunction))
1159  {
1160  break;
1161  }
1162 
1163  if (((halFunction < gHalData.OwnerHalModule->BaseVa) ||
1164  (halFunction > gHalData.OwnerHalModule->BaseVa + gHalData.OwnerHalModule->Size)) &&
1165  ((halFunction < gGuest.KernelVa) || (halFunction > gGuest.KernelVa + gGuest.KernelSize)))
1166  {
1167  return FALSE;
1168  }
1169 
1170  foundFunctions = TRUE;
1171  }
1172 
1173  if (!foundFunctions || 2 != (DWORD)halFunction)
1174  {
1175  return FALSE;
1176  }
1177 
1178  functionOffset = functionPointer - CheckedAddress;
1179  if (functionOffset < WIN_KM_FIELD(Ungrouped, HalIntCtrlTypeMinOffset) ||
1180  functionOffset > WIN_KM_FIELD(Ungrouped, HalIntCtrlTypeMaxOffset))
1181  {
1182  return FALSE;
1183  }
1184 
1185  WIN_KM_FIELD(Ungrouped, HalIntCtrlType) = (DWORD)functionOffset;
1186 
1187  return TRUE;
1188 
1189 #undef MAX_INT_CTRL_COUNT
1190 #undef MAX_INT_CTRL_TYPE_OFFSET
1191 #undef MIN_INT_CTRL_TYPE_OFFSET
1192 }
1193 
1194 
1195 BOOLEAN
1197  _In_ QWORD HalPerfCandidate
1198  )
1213 {
1214 #define MAX_LIST_ITERATIONS_HAL_PERF 20
1215  QWORD nextList;
1216  DWORD numberOfOutsideHalHeap = 0;
1217  QWORD halPerfFunctionPtr = 0;
1218  BOOLEAN foundList = FALSE;
1219  INTSTATUS status;
1220 
1221  if (HalPerfCandidate < gHalData.HalHeapAddress ||
1222  HalPerfCandidate >= gHalData.HalHeapAddress + gHalData.HalHeapSize)
1223  {
1224  return FALSE;
1225  }
1226 
1227  nextList = HalPerfCandidate;
1228 
1229  for (DWORD i = 0; i < MAX_LIST_ITERATIONS_HAL_PERF; i++)
1230  {
1231  status = IntKernVirtMemFetchWordSize(nextList, &nextList);
1232  if (!INT_SUCCESS(status))
1233  {
1234  return FALSE;
1235  }
1236 
1237  if (nextList < gHalData.HalHeapAddress ||
1238  nextList >= gHalData.HalHeapAddress + gHalData.HalHeapSize)
1239  {
1240  numberOfOutsideHalHeap++;
1241  }
1242 
1243  if (numberOfOutsideHalHeap > 1)
1244  {
1245  return FALSE;
1246  }
1247 
1248  if (nextList == HalPerfCandidate)
1249  {
1250  foundList = TRUE;
1251  break;
1252  }
1253  }
1254 
1255  if (!foundList)
1256  {
1257  return FALSE;
1258  }
1259 
1260  status = IntKernVirtMemFetchWordSize(HalPerfCandidate + WIN_KM_FIELD(Ungrouped, HalPerfCntFunctionOffset),
1261  &halPerfFunctionPtr);
1262  if (!INT_SUCCESS(status))
1263  {
1264  return FALSE;
1265  }
1266 
1267  if (halPerfFunctionPtr < gHalData.OwnerHalModule->BaseVa ||
1268  halPerfFunctionPtr >= gHalData.OwnerHalModule->BaseVa + gHalData.OwnerHalModule->Size)
1269  {
1270  return FALSE;
1271  }
1272 
1273  return TRUE;
1274 
1275 #undef MAX_LIST_ITERATIONS_HAL_PERF
1276 }
1277 
1278 
1279 static INTSTATUS
1281  void
1282  )
1299 {
1300 #define MAX_INSTRUCTIONS_SEARCH 10
1301  DWORD rva;
1302  INTSTATUS status;
1303  INSTRUX instrux = { 0 };
1305  QWORD halPerfPtr = 0;
1306  BYTE *buff;
1307  DWORD buffSize;
1308  QWORD currentRip = 0;
1309  QWORD instruxOffset = 0;
1310 
1311  if (gGuest.KernelVa == gHalData.OwnerHalModule->BaseVa)
1312  {
1313  buff = gWinGuest->KernelBuffer;
1314  buffSize = gWinGuest->KernelBufferSize;
1315  }
1316  else
1317  {
1318  buff = gHalData.HalBuffer;
1319  buffSize = gHalData.HalBufferSize;
1320  }
1321 
1323  buff,
1324  buffSize,
1325  "KeQueryPerformanceCounter",
1326  &rva);
1327 
1328  if (!INT_SUCCESS(status))
1329  {
1330  ERROR("[ERROR] IntPeFindExportByName failed: 0x%08x\n", status);
1331  return status;
1332  }
1333 
1334  currentRip = gHalData.OwnerHalModule->BaseVa + rva;
1335  instruxOffset = rva;
1336 
1337  for (size_t i = 0; i < MAX_INSTRUCTIONS_SEARCH; i++)
1338  {
1339  if (instruxOffset + ND_MAX_INSTRUCTION_LENGTH >= buffSize)
1340  {
1341  ERROR("[ERROR] The instruction at 0x%016llx resides outside the buffer!", currentRip);
1343  }
1344 
1345  status = IntDecDecodeInstructionFromBuffer(buff + instruxOffset,
1346  buffSize - instruxOffset,
1347  csType,
1348  &instrux);
1349  if (!INT_SUCCESS(status))
1350  {
1351  ERROR("[ERROR] IntDecDecodeInstructionFromBuffer failed: 0x%08x\n", status);
1352  return status;
1353  }
1354 
1355  currentRip += instrux.Length;
1356  instruxOffset += instrux.Length;
1357 
1358  if (instrux.Instruction == ND_INS_MOV &&
1359  instrux.ExpOperandsCount == 2 &&
1360  instrux.Operands[1].Type == ND_OP_MEM)
1361  {
1362  QWORD possibleHalPerf = 0;
1363 
1364  // On x64 instruction is of the form mov reg, [rip relative address]
1365  if (gGuest.Guest64 && !instrux.Operands[1].Info.Memory.IsRipRel)
1366  {
1367  continue;
1368  }
1369 
1370  // On x86 instruction is of the form mov reg, [address]. Note that address is the displacement
1371  // and the instruction is not considered to use absolute addresses, so IsDirect is not set.
1372  if (!gGuest.Guest64 &&
1373  (instrux.Operands[1].Info.Memory.HasBase ||
1374  instrux.Operands[1].Info.Memory.HasIndex ||
1375  !instrux.Operands[1].Info.Memory.HasDisp))
1376  {
1377  continue;
1378  }
1379 
1380  if (instrux.Operands[1].Info.Memory.IsRipRel)
1381  {
1382  halPerfPtr = currentRip + instrux.Operands[1].Info.Memory.Disp;
1383  }
1384  else
1385  {
1386  halPerfPtr = instrux.Operands[1].Info.Memory.Disp;
1387  }
1388 
1389  status = IntKernVirtMemFetchWordSize(halPerfPtr, &possibleHalPerf);
1390  if (!INT_SUCCESS(status))
1391  {
1392  WARNING("[WARNING] IntKernVirtMemFetchWordSize failed: 0x%08x\n", status);
1393  continue;
1394  }
1395 
1396  if (!IntWinHalIsHalPerf(possibleHalPerf))
1397  {
1398  continue;
1399  }
1400 
1401  TRACE("[INFO] Found HalPerformanceCounter at 0x%016llx!\n", possibleHalPerf);
1402 
1403  gHalData.HalPerfCounterAddress = possibleHalPerf;
1404 
1405  break;
1406  }
1407  }
1408 
1409  if (0 == gHalData.HalPerfCounterAddress)
1410  {
1411  return INT_STATUS_NOT_FOUND;
1412  }
1413 
1415  {
1416  status = IntWinHalProtectHalPerfCounter();
1417  if (!INT_SUCCESS(status))
1418  {
1419  ERROR("[ERROR] IntWinHalProtectHalPerfCounter failed: 0x%08x\n", status);
1420  }
1421  }
1422 
1423  return status;
1424 #undef MAX_INSTRUCTIONS_SEARCH
1425 }
1426 
1427 
1428 static INTSTATUS
1430  void
1431  )
1441 {
1442  INTSTATUS status;
1443 
1445  if (!INT_SUCCESS(status))
1446  {
1447  ERROR("[ERROR] IntWinHalFindPerformanceCounterInternal failed: 0x%08x\n", status);
1448  }
1449 
1450  return status;
1451 }
1452 
1453 
1454 static void
1456  void
1457  )
1464 {
1465  INTSTATUS status;
1466  LIST_ENTRY *initEntry;
1467 
1468  if (NULL != gHalData.HalHdrSwapHandle)
1469  {
1470  status = IntSwapMemRemoveTransaction(gHalData.HalHdrSwapHandle);
1471  if (!INT_SUCCESS(status))
1472  {
1473  ERROR("[ERROR] IntSwapMemRemoveTransaction failed for HAL headers: 0x%08x\n", status);
1474  }
1475 
1476  gHalData.HalHdrSwapHandle = NULL;
1477  }
1478 
1479  if (NULL == gHalData.HalBuffer)
1480  {
1481  return;
1482  }
1483 
1484  initEntry = gHalData.InitSwapHandles.Flink;
1485  while (initEntry != &gHalData.InitSwapHandles)
1486  {
1487  PWIN_INIT_SWAP pInitSwap = CONTAINING_RECORD(initEntry, WIN_INIT_SWAP, Link);
1488  initEntry = initEntry->Flink;
1489 
1490  status = IntSwapMemRemoveTransaction(pInitSwap->SwapHandle);
1491  if (!INT_SUCCESS(status))
1492  {
1493  ERROR("[ERROR] IntSwapMemRemoveTransaction failed for %llx:%x: 0x%08x\n",
1494  pInitSwap->VirtualAddress, pInitSwap->Size, status);
1495  }
1496 
1497  RemoveEntryList(&pInitSwap->Link);
1498 
1499  HpFreeAndNullWithTag(&pInitSwap, IC_TAG_WSWP);
1500  }
1501 }
1502 
1503 
1504 static INTSTATUS
1506  _Inout_ WIN_INIT_SWAP *Context,
1507  _In_ QWORD Cr3,
1508  _In_ QWORD VirtualAddress,
1509  _In_ QWORD PhysicalAddress,
1510  _In_reads_bytes_(DataSize) void *Data,
1511  _In_ DWORD DataSize,
1512  _In_ DWORD Flags
1513  )
1537 {
1538  PWIN_INIT_SWAP pSwp;
1539  QWORD va;
1540  INTSTATUS status;
1541 
1543  UNREFERENCED_PARAMETER(VirtualAddress);
1544  UNREFERENCED_PARAMETER(PhysicalAddress);
1545 
1546  if (Flags & SWAPMEM_FLAG_ASYNC_CALL)
1547  {
1548  IntPauseVcpus();
1549  }
1550 
1551  status = INT_STATUS_SUCCESS;
1552 
1553  pSwp = Context;
1554  va = pSwp->VirtualAddress;
1555 
1556  // Remove the context. The caller knows this may happen & won't use it after IntSwapMemReadData
1557  RemoveEntryList(&pSwp->Link);
1559 
1560  if (0 == gHalData.RemainingSections)
1561  {
1562  ERROR("[ERROR] Callback came after we have no more sections to read...\n");
1564  goto resume_and_exit;
1565  }
1566 
1567  memcpy(gHalData.HalBuffer + va, Data, DataSize);
1568 
1569  gHalData.RemainingSections--;
1570 
1571  if ((0 == gHalData.RemainingSections) && (Flags & SWAPMEM_FLAG_ASYNC_CALL))
1572  {
1573  TRACE("[HAL] All sections from hal were read into buffer\n");
1574 
1575  status = IntWinHalFinishRead();
1576  if (!INT_SUCCESS(status))
1577  {
1578  ERROR("[ERROR] IntWinHalFinishRead failed: 0x%08x\n", status);
1579  }
1580  }
1581 
1582 resume_and_exit:
1583  if (Flags & SWAPMEM_FLAG_ASYNC_CALL)
1584  {
1585  IntResumeVcpus();
1586  }
1587 
1588  return status;
1589 }
1590 
1591 
1592 static INTSTATUS
1594  void
1595  )
1614 {
1615  INTSTATUS status;
1616  INTRO_PE_INFO peInfo = { 0 };
1617  DWORD secCount, secStartOffset;
1618  IMAGE_DOS_HEADER *pDosHeader = (IMAGE_DOS_HEADER *)gHalData.OwnerHalModule->Win.MzPeHeaders;
1619 
1620  // NOTE: The headers will always be valid here; they are either read in IntWinDrvProtect, if HAL protection is
1621  // enabled, or by IntWinHalFindPerformanceCounter, if HAL protection is off.
1622 
1624 
1625  status = IntPeValidateHeader(gHalData.OwnerHalModule->BaseVa,
1626  (BYTE *)pDosHeader,
1627  PAGE_SIZE,
1628  &peInfo,
1629  0);
1630  if (!INT_SUCCESS(status))
1631  {
1632  ERROR("[ERROR] IntPeValidateHeader failed: 0x%08x\n", status);
1633  return status;
1634  }
1635 
1636  if (gGuest.Guest64 != peInfo.Image64Bit)
1637  {
1638  ERROR("[ERROR] Inconsistent MZPE image!\n");
1640  }
1641 
1642  if (peInfo.Image64Bit)
1643  {
1644  PIMAGE_NT_HEADERS64 pNth64;
1645  BOOLEAN unmapNtHeaders = FALSE;
1646 
1647  if ((QWORD)(DWORD)pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64) < PAGE_SIZE)
1648  {
1649  // We are in the same page, so it's safe to use this
1650  pNth64 = (PIMAGE_NT_HEADERS64)((size_t)pDosHeader + pDosHeader->e_lfanew);
1651  }
1652  else
1653  {
1654  status = IntVirtMemMap(gHalData.OwnerHalModule->BaseVa + pDosHeader->e_lfanew, sizeof(*pNth64),
1655  gGuest.Mm.SystemCr3, 0, &pNth64);
1656  if (!INT_SUCCESS(status))
1657  {
1658  ERROR("[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n",
1659  gHalData.OwnerHalModule->BaseVa + pDosHeader->e_lfanew, status);
1660  return status;
1661  }
1662 
1663  unmapNtHeaders = TRUE;
1664  }
1665 
1666  secCount = 0xffff & pNth64->FileHeader.NumberOfSections;
1667  secStartOffset = pDosHeader->e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) +
1669 
1670  if (unmapNtHeaders)
1671  {
1672  IntVirtMemUnmap(&pNth64);
1673  }
1674  }
1675  else
1676  {
1677  PIMAGE_NT_HEADERS32 pNth32;
1678  BOOLEAN unmapNtHeaders = FALSE;
1679 
1680  if ((QWORD)(DWORD)pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32) < PAGE_SIZE)
1681  {
1682  // We are in the same page, so it's safe to use this
1683  pNth32 = (PIMAGE_NT_HEADERS32)((size_t)pDosHeader + pDosHeader->e_lfanew);
1684  }
1685  else
1686  {
1687  status = IntVirtMemMap(gHalData.OwnerHalModule->BaseVa + pDosHeader->e_lfanew, sizeof(*pNth32),
1688  gGuest.Mm.SystemCr3, 0, &pNth32);
1689  if (!INT_SUCCESS(status))
1690  {
1691  ERROR("[ERROR] Failed mapping VA 0x%016llx to host: 0x%08x\n",
1692  gGuest.KernelVa + pDosHeader->e_lfanew, status);
1693  return status;
1694  }
1695 
1696  unmapNtHeaders = TRUE;
1697  }
1698 
1699  secCount = 0xffff & pNth32->FileHeader.NumberOfSections;
1700  secStartOffset = pDosHeader->e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) +
1702 
1703  if (unmapNtHeaders)
1704  {
1705  IntVirtMemUnmap(&pNth32);
1706  }
1707  }
1708 
1709  if (secStartOffset >= PAGE_SIZE)
1710  {
1711  ERROR("[ERROR] Sections get outside the first page. We don't support this yet!\n");
1712  return INT_STATUS_NOT_SUPPORTED;
1713  }
1714 
1715  if (secStartOffset + secCount * sizeof(IMAGE_SECTION_HEADER) > PAGE_SIZE)
1716  {
1717  ERROR("[ERROR] Sections get outside the first page. We don't support this yet!\n");
1718  return INT_STATUS_NOT_SUPPORTED;
1719  }
1720 
1721  if (peInfo.SizeOfImage < PAGE_SIZE)
1722  {
1723  ERROR("[ERROR] SizeOfImage too small: %d!\n", peInfo.SizeOfImage);
1725  }
1726 
1727  gHalData.HalBufferSize = peInfo.SizeOfImage;
1728  gHalData.HalBuffer = HpAllocWithTag(peInfo.SizeOfImage, IC_TAG_HALB);
1729  if (NULL == gHalData.HalBuffer)
1730  {
1732  }
1733 
1734  memcpy(gHalData.HalBuffer, gHalData.OwnerHalModule->Win.MzPeHeaders, PAGE_SIZE);
1735 
1736  gHalData.RemainingSections = secCount;
1737 
1738  for (DWORD i = 0; i < secCount; i++)
1739  {
1740  DWORD secActualSize;
1741 
1742  PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)(gHalData.HalBuffer + secStartOffset +
1743  i * sizeof(IMAGE_SECTION_HEADER));
1744 
1745  secActualSize = ROUND_UP(pSec->Misc.VirtualSize, PAGE_SIZE);
1746 
1747  if (0 == pSec->VirtualAddress)
1748  {
1749  ERROR("[ERROR] We cannot have a section starting at 0!\n");
1750 
1751  return INT_STATUS_NOT_SUPPORTED;
1752  }
1753 
1754  if (0 == pSec->Misc.VirtualSize)
1755  {
1756  ERROR("[ERROR] We cannot have a section starting at 0!\n");
1757 
1758  return INT_STATUS_NOT_SUPPORTED;
1759  }
1760 
1761  // Make sure the section fits within the allocated buffer. We must avoid cases where the SizeOfImage or
1762  // section headers are maliciously altered.
1763  if ((pSec->VirtualAddress >= peInfo.SizeOfImage) ||
1764  (secActualSize > peInfo.SizeOfImage) ||
1765  (pSec->VirtualAddress + secActualSize > peInfo.SizeOfImage))
1766  {
1767  ERROR("[ERROR] Section %d seems corrupted: sizeOfImage = 0x%x, secstart = 0x%x, secsize = 0x%x\n",
1768  i, peInfo.SizeOfImage, pSec->VirtualAddress, pSec->Misc.VirtualSize);
1769 
1771  }
1772 
1774  {
1775  memset(gHalData.HalBuffer + pSec->VirtualAddress, 0, secActualSize);
1776 
1777  gHalData.RemainingSections--;
1778  }
1779  else if (pSec->Characteristics & IMAGE_SCN_MEM_NOT_PAGED)
1780  {
1781  // The section will be present, so read it now
1782  status = IntKernVirtMemRead(gHalData.OwnerHalModule->BaseVa + pSec->VirtualAddress,
1783  secActualSize,
1784  gHalData.HalBuffer + pSec->VirtualAddress,
1785  NULL);
1786  if (!INT_SUCCESS(status))
1787  {
1788  ERROR("[ERROR] IntKernVirtMemRead failed for 0x%016llx -> 0x%016llx %s: 0x%08x\n",
1789  gHalData.OwnerHalModule->BaseVa + pSec->VirtualAddress,
1790  gHalData.OwnerHalModule->BaseVa + pSec->VirtualAddress + secActualSize,
1791  pSec->Name, status);
1792 
1793  return status;
1794  }
1795 
1796  gHalData.RemainingSections--;
1797  }
1798  else
1799  {
1800  DWORD retSize = 0;
1801 
1802  // Use the swap mechanism only if we can't directly read the memory; this avoids unnecessary
1803  // recursive function calls.
1804  status = IntKernVirtMemRead(gHalData.OwnerHalModule->BaseVa + pSec->VirtualAddress,
1805  secActualSize,
1806  gHalData.HalBuffer + pSec->VirtualAddress,
1807  &retSize);
1808  if (!INT_SUCCESS(status))
1809  {
1810  PWIN_INIT_SWAP pSwp = NULL;
1811  void *swapHandle = NULL;
1812 
1813  pSwp = HpAllocWithTag(sizeof(*pSwp), IC_TAG_WSWP);
1814  if (NULL == pSwp)
1815  {
1817  }
1818 
1819  pSwp->VirtualAddress = pSec->VirtualAddress;
1820  pSwp->Size = secActualSize;
1821 
1822  InsertTailList(&gHalData.InitSwapHandles, &pSwp->Link);
1823 
1824  WARNING("Section %d / %d is not in memory, will do a swap mem read\n", i, secCount);
1825 
1826  status = IntSwapMemReadData(0,
1827  gHalData.OwnerHalModule->BaseVa + pSec->VirtualAddress,
1828  secActualSize,
1830  pSwp,
1831  0,
1833  NULL,
1834  &swapHandle);
1835  if (!INT_SUCCESS(status))
1836  {
1837  ERROR("[ERROR] IntSwapMemReadData failed: 0x%08x\n", status);
1838  return status;
1839  }
1840 
1841  // The callback will be called async, save the handle in case an uninit will come
1842  if (NULL != swapHandle)
1843  {
1844  pSwp->SwapHandle = swapHandle;
1845  }
1846  }
1847  else
1848  {
1849  if (retSize != secActualSize)
1850  {
1851  ERROR("We requested %08x bytes, but got %08x!\n", secActualSize, retSize);
1853  }
1854 
1855  gHalData.RemainingSections--;
1856  }
1857  }
1858  }
1859 
1860  // We managed to read everything here, so continue the initialization
1861  if (0 == gHalData.RemainingSections)
1862  {
1863  TRACE("[HAL] All sections were present in memory!\n");
1864 
1865  status = IntWinHalFinishRead();
1866  if (!INT_SUCCESS(status))
1867  {
1868  ERROR("[ERROR] IntWinHalFinishRead failed: 0x%08x\n", status);
1869  }
1870  }
1871 
1872  return status;
1873 }
1874 
1875 
1876 static INTSTATUS
1878  _In_ void *Context,
1879  _In_ QWORD Cr3,
1880  _In_ QWORD VirtualAddress,
1881  _In_ QWORD PhysicalAddress,
1882  _In_reads_bytes_(DataSize) void *Data,
1883  _In_ DWORD DataSize,
1884  _In_ DWORD Flags
1885 )
1900 {
1901  KERNEL_DRIVER *pDriver;
1902 
1904  UNREFERENCED_PARAMETER(VirtualAddress);
1905  UNREFERENCED_PARAMETER(PhysicalAddress);
1906  UNREFERENCED_PARAMETER(Flags);
1907  UNREFERENCED_PARAMETER(DataSize);
1908 
1909  pDriver = Context;
1910 
1911  gHalData.HalHdrSwapHandle = NULL;
1912 
1913  // Just in case someone already allocated the headers.
1914  if (NULL == pDriver->Win.MzPeHeaders)
1915  {
1917  if (NULL == pDriver->Win.MzPeHeaders)
1918  {
1920  }
1921  }
1922 
1923  // Copy the headers internally.
1924  memcpy(pDriver->Win.MzPeHeaders, Data, PAGE_SIZE);
1925 
1926  return IntWinHalReadHal();
1927 }
1928 
1929 
1930 static INTSTATUS
1932  void
1933  )
1947 {
1948  if (gHalData.OwnerHalModule->BaseVa == gGuest.KernelVa)
1949  {
1951  }
1952  else
1953  {
1954  // If the headers have already been read, proceed with reading the rest of the HAL. Otherwise, read the headers
1955  // first, using IntSwapMemReadData (they may be, theoretically, swapped out).
1956  if (gHalData.OwnerHalModule->Win.MzPeHeaders != NULL)
1957  {
1958  return IntWinHalReadHal();
1959  }
1960  else
1961  {
1962  // NOTE: Since a read may already be pending (or HAL protection may be activated in between), we cannot
1963  // use the same swap object (the one located in the module object) for both this read and the protection
1964  // read, since we will end up with a use-after-free.
1966  gHalData.OwnerHalModule, 0, IntWinHalHeadersInMemory, NULL,
1967  &gHalData.HalHdrSwapHandle);
1968  }
1969  }
1970 }
1971 
1972 
1973 static INTSTATUS
1975  _In_ QWORD HalHeap,
1976  _In_ QWORD HalHeapSize,
1977  _Out_ QWORD *HalInterruptController
1978  )
1992 {
1993  INTSTATUS status;
1994  IMAGE_SECTION_HEADER dataSec = { 0 };
1995  DWORD nrSec = 0;
1996  QWORD halIntCtrlGva = 0;
1997  void *dataSectionMem = NULL;
1998 
2000  ".data", 1, gGuest.Mm.SystemCr3, &dataSec, &nrSec);
2001  if (!INT_SUCCESS(status) || nrSec == 0)
2002  {
2003  ERROR("[ERROR] IntPeGetSectionHeadersByName failed: 0x%08x, number of sections: %d\n", status, nrSec);
2004  // status may be a successful one, but if no sections were found we return an error status to signal that
2005  // HalInterruptController is not valid
2006  status = INT_STATUS_NOT_FOUND;
2007  goto exit;
2008  }
2009 
2010  if (dataSec.Misc.VirtualSize < gGuest.WordSize || dataSec.Misc.VirtualSize > ONE_MEGABYTE)
2011  {
2012  ERROR("[ERROR] Invalid data section size:%x\n", dataSec.Misc.VirtualSize);
2013  status = INT_STATUS_NOT_FOUND;
2014  goto exit;
2015  }
2016 
2017  status = IntVirtMemMap(gHalData.OwnerHalModule->BaseVa + dataSec.VirtualAddress, dataSec.Misc.VirtualSize,
2018  gGuest.Mm.SystemCr3, 0, &dataSectionMem);
2019  if (!INT_SUCCESS(status))
2020  {
2021  ERROR("[ERROR] IntVirtMemMap failed: 0x%08x\n", status);
2022 
2023  status = INT_STATUS_NOT_FOUND;
2024  goto exit;
2025  }
2026 
2027  for (DWORD offset = 0; offset <= dataSec.Misc.VirtualSize - gGuest.WordSize; offset += gGuest.WordSize)
2028  {
2029  halIntCtrlGva = gGuest.Guest64 ? *(QWORD*)((QWORD)dataSectionMem + offset) :
2030  *(DWORD*)((QWORD)dataSectionMem + offset);
2031 
2032  if (halIntCtrlGva < HalHeap || halIntCtrlGva >= HalHeap + HalHeapSize)
2033  {
2034  continue;
2035  }
2036 
2037  if (IntWinHalIsIntController(halIntCtrlGva, HalHeap))
2038  {
2039  *HalInterruptController = halIntCtrlGva;
2040  status = INT_STATUS_SUCCESS;
2041  goto exit;
2042  }
2043  }
2044 
2045  status = INT_STATUS_NOT_FOUND;
2046 
2047 exit:
2048  if (dataSectionMem)
2049  {
2050  IntVirtMemUnmap(&dataSectionMem);
2051  }
2052 
2053  return status;
2054 }
2055 
2056 
2057 static INTSTATUS
2059  _Out_ QWORD *HalHeapBaseAddress,
2060  _Out_ QWORD *HalInterruptController
2061  )
2080 {
2081  INTSTATUS status;
2082  DWORD nrSec = 0;
2083  DWORD pteTableIndex = 0;
2084  QWORD ptePhysicalAddress = 0;
2085  QWORD ptPhysicalAddress = 0;
2086  QWORD halHeapStart = 0;
2087  QWORD deviceAddressCount = 0;
2088  VA_TRANSLATION halHeapStartTranslation = { 0 };
2089  IMAGE_SECTION_HEADER dataSec = { 0 };
2090  QWORD fallbackHalHeapVA = 0;
2091  QWORD halInterruptController = 0;
2092  QWORD *pt = NULL;
2093  void *dataSectionMem = NULL;
2094 
2095 #define HAL_HEAP_ORIGINAL 0xFFFFFFFFF0000000
2096 #define MASK_DEVICE_ADDRESS_FEC 0x00000000fec00000
2097 #define MASK_DEVICE_ADDRESS_FED 0x00000000fed00000
2098 #define MASK_DEVICE_ADDRESS_FEE 0x00000000fee00000
2099 #define HAL_HEAP_PHYSICAL_ADDRESS 0x1000
2100 
2102  ".data", 1, gGuest.Mm.SystemCr3, &dataSec, &nrSec);
2103  if (!INT_SUCCESS(status) || nrSec == 0)
2104  {
2105  ERROR("[ERROR] IntPeGetSectionHeadersByName failed: 0x%08x, number of sections: %d\n", status, nrSec);
2106  goto exit;
2107  }
2108 
2109  if (dataSec.Misc.VirtualSize < gGuest.WordSize || dataSec.Misc.VirtualSize > ONE_MEGABYTE)
2110  {
2111  ERROR("[ERROR] Invalid data section size:%x\n", dataSec.Misc.VirtualSize);
2112  status = INT_STATUS_UNSUCCESSFUL;
2113  goto exit;
2114  }
2115 
2116  status = IntVirtMemMap(gHalData.OwnerHalModule->BaseVa + dataSec.VirtualAddress, dataSec.Misc.VirtualSize,
2117  gGuest.Mm.SystemCr3, 0, &dataSectionMem);
2118  if (!INT_SUCCESS(status))
2119  {
2120  ERROR("[ERROR] IntVirtMemMap failed: 0x%08x\n", status);
2121  goto exit;
2122  }
2123 
2124  for (DWORD offset = 0; offset <= dataSec.Misc.VirtualSize - gGuest.WordSize; offset += gGuest.WordSize)
2125  {
2126  halHeapStart = gGuest.Guest64 ? *(QWORD*)((QWORD)dataSectionMem + offset) :
2127  *(DWORD*)((QWORD)dataSectionMem + offset);
2128 
2129  halHeapStart = halHeapStart & HAL_HEAP_ORIGINAL;
2130 
2131  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, halHeapStart))
2132  {
2133  continue;
2134  }
2135 
2136  status = IntTranslateVirtualAddressEx(halHeapStart, gGuest.Mm.SystemCr3, 0, &halHeapStartTranslation);
2137  if (!INT_SUCCESS(status))
2138  {
2139  continue;
2140  }
2141 
2142  if (0 == halHeapStartTranslation.MappingsCount)
2143  {
2144  continue;
2145  }
2146 
2147  // Here we obtain the physical address of the PT (PT[0])
2148  pteTableIndex = halHeapStartTranslation.MappingsCount - 1;
2149  ptePhysicalAddress = halHeapStartTranslation.MappingsTrace[pteTableIndex];
2150  ptPhysicalAddress = ptePhysicalAddress & PHYS_PAGE_MASK;
2151 
2152  // From what I`ve seen, even on KASLR Hal Heap OSes (newer than RS2) the Hal Heap is always mapped to PA 0x1000.
2153  // In theory we could use this to find the Hal Heap but it`s safer to look for mapped devices and keep
2154  // this as a fallback mechanism only.
2155  if (HAL_HEAP_PHYSICAL_ADDRESS == halHeapStartTranslation.PhysicalAddress)
2156  {
2157  fallbackHalHeapVA = halHeapStartTranslation.VirtualAddress;
2158  }
2159 
2160  status = IntPhysMemMap(ptPhysicalAddress, PAGE_SIZE, 0, &pt);
2161  if (!INT_SUCCESS(status))
2162  {
2163  continue;
2164  }
2165 
2166  // Now we are going to look for mapped devices. The PT used to translate the HalHeap VA has other PTEs that map
2167  // physical devices (0xfee00XXX, 0xfec00XXX, 0xfed00XXX, etc.), so we are going to look for them. Below there
2168  // are some PTEs dumped from WinDbg (they illustrate the PTEs that map physical devices).
2169  //
2170  // ffffd07b`d92000a0 80000000`00016863 80000000`fee0087b <- Physicall device
2171  // ffffd07b`d92000b0 80000000`00018863 80000000`fec0081b <- Physicall device
2172  // ffffd07b`d92000c0 80000000`00019863 80000000`0001c863
2173  // ffffd07b`d92000d0 80000000`0001d863 80000000`fed0081b <- Physicall device
2174  deviceAddressCount = 0;
2175  for (DWORD i = 0; i < 512; i++)
2176  {
2177  if (!pt[i])
2178  {
2179  continue;
2180  }
2181 
2182  if ((pt[i] & PHYS_PAGE_MASK) == MASK_DEVICE_ADDRESS_FEE)
2183  {
2184  deviceAddressCount++;
2185  }
2186 
2187  if ((pt[i] & PHYS_PAGE_MASK) == MASK_DEVICE_ADDRESS_FEC)
2188  {
2189  deviceAddressCount++;
2190  }
2191 
2192  if ((pt[i] & PHYS_PAGE_MASK) == MASK_DEVICE_ADDRESS_FED)
2193  {
2194  deviceAddressCount++;
2195  }
2196  }
2197 
2198  status = IntPhysMemUnmap(&pt);
2199  if (!INT_SUCCESS(status))
2200  {
2201  continue;
2202  }
2203 
2204  // If there are at least 2 mapped physical devices, try to find the interrupt controller to validate
2205  // our candidate address.
2206  if (deviceAddressCount >= 2)
2207  {
2208  status = IntWinHalFindInterruptController(halHeapStartTranslation.VirtualAddress,
2210  &halInterruptController);
2211  if (!INT_SUCCESS(status))
2212  {
2213  continue;
2214  }
2215 
2216  TRACE("[HAL] Found HalInterruptController at 0x%016llx\n", halInterruptController);
2217 
2218  *HalHeapBaseAddress = halHeapStartTranslation.VirtualAddress;
2219  *HalInterruptController = halInterruptController;
2220 
2221  goto exit;
2222  }
2223  }
2224 
2225  if (fallbackHalHeapVA)
2226  {
2227  WARNING("[WARNING] We could not find the Hal Heap using the mapped devices - fallback using PA:0x1000 "
2228  "VA:%llx\n", fallbackHalHeapVA);
2229 
2231  &halInterruptController);
2232  if (INT_SUCCESS(status))
2233  {
2234  TRACE("[HAL] Found HalInterruptController at 0x%016llx\n", halInterruptController);
2235 
2236  *HalHeapBaseAddress = fallbackHalHeapVA;
2237  *HalInterruptController = halInterruptController;
2238 
2239  goto exit;
2240  }
2241  else
2242  {
2243  ERROR("[ERROR] We could not find the Hal Heap using the fallback VA\n");
2244  }
2245  }
2246  else
2247  {
2248  ERROR("[ERROR] We could not find the Hal Heap using the mapped devices and there is no fallback address\n");
2249  }
2250 
2251  status = INT_STATUS_NOT_FOUND;
2252 
2253 exit:
2254  if (dataSectionMem)
2255  {
2256  IntVirtMemUnmap(&dataSectionMem);
2257  }
2258 
2259 #undef HAL_HEAP_ORIGINAL
2260 #undef MASK_DEVICE_ADDRESS_FEC
2261 #undef MASK_DEVICE_ADDRESS_FED
2262 #undef MASK_DEVICE_ADDRESS_FEE
2263 #undef HAL_HEAP_PHYSICAL_ADDRESS
2264 
2265  return status;
2266 }
2267 
2268 
2269 INTSTATUS
2271  void
2272  )
2282 {
2283  INTSTATUS status;
2284 
2285  status = IntPeFindKernelExport("HalDispatchTable", &gHalData.HalDispatchTableAddress);
2286  if (!INT_SUCCESS(status))
2287  {
2288  ERROR("[ERROR] IntPeFindKernelExport failed for 'HalDispatchTable': 0x%x\n", status);
2289  return status;
2290  }
2291 
2292  // Starting from 20H1, the Hal Heap and Hal Interrupt controller have been moved to the nt itself on x64 versions
2293  // of Windows.
2295  {
2296  gHalData.OwnerHalModule = gGuest.KernelDriver;
2297  }
2298  else
2299  {
2300  gHalData.OwnerHalModule = IntDriverFindByName(u"hal.dll");
2301  }
2302 
2303  if (NULL == gHalData.OwnerHalModule)
2304  {
2305  ERROR("[ERROR] Could not find the module containing the Hal\n");
2306  return INT_STATUS_NOT_FOUND;
2307  }
2308 
2310 
2311  TRACE("[HAL] Found HalDispatchTable at %llx, size %d\n",
2312  gHalData.HalDispatchTableAddress, gHalData.HalDispatchTableSize);
2313 
2314  // RS2 x64 made the hal heap ASLR compatible
2315  // RS2 x86 still maps the hal heap at the same Virtual Address.
2317  {
2318  QWORD halHeap = 0;
2319  QWORD halInterruptController = 0;
2320  status = IntWinHalFindHalHeapAndInterruptController(&halHeap, &halInterruptController);
2321  if (!INT_SUCCESS(status))
2322  {
2323  LOG("[HAL] Unable to find the HAL heap\n");
2324  goto _skip_hal_heap;
2325  }
2326 
2327  gHalData.HalHeapAddress = halHeap;
2328  gHalData.HalIntCtrlAddress = halInterruptController;
2329  }
2330  else
2331  {
2333  }
2334 
2336 
2337  TRACE("[HAL] Found HalHeap at %llx, size %d\n", gHalData.HalHeapAddress, gHalData.HalHeapSize);
2338 
2340  {
2341  TRACE("[HAL] Hal Interrupt Controller/Performance Counter does not exist on Windows version %d!\n",
2342  gGuest.OSVersion);
2343  goto _skip_hal_heap;
2344  }
2345 
2346  if (!gHalData.HalIntCtrlAddress)
2347  {
2348  QWORD halInterruptController = 0;
2349  status = IntWinHalFindInterruptController(gHalData.HalHeapAddress, gHalData.HalHeapSize,
2350  &halInterruptController);
2351  if (!INT_SUCCESS(status))
2352  {
2353  ERROR("[ERROR] Could not find Hal Interrupt Controller!\n");
2354  goto _skip_hal_heap;
2355  }
2356 
2357  gHalData.HalIntCtrlAddress = halInterruptController;
2358  TRACE("[HAL] Found HalInterruptController at 0x%016llx\n", gHalData.HalIntCtrlAddress);
2359  }
2360 
2362  if (!INT_SUCCESS(status))
2363  {
2364  ERROR("[ERROR] IntWinHalFindPerformanceCounter failed: 0x%08x\n", status);
2365  goto _skip_hal_heap;
2366  }
2367 
2368 _skip_hal_heap:
2369  // Enable protections, if needed.
2371  {
2373  if (!INT_SUCCESS(status))
2374  {
2375  ERROR("[ERROR] IntWinHalHookHalDispatchTable failed: 0x%08x\n", status);
2376  return status;
2377  }
2378  }
2379 
2381  {
2382  status = IntWinHalProtectHalHeapExecs();
2383  if (!INT_SUCCESS(status))
2384  {
2385  ERROR("[ERROR] IntWinHalHookHalHeapExecs failed: 0x%08x\n", status);
2386  return status;
2387  }
2388  }
2389 
2391  {
2392  status = IntWinHalProtectHalIntCtrl();
2393  if (!INT_SUCCESS(status))
2394  {
2395  ERROR("[ERROR] IntWinHalHookHalIntCtrl failed: 0x%08x\n", status);
2396  return status;
2397  }
2398  }
2399 
2400  return status;
2401 }
2402 
2403 
2404 INTSTATUS
2406  void
2407  )
2416 {
2417  INTSTATUS status;
2418 
2420  {
2422  if (!INT_SUCCESS(status))
2423  {
2424  ERROR("[ERROR] IntWinHalHookHalDispatchTable failed: 0x%08x\n", status);
2425  return status;
2426  }
2427  }
2428  else
2429  {
2431  }
2432 
2434  {
2435  status = IntWinHalProtectHalHeapExecs();
2436  if (!INT_SUCCESS(status))
2437  {
2438  ERROR("[ERROR] IntWinHalHookHalHeapExecs failed: 0x%08x\n", status);
2439  return status;
2440  }
2441  }
2442  else
2443  {
2445  }
2446 
2448  {
2449  status = IntWinHalProtectHalIntCtrl();
2450  if (!INT_SUCCESS(status))
2451  {
2452  ERROR("[ERROR] IntWinHalHookHalIntCtrl failed: 0x%08x\n", status);
2453  return status;
2454  }
2455  }
2456  else
2457  {
2459  }
2460 
2462  {
2463  status = IntWinHalProtectHalPerfCounter();
2464  if (!INT_SUCCESS(status))
2465  {
2466  ERROR("[ERROR] IntWinHalProtectHalPerfCounter failed: 0x%08x\n", status);
2467  return status;
2468  }
2469  }
2470  else
2471  {
2473  }
2474 
2475  return INT_STATUS_SUCCESS;
2476 }
2477 
2478 void
2480  void
2481  )
2485 {
2487 
2489 
2491 
2493 
2495 
2496  if (NULL != gHalData.HalBuffer)
2497  {
2499  }
2500 }
Measures kernel mode exceptions checks.
Definition: stats.h:51
#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
UINT16 NumberOfSections
Definition: winpe.h:65
INTSTATUS IntWinHalUnprotectHalHeapExecs(void)
Deactivates the HAL heap execution protection.
Definition: winhal.c:812
struct _IMAGE_NT_HEADERS64 * PIMAGE_NT_HEADERS64
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
void * HalHdrSwapHandle
HAL headers swap handle. Used only if HAL is not protected, and the headers are not read automaticall...
Definition: winhal.h:59
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 CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
#define ROUND_UP(what, to)
Definition: introdefs.h:158
#define VICTIM_HAL_DISPATCH_TABLE
Printable name used for introObjectTypeHalDispatchTable objects.
Definition: intro_types.h:747
INTSTATUS IntWinHalProtectHalPerfCounter(void)
Enables protection on HalPerformanceCounter function pointer.
Definition: winhal.c:989
#define HAL_HEAP_PROT_PAGES_EXEC
The number of HAL heap pages to protect against executions.
Definition: winhal.c:13
struct _IMAGE_FILE_HEADER IMAGE_FILE_HEADER
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:982
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
INTSTATUS IntWinHalUnprotectHalPerfCounter(void)
Removes the protection on HalPerformanceCounter.
Definition: winhal.c:1035
uint8_t BYTE
Definition: intro_types.h:47
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
Definition: winguest.c:37
INTSTATUS IntHookRemoveChain(PHOOK_GPA HookGpa)
Removes a hook chain, starting with the given GPA hook.
Definition: hook.c:105
static INTSTATUS IntWinHalReadHal(void)
Reads the whole Hal image in memory, including swapped-out sections.
Definition: winhal.c:1593
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
static INTSTATUS IntWinHalFindHalHeapAndInterruptController(QWORD *HalHeapBaseAddress, QWORD *HalInterruptController)
Attempts to find the Hal Heap and the Hal Interrupt Controller address within the ...
Definition: winhal.c:2058
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:1199
INTSTATUS IntPeFindKernelExport(const char *Name, QWORD *ExportGva)
Find an export inside the NT kernel image.
Definition: winpe.c:1748
INTSTATUS IntWinHalUpdateProtection(void)
Updates any of the HAL protections.
Definition: winhal.c:2405
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
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:981
void * HalPerfIntegrityObj
The HAL Performance Counter integrity hook object.
Definition: winhal.h:62
#define STATS_EXIT(id)
Definition: stats.h:160
DWORD KernelSize
The size of the kernel.
Definition: guests.h:284
Event structure for integrity violations on monitored structures.
Definition: intro_types.h:1572
LIST_ENTRY InitSwapHandles
A list containing the swap handles for the swapped out sections which should be read in HalBuffer...
Definition: winhal.h:55
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:20
INTSTATUS IntSwapMemReadData(QWORD Cr3, QWORD VirtualAddress, DWORD Length, DWORD Options, void *Context, DWORD ContextTag, PFUNC_PagesReadCallback Callback, PFUNC_PreInjectCallback PreInject, void **SwapHandle)
Reads a region of guest virtual memory, and calls the indicated callback when all the data is availab...
Definition: swapmem.c:417
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
#define IC_TAG_WSWP
Win init swap handle.
Definition: memtags.h:110
QWORD BaseVa
The guest virtual address of the kernel module that owns this driver object.
Definition: drivers.h:41
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
LIST_ENTRY Link
Link inside the WINDOWS_GUEST.InitSwapHandles list.
Definition: winguest.h:867
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
IMAGE_FILE_HEADER FileHeader
Definition: winpe.h:220
#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
BOOLEAN KernelBetaDetections
True if the kernel protection is in beta (log-only) mode.
Definition: guests.h:303
struct _EVENT_INTEGRITY_VIOLATION::@304 Victim
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
INTSTATUS IntPeFindExportByNameInBuffer(QWORD ImageBase, BYTE *Buffer, DWORD BufferSize, const char *Name, DWORD *ExportRva)
Find the export name a Rva lies in.
Definition: winpe.c:1586
#define IC_TAG_HALB
Hal Buffer, cached by the introspection.
Definition: memtags.h:92
#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:675
KERNEL_DRIVER * Driver
The driver that&#39;s modifying the memory.
Definition: exceptions.h:949
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:942
#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
#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:431
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:281
static INTSTATUS IntWinHalFinishRead(void)
This is the function called when the Hal is completely read.
Definition: winhal.c:1429
static INTSTATUS IntWinHalSectionInMemory(WIN_INIT_SWAP *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)
Handles the swap in of a Hal section done while the WIN_HAL_DATA.HalBuffer is read.
Definition: winhal.c:1505
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
Rootkit.
Definition: intro_types.h:1144
Describes a kernel-mode originator.
Definition: exceptions.h:943
#define WIN_HAL_HEAP_BASE_64
The base address of the HAL heap on 64-bit kernels.
Definition: wddefs.h:68
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
#define MIN(a, b)
Definition: introdefs.h:146
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:2270
#define HAL_DISPATCH_TABLE_PTR_COUNT
The number of entries inside the hal dispatch table.
Definition: wddefs.h:1310
#define LOG(fmt,...)
Definition: glue.h:61
32-bit selector.
Definition: glueiface.h:187
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
#define MAX_INSTRUCTIONS_SEARCH
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1217
BOOLEAN IntPolicyCoreIsOptionBeta(QWORD Flag)
Checks if one of the kernel protection options is in log-only mode.
Definition: introcore.c:2603
DWORD HalBufferSize
The size of HAL buffer.
Definition: winhal.h:48
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
void * HalIntCtrlWriteHook
The HAL interrupt controller write hook object.
Definition: winhal.h:35
static INTSTATUS IntWinHalFindPerformanceCounterInternal(void)
Finds and protects if needed the HalPerformanceCounter structure.
Definition: winhal.c:1280
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
#define ALERT_FLAG_BETA
If set, the alert is a BETA alert. No action was taken.
Definition: intro_types.h:671
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:914
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:1974
#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:16
INTSTATUS IntSwapMemRemoveTransaction(void *Transaction)
Remove a transaction.
Definition: swapmem.c:942
DWORD Size
The size of the read.
Definition: winguest.h:871
DWORD HalHeapSize
The size of the HAL heap.
Definition: winhal.h:22
#define CR0_PE
Definition: processor.h:30
void IntAlertFillWriteInfo(const EXCEPTION_VICTIM_ZONE *Victim, INTRO_WRITE_INFO *WriteInfo)
Fills the write information for an alert.
Definition: alerts.c:521
#define INT_STATUS_EXCEPTION_BLOCK
Definition: introstatus.h:421
static INTSTATUS IntWinHalHeadersInMemory(void *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)
This callback is called as soon as all the HAL headers have been read using IntSwapMemReadData.
Definition: winhal.c:1877
Hal interrupt controller.
Definition: intro_types.h:253
DWORD Size
The size of the modified memory area.
Definition: intro_types.h:1618
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:377
#define STATS_ENTER(id)
Definition: stats.h:153
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
Definition: intro_types.h:1196
static INTSTATUS IntWinHalHandlePerfCounterModification(INTEGRITY_REGION *IntegrityRegion)
Integrity callback for detections of modifications over HalPerformanceCounter.
Definition: winhal.c:623
uint8_t * PBYTE
Definition: intro_types.h:47
static void IntWinHalCancelRead(void)
Cancels the Hal module read.
Definition: winhal.c:1455
#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 INTRO_OPT_PROT_KM_HAL_PERF_CNT
Enable protection over HalPerformanceCounter&#39;s function pointer, which is called inside KeQueryPerfor...
Definition: intro_types.h:519
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
#define ZONE_EXECUTE
Used for execute violation.
Definition: exceptions.h:736
#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:433
void * HalDispatchIntegrityHook
The HAL dispatch table integrity hook object.
Definition: winhal.h:37
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
QWORD Current
The currently used options.
Definition: guests.h:236
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:71
INTRO_MODULE Module
The module that modified the monitored region.
Definition: intro_types.h:1578
INTSTATUS IntTranslateVirtualAddress(QWORD Gva, QWORD Cr3, QWORD *PhysicalAddress)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1999
Write protection over HalPerformanceCounter.
Definition: intro_types.h:268
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:1616
#define TRUE
Definition: intro_types.h:30
static INTSTATUS IntWinHalFindPerformanceCounter(void)
Starts the process of finding the HalPerformanceCounter.
Definition: winhal.c:1931
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:1574
#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 RemainingSections
The number of sections which are not yet read into HAL buffer.
Definition: winhal.h:51
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
#define INT_STATUS_INVALID_INTERNAL_STATE
Definition: introstatus.h:272
BYTE * HalBuffer
A buffer containing the whole HAL image.
Definition: winhal.h:45
static BOOLEAN IntWinHalIsIntController(QWORD CheckedAddress, QWORD HalHeap)
Checks if a guest memory range is the HAL interrupt controller.
Definition: winhal.c:1068
#define MASK_DEVICE_ADDRESS_FED
INTSTATUS IntWinHalProtectHalHeapExecs(void)
Hooks the HAL heap against execution.
Definition: winhal.c:718
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:283
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
void IntAlertFillWinProcessCurrent(INTRO_PROCESS *EventProcess)
Saves information about the current Windows process inside an alert.
Definition: alerts.c:781
union _IMAGE_SECTION_HEADER::@214 Misc
struct _IMAGE_NT_HEADERS * PIMAGE_NT_HEADERS32
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
QWORD VirtualAddress
The guest virtual address that will be read.
Definition: winguest.h:870
#define SWAPMEM_FLAG_ASYNC_CALL
Definition: swapmem.h:12
#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 ALERT_FLAG_NOT_RING0
If set, the alert was triggered in ring 1, 2 or 3.
Definition: intro_types.h:674
static void InitializeListHead(LIST_ENTRY *ListHead)
Definition: introlists.h:69
#define PAGE_SIZE
Definition: common.h:70
QWORD HalHeapAddress
The guest virtual address of the HAL heap.
Definition: winhal.h:16
Describes the modified zone.
Definition: exceptions.h:893
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
INTSTATUS IntWinHalUnprotectHalIntCtrl(void)
Deactivates the HAL interrupt controller write protection.
Definition: winhal.c:889
#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
uint32_t DWORD
Definition: intro_types.h:49
UINT32 VirtualSize
Definition: winpe.h:83
DWORD KernelBufferSize
The size of the KernelBuffer.
Definition: winguest.h:852
DWORD HalDispatchTableSize
The size of the HAL dispatch table.
Definition: winhal.h:27
KERNEL_DRIVER * OwnerHalModule
The hal.dll kernel module or ntoskrnl.exe.
Definition: winhal.h:30
UINT32 Characteristics
Definition: winpe.h:92
INTSTATUS IntPeValidateHeader(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD ImageBaseBufferSize, INTRO_PE_INFO *PeInfo, QWORD Cr3)
Validates a PE header.
Definition: winpe.c:131
BOOLEAN Valid
Set to True if the information in the structure is valid, False otherwise.
Definition: intro_types.h:965
QWORD HalDispatchTableAddress
The guest virtual address of the HAL dispatch table.
Definition: winhal.h:25
enum _INTRO_ACTION INTRO_ACTION
Event actions.
#define _In_reads_bytes_(expr)
Definition: intro_sal.h:25
#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:980
INTSTATUS IntIntegrityRemoveRegion(void *Descriptor)
Removes an integrity region from the gIntegrityRegions list.
Definition: integrity.c:313
INTRO_WRITE_INFO WriteInfo
Definition: intro_types.h:1607
#define INT_STATUS_INVALID_OBJECT_TYPE
Definition: introstatus.h:145
#define SWAPMEM_OPT_BP_FAULT
If set, the #PF will be generated from an int3 detour. Use this when injecting kernel PFs...
Definition: swapmem.h:27
BOOLEAN IntWinHalIsHalPerf(QWORD HalPerfCandidate)
Verifies if the given pointer is the HalPerformanceCounter.
Definition: winhal.c:1196
INTSTATUS IntGetEPTPageProtection(DWORD EptIndex, QWORD Gpa, BYTE *Read, BYTE *Write, BYTE *Execute)
Definition: glue.c:659
__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
void IntWinHalUninit(void)
Frees any resources held by gHalData and removes all the HAL protections.
Definition: winhal.c:2479
#define IC_TAG_HAL_HEAP
Page in Hal Heap.
Definition: memtags.h:99
struct _IMAGE_SECTION_HEADER * PIMAGE_SECTION_HEADER
Hal dispatch table.
Definition: intro_types.h:252
#define IMAGE_SCN_MEM_DISCARDABLE
Definition: winpe.h:468
Exploitation for Privilege Escalation.
Definition: intro_types.h:1148
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
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
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:1614
IMAGE_FILE_HEADER FileHeader
Definition: winpe.h:227
The initialization swap handle.
Definition: winguest.h:865
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_HAL_PERFORMANCE_COUNTER
Printable name used for introObjectTypeHalPerfCounter objects.
Definition: intro_types.h:757
__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
BYTE * KernelBuffer
A buffer containing the entire kernel image.
Definition: winguest.h:851
KERNEL_DRIVER * KernelDriver
Points to the driver object that describes the kernel image.
Definition: guests.h:385
#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
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
#define MAX_LIST_ITERATIONS_HAL_PERF
#define INTRO_OPT_PROT_KM_HAL_DISP_TABLE
Enable HDT (Hal Dispatch Table) protection (Windows only).
Definition: intro_types.h:414
UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]
Definition: winpe.h:79
Sent for integrity violation alerts. See EVENT_INTEGRITY_VIOLATION.
Definition: intro_types.h:92
#define HAL_HEAP_PHYSICAL_ADDRESS
64-bit selector.
Definition: glueiface.h:188
static void IntWinHalSendPerfCntIntegrityAlert(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Sends an introEventIntegrityViolation for detections of writes over HalPerformanceCounter.
Definition: winhal.c:557
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
BOOLEAN Image64Bit
True if the image is 64 bit.
Definition: winpe.h:596
#define IC_TAG_HDRS
Module headers as cached inside a KERNEL_MODULE structure.
Definition: memtags.h:52
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:1159
void * HalHeapExecHook
The HAL heap execution hook object.
Definition: winhal.h:33
void * SwapHandle
The actual swap handle returned by IntSwapMemRead.
Definition: winguest.h:868
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
#define IMAGE_SCN_MEM_NOT_PAGED
Definition: winpe.h:470
DWORD UntrustedEptIndex
The EPTP index of the untrusted EPT.
Definition: guests.h:397
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
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:271
QWORD HalPerfCounterAddress
The guest virtual address of the HAL performance counter.
Definition: winhal.h:20
static INTSTATUS IntWinHalHandleHalHeapExec(void *Context, HOOK_GPA *Hook, QWORD Address, INTRO_ACTION *Action)
Handles execution attempts from the HAL heap.
Definition: winhal.c:161
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
UINT16 SizeOfOptionalHeader
Definition: winpe.h:69
INTSTATUS IntWinHalProtectHalIntCtrl(void)
Protects the HAL interrupt controller against writes.
Definition: winhal.c:837
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:3357
#define MAX_INT_CTRL_COUNT
#define INT_STATUS_INVALID_DATA_SIZE
Definition: introstatus.h:142
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
INTSTATUS IntWinHalUnprotectHalDispatchTable(void)
Deactivates the HAL dispatch table protection.
Definition: winhal.c:957