Bitdefender Hypervisor Memory Introspection
windriver.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "windriver.h"
6 #include "alerts.h"
7 #include "crc32.h"
8 #include "hook.h"
9 #include "swapmem.h"
10 #include "winpe.h"
11 #include "winagent.h"
12 #include "windrv_protected.h"
13 
15 
27 
28 
29 static void
31  _In_ KERNEL_DRIVER *Driver,
32  _In_ BOOLEAN Loaded
33  )
43 {
45  {
46  return;
47  }
48 
49  EVENT_MODULE_EVENT *pModEvent = &gAlert.Module;
50  memzero(pModEvent, sizeof(*pModEvent));
51 
52  pModEvent->Loaded = Loaded;
53  pModEvent->Protected = Driver->Protected;
54 
55  IntAlertFillWinKmModule(Driver, &pModEvent->Module);
57 
58  INTSTATUS status = IntNotifyIntroEvent(introEventModuleEvent, pModEvent, sizeof(*pModEvent));
59  if (!INT_SUCCESS(status))
60  {
61  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
62  }
63 }
64 
65 
68  _In_ QWORD PsLoadedModuleListGva,
69  _In_ void *PsLoadedModuleList,
70  _In_ QWORD KernelLdr
71  )
81 {
82  INTSTATUS status;
83  BOOLEAN matched;
84  QWORD name = 0;
85 
86  if (gGuest.Guest64)
87  {
89  LIST_ENTRY64 *pListHead;
90 
91  // PsModuleList is LIST_HEAD, it must not spill into the next page
92  if ((PsLoadedModuleListGva & PAGE_OFFSET) + sizeof(LIST_ENTRY64) > PAGE_SIZE)
93  {
95  }
96 
97  // The driver pointed by the head must not spill in another page.
98  if ((KernelLdr & PAGE_OFFSET) + sizeof(LDR_DATA_TABLE_ENTRY64) >= PAGE_SIZE)
99  {
101  }
102 
103  pListHead = (LIST_ENTRY64 *)PsLoadedModuleList;
104  if (!IS_KERNEL_POINTER_WIN(TRUE, pListHead->Blink))
105  {
107  }
108 
109  status = IntKernVirtMemRead(KernelLdr, sizeof(mod64), &mod64, NULL);
110  if (!INT_SUCCESS(status))
111  {
112  return status;
113  }
114 
115  // The invariant rules
117  matched = matched && IS_KERNEL_POINTER_WIN(TRUE, mod64.InLoadOrderLinks.Blink);
118  matched = matched && IS_KERNEL_POINTER_WIN(TRUE, mod64.DllBase);
119  matched = matched && (mod64.DllBase % PAGE_SIZE == 0);
120  matched = matched && (mod64.EntryPoint > mod64.DllBase && mod64.EntryPoint < mod64.DllBase + mod64.SizeOfImage);
121 
122  if (!matched)
123  {
125  }
126 
127  // Fetch the name of the driver, to make sure it's the kernel (ntos*)
128  status = IntKernVirtMemFetchQword(mod64.DriverName.Buffer, &name);
129  if (!INT_SUCCESS(status))
130  {
131  return status;
132  }
133 
134  if (name != 0x0073006f0074006e) // "ntos", UNICODE
135  {
137  }
138 
139  status = INT_STATUS_SUCCESS;
140  }
141  else
142  {
144  LIST_ENTRY32 *pListHead;
145 
146  // PsModuleList is LIST_HEAD, it must not spill into the next page
147  if (PAGE_REMAINING(PsLoadedModuleListGva) + sizeof(LIST_ENTRY32) > PAGE_SIZE)
148  {
150  }
151 
152  // The driver pointed by the head must not spill in another page.
153  if ((KernelLdr & PAGE_OFFSET) + sizeof(LDR_DATA_TABLE_ENTRY32) >= PAGE_SIZE)
154  {
156  }
157 
158  pListHead = (LIST_ENTRY32 *)PsLoadedModuleList;
159  if (!IS_KERNEL_POINTER_WIN(FALSE, pListHead->Blink))
160  {
162  }
163 
164  status = IntKernVirtMemRead(KernelLdr, sizeof(mod32), &mod32, NULL);
165  if (!INT_SUCCESS(status))
166  {
167  return status;
168  }
169 
170  // The invariant rules
172  matched = matched && IS_KERNEL_POINTER_WIN(FALSE, mod32.InLoadOrderLinks.Blink);
173  matched = matched && IS_KERNEL_POINTER_WIN(FALSE, mod32.DllBase);
174  matched = matched && (mod32.DllBase % PAGE_SIZE == 0);
175  matched = matched &&
176  (mod32.EntryPoint > mod32.DllBase && mod32.EntryPoint < (QWORD)mod32.DllBase + mod32.SizeOfImage);
177 
178  if (!matched)
179  {
181  }
182 
183  // Fetch the name of the driver, to make sure it's the kernel (ntos*)
184  status = IntKernVirtMemFetchQword(mod32.DriverName.Buffer, &name);
185  if (!INT_SUCCESS(status))
186  {
187  return status;
188  }
189 
190  if (name != 0x0073006f0074006e) // "ntos", UNICODE
191  {
193  }
194 
195  if (mod32.InLoadOrderLinks.Blink != PsLoadedModuleListGva)
196  {
197  TRACE("[INFO] Found & skipped shadow module list at 0x%08x (head->flink->blink should be same as head)\n",
198  (DWORD)PsLoadedModuleListGva);
199 
201  }
202 
203  status = INT_STATUS_SUCCESS;
204  }
205 
206  return status;
207 }
208 
209 
210 INTSTATUS
213  _In_ QWORD Aux
214  )
223 {
224  INTSTATUS status;
225  QWORD count = 0;
226  QWORD currentModule = gWinGuest->PsLoadedModuleList;
227 
228  if (Callback == NULL)
229  {
231  }
232 
233  // Read the Flink value
234  if (gGuest.Guest64)
235  {
236  status = IntKernVirtMemFetchQword(currentModule, &currentModule);
237  }
238  else
239  {
240  status = IntKernVirtMemFetchDword(currentModule, (DWORD *)&currentModule);
241  }
242  if (!INT_SUCCESS(status))
243  {
244  ERROR("[ERROR] Failed getting the Flink value of MODULE @ 0x%016llx: 0x%08x\n", currentModule, status);
245  return status;
246  }
247 
248  status = INT_STATUS_SUCCESS;
249 
250  // We'll iterate for maximum DRIVER_MAX_ITERATIONS. We assume that there won't be more than this many drivers.
251  // This is a guard to avoid denial of service with crafted drivers nodes.
252  while ((currentModule != gWinGuest->PsLoadedModuleList) && (count++ < DRIVER_MAX_ITERATIONS))
253  {
254  status = Callback(currentModule, Aux);
255  if (INT_STATUS_BREAK_ITERATION == status)
256  {
257  return INT_STATUS_SUCCESS;
258  }
259 
260  // Go to the next entry
261  if (gGuest.Guest64)
262  {
263  status = IntKernVirtMemFetchQword(currentModule, &currentModule);
264  }
265  else
266  {
267  status = IntKernVirtMemFetchDword(currentModule, (DWORD *)&currentModule);
268  currentModule &= 0xFFFFFFFF;
269  }
270  if (!INT_SUCCESS(status))
271  {
272  ERROR("[ERROR] Failed getting the Flink value of LDR_DATA_TABLE_ENTRY @ 0x%016llx: 0x%08x\n",
273  currentModule, status);
274  break;
275  }
276  }
277 
278  if (count == DRIVER_MAX_ITERATIONS)
279  {
280  // This means that the guest list os crafted somehow...
281  status = INT_STATUS_NOT_SUPPORTED;
282  }
283 
284  return status;
285 }
286 
287 
288 INTSTATUS
290  _In_ QWORD ModuleInfo,
291  _In_ QWORD Flags
292  )
304 {
305  LDR_DATA_TABLE_ENTRY32 pModuleInfo32 = {0};
306  LDR_DATA_TABLE_ENTRY64 pModuleInfo64 = {0};
307  const PROTECTED_MODULE_INFO *pProt = NULL;
308  INTSTATUS status;
309  KERNEL_DRIVER *pDriver;
310  DWORD nameSize, pathSize;
311  QWORD entryPoint;
312 
313  pDriver = NULL;
314 
315  if (gGuest.Guest64)
316  {
317  status = IntKernVirtMemRead(ModuleInfo, sizeof(LDR_DATA_TABLE_ENTRY64), &pModuleInfo64, NULL);
318  }
319  else
320  {
321  status = IntKernVirtMemRead(ModuleInfo, sizeof(LDR_DATA_TABLE_ENTRY32), &pModuleInfo32, NULL);
322  }
323  if (!INT_SUCCESS(status))
324  {
325  ERROR("[ERROR] Failed reading from GVA 0x%016llx to host: 0x%08x\n", ModuleInfo, status);
326  return status;
327  }
328 
329  pDriver = HpAllocWithTag(sizeof(*pDriver), IC_TAG_MODU);
330  if (NULL == pDriver)
331  {
333  }
334 
335  if (gGuest.Guest64)
336  {
337  pDriver->BaseVa = pModuleInfo64.DllBase;
338  pDriver->Size = 0xFFFFFFFF & pModuleInfo64.SizeOfImage;
339  pDriver->EntryPoint = pModuleInfo64.EntryPoint;
340 
341  entryPoint = pModuleInfo64.EntryPoint;
342 
343  pathSize = 0xFFFF & pModuleInfo64.DriverPath.Length;
344 
345  // pathLength + 2: OK - pathLength is DWORD and is AND with 0xFFFF.
346  pDriver->Win.Path = HpAllocWithTag(pathSize + 2ull, IC_TAG_DRNU);
347  if (NULL == pDriver->Win.Path)
348  {
350  goto _cleanup_and_leave;
351  }
352 
353  status = IntKernVirtMemRead(pModuleInfo64.DriverPath.Buffer, pathSize, pDriver->Win.Path, NULL);
354  if (!INT_SUCCESS(status))
355  {
357  pDriver->Win.PathHash = INITIAL_CRC_VALUE;
358  pDriver->Win.PathLength = 0;
359  }
360  else
361  {
362  strlower_utf16(pDriver->Win.Path, pathSize / 2);
363  pDriver->Win.PathLength = pathSize / 2;
364  pDriver->Win.PathHash = Crc32Wstring(pDriver->Win.Path, INITIAL_CRC_VALUE);
365  }
366 
367  nameSize = 0xFFFF & pModuleInfo64.DriverName.Length;
368 
369  // nameLength + 2: OK - pathLength is DWORD and is AND with 0xFFFF.
370  pDriver->Name = HpAllocWithTag(nameSize + 2ull, IC_TAG_DRNU);
371  if (NULL == pDriver->Name)
372  {
374  goto _cleanup_and_leave;
375  }
376 
377  status = IntKernVirtMemRead(pModuleInfo64.DriverName.Buffer, nameSize, pDriver->Name, NULL);
378  if (!INT_SUCCESS(status))
379  {
380  ERROR("[ERROR] Failed reading driver name: 0x%08x\n", status);
381  goto _cleanup_and_leave;
382  }
383 
384  strlower_utf16(pDriver->Name, nameSize / 2);
385  pDriver->NameLength = nameSize / 2;
386  pDriver->NameHash = Crc32Wstring(pDriver->Name, INITIAL_CRC_VALUE);
387  }
388  else
389  {
390  pDriver->BaseVa = pModuleInfo32.DllBase;
391  pDriver->Size = pModuleInfo32.SizeOfImage;
392  pDriver->EntryPoint = pModuleInfo32.EntryPoint;
393 
394  entryPoint = pModuleInfo32.EntryPoint;
395 
396  pathSize = 0xFFFF & pModuleInfo32.DriverPath.Length;
397 
398  // pathLength + 2 OK - pathLength is DWORD and is AND with 0xFFFF.
399  pDriver->Win.Path = HpAllocWithTag(pathSize + 2ull, IC_TAG_DRNU);
400  if (NULL == pDriver->Win.Path)
401  {
403  goto _cleanup_and_leave;
404  }
405 
406  status = IntKernVirtMemRead(pModuleInfo32.DriverPath.Buffer, pathSize, pDriver->Win.Path, NULL);
407  if (!INT_SUCCESS(status))
408  {
410  pDriver->Win.PathHash = INITIAL_CRC_VALUE;
411  pDriver->Win.PathLength = 0;
412  }
413  else
414  {
415  strlower_utf16(pDriver->Win.Path, pathSize / 2);
416  pDriver->Win.PathLength = pathSize / 2;
417  pDriver->Win.PathHash = Crc32Wstring(pDriver->Win.Path, INITIAL_CRC_VALUE);
418  }
419 
420  nameSize = 0xFFFF & pModuleInfo32.DriverName.Length;
421 
422  // nameLength + 2 OK - pathLength is DWORD and is AND with 0xFFFF.
423  pDriver->Name = HpAllocWithTag(nameSize + 2ull, IC_TAG_DRNU);
424  if (NULL == pDriver->Name)
425  {
427  goto _cleanup_and_leave;
428  }
429 
430  status = IntKernVirtMemRead(pModuleInfo32.DriverName.Buffer, nameSize, pDriver->Name, NULL);
431  if (!INT_SUCCESS(status))
432  {
433  ERROR("[ERROR] Failed reading driver name from 0x%08x [%d]: 0x%08x\n",
434  pModuleInfo32.DriverName.Buffer, pModuleInfo32.DriverName.Length, status);
435  goto _cleanup_and_leave;
436  }
437 
438  strlower_utf16(pDriver->Name, nameSize / 2);
439  pDriver->NameHash = Crc32Wstring(pDriver->Name, INITIAL_CRC_VALUE);
440  pDriver->NameLength = nameSize / 2;
441  }
442 
443  TRACE("[DRIVER] Driver '%s' @ 0x%016llx (base: 0x%016llx, hash: 0x%08x) just loaded\n",
444  utf16_for_log(pDriver->Name), ModuleInfo, pDriver->BaseVa, pDriver->NameHash);
445 
446  if ((0 != (Flags & FLAG_DYNAMIC_DETECTION)) &&
447  IS_KERNEL_POINTER_WIN(gGuest.Guest64, entryPoint) &&
448  IntWinDrvHasDriverObject(pDriver))
449  {
450  // We will execute-protect the page with EP from the newly loaded driver. This way,
451  // when the first instruction will get executed, we will be notified, and we'll have
452  // a chance to protect the driver's driver object. As a cool stuff, the section with
453  // the EP of any newly-loaded driver is always mapped in memory (will not be swapped
454  // out). If it isn't, then we're dealing with a regular dll, and not a driver.
455 
457  if (!INT_SUCCESS(status))
458  {
459  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
460  goto _cleanup_and_leave;
461  }
462 
463  status = IntHookObjectHookRegion(pDriver->Win.EpHookObject,
464  0,
465  entryPoint & PAGE_MASK,
466  PAGE_SIZE,
469  pDriver,
470  0,
471  NULL);
472  if (!INT_SUCCESS(status))
473  {
474  ERROR("[ERROR] IntHookObjectHookRegion failed: 0x%08x\n", status);
475  goto _cleanup_and_leave;
476  }
477  }
478 
479  pProt = IntWinDrvIsProtected(pDriver);
480  if (pProt)
481  {
482  status = IntWinDrvProtect(pDriver, pProt->RequiredFlags);
483  if (!INT_SUCCESS(status))
484  {
485  ERROR("[ERROR] IntWinDrvProtect failed: 0x%08x\n", status);
486  }
487  }
488 
489  IntWinDrvSendEvent(pDriver, TRUE);
490 
491  InsertTailList(&gKernelDrivers, &pDriver->Link);
492 
493  return INT_STATUS_SUCCESS;
494 
495 _cleanup_and_leave:
496  if (!INT_SUCCESS(status) && (NULL != pDriver))
497  {
498  IntWinDrvRemoveEntry(pDriver);
499  }
500 
501  return status;
502 }
503 
504 
505 INTSTATUS
507  _In_ QWORD ModuleInfo
508  )
516 {
517  INTSTATUS status;
518  DWORD sizeOfImage;
519  QWORD moduleBase;
520  LDR_DATA_TABLE_ENTRY32 *pModuleInfo32 = NULL;
521  LDR_DATA_TABLE_ENTRY64 *pModuleInfo64 = NULL;
522  DWORD loadCount;
523 
524  if (gGuest.Guest64)
525  {
526  status = IntVirtMemMap(ModuleInfo, sizeof(*pModuleInfo64), gGuest.Mm.SystemCr3, 0, &pModuleInfo64);
527  }
528  else
529  {
530  status = IntVirtMemMap(ModuleInfo, sizeof(*pModuleInfo32), gGuest.Mm.SystemCr3, 0, &pModuleInfo32);
531  }
532  if (!INT_SUCCESS(status))
533  {
534  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx: 0x%08x\n", ModuleInfo, status);
535  return status;
536  }
537 
538  if (pModuleInfo64)
539  {
540  sizeOfImage = 0xffffffff & pModuleInfo64->SizeOfImage;
541  moduleBase = pModuleInfo64->DllBase;
542  loadCount = pModuleInfo64->LoadCount;
543  }
544  else if (pModuleInfo32)
545  {
546  sizeOfImage = pModuleInfo32->SizeOfImage;
547  moduleBase = (QWORD)pModuleInfo32->DllBase;
548  loadCount = pModuleInfo32->LoadCount;
549  }
550  else
551  {
553  }
554 
555  if (loadCount > 1)
556  {
558  goto _cleanup_and_leave;
559  }
560 
561  status = INT_STATUS_NOT_FOUND;
562 
563  list_for_each(gKernelDrivers, KERNEL_DRIVER, pDriver)
564  {
565  if (pDriver->BaseVa == moduleBase && pDriver->Size == sizeOfImage)
566  {
567  IntDriverCacheInv(pDriver->BaseVa, pDriver->Size);
568 
569  TRACE("[DRIVER] Driver 0x%016llx unloaded\n", pDriver->BaseVa);
570 
571  IntWinDrvSendEvent(pDriver, FALSE);
572 
573  RemoveEntryList(&pDriver->Link);
574 
575  status = IntWinDrvRemoveEntry(pDriver);
576  if (!INT_SUCCESS(status))
577  {
578  ERROR("[ERROR] IntWinDrvRemoveEntry failed: 0x%08x\n", status);
579  }
580 
581  status = INT_STATUS_SUCCESS;
582 
583  goto _cleanup_and_leave;
584  }
585  }
586 
587  WARNING("[WARNING] Requested unload of the driver 0x%016llx with"
588  "size 0x%08x, LDR 0x%016llx, but it wasn't found...\n",
589  moduleBase, sizeOfImage, ModuleInfo);
590 
591 _cleanup_and_leave:
592  if (pModuleInfo64)
593  {
594  IntVirtMemUnmap(&pModuleInfo64);
595  }
596  else if (pModuleInfo32)
597  {
598  IntVirtMemUnmap(&pModuleInfo32);
599  }
600 
601  return status;
602 }
603 
604 
605 INTSTATUS
607  void
608  )
614 {
616  IMAGE_DATA_DIRECTORY dataDir = { 0 };
617  DWORD eatRva;
618  DWORD eatSize;
619 
620  if (!gGuest.KernelDriver)
621  {
622  goto exit;
623  }
624 
626  {
627  goto exit;
628  }
629 
631  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
632  {
633  ERROR("[ERROR] IntPeGetDirectory failed: 0x%08x\n", status);
634  goto exit;
635  }
636 
637  eatRva = dataDir.VirtualAddress;
638  eatSize = dataDir.Size;
639 
640  if (eatRva > gGuest.KernelDriver->Size ||
641  eatSize > gGuest.KernelDriver->Size ||
642  (QWORD)eatRva + eatSize > gGuest.KernelDriver->Size)
643  {
644  ERROR("[ERROR] eatRva/eatSize are not valid eatRva:0x%08x, eatSize:0x%08x, "
645  "KernelBaseVa:0x%llx, KernelSize:0x%llx\n",
646  eatRva, eatSize, gGuest.KernelDriver->BaseVa,
648 
649  status = INT_STATUS_OUT_OF_RANGE;
650 
651  goto exit;
652  }
653 
655  0,
656  gGuest.KernelDriver->BaseVa + eatRva,
657  eatSize,
661  0,
663  if (!INT_SUCCESS(status))
664  {
665  ERROR("[ERROR] Failed hooking EAT for ntoskrnl.exe 0x%08x\n", status);
666  }
667 
668 exit:
669  return status;
670 }
671 
672 
673 INTSTATUS
675  void
676  )
682 {
684 
685  if (!gGuest.KernelDriver)
686  {
687  goto exit;
688  }
689 
691  {
692  goto exit;
693  }
694 
696  if (!INT_SUCCESS(status))
697  {
698  ERROR("[ERROR] IntHookObjectRemoveRegion failed, status: 0x%08x\n", status);
699  }
701 
702 exit:
703  return status;
704 }
705 
706 
707 static INTSTATUS
709  _In_ void *Context,
710  _In_ QWORD Cr3,
711  _In_ QWORD VirtualAddress,
712  _In_ QWORD PhysicalAddress,
713  _In_reads_bytes_(DataSize) void *Data,
714  _In_ DWORD DataSize,
715  _In_ DWORD Flags
716  )
731 {
732  INTSTATUS status;
733  KERNEL_DRIVER *pDriver;
735  DWORD i, iatSize, eatSize, iatRva, eatRva;
736  QWORD sectionBase;
737  BOOLEAN iatHooked, eatHooked;
738  IMAGE_DATA_DIRECTORY dataDir = { 0 };
739  INTRO_PE_INFO peInfo = { 0 };
740 
742  UNREFERENCED_PARAMETER(VirtualAddress);
743  UNREFERENCED_PARAMETER(PhysicalAddress);
745  UNREFERENCED_PARAMETER(Flags);
746  UNREFERENCED_PARAMETER(DataSize);
747 
748  pDriver = Context;
749 
750  pDriver->Win.HeadersSwapHandle = NULL;
751 
752  iatHooked = FALSE;
753  eatHooked = FALSE;
754 
755  TRACE("[DRIVER] Adding protection on driver '%s' at %llx...\n",
756  utf16_for_log(pDriver->Name), pDriver->BaseVa);
757 
759  if (NULL == pDriver->Win.MzPeHeaders)
760  {
762  }
763 
764  // Read the kernel headers and cache them internally for every protected driver.
765  status = IntKernVirtMemRead(pDriver->BaseVa, PAGE_SIZE, pDriver->Win.MzPeHeaders, NULL);
766  if (!INT_SUCCESS(status))
767  {
768  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
769  return status;
770  }
771 
772  status = IntPeValidateHeader(pDriver->BaseVa, pDriver->Win.MzPeHeaders, PAGE_SIZE, &peInfo, 0);
773  if (!INT_SUCCESS(status))
774  {
775  ERROR("[ERROR] IntPeValidateHeader failed: 0x%08x\n", status);
777  }
778 
779  // Get the base address of the section headers and set an EPT hook on every section that it's not writable.
780  // The idea is that this way, we will protect the code, IAT, EAT with one shot, since both the IAT & EAT are
781  // placed by the compiler inside a read-only section.
782 
783  pDriver->Win.TimeDateStamp = peInfo.TimeDateStamp;
784  pDriver->EntryPoint = pDriver->BaseVa + peInfo.EntryPoint;
785 
786  sectionBase = pDriver->BaseVa + peInfo.SectionOffset;
787 
788  status = IntPeGetDirectory(0, pDriver->Win.MzPeHeaders, IMAGE_DIRECTORY_ENTRY_IAT, &dataDir);
789  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
790  {
791  ERROR("[ERROR] IntPeGetDirectory failed: 0x%08x\n", status);
792  return status;
793  }
794 
795  iatRva = dataDir.VirtualAddress;
796  iatSize = dataDir.Size;
797 
798  status = IntPeGetDirectory(0, pDriver->Win.MzPeHeaders, IMAGE_DIRECTORY_ENTRY_EXPORT, &dataDir);
799  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
800  {
801  ERROR("[ERROR] IntPeGetDirectory failed: 0x%08x\n", status);
802  return status;
803  }
804 
805  eatRva = dataDir.VirtualAddress;
806  eatSize = dataDir.Size;
807 
808  TRACE("[DRIVER] %s @ 0x%016llx has timedate stamp 0x%08x and size 0x%08x\n",
809  utf16_for_log(pDriver->Name), pDriver->BaseVa, pDriver->Win.TimeDateStamp, (DWORD)pDriver->Size);
810 
812  if (!INT_SUCCESS(status))
813  {
814  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
815  return status;
816  }
817 
818  for (i = 0; i < peInfo.NumberOfSections; i++)
819  {
820  BOOLEAN hookSection = FALSE, ignoreAlign = FALSE;
821  QWORD secStart;
822  QWORD secEnd;
823 
824  // section offset + current section + sizeof section < PAGE_SIZE
825  if (pDriver->Win.MzPeHeaders && (peInfo.SectionOffset + i * sizeof(sec) + sizeof(sec) < PAGE_SIZE))
826  {
827  memcpy(&sec, pDriver->Win.MzPeHeaders + peInfo.SectionOffset + i * sizeof(sec), sizeof(sec));
828  }
829  else
830  {
831  status = IntKernVirtMemRead(sectionBase + i * sizeof(sec), sizeof(sec), &sec, NULL);
832  if (!INT_SUCCESS(status))
833  {
834  ERROR("[ERROR] Failed reading IMAGE_SECTION_HEADER %d for driver 0x%016llx\n", i, pDriver->BaseVa);
835  continue;
836  }
837  }
838 
839  // Skip NULL sections.
840  if (0 == sec.Misc.VirtualSize)
841  {
842  continue;
843  }
844 
845  secStart = pDriver->BaseVa + sec.VirtualAddress;
846  secEnd = secStart + ROUND_UP((QWORD)sec.Misc.VirtualSize, peInfo.SectionAlignment);
847 
848  hookSection = (!(sec.Characteristics & IMAGE_SCN_MEM_WRITE)) && // section must not be writable
849  (!(sec.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)); // section must not be discardable
850 
851  // Special ntoskrnl.exe treatment for some sections.
852  if (pDriver->BaseVa == gGuest.KernelVa)
853  {
854  // Special treatment for INITKDBG section, which is overwritten by kdcom anyway...
855  if (memcmp(sec.Name, "INITKDBG", 8) == 0)
856  {
857  TRACE("[DRIVER] Skipping section INITKDBG...\n");
858  continue;
859  }
860 
861  // Special treatment for ERRATA section (windows 10 BETA [the after the official release])
862  if (memcmp(sec.Name, "ERRATA", 6) == 0)
863  {
864  TRACE("[DRIVER] Skipping section ERRATA on build %d...\n", gGuest.OSVersion);
865  continue;
866  }
867 
868  if (memcmp(sec.Name, "ALMOSTRO", 8) == 0)
869  {
870  // Override the hookSection flag, as even if the ALMOSTRO section contains the KeServiceDescriptorTable
871  // which we want to hook.
872  if (gWinGuest->KeServiceDescriptorTable >= secStart &&
874  {
875  TRACE("[DRIVER] Overriding the hook flag, will hook ALMOSTRO section...\n");
876  hookSection = ignoreAlign = TRUE;
878  secEnd = secStart + KESDT_SIZE;
879  }
880  }
881  }
882 
883  if ((0 == iatRva) ||
884  ((hookSection) && IN_RANGE_LEN(iatRva, sec.VirtualAddress, sec.Misc.VirtualSize) &&
885  IN_RANGE_LEN(iatRva + iatSize, sec.VirtualAddress, sec.Misc.VirtualSize + 1)))
886  {
887  iatHooked = TRUE;
888  }
889 
890  if ((0 == eatRva) ||
891  ((hookSection) && IN_RANGE_LEN(eatRva, sec.VirtualAddress, sec.Misc.VirtualSize) &&
892  IN_RANGE_LEN(eatRva + eatSize, sec.VirtualAddress, sec.Misc.VirtualSize + 1)))
893  {
894  eatHooked = TRUE;
895  }
896 
897  // Now hook the section, if we can
898  if (hookSection)
899  {
900  // Handle overlapping section (Xen drivers workaround).
901  if (!ignoreAlign && ((secStart % PAGE_SIZE != 0) || (secEnd % PAGE_SIZE != 0)))
902  {
903  IMAGE_SECTION_HEADER sec2 = { 0 };
904  QWORD lastPage = (secEnd - 1) & PAGE_MASK;
905  QWORD firstPage = secStart & PAGE_MASK;
906  DWORD k;
907  BOOLEAN lowOverlap = FALSE, highOverlap = FALSE;
908 
909  WARNING("[WARNING] Section %d of driver '%s' is not aligned (%llx:%llx): alignment %x\n",
910  i, utf16_for_log(pDriver->Name), secStart, secEnd, peInfo.SectionAlignment);
911 
912  // Section is not aligned, make sure there is no other writable section that starts in the last page of
913  // this section or ends in the first page of it.
914  for (k = 0; k < peInfo.NumberOfSections; k++)
915  {
916  QWORD curSecStart = 0, curSecEnd = 0, curLastPage = 0, curFirstPage = 0;
917 
918  if (pDriver->Win.MzPeHeaders && (peInfo.SectionOffset + k * sizeof(sec) + sizeof(sec) < PAGE_SIZE))
919  {
920  memcpy(&sec2, pDriver->Win.MzPeHeaders + peInfo.SectionOffset + k * sizeof(sec2), sizeof(sec2));
921  }
922  else
923  {
924  status = IntKernVirtMemRead(sectionBase + k * sizeof(sec2),
925  sizeof(sec2),
926  &sec2,
927  NULL);
928  if (!INT_SUCCESS(status))
929  {
930  ERROR("[ERROR] Failed reading IMAGE_SECTION_HEADER %d for driver %llx\n",
931  k, pDriver->BaseVa);
932  continue;
933  }
934  }
935 
936  curSecStart = pDriver->BaseVa + sec2.VirtualAddress;
937  curSecEnd = curSecStart + ROUND_UP((QWORD)sec2.Misc.VirtualSize, peInfo.SectionAlignment);
938 
939  curLastPage = (curSecEnd - 1) & PAGE_MASK;
940  curFirstPage = curSecStart & PAGE_MASK;
941 
942  // Check if the ends of this section is inside a page where a writable section starts.
943  if ((lastPage == curFirstPage) && (0 != (sec2.Characteristics & IMAGE_SCN_MEM_WRITE)))
944  {
945  WARNING("[WARNING] Section %d overlaps writable section %d (%llx:%llx - %llx:%llx)!\n",
946  i, k, secStart, secEnd, curSecStart, curSecEnd);
947 
948  highOverlap = TRUE;
949  }
950 
951  // Check if the beginning of this section is inside a page where a writable section ends.
952  if ((firstPage == curLastPage) && (0 != (sec2.Characteristics & IMAGE_SCN_MEM_WRITE)))
953  {
954  WARNING("[WARNING] Section %d overlaps writable section %d (%llx:%llx - %llx:%llx)!\n",
955  i, k, secStart, secEnd, curSecStart, curSecEnd);
956 
957  lowOverlap = TRUE;
958  }
959  }
960 
961  if (highOverlap)
962  {
963  // Re-align the page end down to a page-size multiple.
964  secEnd &= PAGE_MASK;
965  }
966 
967  if (lowOverlap)
968  {
969  // Re-align the page start up to a page-size multiple.
970  secStart = (secStart & PAGE_MASK) + 0x1000;
971  }
972  }
973 
974  if (secStart >= secEnd)
975  {
976  WARNING("[WARNING] Section %d overlaps entirely writable sections; will not hook it.\n", i);
977  continue;
978  }
979 
980  status = IntHookObjectHookRegion(pDriver->HookObject,
981  0,
982  secStart,
983  secEnd - secStart,
986  pDriver,
987  0,
988  NULL);
989  if (!INT_SUCCESS(status))
990  {
991  ERROR("[ERROR] Failed hooking section %d for driver 0x%016llx: 0x%08x\n", i, pDriver->BaseVa, status);
992  continue;
993  }
994  }
995  }
996 
997  // Hook the IAT, if it wasn't hooked already.
998  if (!iatHooked)
999  {
1000  status = IntHookObjectHookRegion(pDriver->HookObject,
1001  0,
1002  pDriver->BaseVa + iatRva,
1003  iatSize,
1006  pDriver,
1007  0,
1008  NULL);
1009  if (!INT_SUCCESS(status))
1010  {
1011  ERROR("[ERROR] Failed hooking IAT for driver 0x%016llx: 0x%08x\n", pDriver->BaseVa, status);
1012  }
1013  }
1014 
1015  // Hook the EAT, if it wasn't hooked already.
1016  if (!eatHooked)
1017  {
1018  status = IntHookObjectHookRegion(pDriver->HookObject,
1019  0,
1020  pDriver->BaseVa + eatRva,
1021  eatSize,
1024  pDriver,
1025  0,
1026  NULL);
1027  if (!INT_SUCCESS(status))
1028  {
1029  ERROR("[ERROR] Failed hooking IAT for driver 0x%016llx: 0x%08x\n", pDriver->BaseVa, status);
1030  }
1031 
1032 
1033  }
1034 
1036  {
1037  if (pDriver->BaseVa == gGuest.KernelVa && gWinGuest)
1038  {
1039  gGuest.KernelDriver = pDriver;
1040  status = IntWinProtectReadNtEat();
1041  if (!INT_SUCCESS(status))
1042  {
1043  ERROR("[ERROR] Failed hooking EAT for ntoskrnl.exe, failed: 0x%08x\n", status);
1044  }
1045  }
1046  }
1047 
1048  pDriver->Protected = TRUE;
1049 
1050  return status;
1051 }
1052 
1053 
1054 INTSTATUS
1056  _In_ KERNEL_DRIVER *Driver,
1057  _In_ QWORD ProtectionFlag
1058  )
1069 {
1070  if (NULL == Driver)
1071  {
1073  }
1074 
1075  if (Driver->Protected)
1076  {
1078  }
1079 
1080  Driver->Protected = TRUE;
1081  Driver->ProtectionFlag = ProtectionFlag;
1082 
1083  return IntSwapMemReadData(0, Driver->BaseVa, PAGE_SIZE, SWAPMEM_OPT_NO_FAULT, Driver, 0,
1084  IntWinDrvHeadersInMemory, NULL, &Driver->Win.HeadersSwapHandle);
1085 }
1086 
1087 
1088 INTSTATUS
1090  _In_ KERNEL_DRIVER *Driver
1091  )
1100 {
1101  if (NULL == Driver)
1102  {
1104  }
1105 
1106  if (!Driver->Protected)
1107  {
1109  }
1110 
1111  TRACE("[DRIVER] Removing protection on module '%s' at %llx...\n",
1112  utf16_for_log(Driver->Name), Driver->BaseVa);
1113 
1114  if (NULL != Driver->Win.MzPeHeaders)
1115  {
1116  HpFreeAndNullWithTag(&Driver->Win.MzPeHeaders, IC_TAG_HDRS);
1117  }
1118 
1119  if (NULL != Driver->HookObject)
1120  {
1121  IntHookObjectDestroy((HOOK_OBJECT_DESCRIPTOR **)&Driver->HookObject, 0);
1122  }
1123 
1124  if (NULL != Driver->Win.HeadersSwapHandle)
1125  {
1126  IntSwapMemRemoveTransaction(Driver->Win.HeadersSwapHandle);
1127 
1128  Driver->Win.HeadersSwapHandle = NULL;
1129  }
1130 
1131  Driver->Protected = FALSE;
1132 
1133  return INT_STATUS_SUCCESS;
1134 }
1135 
1136 
1137 INTSTATUS
1139  _In_opt_ void *Context,
1140  _In_ void *Hook,
1141  _In_ QWORD Address,
1142  _Out_ INTRO_ACTION *Action
1143  )
1158 {
1159  INTSTATUS status;
1160  KERNEL_DRIVER *pDriver;
1161  PWIN_DRIVER_OBJECT pDrvObj;
1162  IG_ARCH_REGS *pRegs;
1163  QWORD guestAddress;
1164 
1165  UNREFERENCED_PARAMETER(Address);
1166 
1167  if (NULL == Context)
1168  {
1170  }
1171 
1172  if (NULL == Action)
1173  {
1175  }
1176 
1177  if (NULL == Hook)
1178  {
1180  }
1181 
1182  guestAddress = 0;
1183  pDrvObj = NULL;
1184  pDriver = Context;
1185 
1186  pRegs = &gVcpu->Regs;
1187 
1188  if (pRegs->Rip != pDriver->EntryPoint)
1189  {
1190  *Action = introGuestAllowed;
1191  return INT_STATUS_SUCCESS;
1192  }
1193 
1194  if (gGuest.Guest64)
1195  {
1196  guestAddress = pRegs->Rcx;
1197  }
1198  else
1199  {
1200  status = IntKernVirtMemFetchDword(pRegs->Rsp + 4, (DWORD *)&guestAddress);
1201  if (!INT_SUCCESS(status))
1202  {
1203  ERROR("[ERROR] IntKernVirtMemPatchDword failed: 0x%08x\n", status);
1204  }
1205  }
1206 
1207  if (IntWinDrvObjIsValidDriverObject(guestAddress))
1208  {
1209  status = IntWinDrvObjCreateFromAddress(guestAddress, FALSE, &pDrvObj);
1210  if (!INT_SUCCESS(status))
1211  {
1212  ERROR("[ERROR] IntWinDrvObjCreateDriverObject failed: 0x%08x\n", status);
1213  pDrvObj = NULL;
1214  }
1215 
1216  pDriver->Win.DriverObject = pDrvObj;
1217  }
1218 
1219  if (NULL != pDriver->Win.EpHookObject)
1220  {
1221  status = IntHookObjectDestroy((HOOK_OBJECT_DESCRIPTOR **)&pDriver->Win.EpHookObject, 0);
1222  if (!INT_SUCCESS(status))
1223  {
1224  ERROR("[ERROR] IntHookObjectDestroy failed: 0x%08x\n", status);
1225  }
1226  }
1227 
1228  // we will allow the action, and we don't want notifications to be sent to LINUX/Winguest.
1229  *Action = introGuestRetry;
1230 
1231  return INT_STATUS_SUCCESS;
1232 }
1233 
1234 
1235 static INTSTATUS
1237  _In_ KERNEL_DRIVER *Driver,
1238  _In_ EXCEPTION_VICTIM_ZONE *Victim,
1239  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
1240  _In_ INTRO_ACTION Action,
1241  _In_ INTRO_ACTION_REASON Reason
1242  )
1254 {
1255  INTSTATUS status;
1256  PEVENT_EPT_VIOLATION pEptViol;
1257  PIG_ARCH_REGS regs;
1258 
1259  regs = &gVcpu->Regs;
1260 
1261  pEptViol = &gAlert.Ept;
1262  memzero(pEptViol, sizeof(*pEptViol));
1263 
1264  pEptViol->Header.Action = Action;
1265  pEptViol->Header.Reason = Reason;
1266 
1267  if (!!(Victim->ZoneFlags & ZONE_READ))
1268  {
1269  pEptViol->Header.MitreID = idExploitRemote;
1270  }
1271  else
1272  {
1273  pEptViol->Header.MitreID = idRootkit;
1274  }
1275 
1277 
1278  IntAlertEptFillFromKmOriginator(Originator, pEptViol);
1279  IntAlertEptFillFromVictimZone(Victim, pEptViol);
1280 
1281  pEptViol->Header.Flags = IntAlertCoreGetFlags(Driver->ProtectionFlag, Reason);
1282 
1284 
1285  IntAlertFillCodeBlocks(Originator->Original.Rip, regs->Cr3, FALSE, &pEptViol->CodeBlocks);
1286  IntAlertFillExecContext(0, &pEptViol->ExecContext);
1287 
1288  IntAlertFillVersionInfo(&pEptViol->Header);
1289 
1290  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
1291  if (!INT_SUCCESS(status))
1292  {
1293  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
1294  }
1295 
1296  return INT_STATUS_SUCCESS;
1297 }
1298 
1299 
1300 INTSTATUS
1302  _In_ void *Context,
1303  _In_ void *Hook,
1304  _In_ QWORD Address,
1305  _Out_ INTRO_ACTION *Action
1306  )
1317 {
1318  EXCEPTION_VICTIM_ZONE victim;
1319  EXCEPTION_KM_ORIGINATOR originator;
1320  INTSTATUS status;
1321  INTRO_ACTION_REASON reason;
1322  BOOLEAN exitAfterInformation;
1323  KERNEL_DRIVER *pDriver;
1324 
1325  if (NULL == Context)
1326  {
1328  }
1329 
1330  if (NULL == Action)
1331  {
1333  }
1334 
1335  UNREFERENCED_PARAMETER(Hook);
1336 
1338 
1339  memzero(&victim, sizeof(victim));
1340  memzero(&originator, sizeof(originator));
1341 
1342  // By default we do not allow this
1343  *Action = introGuestNotAllowed;
1344  reason = introReasonUnknown;
1345  exitAfterInformation = FALSE;
1346  pDriver = Context;
1347 
1348  status = IntExceptKernelGetOriginator(&originator, 0);
1349  if (status == INT_STATUS_EXCEPTION_BLOCK)
1350  {
1351  reason = introReasonNoException;
1352  exitAfterInformation = TRUE;
1353  }
1354  else if (!INT_SUCCESS(status))
1355  {
1356  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
1357  reason = introReasonInternalError;
1358  exitAfterInformation = TRUE;
1359  }
1360 
1361  status = IntExceptGetVictimEpt(pDriver,
1362  Address,
1363  IntHookGetGlaFromGpaHook(Hook, Address),
1365  ZONE_WRITE,
1366  &victim);
1367  if (!INT_SUCCESS(status))
1368  {
1369  reason = introReasonInternalError;
1370  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
1371  exitAfterInformation = TRUE;
1372  }
1373 
1374  if (exitAfterInformation)
1375  {
1376  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
1377  }
1378  else
1379  {
1380  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
1381  }
1382 
1384 
1385  if (IntPolicyCoreTakeAction(pDriver->ProtectionFlag, Action, &reason))
1386  {
1387  IntWinDrvSendAlert(pDriver, &victim, &originator, *Action, reason);
1388  }
1389 
1391 
1392  return status;
1393 }
1394 
1395 
1396 static KERNEL_DRIVER *
1398  _In_ QWORD Rip
1399  )
1408 {
1409  list_for_each(gKernelDrivers, KERNEL_DRIVER, pDriver)
1410  {
1411  if (Rip >= pDriver->BaseVa && Rip < pDriver->BaseVa + pDriver->Size)
1412  {
1413  return pDriver;
1414  }
1415  }
1416 
1417  return NULL;
1418 }
1419 
1420 
1421 static INTSTATUS
1423  _In_ KERNEL_DRIVER *CurrentOriginator
1424  )
1439 {
1440  INTSTATUS status;
1441 
1442  if (!CurrentOriginator)
1443  {
1445  }
1446 
1447  if (!gGuest.KernelDriver)
1448  {
1450  }
1451 
1452  ERROR("[ERROR] We have reached %llu reads from ntoskrnl.exe EAT, last driver %s, disabling protection\n",
1453  gGuest.KernelDriver->Win.EatReadCount, utf16_for_log(CurrentOriginator->Name));
1454 
1455  status = IntWinUnprotectReadNtEat();
1456  if (!INT_SUCCESS(status))
1457  {
1458  ERROR("[ERROR] IntWinUnprotectReadNtEat failed: 0x%08x\n", status);
1459  }
1460 
1463 
1464  return INT_STATUS_SUCCESS;
1465 }
1466 
1467 
1468 INTSTATUS
1470  _In_ void *Context,
1471  _In_ void *Hook,
1472  _In_ QWORD Address,
1473  _Out_ INTRO_ACTION *Action
1474  )
1486 {
1487  EXCEPTION_VICTIM_ZONE victim;
1488  EXCEPTION_KM_ORIGINATOR originator;
1489  INTSTATUS status;
1490  INTRO_ACTION_REASON reason;
1491  KERNEL_DRIVER *pDriver;
1492  KERNEL_DRIVER *pOriginatingDriver;
1493  BOOLEAN exitAfterInformation;
1494  QWORD ripPage;
1495 
1496 #define NTOSKRNL_RIP_PAGES_COUNT 20
1497 #define PATCHGUARD_RIP_COUNT 4
1498 #define MAX_KNOWN_DRIVER_READS 100000
1499 
1500  static QWORD ntoskrnlRipPages[NTOSKRNL_RIP_PAGES_COUNT] = { 0 };
1501  static DWORD ntoskrnlRipPagesCount = 0;
1502 
1503  static QWORD patchguardRip[PATCHGUARD_RIP_COUNT] = { 0 };
1504  static DWORD patchguardRipCount = 0;
1505 
1506  if (NULL == Context)
1507  {
1509  }
1510 
1511  if (NULL == Action)
1512  {
1514  }
1515 
1516  // By default we allow this
1517  *Action = introGuestAllowed;
1518  reason = introReasonAllowed;
1519  pDriver = Context;
1520  status = INT_STATUS_SUCCESS;
1521  exitAfterInformation = FALSE;
1522 
1524 
1525  // The ntoskrnl.exe also reads its own EAT - multiple RIPs that are contained within a few pages.
1526  // In order to increase the performance, we are going to save the pages (one by one when the
1527  // originator.Return.Driver is ntoskrnl.exe) and compare the current RIP page value with stored values.
1528  ripPage = gVcpu->Regs.Rip & PAGE_MASK;
1529  for (DWORD i = 0; i < ntoskrnlRipPagesCount; i++)
1530  {
1531  if (ntoskrnlRipPages[i] == ripPage)
1532  {
1533  goto exit;
1534  }
1535  }
1536 
1537  // The PatchGuard usually reads the EAT multiple times from a few RIPs (none of which are inside any known module).
1538  // In order to increase the performance, we are going to save the RIPs (one by one when the
1539  // originator.Original.Driver is NULL and we match the exceptions) and compare the current RIP value with
1540  // stored values.
1541  for (DWORD i = 0; i < patchguardRipCount; i++)
1542  {
1543  if (patchguardRip[i] == gVcpu->Regs.Rip)
1544  {
1545  goto exit;
1546  }
1547  }
1548 
1549  // If the read originates from within one of our own agents - allow.
1551  {
1552  goto exit;
1553  }
1554 
1555  // If the read originates from within a known driver - allow.
1556  pOriginatingDriver = IntWinGetDriverByGva(gVcpu->Regs.Rip);
1557  if (pOriginatingDriver)
1558  {
1559  if (pOriginatingDriver->BaseVa == gGuest.KernelVa)
1560  {
1561  TRACE("[DRIVER] Saving ntoskrnl.exe page:0x%llx\n", gVcpu->Regs.Rip & PAGE_MASK);
1562  ntoskrnlRipPages[(ntoskrnlRipPagesCount++) % NTOSKRNL_RIP_PAGES_COUNT] = gVcpu->Regs.Rip & PAGE_MASK;
1563  }
1564  else
1565  {
1567 
1569  {
1570  status = IntWinDrvForceDisableReadNtEat(pOriginatingDriver);
1571  if (!INT_SUCCESS(status))
1572  {
1573  ERROR("[ERROR] IntWinDrvDisableReadNtEat failed: 0x%08x\n", status);
1574  }
1575  }
1576  }
1577 
1578  goto exit;
1579  }
1580 
1581  memzero(&victim, sizeof(victim));
1582  memzero(&originator, sizeof(originator));
1583 
1584  status = IntExceptKernelGetOriginator(&originator, 0);
1585  if (status == INT_STATUS_EXCEPTION_BLOCK)
1586  {
1587  reason = introReasonNoException;
1588  exitAfterInformation = TRUE;
1589  }
1590  else if (!INT_SUCCESS(status))
1591  {
1592  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
1593  reason = introReasonInternalError;
1594  exitAfterInformation = TRUE;
1595  }
1596 
1597  status = IntExceptGetVictimEpt(pDriver,
1598  Address,
1599  IntHookGetGlaFromGpaHook(Hook, Address),
1601  ZONE_READ,
1602  &victim);
1603  if (!INT_SUCCESS(status))
1604  {
1605  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
1606  reason = introReasonInternalError;
1607  exitAfterInformation = TRUE;
1608  }
1609 
1610  if (exitAfterInformation)
1611  {
1612  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
1613  }
1614  else
1615  {
1616  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
1617  }
1618 
1619  // This is the probably PatchGuard. We are going to store its RIP.
1620  if (introGuestAllowed == *Action)
1621  {
1622  TRACE("[DRIVER] Saving PatchGuard RIP:0x%llx\n", gVcpu->Regs.Rip);
1623  patchguardRip[(patchguardRipCount++) % PATCHGUARD_RIP_COUNT] = gVcpu->Regs.Rip;
1624  }
1625 
1626  if (IntPolicyCoreTakeAction(pDriver->ProtectionFlag, Action, &reason))
1627  {
1628  IntWinDrvSendAlert(pDriver, &victim, &originator, *Action, reason);
1629  }
1630 
1632 
1633 exit:
1635 
1636 #undef NTOSKRNL_RIP_PAGES_COUNT
1637 #undef PATCHGUARD_RIP_COUNT
1638 #undef MAX_KNOWN_DRIVER_READS
1639 
1640  return status;
1641 }
1642 
1643 
1644 static INTSTATUS
1646  _In_ KERNEL_DRIVER *Driver,
1647  _In_ QWORD Reserved
1648  )
1657 {
1658  UNREFERENCED_PARAMETER(Reserved);
1659 
1660  if (NULL != Driver->Win.Path)
1661  {
1662  HpFreeAndNullWithTag(&Driver->Win.Path, IC_TAG_DRNU);
1663  }
1664 
1665  if (NULL != Driver->Name)
1666  {
1667  HpFreeAndNullWithTag(&Driver->Name, IC_TAG_DRNU);
1668  }
1669 
1670  if (NULL != Driver->Win.MzPeHeaders)
1671  {
1672  HpFreeAndNullWithTag(&Driver->Win.MzPeHeaders, IC_TAG_HDRS);
1673  }
1674 
1676 
1677  return INT_STATUS_SUCCESS;
1678 }
1679 
1680 
1681 INTSTATUS
1683  _In_ KERNEL_DRIVER *Driver
1684  )
1692 {
1693  INTSTATUS status;
1694 
1695  if (NULL == Driver)
1696  {
1698  }
1699 
1700  status = IntWinDrvUnprotect(Driver);
1701  if (!INT_SUCCESS(status))
1702  {
1703  ERROR("[ERROR] IntWinModuleUnHook failed: 0x%08x\n", status);
1704  }
1705 
1706  if (NULL != Driver->Win.EpHookObject)
1707  {
1708  IntHookObjectDestroy((HOOK_OBJECT_DESCRIPTOR **)&Driver->Win.EpHookObject, 0);
1709  }
1710 
1711  if (NULL != Driver->Win.DriverObject)
1712  {
1713  PWIN_DRIVER_OBJECT pDrvObj = Driver->Win.DriverObject;
1714 
1715  RemoveEntryList(&pDrvObj->Link);
1716 
1717  status = IntWinDrvObjRemove(pDrvObj);
1718  if (!INT_SUCCESS(status))
1719  {
1720  ERROR("[ERROR] IntWinDrvObjRemoveDriverObject failed: 0x%08x\n", status);
1721  }
1722 
1723  Driver->Win.DriverObject = NULL;
1724  }
1725 
1726  status = IntWinDrvFreeEntry(Driver, 0);
1727  if (!INT_SUCCESS(status))
1728  {
1729  ERROR("[ERROR] IntWinDrvFreeEntry failed: 0x%08x\n", status);
1730  }
1731 
1732  return status;
1733 }
1734 
1735 
1736 INTSTATUS
1738  void
1739  )
1745 {
1746  TRACE("[DRIVER] Updating kernel drivers protections...\n");
1747 
1748  list_for_each(gKernelDrivers, KERNEL_DRIVER, pDriver)
1749  {
1750  INTSTATUS status;
1751 
1752  const PROTECTED_MODULE_INFO *pProtInfo = IntWinDrvIsProtected(pDriver);
1753 
1754  if (!pDriver->Protected && (NULL != pProtInfo))
1755  {
1756  status = IntWinDrvProtect(pDriver, pProtInfo->RequiredFlags);
1757  if (!INT_SUCCESS(status))
1758  {
1759  ERROR("[ERROR] IntWinDrvProtect failed for '%s': 0x%08x\n",
1760  utf16_for_log(pDriver->Name), status);
1761  }
1762  }
1763  else if (pDriver->Protected && (NULL == pProtInfo))
1764  {
1765  status = IntWinDrvUnprotect(pDriver);
1766  if (!INT_SUCCESS(status))
1767  {
1768  ERROR("[ERROR] IntWinDrvUnprotect failed for '%s': 0x%08x\n",
1769  utf16_for_log(pDriver->Name), status);
1770  }
1771  }
1772  }
1773 
1774  return INT_STATUS_SUCCESS;
1775 }
Measures kernel mode exceptions checks.
Definition: stats.h:51
#define SWAPMEM_OPT_NO_FAULT
If set, no PF will be injected. Introcore will wait for the pages to be naturally swapped in...
Definition: swapmem.h:19
#define _In_opt_
Definition: intro_sal.h:16
LIST_ENTRY Link
Entry inside the gWinDriverObjects list.
Definition: windrvobj.h:16
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
INTSTATUS IntWinDrvRemoveEntry(KERNEL_DRIVER *Driver)
Removes the KERNEL_DRIVER from the internal structures.
Definition: windriver.c:1682
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
#define ROUND_UP(what, to)
Definition: introdefs.h:158
INTSTATUS IntWinDrvIterateLoadedModules(PFUNC_IterateListCallback Callback, QWORD Aux)
Used to iterate trough the WINDOWS_GUEST::PsLoadedModuleList.
Definition: windriver.c:211
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
QWORD IntAlertCoreGetFlags(QWORD ProtectionFlag, INTRO_ACTION_REASON Reason)
Returns the flags for an alert.
Definition: alerts.c:366
An internal error occurred (no memory, pages not present, etc.).
Definition: intro_types.h:195
BOOLEAN IntPolicyCoreForceBetaIfNeeded(QWORD Flag, INTRO_ACTION *Action)
Checks if a forced action should be taken even if the log-only mode is active.
Definition: introcore.c:2803
Kernel module (ntoskrnl.exe, hal.dll, etc.)
Definition: intro_types.h:235
Read-access hook.
Definition: glueiface.h:298
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
Definition: winguest.c:35
INTSTATUS IntHookObjectDestroy(HOOK_OBJECT_DESCRIPTOR **Object, DWORD Flags)
Destroy an entire hook object. All regions belonging to this object will be removed.
Definition: hook_object.c:357
QWORD EatReadCount
The number of EAT reads that took place from withing known drivers.
Definition: windriver.h:43
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
QWORD RequiredFlags
The introcore options that need to be active in order to protect this module.
Definition: winguest.h:137
#define _In_
Definition: intro_sal.h:21
INTSTATUS IntPeGetDirectory(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD DirectoryEntry, IMAGE_DATA_DIRECTORY *Directory)
Validate & return the indicated image data directory.
Definition: winpe.c:527
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1088
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:207
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
#define INT_STATUS_OUT_OF_RANGE
Definition: introstatus.h:275
BOOLEAN IntPolicyCoreTakeAction(QWORD Flag, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Returns the action that should be taken for a core introspection option.
Definition: introcore.c:2693
LIST_ENTRY64 InLoadOrderLinks
Definition: wddefs.h:203
#define PAGE_REMAINING(addr)
Definition: pgtable.h:163
WIN_KERNEL_DRIVER Win
Valid only for Windows guests.
Definition: drivers.h:70
#define STATS_EXIT(id)
Definition: stats.h:148
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
INTSTATUS IntWinUnprotectReadNtEat(void)
Used to remove the EAT read hook from ntoskrnl.exe.
Definition: windriver.c:674
#define IC_TAG_MODU
Loaded module.
Definition: memtags.h:15
QWORD BaseVa
The guest virtual address of the kernel module that owns this driver object.
Definition: drivers.h:41
static KERNEL_DRIVER * IntWinGetDriverByGva(QWORD Rip)
Iterates all the loaded drivers to see if the Rip points inside any of them.
Definition: windriver.c:1397
#define IMAGE_SCN_MEM_WRITE
Definition: winpe.h:474
UINT32 VirtualAddress
Definition: winpe.h:98
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
DWORD TimeDateStamp
Time/date stamp.
Definition: winpe.h:600
Event structure for module loading and unloading.
Definition: intro_types.h:1782
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1087
QWORD SectionOffset
Offset of the first section header.
Definition: winpe.h:602
Exposes the types, constants and functions used to describe protected Windows Kernel modules and driv...
#define PAGE_OFFSET
Definition: pgtable.h:32
The action was not allowed because there was no reason to allow it.
Definition: intro_types.h:183
INTSTATUS IntWinDrvObjCreateFromAddress(QWORD GuestAddress, BOOLEAN StaticDetected, PWIN_DRIVER_OBJECT *DriverObject)
Creates a new driver object.
Definition: windrvobj.c:227
Measures reads done from the kernel EAT.
Definition: stats.h:93
DWORD PathLength
The driver`s path length (number of WCHARS).
Definition: windriver.h:26
EVENT_MODULE_EVENT Module
Definition: alerts.h:26
QWORD IntHookGetGlaFromGpaHook(HOOK_GPA const *Hook, QWORD Address)
Gets the GLA from a GPA hook.
Definition: hook.c:279
PBYTE MzPeHeaders
The driver`s MZ/PE headers (cached internally).
Definition: windriver.h:34
Models a LIST_ENTRY structure used by 32-bit Windows guests.
Definition: wddefs.h:153
INTSTATUS IntWinDrvIsListHead(QWORD PsLoadedModuleListGva, void *PsLoadedModuleList, QWORD KernelLdr)
Used to identify WINDOWS_GUEST::PsLoadedModuleList.
Definition: windriver.c:67
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
LIST_ENTRY32 InLoadOrderLinks
Definition: wddefs.h:174
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
DWORD Buffer
The guest virtual address at which the wide-character string is located.
Definition: wddefs.h:129
INTSTATUS IntWinDrvCreateFromAddress(QWORD ModuleInfo, QWORD Flags)
Adds a driver to introspection&#39;s LoadedModuleList (gKernelDrivers). This way we avoid lots of mapping...
Definition: windriver.c:289
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD Size
The size of the kernel module that owns this driver object.
Definition: drivers.h:43
BOOLEAN Protected
True if the driver is protected, False if it is not.
Definition: drivers.h:65
DWORD OSVersion
Os version.
Definition: guests.h:277
BOOLEAN IntWinDrvHasDriverObject(const KERNEL_DRIVER *Driver)
Check wether a kernel driver has a driver object that we care to protect.
void * HeadersSwapHandle
The swap handle used to read the driver`s headers.
Definition: windriver.h:38
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
UNICODE_STRING32 DriverPath
Definition: wddefs.h:180
Rootkit.
Definition: intro_types.h:1033
Describes a kernel-mode originator.
Definition: exceptions.h:897
DWORD SectionAlignment
Sections alignment.
Definition: winpe.h:604
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
Definition: alerts.c:492
DWORD Flink
Definition: wddefs.h:155
EVENT_EPT_VIOLATION Ept
Definition: alerts.h:16
INTSTATUS IntWinDrvRemoveFromAddress(QWORD ModuleInfo)
Removes a driver from the introspection&#39;s loaded modules list (gKernelDrivers).
Definition: windriver.c:506
DWORD TimeDateStamp
The driver`s internal timestamp (from the _IMAGE_FILE_HEADER).
Definition: windriver.h:23
Describes a kernel driver.
Definition: drivers.h:30
#define INT_STATUS_BREAK_ITERATION
Can be used by iteration callbacks to break the iteration early.
Definition: introstatus.h:374
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
Models a LIST_ENTRY structure used by 64-bit Windows guests.
Definition: wddefs.h:162
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1106
DWORD NameHash
The hash of the name.
Definition: drivers.h:59
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1084
INTSTATUS IntAlertFillCodeBlocks(QWORD Rip, QWORD Cr3, BOOLEAN Execute, INTRO_CODEBLOCKS *CodeBlocks)
Fills the code blocks pattern for an alert.
Definition: alerts.c:71
static INTSTATUS IntWinDrvHeadersInMemory(void *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)
This callback is called as soon as all the driver headers have been read using IntSwapMemReadData.
Definition: windriver.c:708
The _LDR_DATA_TABLE_ENTRY structure used by 64-bit guests.
Definition: wddefs.h:201
#define NTOSKRNL_RIP_PAGES_COUNT
void IntAlertEptFillFromKmOriginator(const EXCEPTION_KM_ORIGINATOR *Originator, EVENT_EPT_VIOLATION *EptViolation)
Fills kernel mode originator information inside an EPT alert.
Definition: alerts.c:832
DWORD Blink
Definition: wddefs.h:155
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
INTSTATUS IntSwapMemRemoveTransaction(void *Transaction)
Remove a transaction.
Definition: swapmem.c:942
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
Definition: introcore.c:829
#define INITIAL_CRC_VALUE
Definition: introdefs.h:221
#define INT_STATUS_EXCEPTION_BLOCK
Definition: introstatus.h:421
void IntAlertEptFillFromVictimZone(const EXCEPTION_VICTIM_ZONE *Victim, EVENT_EPT_VIOLATION *EptViolation)
Fills the victim information inside an EPT alert.
Definition: alerts.c:868
QWORD PsLoadedModuleList
Guest virtual address of the PsLoadedModuleList kernel variable.
Definition: winguest.h:822
#define INT_STATUS_NOT_INITIALIZED
Definition: introstatus.h:266
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
Definition: introcore.c:811
SIZE_T NameLength
The length of the Name. This is the number of characters in the Name buffer.
Definition: drivers.h:56
#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
INTSTATUS IntWinDrvObjRemove(WIN_DRIVER_OBJECT *DriverObject)
Removes a driver object and updates its owner module.
Definition: windrvobj.c:1289
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Definition: glue.c:1042
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
Holds information about a driver object.
Definition: windrvobj.h:13
QWORD Flink
Definition: wddefs.h:164
#define memzero(a, s)
Definition: introcrt.h:35
INTSTATUS IntWinDrvHandleDriverEntry(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Used to notify the introspection engine when the DriverEntry of a module starts executing.
Definition: windriver.c:1138
UINT16 Length
The length, in bytes, of the string in Buffer, not including the NULL terminator, if any...
Definition: wddefs.h:123
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
Definition: guests.h:286
INTSTATUS IntWinDrvHandleWrite(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Used to notify the introspection engine when a write took place on a protected driver.
Definition: windriver.c:1301
INTSTATUS IntExceptGetVictimEpt(void *Context, QWORD Gpa, QWORD Gva, INTRO_OBJECT_TYPE Type, DWORD ZoneFlags, EXCEPTION_VICTIM_ZONE *Victim)
Fills an EXCEPTION_VICTIM_ZONE with relevant information from an EPT violation.
Definition: exceptions.c:742
unsigned long long QWORD
Definition: intro_types.h:53
QWORD Current
The currently used options.
Definition: guests.h:232
union _IMAGE_SECTION_HEADER::@209 Misc
int strlower_utf16(WCHAR *buf, size_t len)
Definition: introcrt.c:28
#define IN_RANGE_LEN(x, start, len)
Definition: introdefs.h:175
#define TRUE
Definition: intro_types.h:30
INTSTATUS(* PFUNC_IterateListCallback)(QWORD Node, QWORD Aux)
Definition: introtypes.h:71
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
UINT32 VirtualAddress
Definition: winpe.h:85
#define IS_KERNEL_POINTER_WIN(is64, p)
Checks if a guest virtual address resides inside the Windows kernel address space.
Definition: wddefs.h:76
QWORD NumberOfSections
Number of sections.
Definition: winpe.h:603
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
#define TRACE(fmt,...)
Definition: glue.h:58
#define INT_STATUS_INVALID_INTERNAL_STATE
Definition: introstatus.h:272
#define INTRO_OPT_EVENT_MODULES
Enable user mode and kernel mode module load and unload events (generates introEventModuleEvent event...
Definition: intro_types.h:429
void * Name
The name of the driver.
Definition: drivers.h:54
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:279
The _LDR_DATA_TABLE_ENTRY structure used by 32-bit guests.
Definition: wddefs.h:172
void IntExceptKernelLogInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-mode violation and dumps the code-blocks.
Kernel-mode exception.
Definition: exceptions.h:62
void IntAlertFillWinProcessCurrent(INTRO_PROCESS *EventProcess)
Saves information about the current Windows process inside an alert.
Definition: alerts.c:781
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
Definition: intro_types.h:1191
BOOLEAN Loaded
True if the module was loaded, False if it was unloaded.
Definition: intro_types.h:1785
INTSTATUS IntWinDrvUnprotect(KERNEL_DRIVER *Driver)
Used to disable protection for the given driver.
Definition: windriver.c:1089
#define INT_STATUS_ALREADY_INITIALIZED_HINT
Definition: introstatus.h:323
#define MAX_KNOWN_DRIVER_READS
#define WARNING(fmt,...)
Definition: glue.h:60
void * HookObject
The hook object used to protect this driver. NULL if the driver is not protected. ...
Definition: drivers.h:62
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
Definition: intro_types.h:84
PWCHAR Path
The driver`s path.
Definition: windriver.h:28
#define INTRO_OPT_PROT_KM_NT_EAT_READS
Enable kernel EAT read protection (Windows only).
Definition: intro_types.h:481
#define PAGE_SIZE
Definition: common.h:53
DWORD Crc32Wstring(const WCHAR *String, DWORD InitialCrc)
Computes the CRC for a NULL-terminated wide char string.
Definition: crc32.c:226
Describes the modified zone.
Definition: exceptions.h:847
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
INTSTATUS IntHookObjectRemoveRegion(HOOK_REGION_DESCRIPTOR **Region, DWORD Flags)
Remove a hooked region of memory.
Definition: hook_object.c:309
#define KESDT_SIZE
The size of the KeServiceDescriptorTable.
Definition: wddefs.h:42
#define IMAGE_DIRECTORY_ENTRY_EXPORT
Definition: winpe.h:20
void * EatReadHook
The read hook placed on the driver`s EAT.
Definition: windriver.h:40
uint32_t DWORD
Definition: intro_types.h:49
UINT32 VirtualSize
Definition: winpe.h:83
QWORD ProtectionFlag
The introcore option that decided that this driver must be protected.
Definition: drivers.h:49
UINT32 Characteristics
Definition: winpe.h:92
DWORD EntryPoint
Entry point (RVA).
Definition: winpe.h:601
INTRO_PROCESS CurrentProcess
The currently active process.
Definition: intro_types.h:1794
INTSTATUS IntPeValidateHeader(QWORD ImageBase, BYTE *ImageBaseBuffer, DWORD ImageBaseBufferSize, INTRO_PE_INFO *PeInfo, QWORD Cr3)
Validates a PE header.
Definition: winpe.c:131
enum _INTRO_ACTION INTRO_ACTION
Event actions.
#define _In_reads_bytes_(expr)
Definition: intro_sal.h:25
LIST_HEAD gKernelDrivers
List of all the drivers currently loaded inside the guest.
Definition: drivers.c:11
LIST_ENTRY Link
Entry inside the gKernelDrivers list.
Definition: drivers.h:33
#define INT_STATUS_INVALID_OBJECT_TYPE
Definition: introstatus.h:145
INTRO_MODULE Module
The module for which this event was triggered.
Definition: intro_types.h:1797
INTSTATUS IntWinDrvHandleRead(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Used to notify the introspection engine when a read took place on a protected driver (used only for n...
Definition: windriver.c:1469
__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
UNICODE_STRING64 DriverPath
Definition: wddefs.h:209
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:370
UNICODE_STRING32 DriverName
Definition: wddefs.h:181
QWORD KeServiceDescriptorTable
Guest virtual address of the KeServiceDescriptorTable variable.
Definition: winguest.h:803
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:48
static INTSTATUS IntWinDrvFreeEntry(KERNEL_DRIVER *Driver, QWORD Reserved)
Frees the memory allocate for the KERNEL_DRIVER structure.
Definition: windriver.c:1645
void IntAlertFillWinProcessByCr3(QWORD ProcessCr3, INTRO_PROCESS *EventProcess)
Saves information about a Windows process inside an alert. The process is searched by its kernel CR3...
Definition: alerts.c:756
QWORD Blink
Definition: wddefs.h:164
#define IMAGE_DIRECTORY_ENTRY_IAT
Definition: winpe.h:33
#define IMAGE_SCN_MEM_DISCARDABLE
Definition: winpe.h:468
BOOLEAN IntWinDrvObjIsValidDriverObject(QWORD DriverObjectAddress)
Checks if a guest memory area contains a valid _DRIVER_OBJECT structure.
Definition: windrvobj.c:28
Encapsulates a protected Windows kernel module.
Definition: winguest.h:124
BOOLEAN IntWinAgentIsRipInsideCurrentAgent(QWORD Rip)
Return true if the given RIP points inside the currently active boot driver.
Definition: winagent.c:197
void * EpHookObject
The EP hook placed on the driver (we will be notified when the execution began) - useful to obtain th...
Definition: windriver.h:32
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 ZONE_READ
Used for read violation.
Definition: exceptions.h:699
UNICODE_STRING64 DriverName
Definition: wddefs.h:210
static void IntWinDrvSendEvent(KERNEL_DRIVER *Driver, BOOLEAN Loaded)
Send a driver loaded/unloaded event.
Definition: windriver.c:30
INTSTATUS IntHookObjectHookRegion(void *Object, QWORD Cr3, QWORD Gla, SIZE_T Length, BYTE Type, void *Callback, void *Context, DWORD Flags, HOOK_REGION_DESCRIPTOR **Region)
Hook a contiguous region of virtual memory inside the provided virtual address space.
Definition: hook_object.c:132
WORD Length
The length, in bytes, of the string in Buffer, not including the NULL terminator, if any...
Definition: wddefs.h:139
static INTSTATUS IntWinDrvForceDisableReadNtEat(KERNEL_DRIVER *CurrentOriginator)
This function is used to disable the INTRO_OPT_PROT_KM_NT_EAT_READS by removing the hook IntWinDrvHan...
Definition: windriver.c:1422
The object was detected when it was created.
Definition: winguest.h:150
KERNEL_DRIVER * KernelDriver
Points to the driver object that describes the kernel image.
Definition: guests.h:381
char * utf16_for_log(const WCHAR *WString)
Converts a UTF-16 to a UTF-8 string to be used inside logging macros.
Definition: introcore.c:2845
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1086
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:57
INTSTATUS IntWinDrvUpdateProtection(void)
Used to update the protection for all the loaded modules (gKernelDrivers).
Definition: windriver.c:1737
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]
Definition: winpe.h:79
static INTSTATUS IntWinDrvSendAlert(KERNEL_DRIVER *Driver, EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Sends a driver related EPT violation alert.
Definition: windriver.c:1236
#define PATCHGUARD_RIP_COUNT
#define DRIVER_MAX_ITERATIONS
When iterating the guest PsLoadedModuleList, we won&#39;t go through more than this many entries...
Definition: windriver.h:52
void IntGuestUpdateCoreOptions(QWORD NewOptions)
Updates Introcore options.
Definition: guests.c:1424
INTSTATUS IntWinProtectReadNtEat(void)
Used to place a read hook on the ntoskrnl.exe EAT.
Definition: windriver.c:606
Holds register state.
Definition: glueiface.h:30
Event structure for EPT violations.
Definition: intro_types.h:1104
QWORD EntryPoint
The entry point of this driver.
Definition: drivers.h:45
#define INT_STATUS_NOT_READY
Definition: introstatus.h:308
#define IC_TAG_DRNU
Guest loaded module name buffer (Unicode)
Definition: memtags.h:11
#define IC_TAG_HDRS
Module headers as cached inside a KERNEL_MODULE structure.
Definition: memtags.h:52
PWIN_DRIVER_OBJECT DriverObject
The driver object.
Definition: windriver.h:36
Execute-access hook.
Definition: glueiface.h:300
void IntAlertFillWinKmModule(const KERNEL_DRIVER *Driver, INTRO_MODULE *EventModule)
Saves kernel module information inside an alert.
Definition: alerts.c:617
DWORD PathHash
CRC32 hash value for the driver`s path.
Definition: windriver.h:25
INTSTATUS IntWinDrvProtect(KERNEL_DRIVER *Driver, QWORD ProtectionFlag)
Used to enable protection for the given driver.
Definition: windriver.c:1055
#define list_for_each(_head, _struct_type, _var)
Definition: introlists.h:41
Exploitation of Remote Services.
Definition: intro_types.h:1048
const PROTECTED_MODULE_INFO * IntWinDrvIsProtected(const KERNEL_DRIVER *Driver)
Get the protected module information for a kernel driver.
Exposes the types, constants and functions used to handle Windows Drivers related events...
Write-access hook.
Definition: glueiface.h:299
#define PAGE_MASK
Definition: pgtable.h:35
INTSTATUS IntExceptKernelGetOriginator(EXCEPTION_KM_ORIGINATOR *Originator, DWORD Options)
This function is used to get the information about the kernel-mode originator.
INTSTATUS IntAlertFillExecContext(QWORD Cr3, INTRO_EXEC_CONTEXT *ExecContext)
Fills the current execution context.
Definition: alerts.c:31
#define ZONE_WRITE
Used for write violation.
Definition: exceptions.h:698
QWORD Buffer
The guest virtual address at which the wide-character string is located.
Definition: wddefs.h:146
#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
INTSTATUS IntHookObjectCreate(DWORD ObjectType, QWORD Cr3, void **Object)
Create a new hook object.
Definition: hook_object.c:81
void IntExcept(EXCEPTION_VICTIM_ZONE *Victim, void *Originator, EXCEPTION_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason, INTRO_EVENT_TYPE EventClass)
This function is the entry point for the exception mechanism.
Definition: exceptions.c:3317
BOOLEAN Protected
True if the module is protected.
Definition: intro_types.h:1787
void IntDriverCacheInv(const QWORD BaseAddress, const QWORD Length)
Invalidates all cache entries for a given guest memory range.
Definition: drivers.c:508
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281