Bitdefender Hypervisor Memory Introspection
winvad.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "winvad.h"
6 #include "hook.h"
7 #include "processor.h"
8 #include "swapmem.h"
9 #include "winprocesshp.h"
10 #include "shellcode.h"
11 #include "winummodule.h"
12 #include "winthread.h"
13 #include "exceptions.h"
14 #include "alerts.h"
15 #include "scan_engines.h"
16 #include "winnet.h"
17 
19 #define VAD_SEARCH_LIMIT 1000
20 #define MAX_VAD_EXECS 64u
22 
23 static INTSTATUS
25  _Inout_ WIN_PROCESS_OBJECT *Process,
26  _In_ QWORD VadAddress,
27  _In_ BOOLEAN StaticScan,
28  _Out_opt_ VAD **Vad
29  );
30 
31 
32 static __forceinline BYTE *
34  _In_ QWORD Gva
35  )
48 {
49  void *ptr = NULL;
50 
51  if (!INT_SUCCESS(IntVirtMemMap(Gva, WIN_KM_FIELD(VadShort, Size), gGuest.Mm.SystemCr3, 0, &ptr)))
52  {
53  return NULL;
54  }
55 
56  return ptr;
57 }
58 
68 #define VAD_SHORT_FIELD_PTR(type_, ptr_, field_) (type_ *)((BYTE *)(ptr_) + WIN_KM_FIELD(VadShort, field_))
69 
78 #define VAD_LONG_FIELD_PTR(type_, ptr_, field_) (type_ *)((BYTE *)(ptr_) + WIN_KM_FIELD(VadLong, field_))
79 
90 #define VadShortByte(ptr_, field_) *VAD_SHORT_FIELD_PTR(BYTE, ptr_, field_)
91 
102 #define VadShortWord(ptr_, field_) *VAD_SHORT_FIELD_PTR(WORD, ptr_, field_)
103 
114 #define VadShortDword(ptr_, field_) *VAD_SHORT_FIELD_PTR(DWORD, ptr_, field_)
115 
126 #define VadShortQword(ptr_, field_) *VAD_SHORT_FIELD_PTR(QWORD, ptr_, field_)
127 
139 #define VadShortPtrSize(ptr_, field_) gGuest.Guest64 ? VadShortQword(ptr_, field_) : VadShortDword(ptr_, field_)
140 
151 #define VadShortAnySize(size_, ptr_, field_) (size_) == 8 ? VadShortQword(ptr_, field_) : \
152  (size_) == 4 ? VadShortDword(ptr_, field_) : \
153  (size_) == 2 ? VadShortWord(ptr_, field_) : \
154  (size_) == 1 ? VadShortByte(ptr_, field_) : 0
155 
156 
157 static __forceinline BOOLEAN
159  _In_ VAD const *Vad
160  )
168 {
169  // NaCl regions come in chunks of 16 pages as private memory, ignore them
170  return Vad->Process->HasNaClEnabled && 16 == Vad->PageCount && VadNone == Vad->VadType;
171 }
172 
173 
174 static BOOLEAN
176  _In_ VAD const *Vad
177  )
188 
189 {
190  return Vad->VadType == VadNone &&
191  (Vad->VadProtection & VAD_PROT_EXECUTE_READWRITE) &&
192  Vad->Process->IsDominoJava &&
193  !Vad->Process->FirstDominoJavaIgnored;
194 }
195 
196 
197 static INTSTATUS
199  _Inout_ VAD *Vad,
200  _In_ QWORD StartPage,
201  _In_ QWORD EndPage
202  )
218 {
219  INTSTATUS status;
220 
221  if (NULL == Vad->VadPages)
222  {
224  }
225 
226  for (QWORD curpg = (StartPage & PAGE_MASK); curpg <= (EndPage & PAGE_MASK); curpg += PAGE_SIZE)
227  {
228  DWORD pos = (DWORD)((curpg - Vad->StartPage) >> 12);
229 
230  if (NULL == Vad->VadPages[pos])
231  {
232  continue;
233  }
234 
235  if (NULL != Vad->VadPages[pos]->ExecHook)
236  {
237  // The page was hooked
238  status = IntHookGvaRemoveHook((HOOK_GVA **)&Vad->VadPages[pos]->ExecHook, 0);
239  if (!INT_SUCCESS(status))
240  {
241  ERROR("[ERROR] IntHookGvaRemoveHook failed: 0x%08x\n", status);
242  }
243  }
244 
245  HpFreeAndNullWithTag(&Vad->VadPages[pos], IC_TAG_VAD_PAGE);
246  }
247 
248  return INT_STATUS_SUCCESS;
249 }
250 
251 
252 static INTSTATUS
254  _Inout_ VAD *Vad
255  )
265 {
266  INTSTATUS status;
267 
268  status = INT_STATUS_SUCCESS;
269  if (NULL != Vad->VadPages)
270  {
271  status = IntWinVadRemoveRange(Vad, Vad->StartPage, Vad->EndPage);
272  if (!INT_SUCCESS(status))
273  {
274  ERROR("[ERROR] IntWinVadRemoveRange failed for VAD 0x%016llx: 0x%08x\n", Vad->VadGva, status);
275  }
276 
277  HpFreeAndNullWithTag(&Vad->VadPages, IC_TAG_VAD_PGARR);
278  }
279 
280  return status;
281 }
282 
283 
284 void
286  _Inout_ VAD **Vad
287  )
297 {
298  INTSTATUS status;
299  PVAD pVad;
300 
301  if (NULL == Vad || NULL == *Vad)
302  {
303  return;
304  }
305 
306  pVad = *Vad;
307  *Vad = NULL;
308 
309  // Remove the VAD transaction, if any.
310  if (pVad->PathSwapHandle)
311  {
313  if (!INT_SUCCESS(status))
314  {
315  ERROR("[ERROR] IntSwapMemRemoveTransactionsForAddress failed: 0x%08x\n", status);
316  }
317 
318  pVad->PathSwapHandle = NULL;
319  }
320 
321  if ((VadImageMap == pVad->VadType) && (NULL != pVad->Path))
322  {
323  status = IntWinModHandleUnloadFromVad(pVad->Process, pVad);
324  if (!INT_SUCCESS(status))
325  {
326  ERROR("[ERROR] IntWinModHandleUnloadFromVad failed: 0x%08x\n", status);
327  }
328  }
329 
331 
332  // Remove all the pages from this VAD.
334 
336 }
337 
338 
341  _Inout_ RBNODE *Node
342  )
348 {
349  PVAD pVad = CONTAINING_RECORD(Node, VAD, RbNode);
350 
351  IntWinVadDestroyObject(&pVad);
352 }
353 
354 
357  _In_ RBNODE const *Left,
358  _In_ RBNODE const *Right
359  )
373 {
374  VAD const *p1 = CONTAINING_RECORD(Left, VAD, RbNode);
375  VAD const *p2 = CONTAINING_RECORD(Right, VAD, RbNode);
376 
377  if (p1->EndPage < p2->StartPage)
378  {
379  return -1;
380  }
381  else if (p1->StartPage > p2->EndPage)
382  {
383  return 1;
384  }
385  else
386  {
387  return 0;
388  }
389 }
390 
391 
394  _In_ RBNODE const *Node,
395  _In_ void *Key
396  )
407 {
408  QWORD gva = (QWORD)Key;
409  VAD const *vad = CONTAINING_RECORD(Node, VAD, RbNode);
410 
411  if (gva >= vad->StartPage && gva < vad->StartPage + vad->PageCount * PAGE_SIZE)
412  {
413  return 0;
414  }
415  else if (vad->StartPage < gva)
416  {
417  return -1;
418  }
419  else
420  {
421  return 1;
422  }
423 }
424 
425 
428  _In_ RBNODE const *Node,
429  _In_ void *Key
430  )
442 {
443  QWORD base = (QWORD)Key;
444  VAD const *vad = CONTAINING_RECORD(Node, VAD, RbNode);
445 
446  if (base == vad->StartPage)
447  {
448  return 0;
449  }
450  else if (vad->StartPage < base)
451  {
452  return -1;
453  }
454  else
455  {
456  return 1;
457  }
458 }
459 
460 
461 void
463  _Inout_ WIN_PROCESS_OBJECT *Process
464  )
473 {
474  RbPreinit(&Process->VadTree);
475 
477 }
478 
479 
480 static DWORD
482  _In_ DWORD VmProtection
483  )
493 {
494  // High bits represent NoCache, Guard & WriteCombine.
495  VmProtection &= 0xFF;
496 
497  switch (VmProtection)
498  {
500  return 0;
502  return PROT_READ;
504  return PROT_READ | PROT_WRITE;
506  return PROT_READ | PROT_WRITE;
507  case WIN_MM_PAGE_EXECUTE:
508  return PROT_EXEC;
510  return PROT_READ | PROT_EXEC;
512  return PROT_READ | PROT_WRITE | PROT_EXEC;
514  return PROT_READ | PROT_WRITE | PROT_EXEC;
515  default:
516  return 0;
517  }
518 }
519 
520 
521 static DWORD
523  _In_ WIN_VAD_PROT VadProtection
524  )
533 {
534  // High bits represent NoCache, Guard & WriteCombine.
535  VadProtection &= 0xFF;
536 
537  switch (VadProtection)
538  {
539  case VAD_PROT_NOACCESS:
540  return 0;
541  case VAD_PROT_READONLY:
542  return PROT_READ;
543  case VAD_PROT_READWRITE:
544  return PROT_READ | PROT_WRITE;
545  case VAD_PROT_WRITECOPY:
546  return PROT_READ | PROT_WRITE;
547  case VAD_PROT_EXECUTE:
548  return PROT_EXEC;
550  return PROT_READ | PROT_EXEC;
552  return PROT_READ | PROT_WRITE | PROT_EXEC;
554  return PROT_READ | PROT_WRITE | PROT_EXEC;
555  default:
556  return 0;
557  }
558 }
559 
560 
561 static DWORD
563  _In_ WIN_VAD_PROT VadProtection
564  )
573 {
574  // High bits represent NoCache, Guard & WriteCombine.
575  VadProtection &= 0xFF;
576 
577  switch (VadProtection)
578  {
579  case VAD_PROT_NOACCESS:
580  return WIN_MM_PAGE_NOACCESS;
581  case VAD_PROT_READONLY:
582  return WIN_MM_PAGE_READONLY;
583  case VAD_PROT_READWRITE:
584  return WIN_MM_PAGE_READWRITE;
585  case VAD_PROT_WRITECOPY:
586  return WIN_MM_PAGE_WRITECOPY;
587  case VAD_PROT_EXECUTE:
588  return WIN_MM_PAGE_EXECUTE;
595  default:
596  return 0;
597  }
598 }
599 
600 
601 VAD *
603  _In_ WIN_PROCESS_OBJECT *Process,
604  _In_ QWORD Va
605  )
614 {
615  PRBNODE found = NULL;
616 
617  RbLookupNodeCustomCompare(&Process->VadTree, IntWinVadRbTreeNodeCompareVa, (void *)Va, &found);
618 
619  if (!found)
620  {
621  return NULL;
622  }
623 
624  return CONTAINING_RECORD(found, VAD, RbNode);
625 }
626 
627 
628 static VAD *
630  _In_ PWIN_PROCESS_OBJECT Process,
631  _In_ QWORD StartPage,
632  _In_ QWORD EndPage
633  )
645 {
646  VAD target;
647  PRBNODE found;
648 
649  target.StartPage = StartPage;
650  target.EndPage = EndPage;
651 
652  found = NULL;
653 
654  RbLookupNode(&Process->VadTree, &target.RbNode, &found);
655 
656  if (!found)
657  {
658  return NULL;
659  }
660 
661  return CONTAINING_RECORD(found, VAD, RbNode);
662 }
663 
664 
665 static PVAD
667  _In_ PWIN_PROCESS_OBJECT Process,
668  _In_ QWORD Base
669  )
680 {
681  PRBNODE found = NULL;
682 
683  RbLookupNodeCustomCompare(&Process->VadTree, IntWinVadRbTreeNodeCompareBases, (void *)Base, &found);
684 
685  if (!found)
686  {
687  return NULL;
688  }
689 
690  return CONTAINING_RECORD(found, VAD, RbNode);
691 }
692 
693 
694 static INTSTATUS
696  _Inout_ VAD *Vad,
697  _In_ QWORD NewStartPage,
698  _In_ QWORD NewEndPage
699  )
717 {
718  INTSTATUS status;
719  VAD_PAGE **pNewVadPages = NULL;
720  QWORD newPageCount = 0, newPageIdx = 0;
721 
722  // New current pages array contains the region [Vad->StartPage, Vad->EndPage]. We need to adjust that region to
723  // hold only [NewStartPage, NewOldPage].
724  newPageCount = ((NewEndPage - NewStartPage) >> 12) + 1;
725 
726  if (NULL == Vad->VadPages)
727  {
728  goto no_array;
729  }
730 
731  pNewVadPages = HpAllocWithTag(sizeof(*pNewVadPages) * newPageCount, IC_TAG_VAD_PGARR);
732  if (NULL == pNewVadPages)
733  {
735  }
736 
737  for (QWORD curpg = (Vad->StartPage & PAGE_MASK); curpg <= (Vad->EndPage & PAGE_MASK); curpg += PAGE_SIZE)
738  {
739  QWORD pos = ((curpg - Vad->StartPage) >> 12);
740 
741  if (curpg >= NewStartPage && curpg <= NewEndPage)
742  {
743  if (NULL == Vad->VadPages[pos])
744  {
745  pNewVadPages[newPageIdx++] = NULL;
746  }
747  else
748  {
749  Vad->VadPages[pos]->RangeStart = MAX(Vad->VadPages[pos]->RangeStart, NewStartPage);
750  Vad->VadPages[pos]->RangeEnd = MIN(Vad->VadPages[pos]->RangeEnd, NewEndPage);
751 
752  pNewVadPages[newPageIdx++] = Vad->VadPages[pos];
753  }
754  }
755  else
756  {
757  if (NULL != Vad->VadPages[pos])
758  {
759  if (NULL != Vad->VadPages[pos]->ExecHook)
760  {
761  // The page was hooked
762  status = IntHookGvaRemoveHook((HOOK_GVA **)&Vad->VadPages[pos]->ExecHook, 0);
763  if (!INT_SUCCESS(status))
764  {
765  ERROR("[ERROR] IntHookGvaRemoveHook failed: 0x%08x\n", status);
766  }
767  }
768 
769  HpFreeAndNullWithTag(&Vad->VadPages[pos], IC_TAG_VAD_PAGE);
770  }
771  }
772  }
773 
774  HpFreeAndNullWithTag(&Vad->VadPages, IC_TAG_VAD_PGARR);
775 
776  Vad->VadPages = pNewVadPages;
777 
778 no_array:
779  Vad->StartPage = NewStartPage;
780  Vad->EndPage = NewEndPage;
781  Vad->PageCount = newPageCount;
782 
783  return INT_STATUS_SUCCESS;
784 }
785 
786 
787 static INTSTATUS
789  _In_ WIN_PROCESS_OBJECT* Process,
790  _In_ QWORD VirtualAddress,
791  _In_ QWORD PhysicalAddress,
792  _Out_ INTRO_ACTION* Action
793  )
816 {
817  INTSTATUS status;
818  QWORD scflags;
819  PIG_ARCH_REGS regs;
820  PINSTRUX instrux;
821  char text[ND_MIN_BUF_SIZE] = { 0 };
822  BOOLEAN bRspOut, bIsStack;
823  QWORD tibBase, stackBase, stackLimit;
824  BOOLEAN detected, feedback;
825  INTRO_ACTION_REASON reason;
826  BOOLEAN isCurrentProcess;
827 
828  EXCEPTION_UM_ORIGINATOR originator = { 0 };
829  EXCEPTION_VICTIM_ZONE victim = { 0 };
830 
831  scflags = 0;
832  tibBase = stackBase = stackLimit = 0;
833  detected = feedback = FALSE;
834 
835  if (NULL == Process)
836  {
838  }
839 
840  if (NULL == Action)
841  {
843  }
844 
845  *Action = introGuestAllowed;
846  reason = introReasonAllowed;
847 
848  regs = &gVcpu->Regs;
849  instrux = &gVcpu->Instruction;
850 
851  isCurrentProcess = Process->Cr3 == regs->Cr3;
852 
853  status = IntWinThrGetCurrentStackBaseAndLimit(&tibBase, &stackBase, &stackLimit);
854  if ((INT_STATUS_PAGE_NOT_PRESENT == status) || (INT_STATUS_NO_MAPPING_STRUCTURES == status))
855  {
856  LOG("TIB is not present! Will inject #PF for %llx!\n", tibBase);
857 
858  // We just blocked an instruction being executed inside user-mode. It is safe to inject a #PF right now.
859  // NOTE: We do not save a handle for this swap event (this is the only one) since this page may be executed
860  // in the context of multiple threads, which would mean multiple swap-in attempts; therefore, we don't use
861  // a context or a callback for this swap, which will be removed when terminating the process, if needed.
862  status = IntSwapMemReadData(regs->Cr3, tibBase, 32, SWAPMEM_OPT_UM_FAULT | SWAPMEM_OPT_NO_DUPS,
863  NULL, 0, NULL, NULL, NULL);
864  if (!INT_SUCCESS(status))
865  {
866  ERROR("[ERROR] IntSwapMemReadData failed: 0x%08x\n", status);
867  return status;
868  }
869  else
870  {
871  *Action = introGuestRetry;
872  return INT_STATUS_SUCCESS;
873  }
874  }
875  else if (!INT_SUCCESS(status))
876  {
877  // If we couldn't read the TIB and the stack base/stack limit, assume the stack is OK - we still need to
878  // validate the code!
879  ERROR("[ERROR] IntWinThrGetCurrentStackBaseAndLimit failed: 0x%08x\n", status);
880  stackLimit = stackBase = 0;
881  }
882 
886  if ((stackLimit == 0) && (stackBase == 0))
887  {
888  bRspOut = bIsStack = FALSE;
889  }
890  else
891  {
892  // Take a 3 page safety margin - the usual size of the guard region; we may have a RSP that points slightly
893  // out of the stack area, but within the guard area.
894  bRspOut = ((regs->Rsp < stackLimit - 0x3000) || (regs->Rsp >= stackBase));
895  bIsStack = (VirtualAddress >= stackLimit) && (VirtualAddress < stackBase);
896  }
897 
898  status = IntShcIsSuspiciousCode(VirtualAddress, PhysicalAddress, IG_CS_TYPE_INVALID, regs, &scflags);
899  if (!INT_SUCCESS(status))
900  {
901  scflags = 0;
902  }
903 
904  if (bRspOut || bIsStack)
905  {
906  // Pivoted stack or executions on the stack trigger detection directly.
907  detected = TRUE;
908  }
909  else if (0 != scflags)
910  {
911  detected = TRUE;
912 
913  // Shellcode flags (as set by the shellcode emulator) may be overridden via CAMI. A flag marked for feedback
914  // will cause the alert to be logged & sent, but no actual detection will appear. Note that we force feedback
915  // for shellcode flags if and only if all the reported flags are marked as feedback. If there is a single
916  // shellcode flag set that is not feedback, a normal detection will be generated.
917  if ((scflags & gGuest.ShemuOptions.Feedback) == scflags)
918  {
919  feedback = TRUE;
920  }
921  }
922 
923  if (!detected)
924  {
925  // We did not find malicious activity, send context to the scan engine if we have the options set, but only
926  // once, for the current process
927  if (isCurrentProcess && !!(gGuest.CoreOptions.Current & INTRO_OPT_NOTIFY_ENGINES))
928  {
929  INTRO_EXEC_INFO executionInfo = { 0 };
930 
931  executionInfo.Rsp = regs->Rsp;
932  executionInfo.StackBase = stackBase;
933  executionInfo.StackLimit = stackLimit;
934  executionInfo.Length = instrux->Length;
935 
936  status = IntWinEngExecSendNotification(Process, regs, &executionInfo);
937  if (!INT_SUCCESS(status))
938  {
939  WARNING("[WARNING] IntWinEngExecSendNotification failed: 0x%08x\n", status);
940  }
941  }
942 
943  // Since the engines scan is asynchronous we can't do anything else, but exit
944  goto _send_notification;
945  }
946 
947  status = IntExceptUserGetExecOriginator(Process, &originator);
948  if (!INT_SUCCESS(status))
949  {
950  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
951  goto _send_notification;
952  }
953 
954  status = IntExceptGetVictimEpt(Process,
955  PhysicalAddress,
956  VirtualAddress,
958  ZONE_EXECUTE,
959  &victim);
960  if (!INT_SUCCESS(status))
961  {
962  ERROR("[ERROR] Failed getting modified zone: 0x%08x\n", status);
963  goto _send_notification;
964  }
965 
966  IntExcept(&victim, &originator, exceptionTypeUm, Action, &reason, introEventEptViolation);
967  // Override the action & reason, if we have shemu feedback only.
968  if ((*Action == introGuestNotAllowed) && feedback)
969  {
970  *Action = introGuestAllowed;
972  }
973 
974 _send_notification:
975  // Since we can get here for other processes, not only the current one, we have to make sure we don't send an
976  // alert and we don't inject a #UD unless we are doing it for the current process. We still want to analyze the
977  // code in order to properly mark the page as non-malicious, if needed
978  if (IntPolicyProcTakeAction(PROC_OPT_PROT_EXPLOIT, Process, Action, &reason) && isCurrentProcess)
979  {
980  EVENT_EPT_VIOLATION* pEptViol = &gAlert.Ept;
981 
982  memzero(pEptViol, sizeof(*pEptViol));
983 
984  status = NdToText(instrux, regs->Rip, ND_MIN_BUF_SIZE, text);
985  if (!INT_SUCCESS(status))
986  {
987  ERROR("[ERROR] NdToText failed: 0x%08x\n", status);
988  return status;
989  }
990 
991  LOG("[VADNX] [CPU %d] EXPLOIT detected! Execution attempted at 0x%016llx! Instruction: %s\n",
992  gVcpu->Index, regs->Rip, text);
993 
994  LOG("[VADNX] Current address: %llx, current stack: %llx, known stack: %llx/%llx, TIB: %llx\n",
995  regs->Rip, regs->Rsp, stackBase, stackLimit, tibBase);
996 
997  LOG("[VADNX] RSP out: %d; Is stack: %d; Shellcode flags: %llx;\n",
998  bRspOut, bIsStack, scflags);
999 
1000  IntDumpCodeAndRegs(regs->Rip, PhysicalAddress, regs);
1001 
1002  pEptViol->Header.Action = *Action;
1003  pEptViol->Header.Reason = reason;
1004  pEptViol->Header.MitreID = idExploitClientExec;
1005 
1006  IntAlertEptFillFromVictimZone(&victim, pEptViol);
1007 
1009 
1010  IntAlertFillWinProcess(Process, &pEptViol->Header.CurrentProcess);
1011 
1013  pEptViol->ReturnRip = originator.Return.Rip;
1014 
1015  pEptViol->Header.Flags = IntAlertProcGetFlags(PROC_OPT_PROT_EXPLOIT, Process, reason, 0);
1016 
1017  IntAlertFillCodeBlocks(regs->Rip, regs->Cr3, TRUE, &pEptViol->CodeBlocks);
1018  IntAlertFillExecContext(0, &pEptViol->ExecContext);
1019 
1020  IntAlertFillVersionInfo(&pEptViol->Header);
1021 
1022  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
1023  if (!INT_SUCCESS(status))
1024  {
1025  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
1026  }
1027 
1028  status = IntWinNetSendProcessConnections(Process);
1029  if (!INT_SUCCESS(status))
1030  {
1031  WARNING("[WARNING] IntWinNetSendProcessConnections failed: 0x%08x\n", status);
1032  }
1033  }
1034 
1035  return INT_STATUS_SUCCESS;
1036 }
1037 
1038 
1039 static INTSTATUS
1041  _Inout_ VAD_PAGE *Context,
1042  _In_ void const *Hook,
1043  _In_ QWORD Address,
1044  _Out_ INTRO_ACTION *Action
1045  )
1115 {
1116  INTSTATUS status;
1117  PVAD_PAGE pPage;
1118  PWIN_PROCESS_OBJECT pProc;
1119  PIG_ARCH_REGS regs;
1120  QWORD currentThread = 0;
1121  INFO_UD_PENDING *entryPendingUD = NULL;
1122  BOOLEAN isCurrentProcess;
1123 
1124  UNREFERENCED_PARAMETER(Hook);
1125 
1126  // Default action = allow.
1127  *Action = introGuestAllowed;
1128 
1129  pPage = Context;
1130  pProc = pPage->Vad->Process;
1131  regs = &gVcpu->Regs;
1132  isCurrentProcess = pProc->Cr3 == regs->Cr3;
1133 
1134  // If this is a shared memory region between two protected processes, the hook will be invoked for both, but the
1135  // current process is the one that triggered the violation, so ignore the others
1136  if (!isCurrentProcess)
1137  {
1138  // If this page is shared between multiple processes, we can be in one of the following cases:
1139  // 1. process a.exe and b.exe share the same page; a.exe is protected, while b.exe is not - if b.exe fetches
1140  // instructions from that page, an EPT violation will be generated; since the page is not hooked in the
1141  // current process (b.exe), we allow the execution. This can pretty much freeze the guest in two situations:
1142  // i. for each instruction that the guest tries to execute from the monitored page while in the context
1143  // of b.exe, an EPT violation will be triggered
1144  // ii. if an interrupt is pending and is delivered to the guest, the same instruction ends up being retried
1145  // in an infinite loop
1146  // 2. both a.exe, and b.exe are protected against exploits. b.exe executes code from the shared page, an
1147  // EPT violation is triggered and introcore inspects the code from that page and considers that it is not
1148  // malicious, marking the page as legitimate and removing the hook from that page. Since the same page is
1149  // hooked more than once, the EPT hook is still in place, and further attempts made by b.exe to execute code
1150  // from that page will trigger new EPT violations.
1151  // https://lists.xenproject.org/archives/html/xen-devel/2019-01/msg00900.html is also relevant
1152  // In the first case, we will allow the action, which will remove the hook on that page, but will still
1153  // keep the VAD. The second case is handled partially in IntShcWinHandlePageExecution, as it is more tricky.
1154  // We have to keep in mind that the page may indeed contain malicious code, and that we can't make any
1155  // assumptions about the order in which the hooks are invoked, for example, if we have a.exe, b.exe and c.exe
1156  // all sharing the same page, and b.exe is the current process and the hooks are invoked in order (first for a,
1157  // then for b and lastly for c) we want to keep the hook in all processes, but send the alert only for b.exe.
1158  // So we have to analyze code and then take an action.
1159  // If the code is clean, the page will be marked as clean in all processes, and unhooked from all
1160  // processes; if it is malicious, it will remain hooked in all processes, but the alert will be sent only
1161  // for the current process.
1162  PWIN_PROCESS_OBJECT pCurrentProcess = IntWinProcFindObjectByCr3(regs->Cr3);
1163  if (!pCurrentProcess->ProtExploits)
1164  {
1165  TRACE("[WINVAD] Removing VAD hook on 0x%016llx for process `%s` (Cr3 0x%016llx). "
1166  "Current process is `%s` (Cr3 0x%016llx)\n",
1167  pPage->Address, pProc->Name, pProc->Cr3, pCurrentProcess->Name, pCurrentProcess->Cr3);
1168 
1169  status = INT_STATUS_NOT_NEEDED_HINT;
1170  *Action = introGuestAllowed;
1171  goto cleanup_and_exit;
1172  }
1173  }
1174 
1175  // We keep a list of tuples (CR3, RIP, ETHREAD) for all the injected/pending UDs
1176  // If a tuple comes more than once it means that the requested #UD did not happen before and now we will just
1177  // request another #UD; without checking again and without generating duplicated alerts for the same execution.
1178  // The list cleanup takes place:
1179  // 1. when #UD is successfully injected --> IntHandleEventInjection (using gVcpu->Exception.CurrentUD which stores
1180  // the allocated addresses for a tuple)
1181  // 2. when a process terminates --> IntWinProcDeleteProcessObject (using the CR3)
1182 
1183  status = IntWinThrGetCurrentThread(gVcpu->Index, &currentThread);
1184  if (!INT_SUCCESS(status))
1185  {
1186  ERROR("[ERROR] IntWinThrGetCurrentThread failed: 0x%08x\n", status);
1187  return status;
1188  }
1189 
1190  entryPendingUD = IntUDGetEntry(regs->Cr3, regs->Rip, currentThread);
1191  if (NULL != entryPendingUD)
1192  {
1193  goto retry_inject_ud;
1194  }
1195 
1196  if (IntWinVadIsProbablyDominoJava(pPage->Vad))
1197  {
1199  pPage->Vad->IsIgnored = 1;
1200  pPage->Legitimate = TRUE;
1201  status = INT_STATUS_SUCCESS;
1202  goto cleanup_and_exit;
1203  }
1204 
1205  status = IntWinVadIsExecSuspicious(pProc, regs->Rip, Address, Action);
1206  if (!INT_SUCCESS(status))
1207  {
1208  ERROR("[ERROR] IntWinVadIsExecSuspicious failed: 0x%08x\n", status);
1209  goto cleanup_and_exit;
1210  }
1211 
1212  // If the actions is allowed, remove the hook on the page/region.
1213  if (introGuestAllowed == *Action)
1214  {
1215  pPage->Legitimate = TRUE;
1216  }
1217 
1219 
1220 cleanup_and_exit:
1221  // Remove the exec hook if we allow the action.
1222  if ((introGuestAllowed == *Action) && (NULL != pPage->ExecHook))
1223  {
1224  // Remove the hook on this page, only if we didn't block anything. If we did, we will maintain the hook in
1225  // order to block further execution attempts. We also remove the hook if we're in BETA mode - otherwise,
1226  // there will be lots & lots of alerts, that may end up hanging the process.
1227  status = IntHookGvaRemoveHook((HOOK_GVA **)&pPage->ExecHook, 0);
1228  if (!INT_SUCCESS(status))
1229  {
1230  ERROR("[ERROR] IntHookGvaRemoveHook failed: 0x%08x\n", status);
1231  }
1232 
1233  // Since we removed the protection from this page, it is safe to return introGuestRetry. This will re-enter the
1234  // guest at the same instruction, and it will execute it natively. Returning introGuestAllowed will simply
1235  // cause the instruction to be emulated, which is not ideal. In addition, returning anything else than
1236  // introGuestRetry on an execution attempt, will cause the EPT violation handler to dissect the instruction
1237  // and to call the EPT handler for every memory access made by the instruction; in certain cases, this may lead
1238  // to weird scenarios: for example, if we have a piece of code outside any module which places a memory hook,
1239  // the following would happen:
1240  // 1. The code executes & triggers an EPT exec violation;
1241  // 2. Introcore deems the attempt legitimate, and returns allowed instead of retry;
1242  // 3. The EPT callback will dissect the instruction, and it will analyze any other memory accesses;
1243  // 4. If the instruction that triggered the execution EPT violation also makes a write on a shared module,
1244  // we would see this, and we would call the appropriate EPT handlers BUT this will happen without triggering
1245  // the CoW inside the guest.
1246  *Action = introGuestRetry;
1247 
1248  // If the entire VAD was created executable, and the first page executed was deemed legitimate, then remove
1249  // the protection on the entire memory region.
1250  if (pPage->Legitimate)
1251  {
1252  pPage->Vad->ExecCount++;
1253 
1254  status = IntWinVadRemoveRange(pPage->Vad, pPage->RangeStart, pPage->RangeEnd);
1255  if (!INT_SUCCESS(status))
1256  {
1257  ERROR("[ERROR] IntWinVadRemoveRanges failed: 0x%08x\n", status);
1258  }
1259  }
1260  }
1261 
1262 retry_inject_ud:
1263  // Terminate the process, if we decided to or if #UD already pending, inject it again
1264  if ((INT_SUCCESS(status) && (introGuestNotAllowed == *Action) && ((NULL != pProc) && pProc->ProtKillExploit) &&
1265  isCurrentProcess) ||
1266  NULL != entryPendingUD)
1267  {
1268  INTSTATUS status2;
1269 
1270  // If we already injected the same entry, there's no need for another injection, most probably causing an error
1271  if (entryPendingUD != NULL && gVcpu->CurrentUD == entryPendingUD)
1272  {
1273  goto _skip_inject;
1274  }
1275 
1277  if (!INT_SUCCESS(status2))
1278  {
1279  ERROR("[ERROR] IntInjectExceptionInGuest failed, process will not be killed: %08x\n", status2);
1280  }
1281  else
1282  {
1283  if (NULL == entryPendingUD)
1284  {
1285  // If not already pending, add to the list of pending UDs and store the allocated address
1286  // in entryPendingUD
1287  status = IntUDAddToPendingList(regs->Cr3, regs->Rip, currentThread, &entryPendingUD);
1288  if (!INT_SUCCESS(status))
1289  {
1290  ERROR("[ERROR] IntUDAddToPendingList failed: 0x%08x\n", status);
1291  return status;
1292  }
1293  }
1294 
1295  // Set gVcpu->CurrentUD pointer to the allocated address for the tuple
1296  gVcpu->CurrentUD = entryPendingUD;
1297  }
1298 
1299 _skip_inject:
1300  *Action = introGuestRetry;
1301  }
1302 
1303  return status;
1304 }
1305 
1306 
1307 static INTSTATUS
1309  _Inout_ VAD *Context,
1310  _In_ QWORD Cr3,
1311  _In_ QWORD VirtualAddress,
1312  _In_ QWORD PhysicalAddress,
1313  _In_reads_bytes_(DataSize) void *Data,
1314  _In_ DWORD DataSize,
1315  _In_ DWORD Flags
1316  )
1334 {
1335  PVAD pVad = Context;
1336 
1338  UNREFERENCED_PARAMETER(VirtualAddress);
1339  UNREFERENCED_PARAMETER(PhysicalAddress);
1340  UNREFERENCED_PARAMETER(Flags);
1341 
1342  pVad->PathSwapHandle = NULL;
1343 
1344  pVad->Path = IntWinUmPathCreate(Data, DataSize, pVad->SubsectionGva);
1345 
1346  return IntWinModHandleLoadFromVad(pVad->Process, pVad);
1347 }
1348 
1349 
1350 INTSTATUS
1352  _Inout_ WIN_PROCESS_OBJECT *Process
1353  )
1362 {
1363  if (NULL == Process)
1364  {
1366  }
1367 
1368  RbUninit(&Process->VadTree);
1369 
1370  return INT_STATUS_SUCCESS;
1371 }
1372 
1373 
1374 static INTSTATUS
1376  _In_ QWORD VadGva,
1377  _Out_ VAD *Vad,
1378  _In_ BOOLEAN FailOnCorruptRange
1379  )
1397 {
1398  BYTE *vadBuffer = IntWinVadMapShortVad(VadGva);
1399  QWORD flags = 0;
1400  QWORD startVpn, endVpn;
1401 
1402  if (NULL == vadBuffer)
1403  {
1405  }
1406 
1407  Vad->VadGva = VadGva;
1408 
1409  // Parent, Left, and Right are always pointers, so read WordSize from the guest
1410  Vad->Parent = VadShortPtrSize(vadBuffer, Parent);
1411  Vad->Left = VadShortPtrSize(vadBuffer, Left);
1412  Vad->Right = VadShortPtrSize(vadBuffer, Right);
1413 
1414  startVpn = endVpn = 0;
1415  // Starting and Ending Vpn can have different sizes and sometimes can be extended by another High byte
1416  if (WIN_KM_FIELD(VadShort, VpnSize) == 4)
1417  {
1418  startVpn = VadShortDword(vadBuffer, StartingVpn);
1419  endVpn = VadShortDword(vadBuffer, EndingVpn);
1420  }
1421  else
1422  {
1423  startVpn = VadShortQword(vadBuffer, StartingVpn);
1424  endVpn = VadShortQword(vadBuffer, EndingVpn);
1425  }
1426 
1427  // Add the extra byte if it is present
1428  if (0 != WIN_KM_FIELD(VadShort, StartingVpnHigh))
1429  {
1430  startVpn |= ((QWORD)VadShortByte(vadBuffer, StartingVpnHigh) << 32);
1431  }
1432  if (0 != WIN_KM_FIELD(VadShort, EndingVpnHigh))
1433  {
1434  endVpn |= ((QWORD)VadShortByte(vadBuffer, EndingVpnHigh) << 32);
1435  }
1436 
1437  Vad->StartPage = startVpn << 12;
1438  Vad->EndPage = endVpn << 12;
1439 
1440  if (FailOnCorruptRange && Vad->EndPage < Vad->StartPage)
1441  {
1442  ERROR("[ERROR] VAD EndPage is before StartPage: start = 0x%016llx, end = 0x%016llx, vad at 0x%016llx\n",
1443  Vad->StartPage, Vad->EndPage, VadGva);
1444  IntVirtMemUnmap(&vadBuffer);
1446  }
1447 
1448  // The Flags field can have different sizes, so read it into a QWORD
1449  flags = VadShortAnySize(WIN_KM_FIELD(VadShort, FlagsSize), vadBuffer, Flags);
1450 
1451  // Type and Protection are 3 and 5 bits long, but are not the same bits always, so normalize them
1452  Vad->VadType = (flags >> WIN_KM_FIELD(VadFlags, TypeShift)) & WIN_KM_FIELD(VadFlags, TypeMask);
1453  Vad->VadProtection = (flags >> WIN_KM_FIELD(VadFlags, ProtectionShift)) & WIN_KM_FIELD(VadFlags, ProtectionMask);
1454 
1455  // NoChange is always 1 bit and it is present on all Windows versions, so check for it
1456  Vad->NoChange = 0 != (flags & BIT(WIN_KM_FIELD(VadFlags, NoChangeBit)));
1457 
1458  // DeleteInProgress and PrivateFixup are always 1-bit wide, but are not present on all Windows versions, so it is
1459  // easier to check them directly against a mask instead of the method used for NoChange; if they are not used,
1460  // the mask is 0
1461  Vad->DeleteInProgress = 0 != (flags & WIN_KM_FIELD(VadFlags, DeleteInProgressMask));
1462  Vad->PrivateFixup = 0 != (flags & WIN_KM_FIELD(VadFlags, PrivateFixupMask));
1463 
1464  Vad->PageCount = (((Vad->EndPage - Vad->StartPage) >> 12) + 1);
1465  Vad->Protection = IntWinVadVadProtectionToIntroProtection(Vad->VadProtection);
1466 
1467  Vad->HugeVad = (Vad->PageCount * sizeof(VAD_PAGE) >= 4 * ONE_GIGABYTE);
1468  Vad->Path = NULL;
1469  Vad->Process = NULL;
1470 
1471  IntVirtMemUnmap(&vadBuffer);
1472 
1473  return INT_STATUS_SUCCESS;
1474 }
1475 
1476 
1477 static INTSTATUS
1479  _Inout_ VAD *Vad
1480  )
1492 {
1493  DWORD len = 0;
1494  QWORD pathGva = 0;
1495  QWORD tmp = 0;
1496  DWORD subsecOffsetInVad;
1497  DWORD ctlAreaOffsetInSubsec;
1498  DWORD fileObjectOffsetInCtlArea;
1499  DWORD fileLengthOffsetInFileObject;
1500  DWORD fileBufferOffsetInFileObject;
1501  INTSTATUS status;
1502 
1503  if (NULL != Vad->Path)
1504  {
1506  }
1507 
1508  subsecOffsetInVad = WIN_KM_FIELD(VadLong, Subsection);
1509  ctlAreaOffsetInSubsec = WIN_KM_FIELD(Ungrouped, SubsectionCtlArea);
1510  fileObjectOffsetInCtlArea = WIN_KM_FIELD(Ungrouped, CtlAreaFile);
1511  fileLengthOffsetInFileObject = WIN_KM_FIELD(FileObject, NameLength);
1512  fileBufferOffsetInFileObject = WIN_KM_FIELD(FileObject, NameBuffer);
1513 
1514  // Read the _SUBSECTION address.
1515  status = IntKernVirtMemRead(Vad->VadGva + subsecOffsetInVad, gGuest.WordSize, &tmp, NULL);
1516  if (!INT_SUCCESS(status))
1517  {
1518  return status;
1519  }
1520 
1521  if (0 == tmp)
1522  {
1524  }
1525 
1526  Vad->SubsectionGva = tmp;
1527  Vad->Path = IntWinUmPathFetchAndReferenceBySubsection(Vad->SubsectionGva);
1528 
1529  if (NULL != Vad->Path)
1530  {
1531  // If we can reuse the path, then we can already consider it is a module load
1532  return IntWinModHandleLoadFromVad(Vad->Process, Vad);
1533  }
1534 
1535  // Read the _CONTROL_AREA address.
1536  status = IntKernVirtMemRead(tmp + ctlAreaOffsetInSubsec, gGuest.WordSize, &tmp, NULL);
1537  if (!INT_SUCCESS(status))
1538  {
1539  return status;
1540  }
1541 
1542  if (0 == tmp)
1543  {
1545  }
1546 
1547  // Read the _FILE_OBJECT address.
1548  status = IntKernVirtMemRead(tmp + fileObjectOffsetInCtlArea, gGuest.WordSize, &tmp, NULL);
1549  if (!INT_SUCCESS(status))
1550  {
1551  return status;
1552  }
1553 
1554  tmp = EX_FAST_REF_TO_PTR(gGuest.Guest64, tmp);
1555 
1556  if (0 == tmp)
1557  {
1559  }
1560 
1561  status = IntKernVirtMemRead(tmp + fileLengthOffsetInFileObject, sizeof(WORD), &len, NULL);
1562  if (!INT_SUCCESS(status))
1563  {
1564  return status;
1565  }
1566 
1567  status = IntKernVirtMemRead(tmp + fileBufferOffsetInFileObject, gGuest.WordSize, &pathGva, NULL);
1568  if (!INT_SUCCESS(status))
1569  {
1570  return status;
1571  }
1572 
1573  status = IntSwapMemReadData(0, pathGva, len, SWAPMEM_OPT_BP_FAULT, Vad, 0,
1574  IntWinVadHandleFilePathInMemory, NULL, &Vad->PathSwapHandle);
1575  if (!INT_SUCCESS(status))
1576  {
1577  ERROR("[ERROR] IntSwapMemReadData failed: 0x%08x\n", status);
1578  }
1579 
1580  return INT_STATUS_SUCCESS;
1581 }
1582 
1583 
1584 static INTSTATUS
1586  _In_ WIN_PROCESS_OBJECT *Process,
1587  _In_ QWORD VadGva,
1588  _Out_ VAD **Vad,
1589  _In_ BOOLEAN StaticScan
1590  )
1610 {
1611  INTSTATUS status;
1612 
1613  VAD *pVad = HpAllocWithTag(sizeof(*pVad), IC_TAG_VAD);
1614  if (NULL == pVad)
1615  {
1617  }
1618 
1619  // We want to fail if the memory range described by this VAD is not valid.
1620  status = IntWinVadFetchVadFromMemory(VadGva, pVad, TRUE);
1621  if (!INT_SUCCESS(status))
1622  {
1624  ERROR("[ERROR] IntWinVadFetchVadFromMemory failed from GVA %llx: 0x%08x\n", VadGva, status);
1625  return status;
1626  }
1627 
1628  // We don't handle other VAD types except for VadNone and VadImageMap.
1629  if ((pVad->VadType != VadNone) && (pVad->VadType != VadImageMap) && (pVad->VadType != VadWriteWatch))
1630  {
1631  TRACE("[WINVAD] Vad with type %d created at [0x%016llx, 0x%016llx]. Will ignore it.\n",
1632  pVad->VadType, pVad->StartPage, pVad->EndPage);
1634  *Vad = NULL;
1636  }
1637 
1638  pVad->Process = Process;
1639  pVad->Path = NULL;
1640  pVad->VadPages = NULL;
1641  pVad->StaticScan = StaticScan;
1642 
1643  if (VadImageMap == pVad->VadType)
1644  {
1645  status = IntWinVadFetchImageName(pVad);
1646  if (!INT_SUCCESS(status))
1647  {
1648  ERROR("[ERROR] IntWinVadFetchImageName failed for VAD 0x%016llx: 0x%08x\n", pVad->VadGva, status);
1649  }
1650  }
1651 
1652  *Vad = pVad;
1653 
1654  return INT_STATUS_SUCCESS;
1655 }
1656 
1657 
1658 INTSTATUS
1660  _In_ QWORD VadNodeGva,
1661  _In_ DWORD Level,
1662  _In_opt_ void *Context
1663  )
1673 {
1674  const PCHAR prot[] =
1675  {
1676  "noaccess", "readonly", "execute", "execute-read", "readwrite",
1677  "writecopy", "execute-readwrite", "execute-writecopy"
1678  };
1679  VAD vad = {0};
1680  INTSTATUS status;
1681 
1682  UNREFERENCED_PARAMETER(Context);
1683 
1684  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, VadNodeGva))
1685  {
1687  }
1688 
1689  // We simply dump guest memory, we do not care if the range is valid or not.
1690  status = IntWinVadFetchVadFromMemory(VadNodeGva, &vad, FALSE);
1691  if (!INT_SUCCESS(status))
1692  {
1693  return status;
1694  }
1695 
1696  NLOG("0x%016llx (%d): [0x%016llx, 0x%016llx]: Type: %d Prot: 0x%04x (%s)\n",
1697  VadNodeGva, Level, vad.StartPage, vad.EndPage, vad.VadType, vad.VadProtection,
1698  vad.VadProtection >= ARRAYSIZE(prot) ? "" : prot[vad.VadProtection]);
1699 
1700  return INT_STATUS_SUCCESS;
1701 }
1702 
1703 
1705 BOOLEAN
1707  _In_ VAD const *Vad,
1708  _In_ void *Context
1709  )
1718 {
1719  QWORD i;
1720  const char *vadTypes[] =
1721  {
1722  "VadNone",
1723  "VadDevicePhysicalMemory",
1724  "VadImageMap",
1725  "VadAwe",
1726  "VadWriteWatch",
1727  "VadLargePages",
1728  "VadRotatePhysical",
1729  "VadLargePageSection",
1730  };
1731 
1732  UNREFERENCED_PARAMETER(Context);
1733 
1734  if (NULL == Vad)
1735  {
1736  return FALSE;
1737  }
1738 
1739  NLOG(" VAD @ 0x%016llx for [0x%016llx, 0x%016llx], type %-24s, protection: 0x%08x (%c%c%c) "
1740  "Ignored: %d, ExecCount: %d",
1741  Vad->VadGva, Vad->StartPage, Vad->EndPage,
1742  Vad->VadType < sizeof(vadTypes) / sizeof(vadTypes[0]) ? vadTypes[Vad->VadType] : "unknown",
1743  Vad->VadProtection,
1744  (Vad->Protection & PROT_READ) ? 'R' : '-',
1745  (Vad->Protection & PROT_WRITE) ? 'W' : '-',
1746  (Vad->Protection & PROT_EXEC) ? 'X' : '-',
1747  Vad->IsIgnored,
1748  Vad->ExecCount);
1749 
1750  if (NULL != Vad->Path)
1751  {
1752  NLOG(", path '%s'\n", utf16_for_log(Vad->Path->Path));
1753  }
1754  else
1755  {
1756  NLOG("\n");
1757  }
1758 
1759  if (NULL != Vad->VadPages)
1760  {
1761  for (i = 0; i < Vad->PageCount; i++)
1762  {
1763  if (NULL != Vad->VadPages[i])
1764  {
1765  NLOG(" PAGE @ %llx, protection %c%c%c, hook at %p\n",
1766  Vad->VadPages[i]->Address,
1767  (Vad->VadPages[i]->Protection & PROT_READ) ? 'R' : '-',
1768  (Vad->VadPages[i]->Protection & PROT_WRITE) ? 'W' : '-',
1769  (Vad->VadPages[i]->Protection & PROT_EXEC) ? 'X' : '-',
1770  Vad->VadPages[i]->ExecHook);
1771  }
1772  }
1773  }
1774 
1775  return TRUE;
1776 }
1777 
1778 
1780 BOOLEAN
1782  _Inout_ VAD *Vad,
1783  _In_ void *Context
1784  )
1796 {
1797  UNREFERENCED_PARAMETER(Context);
1798 
1799  if (NULL == Vad)
1800  {
1801  return FALSE;
1802  }
1803 
1805 
1806  return TRUE;
1807 }
1808 
1809 
1810 void
1812  _Inout_ WIN_PROCESS_OBJECT *Process
1813  )
1819 {
1821 }
1822 
1823 
1824 QWORD
1826  _In_ QWORD VadRoot,
1827  _In_ QWORD StartPage,
1828  _In_ QWORD EndPage,
1829  _In_ DWORD Level,
1830  _In_ QWORD OldStartPage,
1831  _In_ BOOLEAN LastBranchRight
1832  )
1852 {
1853  INTSTATUS status;
1854  VAD vad = { 0 };
1855  // Workaround for Windows 7/8: the first level isn't in fact a VAD, and we have to follow the right branch.
1856  const BOOLEAN notAVad = (gGuest.OSVersion <= 9200) && (0 == Level);
1857 
1858  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, VadRoot))
1859  {
1860  return 0;
1861  }
1862 
1863  if (Level >= VAD_SEARCH_LIMIT)
1864  {
1865  ERROR("[ERROR] Max recursion level reached, will bail out\n");
1866  return 0;
1867  }
1868 
1869  VadRoot = RTL_BALANCED_NODE_PARENT_TO_PTR(VadRoot);
1870 
1871  // If this is not actually a VAD we allow errors in the memory range that it describes. We are interested only in
1872  // the Left and Right branch values. In the other cases we want to bail out if the range is not valid, because
1873  // our search algorithm will no longer work if Start > End.
1874  status = IntWinVadFetchVadFromMemory(VadRoot, &vad, !notAVad);
1875  if (!INT_SUCCESS(status))
1876  {
1877  ERROR("[ERROR] IntWinVadFetchVadFromMemory failed: 0x%08x\n", status);
1878  return 0;
1879  }
1880 
1881  if (notAVad)
1882  {
1883  return IntWinVadFindNodeInGuestSpace(vad.Right, StartPage, EndPage, Level + 1, 0, TRUE);
1884  }
1885 
1886  if (Level > 0 && vad.StartPage <= OldStartPage && LastBranchRight)
1887  {
1888  ERROR("[ERROR] The in-guest VAD tree seems to be corrupted! Last branch right, "
1889  "current start page: 0x%16llx, old start page: 0x%16llx\n",
1890  vad.StartPage, OldStartPage);
1891  return 0;
1892  }
1893 
1894  if (Level > 0 && vad.StartPage >= OldStartPage && !LastBranchRight)
1895  {
1896  ERROR("[ERROR] The in-guest VAD tree seems to be corrupted! Last branch left, "
1897  "current start page: 0x%16llx, old start page: 0x%16llx\n",
1898  vad.StartPage, OldStartPage);
1899  return 0;
1900  }
1901 
1902  if (StartPage > vad.EndPage)
1903  {
1904  return IntWinVadFindNodeInGuestSpace(vad.Right, StartPage, EndPage, Level + 1, vad.StartPage, TRUE);
1905  }
1906  else if (EndPage < vad.StartPage)
1907  {
1908  return IntWinVadFindNodeInGuestSpace(vad.Left, StartPage, EndPage, Level + 1, vad.StartPage, FALSE);
1909  }
1910  else if (StartPage >= vad.StartPage && EndPage <= vad.EndPage)
1911  {
1912  return vad.VadGva;
1913  }
1914 
1915  return 0;
1916 }
1917 
1918 
1919 INTSTATUS
1921  _In_ QWORD VadNodeGva,
1922  _In_ DWORD Level,
1924  _In_opt_ void *Context
1925  )
1945 {
1946  INTSTATUS status;
1947  QWORD left;
1948  QWORD right;
1949  INTSTATUS failStatus = INT_STATUS_SUCCESS;
1950  VAD vad = { 0 };
1951  // Workaround for Windows 7/8: the first level isn't in fact a VAD.
1952  const BOOLEAN notAVad = (gGuest.OSVersion <= 9200) && (0 == Level);
1953 #define MAX_LEVEL 64
1954 
1955  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, VadNodeGva))
1956  {
1958  }
1959 
1960  if (NULL == Callback)
1961  {
1963  }
1964 
1965  if (Level > MAX_LEVEL)
1966  {
1967  ERROR("[ERROR] Too much recursion: requested level: %d, max level: %d\n", Level, MAX_LEVEL);
1969  }
1970 
1971  // On OSs with _MM_AVL_TABLE in the root, we should convert it to ptr by stripping the last 2 bits.
1972  // Otherwise the structure might be off by some bits and invalid data could be read from the guest.
1973  if (notAVad)
1974  {
1975  VadNodeGva = RTL_BALANCED_NODE_PARENT_TO_PTR(VadNodeGva);
1976  }
1977 
1978  // If this is not actually a VAD we allow errors in the memory range that it describes. We are interested only in
1979  // the Left and Right branch values.
1980  status = IntWinVadFetchVadFromMemory(VadNodeGva, &vad, !notAVad);
1981  if (!INT_SUCCESS(status))
1982  {
1983  ERROR("[ERROR] IntWinVadFetchVadFromMemory failed for 0x%016llx: 0x%08x\n", VadNodeGva, status);
1984  return status;
1985  }
1986 
1987  left = vad.Left;
1988  right = vad.Right;
1989 
1991  {
1992  status = IntWinVadInOrderRecursiveTraversal(left, Level + 1, Callback, Context);
1993  if (!INT_SUCCESS(status))
1994  {
1995  failStatus = status;
1996  }
1997  }
1998 
1999  if (notAVad)
2000  {
2001  // Windows 7 and Windows 8 hold in _EPROCESS.VadRoot a _MM_AVL_TABLE struct. It's Parent points to itself,
2002  // the children may be NULL or valid tree nodes, skip the callback for the fake root
2003  TRACE("[WINVAD] -------> Special Win 7/8 case: 0x%016llx is not an actual VAD. Left = 0x%016llx "
2004  "Right = 0x%016llx\n", VadNodeGva, left, right);
2005  }
2006  else
2007  {
2008  Callback(VadNodeGva, Level, Context);
2009  }
2010 
2011  if (IS_KERNEL_POINTER_WIN(gGuest.Guest64, right))
2012  {
2013  status = IntWinVadInOrderRecursiveTraversal(right, Level + 1, Callback, Context);
2014  if (!INT_SUCCESS(status))
2015  {
2016  failStatus = status;
2017  }
2018  }
2019 
2020  return failStatus;
2021 }
2022 
2023 
2024 INTSTATUS
2026  _In_ PWIN_PROCESS_OBJECT Process,
2028  )
2040 {
2041  if (NULL == Process)
2042  {
2044  }
2045 
2046  if (NULL == Callback)
2047  {
2049  }
2050 
2051  RbWalkInorderTree(&Process->VadTree, Callback, NULL);
2052 
2053  return INT_STATUS_SUCCESS;
2054 }
2055 
2056 
2057 static PVAD
2059  _Inout_ WIN_PROCESS_OBJECT *Process,
2060  _In_ QWORD StartPage,
2061  _In_ QWORD EndPage
2062  )
2079 {
2080  INTSTATUS status;
2081  PVAD pVad;
2082  QWORD vadroot = 0, vadgva = 0;
2083 
2084  status = IntKernVirtMemRead(Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
2085  gGuest.WordSize, &vadroot, NULL);
2086  if (!INT_SUCCESS(status))
2087  {
2088  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
2089  return NULL;
2090  }
2091 
2092  for (DWORD tries = 0; tries < VAD_SEARCH_LIMIT; tries++)
2093  {
2094  vadgva = IntWinVadFindNodeInGuestSpace(vadroot, StartPage, EndPage, 0, 0, FALSE);
2095  if (0 != vadgva)
2096  {
2097  TRACE("[WINVAD] VAD for range [0x%016llx, 0x%016llx] found at 0x%016llx. Tries: %u\n",
2098  StartPage, EndPage, vadgva, tries);
2099  break;
2100  }
2101  }
2102 
2103  if (0 == vadgva)
2104  {
2105  LOG("IntWinVadFindNodeInGuestSpace failed for range [0x%016llx, 0x%016llx] in process %u\n",
2106  StartPage, EndPage, Process->Pid);
2107  return NULL;
2108  }
2109 
2110  status = IntWinVadHandleInsertGeneric(Process, vadgva, FALSE, &pVad);
2111  if (!INT_SUCCESS(status))
2112  {
2113  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for VAD %llx: 0x%08x\n", vadgva, status);
2114  return NULL;
2115  }
2116 
2117  return pVad;
2118 }
2119 
2120 
2121 VAD *
2123  _Inout_ WIN_PROCESS_OBJECT *Process,
2124  _In_ QWORD StartHint,
2125  _In_ QWORD LengthHint
2126  )
2140 {
2141  const QWORD startPage = StartHint & PAGE_MASK;
2142  const QWORD endPage = (StartHint + LengthHint - 1) & PAGE_MASK;
2143  VAD *vad = IntWinVadFindByRange(Process, startPage, endPage);
2144  if (NULL != vad && startPage >= vad->StartPage && endPage <= vad->EndPage)
2145  {
2146  return vad;
2147  }
2148 
2149  vad = IntWinVadRescanVad(Process, startPage, endPage);
2150  if (NULL == vad)
2151  {
2152  LOG("IntWinVadRescanVad failed for [0x%016llx, 0x%016llx] in process %u\n",
2153  startPage, endPage, Process->Pid);
2154  }
2155 
2156  return vad;
2157 }
2158 
2159 
2160 static INTSTATUS
2162  _Inout_ WIN_PROCESS_OBJECT *Process,
2163  _In_ QWORD StartPage,
2164  _In_ QWORD EndPage,
2165  _In_ DWORD VmProtection,
2166  _In_ BOOLEAN AtInsertion
2167  )
2204 
2205 {
2206  INTSTATUS status;
2207  PVAD pVad;
2208  DWORD newprot;
2209 
2210  if (EndPage < StartPage)
2211  {
2213  }
2214 
2215  // Get the associated VAD.
2216  pVad = IntWinVadFindByRange(Process, StartPage, EndPage);
2217  if (NULL == pVad)
2218  {
2219  QWORD vadroot = 0, vadgva = 0;
2220 
2221  TRACE("[WINVAD] Range [%llx, %llx] not cached, searching guest space for VAD...\n", StartPage, EndPage);
2222 
2223  status = IntKernVirtMemRead(Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
2224  gGuest.WordSize,
2225  &vadroot,
2226  NULL);
2227  if (!INT_SUCCESS(status))
2228  {
2229  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
2230  return status;
2231  }
2232 
2233  for (DWORD tries = 0; tries < VAD_SEARCH_LIMIT; tries++)
2234  {
2235  vadgva = IntWinVadFindNodeInGuestSpace(vadroot, StartPage, EndPage, 0, 0, FALSE);
2236  if (0 != vadgva)
2237  {
2238  break;
2239  }
2240  }
2241 
2242  if (0 == vadgva)
2243  {
2244  // We'll only warn and return an informational status as there might be in-guest race conditions.
2245  // For example, calling VirtualProtectEx on a previously freed memory region.
2246  WARNING("[WARNING] IntWinVadFindNodeInGuestSpacefailed to find a VAD for range [%llx, %llx] "
2247  "in process %d\n", StartPage, EndPage, Process->Pid);
2249  }
2250 
2251  TRACE("[WINVAD] VAD for range [%llx, %llx] found at %llx\n", StartPage, EndPage, vadgva);
2252 
2253  status = IntWinVadHandleInsertGeneric(Process, vadgva, FALSE, &pVad);
2254  if (!INT_SUCCESS(status))
2255  {
2256  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for VAD %llx: 0x%08x\n", vadgva, status);
2257  return status;
2258  }
2259  }
2260 
2261  if ((StartPage < pVad->StartPage) || (StartPage > pVad->EndPage))
2262  {
2263  ERROR("[ERROR] The start page lies outside the VAD range: 0x%016llx vs [0x%016llx, 0x%016llx]\n",
2264  StartPage, pVad->StartPage, pVad->EndPage);
2266  }
2267 
2268  if ((EndPage < pVad->StartPage) || (EndPage > pVad->EndPage))
2269  {
2270  ERROR("[ERROR] The end page lies outside the VAD range: 0x%016llx vs [0x%016llx, 0x%016llx]\n",
2271  EndPage, pVad->StartPage, pVad->EndPage);
2273  }
2274 
2275  if (pVad->HugeVad)
2276  {
2277  WARNING("[WARNING] Protecting range [0x%016llx, 0x%016llx] of huge VAD [0x%016llx, 0x%016llx] "
2278  "with %llu pages at GVA 0x%016llx\n",
2279  StartPage, EndPage, pVad->StartPage, pVad->EndPage, pVad->PageCount, pVad->VadGva);
2281  }
2282 
2283  pVad->IsIgnored = IntWinVadIsProbablyNaCl(pVad);
2284  if (pVad->IsIgnored)
2285  {
2286  TRACE("[INFO] Ignoring VAD @ 0x%016llx [0x%016llx, 0x%016llx] for process `%s` (%d)\n",
2287  pVad->VadGva, pVad->StartPage, pVad->EndPage, Process->Name, Process->Pid);
2289  }
2290 
2291  // We are not interested in mapped executable files, so we will skip them.
2292  if (((pVad->VadType == VadImageMap) && (pVad->PageCount > 2)) ||
2293  (VadRotatePhysical == pVad->VadType) ||
2294  (VadDevicePhysicalMemory == pVad->VadType) ||
2295  !pVad->Process->ProtExploits ||
2296  (pVad->ExecCount > MIN((pVad->PageCount / 20), MAX_VAD_EXECS)))
2297  {
2299  }
2300 
2301  // If the function was called due to some VirtualProtect call (or commit with different rights)
2302  // and the Vad.u.VadFlags.NoChange is set, we should bail out, as the OS won't apply the protections to it.
2303  if (pVad->NoChange && !AtInsertion)
2304  {
2306  }
2307 
2308  // Compute the simplified protection mask.
2309  newprot = IntWinVadVmProtectionToIntroProtection(VmProtection);
2310  if (VmProtection & WIN_MM_PAGE_GUARD)
2311  {
2312  pVad->IsStack = TRUE;
2313  }
2314 
2315  // If the pages array was not allocated, do so now.
2316  if (NULL == pVad->VadPages)
2317  {
2318  pVad->VadPages = HpAllocWithTag(sizeof(*pVad->VadPages) * pVad->PageCount, IC_TAG_VAD_PGARR);
2319  if (NULL == pVad->VadPages)
2320  {
2322  }
2323  }
2324 
2325  for (QWORD curpg = (StartPage & PAGE_MASK); curpg <= (EndPage & PAGE_MASK); curpg += PAGE_SIZE)
2326  {
2327  DWORD pos = (DWORD)((curpg - pVad->StartPage) >> 12);
2328 
2329  if (NULL == pVad->VadPages[pos])
2330  {
2331  pVad->VadPages[pos] = HpAllocWithTag(sizeof(**pVad->VadPages), IC_TAG_VAD_PAGE);
2332  if (NULL == pVad->VadPages[pos])
2333  {
2335  }
2336 
2337  // So we can do MIN/MAX on them.
2338  pVad->VadPages[pos]->RangeStart = 0xFFFFFFFFFFFFFFFF;
2339  pVad->VadPages[pos]->RangeEnd = 0;
2340 
2341  // The old page protection was given by the VAD protection.
2342  pVad->VadPages[pos]->Vad = pVad;
2343  pVad->VadPages[pos]->Address = curpg;
2344  pVad->VadPages[pos]->VmProtection = VmProtection;
2345  pVad->VadPages[pos]->Protection = newprot;
2346  }
2347  else
2348  {
2349  pVad->VadPages[pos]->VmProtection = VmProtection;
2350  pVad->VadPages[pos]->Protection = newprot;
2351  }
2352 
2353  // We always store the maximum range, in order to remove as many pages when we detect a legitimate execution.
2354  pVad->VadPages[pos]->RangeStart = MIN(pVad->VadPages[pos]->RangeStart, StartPage);
2355  pVad->VadPages[pos]->RangeEnd = MAX(pVad->VadPages[pos]->RangeEnd, EndPage);
2356 
2357  if ((0 != (newprot & PROT_EXEC)) &&
2358  (NULL == pVad->VadPages[pos]->ExecHook) && (!pVad->VadPages[pos]->Legitimate))
2359  {
2360  status = IntHookGvaSetHook(Process->Cr3, curpg, PAGE_SIZE, IG_EPT_HOOK_EXECUTE,
2361  IntWinVadHandlePageExecution, pVad->VadPages[pos], NULL, 0,
2362  (PHOOK_GVA *)&pVad->VadPages[pos]->ExecHook);
2363  if (!INT_SUCCESS(status))
2364  {
2365  ERROR("[ERROR] IntHookGvaSetHook failed: 0x%08x\n", status);
2366  }
2367  }
2368 
2369  // The page was executable, and now it is not.
2370  if (0 == (newprot & PROT_EXEC) && (NULL != pVad->VadPages[pos]->ExecHook))
2371  {
2372  status = IntHookGvaRemoveHook((HOOK_GVA **)&pVad->VadPages[pos]->ExecHook, 0);
2373  if (!INT_SUCCESS(status))
2374  {
2375  ERROR("[ERROR] IntHookGvaRemoveHook failed: 0x%08x\n", status);
2376  }
2377  }
2378  }
2379 
2380  return INT_STATUS_SUCCESS;
2381 }
2382 
2383 
2384 static INTSTATUS
2386  _Inout_ WIN_PROCESS_OBJECT *Process
2387  )
2397 {
2398  INTSTATUS status;
2399 
2400  status = IntWinVadRemoveProcessTree(Process);
2401  if (!INT_SUCCESS(status))
2402  {
2403  ERROR("[ERROR] IntWinVadRemoveProcessTree failed: 0x%08x\n", status);
2404  return status;
2405  }
2406 
2407  status = IntWinVadImportProcessTree(Process);
2408  if (!INT_SUCCESS(status))
2409  {
2410  ERROR("[ERROR] IntWinVadImportProcessTree failed: 0x%08x\n", status);
2411  return status;
2412  }
2413 
2414  return status;
2415 }
2416 
2417 
2418 static INTSTATUS
2420  _Inout_ WIN_PROCESS_OBJECT *Process,
2421  _In_ QWORD StartPage,
2422  _In_ QWORD EndPage,
2423  _In_ DWORD Level
2424  )
2465 {
2466  INTSTATUS status;
2467  PVAD pVad;
2468 
2469  if (Level >= 2)
2470  {
2471  WARNING("[WARNING] Exceeded max recursion level for VAD deletion @ [0x%016llx, 0x%016llx] %s:%d\n",
2472  StartPage, EndPage, Process->Name, Process->Pid);
2475  }
2476 
2477  if (EndPage < StartPage)
2478  {
2479  WARNING("[WARNING] EndPage is LESS than StartPage: [0x%016llx, 0x%016llx]\n", StartPage, EndPage);
2482  }
2483 
2484  pVad = IntWinVadFindByRange(Process, StartPage, EndPage);
2485  if (NULL == pVad)
2486  {
2487  // Since we ignore all VAD types except for VadNone and VadImageMap, we don't have to log error here or
2488  // return an error.
2489  }
2490  else if ((StartPage == pVad->StartPage) && (EndPage == pVad->EndPage))
2491  {
2492  RbDeleteNode(&Process->VadTree, &pVad->RbNode);
2493 
2494  IntWinVadDestroyObject(&pVad);
2495  }
2496  else if (StartPage == pVad->StartPage)
2497  {
2498  // Only the lower sub-range is deleted
2499  QWORD newStart = EndPage + PAGE_SIZE;
2500 
2501  TRACE("[WINVAD] Adjusting VAD 0x%016llx. Old start: 0x%016llx New start: 0x%016llx "
2502  "for process %s:%d (0x%016llx)\n",
2503  pVad->VadGva, pVad->StartPage, newStart, Process->Name, Process->Pid, Process->EprocessAddress);
2504 
2505  status = IntWinVadAdjustRange(pVad, newStart, pVad->EndPage);
2506  if (!INT_SUCCESS(status))
2507  {
2508  ERROR("[ERROR] IntWinVadAdjustRange failed for [0x%016llx, 0x%016llx] in VAD 0x%016llx "
2509  "process 0x%016llx: 0x%08x\n",
2510  StartPage, EndPage, pVad->VadGva, Process->EprocessAddress, status);
2511  }
2512  }
2513  else if (EndPage == pVad->EndPage)
2514  {
2515  // Only the upper sub-range is deleted
2516  QWORD newEnd = StartPage - PAGE_SIZE;
2517 
2518  TRACE("[WINVAD] Adjusting VAD 0x%016llx. Old end: 0x%016llx New end: 0x%016llx for process %s:%d (0x%016llx)\n",
2519  pVad->VadGva, pVad->EndPage, newEnd, Process->Name, Process->Pid, Process->EprocessAddress);
2520 
2521  status = IntWinVadAdjustRange(pVad, pVad->StartPage, newEnd);
2522  if (!INT_SUCCESS(status))
2523  {
2524  ERROR("[ERROR] IntWinVadAdjustRange failed for [0x%016llx, 0x%016llx] in VAD 0x%016llx "
2525  "process 0x%016llx: 0x%08x\n",
2526  StartPage, EndPage, pVad->VadGva, Process->EprocessAddress, status);
2527  }
2528  }
2529  else
2530  {
2531  TRACE("[WINVAD] Guest attempts to delete VAD [%016llx, %016llx], but we matched with VAD [%016llx, %016llx]"
2532  ", will reimport process tree for %s:%d\n",
2533  StartPage, EndPage, pVad->StartPage, pVad->EndPage,
2534  Process->Name, Process->Pid);
2535 
2536  IntPauseVcpus();
2537 
2538  status = IntWinVadReimportProcessTree(Process);
2539  if (!INT_SUCCESS(status))
2540  {
2541  ERROR("[ERROR] IntWinVadReimportProcessTree failed: 0x%08x\n", status);
2542  goto _resume_maybe_enter_dbg;
2543  }
2544 
2545  status = IntWinVadHandleDeleteGeneric(Process, StartPage, EndPage, Level + 1);
2546  if (!INT_SUCCESS(status))
2547  {
2548  ERROR("[ERROR] IntWinVadHandleDeleteGeneric failed: 0x%08x\n", status);
2549  goto _resume_maybe_enter_dbg;
2550  }
2551 
2552 _resume_maybe_enter_dbg:
2553  IntResumeVcpus();
2554 
2555  if (!INT_SUCCESS(status))
2556  {
2558  }
2559  }
2560 
2561  return INT_STATUS_SUCCESS;
2562 }
2563 
2564 
2565 static INTSTATUS
2567  _Inout_ WIN_PROCESS_OBJECT *Process,
2568  _In_ QWORD VadAddress,
2569  _In_ BOOLEAN StaticScan,
2570  _Out_opt_ VAD **Vad
2571  )
2601 
2602 {
2603  INTSTATUS status;
2604  PVAD pVad = NULL;
2605  BOOLEAN previouslyMonitored;
2606 
2607  if (Vad != NULL)
2608  {
2609  *Vad = NULL;
2610  }
2611 
2612  previouslyMonitored = !!(Process->MonitorVad);
2613 
2614  status = IntWinVadCreateObject(Process, VadAddress, &pVad, StaticScan);
2615  if (!INT_SUCCESS(status))
2616  {
2617  ERROR("[ERROR] IntWinVadCreateObject failed: 0x%08x\n", status);
2618 
2619  return status;
2620  }
2621 
2622  if (NULL != pVad && Process->MonitorVad)
2623  {
2624  BOOLEAN hugeNoWrite;
2625  const QWORD maxTries = pVad->PageCount + 1;
2626  QWORD tryCount = 0;
2627 
2628  do
2629  {
2630  PVAD toRemove;
2631 
2632  status = RbInsertNode(&Process->VadTree, &pVad->RbNode);
2633  if (INT_STATUS_KEY_ALREADY_EXISTS != status)
2634  {
2635  // We managed to insert it (or another error occurred), break out of the loop
2636  break;
2637  }
2638 
2639  WARNING("[WARNING] [WINVAD] Special case `INT_STATUS_KEY_ALREADY_EXISTS` while inserting 0x%016llx "
2640  "[0x%016llx, 0x%016llx] in 0x%016llx (PID %u)\n",
2641  pVad->VadGva, pVad->StartPage, pVad->EndPage, Process->EprocessAddress, Process->Pid);
2642 
2643  toRemove = IntWinVadFindByRange(Process, pVad->StartPage, pVad->EndPage);
2644  if (NULL == toRemove)
2645  {
2646  ERROR("[ERROR] IntWinVadFindByRange failed for [%016llx, %016llx]\n", pVad->StartPage, pVad->EndPage);
2648  IntWinVadDestroyObject(&pVad);
2649 
2650  return status;
2651  }
2652 
2653  status = IntWinVadHandleDeleteGeneric(Process, toRemove->StartPage, toRemove->EndPage, 0);
2654  if (!INT_SUCCESS(status))
2655  {
2656  ERROR("[ERROR] IntWinVadHandleDeleteGeneric failed for [0x%016llx, 0x%016llx] "
2657  "in process 0x%016llx: 0x%08x\n",
2658  toRemove->StartPage, toRemove->EndPage, Process->EprocessAddress, status);
2659  }
2660 
2661  tryCount++;
2662  } while (tryCount < maxTries);
2663  if (!INT_SUCCESS(status))
2664  {
2665  ERROR("[ERROR] RbInsertNode failed for [0x%016llx, 0x%016llx] in process PID %u: 0x%08x\n",
2666  pVad->StartPage, pVad->EndPage, Process->Pid, status);
2668  IntWinVadDestroyObject(&pVad);
2669 
2670  return status;
2671  }
2672 
2673  pVad->IsIgnored = IntWinVadIsProbablyNaCl(pVad);
2674  if (pVad->IsIgnored)
2675  {
2676  TRACE("[INFO] Ignoring VAD @ 0x%016llx [0x%016llx, 0x%016llx] for process `%s` (%d)\n",
2677  pVad->VadGva, pVad->StartPage, pVad->EndPage, Process->Name, Process->Pid);
2678  }
2679 
2680  hugeNoWrite = (pVad->PageCount >= 65536) && (0 == (pVad->Protection & PROT_WRITE));
2681 
2682  // If needed, monitor these pages.
2683  if ((!pVad->IsIgnored) && (!hugeNoWrite) && (pVad->Protection & PROT_EXEC) &&
2684  ((pVad->VadType != VadImageMap) || (pVad->PageCount <= 2)))
2685  {
2686  status = IntWinVadHandleProtectGeneric(Process, pVad->StartPage, pVad->EndPage,
2688  if (!INT_SUCCESS(status))
2689  {
2690  ERROR("[ERROR] IntWinVadHandleProtectGeneric failed: 0x%08x\n", status);
2691  }
2692  }
2693  }
2694  else if (pVad != NULL && previouslyMonitored)
2695  {
2696  //
2697  // We decided on the current VAD (which is also the main module) that VAD should not be monitored
2698  // anymore. Thus the current VAD should be destroyed. Note that the VADs inserted before this
2699  // would have already been destroyed, due to the fact that we called IntWinVadRemoveProcessTree,
2700  // but the current VAD has not got the chance to be added into the tree - thus it will be leaked
2701  // otherwise.
2702  // Also, a big note to this is the fact that a caller might externally call this function mistakenly
2703  // for non-protected (and non-vad-monitored) processes. As a safe guard, we'll destroy the VAD only
2704  // if it was decided in IntWinVadCreateObject that from now on we should not monitor vad anymore.
2705  //
2706  IntWinVadDestroyObject(&pVad);
2707  }
2708 
2709  if (Vad != NULL)
2710  {
2711  *Vad = pVad;
2712  }
2713  return INT_STATUS_SUCCESS;
2714 }
2715 
2716 
2717 static INTSTATUS
2719  _In_ QWORD VadNodeGva,
2720  _In_ DWORD Level,
2721  _Inout_ WIN_PROCESS_OBJECT *Process
2722  )
2736 {
2737  INTSTATUS status;
2738 
2739  UNREFERENCED_PARAMETER(Level);
2740 
2741  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, VadNodeGva))
2742  {
2744  }
2745 
2746  // It is possible that during VAD iteration we decided to remove the process protection (based on the Main Module)
2747  // Thus, don't insert the current node if MonitorVad was cleared.
2748  if (!Process->MonitorVad)
2749  {
2751  }
2752 
2753  status = IntWinVadHandleInsertGeneric(Process, VadNodeGva, TRUE, NULL);
2754  if (!INT_SUCCESS(status))
2755  {
2756  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for 0x%016llx in process %d: 0x%08x\n",
2757  VadNodeGva, Process->Pid, status);
2758  return status;
2759  }
2760 
2761  TRACE("[WINVAD] VAD 0x%016llx found at static scan on level %d\n", VadNodeGva, Level);
2762 
2763  return INT_STATUS_SUCCESS;
2764 }
2765 
2766 
2767 INTSTATUS
2769  _Inout_ WIN_PROCESS_OBJECT *Process
2770  )
2782 {
2783  INTSTATUS status;
2784  QWORD root = 0;
2785 
2786  if (NULL == Process)
2787  {
2789  }
2790 
2791  status = IntKernVirtMemRead(Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
2792  gGuest.WordSize,
2793  &root,
2794  NULL);
2795  if (!INT_SUCCESS(status))
2796  {
2797  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
2798  return status;
2799  }
2800 
2801  if (0 == root)
2802  {
2803  TRACE("[WINVAD] Skipping static scan for process 0x%016llx because root @ 0x%016llx is 0\n",
2804  Process->EprocessAddress, Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot));
2806  }
2807 
2808  TRACE("[WINVAD] Starting static scan for process 0x%016llx from root @ 0x%016llx = 0x%016llx\n",
2809  Process->EprocessAddress,
2810  Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
2811  root);
2812 
2814  if (!INT_SUCCESS(status))
2815  {
2816  ERROR("[ERROR] IntWinVadInOrderRecursiveTraversal failed for root 0x%016llx: 0x%08x\n", root, status);
2817  return status;
2818  }
2819 
2820  return INT_STATUS_SUCCESS;
2821 }
2822 
2823 
2824 INTSTATUS
2826  _In_ void const *Detour
2827  )
2845 {
2846  INTSTATUS status;
2847  WIN_PROCESS_OBJECT *pProc;
2848  QWORD args[2];
2849  QWORD vadGva;
2850  QWORD eprocessGva;
2851 
2852  if (NULL == Detour)
2853  {
2855  }
2856 
2857  // the parameters are the same on x86 as on x64
2858  // RCX: pointer to a MMVAD or MMVAD_SHORT structure. Private VADs (created by VirtualAlloc(Ex) calls) are
2859  // always MMVAD_SHORT
2860  // RDX: pointer to the EPROCESS structure of the process for which the VAD is created. This might not be in
2861  // the process list yet
2862  status = IntDetGetArguments(Detour, 2, args);
2863  if (!INT_SUCCESS(status))
2864  {
2865  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
2866  goto cleanup_and_exit;
2867  }
2868 
2869  vadGva = args[0];
2870  eprocessGva = args[1];
2871 
2872  // Get the process object.
2873  pProc = IntWinProcFindObjectByEprocess(eprocessGva);
2874  if (!pProc || !pProc->MonitorVad)
2875  {
2876  status = INT_STATUS_NOT_NEEDED_HINT;
2877  goto cleanup_and_exit;
2878  }
2879 
2880  status = IntWinVadHandleInsertGeneric(pProc, vadGva, FALSE, NULL);
2881  if (INT_STATUS_NOT_FOUND != status && !INT_SUCCESS(status))
2882  {
2883  ERROR("[ERROR] IntWinVadHandleInsertionGeneric failed for process 0x%016llx VAD 0x%016llx: 0x%08x\n",
2884  eprocessGva, vadGva, status);
2885  goto cleanup_and_exit;
2886  }
2887 
2888  status = INT_STATUS_SUCCESS;
2889 
2890 cleanup_and_exit:
2891 
2892  return status;
2893 }
2894 
2895 
2896 INTSTATUS
2898  _In_ void const *Detour
2899  )
2916 {
2917  INTSTATUS status;
2918  PWIN_PROCESS_OBJECT pProc = NULL;
2919  PIG_ARCH_REGS pRegs = NULL;
2920  QWORD vadGva = 0;
2921 
2922  if (NULL == Detour)
2923  {
2925  }
2926 
2927  pRegs = &gVcpu->Regs;
2928 
2929  status = IntDetGetArgument(Detour, 0, NULL, 0, &vadGva);
2930  if (!INT_SUCCESS(status))
2931  {
2932  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
2933  goto cleanup_and_exit;
2934  }
2935 
2936  pProc = IntWinProcFindObjectByCr3(pRegs->Cr3);
2937  if (!pProc || !pProc->MonitorVad)
2938  {
2939  status = INT_STATUS_NOT_NEEDED_HINT;
2940  goto cleanup_and_exit;
2941  }
2942 
2943  status = IntWinVadHandleInsertGeneric(pProc, vadGva, FALSE, NULL);
2944  if (INT_STATUS_NOT_FOUND != status && !INT_SUCCESS(status))
2945  {
2946  ERROR("[ERROR] IntWinVadHandleInsertionGeneric failed for process 0x%016llx VAD 0x%016llx: 0x%08x\n",
2947  pProc->EprocessAddress, vadGva, status);
2948  goto cleanup_and_exit;
2949  }
2950 
2951  status = INT_STATUS_SUCCESS;
2952 
2953 cleanup_and_exit:
2954 
2955  return status;
2956 }
2957 
2959 INTSTATUS
2961  _In_ QWORD FunctionAddress,
2962  _Inout_ API_HOOK_HANDLER *Handler,
2963  _In_ void *Descriptor
2964  )
2981 {
2982  API_HOOK_HANDLER *pHandler = Handler;
2983 
2984  UNREFERENCED_PARAMETER(FunctionAddress);
2985  UNREFERENCED_PARAMETER(Descriptor);
2986 
2987  if (gGuest.Guest64)
2988  {
2989  *(DWORD *)(pHandler->Code + 0x0d) = WIN_KM_FIELD(Pcr, CurrentThread);
2990 
2991  *(DWORD *)(pHandler->Code + 0x14) = WIN_KM_FIELD(Thread, AttachedProcess);
2992 
2993  *(DWORD *)(pHandler->Code + 0x1f) = WIN_KM_FIELD(Thread, Process);
2994 
2995  *(DWORD *)(pHandler->Code + 0x25) = WIN_KM_FIELD(Process, Spare);
2996  *(DWORD *)(pHandler->Code + 0x2d) = WIN_KM_FIELD(Process, Spare);
2997  }
2998  else
2999  {
3001  {
3002  // Stdcall
3003  *(BYTE *)(pHandler->Code + 0x3) = 0x10;
3004  }
3005  else
3006  {
3007  // Fastcall
3008  *(BYTE *)(pHandler->Code + 0x3) = 0x8;
3009  }
3010 
3011  *(DWORD *)(pHandler->Code + 0x0c) = WIN_KM_FIELD(Pcr, CurrentThread);
3012 
3013  *(DWORD *)(pHandler->Code + 0x12) = WIN_KM_FIELD(Thread, AttachedProcess);
3014 
3015  *(DWORD *)(pHandler->Code + 0x1c) = WIN_KM_FIELD(Thread, Process);
3016 
3017  *(DWORD *)(pHandler->Code + 0x22) = WIN_KM_FIELD(Process, Spare);
3018  *(DWORD *)(pHandler->Code + 0x2a) = WIN_KM_FIELD(Process, Spare);
3019  }
3020 
3021  return INT_STATUS_SUCCESS;
3022 }
3023 
3024 
3025 INTSTATUS
3027  _In_ void const *Detour
3028  )
3061 {
3062  WIN_PROCESS_OBJECT *pProc;
3063  IG_ARCH_REGS *regs;
3064  INTSTATUS status;
3065  QWORD gvaVad;
3066  QWORD protPage;
3067  QWORD protSize;
3068  DWORD vmProt;
3069  QWORD endPage;
3070  QWORD args[4] = {0};
3071  VAD *pVad;
3072 
3074 
3075  regs = &gVcpu->Regs;
3076  pProc = IntWinProcFindObjectByCr3(regs->Cr3);
3077 
3078  if (!pProc || !pProc->Protected || !pProc->MonitorVad)
3079  {
3080  // Nothing to do
3081  goto cleanup_and_exit;
3082  }
3083 
3084  status = IntDetGetArguments(Detour, 4, args);
3085  if (!INT_SUCCESS(status))
3086  {
3087  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
3088  goto cleanup_and_exit;
3089  }
3090 
3091  gvaVad = args[0];
3092  protPage = args[1];
3093  protSize = args[2];
3094  vmProt = (DWORD)args[3];
3095 
3096  // Try to find an existing VAD
3097  pVad = IntWinVadFindByVa(pProc, protPage);
3098  if (NULL != pVad)
3099  {
3100  if (gvaVad != pVad->VadGva)
3101  {
3102  // This VAD was deleted in the meantime, try to get it back
3103  status = IntWinVadHandleInsertGeneric(pProc, gvaVad, FALSE, NULL);
3104  if (!INT_SUCCESS(status))
3105  {
3106  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for 0x%016llx: 0x%08x\n", gvaVad, status);
3107  goto cleanup_and_exit;
3108  }
3109  }
3110  }
3111  else
3112  {
3113  status = IntWinVadHandleInsertGeneric(pProc, gvaVad, FALSE, NULL);
3114  if (!INT_SUCCESS(status))
3115  {
3116  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for 0x%016llx: 0x%08x\n", gvaVad, status);
3117  goto cleanup_and_exit;
3118  }
3119  }
3120 
3121  // Now apply the protection change. Note that VAD ranges are inclusive, so the end page is the last page
3122  // contained by the VAD
3123  endPage = (protPage + protSize - 1) & PAGE_MASK;
3124  protPage &= PAGE_MASK;
3125 
3126  status = IntWinVadHandleProtectGeneric(pProc, protPage, endPage, vmProt, FALSE);
3127  if (!INT_SUCCESS(status))
3128  {
3129  ERROR("[ERROR] IntWinVadHandleProtectGeneric failed for [0x%016llx, 0x%016llx]: 0x%08x\n",
3130  protPage, endPage, status);
3131  goto cleanup_and_exit;
3132  }
3133 
3134 cleanup_and_exit:
3136 
3137  return INT_STATUS_SUCCESS;
3138 }
3139 
3140 
3141 INTSTATUS
3143  _In_ void const *Detour
3144  )
3160 {
3161  INTSTATUS status;
3162  PIG_ARCH_REGS pRegs;
3163  PWIN_PROCESS_OBJECT pProc;
3164  QWORD vadGva;
3165 
3166  if (NULL == Detour)
3167  {
3169  }
3170 
3171  pRegs = &gVcpu->Regs;
3172 
3173  status = IntDetGetArgument(Detour, 0, NULL, 0, &vadGva);
3174  if (!INT_SUCCESS(status))
3175  {
3176  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
3177  return status;
3178  }
3179 
3180  pProc = IntWinProcFindObjectByCr3(pRegs->Cr3);
3181  if (NULL == pProc || !pProc->MonitorVad)
3182  {
3184  }
3185 
3186  status = IntWinVadHandleInsertGeneric(pProc, vadGva, FALSE, NULL);
3187  if (INT_STATUS_NOT_FOUND != status && !INT_SUCCESS(status))
3188  {
3189  ERROR("[ERROR] IntWinVadHandleInsertionGeneric failed for VAD 0x%016llx: 0x%08x\n", vadGva, status);
3190  }
3191 
3192  return status;
3193 }
3194 
3195 
3196 INTSTATUS
3198  _In_ void const *Detour
3199  )
3217 {
3218  QWORD startPage;
3219  QWORD endPage;
3220  PIG_ARCH_REGS pRegs;
3221  PWIN_PROCESS_OBJECT pProcess;
3222  QWORD args[2];
3223  INTSTATUS status;
3224 
3225  if (NULL == Detour)
3226  {
3228  }
3229 
3230  pRegs = &gVcpu->Regs;
3231 
3232  status = IntDetGetArguments(Detour, 2, args);
3233  if (!INT_SUCCESS(status))
3234  {
3235  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
3236  return status;
3237  }
3238 
3239  startPage = args[0];
3240  endPage = args[1];
3241 
3242  // Align addresses to page boundaries
3243  startPage &= PAGE_MASK;
3244  endPage &= PAGE_MASK;
3245 
3246  // This function is always executed in the context of the process from who's address space the pages are removed
3247  // so we can simply get it by the current Cr3
3248  pProcess = IntWinProcFindObjectByCr3(pRegs->Cr3);
3249  if (!pProcess || !pProcess->MonitorVad)
3250  {
3251  // No process was created yet, or the process is not VAD monitored - bail out.
3253  }
3254 
3255  // Delete the VAD from our internal tree.
3256  status = IntWinVadHandleDeleteGeneric(pProcess, startPage, endPage, 0);
3257  if (!INT_SUCCESS(status))
3258  {
3259  ERROR("[ERROR] IntWinVadHandleDeleteGeneric failed: 0x%08x\n", status);
3260  return status;
3261  }
3262 
3263  return INT_STATUS_SUCCESS;
3264 }
3265 
3266 
3267 INTSTATUS
3269  _In_ void const *Detour
3270  )
3288 {
3289  QWORD startPage;
3290  QWORD endPage;
3291  PIG_ARCH_REGS pRegs;
3292  PWIN_PROCESS_OBJECT pProcess;
3293  QWORD args[2];
3294  INTSTATUS status;
3295 
3296  if (NULL == Detour)
3297  {
3299  }
3300 
3301  pRegs = &gVcpu->Regs;
3302 
3303  status = IntDetGetArguments(Detour, 2, args);
3304  if (!INT_SUCCESS(status))
3305  {
3306  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
3307  return status;
3308  }
3309 
3310  startPage = args[0];
3311  endPage = args[1];
3312 
3313  // Align addresses to page boundaries
3314  startPage &= PAGE_MASK;
3315  endPage &= PAGE_MASK;
3316 
3317  // This function is always executed in the context of the process from who's address space the pages are removed
3318  // so we can simply get it by the current Cr3
3319  pProcess = IntWinProcFindObjectByCr3(pRegs->Cr3);
3320  if (!pProcess || !pProcess->MonitorVad)
3321  {
3322  // No process was created yet, or the process is not VAD monitored - bail out.
3324  }
3325 
3326  // Delete the VAD from our internal tree.
3327  status = IntWinVadHandleDeleteGeneric(pProcess, startPage, endPage, 0);
3328  if (!INT_SUCCESS(status))
3329  {
3330  ERROR("[ERROR] IntWinVadHandleDeleteGeneric failed: 0x%08x\n", status);
3331  return status;
3332  }
3333 
3334  return INT_STATUS_SUCCESS;
3335 }
3336 
3337 
3338 INTSTATUS
3340  _In_ void const *Detour
3341  )
3367 {
3368  INTSTATUS status;
3369  QWORD dstEproc = 0;
3370  QWORD baseGva = 0;
3371  QWORD startPage = 0;
3372  QWORD endPage = 0;
3373  QWORD length = 0;
3374  QWORD newRights; // WIN_MM_PAGE_* constants (as passed to VirtualProtect(Ex))
3375  WIN_PROCESS_OBJECT *pDestProc;
3376  QWORD args[4];
3377 
3378  status = IntDetGetArgument(Detour, 0, NULL, 0, &dstEproc);
3379  if (!INT_SUCCESS(status))
3380  {
3381  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
3382  goto cleanup_and_exit;
3383  }
3384 
3385  pDestProc = IntWinProcFindObjectByEprocess(dstEproc);
3386  if (!pDestProc || !pDestProc->MonitorVad || !pDestProc->ProtExploits)
3387  {
3388  status = INT_STATUS_NOT_NEEDED_HINT;
3389  goto cleanup_and_exit;
3390  }
3391 
3392  status = IntDetGetArguments(Detour, 4, args);
3393  if (!INT_SUCCESS(status))
3394  {
3395  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
3396  goto cleanup_and_exit;
3397  }
3398 
3399  status = IntKernVirtMemRead(args[1], gGuest.WordSize, &baseGva, NULL);
3400  if (!INT_SUCCESS(status))
3401  {
3402  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
3403  goto cleanup_and_exit;
3404  }
3405 
3406  status = IntKernVirtMemRead(args[2], gGuest.WordSize, &length, NULL);
3407  if (!INT_SUCCESS(status))
3408  {
3409  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
3410  goto cleanup_and_exit;
3411  }
3412 
3413  newRights = args[3] & 0xFFFFFFFF;
3414 
3415  // VirtualProtect documentation: The region of affected pages includes all pages containing one or more bytes in
3416  // the range from the lpAddress parameter to (lpAddress+dwSize). This means that a 2-byte range straddling a page
3417  // boundary causes the protection attributes of both pages to be changed.
3418 
3419  endPage = (baseGva + length - 1) & PAGE_MASK;
3420  startPage = baseGva & PAGE_MASK;
3421 
3422  status = IntWinVadHandleProtectGeneric(pDestProc, startPage, endPage, (DWORD)newRights, FALSE);
3423  if (!INT_SUCCESS(status))
3424  {
3425  ERROR("[ERROR] IntWinVadHandleProtectGeneric failed for [0x%016llx, 0x%016llx] in process 0x%016llx: 0x%08x\n",
3426  startPage, endPage, pDestProc->EprocessAddress, status);
3427  goto cleanup_and_exit;
3428  }
3429 
3430 cleanup_and_exit:
3431 
3432  return status;
3433 }
3434 
3435 
3436 BOOLEAN
3438  _In_ const VAD *Vad
3439  )
3451 {
3452  INTSTATUS status;
3453  VAD dummy = { 0 };
3454  VAD parent = { 0 };
3455 
3456  if (NULL == Vad)
3457  {
3458  return FALSE;
3459  }
3460 
3461  // We allow possible corrupt ranges.
3462  status = IntWinVadFetchVadFromMemory(Vad->VadGva, &dummy, FALSE);
3463  if (!INT_SUCCESS(status))
3464  {
3465  ERROR("[ERROR] Could not fetch VAD 0x%016llx from memory: 0x%08x\n", Vad->VadGva, status);
3466  return FALSE;
3467  }
3468 
3469  // If the parent value is not a valid kernel pointer, we can assume the VAD was not inserted yet. The parent value
3470  // seems to always be 0xFFFFFFFE on x86/0xFFFFFFFFFFFFFFFE on x64, but we allow a more relaxed interval, for safety.
3471  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, dummy.Parent) ||
3472  (dummy.Parent == 0) ||
3473  ((dummy.Parent >= 0xFFFFFFF0) && (dummy.Parent <= 0xFFFFFFFF)) ||
3474  ((dummy.Parent >= 0xFFFFFFFFFFFFFFF0) && (dummy.Parent <= 0xFFFFFFFFFFFFFFFF)))
3475  {
3476  return FALSE;
3477  }
3478 
3479  // Red is bit 0 and Balance is bit 1. We allow possible corrupt ranges.
3480  status = IntWinVadFetchVadFromMemory(dummy.Parent & (~3), &parent, FALSE);
3481  if (!INT_SUCCESS(status))
3482  {
3483  WARNING("[WARNING] IntWinVadFetchVadFromMemory failed for parent 0x%016llx: 0x%08x\n",
3484  dummy.Parent & (~3), status);
3485  return FALSE;
3486  }
3487 
3488  // We can also verify for now that the parent has either the left or right node the current VAD
3489  if (parent.Left != Vad->VadGva && parent.Right != Vad->VadGva)
3490  {
3491  WARNING("[WARNING] The current VAD's parent doesn't have as a child 0x%016llx "
3492  "(left 0x%016llx, right: 0x%016llx)\n",
3493  Vad->VadGva, parent.Left, parent.Right);
3494  return FALSE;
3495  }
3496 
3497  if (Vad->NoChange != Vad->PrivateFixup || Vad->DeleteInProgress)
3498  {
3499  WARNING("[WARNING] NoChange is %d, PrivateFixup is %d, DeleteInProgress is %d, "
3500  "the VAD doesn't seem to be considered in the tree!\n",
3501  Vad->NoChange, Vad->PrivateFixup, Vad->DeleteInProgress);
3502  return FALSE;
3503  }
3504 
3505 
3506  return TRUE;
3507 }
3508 
3509 
3511 INTSTATUS
3513  _In_ QWORD FunctionAddress,
3514  _Inout_ API_HOOK_HANDLER *Handler,
3515  _In_ void *Descriptor
3516  )
3531 {
3532  API_HOOK_HANDLER *pHandler = Handler;
3533 
3534  UNREFERENCED_PARAMETER(FunctionAddress);
3535  UNREFERENCED_PARAMETER(Descriptor);
3536 
3537  if (gGuest.Guest64)
3538  {
3539  if (gGuest.OSVersion == 9600)
3540  {
3541  *(DWORD *)(&pHandler->Code[9]) = WIN_KM_FIELD(Process, Spare);
3542  *(DWORD *)(&pHandler->Code[18]) = WIN_KM_FIELD(Process, Spare);
3543  }
3544  else
3545  {
3546  *(DWORD *)(&pHandler->Code[37]) = WIN_KM_FIELD(Process, Spare);
3547  *(DWORD *)(&pHandler->Code[45]) = WIN_KM_FIELD(Process, Spare);
3548  }
3549  }
3550  else
3551  {
3552  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 7602)
3553  {
3554  *(DWORD *)(&pHandler->Code[30]) = WIN_KM_FIELD(Process, Spare);
3555  }
3556  else if (gGuest.OSVersion == 9200)
3557  {
3558  *(DWORD *)(&pHandler->Code[7]) = WIN_KM_FIELD(Process, Spare);
3559  }
3560  else if (gGuest.OSVersion >= 9600)
3561  {
3562  *(DWORD *)(&pHandler->Code[13]) = WIN_KM_FIELD(Process, Spare);
3563  }
3564  }
3565 
3566  return INT_STATUS_SUCCESS;
3567 }
3568 
3569 
3571 INTSTATUS
3573  _In_ QWORD FunctionAddress,
3574  _Inout_ API_HOOK_HANDLER *Handler,
3575  _In_ void *Descriptor
3576  )
3591 {
3592  API_HOOK_HANDLER *pHandler = Handler;
3593 
3594  UNREFERENCED_PARAMETER(FunctionAddress);
3595  UNREFERENCED_PARAMETER(Handler);
3596  UNREFERENCED_PARAMETER(Descriptor);
3597 
3598  if (gGuest.Guest64)
3599  {
3600  *(DWORD *)(&pHandler->Code[37]) = WIN_KM_FIELD(Process, Spare);
3601  *(DWORD *)(&pHandler->Code[45]) = WIN_KM_FIELD(Process, Spare);
3602  }
3603  else
3604  {
3605  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 7602)
3606  {
3607  *(DWORD *)(&pHandler->Code[30]) = WIN_KM_FIELD(Process, Spare);
3608  }
3609  else if (gGuest.OSVersion >= 9200)
3610  {
3611  *(DWORD *)(&pHandler->Code[33]) = WIN_KM_FIELD(Process, Spare);
3612  }
3613  }
3614 
3615  return INT_STATUS_SUCCESS;
3616 }
3617 
3618 
3620 INTSTATUS
3622  _In_ QWORD FunctionAddress,
3623  _Inout_ API_HOOK_HANDLER *Handler,
3624  _In_ void *Descriptor
3625  )
3640 {
3641  API_HOOK_HANDLER *pHandler = Handler;
3642 
3643  UNREFERENCED_PARAMETER(FunctionAddress);
3644  UNREFERENCED_PARAMETER(Descriptor);
3645 
3646  if (gGuest.Guest64)
3647  {
3648  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 9200)
3649  {
3650  *(DWORD *)(&pHandler->Code[8]) = WIN_KM_FIELD(Process, Spare);
3651  *(DWORD *)(&pHandler->Code[16]) = WIN_KM_FIELD(Process, Spare);
3652  }
3653  else if (gGuest.OSVersion >= 9600)
3654  {
3655  *(DWORD *)(&pHandler->Code[9]) = WIN_KM_FIELD(Process, Spare);
3656  *(DWORD *)(&pHandler->Code[17]) = WIN_KM_FIELD(Process, Spare);
3657  }
3658  }
3659  else
3660  {
3661  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 9200)
3662  {
3663  *(DWORD *)(&pHandler->Code[14]) = WIN_KM_FIELD(Process, Spare);
3664  }
3665  else if (gGuest.OSVersion >= 9600)
3666  {
3667  *(DWORD *)(&pHandler->Code[9]) = WIN_KM_FIELD(Process, Spare);
3668  *(DWORD *)(&pHandler->Code[17]) = WIN_KM_FIELD(Process, Spare);
3669  }
3670  }
3671 
3672  return INT_STATUS_SUCCESS;
3673 }
3674 
3675 
3677 INTSTATUS
3679  _In_ QWORD FunctionAddress,
3680  _Inout_ API_HOOK_HANDLER *Handler,
3681  _In_ void *Descriptor
3682  )
3697 {
3698  API_HOOK_HANDLER *pHandler = Handler;
3699 
3700  UNREFERENCED_PARAMETER(FunctionAddress);
3701  UNREFERENCED_PARAMETER(Descriptor);
3702 
3703  if (gGuest.Guest64)
3704  {
3705  *(DWORD *)(&pHandler->Code[31]) = WIN_KM_FIELD(Process, Spare);
3706  *(DWORD *)(&pHandler->Code[39]) = WIN_KM_FIELD(Process, Spare);
3707  }
3708  else
3709  {
3710  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 7602)
3711  {
3712  *(DWORD *)(&pHandler->Code[24]) = WIN_KM_FIELD(Process, Spare);
3713  }
3714  else if (gGuest.OSVersion >= 9200 && gGuest.OSVersion <= 16299)
3715  {
3716  *(DWORD *)(&pHandler->Code[27]) = WIN_KM_FIELD(Process, Spare);
3717  }
3718  }
3719 
3720  return INT_STATUS_SUCCESS;
3721 }
3722 
3723 
3725 INTSTATUS
3727  _In_ QWORD FunctionAddress,
3728  _Inout_ API_HOOK_HANDLER *Handler,
3729  _In_ void *Descriptor
3730  )
3745 {
3746  API_HOOK_HANDLER *pHandler = Handler;
3747 
3748  UNREFERENCED_PARAMETER(FunctionAddress);
3749  UNREFERENCED_PARAMETER(Descriptor);
3750 
3751  if (gGuest.Guest64)
3752  {
3753  *(DWORD *)(&pHandler->Code[37]) = WIN_KM_FIELD(Process, Spare);
3754  *(DWORD *)(&pHandler->Code[45]) = WIN_KM_FIELD(Process, Spare);
3755  }
3756  else
3757  {
3758  if (gGuest.OSVersion >= 17134)
3759  {
3760  *(DWORD *)(&pHandler->Code[27]) = WIN_KM_FIELD(Process, Spare);
3761  }
3762  }
3763 
3764  return INT_STATUS_SUCCESS;
3765 }
3766 
3767 
3769 INTSTATUS
3771  _In_ QWORD FunctionAddress,
3772  _Inout_ API_HOOK_HANDLER *Handler,
3773  _In_ void *Descriptor
3774  )
3789 {
3790  API_HOOK_HANDLER *pHandler = Handler;
3791 
3792  UNREFERENCED_PARAMETER(FunctionAddress);
3793  UNREFERENCED_PARAMETER(Descriptor);
3794 
3795  if (gGuest.Guest64)
3796  {
3797  if (gGuest.OSVersion >= 10240)
3798  {
3799  *(DWORD *)(&pHandler->Code[8]) = WIN_KM_FIELD(Process, Spare);
3800  *(DWORD *)(&pHandler->Code[16]) = WIN_KM_FIELD(Process, Spare);
3801  }
3802  }
3803  else
3804  {
3805  if (gGuest.OSVersion >= 18363)
3806  {
3807  *(DWORD *)(&pHandler->Code[9]) = WIN_KM_FIELD(Process, Spare);
3808  }
3809  }
3810 
3811  return INT_STATUS_SUCCESS;
3812 }
3813 
3814 
3815 INTSTATUS
3817  _Inout_ WIN_PROCESS_OBJECT *Process
3818  )
3827 {
3828  INTSTATUS status;
3829  QWORD vadRoot;
3830  QWORD vadNode;
3831 
3832  vadNode = 0;
3833  vadRoot = 0;
3834 
3835  if (NULL == Process)
3836  {
3838  }
3839 
3840  status = IntKernVirtMemRead(Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
3841  gGuest.WordSize,
3842  &vadRoot,
3843  NULL);
3844  if (!INT_SUCCESS(status))
3845  {
3846  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
3847  return status;
3848  }
3849 
3850  vadNode = IntWinVadFindNodeInGuestSpace(vadRoot,
3851  Process->MainModuleAddress & PAGE_MASK,
3852  Process->MainModuleAddress & PAGE_MASK,
3853  0,
3854  0,
3855  FALSE);
3856  if (!vadNode)
3857  {
3858  // We cannot get a valid VAD - skipping.
3860  }
3861 
3862  // Note that we don't want to insert a vad in the tree here, we just want to get a vad object for
3863  // the main module vad. This will get destroyed at process uninit, therefore there is no need to
3864  // cleanup this vad during the RbTree uninit. Also, since the VAD might have been previously loaded
3865  // inside the process, we will consider it as "static scanned".
3866  status = IntWinVadCreateObject(Process, vadNode, (VAD **)&Process->MainModuleVad, TRUE);
3867  if (!INT_SUCCESS(status))
3868  {
3869  ERROR("[ERROR] IntWinVadCreateObject failed: 0x%08x\n", status);
3870  return status;
3871  }
3872 
3873  return INT_STATUS_SUCCESS;
3874 }
3875 
3876 INTSTATUS
3878  _In_ QWORD VadRoot,
3879  _In_ QWORD StartPage,
3880  _In_ QWORD EndPage,
3881  _Out_ VAD *Vad
3882  )
3901 
3902 {
3903  QWORD vadNode = 0;
3904 
3905  if (0 == VadRoot)
3906  {
3908  }
3909 
3910  if (NULL == Vad)
3911  {
3913  }
3914 
3915  for (DWORD tries = 0; tries < VAD_SEARCH_LIMIT; tries++)
3916  {
3917  vadNode = IntWinVadFindNodeInGuestSpace(VadRoot,
3918  StartPage & PAGE_MASK,
3919  EndPage & PAGE_MASK,
3920  0,
3921  0,
3922  FALSE);
3923  if (0 != vadNode)
3924  {
3925  TRACE("[WINVAD] VAD for range [0x%016llx, 0x%016llx] found at 0x%016llx. Tries: %u\n",
3926  StartPage, EndPage, vadNode, tries);
3927  break;
3928  }
3929  }
3930 
3931  if (0 == vadNode)
3932  {
3933  ERROR("[ERROR] Vad [0x%016llx, 0x%016llx] not found starting from root 0x%016llx\n",
3934  StartPage,
3935  EndPage,
3936  VadRoot);
3937 
3938  return INT_STATUS_NOT_FOUND;
3939  }
3940 
3941  return IntWinVadFetchVadFromMemory(vadNode, Vad, TRUE);
3942 }
3943 
3944 
3945 #undef VAD_SHORT_FIELD_PTR
3946 #undef VAD_LONG_FIELD_PTR
3947 
3948 #undef VadShortByte
3949 #undef VadShortWord
3950 #undef VadShortDword
3951 #undef VadShortQword
3952 #undef VadShortPtrSize
3953 #undef VadShortAnySize
INTSTATUS IntWinVadPatchInsert(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
This is the PFUNC_PreDetourCallback for the MiInsertVad guest API detour.It will be invoked before th...
Definition: winvad.c:3770
#define _In_opt_
Definition: intro_sal.h:16
#define INT_STATUS_PAGE_NOT_PRESENT
Indicates that a virtual address is not present.
Definition: introstatus.h:438
void * PathSwapHandle
Definition: winvad.h:133
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
int FUNC_RbTreeNodeCustomCompare(RBNODE *Node, void *Key)
Definition: rbtree.h:70
static BOOLEAN IntWinVadRemoveRanges(VAD *Vad, void *Context)
Removes all pages from a VAD.
Definition: winvad.c:1781
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
#define CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
static INTSTATUS IntWinVadCreateObject(WIN_PROCESS_OBJECT *Process, QWORD VadGva, VAD **Vad, BOOLEAN StaticScan)
Creates and initializes a VAD structure.
Definition: winvad.c:1585
INTSTATUS IntWinVadHandleInsert(void const *Detour)
The detour handler that will be invoked when the guest inserts a new VAD in the tree.This is the detour handler for the MiInsertVad guest API.
Definition: winvad.c:2825
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
void IntWinVadProcessInit(WIN_PROCESS_OBJECT *Process)
Initializes a WIN_PROCESS_OBJECT.VadTree.
Definition: winvad.c:462
INTSTATUS IntWinThrGetCurrentStackBaseAndLimit(QWORD *TibBase, QWORD *StackBase, QWORD *StackLimit)
Obtains the stack base, stack limit and TIB address of the current thread.
Definition: winthread.c:321
#define EX_FAST_REF_TO_PTR(is64, p)
Converts a _EX_FAST_REF value to a pointer.
Definition: wddefs.h:100
INTSTATUS IntWinVadHandleDeleteVaRange(void const *Detour)
The detour handler that will be invoked when a memory range contained by a VAD is deleted...
Definition: winvad.c:3197
uint8_t BYTE
Definition: intro_types.h:47
#define VadShortQword(ptr_, field_)
Reads a qword from a VAD short buffer.
Definition: winvad.c:126
INTSTATUS IntWinVadFetchByRange(QWORD VadRoot, QWORD StartPage, QWORD EndPage, VAD *Vad)
Fetches and returns a VAD object containing the range represented by [StartPage, EndPage].
Definition: winvad.c:3877
INTSTATUS IntWinVadPatchInsertMap(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
This is the PFUNC_PreDetourCallback for the MiGetWsAndInsertVad guest API detour.It will be invoked b...
Definition: winvad.c:3572
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
#define VadShortAnySize(size_, ptr_, field_)
Reads a certain size from a VAD short buffer.
Definition: winvad.c:151
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
WINUM_PATH * IntWinUmPathFetchAndReferenceBySubsection(QWORD SubsectionGva)
Fetches a WINUM_PATH object by the unique identifier and increments the reference counter on it...
Definition: winumpath.c:314
#define BIT(x)
Definition: common.h:68
struct _EXCEPTION_UM_ORIGINATOR::@75 Return
uint16_t WORD
Definition: intro_types.h:48
#define VadShortPtrSize(ptr_, field_)
Reads a guest pointer from a VAD short buffer.
Definition: winvad.c:139
QWORD ReturnRip
The RIP at which the code that triggered the alert returns.
Definition: intro_types.h:1282
#define VadShortDword(ptr_, field_)
Reads a dword from a VAD short buffer.
Definition: winvad.c:114
#define STATS_EXIT(id)
Definition: stats.h:160
#define MAX_LEVEL
void IntAlertFillWinProcess(const WIN_PROCESS_OBJECT *Process, INTRO_PROCESS *EventProcess)
Saves information about a windows process inside an alert.
Definition: alerts.c:689
#define RTL_BALANCED_NODE_PARENT_TO_PTR(Parent)
Gets the pointer to the parent of a _RTL_BALANCED_NODE.
Definition: wddefs.h:1317
User-mode exception.
Definition: exceptions.h:60
Described a detour handler.
Definition: detours.h:283
Ignored by introcore.
Definition: wddefs.h:1326
User-mode non executable zone.
Definition: intro_types.h:247
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
#define VECTOR_UD
Definition: processor.h:109
#define VadShortByte(ptr_, field_)
Reads a byte from a VAD short buffer.
Definition: winvad.c:90
VAD * IntWinVadFindAndUpdateIfNecessary(WIN_PROCESS_OBJECT *Process, QWORD StartHint, QWORD LengthHint)
Searches for a VAD in the Introcore VAD tree. If no VAD is found, or if the found one does not fully ...
Definition: winvad.c:2122
Memory used by video drivers to transfer data between the GPU and a process.
Definition: wddefs.h:1341
QWORD Feedback
Options that will be forced to feedback only mode.
Definition: guests.h:255
void FUNC_RbTreeNodeFree(RBNODE *Node)
Definition: rbtree.h:47
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
INTSTATUS IntWinThrGetCurrentThread(DWORD CpuNumber, QWORD *EthreadAddress)
Get the ETHREAD structure address of the thread currently running on the given CPU.
Definition: winthread.c:26
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
Definition: rbtree.h:34
QWORD Right
Definition: winvad.h:93
static INTSTATUS IntWinVadHandleFilePathInMemory(VAD *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)
Handles the swap-in of a file path taken from a Windows VAD structure.
Definition: winvad.c:1308
The action was not allowed because there was no reason to allow it.
Definition: intro_types.h:183
#define ARRAYSIZE(A)
Definition: introdefs.h:101
#define SWAPMEM_OPT_NO_DUPS
If set, will make sure that a single PF is scheduled for this page.
Definition: swapmem.h:31
INTSTATUS IntWinVadHandleVirtualProtect(void const *Detour)
The detour handler that will be invoked when a memory range contained by a VAD has the protection rig...
Definition: winvad.c:3339
BOOLEAN FirstDominoJavaIgnored
TRUE if the first Domino Java execution VAD was ignored.
Definition: winprocess.h:195
INTSTATUS RbLookupNode(RBTREE *Tree, RBNODE *NodeToSearch, RBNODE **NodeFound)
Definition: rbtree.c:517
INFO_UD_PENDING * IntUDGetEntry(const QWORD Cr3, const QWORD Rip, const QWORD Thread)
Get a UD entry for the provided Cr3, Rip and Thread ID.
Definition: udlist.c:150
#define WIN_MM_PAGE_GUARD
Defined by Windows as PAGE_GUARD in winnt.h.
Definition: wddefs.h:1357
INTSTATUS RbWalkInorderTree(RBTREE *Tree, PFUNC_RbTreeWalkCallback Callback, void *WalkContext)
Definition: rbtree.c:806
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
INTSTATUS RbLookupNodeCustomCompare(RBTREE *Tree, PFUNC_RbTreeNodeCustomCompare CompareFunc, void *Key, RBNODE **NodeFound)
Definition: rbtree.c:552
#define ERROR(fmt,...)
Definition: glue.h:62
Describes a user-mode originator.
Definition: exceptions.h:994
#define WIN_MM_PAGE_EXECUTE_READ
Defined by Windows as PAGE_EXECUTE_READ in winnt.h.
Definition: wddefs.h:1354
INTSTATUS IntShcIsSuspiciousCode(QWORD Gva, QWORD Gpa, DWORD CsType, IG_ARCH_REGS *Registers, QWORD *ShellcodeFlags)
Checks if the code located at the given guest virtual address is suspicious or not.
Definition: shellcode.c:25
struct _EVENT_EPT_VIOLATION::@283 Originator
static int IntWinVadRbTreeNodeCompareVa(RBNODE const *Node, void *Key)
Custom compare function for a VAD RBTREE. This will compare VADs against a given guest virtual addres...
Definition: winvad.c:393
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
int INTSTATUS
The status data type.
Definition: introstatus.h:24
INTSTATUS IntWinVadImportProcessTree(WIN_PROCESS_OBJECT *Process)
Scans the guest VAD tree and imports the nodes into our VAD tree.
Definition: winvad.c:2768
#define PROT_EXEC
One of the Introcore VAD protection constants. This means that the page is executable.
Definition: winvad.h:16
void IntWinUmPathDereference(WINUM_PATH **Path)
Dereferences a WINUM_PATH object, releasing the resources if the reference count has reached 0...
Definition: winumpath.c:340
DWORD OSVersion
Os version.
Definition: guests.h:281
INTSTATUS RbInit(RBTREE *Tree, PFUNC_RbTreeNodeFree NodeFree, PFUNC_RbTreeNodeCompare NodeCompare)
Definition: rbtree.c:386
int FUNC_RbTreeNodeCompare(RBNODE *Left, RBNODE *Right)
Definition: rbtree.h:59
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
QWORD RangeStart
Definition: winvad.h:65
INTSTATUS IntWinVadRemoveProcessTree(WIN_PROCESS_OBJECT *Process)
Removes the VAD tree from a process.
Definition: winvad.c:1351
INTSTATUS IntInjectExceptionInGuest(BYTE Vector, QWORD Cr2, DWORD ErrorCode, DWORD CpuNumber)
Injects an exception inside the guest.
Definition: introcore.c:2264
#define VAD_SEARCH_LIMIT
The maximum number of tries to make when searching for a VAD inside the guest.
Definition: winvad.c:19
DWORD VmProtection
Definition: winvad.h:50
INTSTATUS IntWinVadHandleCommit(void const *Detour)
The detour handler that will be invoked when an existing VAD is committed by the guest.This is the detour handler for the MiCommitExistingVad guest API. Due to the way we ignore certain VADs, this can be invoked either when protection is changed for a known VAD, in which case we have to adjust our protection; or, when protection is changed for a previously unknown VAD in a way that makes it relevant for Introcore, in which case we treat as a newly created VAD.
Definition: winvad.c:3026
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
Definition: introcore.c:2320
static INTSTATUS IntWinVadFetchImageName(VAD *Vad)
Reads the path of the image file mapped by a _MMVAD_LONG structure.
Definition: winvad.c:1478
INTSTATUS IntDumpCodeAndRegs(QWORD Gva, QWORD Gpa, IG_ARCH_REGS *Registers)
This function dumps an entire page (textual disassembly and opcodes) as well as the values of the reg...
Definition: dumper.c:692
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
Definition: alerts.c:492
BOOLEAN Legitimate
True if an execution from this page was attempted and it was deemed to no be malicious.
Definition: winvad.h:73
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
Definition: guests.h:88
#define INT_STATUS_BUFFER_OVERFLOW
Definition: introstatus.h:200
QWORD VadGva
The guest virtual address at which the corresponding Windows _MMVAD structure is located.
Definition: winvad.h:108
QWORD Left
Definition: winvad.h:88
#define MIN(a, b)
Definition: introdefs.h:146
EVENT_EPT_VIOLATION Ept
Definition: alerts.h:16
QWORD SubsectionGva
Definition: winvad.h:139
DWORD Protected
TRUE if this is a protected process. If this is FALSE, most of the above fields aren&#39;t used at all...
Definition: winprocess.h:130
static INTSTATUS IntWinVadRemoveRange(VAD *Vad, QWORD StartPage, QWORD EndPage)
Removes a memory range from a VAD.
Definition: winvad.c:198
#define LOG(fmt,...)
Definition: glue.h:61
static INTSTATUS IntWinVadHandlePageExecution(VAD_PAGE *Context, void const *Hook, QWORD Address, INTRO_ACTION *Action)
Handles execution attempts from a page owned by a monitored VAD.
Definition: winvad.c:1040
void IntWinVadStopExploitMonitor(WIN_PROCESS_OBJECT *Process)
Disables the exploit monitoring for a process.
Definition: winvad.c:1811
#define IC_TAG_VAD
Virtual Address Descriptor for user mode address ranges.
Definition: memtags.h:95
INTSTATUS IntHookGvaSetHook(QWORD Cr3, QWORD Gva, DWORD Length, BYTE Type, void *Callback, void *Context, void *ParentHook, DWORD Flags, HOOK_GVA **GvaHook)
Set a read, write, execute or swap hook on a guest virtual address.
Definition: hook_gva.c:345
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
QWORD IntAlertProcGetFlags(QWORD ProtectionFlag, const void *Process, INTRO_ACTION_REASON Reason, QWORD AdditionalFlags)
Returns the flags for an alert.
Definition: alerts.c:425
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1217
static DWORD IntWinVadVadProtectionToIntroProtection(WIN_VAD_PROT VadProtection)
Converts Windows VAD protection rights to Introcore protection rights.
Definition: winvad.c:522
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
BOOLEAN IntWinVadDump(VAD const *Vad, void *Context)
Prints a VAD structure.
Definition: winvad.c:1706
static VAD * IntWinVadFindByRange(PWIN_PROCESS_OBJECT Process, QWORD StartPage, QWORD EndPage)
Finds a VAD by the range it maps.
Definition: winvad.c:629
INTSTATUS IntAlertFillCodeBlocks(QWORD Rip, QWORD Cr3, BOOLEAN Execute, INTRO_CODEBLOCKS *CodeBlocks)
Fills the code blocks pattern for an alert.
Definition: alerts.c:71
WIN_VAD_PROT
VAD protection flags as used by the Windows kernel. These represent the values in the Protection port...
Definition: winvad.h:24
Exposes the functions used to provide Windows Threads related support.
QWORD Cr3
Process PDBR. Includes PCID.
Definition: winprocess.h:98
Exposes the functions used to schedule an asynchronous code execution scan and receives its result...
void * Library
The library that&#39;s modifying the memory (if that&#39;s the case).
Definition: exceptions.h:1013
#define MAX_VAD_EXECS
The maximum number of execution from a VAD that Introcore will take into consideration.
Definition: winvad.c:21
QWORD IntWinVadFindNodeInGuestSpace(QWORD VadRoot, QWORD StartPage, QWORD EndPage, DWORD Level, QWORD OldStartPage, BOOLEAN LastBranchRight)
Searches for a VAD node inside a guest VAD tree.
Definition: winvad.c:1825
DWORD ExecCount
The number of execution violations triggered by pages inside this VAD.
Definition: winvad.h:147
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
QWORD Address
The base address of the page.
Definition: winvad.h:44
#define _Inout_
Definition: intro_sal.h:20
#define WIN_MM_PAGE_EXECUTE_WRITECOPY
Defined by Windows as PAGE_EXECUTE_WRITECOPY in winnt.h.
Definition: wddefs.h:1356
QWORD StartPage
Definition: winvad.h:102
INTSTATUS IntSwapMemRemoveTransaction(void *Transaction)
Remove a transaction.
Definition: swapmem.c:942
static BOOLEAN IntWinVadIsProbablyNaCl(VAD const *Vad)
Checks if a VAD is used by the Chrome&#39;s NaCl mechanism.
Definition: winvad.c:158
static DWORD IntWinVadVmProtectionToIntroProtection(DWORD VmProtection)
Converts Windows memory protection constants to Introcore protection flags.
Definition: winvad.c:481
#define IC_TAG_VAD_PGARR
Virtual page array with the pages contained by a VAD.
Definition: memtags.h:96
#define _Out_opt_
Definition: intro_sal.h:30
QWORD Parent
Definition: winvad.h:98
BOOLEAN IntPolicyProcTakeAction(QWORD Flag, void const *Process, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Returns the action that should be taken for a process protection option.
Definition: introcore.c:2732
void IntAlertEptFillFromVictimZone(const EXCEPTION_VICTIM_ZONE *Victim, EVENT_EPT_VIOLATION *EptViolation)
Fills the victim information inside an EPT alert.
Definition: alerts.c:868
INTSTATUS IntWinVadPatchVirtualProtect(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
This is the PFUNC_PreDetourCallback for the MiProtectVirtualMemory guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the value of winKmFieldProcessSpare.
Definition: winvad.c:3621
#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
DWORD Protection
Definition: winvad.h:124
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:736
static INTSTATUS IntWinVadHandleInsertGeneric(WIN_PROCESS_OBJECT *Process, QWORD VadAddress, BOOLEAN StaticScan, VAD **Vad)
Handles the insertion of a VAD into a process VAD tree.
Definition: winvad.c:2566
#define PROT_WRITE
One of the Introcore VAD protection constants. This means that the page is writable.
Definition: winvad.h:14
#define memzero(a, s)
Definition: introcrt.h:35
static INTSTATUS IntWinVadFetchVadFromMemory(QWORD VadGva, VAD *Vad, BOOLEAN FailOnCorruptRange)
Reads a _MMVAD structure from the Windows kernel and creates a corresponding VAD structure.
Definition: winvad.c:1375
void * ExecHook
Execution hook handle, if one exists.
Definition: winvad.h:59
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
CHAR Name[IMAGE_BASE_NAME_LEN]
Process base name.
Definition: winprocess.h:108
QWORD Current
The currently used options.
Definition: guests.h:236
BYTE Code[DETOUR_MAX_HANDLER_SIZE]
The code of the detour handler. Only CodeLength bytes are valid.
Definition: detours.h:298
WINUM_PATH * Path
Definition: winvad.h:144
Measures the IntWinVadHandleCommit detour handler.
Definition: stats.h:57
INTSTATUS IntWinVadPatchDeleteVaRange(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
This is the PFUNC_PreDetourCallback for the MiDeleteVirtualAddresses guest API detour.It will be invoked before the detour is placed inside the guest and will patch the detour handler with the value of winKmFieldProcessSpare.
Definition: winvad.c:3678
#define WIN_MM_PAGE_READWRITE
Defined by Windows as PAGE_READWRITE in winnt.h.
Definition: wddefs.h:1351
QWORD RangeEnd
Definition: winvad.h:70
#define TRUE
Definition: intro_types.h:30
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
INTSTATUS IntWinVadHandleInsertPrivate(void const *Detour)
The detour handler that will be invoked when the guest inserts a new VAD in the tree.This is the detour handler for the MiInsertPrivateVad guest API.
Definition: winvad.c:2897
VAD * IntWinVadFindByVa(WIN_PROCESS_OBJECT *Process, QWORD Va)
Finds a VAD that contains a given guest virtual address.
Definition: winvad.c:602
static BYTE * IntWinVadMapShortVad(QWORD Gva)
Maps a _MMVAD_SHORT structure inside Introcore.
Definition: winvad.c:33
#define IS_KERNEL_POINTER_WIN(is64, p)
Checks if a guest virtual address resides inside the Windows kernel address space.
Definition: wddefs.h:76
#define WIN_BUILD_8_1
Definition: wddefs.h:51
INTSTATUS IntWinVadPatchFinishVadDeletion(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
This is the PFUNC_PreDetourCallback for the MiFinishVadDeletion guest API detour.It will be invoked b...
Definition: winvad.c:3726
#define TRACE(fmt,...)
Definition: glue.h:58
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
INFO_UD_PENDING * CurrentUD
The currently pending #UD injection on this CPU.
Definition: guests.h:123
PWIN_PROCESS_OBJECT IntWinProcFindObjectByCr3(QWORD Cr3)
Finds a process by its kernel CR3.
Definition: winprocesshp.c:195
#define INT_STATUS_INVALID_DATA_STATE
Definition: introstatus.h:183
DWORD VadProtection
Definition: winvad.h:116
#define INT_STATUS_KEY_ALREADY_EXISTS
Definition: introstatus.h:239
INTSTATUS IntWinVadProcImportMainModuleVad(WIN_PROCESS_OBJECT *Process)
Imports the VAD that describes the main module of a process.
Definition: winvad.c:3816
QWORD StackLimit
The stack limit for the thread that attempted the execution.
Definition: intro_types.h:1003
static INTSTATUS IntWinVadStaticInsertNodeIntoProcess(QWORD VadNodeGva, DWORD Level, WIN_PROCESS_OBJECT *Process)
Inserts a VAD found by a memory scan inside a Introcore process VAD tree.
Definition: winvad.c:2718
#define WIN_MM_PAGE_EXECUTE
Defined by Windows as PAGE_EXECUTE in winnt.h.
Definition: wddefs.h:1353
static void IntWinVadRbTreeNodeFree(RBNODE *Node)
The node free callback used by the WIN_PROCESS_OBJECT.VadTree tree.
Definition: winvad.c:340
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
Definition: guests.h:367
struct _VAD * Vad
The VAD containing this page.
Definition: winvad.h:57
void RbUninit(RBTREE *Tree)
Definition: rbtree.c:419
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
Definition: intro_types.h:1309
VAD_TYPE VadType
The type of the VAD.
Definition: winvad.h:118
static INTSTATUS IntWinVadReimportProcessTree(WIN_PROCESS_OBJECT *Process)
Re-scans and re-imports the VAD tree of a process.
Definition: winvad.c:2385
char * PCHAR
Definition: intro_types.h:56
INTSTATUS IntDetGetArgument(void const *Detour, DWORD Index, BYTE const *StackBuffer, DWORD StackBufferSize, QWORD *Value)
Reads the specified argument for a detour.
Definition: detours.c:2237
INTSTATUS(* PFUNC_PreDetourCallback)(QWORD FunctionAddress, void *Handler, void *Descriptor)
The type of a callback invoked before setting a detour.
Definition: detours.h:232
#define WARNING(fmt,...)
Definition: glue.h:60
INTSTATUS IntHookGvaRemoveHook(HOOK_GVA **Hook, DWORD Flags)
Remove a GVA hook.
Definition: hook_gva.c:507
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
Definition: intro_types.h:84
RBNODE RbNode
The node inside the WIN_PROCESS_OBJECT.VadTree tree.
Definition: winvad.h:83
INTSTATUS IntWinPatchVadHandleCommit(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
This is the PFUNC_PreDetourCallback for the MiCommitExistingVad guest API detour.It will be invoked b...
Definition: winvad.c:2960
#define WIN_MM_PAGE_NOACCESS
Defined by Windows as PAGE_NOACCESS in winnt.h.
Definition: wddefs.h:1349
#define PAGE_SIZE
Definition: common.h:70
static INTSTATUS IntWinVadIsExecSuspicious(WIN_PROCESS_OBJECT *Process, QWORD VirtualAddress, QWORD PhysicalAddress, INTRO_ACTION *Action)
Handle code execution from a memory page.
Definition: winvad.c:788
Describes the modified zone.
Definition: exceptions.h:893
void RbPreinit(RBTREE *Tree)
Definition: rbtree.c:377
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
#define PROC_OPT_PROT_EXPLOIT
Blocks malicious execution attempts.
Definition: intro_types.h:352
A representation of a memory page included in a VAD structure.
Definition: winvad.h:41
DWORD StaticScan
Set if the VAD was statically detected by a scan, after it was created.
Definition: winvad.h:152
#define __forceinline
Definition: introtypes.h:61
WIN_PROCESS_OBJECT * Process
The process to which this VAD belongs to.
Definition: winvad.h:127
#define WIN_KM_FIELD(Structure, Field)
Macro used to access kernel mode fields inside the WIN_OPAQUE_FIELDS structure.
Definition: winguest.h:740
INTSTATUS IntWinEngExecSendNotification(PWIN_PROCESS_OBJECT Process, PIG_ARCH_REGS Registers, PINTRO_EXEC_INFO ExecInfo)
Notify the scan engines about a possible malicious code execution in a Windows guest.
Definition: scan_engines.c:293
uint32_t DWORD
Definition: intro_types.h:49
INTSTATUS IntDetGetArguments(void const *Detour, DWORD Argc, QWORD *Argv)
Reads multiple arguments from a detour.
Definition: detours.c:2296
None. Normal allocations have this type.
Definition: wddefs.h:1325
INTSTATUS IntWinVadHandleInsertMap(void const *Detour)
The detour handler that will be invoked when a VAD is inserted in the guest VAD tree.This is the detour handler for the MiGetWsAndInsertVad guest API.
Definition: winvad.c:3142
INTSTATUS IntWinVadPatchInsertPrivate(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, void *Descriptor)
This is the PFUNC_PreDetourCallback for the MiInsertPrivateVad guest API detour.It will be invoked be...
Definition: winvad.c:3512
INTSTATUS IntWinModHandleLoadFromVad(WIN_PROCESS_OBJECT *Process, const VAD *Vad)
Handle a module load from a VAD.
Definition: winummodule.c:1587
#define NO_ERRORCODE
Definition: processor.h:123
BOOLEAN IntWinVadIsInTree(const VAD *Vad)
Checks if a VAD is inserted in a guest VAD tree.
Definition: winvad.c:3437
enum _INTRO_ACTION INTRO_ACTION
Event actions.
BOOLEAN IntPolicyProcForceBetaIfNeeded(QWORD Flag, void *Process, INTRO_ACTION *Action)
Checks if a forced action should be taken even if the process log-only mode is active.
Definition: introcore.c:2773
static int IntWinVadRbTreeNodeCompare(RBNODE const *Left, RBNODE const *Right)
The node compare callback used by the WIN_PROCESS_OBJECT.VadTree tree.
Definition: winvad.c:356
FUNC_RbTreeWalkCallback * PFUNC_RbTreeWalkCallback
Definition: rbtree.h:79
#define _In_reads_bytes_(expr)
Definition: intro_sal.h:25
WINUM_PATH * IntWinUmPathCreate(const WCHAR *Path, DWORD PathSize, QWORD SubsectionGva)
Creates a WINUM_PATH object from the given parameters.
Definition: winumpath.c:184
static INTSTATUS IntWinVadRemoveAllPages(VAD *Vad)
Removes all pages from a VAD.
Definition: winvad.c:253
#define WIN_MM_PAGE_EXECUTE_READWRITE
Defined by Windows as PAGE_EXECUTE_READWRITE in winnt.h.
Definition: wddefs.h:1355
INTSTATUS IntWinVadHandleFinishVadDeletion(void const *Detour)
The detour handler that will be invoked when a memory range contained by a VAD is deleted...
Definition: winvad.c:3268
#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
The action was allowed, but it has the BETA flag (Introcore is in log-only mode). ...
Definition: intro_types.h:185
#define IntDbgEnterDebugger()
Definition: introcore.h:381
#define MAX(a, b)
Definition: introdefs.h:151
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
Definition: introcore.c:2134
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
QWORD EprocessAddress
This will be the address of the ActiveProcess field.
Definition: winprocess.h:90
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
static DWORD IntWinVadVadProtectionToVmProtection(WIN_VAD_PROT VadProtection)
Converts Windows VAD protection rights to a Windows memory protection constant.
Definition: winvad.c:562
#define _Function_class_(expr)
Definition: intro_sal.h:40
void IntWinVadDestroyObject(VAD **Vad)
Frees a VAD and all the resources held by it.
Definition: winvad.c:285
static int IntWinVadRbTreeNodeCompareBases(RBNODE const *Node, void *Key)
Custom compare function for a VAD RBTREE. This will compare a VAD start page with a given guest virtu...
Definition: winvad.c:427
static INTSTATUS IntWinVadHandleDeleteGeneric(WIN_PROCESS_OBJECT *Process, QWORD StartPage, QWORD EndPage, DWORD Level)
Handles the deletion of a VAD or of memory range from a VAD.
Definition: winvad.c:2419
PWIN_PROCESS_OBJECT IntWinProcFindObjectByEprocess(QWORD Eprocess)
Finds a process by the address of its _EPROCESS structure.
Definition: winprocesshp.c:96
void RbDeleteNode(RBTREE *Tree, RBNODE *Node)
Definition: rbtree.c:710
#define PROT_READ
One of the Introcore VAD protection constants. This means that the page is readable.
Definition: winvad.h:12
QWORD Rsp
The value of the guest RSP register at the moment of execution.
Definition: intro_types.h:1001
INTRO_PROT_OPTIONS ShemuOptions
Flags which describe the way shemu will give detections.
Definition: guests.h:272
INTSTATUS(* PFUNC_WinVadTraversalCallback)(QWORD VadNodeGva, DWORD Level, void *Context)
Callback type used for in-guest VAD tree traversals.
Definition: winvad.h:182
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1194
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
#define INT_STATUS_NO_MAPPING_STRUCTURES
Indicates that not all mapping structures of a virtual address are present.
Definition: introstatus.h:434
INTSTATUS IntUDAddToPendingList(const QWORD Cr3, const QWORD Rip, const QWORD Thread, INFO_UD_PENDING **CurrentPendingUD)
Add a new UD to the list of pending injections.
Definition: udlist.c:30
QWORD PageCount
The number of 4K pages in the VAD.
Definition: winvad.h:110
#define NLOG(fmt,...)
Definition: glue.h:43
DWORD MonitorVad
TRUE if we need to handle VAD events for this process.
Definition: winprocess.h:162
The type of an allocation that specified the MEM_WRITE_WATCH VirtualAlloc flag.
Definition: wddefs.h:1335
Holds information about an execution attempt.
Definition: intro_types.h:999
INTSTATUS RbInsertNode(RBTREE *Tree, RBNODE *Node)
Definition: rbtree.c:606
INTSTATUS IntExceptUserGetExecOriginator(void *Process, EXCEPTION_UM_ORIGINATOR *Originator)
This function is used to get the originator for heap execution.
#define INT_STATUS_NOT_INITIALIZED_HINT
Definition: introstatus.h:320
char * utf16_for_log(const WCHAR *WString)
Converts a UTF-16 to a UTF-8 string to be used inside logging macros.
Definition: introcore.c:2845
QWORD StackBase
The stack base for the thread that attempted the execution.
Definition: intro_types.h:1002
INTSTATUS IntWinVadShortDump(QWORD VadNodeGva, DWORD Level, void *Context)
Prints a _MMVAD_SHORT structure.
Definition: winvad.c:1659
DWORD Protection
Definition: winvad.h:54
BOOLEAN FUNC_RbTreeWalkCallback(RBNODE *Node, void *WalkContext)
Definition: rbtree.h:78
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1197
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
#define WIN_MM_PAGE_WRITECOPY
Defined by Windows as PAGE_WRITECOPY in winnt.h.
Definition: wddefs.h:1352
#define IC_TAG_VAD_PAGE
Virtual page from a VAD page array.
Definition: memtags.h:97
void IntAlertFillWinUmModule(const WIN_PROCESS_MODULE *Module, INTRO_MODULE *EventModule)
Fills information about a user mode module inside an alert.
Definition: alerts.c:653
static INTSTATUS IntWinVadAdjustRange(VAD *Vad, QWORD NewStartPage, QWORD NewEndPage)
Modifies the range of pages owned by a VAD.
Definition: winvad.c:695
INTSTATUS IntWinVadInOrderRecursiveTraversal(QWORD VadNodeGva, DWORD Level, PFUNC_WinVadTraversalCallback Callback, void *Context)
Traverses a guest VAD tree.
Definition: winvad.c:1920
INTSTATUS IntWinVadWalkTree(PWIN_PROCESS_OBJECT Process, PFUNC_RbTreeWalkCallback Callback)
Walks the VAD tree of a process.
Definition: winvad.c:2025
#define INT_STATUS_INVALID_PARAMETER_MIX
Definition: introstatus.h:98
Holds register state.
Definition: glueiface.h:30
#define ONE_GIGABYTE
Definition: introdefs.h:91
Event structure for EPT violations.
Definition: intro_types.h:1215
static PVAD IntWinVadFindByBase(PWIN_PROCESS_OBJECT Process, QWORD Base)
Finds a VAD by the start of the virtual address range it represents.
Definition: winvad.c:666
DWORD HugeVad
Set if the memory range represented by this VAD has a size of at least 4G.
Definition: winvad.h:156
Execute-access hook.
Definition: glueiface.h:300
QWORD EndPage
Definition: winvad.h:106
Exploitation for Client Execution.
Definition: intro_types.h:1157
DWORD Length
The length of the instruction.
Definition: intro_types.h:1004
DWORD NoChange
Set if the NoChange bit inside the VadFlags field is set.
Definition: winvad.h:160
Invalid selector.
Definition: glueiface.h:185
static BOOLEAN IntWinVadIsProbablyDominoJava(VAD const *Vad)
Checks if a VAD is used by Domino Java.
Definition: winvad.c:175
A representation of a Windows VAD structure.
Definition: winvad.h:80
static INTSTATUS IntWinVadHandleProtectGeneric(WIN_PROCESS_OBJECT *Process, QWORD StartPage, QWORD EndPage, DWORD VmProtection, BOOLEAN AtInsertion)
Handles a VAD protection change.
Definition: winvad.c:2161
#define PAGE_MASK
Definition: pgtable.h:35
DWORD IsIgnored
Set if this VAD is not monitored regardless of the protection rights it has.
Definition: winvad.h:158
struct _VAD_PAGE VAD_PAGE
A representation of a memory page included in a VAD structure.
INTSTATUS IntAlertFillExecContext(QWORD Cr3, INTRO_EXEC_CONTEXT *ExecContext)
Fills the current execution context.
Definition: alerts.c:31
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:271
DWORD IsStack
Set if the memory range represented by this VAD is a stack.
Definition: winvad.h:154
QWORD Rip
Where the write/exec came.
Definition: exceptions.h:1019
static PVAD IntWinVadRescanVad(WIN_PROCESS_OBJECT *Process, QWORD StartPage, QWORD EndPage)
Searches for a VAD inside the guest tree and inserts it into our VAD tree.
Definition: winvad.c:2058
#define WIN_MM_PAGE_READONLY
Defined by Windows as PAGE_READONLY in winnt.h.
Definition: wddefs.h:1350
#define SWAPMEM_OPT_UM_FAULT
If set, the PF must be injected only while in user-mode. Use it when reading user-mode memory...
Definition: swapmem.h:21
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
INTSTATUS IntWinNetSendProcessConnections(WIN_PROCESS_OBJECT *Process)
Send connection events for all active connections whose owner is the given process.
Definition: winnet.c:1768
INTSTATUS IntWinModHandleUnloadFromVad(PWIN_PROCESS_OBJECT Process, PVAD Vad)
Handle a module unload.
Definition: winummodule.c:1762
VAD_PAGE ** VadPages
An array representing each page in the VAD. It has PageCount entries.
Definition: winvad.h:129
INTRO_MODULE ReturnModule
The module to which the current code returns to.
Definition: intro_types.h:1222
#define INTRO_OPT_NOTIFY_ENGINES
Send suspicious pages to be scanned by third party scan engines.
Definition: intro_types.h:459
#define FALSE
Definition: intro_types.h:34
This structure describes a running process inside the guest.
Definition: winprocess.h:83
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68