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->Flink) ||
105  !IS_KERNEL_POINTER_WIN(TRUE, pListHead->Blink))
106  {
107  TRACE("Failed kernel pointer checks on PsLoadedModuleList Flink/Blink = 0x%016llx/0x%016llx\n",
108  pListHead->Flink, pListHead->Blink);
110  }
111 
112  status = IntKernVirtMemRead(KernelLdr, sizeof(mod64), &mod64, NULL);
113  if (!INT_SUCCESS(status))
114  {
115  return status;
116  }
117 
118  // The invariant rules
120  matched = matched && IS_KERNEL_POINTER_WIN(TRUE, mod64.InLoadOrderLinks.Blink);
121  matched = matched && IS_KERNEL_POINTER_WIN(TRUE, mod64.DllBase);
122  matched = matched && IS_KERNEL_POINTER_WIN(TRUE, mod64.DriverName.Buffer);
123  matched = matched && (mod64.DllBase % PAGE_SIZE == 0);
124  matched = matched && (mod64.EntryPoint > mod64.DllBase && mod64.EntryPoint < mod64.DllBase + mod64.SizeOfImage);
125 
126  if (!matched)
127  {
129  }
130 
131  if (mod64.InLoadOrderLinks.Blink != PsLoadedModuleListGva)
132  {
133  TRACE("[INFO] Found & skipped shadow module list at 0x%016llx (head->flink->blink should be same as head)\n",
134  PsLoadedModuleListGva);
135 
137  }
138 
139  // Fetch the name of the driver, to make sure it's the kernel (ntos*)
140  status = IntKernVirtMemFetchQword(mod64.DriverName.Buffer, &name);
141  if (!INT_SUCCESS(status))
142  {
143  return status;
144  }
145 
146  if (name != 0x0073006f0074006e) // "ntos", UNICODE
147  {
149  }
150 
151  status = INT_STATUS_SUCCESS;
152  }
153  else
154  {
156  LIST_ENTRY32 *pListHead;
157 
158  // PsModuleList is LIST_HEAD, it must not spill into the next page
159  if ((PsLoadedModuleListGva & PAGE_OFFSET) + sizeof(LIST_ENTRY32) > PAGE_SIZE)
160  {
162  }
163 
164  // The driver pointed by the head must not spill in another page.
165  if ((KernelLdr & PAGE_OFFSET) + sizeof(LDR_DATA_TABLE_ENTRY32) > PAGE_SIZE)
166  {
168  }
169 
170  pListHead = (LIST_ENTRY32 *)PsLoadedModuleList;
171  if (!IS_KERNEL_POINTER_WIN(FALSE, pListHead->Flink) ||
172  !IS_KERNEL_POINTER_WIN(FALSE, pListHead->Blink))
173  {
174  TRACE("Failed kernel pointer checks on PsLoadedModuleList Flink/Blink = 0x%08x/0x%08x\n",
175  pListHead->Flink, pListHead->Blink);
177  }
178 
179  status = IntKernVirtMemRead(KernelLdr, sizeof(mod32), &mod32, NULL);
180  if (!INT_SUCCESS(status))
181  {
182  return status;
183  }
184 
185  // The invariant rules
187  matched = matched && IS_KERNEL_POINTER_WIN(FALSE, mod32.InLoadOrderLinks.Blink);
188  matched = matched && IS_KERNEL_POINTER_WIN(FALSE, mod32.DllBase);
189  matched = matched && IS_KERNEL_POINTER_WIN(FALSE, mod32.DriverName.Buffer);
190  matched = matched && (mod32.DllBase % PAGE_SIZE == 0);
191  matched = matched &&
192  (mod32.EntryPoint > mod32.DllBase && mod32.EntryPoint < (QWORD)mod32.DllBase + mod32.SizeOfImage);
193 
194  if (!matched)
195  {
197  }
198 
199  if (mod32.InLoadOrderLinks.Blink != PsLoadedModuleListGva)
200  {
201  TRACE("[INFO] Found & skipped shadow module list at 0x%08x (head->flink->blink should be same as head)\n",
202  (DWORD)PsLoadedModuleListGva);
203 
205  }
206 
207  // Fetch the name of the driver, to make sure it's the kernel (ntos*)
208  status = IntKernVirtMemFetchQword(mod32.DriverName.Buffer, &name);
209  if (!INT_SUCCESS(status))
210  {
211  return status;
212  }
213 
214  if (name != 0x0073006f0074006e) // "ntos", UNICODE
215  {
217  }
218 
219  status = INT_STATUS_SUCCESS;
220  }
221 
222  return status;
223 }
224 
225 
226 INTSTATUS
229  _In_ QWORD Aux
230  )
239 {
240  INTSTATUS status;
241  QWORD count = 0;
242  QWORD currentModule = gWinGuest->PsLoadedModuleList;
243 
244  if (Callback == NULL)
245  {
247  }
248 
249  // Read the Flink value
250  if (gGuest.Guest64)
251  {
252  status = IntKernVirtMemFetchQword(currentModule, &currentModule);
253  }
254  else
255  {
256  status = IntKernVirtMemFetchDword(currentModule, (DWORD *)&currentModule);
257  }
258  if (!INT_SUCCESS(status))
259  {
260  ERROR("[ERROR] Failed getting the Flink value of MODULE @ 0x%016llx: 0x%08x\n", currentModule, status);
261  return status;
262  }
263 
264  status = INT_STATUS_SUCCESS;
265 
266  // We'll iterate for maximum DRIVER_MAX_ITERATIONS. We assume that there won't be more than this many drivers.
267  // This is a guard to avoid denial of service with crafted drivers nodes.
268  while ((currentModule != gWinGuest->PsLoadedModuleList) && (count++ < DRIVER_MAX_ITERATIONS))
269  {
270  status = Callback(currentModule, Aux);
271  if (INT_STATUS_BREAK_ITERATION == status)
272  {
273  return INT_STATUS_SUCCESS;
274  }
275 
276  // Go to the next entry
277  if (gGuest.Guest64)
278  {
279  status = IntKernVirtMemFetchQword(currentModule, &currentModule);
280  }
281  else
282  {
283  status = IntKernVirtMemFetchDword(currentModule, (DWORD *)&currentModule);
284  currentModule &= 0xFFFFFFFF;
285  }
286  if (!INT_SUCCESS(status))
287  {
288  ERROR("[ERROR] Failed getting the Flink value of LDR_DATA_TABLE_ENTRY @ 0x%016llx: 0x%08x\n",
289  currentModule, status);
290  break;
291  }
292  }
293 
294  if (count == DRIVER_MAX_ITERATIONS)
295  {
296  // This means that the guest list os crafted somehow...
297  status = INT_STATUS_NOT_SUPPORTED;
298  }
299 
300  return status;
301 }
302 
303 
304 INTSTATUS
306  _In_ QWORD ModuleInfo,
307  _In_ QWORD Flags
308  )
320 {
321  LDR_DATA_TABLE_ENTRY32 pModuleInfo32 = {0};
322  LDR_DATA_TABLE_ENTRY64 pModuleInfo64 = {0};
323  const PROTECTED_MODULE_INFO *pProt = NULL;
324  INTSTATUS status;
325  KERNEL_DRIVER *pDriver;
326  DWORD nameSize, pathSize;
327  QWORD entryPoint;
328 
329  pDriver = NULL;
330 
331  if (gGuest.Guest64)
332  {
333  status = IntKernVirtMemRead(ModuleInfo, sizeof(LDR_DATA_TABLE_ENTRY64), &pModuleInfo64, NULL);
334  }
335  else
336  {
337  status = IntKernVirtMemRead(ModuleInfo, sizeof(LDR_DATA_TABLE_ENTRY32), &pModuleInfo32, NULL);
338  }
339  if (!INT_SUCCESS(status))
340  {
341  ERROR("[ERROR] Failed reading from GVA 0x%016llx to host: 0x%08x\n", ModuleInfo, status);
342  return status;
343  }
344 
345  pDriver = HpAllocWithTag(sizeof(*pDriver), IC_TAG_MODU);
346  if (NULL == pDriver)
347  {
349  }
350 
351  if (gGuest.Guest64)
352  {
353  pDriver->BaseVa = pModuleInfo64.DllBase;
354  pDriver->Size = 0xFFFFFFFF & pModuleInfo64.SizeOfImage;
355  pDriver->EntryPoint = pModuleInfo64.EntryPoint;
356 
357  entryPoint = pModuleInfo64.EntryPoint;
358 
359  pathSize = 0xFFFF & pModuleInfo64.DriverPath.Length;
360 
361  // pathLength + 2: OK - pathLength is DWORD and is AND with 0xFFFF.
362  pDriver->Win.Path = HpAllocWithTag(pathSize + 2ull, IC_TAG_DRNU);
363  if (NULL == pDriver->Win.Path)
364  {
366  goto _cleanup_and_leave;
367  }
368 
369  status = IntKernVirtMemRead(pModuleInfo64.DriverPath.Buffer, pathSize, pDriver->Win.Path, NULL);
370  if (!INT_SUCCESS(status))
371  {
373  pDriver->Win.PathHash = INITIAL_CRC_VALUE;
374  pDriver->Win.PathLength = 0;
375  }
376  else
377  {
378  strlower_utf16(pDriver->Win.Path, pathSize / 2);
379  pDriver->Win.PathLength = pathSize / 2;
380  pDriver->Win.PathHash = Crc32Wstring(pDriver->Win.Path, INITIAL_CRC_VALUE);
381  }
382 
383  nameSize = 0xFFFF & pModuleInfo64.DriverName.Length;
384 
385  // nameLength + 2: OK - pathLength is DWORD and is AND with 0xFFFF.
386  pDriver->Name = HpAllocWithTag(nameSize + 2ull, IC_TAG_DRNU);
387  if (NULL == pDriver->Name)
388  {
390  goto _cleanup_and_leave;
391  }
392 
393  status = IntKernVirtMemRead(pModuleInfo64.DriverName.Buffer, nameSize, pDriver->Name, NULL);
394  if (!INT_SUCCESS(status))
395  {
396  ERROR("[ERROR] Failed reading driver name: 0x%08x\n", status);
397  goto _cleanup_and_leave;
398  }
399 
400  strlower_utf16(pDriver->Name, nameSize / 2);
401  pDriver->NameLength = nameSize / 2;
402  pDriver->NameHash = Crc32Wstring(pDriver->Name, INITIAL_CRC_VALUE);
403  }
404  else
405  {
406  pDriver->BaseVa = pModuleInfo32.DllBase;
407  pDriver->Size = pModuleInfo32.SizeOfImage;
408  pDriver->EntryPoint = pModuleInfo32.EntryPoint;
409 
410  entryPoint = pModuleInfo32.EntryPoint;
411 
412  pathSize = 0xFFFF & pModuleInfo32.DriverPath.Length;
413 
414  // pathLength + 2 OK - pathLength is DWORD and is AND with 0xFFFF.
415  pDriver->Win.Path = HpAllocWithTag(pathSize + 2ull, IC_TAG_DRNU);
416  if (NULL == pDriver->Win.Path)
417  {
419  goto _cleanup_and_leave;
420  }
421 
422  status = IntKernVirtMemRead(pModuleInfo32.DriverPath.Buffer, pathSize, pDriver->Win.Path, NULL);
423  if (!INT_SUCCESS(status))
424  {
426  pDriver->Win.PathHash = INITIAL_CRC_VALUE;
427  pDriver->Win.PathLength = 0;
428  }
429  else
430  {
431  strlower_utf16(pDriver->Win.Path, pathSize / 2);
432  pDriver->Win.PathLength = pathSize / 2;
433  pDriver->Win.PathHash = Crc32Wstring(pDriver->Win.Path, INITIAL_CRC_VALUE);
434  }
435 
436  nameSize = 0xFFFF & pModuleInfo32.DriverName.Length;
437 
438  // nameLength + 2 OK - pathLength is DWORD and is AND with 0xFFFF.
439  pDriver->Name = HpAllocWithTag(nameSize + 2ull, IC_TAG_DRNU);
440  if (NULL == pDriver->Name)
441  {
443  goto _cleanup_and_leave;
444  }
445 
446  status = IntKernVirtMemRead(pModuleInfo32.DriverName.Buffer, nameSize, pDriver->Name, NULL);
447  if (!INT_SUCCESS(status))
448  {
449  ERROR("[ERROR] Failed reading driver name from 0x%08x [%d]: 0x%08x\n",
450  pModuleInfo32.DriverName.Buffer, pModuleInfo32.DriverName.Length, status);
451  goto _cleanup_and_leave;
452  }
453 
454  strlower_utf16(pDriver->Name, nameSize / 2);
455  pDriver->NameHash = Crc32Wstring(pDriver->Name, INITIAL_CRC_VALUE);
456  pDriver->NameLength = nameSize / 2;
457  }
458 
459  TRACE("[DRIVER] Driver '%s' @ 0x%016llx (base: 0x%016llx, hash: 0x%08x) just loaded\n",
460  utf16_for_log(pDriver->Name), ModuleInfo, pDriver->BaseVa, pDriver->NameHash);
461 
462  if ((0 != (Flags & FLAG_DYNAMIC_DETECTION)) &&
463  IS_KERNEL_POINTER_WIN(gGuest.Guest64, entryPoint) &&
464  IntWinDrvHasDriverObject(pDriver))
465  {
466  // We will execute-protect the page with EP from the newly loaded driver. This way,
467  // when the first instruction will get executed, we will be notified, and we'll have
468  // a chance to protect the driver's driver object. As a cool stuff, the section with
469  // the EP of any newly-loaded driver is always mapped in memory (will not be swapped
470  // out). If it isn't, then we're dealing with a regular dll, and not a driver.
471 
473  if (!INT_SUCCESS(status))
474  {
475  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
476  goto _cleanup_and_leave;
477  }
478 
479  status = IntHookObjectHookRegion(pDriver->Win.EpHookObject,
480  0,
481  entryPoint & PAGE_MASK,
482  PAGE_SIZE,
485  pDriver,
486  0,
487  NULL);
488  if (!INT_SUCCESS(status))
489  {
490  ERROR("[ERROR] IntHookObjectHookRegion failed: 0x%08x\n", status);
491  goto _cleanup_and_leave;
492  }
493  }
494 
495  pProt = IntWinDrvIsProtected(pDriver);
496  if (pProt)
497  {
498  status = IntWinDrvProtect(pDriver, pProt->RequiredFlags);
499  if (!INT_SUCCESS(status))
500  {
501  ERROR("[ERROR] IntWinDrvProtect failed: 0x%08x\n", status);
502  }
503  }
504 
505  IntWinDrvSendEvent(pDriver, TRUE);
506 
507  InsertTailList(&gKernelDrivers, &pDriver->Link);
508 
509  return INT_STATUS_SUCCESS;
510 
511 _cleanup_and_leave:
512  if (!INT_SUCCESS(status) && (NULL != pDriver))
513  {
514  IntWinDrvRemoveEntry(pDriver);
515  }
516 
517  return status;
518 }
519 
520 
521 INTSTATUS
523  _In_ QWORD ModuleInfo
524  )
532 {
533  INTSTATUS status;
534  DWORD sizeOfImage;
535  QWORD moduleBase;
536  LDR_DATA_TABLE_ENTRY32 *pModuleInfo32 = NULL;
537  LDR_DATA_TABLE_ENTRY64 *pModuleInfo64 = NULL;
538  DWORD loadCount;
539 
540  if (gGuest.Guest64)
541  {
542  status = IntVirtMemMap(ModuleInfo, sizeof(*pModuleInfo64), gGuest.Mm.SystemCr3, 0, &pModuleInfo64);
543  }
544  else
545  {
546  status = IntVirtMemMap(ModuleInfo, sizeof(*pModuleInfo32), gGuest.Mm.SystemCr3, 0, &pModuleInfo32);
547  }
548  if (!INT_SUCCESS(status))
549  {
550  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx: 0x%08x\n", ModuleInfo, status);
551  return status;
552  }
553 
554  if (pModuleInfo64)
555  {
556  sizeOfImage = 0xffffffff & pModuleInfo64->SizeOfImage;
557  moduleBase = pModuleInfo64->DllBase;
558  loadCount = pModuleInfo64->LoadCount;
559  }
560  else if (pModuleInfo32)
561  {
562  sizeOfImage = pModuleInfo32->SizeOfImage;
563  moduleBase = (QWORD)pModuleInfo32->DllBase;
564  loadCount = pModuleInfo32->LoadCount;
565  }
566  else
567  {
569  }
570 
571  if (loadCount > 1)
572  {
574  goto _cleanup_and_leave;
575  }
576 
577  status = INT_STATUS_NOT_FOUND;
578 
579  list_for_each(gKernelDrivers, KERNEL_DRIVER, pDriver)
580  {
581  if (pDriver->BaseVa == moduleBase && pDriver->Size == sizeOfImage)
582  {
583  IntDriverCacheInv(pDriver->BaseVa, pDriver->Size);
584 
585  TRACE("[DRIVER] Driver 0x%016llx unloaded\n", pDriver->BaseVa);
586 
587  IntWinDrvSendEvent(pDriver, FALSE);
588 
589  RemoveEntryList(&pDriver->Link);
590 
591  status = IntWinDrvRemoveEntry(pDriver);
592  if (!INT_SUCCESS(status))
593  {
594  ERROR("[ERROR] IntWinDrvRemoveEntry failed: 0x%08x\n", status);
595  }
596 
597  status = INT_STATUS_SUCCESS;
598 
599  goto _cleanup_and_leave;
600  }
601  }
602 
603  WARNING("[WARNING] Requested unload of the driver 0x%016llx with"
604  "size 0x%08x, LDR 0x%016llx, but it wasn't found...\n",
605  moduleBase, sizeOfImage, ModuleInfo);
606 
607 _cleanup_and_leave:
608  if (pModuleInfo64)
609  {
610  IntVirtMemUnmap(&pModuleInfo64);
611  }
612  else if (pModuleInfo32)
613  {
614  IntVirtMemUnmap(&pModuleInfo32);
615  }
616 
617  return status;
618 }
619 
620 
621 INTSTATUS
623  void
624  )
630 {
632  IMAGE_DATA_DIRECTORY dataDir = { 0 };
633  DWORD eatRva;
634  DWORD eatSize;
635 
636  if (!gGuest.KernelDriver)
637  {
638  goto exit;
639  }
640 
642  {
643  goto exit;
644  }
645 
647  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
648  {
649  ERROR("[ERROR] IntPeGetDirectory failed: 0x%08x\n", status);
650  goto exit;
651  }
652 
653  eatRva = dataDir.VirtualAddress;
654  eatSize = dataDir.Size;
655 
656  if (eatRva > gGuest.KernelDriver->Size ||
657  eatSize > gGuest.KernelDriver->Size ||
658  (QWORD)eatRva + eatSize > gGuest.KernelDriver->Size)
659  {
660  ERROR("[ERROR] eatRva/eatSize are not valid eatRva:0x%08x, eatSize:0x%08x, "
661  "KernelBaseVa:0x%llx, KernelSize:0x%llx\n",
662  eatRva, eatSize, gGuest.KernelDriver->BaseVa,
664 
665  status = INT_STATUS_OUT_OF_RANGE;
666 
667  goto exit;
668  }
669 
671  0,
672  gGuest.KernelDriver->BaseVa + eatRva,
673  eatSize,
677  0,
679  if (!INT_SUCCESS(status))
680  {
681  ERROR("[ERROR] Failed hooking EAT for ntoskrnl.exe 0x%08x\n", status);
682  }
683 
684 exit:
685  return status;
686 }
687 
688 
689 INTSTATUS
691  void
692  )
698 {
700 
701  if (!gGuest.KernelDriver)
702  {
703  goto exit;
704  }
705 
707  {
708  goto exit;
709  }
710 
712  if (!INT_SUCCESS(status))
713  {
714  ERROR("[ERROR] IntHookObjectRemoveRegion failed, status: 0x%08x\n", status);
715  }
717 
718 exit:
719  return status;
720 }
721 
722 
723 static INTSTATUS
725  _In_ void *Context,
726  _In_ QWORD Cr3,
727  _In_ QWORD VirtualAddress,
728  _In_ QWORD PhysicalAddress,
729  _In_reads_bytes_(DataSize) void *Data,
730  _In_ DWORD DataSize,
731  _In_ DWORD Flags
732  )
747 {
748  INTSTATUS status;
749  KERNEL_DRIVER *pDriver;
751  DWORD i, iatSize, eatSize, iatRva, eatRva;
752  QWORD sectionBase;
753  BOOLEAN iatHooked, eatHooked;
754  IMAGE_DATA_DIRECTORY dataDir = { 0 };
755  INTRO_PE_INFO peInfo = { 0 };
756 
758  UNREFERENCED_PARAMETER(VirtualAddress);
759  UNREFERENCED_PARAMETER(PhysicalAddress);
760  UNREFERENCED_PARAMETER(Flags);
761  UNREFERENCED_PARAMETER(DataSize);
762 
763  pDriver = Context;
764 
765  pDriver->Win.HeadersSwapHandle = NULL;
766 
767  iatHooked = FALSE;
768  eatHooked = FALSE;
769 
770  TRACE("[DRIVER] Adding protection on driver '%s' at %llx...\n",
771  utf16_for_log(pDriver->Name), pDriver->BaseVa);
772 
773  // Just in case someone allocated these headers already.
774  if (NULL == pDriver->Win.MzPeHeaders)
775  {
777  if (NULL == pDriver->Win.MzPeHeaders)
778  {
780  }
781  }
782 
783  // Copy the kernel headers and cache them internally for every protected driver.
784  memcpy(pDriver->Win.MzPeHeaders, Data, PAGE_SIZE);
785 
786  status = IntPeValidateHeader(pDriver->BaseVa, pDriver->Win.MzPeHeaders, PAGE_SIZE, &peInfo, 0);
787  if (!INT_SUCCESS(status))
788  {
789  ERROR("[ERROR] IntPeValidateHeader failed: 0x%08x\n", status);
791  }
792 
793  // Get the base address of the section headers and set an EPT hook on every section that it's not writable.
794  // The idea is that this way, we will protect the code, IAT, EAT with one shot, since both the IAT & EAT are
795  // placed by the compiler inside a read-only section.
796 
797  pDriver->Win.TimeDateStamp = peInfo.TimeDateStamp;
798  pDriver->EntryPoint = pDriver->BaseVa + peInfo.EntryPoint;
799 
800  sectionBase = pDriver->BaseVa + peInfo.SectionOffset;
801 
802  status = IntPeGetDirectory(0, pDriver->Win.MzPeHeaders, IMAGE_DIRECTORY_ENTRY_IAT, &dataDir);
803  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
804  {
805  ERROR("[ERROR] IntPeGetDirectory failed: 0x%08x\n", status);
806  return status;
807  }
808 
809  iatRva = dataDir.VirtualAddress;
810  iatSize = dataDir.Size;
811 
812  status = IntPeGetDirectory(0, pDriver->Win.MzPeHeaders, IMAGE_DIRECTORY_ENTRY_EXPORT, &dataDir);
813  if (!INT_SUCCESS(status) && status != INT_STATUS_NOT_FOUND)
814  {
815  ERROR("[ERROR] IntPeGetDirectory failed: 0x%08x\n", status);
816  return status;
817  }
818 
819  eatRva = dataDir.VirtualAddress;
820  eatSize = dataDir.Size;
821 
822  TRACE("[DRIVER] %s @ 0x%016llx has timedate stamp 0x%08x and size 0x%08x\n",
823  utf16_for_log(pDriver->Name), pDriver->BaseVa, pDriver->Win.TimeDateStamp, (DWORD)pDriver->Size);
824 
826  if (!INT_SUCCESS(status))
827  {
828  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
829  return status;
830  }
831 
832  for (i = 0; i < peInfo.NumberOfSections; i++)
833  {
834  BOOLEAN hookSection = FALSE, ignoreAlign = FALSE;
835  QWORD secStart;
836  QWORD secEnd;
837 
838  // section offset + current section + sizeof section < PAGE_SIZE
839  if (pDriver->Win.MzPeHeaders && (peInfo.SectionOffset + i * sizeof(sec) + sizeof(sec) < PAGE_SIZE))
840  {
841  memcpy(&sec, pDriver->Win.MzPeHeaders + peInfo.SectionOffset + i * sizeof(sec), sizeof(sec));
842  }
843  else
844  {
845  status = IntKernVirtMemRead(sectionBase + i * sizeof(sec), sizeof(sec), &sec, NULL);
846  if (!INT_SUCCESS(status))
847  {
848  ERROR("[ERROR] Failed reading IMAGE_SECTION_HEADER %d for driver 0x%016llx\n", i, pDriver->BaseVa);
849  continue;
850  }
851  }
852 
853  // Skip NULL sections.
854  if (0 == sec.Misc.VirtualSize)
855  {
856  continue;
857  }
858 
859  secStart = pDriver->BaseVa + sec.VirtualAddress;
860  secEnd = secStart + ROUND_UP((QWORD)sec.Misc.VirtualSize, peInfo.SectionAlignment);
861 
862  hookSection = (!(sec.Characteristics & IMAGE_SCN_MEM_WRITE)) && // section must not be writable
863  (!(sec.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)); // section must not be discardable
864 
865  // Special ntoskrnl.exe treatment for some sections.
866  if (pDriver->BaseVa == gGuest.KernelVa)
867  {
868  // Special treatment for INITKDBG section, which is overwritten by kdcom anyway...
869  if (memcmp(sec.Name, "INITKDBG", 8) == 0)
870  {
871  TRACE("[DRIVER] Skipping section INITKDBG...\n");
872  continue;
873  }
874 
875  // Special treatment for ERRATA section (windows 10 BETA [the after the official release])
876  if (memcmp(sec.Name, "ERRATA", 6) == 0)
877  {
878  TRACE("[DRIVER] Skipping section ERRATA on build %d...\n", gGuest.OSVersion);
879  continue;
880  }
881 
882  if (memcmp(sec.Name, "ALMOSTRO", 8) == 0)
883  {
884  // Override the hookSection flag, as even if the ALMOSTRO section contains the KeServiceDescriptorTable
885  // which we want to hook.
886  if (gWinGuest->KeServiceDescriptorTable >= secStart &&
888  {
889  TRACE("[DRIVER] Overriding the hook flag, will hook ALMOSTRO section...\n");
890  hookSection = ignoreAlign = TRUE;
892  secEnd = secStart + KESDT_SIZE;
893  }
894  }
895  }
896 
897  if ((0 == iatRva) ||
898  ((hookSection) && IN_RANGE_LEN(iatRva, sec.VirtualAddress, sec.Misc.VirtualSize) &&
899  IN_RANGE_LEN(iatRva + iatSize, sec.VirtualAddress, sec.Misc.VirtualSize + 1)))
900  {
901  iatHooked = TRUE;
902  }
903 
904  if ((0 == eatRva) ||
905  ((hookSection) && IN_RANGE_LEN(eatRva, sec.VirtualAddress, sec.Misc.VirtualSize) &&
906  IN_RANGE_LEN(eatRva + eatSize, sec.VirtualAddress, sec.Misc.VirtualSize + 1)))
907  {
908  eatHooked = TRUE;
909  }
910 
911  // Now hook the section, if we can
912  if (hookSection)
913  {
914  // Handle overlapping section (Xen drivers workaround).
915  if (!ignoreAlign && ((secStart % PAGE_SIZE != 0) || (secEnd % PAGE_SIZE != 0)))
916  {
917  IMAGE_SECTION_HEADER sec2 = { 0 };
918  QWORD lastPage = (secEnd - 1) & PAGE_MASK;
919  QWORD firstPage = secStart & PAGE_MASK;
920  DWORD k;
921  BOOLEAN lowOverlap = FALSE, highOverlap = FALSE;
922 
923  WARNING("[WARNING] Section %d of driver '%s' is not aligned (%llx:%llx): alignment %x\n",
924  i, utf16_for_log(pDriver->Name), secStart, secEnd, peInfo.SectionAlignment);
925 
926  // Section is not aligned, make sure there is no other writable section that starts in the last page of
927  // this section or ends in the first page of it.
928  for (k = 0; k < peInfo.NumberOfSections; k++)
929  {
930  QWORD curSecStart = 0, curSecEnd = 0, curLastPage = 0, curFirstPage = 0;
931 
932  if (pDriver->Win.MzPeHeaders && (peInfo.SectionOffset + k * sizeof(sec) + sizeof(sec) < PAGE_SIZE))
933  {
934  memcpy(&sec2, pDriver->Win.MzPeHeaders + peInfo.SectionOffset + k * sizeof(sec2), sizeof(sec2));
935  }
936  else
937  {
938  status = IntKernVirtMemRead(sectionBase + k * sizeof(sec2),
939  sizeof(sec2),
940  &sec2,
941  NULL);
942  if (!INT_SUCCESS(status))
943  {
944  ERROR("[ERROR] Failed reading IMAGE_SECTION_HEADER %d for driver %llx\n",
945  k, pDriver->BaseVa);
946  continue;
947  }
948  }
949 
950  curSecStart = pDriver->BaseVa + sec2.VirtualAddress;
951  curSecEnd = curSecStart + ROUND_UP((QWORD)sec2.Misc.VirtualSize, peInfo.SectionAlignment);
952 
953  curLastPage = (curSecEnd - 1) & PAGE_MASK;
954  curFirstPage = curSecStart & PAGE_MASK;
955 
956  // Check if the ends of this section is inside a page where a writable section starts.
957  if ((lastPage == curFirstPage) && (0 != (sec2.Characteristics & IMAGE_SCN_MEM_WRITE)))
958  {
959  WARNING("[WARNING] Section %d overlaps writable section %d (%llx:%llx - %llx:%llx)!\n",
960  i, k, secStart, secEnd, curSecStart, curSecEnd);
961 
962  highOverlap = TRUE;
963  }
964 
965  // Check if the beginning of this section is inside a page where a writable section ends.
966  if ((firstPage == curLastPage) && (0 != (sec2.Characteristics & IMAGE_SCN_MEM_WRITE)))
967  {
968  WARNING("[WARNING] Section %d overlaps writable section %d (%llx:%llx - %llx:%llx)!\n",
969  i, k, secStart, secEnd, curSecStart, curSecEnd);
970 
971  lowOverlap = TRUE;
972  }
973  }
974 
975  if (highOverlap)
976  {
977  // Re-align the page end down to a page-size multiple.
978  secEnd &= PAGE_MASK;
979  }
980 
981  if (lowOverlap)
982  {
983  // Re-align the page start up to a page-size multiple.
984  secStart = (secStart & PAGE_MASK) + 0x1000;
985  }
986  }
987 
988  if (secStart >= secEnd)
989  {
990  WARNING("[WARNING] Section %d overlaps entirely writable sections; will not hook it.\n", i);
991  continue;
992  }
993 
994  status = IntHookObjectHookRegion(pDriver->HookObject,
995  0,
996  secStart,
997  secEnd - secStart,
1000  pDriver,
1001  0,
1002  NULL);
1003  if (!INT_SUCCESS(status))
1004  {
1005  ERROR("[ERROR] Failed hooking section %d for driver 0x%016llx: 0x%08x\n", i, pDriver->BaseVa, status);
1006  continue;
1007  }
1008  }
1009  }
1010 
1011  // Hook the IAT, if it wasn't hooked already.
1012  if (!iatHooked)
1013  {
1014  status = IntHookObjectHookRegion(pDriver->HookObject,
1015  0,
1016  pDriver->BaseVa + iatRva,
1017  iatSize,
1020  pDriver,
1021  0,
1022  NULL);
1023  if (!INT_SUCCESS(status))
1024  {
1025  ERROR("[ERROR] Failed hooking IAT for driver 0x%016llx: 0x%08x\n", pDriver->BaseVa, status);
1026  }
1027  }
1028 
1029  // Hook the EAT, if it wasn't hooked already.
1030  if (!eatHooked)
1031  {
1032  status = IntHookObjectHookRegion(pDriver->HookObject,
1033  0,
1034  pDriver->BaseVa + eatRva,
1035  eatSize,
1038  pDriver,
1039  0,
1040  NULL);
1041  if (!INT_SUCCESS(status))
1042  {
1043  ERROR("[ERROR] Failed hooking IAT for driver 0x%016llx: 0x%08x\n", pDriver->BaseVa, status);
1044  }
1045 
1046 
1047  }
1048 
1050  {
1051  if (pDriver->BaseVa == gGuest.KernelVa && gWinGuest)
1052  {
1053  gGuest.KernelDriver = pDriver;
1054  status = IntWinProtectReadNtEat();
1055  if (!INT_SUCCESS(status))
1056  {
1057  ERROR("[ERROR] Failed hooking EAT for ntoskrnl.exe, failed: 0x%08x\n", status);
1058  }
1059  }
1060  }
1061 
1062  pDriver->Protected = TRUE;
1063 
1064  return status;
1065 }
1066 
1067 
1068 INTSTATUS
1070  _In_ KERNEL_DRIVER *Driver,
1071  _In_ QWORD ProtectionFlag
1072  )
1083 {
1084  if (NULL == Driver)
1085  {
1087  }
1088 
1089  if (Driver->Protected)
1090  {
1092  }
1093 
1094  Driver->Protected = TRUE;
1095  Driver->ProtectionFlag = ProtectionFlag;
1096 
1097  return IntSwapMemReadData(0, Driver->BaseVa, PAGE_SIZE, SWAPMEM_OPT_NO_FAULT, Driver, 0,
1098  IntWinDrvHeadersInMemory, NULL, &Driver->Win.HeadersSwapHandle);
1099 }
1100 
1101 
1102 INTSTATUS
1104  _In_ KERNEL_DRIVER *Driver
1105  )
1114 {
1115  if (NULL == Driver)
1116  {
1118  }
1119 
1120  if (!Driver->Protected)
1121  {
1123  }
1124 
1125  TRACE("[DRIVER] Removing protection on module '%s' at %llx...\n",
1126  utf16_for_log(Driver->Name), Driver->BaseVa);
1127 
1128  if (NULL != Driver->Win.MzPeHeaders)
1129  {
1130  HpFreeAndNullWithTag(&Driver->Win.MzPeHeaders, IC_TAG_HDRS);
1131  }
1132 
1133  if (NULL != Driver->HookObject)
1134  {
1135  IntHookObjectDestroy((HOOK_OBJECT_DESCRIPTOR **)&Driver->HookObject, 0);
1136  }
1137 
1138  if (NULL != Driver->Win.HeadersSwapHandle)
1139  {
1140  IntSwapMemRemoveTransaction(Driver->Win.HeadersSwapHandle);
1141 
1142  Driver->Win.HeadersSwapHandle = NULL;
1143  }
1144 
1145  Driver->Protected = FALSE;
1146 
1147  return INT_STATUS_SUCCESS;
1148 }
1149 
1150 
1151 INTSTATUS
1153  _In_opt_ void *Context,
1154  _In_ void *Hook,
1155  _In_ QWORD Address,
1156  _Out_ INTRO_ACTION *Action
1157  )
1172 {
1173  INTSTATUS status;
1174  KERNEL_DRIVER *pDriver;
1175  PWIN_DRIVER_OBJECT pDrvObj;
1176  IG_ARCH_REGS *pRegs;
1177  QWORD guestAddress;
1178 
1179  UNREFERENCED_PARAMETER(Address);
1180 
1181  if (NULL == Context)
1182  {
1184  }
1185 
1186  if (NULL == Action)
1187  {
1189  }
1190 
1191  if (NULL == Hook)
1192  {
1194  }
1195 
1196  guestAddress = 0;
1197  pDrvObj = NULL;
1198  pDriver = Context;
1199 
1200  pRegs = &gVcpu->Regs;
1201 
1202  if (pRegs->Rip != pDriver->EntryPoint)
1203  {
1204  *Action = introGuestAllowed;
1205  return INT_STATUS_SUCCESS;
1206  }
1207 
1208  if (gGuest.Guest64)
1209  {
1210  guestAddress = pRegs->Rcx;
1211  }
1212  else
1213  {
1214  status = IntKernVirtMemFetchDword(pRegs->Rsp + 4, (DWORD *)&guestAddress);
1215  if (!INT_SUCCESS(status))
1216  {
1217  ERROR("[ERROR] IntKernVirtMemPatchDword failed: 0x%08x\n", status);
1218  }
1219  }
1220 
1221  if (IntWinDrvObjIsValidDriverObject(guestAddress))
1222  {
1223  status = IntWinDrvObjCreateFromAddress(guestAddress, FALSE, &pDrvObj);
1224  if (!INT_SUCCESS(status))
1225  {
1226  ERROR("[ERROR] IntWinDrvObjCreateDriverObject failed: 0x%08x\n", status);
1227  pDrvObj = NULL;
1228  }
1229 
1230  pDriver->Win.DriverObject = pDrvObj;
1231  }
1232 
1233  if (NULL != pDriver->Win.EpHookObject)
1234  {
1235  status = IntHookObjectDestroy((HOOK_OBJECT_DESCRIPTOR **)&pDriver->Win.EpHookObject, 0);
1236  if (!INT_SUCCESS(status))
1237  {
1238  ERROR("[ERROR] IntHookObjectDestroy failed: 0x%08x\n", status);
1239  }
1240  }
1241 
1242  // we will allow the action, and we don't want notifications to be sent to LINUX/Winguest.
1243  *Action = introGuestRetry;
1244 
1245  return INT_STATUS_SUCCESS;
1246 }
1247 
1248 
1249 static INTSTATUS
1251  _In_ KERNEL_DRIVER *Driver,
1252  _In_ EXCEPTION_VICTIM_ZONE *Victim,
1253  _In_ EXCEPTION_KM_ORIGINATOR *Originator,
1254  _In_ INTRO_ACTION Action,
1255  _In_ INTRO_ACTION_REASON Reason
1256  )
1268 {
1269  INTSTATUS status;
1270  PEVENT_EPT_VIOLATION pEptViol;
1271  PIG_ARCH_REGS regs;
1272 
1273  regs = &gVcpu->Regs;
1274 
1275  pEptViol = &gAlert.Ept;
1276  memzero(pEptViol, sizeof(*pEptViol));
1277 
1278  pEptViol->Header.Action = Action;
1279  pEptViol->Header.Reason = Reason;
1280 
1281  if (!!(Victim->ZoneFlags & ZONE_READ))
1282  {
1283  pEptViol->Header.MitreID = idExploitRemote;
1284  }
1285  else
1286  {
1287  pEptViol->Header.MitreID = idRootkit;
1288  }
1289 
1291 
1292  IntAlertEptFillFromKmOriginator(Originator, pEptViol);
1293  IntAlertEptFillFromVictimZone(Victim, pEptViol);
1294 
1295  pEptViol->Header.Flags = IntAlertCoreGetFlags(Driver->ProtectionFlag, Reason);
1296 
1298 
1299  IntAlertFillCodeBlocks(Originator->Original.Rip, regs->Cr3, FALSE, &pEptViol->CodeBlocks);
1300  IntAlertFillExecContext(0, &pEptViol->ExecContext);
1301 
1302  IntAlertFillVersionInfo(&pEptViol->Header);
1303 
1304  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
1305  if (!INT_SUCCESS(status))
1306  {
1307  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
1308  }
1309 
1310  return INT_STATUS_SUCCESS;
1311 }
1312 
1313 
1314 INTSTATUS
1316  _In_ void *Context,
1317  _In_ void *Hook,
1318  _In_ QWORD Address,
1319  _Out_ INTRO_ACTION *Action
1320  )
1331 {
1332  EXCEPTION_VICTIM_ZONE victim;
1333  EXCEPTION_KM_ORIGINATOR originator;
1334  INTSTATUS status;
1335  INTRO_ACTION_REASON reason;
1336  BOOLEAN exitAfterInformation;
1337  KERNEL_DRIVER *pDriver;
1338 
1339  if (NULL == Context)
1340  {
1342  }
1343 
1344  if (NULL == Action)
1345  {
1347  }
1348 
1349  UNREFERENCED_PARAMETER(Hook);
1350 
1352 
1353  memzero(&victim, sizeof(victim));
1354  memzero(&originator, sizeof(originator));
1355 
1356  // By default we do not allow this
1357  *Action = introGuestNotAllowed;
1358  reason = introReasonUnknown;
1359  exitAfterInformation = FALSE;
1360  pDriver = Context;
1361 
1362  status = IntExceptKernelGetOriginator(&originator, 0);
1363  if (status == INT_STATUS_EXCEPTION_BLOCK)
1364  {
1365  reason = introReasonNoException;
1366  exitAfterInformation = TRUE;
1367  }
1368  else if (!INT_SUCCESS(status))
1369  {
1370  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
1371  reason = introReasonInternalError;
1372  exitAfterInformation = TRUE;
1373  }
1374 
1375  status = IntExceptGetVictimEpt(pDriver,
1376  Address,
1377  IntHookGetGlaFromGpaHook(Hook, Address),
1379  ZONE_WRITE,
1380  &victim);
1381  if (!INT_SUCCESS(status))
1382  {
1383  reason = introReasonInternalError;
1384  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
1385  exitAfterInformation = TRUE;
1386  }
1387 
1388  if (exitAfterInformation)
1389  {
1390  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
1391  }
1392  else
1393  {
1394  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
1395  }
1396 
1398 
1399  if (IntPolicyCoreTakeAction(pDriver->ProtectionFlag, Action, &reason))
1400  {
1401  IntWinDrvSendAlert(pDriver, &victim, &originator, *Action, reason);
1402  }
1403 
1405 
1406  return status;
1407 }
1408 
1409 
1410 static KERNEL_DRIVER *
1412  _In_ QWORD Rip
1413  )
1422 {
1423  list_for_each(gKernelDrivers, KERNEL_DRIVER, pDriver)
1424  {
1425  if (Rip >= pDriver->BaseVa && Rip < pDriver->BaseVa + pDriver->Size)
1426  {
1427  return pDriver;
1428  }
1429  }
1430 
1431  return NULL;
1432 }
1433 
1434 
1435 static INTSTATUS
1437  _In_ KERNEL_DRIVER *CurrentOriginator
1438  )
1453 {
1454  INTSTATUS status;
1455 
1456  if (!CurrentOriginator)
1457  {
1459  }
1460 
1461  if (!gGuest.KernelDriver)
1462  {
1464  }
1465 
1466  ERROR("[ERROR] We have reached %llu reads from ntoskrnl.exe EAT, last driver %s, disabling protection\n",
1467  gGuest.KernelDriver->Win.EatReadCount, utf16_for_log(CurrentOriginator->Name));
1468 
1469  status = IntWinUnprotectReadNtEat();
1470  if (!INT_SUCCESS(status))
1471  {
1472  ERROR("[ERROR] IntWinUnprotectReadNtEat failed: 0x%08x\n", status);
1473  }
1474 
1477 
1478  return INT_STATUS_SUCCESS;
1479 }
1480 
1481 
1482 INTSTATUS
1484  _In_ void *Context,
1485  _In_ void *Hook,
1486  _In_ QWORD Address,
1487  _Out_ INTRO_ACTION *Action
1488  )
1500 {
1501  EXCEPTION_VICTIM_ZONE victim;
1502  EXCEPTION_KM_ORIGINATOR originator;
1503  INTSTATUS status;
1504  INTRO_ACTION_REASON reason;
1505  KERNEL_DRIVER *pDriver;
1506  KERNEL_DRIVER *pOriginatingDriver;
1507  BOOLEAN exitAfterInformation;
1508  QWORD ripPage;
1509 
1510 #define NTOSKRNL_RIP_PAGES_COUNT 20
1511 #define PATCHGUARD_RIP_COUNT 4
1512 #define MAX_KNOWN_DRIVER_READS 100000
1513 
1514  static QWORD ntoskrnlRipPages[NTOSKRNL_RIP_PAGES_COUNT] = { 0 };
1515  static DWORD ntoskrnlRipPagesCount = 0;
1516 
1517  static QWORD patchguardRip[PATCHGUARD_RIP_COUNT] = { 0 };
1518  static DWORD patchguardRipCount = 0;
1519 
1520  if (NULL == Context)
1521  {
1523  }
1524 
1525  if (NULL == Action)
1526  {
1528  }
1529 
1530  // By default we allow this
1531  *Action = introGuestAllowed;
1532  reason = introReasonAllowed;
1533  pDriver = Context;
1534  status = INT_STATUS_SUCCESS;
1535  exitAfterInformation = FALSE;
1536 
1538 
1539  // The ntoskrnl.exe also reads its own EAT - multiple RIPs that are contained within a few pages.
1540  // In order to increase the performance, we are going to save the pages (one by one when the
1541  // originator.Return.Driver is ntoskrnl.exe) and compare the current RIP page value with stored values.
1542  ripPage = gVcpu->Regs.Rip & PAGE_MASK;
1543  for (DWORD i = 0; i < ntoskrnlRipPagesCount; i++)
1544  {
1545  if (ntoskrnlRipPages[i] == ripPage)
1546  {
1547  goto exit;
1548  }
1549  }
1550 
1551  // The PatchGuard usually reads the EAT multiple times from a few RIPs (none of which are inside any known module).
1552  // In order to increase the performance, we are going to save the RIPs (one by one when the
1553  // originator.Original.Driver is NULL and we match the exceptions) and compare the current RIP value with
1554  // stored values.
1555  for (DWORD i = 0; i < patchguardRipCount; i++)
1556  {
1557  if (patchguardRip[i] == gVcpu->Regs.Rip)
1558  {
1559  goto exit;
1560  }
1561  }
1562 
1563  // If the read originates from within one of our own agents - allow.
1565  {
1566  goto exit;
1567  }
1568 
1569  // If the read originates from within a known driver - allow.
1570  pOriginatingDriver = IntWinGetDriverByGva(gVcpu->Regs.Rip);
1571  if (pOriginatingDriver)
1572  {
1573  if (pOriginatingDriver->BaseVa == gGuest.KernelVa)
1574  {
1575  TRACE("[DRIVER] Saving ntoskrnl.exe page:0x%llx\n", gVcpu->Regs.Rip & PAGE_MASK);
1576  ntoskrnlRipPages[(ntoskrnlRipPagesCount++) % NTOSKRNL_RIP_PAGES_COUNT] = gVcpu->Regs.Rip & PAGE_MASK;
1577  }
1578  else
1579  {
1581 
1583  {
1584  status = IntWinDrvForceDisableReadNtEat(pOriginatingDriver);
1585  if (!INT_SUCCESS(status))
1586  {
1587  ERROR("[ERROR] IntWinDrvDisableReadNtEat failed: 0x%08x\n", status);
1588  }
1589  }
1590  }
1591 
1592  goto exit;
1593  }
1594 
1595  memzero(&victim, sizeof(victim));
1596  memzero(&originator, sizeof(originator));
1597 
1598  status = IntExceptKernelGetOriginator(&originator, 0);
1599  if (status == INT_STATUS_EXCEPTION_BLOCK)
1600  {
1601  reason = introReasonNoException;
1602  exitAfterInformation = TRUE;
1603  }
1604  else if (!INT_SUCCESS(status))
1605  {
1606  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
1607  reason = introReasonInternalError;
1608  exitAfterInformation = TRUE;
1609  }
1610 
1611  status = IntExceptGetVictimEpt(pDriver,
1612  Address,
1613  IntHookGetGlaFromGpaHook(Hook, Address),
1615  ZONE_READ,
1616  &victim);
1617  if (!INT_SUCCESS(status))
1618  {
1619  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
1620  reason = introReasonInternalError;
1621  exitAfterInformation = TRUE;
1622  }
1623 
1624  if (exitAfterInformation)
1625  {
1626  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
1627  }
1628  else
1629  {
1630  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
1631  }
1632 
1633  // This is the probably PatchGuard. We are going to store its RIP.
1634  if (introGuestAllowed == *Action)
1635  {
1636  TRACE("[DRIVER] Saving PatchGuard RIP:0x%llx\n", gVcpu->Regs.Rip);
1637  patchguardRip[(patchguardRipCount++) % PATCHGUARD_RIP_COUNT] = gVcpu->Regs.Rip;
1638  }
1639 
1640  if (IntPolicyCoreTakeAction(pDriver->ProtectionFlag, Action, &reason))
1641  {
1642  IntWinDrvSendAlert(pDriver, &victim, &originator, *Action, reason);
1643  }
1644 
1646 
1647 exit:
1649 
1650 #undef NTOSKRNL_RIP_PAGES_COUNT
1651 #undef PATCHGUARD_RIP_COUNT
1652 #undef MAX_KNOWN_DRIVER_READS
1653 
1654  return status;
1655 }
1656 
1657 
1658 static INTSTATUS
1660  _In_ KERNEL_DRIVER *Driver,
1661  _In_ QWORD Reserved
1662  )
1671 {
1672  UNREFERENCED_PARAMETER(Reserved);
1673 
1674  if (NULL != Driver->Win.Path)
1675  {
1676  HpFreeAndNullWithTag(&Driver->Win.Path, IC_TAG_DRNU);
1677  }
1678 
1679  if (NULL != Driver->Name)
1680  {
1681  HpFreeAndNullWithTag(&Driver->Name, IC_TAG_DRNU);
1682  }
1683 
1684  if (NULL != Driver->Win.MzPeHeaders)
1685  {
1686  HpFreeAndNullWithTag(&Driver->Win.MzPeHeaders, IC_TAG_HDRS);
1687  }
1688 
1690 
1691  return INT_STATUS_SUCCESS;
1692 }
1693 
1694 
1695 INTSTATUS
1697  _In_ KERNEL_DRIVER *Driver
1698  )
1706 {
1707  INTSTATUS status;
1708 
1709  if (NULL == Driver)
1710  {
1712  }
1713 
1714  status = IntWinDrvUnprotect(Driver);
1715  if (!INT_SUCCESS(status))
1716  {
1717  ERROR("[ERROR] IntWinModuleUnHook failed: 0x%08x\n", status);
1718  }
1719 
1720  if (NULL != Driver->Win.EpHookObject)
1721  {
1722  IntHookObjectDestroy((HOOK_OBJECT_DESCRIPTOR **)&Driver->Win.EpHookObject, 0);
1723  }
1724 
1725  if (NULL != Driver->Win.DriverObject)
1726  {
1727  PWIN_DRIVER_OBJECT pDrvObj = Driver->Win.DriverObject;
1728 
1729  RemoveEntryList(&pDrvObj->Link);
1730 
1731  status = IntWinDrvObjRemove(pDrvObj);
1732  if (!INT_SUCCESS(status))
1733  {
1734  ERROR("[ERROR] IntWinDrvObjRemoveDriverObject failed: 0x%08x\n", status);
1735  }
1736 
1737  Driver->Win.DriverObject = NULL;
1738  }
1739 
1740  status = IntWinDrvFreeEntry(Driver, 0);
1741  if (!INT_SUCCESS(status))
1742  {
1743  ERROR("[ERROR] IntWinDrvFreeEntry failed: 0x%08x\n", status);
1744  }
1745 
1746  return status;
1747 }
1748 
1749 
1750 INTSTATUS
1752  void
1753  )
1759 {
1760  TRACE("[DRIVER] Updating kernel drivers protections...\n");
1761 
1762  list_for_each(gKernelDrivers, KERNEL_DRIVER, pDriver)
1763  {
1764  INTSTATUS status;
1765 
1766  const PROTECTED_MODULE_INFO *pProtInfo = IntWinDrvIsProtected(pDriver);
1767 
1768  if (!pDriver->Protected && (NULL != pProtInfo))
1769  {
1770  status = IntWinDrvProtect(pDriver, pProtInfo->RequiredFlags);
1771  if (!INT_SUCCESS(status))
1772  {
1773  ERROR("[ERROR] IntWinDrvProtect failed for '%s': 0x%08x\n",
1774  utf16_for_log(pDriver->Name), status);
1775  }
1776  }
1777  else if (pDriver->Protected && (NULL == pProtInfo))
1778  {
1779  status = IntWinDrvUnprotect(pDriver);
1780  if (!INT_SUCCESS(status))
1781  {
1782  ERROR("[ERROR] IntWinDrvUnprotect failed for '%s': 0x%08x\n",
1783  utf16_for_log(pDriver->Name), status);
1784  }
1785  }
1786  }
1787 
1788  return INT_STATUS_SUCCESS;
1789 }
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:1263
INTSTATUS IntWinDrvRemoveEntry(KERNEL_DRIVER *Driver)
Removes the KERNEL_DRIVER from the internal structures.
Definition: windriver.c:1696
#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:227
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:238
Read-access hook.
Definition: glueiface.h:298
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
Definition: winguest.c:37
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:139
#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:552
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1199
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#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
WIN_KERNEL_DRIVER Win
Valid only for Windows guests.
Definition: drivers.h:70
#define STATS_EXIT(id)
Definition: stats.h:160
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:690
#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:1411
#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:1945
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
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:305
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:281
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:1144
Describes a kernel-mode originator.
Definition: exceptions.h:943
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:522
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:1217
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:1195
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:724
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:836
#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:153
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
Definition: intro_types.h:1196
INTSTATUS IntWinDrvObjRemove(WIN_DRIVER_OBJECT *DriverObject)
Removes a driver object and updates its owner module.
Definition: windrvobj.c:1344
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:1152
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:290
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:1315
INTSTATUS IntExceptGetVictimEpt(void *Context, QWORD Gpa, QWORD Gva, INTRO_OBJECT_TYPE Type, DWORD ZoneFlags, EXCEPTION_VICTIM_ZONE *Victim)
Fills an EXCEPTION_VICTIM_ZONE with relevant information from an EPT violation.
Definition: exceptions.c:742
unsigned long long QWORD
Definition: intro_types.h:53
QWORD Current
The currently used options.
Definition: guests.h:236
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:445
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:283
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:61
void IntAlertFillWinProcessCurrent(INTRO_PROCESS *EventProcess)
Saves information about the current Windows process inside an alert.
Definition: alerts.c:781
union _IMAGE_SECTION_HEADER::@214 Misc
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:1309
BOOLEAN Loaded
True if the module was loaded, False if it was unloaded.
Definition: intro_types.h:1948
INTSTATUS IntWinDrvUnprotect(KERNEL_DRIVER *Driver)
Used to disable protection for the given driver.
Definition: windriver.c:1103
#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:497
#define PAGE_SIZE
Definition: common.h:70
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:893
#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:1957
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:1960
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:1483
__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:374
UNICODE_STRING32 DriverName
Definition: wddefs.h:181
QWORD KeServiceDescriptorTable
Guest virtual address of the KeServiceDescriptorTable variable.
Definition: winguest.h:817
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
static INTSTATUS IntWinDrvFreeEntry(KERNEL_DRIVER *Driver, QWORD Reserved)
Frees the memory allocate for the KERNEL_DRIVER structure.
Definition: windriver.c:1659
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:126
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:1194
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
#define ZONE_READ
Used for read violation.
Definition: exceptions.h:735
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:1436
The object was detected when it was created.
Definition: winguest.h:152
KERNEL_DRIVER * KernelDriver
Points to the driver object that describes the kernel image.
Definition: guests.h:385
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:1197
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
INTSTATUS IntWinDrvUpdateProtection(void)
Used to update the protection for all the loaded modules (gKernelDrivers).
Definition: windriver.c:1751
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:1250
#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:1426
INTSTATUS IntWinProtectReadNtEat(void)
Used to place a read hook on the ntoskrnl.exe EAT.
Definition: windriver.c:622
Holds register state.
Definition: glueiface.h:30
Event structure for EPT violations.
Definition: intro_types.h:1215
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:1069
#define list_for_each(_head, _struct_type, _var)
Definition: introlists.h:41
Exploitation of Remote Services.
Definition: intro_types.h:1159
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:734
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:271
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:3357
BOOLEAN Protected
True if the module is protected.
Definition: intro_types.h:1950
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