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  )
1392 {
1393  BYTE *vadBuffer = IntWinVadMapShortVad(VadGva);
1394  QWORD flags = 0;
1395  QWORD startVpn, endVpn;
1396 
1397  if (NULL == vadBuffer)
1398  {
1400  }
1401 
1402  Vad->VadGva = VadGva;
1403 
1404  // Parent, Left, and Right are always pointers, so read WordSize from the guest
1405  Vad->Parent = VadShortPtrSize(vadBuffer, Parent);
1406  Vad->Left = VadShortPtrSize(vadBuffer, Left);
1407  Vad->Right = VadShortPtrSize(vadBuffer, Right);
1408 
1409  startVpn = endVpn = 0;
1410  // Starting and Ending Vpn can have different sizes and sometimes can be extended by another High byte
1411  if (WIN_KM_FIELD(VadShort, VpnSize) == 4)
1412  {
1413  startVpn = VadShortDword(vadBuffer, StartingVpn);
1414  endVpn = VadShortDword(vadBuffer, EndingVpn);
1415  }
1416  else
1417  {
1418  startVpn = VadShortQword(vadBuffer, StartingVpn);
1419  endVpn = VadShortQword(vadBuffer, EndingVpn);
1420  }
1421 
1422  // Add the extra byte if it is present
1423  if (0 != WIN_KM_FIELD(VadShort, StartingVpnHigh))
1424  {
1425  startVpn |= ((QWORD)VadShortByte(vadBuffer, StartingVpnHigh) << 32);
1426  }
1427  if (0 != WIN_KM_FIELD(VadShort, EndingVpnHigh))
1428  {
1429  endVpn |= ((QWORD)VadShortByte(vadBuffer, EndingVpnHigh) << 32);
1430  }
1431 
1432  Vad->StartPage = startVpn << 12;
1433  Vad->EndPage = endVpn << 12;
1434 
1435  if (Vad->EndPage < Vad->StartPage)
1436  {
1437  WARNING("[WARNING] VAD EndPage is before StartPage: start = 0x%016llx, end = 0x%016llx, vad at 0x%016llx!\n",
1438  Vad->StartPage, Vad->EndPage, VadGva);
1439  Vad->EndPage = Vad->StartPage;
1440  }
1441 
1442  // The Flags field can have different sizes, so read it into a QWORD
1443  flags = VadShortAnySize(WIN_KM_FIELD(VadShort, FlagsSize), vadBuffer, Flags);
1444 
1445  // Type and Protection are 3 and 5 bits long, but are not the same bits always, so normalize them
1446  Vad->VadType = (flags >> WIN_KM_FIELD(VadFlags, TypeShift)) & WIN_KM_FIELD(VadFlags, TypeMask);
1447  Vad->VadProtection = (flags >> WIN_KM_FIELD(VadFlags, ProtectionShift)) & WIN_KM_FIELD(VadFlags, ProtectionMask);
1448 
1449  // NoChange is always 1 bit and it is present on all Windows versions, so check for it
1450  Vad->NoChange = 0 != (flags & BIT(WIN_KM_FIELD(VadFlags, NoChangeBit)));
1451 
1452  // DeleteInProgress and PrivateFixup are always 1-bit wide, but are not present on all Windows versions, so it is
1453  // easier to check them directly against a mask instead of the method used for NoChange; if they are not used,
1454  // the mask is 0
1455  Vad->DeleteInProgress = 0 != (flags & WIN_KM_FIELD(VadFlags, DeleteInProgressMask));
1456  Vad->PrivateFixup = 0 != (flags & WIN_KM_FIELD(VadFlags, PrivateFixupMask));
1457 
1458  Vad->PageCount = (((Vad->EndPage - Vad->StartPage) >> 12) + 1);
1459  Vad->Protection = IntWinVadVadProtectionToIntroProtection(Vad->VadProtection);
1460 
1461  Vad->HugeVad = (Vad->PageCount * sizeof(VAD_PAGE) >= 4 * ONE_GIGABYTE);
1462  Vad->Path = NULL;
1463  Vad->Process = NULL;
1464 
1465  IntVirtMemUnmap(&vadBuffer);
1466 
1467  return INT_STATUS_SUCCESS;
1468 }
1469 
1470 
1471 static INTSTATUS
1473  _Inout_ VAD *Vad
1474  )
1486 {
1487  DWORD len = 0;
1488  QWORD pathGva = 0;
1489  QWORD tmp = 0;
1490  DWORD subsecOffsetInVad;
1491  DWORD ctlAreaOffsetInSubsec;
1492  DWORD fileObjectOffsetInCtlArea;
1493  DWORD fileLengthOffsetInFileObject;
1494  DWORD fileBufferOffsetInFileObject;
1495  INTSTATUS status;
1496 
1497  if (NULL != Vad->Path)
1498  {
1500  }
1501 
1502  subsecOffsetInVad = WIN_KM_FIELD(VadLong, Subsection);
1503  ctlAreaOffsetInSubsec = WIN_KM_FIELD(Ungrouped, SubsectionCtlArea);
1504  fileObjectOffsetInCtlArea = WIN_KM_FIELD(Ungrouped, CtlAreaFile);
1505  fileLengthOffsetInFileObject = WIN_KM_FIELD(FileObject, NameLength);
1506  fileBufferOffsetInFileObject = WIN_KM_FIELD(FileObject, NameBuffer);
1507 
1508  // Read the _SUBSECTION address.
1509  status = IntKernVirtMemRead(Vad->VadGva + subsecOffsetInVad, gGuest.WordSize, &tmp, NULL);
1510  if (!INT_SUCCESS(status))
1511  {
1512  return status;
1513  }
1514 
1515  if (0 == tmp)
1516  {
1518  }
1519 
1520  Vad->SubsectionGva = tmp;
1521  Vad->Path = IntWinUmPathFetchAndReferenceBySubsection(Vad->SubsectionGva);
1522 
1523  if (NULL != Vad->Path)
1524  {
1525  // If we can reuse the path, then we can already consider it is a module load
1526  return IntWinModHandleLoadFromVad(Vad->Process, Vad);
1527  }
1528 
1529  // Read the _CONTROL_AREA address.
1530  status = IntKernVirtMemRead(tmp + ctlAreaOffsetInSubsec, gGuest.WordSize, &tmp, NULL);
1531  if (!INT_SUCCESS(status))
1532  {
1533  return status;
1534  }
1535 
1536  if (0 == tmp)
1537  {
1539  }
1540 
1541  // Read the _FILE_OBJECT address.
1542  status = IntKernVirtMemRead(tmp + fileObjectOffsetInCtlArea, gGuest.WordSize, &tmp, NULL);
1543  if (!INT_SUCCESS(status))
1544  {
1545  return status;
1546  }
1547 
1548  tmp = EX_FAST_REF_TO_PTR(gGuest.Guest64, tmp);
1549 
1550  if (0 == tmp)
1551  {
1553  }
1554 
1555  status = IntKernVirtMemRead(tmp + fileLengthOffsetInFileObject, sizeof(WORD), &len, NULL);
1556  if (!INT_SUCCESS(status))
1557  {
1558  return status;
1559  }
1560 
1561  status = IntKernVirtMemRead(tmp + fileBufferOffsetInFileObject, gGuest.WordSize, &pathGva, NULL);
1562  if (!INT_SUCCESS(status))
1563  {
1564  return status;
1565  }
1566 
1567  status = IntSwapMemReadData(0, pathGva, len, SWAPMEM_OPT_BP_FAULT, Vad, 0,
1568  IntWinVadHandleFilePathInMemory, NULL, &Vad->PathSwapHandle);
1569  if (!INT_SUCCESS(status))
1570  {
1571  ERROR("[ERROR] IntSwapMemReadData failed: 0x%08x\n", status);
1572  }
1573 
1574  return INT_STATUS_SUCCESS;
1575 }
1576 
1577 
1578 static INTSTATUS
1580  _In_ WIN_PROCESS_OBJECT *Process,
1581  _In_ QWORD VadGva,
1582  _Out_ VAD **Vad,
1583  _In_ BOOLEAN StaticScan
1584  )
1604 {
1605  INTSTATUS status;
1606 
1607  VAD *pVad = HpAllocWithTag(sizeof(*pVad), IC_TAG_VAD);
1608  if (NULL == pVad)
1609  {
1611  }
1612 
1613  status = IntWinVadFetchVadFromMemory(VadGva, pVad);
1614  if (!INT_SUCCESS(status))
1615  {
1617  ERROR("[ERROR] IntWinVadFetchVadFromMemory failed from GVA %llx: 0x%08x\n", VadGva, status);
1618  return status;
1619  }
1620 
1621  // We don't handle other VAD types except for VadNone and VadImageMap.
1622  if ((pVad->VadType != VadNone) && (pVad->VadType != VadImageMap) && (pVad->VadType != VadWriteWatch))
1623  {
1624  TRACE("[WINVAD] Vad with type %d created at [0x%016llx, 0x%016llx]. Will ignore it.\n",
1625  pVad->VadType, pVad->StartPage, pVad->EndPage);
1627  *Vad = NULL;
1629  }
1630 
1631  pVad->Process = Process;
1632  pVad->Path = NULL;
1633  pVad->VadPages = NULL;
1634  pVad->StaticScan = StaticScan;
1635 
1636  if (VadImageMap == pVad->VadType)
1637  {
1638  status = IntWinVadFetchImageName(pVad);
1639  if (!INT_SUCCESS(status))
1640  {
1641  ERROR("[ERROR] IntWinVadFetchImageName failed for VAD 0x%016llx: 0x%08x\n", pVad->VadGva, status);
1642  }
1643  }
1644 
1645  *Vad = pVad;
1646 
1647  return INT_STATUS_SUCCESS;
1648 }
1649 
1650 
1651 INTSTATUS
1653  _In_ QWORD VadNodeGva,
1654  _In_ DWORD Level,
1655  _In_opt_ void *Context
1656  )
1666 {
1667  const PCHAR prot[] =
1668  {
1669  "noaccess", "readonly", "execute", "execute-read", "readwrite",
1670  "writecopy", "execute-readwrite", "execute-writecopy"
1671  };
1672  VAD vad = {0};
1673  INTSTATUS status;
1674 
1675  UNREFERENCED_PARAMETER(Context);
1676 
1677  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, VadNodeGva))
1678  {
1680  }
1681 
1682  status = IntWinVadFetchVadFromMemory(VadNodeGva, &vad);
1683  if (!INT_SUCCESS(status))
1684  {
1685  return status;
1686  }
1687 
1688  NLOG("0x%016llx (%d): [0x%016llx, 0x%016llx]: Type: %d Prot: 0x%04x (%s)\n",
1689  VadNodeGva, Level, vad.StartPage, vad.EndPage, vad.VadType, vad.VadProtection,
1690  vad.VadProtection >= ARRAYSIZE(prot) ? "" : prot[vad.VadProtection]);
1691 
1692  return INT_STATUS_SUCCESS;
1693 }
1694 
1695 
1697 BOOLEAN
1699  _In_ VAD const *Vad,
1700  _In_ void *Context
1701  )
1710 {
1711  QWORD i;
1712  const char *vadTypes[] =
1713  {
1714  "VadNone",
1715  "VadDevicePhysicalMemory",
1716  "VadImageMap",
1717  "VadAwe",
1718  "VadWriteWatch",
1719  "VadLargePages",
1720  "VadRotatePhysical",
1721  "VadLargePageSection",
1722  };
1723 
1724  UNREFERENCED_PARAMETER(Context);
1725 
1726  if (NULL == Vad)
1727  {
1728  return FALSE;
1729  }
1730 
1731  NLOG(" VAD @ 0x%016llx for [0x%016llx, 0x%016llx], type %-24s, protection: 0x%08x (%c%c%c) "
1732  "Ignored: %d, ExecCount: %d",
1733  Vad->VadGva, Vad->StartPage, Vad->EndPage,
1734  Vad->VadType < sizeof(vadTypes) / sizeof(vadTypes[0]) ? vadTypes[Vad->VadType] : "unknown",
1735  Vad->VadProtection,
1736  (Vad->Protection & PROT_READ) ? 'R' : '-',
1737  (Vad->Protection & PROT_WRITE) ? 'W' : '-',
1738  (Vad->Protection & PROT_EXEC) ? 'X' : '-',
1739  Vad->IsIgnored,
1740  Vad->ExecCount);
1741 
1742  if (NULL != Vad->Path)
1743  {
1744  NLOG(", path '%s'\n", utf16_for_log(Vad->Path->Path));
1745  }
1746  else
1747  {
1748  NLOG("\n");
1749  }
1750 
1751  if (NULL != Vad->VadPages)
1752  {
1753  for (i = 0; i < Vad->PageCount; i++)
1754  {
1755  if (NULL != Vad->VadPages[i])
1756  {
1757  NLOG(" PAGE @ %llx, protection %c%c%c, hook at %p\n",
1758  Vad->VadPages[i]->Address,
1759  (Vad->VadPages[i]->Protection & PROT_READ) ? 'R' : '-',
1760  (Vad->VadPages[i]->Protection & PROT_WRITE) ? 'W' : '-',
1761  (Vad->VadPages[i]->Protection & PROT_EXEC) ? 'X' : '-',
1762  Vad->VadPages[i]->ExecHook);
1763  }
1764  }
1765  }
1766 
1767  return TRUE;
1768 }
1769 
1770 
1772 BOOLEAN
1774  _Inout_ VAD *Vad,
1775  _In_ void *Context
1776  )
1788 {
1789  UNREFERENCED_PARAMETER(Context);
1790 
1791  if (NULL == Vad)
1792  {
1793  return FALSE;
1794  }
1795 
1797 
1798  return TRUE;
1799 }
1800 
1801 
1802 void
1804  _Inout_ WIN_PROCESS_OBJECT *Process
1805  )
1811 {
1813 }
1814 
1815 
1816 QWORD
1818  _In_ QWORD VadRoot,
1819  _In_ QWORD StartPage,
1820  _In_ QWORD EndPage,
1821  _In_ DWORD Level,
1822  _In_ QWORD OldStartPage,
1823  _In_ BOOLEAN LastBranchRight
1824  )
1844 {
1845  INTSTATUS status;
1846  VAD vad = {0};
1847 
1848  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, VadRoot))
1849  {
1850  return 0;
1851  }
1852 
1853  if (Level >= VAD_SEARCH_LIMIT)
1854  {
1855  ERROR("[ERROR] Max recursion level reached, will bail out\n");
1856  return 0;
1857  }
1858 
1859  VadRoot = RTL_BALANCED_NODE_PARENT_TO_PTR(VadRoot);
1860 
1861  status = IntWinVadFetchVadFromMemory(VadRoot, &vad);
1862  if (!INT_SUCCESS(status))
1863  {
1864  ERROR("[ERROR] IntWinVadFetchVadFromMemory failed: 0x%08x\n", status);
1865  return 0;
1866  }
1867 
1868  // Workaround for Windows 7/8: the first level isn't in fact a VAD, and we have to follow the right branch.
1869  if ((gGuest.OSVersion <= 9200) && (0 == Level))
1870  {
1871  return IntWinVadFindNodeInGuestSpace(vad.Right, StartPage, EndPage, Level + 1, 0, TRUE);
1872  }
1873 
1874  if (Level > 0 && vad.StartPage <= OldStartPage && LastBranchRight)
1875  {
1876  ERROR("[ERROR] The in-guest VAD tree seems to be corrupted! Last branch right, "
1877  "current start page: 0x%16llx, old start page: 0x%16llx\n",
1878  vad.StartPage, OldStartPage);
1879  return 0;
1880  }
1881 
1882  if (Level > 0 && vad.StartPage >= OldStartPage && !LastBranchRight)
1883  {
1884  ERROR("[ERROR] The in-guest VAD tree seems to be corrupted! Last branch left, "
1885  "current start page: 0x%16llx, old start page: 0x%16llx\n",
1886  vad.StartPage, OldStartPage);
1887  return 0;
1888  }
1889 
1890  if (StartPage > vad.EndPage)
1891  {
1892  return IntWinVadFindNodeInGuestSpace(vad.Right, StartPage, EndPage, Level + 1, vad.StartPage, TRUE);
1893  }
1894  else if (EndPage < vad.StartPage)
1895  {
1896  return IntWinVadFindNodeInGuestSpace(vad.Left, StartPage, EndPage, Level + 1, vad.StartPage, FALSE);
1897  }
1898  else if (StartPage >= vad.StartPage && EndPage <= vad.EndPage)
1899  {
1900  return vad.VadGva;
1901  }
1902 
1903  return 0;
1904 }
1905 
1906 
1907 INTSTATUS
1909  _In_ QWORD VadNodeGva,
1910  _In_ DWORD Level,
1912  _In_opt_ void *Context
1913  )
1933 {
1934  INTSTATUS status;
1935  QWORD left;
1936  QWORD right;
1937  INTSTATUS failStatus = INT_STATUS_SUCCESS;
1938  VAD vad = {0};
1939 #define MAX_LEVEL 64
1940 
1941  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, VadNodeGva))
1942  {
1944  }
1945 
1946  if (NULL == Callback)
1947  {
1949  }
1950 
1951  if (Level > MAX_LEVEL)
1952  {
1953  ERROR("[ERROR] Too much recursion: requested level: %d, max level: %d\n", Level, MAX_LEVEL);
1955  }
1956 
1957  // On OSs with _MM_AVL_TABLE in the root, we should convert it to ptr by stripping the last 2 bits.
1958  // Otherwise the structure might be off by some bits and invalid data could be read from the guest.
1959  if (gGuest.OSVersion <= 9200 && 0 == Level)
1960  {
1961  VadNodeGva = RTL_BALANCED_NODE_PARENT_TO_PTR(VadNodeGva);
1962  }
1963 
1964  status = IntWinVadFetchVadFromMemory(VadNodeGva, &vad);
1965  if (!INT_SUCCESS(status))
1966  {
1967  ERROR("[ERROR] IntWinVadFetchVadFromMemory failed for 0x%016llx: 0x%08x\n", VadNodeGva, status);
1968  return status;
1969  }
1970 
1971  left = vad.Left;
1972  right = vad.Right;
1973 
1975  {
1976  status = IntWinVadInOrderRecursiveTraversal(left, Level + 1, Callback, Context);
1977  if (!INT_SUCCESS(status))
1978  {
1979  failStatus = status;
1980  }
1981  }
1982 
1983  if (gGuest.OSVersion <= 9200 && 0 == Level)
1984  {
1985  // Windows 7 and Windows 8 hold in _EPROCESS.VadRoot a _MM_AVL_TABLE struct. It's Parent points to itself,
1986  // the children may be NULL or valid tree nodes, skip the callback for the fake root
1987  TRACE("[WINVAD] -------> Special Win 7/8 case: 0x%016llx is not an actual VAD. Left = 0x%016llx "
1988  "Right = 0x%016llx\n", VadNodeGva, left, right);
1989  }
1990  else
1991  {
1992  Callback(VadNodeGva, Level, Context);
1993  }
1994 
1995  if (IS_KERNEL_POINTER_WIN(gGuest.Guest64, right))
1996  {
1997  status = IntWinVadInOrderRecursiveTraversal(right, Level + 1, Callback, Context);
1998  if (!INT_SUCCESS(status))
1999  {
2000  failStatus = status;
2001  }
2002  }
2003 
2004  return failStatus;
2005 }
2006 
2007 
2008 INTSTATUS
2010  _In_ PWIN_PROCESS_OBJECT Process,
2012  )
2024 {
2025  if (NULL == Process)
2026  {
2028  }
2029 
2030  if (NULL == Callback)
2031  {
2033  }
2034 
2035  RbWalkInorderTree(&Process->VadTree, Callback, NULL);
2036 
2037  return INT_STATUS_SUCCESS;
2038 }
2039 
2040 
2041 static PVAD
2043  _Inout_ WIN_PROCESS_OBJECT *Process,
2044  _In_ QWORD StartPage,
2045  _In_ QWORD EndPage
2046  )
2063 {
2064  INTSTATUS status;
2065  PVAD pVad;
2066  QWORD vadroot = 0, vadgva = 0;
2067 
2068  status = IntKernVirtMemRead(Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
2069  gGuest.WordSize, &vadroot, NULL);
2070  if (!INT_SUCCESS(status))
2071  {
2072  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
2073  return NULL;
2074  }
2075 
2076  for (DWORD tries = 0; tries < VAD_SEARCH_LIMIT; tries++)
2077  {
2078  vadgva = IntWinVadFindNodeInGuestSpace(vadroot, StartPage, EndPage, 0, 0, FALSE);
2079  if (0 != vadgva)
2080  {
2081  TRACE("[WINVAD] VAD for range [0x%016llx, 0x%016llx] found at 0x%016llx. Tries: %u\n",
2082  StartPage, EndPage, vadgva, tries);
2083  break;
2084  }
2085  }
2086 
2087  if (0 == vadgva)
2088  {
2089  LOG("IntWinVadFindNodeInGuestSpace failed for range [0x%016llx, 0x%016llx] in process %u\n",
2090  StartPage, EndPage, Process->Pid);
2091  return NULL;
2092  }
2093 
2094  status = IntWinVadHandleInsertGeneric(Process, vadgva, FALSE, &pVad);
2095  if (!INT_SUCCESS(status))
2096  {
2097  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for VAD %llx: 0x%08x\n", vadgva, status);
2098  return NULL;
2099  }
2100 
2101  return pVad;
2102 }
2103 
2104 
2105 VAD *
2107  _Inout_ WIN_PROCESS_OBJECT *Process,
2108  _In_ QWORD StartHint,
2109  _In_ QWORD LengthHint
2110  )
2124 {
2125  const QWORD startPage = StartHint & PAGE_MASK;
2126  const QWORD endPage = (StartHint + LengthHint - 1) & PAGE_MASK;
2127  VAD *vad = IntWinVadFindByRange(Process, startPage, endPage);
2128  if (NULL != vad && startPage >= vad->StartPage && endPage <= vad->EndPage)
2129  {
2130  return vad;
2131  }
2132 
2133  vad = IntWinVadRescanVad(Process, startPage, endPage);
2134  if (NULL == vad)
2135  {
2136  LOG("IntWinVadRescanVad failed for [0x%016llx, 0x%016llx] in process %u\n",
2137  startPage, endPage, Process->Pid);
2138  }
2139 
2140  return vad;
2141 }
2142 
2143 
2144 static INTSTATUS
2146  _Inout_ WIN_PROCESS_OBJECT *Process,
2147  _In_ QWORD StartPage,
2148  _In_ QWORD EndPage,
2149  _In_ DWORD VmProtection,
2150  _In_ BOOLEAN AtInsertion
2151  )
2188 
2189 {
2190  INTSTATUS status;
2191  PVAD pVad;
2192  DWORD newprot;
2193 
2194  if (EndPage < StartPage)
2195  {
2197  }
2198 
2199  // Get the associated VAD.
2200  pVad = IntWinVadFindByRange(Process, StartPage, EndPage);
2201  if (NULL == pVad)
2202  {
2203  QWORD vadroot = 0, vadgva = 0;
2204 
2205  TRACE("[WINVAD] Range [%llx, %llx] not cached, searching guest space for VAD...\n", StartPage, EndPage);
2206 
2207  status = IntKernVirtMemRead(Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
2208  gGuest.WordSize,
2209  &vadroot,
2210  NULL);
2211  if (!INT_SUCCESS(status))
2212  {
2213  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
2214  return status;
2215  }
2216 
2217  for (DWORD tries = 0; tries < VAD_SEARCH_LIMIT; tries++)
2218  {
2219  vadgva = IntWinVadFindNodeInGuestSpace(vadroot, StartPage, EndPage, 0, 0, FALSE);
2220  if (0 != vadgva)
2221  {
2222  break;
2223  }
2224  }
2225 
2226  if (0 == vadgva)
2227  {
2228  // We'll only warn and return an informational status as there might be in-guest race conditions.
2229  // For example, calling VirtualProtectEx on a previously freed memory region.
2230  WARNING("[WARNING] IntWinVadFindNodeInGuestSpacefailed to find a VAD for range [%llx, %llx] "
2231  "in process %d\n", StartPage, EndPage, Process->Pid);
2233  }
2234 
2235  TRACE("[WINVAD] VAD for range [%llx, %llx] found at %llx\n", StartPage, EndPage, vadgva);
2236 
2237  status = IntWinVadHandleInsertGeneric(Process, vadgva, FALSE, &pVad);
2238  if (!INT_SUCCESS(status))
2239  {
2240  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for VAD %llx: 0x%08x\n", vadgva, status);
2241  return status;
2242  }
2243  }
2244 
2245  if ((StartPage < pVad->StartPage) || (StartPage > pVad->EndPage))
2246  {
2247  ERROR("[ERROR] The start page lies outside the VAD range: 0x%016llx vs [0x%016llx, 0x%016llx]\n",
2248  StartPage, pVad->StartPage, pVad->EndPage);
2250  }
2251 
2252  if ((EndPage < pVad->StartPage) || (EndPage > pVad->EndPage))
2253  {
2254  ERROR("[ERROR] The end page lies outside the VAD range: 0x%016llx vs [0x%016llx, 0x%016llx]\n",
2255  EndPage, pVad->StartPage, pVad->EndPage);
2257  }
2258 
2259  if (pVad->HugeVad)
2260  {
2261  WARNING("[WARNING] Protecting range [0x%016llx, 0x%016llx] of huge VAD [0x%016llx, 0x%016llx] "
2262  "with %llu pages at GVA 0x%016llx\n",
2263  StartPage, EndPage, pVad->StartPage, pVad->EndPage, pVad->PageCount, pVad->VadGva);
2265  }
2266 
2267  pVad->IsIgnored = IntWinVadIsProbablyNaCl(pVad);
2268  if (pVad->IsIgnored)
2269  {
2270  TRACE("[INFO] Ignoring VAD @ 0x%016llx [0x%016llx, 0x%016llx] for process `%s` (%d)\n",
2271  pVad->VadGva, pVad->StartPage, pVad->EndPage, Process->Name, Process->Pid);
2273  }
2274 
2275  // We are not interested in mapped executable files, so we will skip them.
2276  if (((pVad->VadType == VadImageMap) && (pVad->PageCount > 2)) ||
2277  (VadRotatePhysical == pVad->VadType) ||
2278  (VadDevicePhysicalMemory == pVad->VadType) ||
2279  !pVad->Process->ProtExploits ||
2280  (pVad->ExecCount > MIN((pVad->PageCount / 20), MAX_VAD_EXECS)))
2281  {
2283  }
2284 
2285  // If the function was called due to some VirtualProtect call (or commit with different rights)
2286  // and the Vad.u.VadFlags.NoChange is set, we should bail out, as the OS won't apply the protections to it.
2287  if (pVad->NoChange && !AtInsertion)
2288  {
2290  }
2291 
2292  // Compute the simplified protection mask.
2293  newprot = IntWinVadVmProtectionToIntroProtection(VmProtection);
2294  if (VmProtection & WIN_MM_PAGE_GUARD)
2295  {
2296  pVad->IsStack = TRUE;
2297  }
2298 
2299  // If the pages array was not allocated, do so now.
2300  if (NULL == pVad->VadPages)
2301  {
2302  pVad->VadPages = HpAllocWithTag(sizeof(*pVad->VadPages) * pVad->PageCount, IC_TAG_VAD_PGARR);
2303  if (NULL == pVad->VadPages)
2304  {
2306  }
2307  }
2308 
2309  for (QWORD curpg = (StartPage & PAGE_MASK); curpg <= (EndPage & PAGE_MASK); curpg += PAGE_SIZE)
2310  {
2311  DWORD pos = (DWORD)((curpg - pVad->StartPage) >> 12);
2312 
2313  if (NULL == pVad->VadPages[pos])
2314  {
2315  pVad->VadPages[pos] = HpAllocWithTag(sizeof(**pVad->VadPages), IC_TAG_VAD_PAGE);
2316  if (NULL == pVad->VadPages[pos])
2317  {
2319  }
2320 
2321  // So we can do MIN/MAX on them.
2322  pVad->VadPages[pos]->RangeStart = 0xFFFFFFFFFFFFFFFF;
2323  pVad->VadPages[pos]->RangeEnd = 0;
2324 
2325  // The old page protection was given by the VAD protection.
2326  pVad->VadPages[pos]->Vad = pVad;
2327  pVad->VadPages[pos]->Address = curpg;
2328  pVad->VadPages[pos]->VmProtection = VmProtection;
2329  pVad->VadPages[pos]->Protection = newprot;
2330  }
2331  else
2332  {
2333  pVad->VadPages[pos]->VmProtection = VmProtection;
2334  pVad->VadPages[pos]->Protection = newprot;
2335  }
2336 
2337  // We always store the maximum range, in order to remove as many pages when we detect a legitimate execution.
2338  pVad->VadPages[pos]->RangeStart = MIN(pVad->VadPages[pos]->RangeStart, StartPage);
2339  pVad->VadPages[pos]->RangeEnd = MAX(pVad->VadPages[pos]->RangeEnd, EndPage);
2340 
2341  if ((0 != (newprot & PROT_EXEC)) &&
2342  (NULL == pVad->VadPages[pos]->ExecHook) && (!pVad->VadPages[pos]->Legitimate))
2343  {
2344  status = IntHookGvaSetHook(Process->Cr3, curpg, PAGE_SIZE, IG_EPT_HOOK_EXECUTE,
2345  IntWinVadHandlePageExecution, pVad->VadPages[pos], NULL, 0,
2346  (PHOOK_GVA *)&pVad->VadPages[pos]->ExecHook);
2347  if (!INT_SUCCESS(status))
2348  {
2349  ERROR("[ERROR] IntHookGvaSetHook failed: 0x%08x\n", status);
2350  }
2351  }
2352 
2353  // The page was executable, and now it is not.
2354  if (0 == (newprot & PROT_EXEC) && (NULL != pVad->VadPages[pos]->ExecHook))
2355  {
2356  status = IntHookGvaRemoveHook((HOOK_GVA **)&pVad->VadPages[pos]->ExecHook, 0);
2357  if (!INT_SUCCESS(status))
2358  {
2359  ERROR("[ERROR] IntHookGvaRemoveHook failed: 0x%08x\n", status);
2360  }
2361  }
2362  }
2363 
2364  return INT_STATUS_SUCCESS;
2365 }
2366 
2367 
2368 static INTSTATUS
2370  _Inout_ WIN_PROCESS_OBJECT *Process
2371  )
2381 {
2382  INTSTATUS status;
2383 
2384  status = IntWinVadRemoveProcessTree(Process);
2385  if (!INT_SUCCESS(status))
2386  {
2387  ERROR("[ERROR] IntWinVadRemoveProcessTree failed: 0x%08x\n", status);
2388  return status;
2389  }
2390 
2391  status = IntWinVadImportProcessTree(Process);
2392  if (!INT_SUCCESS(status))
2393  {
2394  ERROR("[ERROR] IntWinVadImportProcessTree failed: 0x%08x\n", status);
2395  return status;
2396  }
2397 
2398  return status;
2399 }
2400 
2401 
2402 static INTSTATUS
2404  _Inout_ WIN_PROCESS_OBJECT *Process,
2405  _In_ QWORD StartPage,
2406  _In_ QWORD EndPage,
2407  _In_ DWORD Level
2408  )
2449 {
2450  INTSTATUS status;
2451  PVAD pVad;
2452 
2453  if (Level >= 2)
2454  {
2455  WARNING("[WARNING] Exceeded max recursion level for VAD deletion @ [0x%016llx, 0x%016llx] %s:%d\n",
2456  StartPage, EndPage, Process->Name, Process->Pid);
2459  }
2460 
2461  if (EndPage < StartPage)
2462  {
2463  WARNING("[WARNING] EndPage is LESS than StartPage: [0x%016llx, 0x%016llx]\n", StartPage, EndPage);
2466  }
2467 
2468  pVad = IntWinVadFindByRange(Process, StartPage, EndPage);
2469  if (NULL == pVad)
2470  {
2471  // Since we ignore all VAD types except for VadNone and VadImageMap, we don't have to log error here or
2472  // return an error.
2473  }
2474  else if ((StartPage == pVad->StartPage) && (EndPage == pVad->EndPage))
2475  {
2476  RbDeleteNode(&Process->VadTree, &pVad->RbNode);
2477 
2478  IntWinVadDestroyObject(&pVad);
2479  }
2480  else if (StartPage == pVad->StartPage)
2481  {
2482  // Only the lower sub-range is deleted
2483  QWORD newStart = EndPage + PAGE_SIZE;
2484 
2485  TRACE("[WINVAD] Adjusting VAD 0x%016llx. Old start: 0x%016llx New start: 0x%016llx "
2486  "for process %s:%d (0x%016llx)\n",
2487  pVad->VadGva, pVad->StartPage, newStart, Process->Name, Process->Pid, Process->EprocessAddress);
2488 
2489  status = IntWinVadAdjustRange(pVad, newStart, pVad->EndPage);
2490  if (!INT_SUCCESS(status))
2491  {
2492  ERROR("[ERROR] IntWinVadAdjustRange failed for [0x%016llx, 0x%016llx] in VAD 0x%016llx "
2493  "process 0x%016llx: 0x%08x\n",
2494  StartPage, EndPage, pVad->VadGva, Process->EprocessAddress, status);
2495  }
2496  }
2497  else if (EndPage == pVad->EndPage)
2498  {
2499  // Only the upper sub-range is deleted
2500  QWORD newEnd = StartPage - PAGE_SIZE;
2501 
2502  TRACE("[WINVAD] Adjusting VAD 0x%016llx. Old end: 0x%016llx New end: 0x%016llx for process %s:%d (0x%016llx)\n",
2503  pVad->VadGva, pVad->EndPage, newEnd, Process->Name, Process->Pid, Process->EprocessAddress);
2504 
2505  status = IntWinVadAdjustRange(pVad, pVad->StartPage, newEnd);
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
2514  {
2515  TRACE("[WINVAD] Guest attempts to delete VAD [%016llx, %016llx], but we matched with VAD [%016llx, %016llx]"
2516  ", will reimport process tree for %s:%d\n",
2517  StartPage, EndPage, pVad->StartPage, pVad->EndPage,
2518  Process->Name, Process->Pid);
2519 
2520  IntPauseVcpus();
2521 
2522  status = IntWinVadReimportProcessTree(Process);
2523  if (!INT_SUCCESS(status))
2524  {
2525  ERROR("[ERROR] IntWinVadReimportProcessTree failed: 0x%08x\n", status);
2526  goto _resume_maybe_enter_dbg;
2527  }
2528 
2529  status = IntWinVadHandleDeleteGeneric(Process, StartPage, EndPage, Level + 1);
2530  if (!INT_SUCCESS(status))
2531  {
2532  ERROR("[ERROR] IntWinVadHandleDeleteGeneric failed: 0x%08x\n", status);
2533  goto _resume_maybe_enter_dbg;
2534  }
2535 
2536 _resume_maybe_enter_dbg:
2537  IntResumeVcpus();
2538 
2539  if (!INT_SUCCESS(status))
2540  {
2542  }
2543  }
2544 
2545  return INT_STATUS_SUCCESS;
2546 }
2547 
2548 
2549 static INTSTATUS
2551  _Inout_ WIN_PROCESS_OBJECT *Process,
2552  _In_ QWORD VadAddress,
2553  _In_ BOOLEAN StaticScan,
2554  _Out_opt_ VAD **Vad
2555  )
2585 
2586 {
2587  INTSTATUS status;
2588  PVAD pVad = NULL;
2589  BOOLEAN previouslyMonitored;
2590 
2591  if (Vad != NULL)
2592  {
2593  *Vad = NULL;
2594  }
2595 
2596  previouslyMonitored = !!(Process->MonitorVad);
2597 
2598  status = IntWinVadCreateObject(Process, VadAddress, &pVad, StaticScan);
2599  if (!INT_SUCCESS(status))
2600  {
2601  ERROR("[ERROR] IntWinVadCreateObject failed: 0x%08x\n", status);
2602 
2603  return status;
2604  }
2605 
2606  if (NULL != pVad && Process->MonitorVad)
2607  {
2608  BOOLEAN hugeNoWrite;
2609  const QWORD maxTries = pVad->PageCount + 1;
2610  QWORD tryCount = 0;
2611 
2612  do
2613  {
2614  PVAD toRemove;
2615 
2616  status = RbInsertNode(&Process->VadTree, &pVad->RbNode);
2617  if (INT_STATUS_KEY_ALREADY_EXISTS != status)
2618  {
2619  // We managed to insert it (or another error occurred), break out of the loop
2620  break;
2621  }
2622 
2623  WARNING("[WARNING] [WINVAD] Special case `INT_STATUS_KEY_ALREADY_EXISTS` while inserting 0x%016llx "
2624  "[0x%016llx, 0x%016llx] in 0x%016llx (PID %u)\n",
2625  pVad->VadGva, pVad->StartPage, pVad->EndPage, Process->EprocessAddress, Process->Pid);
2626 
2627  toRemove = IntWinVadFindByRange(Process, pVad->StartPage, pVad->EndPage);
2628  if (NULL == toRemove)
2629  {
2630  ERROR("[ERROR] IntWinVadFindByRange failed for [%016llx, %016llx]\n", pVad->StartPage, pVad->EndPage);
2632  IntWinVadDestroyObject(&pVad);
2633 
2634  return status;
2635  }
2636 
2637  status = IntWinVadHandleDeleteGeneric(Process, toRemove->StartPage, toRemove->EndPage, 0);
2638  if (!INT_SUCCESS(status))
2639  {
2640  ERROR("[ERROR] IntWinVadHandleDeleteGeneric failed for [0x%016llx, 0x%016llx] "
2641  "in process 0x%016llx: 0x%08x\n",
2642  toRemove->StartPage, toRemove->EndPage, Process->EprocessAddress, status);
2643  }
2644 
2645  tryCount++;
2646  } while (tryCount < maxTries);
2647  if (!INT_SUCCESS(status))
2648  {
2649  ERROR("[ERROR] RbInsertNode failed for [0x%016llx, 0x%016llx] in process PID %u: 0x%08x\n",
2650  pVad->StartPage, pVad->EndPage, Process->Pid, status);
2652  IntWinVadDestroyObject(&pVad);
2653 
2654  return status;
2655  }
2656 
2657  pVad->IsIgnored = IntWinVadIsProbablyNaCl(pVad);
2658  if (pVad->IsIgnored)
2659  {
2660  TRACE("[INFO] Ignoring VAD @ 0x%016llx [0x%016llx, 0x%016llx] for process `%s` (%d)\n",
2661  pVad->VadGva, pVad->StartPage, pVad->EndPage, Process->Name, Process->Pid);
2662  }
2663 
2664  hugeNoWrite = (pVad->PageCount >= 65536) && (0 == (pVad->Protection & PROT_WRITE));
2665 
2666  // If needed, monitor these pages.
2667  if ((!pVad->IsIgnored) && (!hugeNoWrite) && (pVad->Protection & PROT_EXEC) &&
2668  ((pVad->VadType != VadImageMap) || (pVad->PageCount <= 2)))
2669  {
2670  status = IntWinVadHandleProtectGeneric(Process, pVad->StartPage, pVad->EndPage,
2672  if (!INT_SUCCESS(status))
2673  {
2674  ERROR("[ERROR] IntWinVadHandleProtectGeneric failed: 0x%08x\n", status);
2675  }
2676  }
2677  }
2678  else if (pVad != NULL && previouslyMonitored)
2679  {
2680  //
2681  // We decided on the current VAD (which is also the main module) that VAD should not be monitored
2682  // anymore. Thus the current VAD should be destroyed. Note that the VADs inserted before this
2683  // would have already been destroyed, due to the fact that we called IntWinVadRemoveProcessTree,
2684  // but the current VAD has not got the chance to be added into the tree - thus it will be leaked
2685  // otherwise.
2686  // Also, a big note to this is the fact that a caller might externally call this function mistakenly
2687  // for non-protected (and non-vad-monitored) processes. As a safe guard, we'll destroy the VAD only
2688  // if it was decided in IntWinVadCreateObject that from now on we should not monitor vad anymore.
2689  //
2690  IntWinVadDestroyObject(&pVad);
2691  }
2692 
2693  if (Vad != NULL)
2694  {
2695  *Vad = pVad;
2696  }
2697  return INT_STATUS_SUCCESS;
2698 }
2699 
2700 
2701 static INTSTATUS
2703  _In_ QWORD VadNodeGva,
2704  _In_ DWORD Level,
2705  _Inout_ WIN_PROCESS_OBJECT *Process
2706  )
2720 {
2721  INTSTATUS status;
2722 
2723  UNREFERENCED_PARAMETER(Level);
2724 
2725  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, VadNodeGva))
2726  {
2728  }
2729 
2730  // It is possible that during VAD iteration we decided to remove the process protection (based on the Main Module)
2731  // Thus, don't insert the current node if MonitorVad was cleared.
2732  if (!Process->MonitorVad)
2733  {
2735  }
2736 
2737  status = IntWinVadHandleInsertGeneric(Process, VadNodeGva, TRUE, NULL);
2738  if (!INT_SUCCESS(status))
2739  {
2740  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for 0x%016llx in process %d: 0x%08x\n",
2741  VadNodeGva, Process->Pid, status);
2742  return status;
2743  }
2744 
2745  TRACE("[WINVAD] VAD 0x%016llx found at static scan on level %d\n", VadNodeGva, Level);
2746 
2747  return INT_STATUS_SUCCESS;
2748 }
2749 
2750 
2751 INTSTATUS
2753  _Inout_ WIN_PROCESS_OBJECT *Process
2754  )
2766 {
2767  INTSTATUS status;
2768  QWORD root = 0;
2769 
2770  if (NULL == Process)
2771  {
2773  }
2774 
2775  status = IntKernVirtMemRead(Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
2776  gGuest.WordSize,
2777  &root,
2778  NULL);
2779  if (!INT_SUCCESS(status))
2780  {
2781  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
2782  return status;
2783  }
2784 
2785  if (0 == root)
2786  {
2787  TRACE("[WINVAD] Skipping static scan for process 0x%016llx because root @ 0x%016llx is 0\n",
2788  Process->EprocessAddress, Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot));
2790  }
2791 
2792  TRACE("[WINVAD] Starting static scan for process 0x%016llx from root @ 0x%016llx = 0x%016llx\n",
2793  Process->EprocessAddress,
2794  Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
2795  root);
2796 
2798  if (!INT_SUCCESS(status))
2799  {
2800  ERROR("[ERROR] IntWinVadInOrderRecursiveTraversal failed for root 0x%016llx: 0x%08x\n", root, status);
2801  return status;
2802  }
2803 
2804  return INT_STATUS_SUCCESS;
2805 }
2806 
2807 
2808 INTSTATUS
2810  _In_ void const *Detour
2811  )
2829 {
2830  INTSTATUS status;
2831  WIN_PROCESS_OBJECT *pProc;
2832  QWORD args[2];
2833  QWORD vadGva;
2834  QWORD eprocessGva;
2835 
2836  if (NULL == Detour)
2837  {
2839  }
2840 
2841  // the parameters are the same on x86 as on x64
2842  // RCX: pointer to a MMVAD or MMVAD_SHORT structure. Private VADs (created by VirtualAlloc(Ex) calls) are
2843  // always MMVAD_SHORT
2844  // RDX: pointer to the EPROCESS structure of the process for which the VAD is created. This might not be in
2845  // the process list yet
2846  status = IntDetGetArguments(Detour, 2, args);
2847  if (!INT_SUCCESS(status))
2848  {
2849  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
2850  goto cleanup_and_exit;
2851  }
2852 
2853  vadGva = args[0];
2854  eprocessGva = args[1];
2855 
2856  // Get the process object.
2857  pProc = IntWinProcFindObjectByEprocess(eprocessGva);
2858  if (!pProc || !pProc->MonitorVad)
2859  {
2860  status = INT_STATUS_NOT_NEEDED_HINT;
2861  goto cleanup_and_exit;
2862  }
2863 
2864  status = IntWinVadHandleInsertGeneric(pProc, vadGva, FALSE, NULL);
2865  if (INT_STATUS_NOT_FOUND != status && !INT_SUCCESS(status))
2866  {
2867  ERROR("[ERROR] IntWinVadHandleInsertionGeneric failed for process 0x%016llx VAD 0x%016llx: 0x%08x\n",
2868  eprocessGva, vadGva, status);
2869  goto cleanup_and_exit;
2870  }
2871 
2872  status = INT_STATUS_SUCCESS;
2873 
2874 cleanup_and_exit:
2875 
2876  return status;
2877 }
2878 
2879 
2880 INTSTATUS
2882  _In_ void const *Detour
2883  )
2900 {
2901  INTSTATUS status;
2902  PWIN_PROCESS_OBJECT pProc = NULL;
2903  PIG_ARCH_REGS pRegs = NULL;
2904  QWORD vadGva = 0;
2905 
2906  if (NULL == Detour)
2907  {
2909  }
2910 
2911  pRegs = &gVcpu->Regs;
2912 
2913  status = IntDetGetArgument(Detour, 0, NULL, 0, &vadGva);
2914  if (!INT_SUCCESS(status))
2915  {
2916  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
2917  goto cleanup_and_exit;
2918  }
2919 
2920  pProc = IntWinProcFindObjectByCr3(pRegs->Cr3);
2921  if (!pProc || !pProc->MonitorVad)
2922  {
2923  status = INT_STATUS_NOT_NEEDED_HINT;
2924  goto cleanup_and_exit;
2925  }
2926 
2927  status = IntWinVadHandleInsertGeneric(pProc, vadGva, FALSE, NULL);
2928  if (INT_STATUS_NOT_FOUND != status && !INT_SUCCESS(status))
2929  {
2930  ERROR("[ERROR] IntWinVadHandleInsertionGeneric failed for process 0x%016llx VAD 0x%016llx: 0x%08x\n",
2931  pProc->EprocessAddress, vadGva, status);
2932  goto cleanup_and_exit;
2933  }
2934 
2935  status = INT_STATUS_SUCCESS;
2936 
2937 cleanup_and_exit:
2938 
2939  return status;
2940 }
2941 
2943 INTSTATUS
2945  _In_ QWORD FunctionAddress,
2946  _Inout_ API_HOOK_HANDLER *Handler,
2947  _In_ QWORD HandlerAddress
2948  )
2965 {
2966  API_HOOK_HANDLER *pHandler = Handler;
2967 
2968  UNREFERENCED_PARAMETER(FunctionAddress);
2969  UNREFERENCED_PARAMETER(HandlerAddress);
2970 
2971  if (gGuest.Guest64)
2972  {
2973  *(DWORD *)(pHandler->Code + 0x0d) = WIN_KM_FIELD(Pcr, CurrentThread);
2974 
2975  *(DWORD *)(pHandler->Code + 0x14) = WIN_KM_FIELD(Thread, AttachedProcess);
2976 
2977  *(DWORD *)(pHandler->Code + 0x1f) = WIN_KM_FIELD(Thread, Process);
2978 
2979  *(DWORD *)(pHandler->Code + 0x25) = WIN_KM_FIELD(Process, Spare);
2980  *(DWORD *)(pHandler->Code + 0x2d) = WIN_KM_FIELD(Process, Spare);
2981  }
2982  else
2983  {
2985  {
2986  // Stdcall
2987  *(BYTE *)(pHandler->Code + 0x3) = 0x10;
2988  }
2989  else
2990  {
2991  // Fastcall
2992  *(BYTE *)(pHandler->Code + 0x3) = 0x8;
2993  }
2994 
2995  *(DWORD *)(pHandler->Code + 0x0c) = WIN_KM_FIELD(Pcr, CurrentThread);
2996 
2997  *(DWORD *)(pHandler->Code + 0x12) = WIN_KM_FIELD(Thread, AttachedProcess);
2998 
2999  *(DWORD *)(pHandler->Code + 0x1c) = WIN_KM_FIELD(Thread, Process);
3000 
3001  *(DWORD *)(pHandler->Code + 0x22) = WIN_KM_FIELD(Process, Spare);
3002  *(DWORD *)(pHandler->Code + 0x2a) = WIN_KM_FIELD(Process, Spare);
3003  }
3004 
3005  return INT_STATUS_SUCCESS;
3006 }
3007 
3008 
3009 INTSTATUS
3011  _In_ void const *Detour
3012  )
3045 {
3046  WIN_PROCESS_OBJECT *pProc;
3047  IG_ARCH_REGS *regs;
3048  INTSTATUS status;
3049  QWORD gvaVad;
3050  QWORD protPage;
3051  QWORD protSize;
3052  DWORD vmProt;
3053  QWORD endPage;
3054  QWORD args[4] = {0};
3055  VAD *pVad;
3056 
3058 
3059  regs = &gVcpu->Regs;
3060  pProc = IntWinProcFindObjectByCr3(regs->Cr3);
3061 
3062  if (!pProc || !pProc->Protected || !pProc->MonitorVad)
3063  {
3064  // Nothing to do
3065  goto cleanup_and_exit;
3066  }
3067 
3068  status = IntDetGetArguments(Detour, 4, args);
3069  if (!INT_SUCCESS(status))
3070  {
3071  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
3072  goto cleanup_and_exit;
3073  }
3074 
3075  gvaVad = args[0];
3076  protPage = args[1];
3077  protSize = args[2];
3078  vmProt = (DWORD)args[3];
3079 
3080  // Try to find an existing VAD
3081  pVad = IntWinVadFindByVa(pProc, protPage);
3082  if (NULL != pVad)
3083  {
3084  if (gvaVad != pVad->VadGva)
3085  {
3086  // This VAD was deleted in the meantime, try to get it back
3087  status = IntWinVadHandleInsertGeneric(pProc, gvaVad, FALSE, NULL);
3088  if (!INT_SUCCESS(status))
3089  {
3090  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for 0x%016llx: 0x%08x\n", gvaVad, status);
3091  goto cleanup_and_exit;
3092  }
3093  }
3094  }
3095  else
3096  {
3097  status = IntWinVadHandleInsertGeneric(pProc, gvaVad, FALSE, NULL);
3098  if (!INT_SUCCESS(status))
3099  {
3100  ERROR("[ERROR] IntWinVadHandleInsertGeneric failed for 0x%016llx: 0x%08x\n", gvaVad, status);
3101  goto cleanup_and_exit;
3102  }
3103  }
3104 
3105  // Now apply the protection change. Note that VAD ranges are inclusive, so the end page is the last page
3106  // contained by the VAD
3107  endPage = (protPage + protSize - 1) & PAGE_MASK;
3108  protPage &= PAGE_MASK;
3109 
3110  status = IntWinVadHandleProtectGeneric(pProc, protPage, endPage, vmProt, FALSE);
3111  if (!INT_SUCCESS(status))
3112  {
3113  ERROR("[ERROR] IntWinVadHandleProtectGeneric failed for [0x%016llx, 0x%016llx]: 0x%08x\n",
3114  protPage, endPage, status);
3115  goto cleanup_and_exit;
3116  }
3117 
3118 cleanup_and_exit:
3120 
3121  return INT_STATUS_SUCCESS;
3122 }
3123 
3124 
3125 INTSTATUS
3127  _In_ void const *Detour
3128  )
3144 {
3145  INTSTATUS status;
3146  PIG_ARCH_REGS pRegs;
3147  PWIN_PROCESS_OBJECT pProc;
3148  QWORD vadGva;
3149 
3150  if (NULL == Detour)
3151  {
3153  }
3154 
3155  pRegs = &gVcpu->Regs;
3156 
3157  status = IntDetGetArgument(Detour, 0, NULL, 0, &vadGva);
3158  if (!INT_SUCCESS(status))
3159  {
3160  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
3161  return status;
3162  }
3163 
3164  pProc = IntWinProcFindObjectByCr3(pRegs->Cr3);
3165  if (NULL == pProc || !pProc->MonitorVad)
3166  {
3168  }
3169 
3170  status = IntWinVadHandleInsertGeneric(pProc, vadGva, FALSE, NULL);
3171  if (INT_STATUS_NOT_FOUND != status && !INT_SUCCESS(status))
3172  {
3173  ERROR("[ERROR] IntWinVadHandleInsertionGeneric failed for VAD 0x%016llx: 0x%08x\n", vadGva, status);
3174  }
3175 
3176  return status;
3177 }
3178 
3179 
3180 INTSTATUS
3182  _In_ void const *Detour
3183  )
3201 {
3202  QWORD startPage;
3203  QWORD endPage;
3204  PIG_ARCH_REGS pRegs;
3205  PWIN_PROCESS_OBJECT pProcess;
3206  QWORD args[2];
3207  INTSTATUS status;
3208 
3209  if (NULL == Detour)
3210  {
3212  }
3213 
3214  pRegs = &gVcpu->Regs;
3215 
3216  status = IntDetGetArguments(Detour, 2, args);
3217  if (!INT_SUCCESS(status))
3218  {
3219  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
3220  return status;
3221  }
3222 
3223  startPage = args[0];
3224  endPage = args[1];
3225 
3226  // Align addresses to page boundaries
3227  startPage &= PAGE_MASK;
3228  endPage &= PAGE_MASK;
3229 
3230  // This function is always executed in the context of the process from who's address space the pages are removed
3231  // so we can simply get it by the current Cr3
3232  pProcess = IntWinProcFindObjectByCr3(pRegs->Cr3);
3233  if (!pProcess || !pProcess->MonitorVad)
3234  {
3235  // No process was created yet, or the process is not VAD monitored - bail out.
3237  }
3238 
3239  // Delete the VAD from our internal tree.
3240  status = IntWinVadHandleDeleteGeneric(pProcess, startPage, endPage, 0);
3241  if (!INT_SUCCESS(status))
3242  {
3243  ERROR("[ERROR] IntWinVadHandleDeleteGeneric failed: 0x%08x\n", status);
3244  return status;
3245  }
3246 
3247  return INT_STATUS_SUCCESS;
3248 }
3249 
3250 
3251 INTSTATUS
3253  _In_ void const *Detour
3254  )
3272 {
3273  QWORD startPage;
3274  QWORD endPage;
3275  PIG_ARCH_REGS pRegs;
3276  PWIN_PROCESS_OBJECT pProcess;
3277  QWORD args[2];
3278  INTSTATUS status;
3279 
3280  if (NULL == Detour)
3281  {
3283  }
3284 
3285  pRegs = &gVcpu->Regs;
3286 
3287  status = IntDetGetArguments(Detour, 2, args);
3288  if (!INT_SUCCESS(status))
3289  {
3290  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
3291  return status;
3292  }
3293 
3294  startPage = args[0];
3295  endPage = args[1];
3296 
3297  // Align addresses to page boundaries
3298  startPage &= PAGE_MASK;
3299  endPage &= PAGE_MASK;
3300 
3301  // This function is always executed in the context of the process from who's address space the pages are removed
3302  // so we can simply get it by the current Cr3
3303  pProcess = IntWinProcFindObjectByCr3(pRegs->Cr3);
3304  if (!pProcess || !pProcess->MonitorVad)
3305  {
3306  // No process was created yet, or the process is not VAD monitored - bail out.
3308  }
3309 
3310  // Delete the VAD from our internal tree.
3311  status = IntWinVadHandleDeleteGeneric(pProcess, startPage, endPage, 0);
3312  if (!INT_SUCCESS(status))
3313  {
3314  ERROR("[ERROR] IntWinVadHandleDeleteGeneric failed: 0x%08x\n", status);
3315  return status;
3316  }
3317 
3318  return INT_STATUS_SUCCESS;
3319 }
3320 
3321 
3322 INTSTATUS
3324  _In_ void const *Detour
3325  )
3351 {
3352  INTSTATUS status;
3353  QWORD dstEproc = 0;
3354  QWORD baseGva = 0;
3355  QWORD startPage = 0;
3356  QWORD endPage = 0;
3357  QWORD length = 0;
3358  QWORD newRights; // WIN_MM_PAGE_* constants (as passed to VirtualProtect(Ex))
3359  WIN_PROCESS_OBJECT *pDestProc;
3360  QWORD args[4];
3361 
3362  status = IntDetGetArgument(Detour, 0, NULL, 0, &dstEproc);
3363  if (!INT_SUCCESS(status))
3364  {
3365  ERROR("[ERROR] IntDetGetArgument failed: 0x%08x\n", status);
3366  goto cleanup_and_exit;
3367  }
3368 
3369  pDestProc = IntWinProcFindObjectByEprocess(dstEproc);
3370  if (!pDestProc || !pDestProc->MonitorVad || !pDestProc->ProtExploits)
3371  {
3372  status = INT_STATUS_NOT_NEEDED_HINT;
3373  goto cleanup_and_exit;
3374  }
3375 
3376  status = IntDetGetArguments(Detour, 4, args);
3377  if (!INT_SUCCESS(status))
3378  {
3379  ERROR("[ERROR] IntDetGetArguments failed: 0x%08x\n", status);
3380  goto cleanup_and_exit;
3381  }
3382 
3383  status = IntKernVirtMemRead(args[1], gGuest.WordSize, &baseGva, NULL);
3384  if (!INT_SUCCESS(status))
3385  {
3386  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
3387  goto cleanup_and_exit;
3388  }
3389 
3390  status = IntKernVirtMemRead(args[2], gGuest.WordSize, &length, NULL);
3391  if (!INT_SUCCESS(status))
3392  {
3393  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
3394  goto cleanup_and_exit;
3395  }
3396 
3397  newRights = args[3] & 0xFFFFFFFF;
3398 
3399  // VirtualProtect documentation: The region of affected pages includes all pages containing one or more bytes in
3400  // the range from the lpAddress parameter to (lpAddress+dwSize). This means that a 2-byte range straddling a page
3401  // boundary causes the protection attributes of both pages to be changed.
3402 
3403  endPage = (baseGva + length - 1) & PAGE_MASK;
3404  startPage = baseGva & PAGE_MASK;
3405 
3406  status = IntWinVadHandleProtectGeneric(pDestProc, startPage, endPage, (DWORD)newRights, FALSE);
3407  if (!INT_SUCCESS(status))
3408  {
3409  ERROR("[ERROR] IntWinVadHandleProtectGeneric failed for [0x%016llx, 0x%016llx] in process 0x%016llx: 0x%08x\n",
3410  startPage, endPage, pDestProc->EprocessAddress, status);
3411  goto cleanup_and_exit;
3412  }
3413 
3414 cleanup_and_exit:
3415 
3416  return status;
3417 }
3418 
3419 
3420 BOOLEAN
3422  _In_ const VAD *Vad
3423  )
3435 {
3436  INTSTATUS status;
3437  VAD dummy = { 0 };
3438  VAD parent = { 0 };
3439 
3440  if (NULL == Vad)
3441  {
3442  return FALSE;
3443  }
3444 
3445  status = IntWinVadFetchVadFromMemory(Vad->VadGva, &dummy);
3446  if (!INT_SUCCESS(status))
3447  {
3448  ERROR("[ERROR] Could not fetch VAD 0x%016llx from memory: 0x%08x\n", Vad->VadGva, status);
3449  return FALSE;
3450  }
3451 
3452  // If the parent value is not a valid kernel pointer, we can assume the VAD was not inserted yet. The parent value
3453  // seems to always be 0xFFFFFFFE on x86/0xFFFFFFFFFFFFFFFE on x64, but we allow a more relaxed interval, for safety.
3454  if (!IS_KERNEL_POINTER_WIN(gGuest.Guest64, dummy.Parent) ||
3455  (dummy.Parent == 0) ||
3456  ((dummy.Parent >= 0xFFFFFFF0) && (dummy.Parent <= 0xFFFFFFFF)) ||
3457  ((dummy.Parent >= 0xFFFFFFFFFFFFFFF0) && (dummy.Parent <= 0xFFFFFFFFFFFFFFFF)))
3458  {
3459  return FALSE;
3460  }
3461 
3462  // Red is bit 0 and Balance is bit 1
3463  status = IntWinVadFetchVadFromMemory(dummy.Parent & (~3), &parent);
3464  if (!INT_SUCCESS(status))
3465  {
3466  WARNING("[WARNING] IntWinVadFetchVadFromMemory failed for parent 0x%016llx: 0x%08x\n",
3467  dummy.Parent & (~3), status);
3468  return FALSE;
3469  }
3470 
3471  // We can also verify for now that the parent has either the left or right node the current VAD
3472  if (parent.Left != Vad->VadGva && parent.Right != Vad->VadGva)
3473  {
3474  WARNING("[WARNING] The current VAD's parent doesn't have as a child 0x%016llx "
3475  "(left 0x%016llx, right: 0x%016llx)\n",
3476  Vad->VadGva, parent.Left, parent.Right);
3477  return FALSE;
3478  }
3479 
3480  if (Vad->NoChange != Vad->PrivateFixup || Vad->DeleteInProgress)
3481  {
3482  WARNING("[WARNING] NoChange is %d, PrivateFixup is %d, DeleteInProgress is %d, "
3483  "the VAD doesn't seem to be considered in the tree!\n",
3484  Vad->NoChange, Vad->PrivateFixup, Vad->DeleteInProgress);
3485  return FALSE;
3486  }
3487 
3488 
3489  return TRUE;
3490 }
3491 
3492 
3494 INTSTATUS
3496  _In_ QWORD FunctionAddress,
3497  _Inout_ API_HOOK_HANDLER *Handler,
3498  _In_ QWORD HandlerAddress
3499  )
3514 {
3515  API_HOOK_HANDLER *pHandler = Handler;
3516 
3517  UNREFERENCED_PARAMETER(FunctionAddress);
3518  UNREFERENCED_PARAMETER(HandlerAddress);
3519 
3520  if (gGuest.Guest64)
3521  {
3522  if (gGuest.OSVersion == 9600)
3523  {
3524  *(DWORD *)(&pHandler->Code[9]) = WIN_KM_FIELD(Process, Spare);
3525  *(DWORD *)(&pHandler->Code[18]) = WIN_KM_FIELD(Process, Spare);
3526  }
3527  else
3528  {
3529  *(DWORD *)(&pHandler->Code[37]) = WIN_KM_FIELD(Process, Spare);
3530  *(DWORD *)(&pHandler->Code[45]) = WIN_KM_FIELD(Process, Spare);
3531  }
3532  }
3533  else
3534  {
3535  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 7602)
3536  {
3537  *(DWORD *)(&pHandler->Code[30]) = WIN_KM_FIELD(Process, Spare);
3538  }
3539  else if (gGuest.OSVersion == 9200)
3540  {
3541  *(DWORD *)(&pHandler->Code[7]) = WIN_KM_FIELD(Process, Spare);
3542  }
3543  else if (gGuest.OSVersion >= 9600)
3544  {
3545  *(DWORD *)(&pHandler->Code[13]) = WIN_KM_FIELD(Process, Spare);
3546  }
3547  }
3548 
3549  return INT_STATUS_SUCCESS;
3550 }
3551 
3552 
3554 INTSTATUS
3556  _In_ QWORD FunctionAddress,
3557  _Inout_ API_HOOK_HANDLER *Handler,
3558  _In_ QWORD HandlerAddress
3559  )
3574 {
3575  API_HOOK_HANDLER *pHandler = Handler;
3576 
3577  UNREFERENCED_PARAMETER(FunctionAddress);
3578  UNREFERENCED_PARAMETER(Handler);
3579  UNREFERENCED_PARAMETER(HandlerAddress);
3580 
3581  if (gGuest.Guest64)
3582  {
3583  *(DWORD *)(&pHandler->Code[37]) = WIN_KM_FIELD(Process, Spare);
3584  *(DWORD *)(&pHandler->Code[45]) = WIN_KM_FIELD(Process, Spare);
3585  }
3586  else
3587  {
3588  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 7602)
3589  {
3590  *(DWORD *)(&pHandler->Code[30]) = WIN_KM_FIELD(Process, Spare);
3591  }
3592  else if (gGuest.OSVersion >= 9200)
3593  {
3594  *(DWORD *)(&pHandler->Code[33]) = WIN_KM_FIELD(Process, Spare);
3595  }
3596  }
3597 
3598  return INT_STATUS_SUCCESS;
3599 }
3600 
3601 
3603 INTSTATUS
3605  _In_ QWORD FunctionAddress,
3606  _Inout_ API_HOOK_HANDLER *Handler,
3607  _In_ QWORD HandlerAddress
3608  )
3623 {
3624  API_HOOK_HANDLER *pHandler = Handler;
3625 
3626  UNREFERENCED_PARAMETER(FunctionAddress);
3627  UNREFERENCED_PARAMETER(HandlerAddress);
3628 
3629  if (gGuest.Guest64)
3630  {
3631  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 9200)
3632  {
3633  *(DWORD *)(&pHandler->Code[8]) = WIN_KM_FIELD(Process, Spare);
3634  *(DWORD *)(&pHandler->Code[16]) = WIN_KM_FIELD(Process, Spare);
3635  }
3636  else if (gGuest.OSVersion >= 9600)
3637  {
3638  *(DWORD *)(&pHandler->Code[9]) = WIN_KM_FIELD(Process, Spare);
3639  *(DWORD *)(&pHandler->Code[17]) = WIN_KM_FIELD(Process, Spare);
3640  }
3641  }
3642  else
3643  {
3644  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 9200)
3645  {
3646  *(DWORD *)(&pHandler->Code[14]) = WIN_KM_FIELD(Process, Spare);
3647  }
3648  else if (gGuest.OSVersion >= 9600)
3649  {
3650  *(DWORD *)(&pHandler->Code[9]) = WIN_KM_FIELD(Process, Spare);
3651  *(DWORD *)(&pHandler->Code[17]) = WIN_KM_FIELD(Process, Spare);
3652  }
3653  }
3654 
3655  return INT_STATUS_SUCCESS;
3656 }
3657 
3658 
3660 INTSTATUS
3662  _In_ QWORD FunctionAddress,
3663  _Inout_ API_HOOK_HANDLER *Handler,
3664  _In_ QWORD HandlerAddress
3665  )
3680 {
3681  API_HOOK_HANDLER *pHandler = Handler;
3682 
3683  UNREFERENCED_PARAMETER(FunctionAddress);
3684  UNREFERENCED_PARAMETER(HandlerAddress);
3685 
3686  if (gGuest.Guest64)
3687  {
3688  *(DWORD *)(&pHandler->Code[31]) = WIN_KM_FIELD(Process, Spare);
3689  *(DWORD *)(&pHandler->Code[39]) = WIN_KM_FIELD(Process, Spare);
3690  }
3691  else
3692  {
3693  if (gGuest.OSVersion >= 7600 && gGuest.OSVersion <= 7602)
3694  {
3695  *(DWORD *)(&pHandler->Code[24]) = WIN_KM_FIELD(Process, Spare);
3696  }
3697  else if (gGuest.OSVersion >= 9200 && gGuest.OSVersion <= 16299)
3698  {
3699  *(DWORD *)(&pHandler->Code[27]) = WIN_KM_FIELD(Process, Spare);
3700  }
3701  }
3702 
3703  return INT_STATUS_SUCCESS;
3704 }
3705 
3706 
3708 INTSTATUS
3710  _In_ QWORD FunctionAddress,
3711  _Inout_ API_HOOK_HANDLER *Handler,
3712  _In_ QWORD HandlerAddress
3713  )
3728 {
3729  API_HOOK_HANDLER *pHandler = Handler;
3730 
3731  UNREFERENCED_PARAMETER(FunctionAddress);
3732  UNREFERENCED_PARAMETER(HandlerAddress);
3733 
3734  if (gGuest.Guest64)
3735  {
3736  *(DWORD *)(&pHandler->Code[37]) = WIN_KM_FIELD(Process, Spare);
3737  *(DWORD *)(&pHandler->Code[45]) = WIN_KM_FIELD(Process, Spare);
3738  }
3739  else
3740  {
3741  if (gGuest.OSVersion >= 17134)
3742  {
3743  *(DWORD *)(&pHandler->Code[27]) = WIN_KM_FIELD(Process, Spare);
3744  }
3745  }
3746 
3747  return INT_STATUS_SUCCESS;
3748 }
3749 
3750 
3752 INTSTATUS
3754  _In_ QWORD FunctionAddress,
3755  _Inout_ API_HOOK_HANDLER *Handler,
3756  _In_ QWORD HandlerAddress
3757  )
3772 {
3773  API_HOOK_HANDLER *pHandler = Handler;
3774 
3775  UNREFERENCED_PARAMETER(FunctionAddress);
3776  UNREFERENCED_PARAMETER(HandlerAddress);
3777 
3778  if (gGuest.Guest64)
3779  {
3780  if (gGuest.OSVersion >= 10240)
3781  {
3782  *(DWORD *)(&pHandler->Code[8]) = WIN_KM_FIELD(Process, Spare);
3783  *(DWORD *)(&pHandler->Code[16]) = WIN_KM_FIELD(Process, Spare);
3784  }
3785  }
3786  else
3787  {
3788  if (gGuest.OSVersion >= 18363)
3789  {
3790  *(DWORD *)(&pHandler->Code[9]) = WIN_KM_FIELD(Process, Spare);
3791  }
3792  }
3793 
3794  return INT_STATUS_SUCCESS;
3795 }
3796 
3797 
3798 INTSTATUS
3800  _Inout_ WIN_PROCESS_OBJECT *Process
3801  )
3811 {
3812  INTSTATUS status;
3813  QWORD vadRoot;
3814  QWORD vadNode;
3815 
3816  vadNode = 0;
3817  vadRoot = 0;
3818 
3819  if (NULL == Process)
3820  {
3822  }
3823 
3824  status = IntKernVirtMemRead(Process->EprocessAddress + WIN_KM_FIELD(Process, VadRoot),
3825  gGuest.WordSize,
3826  &vadRoot,
3827  NULL);
3828  if (!INT_SUCCESS(status))
3829  {
3830  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
3831  return status;
3832  }
3833 
3834  vadNode = IntWinVadFindNodeInGuestSpace(vadRoot,
3835  Process->MainModuleAddress & PAGE_MASK,
3836  Process->MainModuleAddress & PAGE_MASK,
3837  0,
3838  0,
3839  FALSE);
3840  if (!vadNode)
3841  {
3842  // We cannot get a valid VAD - skipping.
3844  }
3845 
3846  // Note that we don't want to insert a vad in the tree here, we just want to get a vad object for
3847  // the main module vad. This will get destroyed at process uninit, therefore there is no need to
3848  // cleanup this vad during the RbTree uninit. Also, since the VAD might have been previously loaded
3849  // inside the process, we will consider it as "static scanned".
3850  status = IntWinVadCreateObject(Process, vadNode, (VAD **)&Process->MainModuleVad, TRUE);
3851  if (!INT_SUCCESS(status))
3852  {
3853  ERROR("[ERROR] IntWinVadCreateObject failed: 0x%08x\n", status);
3854  return status;
3855  }
3856 
3857  return INT_STATUS_SUCCESS;
3858 }
3859 
3860 INTSTATUS
3862  _In_ QWORD VadRoot,
3863  _In_ QWORD StartPage,
3864  _In_ QWORD EndPage,
3865  _Out_ VAD *Vad
3866  )
3885 
3886 {
3887  QWORD vadNode = 0;
3888 
3889  if (0 == VadRoot)
3890  {
3892  }
3893 
3894  if (NULL == Vad)
3895  {
3897  }
3898 
3899  vadNode = IntWinVadFindNodeInGuestSpace(VadRoot,
3900  StartPage & PAGE_MASK,
3901  EndPage & PAGE_MASK,
3902  0,
3903  0,
3904  FALSE);
3905  if (0 == vadNode)
3906  {
3907  ERROR("[ERROR] Vad [0x%016llx, 0x%016llx] not found starting from root 0x%016llx\n",
3908  StartPage,
3909  EndPage,
3910  VadRoot);
3911 
3912  return INT_STATUS_NOT_FOUND;
3913  }
3914 
3915  return IntWinVadFetchVadFromMemory(vadNode, Vad);
3916 }
3917 
3918 
3919 #undef VAD_SHORT_FIELD_PTR
3920 #undef VAD_LONG_FIELD_PTR
3921 
3922 #undef VadShortByte
3923 #undef VadShortWord
3924 #undef VadShortDword
3925 #undef VadShortQword
3926 #undef VadShortPtrSize
3927 #undef VadShortAnySize
#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:1145
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:1773
#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:1579
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:2809
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:3181
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:3861
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
DWORD Index
The VCPU number.
Definition: guests.h:172
#define _In_
Definition: intro_sal.h:21
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1088
#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:207
#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:51
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:1164
INTSTATUS IntWinVadPatchInsertMap(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, QWORD HandlerAddress)
This is the PFUNC_PreDetourCallback for the MiGetWsAndInsertVad guest API detour.It will be invoked b...
Definition: winvad.c:3555
#define VadShortDword(ptr_, field_)
Reads a dword from a VAD short buffer.
Definition: winvad.c:114
#define STATS_EXIT(id)
Definition: stats.h:148
#define MAX_LEVEL
struct _EVENT_EPT_VIOLATION::@276 Originator
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:1172
User-mode exception.
Definition: exceptions.h:61
Described a detour handler.
Definition: detours.h:279
Ignored by introcore.
Definition: wddefs.h:1181
User-mode non executable zone.
Definition: intro_types.h:244
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:2106
Memory used by video drivers to transfer data between the GPU and a process.
Definition: wddefs.h:1196
QWORD Feedback
Options that will be forced to feedback only mode.
Definition: guests.h:251
void FUNC_RbTreeNodeFree(RBNODE *Node)
Definition: rbtree.h:47
static INTSTATUS IntWinVadFetchVadFromMemory(QWORD VadGva, VAD *Vad)
Reads a _MMVAD structure from the Windows kernel and creates a corresponding VAD structure.
Definition: winvad.c:1375
#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:1087
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
Definition: introcore.c:2355
Definition: rbtree.h:34
INTSTATUS IntWinVadPatchVirtualProtect(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, QWORD HandlerAddress)
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:3604
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:3323
BOOLEAN FirstDominoJavaIgnored
TRUE if the first Domino Java execution VAD was ignored.
Definition: winprocess.h:191
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:1212
INTSTATUS RbWalkInorderTree(RBTREE *Tree, PFUNC_RbTreeWalkCallback Callback, void *WalkContext)
Definition: rbtree.c:806
INTSTATUS IntWinPatchVadHandleCommit(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, QWORD HandlerAddress)
This is the PFUNC_PreDetourCallback for the MiCommitExistingVad guest API detour.It will be invoked b...
Definition: winvad.c:2944
#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:933
#define WIN_MM_PAGE_EXECUTE_READ
Defined by Windows as PAGE_EXECUTE_READ in winnt.h.
Definition: wddefs.h:1209
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
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
INTSTATUS IntWinVadPatchInsert(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, QWORD HandlerAddress)
This is the PFUNC_PreDetourCallback for the MiInsertVad guest API detour.It will be invoked before th...
Definition: winvad.c:3753
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:2752
#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:277
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:3010
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:1472
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:622
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:128
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:1803
#define IC_TAG_VAD
Virtual Address Descriptor for user mode address ranges.
Definition: memtags.h:93
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:1106
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:1084
BOOLEAN IntWinVadDump(VAD const *Vad, void *Context)
Prints a VAD structure.
Definition: winvad.c:1698
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:96
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:952
#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:1817
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:1211
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
INTSTATUS IntWinVadPatchDeleteVaRange(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, QWORD HandlerAddress)
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:3661
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:94
#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
#define STATS_ENTER(id)
Definition: stats.h:141
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
Definition: intro_types.h:1085
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:700
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:2550
#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
INTSTATUS(* PFUNC_PreDetourCallback)(QWORD FunctionAddress, void *Handler, QWORD HandlerAddress)
The type of a callback invoked before setting a detour.
Definition: detours.h:228
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:286
INTSTATUS IntExceptGetVictimEpt(void *Context, QWORD Gpa, QWORD Gva, INTRO_OBJECT_TYPE Type, DWORD ZoneFlags, EXCEPTION_VICTIM_ZONE *Victim)
Fills an EXCEPTION_VICTIM_ZONE with relevant information from an EPT violation.
Definition: exceptions.c:742
unsigned long long QWORD
Definition: intro_types.h:53
CHAR Name[IMAGE_BASE_NAME_LEN]
Process base name.
Definition: winprocess.h:106
QWORD Current
The currently used options.
Definition: guests.h:232
BYTE Code[DETOUR_MAX_HANDLER_SIZE]
The code of the detour handler. Only CodeLength bytes are valid.
Definition: detours.h:294
WINUM_PATH * Path
Definition: winvad.h:144
Measures the IntWinVadHandleCommit detour handler.
Definition: stats.h:57
#define WIN_MM_PAGE_READWRITE
Defined by Windows as PAGE_READWRITE in winnt.h.
Definition: wddefs.h:1206
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:2881
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
#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:122
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:3799
QWORD StackLimit
The stack limit for the thread that attempted the execution.
Definition: intro_types.h:917
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:2702
#define WIN_MM_PAGE_EXECUTE
Defined by Windows as PAGE_EXECUTE in winnt.h.
Definition: wddefs.h:1208
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:363
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:1191
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:2369
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:2105
#define WARNING(fmt,...)
Definition: glue.h:60
INTSTATUS IntWinVadPatchInsertPrivate(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, QWORD HandlerAddress)
This is the PFUNC_PreDetourCallback for the MiInsertPrivateVad guest API detour.It will be invoked be...
Definition: winvad.c:3495
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
#define WIN_MM_PAGE_NOACCESS
Defined by Windows as PAGE_NOACCESS in winnt.h.
Definition: wddefs.h:1204
#define PAGE_SIZE
Definition: common.h:53
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:847
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:341
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:726
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:2164
None. Normal allocations have this type.
Definition: wddefs.h:1180
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:3126
INTSTATUS IntWinModHandleLoadFromVad(WIN_PROCESS_OBJECT *Process, const VAD *Vad)
Handle a module load from a VAD.
Definition: winummodule.c:1260
#define NO_ERRORCODE
Definition: processor.h:123
INTSTATUS IntWinVadPatchFinishVadDeletion(QWORD FunctionAddress, API_HOOK_HANDLER *Handler, QWORD HandlerAddress)
This is the PFUNC_PreDetourCallback for the MiFinishVadDeletion guest API detour.It will be invoked b...
Definition: winvad.c:3709
BOOLEAN IntWinVadIsInTree(const VAD *Vad)
Checks if a VAD is inserted in a guest VAD tree.
Definition: winvad.c:3421
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:1210
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:3252
#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:370
QWORD EprocessAddress
This will be the address of the ActiveProcess field.
Definition: winprocess.h:88
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:48
struct _EXCEPTION_UM_ORIGINATOR::@72 Return
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:2403
PWIN_PROCESS_OBJECT IntWinProcFindObjectByEprocess(QWORD Eprocess)
Finds a process by the address of its _EPROCESS structure.
Definition: winprocesshp.c:23
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:915
INTRO_PROT_OPTIONS ShemuOptions
Flags which describe the way shemu will give detections.
Definition: guests.h:268
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:1083
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:160
The type of an allocation that specified the MEM_WRITE_WATCH VirtualAlloc flag.
Definition: wddefs.h:1190
Holds information about an execution attempt.
Definition: intro_types.h:913
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:916
INTSTATUS IntWinVadShortDump(QWORD VadNodeGva, DWORD Level, void *Context)
Prints a _MMVAD_SHORT structure.
Definition: winvad.c:1652
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:1086
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:57
#define WIN_MM_PAGE_WRITECOPY
Defined by Windows as PAGE_WRITECOPY in winnt.h.
Definition: wddefs.h:1207
#define IC_TAG_VAD_PAGE
Virtual page from a VAD page array.
Definition: memtags.h:95
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:1908
INTSTATUS IntWinVadWalkTree(PWIN_PROCESS_OBJECT Process, PFUNC_RbTreeWalkCallback Callback)
Walks the VAD tree of a process.
Definition: winvad.c:2009
#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:1104
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:1046
DWORD Length
The length of the instruction.
Definition: intro_types.h:918
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:2145
#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:267
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:958
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:2042
#define WIN_MM_PAGE_READONLY
Defined by Windows as PAGE_READONLY in winnt.h.
Definition: wddefs.h:1205
#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:3317
INTSTATUS IntWinNetSendProcessConnections(WIN_PROCESS_OBJECT *Process)
Send connection events for all active connections whose owner is the given process.
Definition: winnet.c:1751
INTSTATUS IntWinModHandleUnloadFromVad(PWIN_PROCESS_OBJECT Process, PVAD Vad)
Handle a module unload.
Definition: winummodule.c:1435
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:1111
#define INTRO_OPT_NOTIFY_ENGINES
Send suspicious pages to be scanned by third party scan engines.
Definition: intro_types.h:443
#define FALSE
Definition: intro_types.h:34
This structure describes a running process inside the guest.
Definition: winprocess.h:81
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68