Bitdefender Hypervisor Memory Introspection
lixmm.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixmm.h"
6 #include "alerts.h"
7 #include "hook.h"
8 #include "lixfiles.h"
9 #include "lixnet.h"
10 #include "scan_engines.h"
11 #include "shellcode.h"
12 #include "lixksym.h"
13 #include "lixfastread.h"
14 
18 #define LIX_VMA_VDSO_FLAGS (VM_READ | VM_EXEC | VM_DONTEXPAND | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
19 
23 #define LIX_VMA_PROT_MASK BIT(63)
24 
28 #define LIX_VMA_IS_VDSO(Vma) (((((Vma)->Flags & LIX_VMA_VDSO_FLAGS) == LIX_VMA_VDSO_FLAGS) && (0 == (Vma)->File) && (IntLixVmaGetPageCount(Vma) <= 2)))
29 
33 #define LIX_VMA_MAX_GUEST (10 * 4096)
34 
38 #define for_each_vad(Process, _var_name) list_for_each((Process)->Vmas, LIX_VMA, _var_name)
39 
40 
41 static INTSTATUS
43  _In_ QWORD VmaGva,
44  _In_opt_ LIX_TASK_OBJECT *Process,
45  _Out_ LIX_VMA *Vma
46  );
47 
48 
49 static inline size_t
51  _In_ const LIX_VMA *Vma
52  )
60 {
61 #ifdef DEBUG
62  if (Vma->Start >= Vma->End)
63  {
64  ERROR("[ERROR] Invalid VMA [%llx - %llx]\n", Vma->Start, Vma->End);
65  IntDumpGva(Vma->Gva, 0x100, gGuest.Mm.SystemCr3);
66 
67  return 0;
68  }
69 #endif
70 
71  return (Vma->End - Vma->Start) / PAGE_SIZE;
72 }
73 
74 
77  _Out_ QWORD *InitMm
78  )
106 {
107  INTSTATUS status;
108  QWORD startGva;
109 
110  if (NULL == InitMm)
111  {
113  }
114 
115  // It should be there, except on Debian
116  startGva = IntKsymFindByName("init_mm", NULL);
117  if (startGva)
118  {
119  *InitMm = startGva;
120  return INT_STATUS_SUCCESS;
121  }
122 
123  for (startGva = gLixGuest->Layout.DataStart & PAGE_MASK;
124  startGva < gLixGuest->Layout.DataEnd;
125  startGva += PAGE_SIZE)
126  {
127  BYTE *p;
128  BOOLEAN found = FALSE;
129 
130  status = IntVirtMemMap(startGva, PAGE_SIZE, gGuest.Mm.SystemCr3, 0, &p);
131  if (!INT_SUCCESS(status))
132  {
133  ERROR("[ERROR] IntVirtMemMap failed for 0x%016llx: 0x%08x\n", startGva, status);
134  continue;
135  }
136 
137  for (QWORD mm = startGva; mm < startGva + PAGE_SIZE; mm += sizeof(QWORD))
138  {
139  QWORD pgd, next, prev;
140  QWORD startCode, endCode, startData, endData;
141  DWORD offset = mm & PAGE_OFFSET;
142 
143  // 1. init_mm.pgd inside .data
144  if (offset + LIX_FIELD(MmStruct, Pgd) >= PAGE_SIZE)
145  {
146  status = IntKernVirtMemFetchQword(mm + LIX_FIELD(MmStruct, Pgd), &pgd);
147  if (!INT_SUCCESS(status))
148  {
149  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x%016llx: 0x%08x\n",
150  mm + LIX_FIELD(MmStruct, Pgd), status);
151  continue;
152  }
153  }
154  else
155  {
156  pgd = *(QWORD *)(p + offset + LIX_FIELD(MmStruct, Pgd));
157  }
158 
159  if (pgd < gLixGuest->Layout.DataStart || pgd > gLixGuest->Layout.DataEnd)
160  {
161  continue;
162  }
163 
164  // 2. init_mm.mmlist it's a list
165  // init_mm.mmlist->next->prev = init_mm
166  // init_mm.mmlist->prev->next = init_mm
167  if (offset + LIX_FIELD(MmStruct, MmList) + 8 >= PAGE_SIZE)
168  {
169  status = IntKernVirtMemFetchQword(mm + LIX_FIELD(MmStruct, MmList), &next);
170  if (!INT_SUCCESS(status))
171  {
172  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x%016llx: 0x%08x\n",
173  mm + LIX_FIELD(MmStruct, MmList), status);
174  continue;
175  }
176 
177  status = IntKernVirtMemFetchQword(mm + LIX_FIELD(MmStruct, MmList) + 8, &prev);
178  if (!INT_SUCCESS(status))
179  {
180  ERROR("[ERROR] IntVirtMemFetchQword failed for 0x%016llx: 0x%08x\n",
181  mm + LIX_FIELD(MmStruct, MmList) + 8, status);
182  continue;
183  }
184  }
185  else
186  {
187  next = *(QWORD *)(p + offset + LIX_FIELD(MmStruct, MmList));
188  prev = *(QWORD *)(p + offset + LIX_FIELD(MmStruct, MmList) + 8);
189  }
190 
191  if (!IS_KERNEL_POINTER_LIX(prev) ||
192  !IS_KERNEL_POINTER_LIX(next) ||
193  prev == 0xffffffffffffffff || next == 0xffffffffffffffff)
194  {
195  continue;
196  }
197 
198  if (prev != mm + LIX_FIELD(MmStruct, MmList) + 8)
199  {
200  QWORD prevNext;
201 
202  status = IntKernVirtMemFetchQword(prev, &prevNext);
203  if (!INT_SUCCESS(status))
204  {
205  continue;
206  }
207 
208  if (prevNext != mm + LIX_FIELD(MmStruct, MmList))
209  {
210  continue;
211  }
212  }
213 
214  if (next != mm + LIX_FIELD(MmStruct, MmList))
215  {
216  QWORD nextPrev;
217 
218  status = IntKernVirtMemFetchQword(next + 8, &nextPrev);
219  if (!INT_SUCCESS(status))
220  {
221  continue;
222  }
223 
224  if (nextPrev != mm + LIX_FIELD(MmStruct, MmList))
225  {
226  continue;
227  }
228  }
229 
230  // 3. init_mm.start_code = _stext
231  if (offset + LIX_FIELD(MmStruct, StartCode) >= PAGE_SIZE)
232  {
233  status = IntKernVirtMemFetchQword(mm + LIX_FIELD(MmStruct, StartCode), &startCode);
234  if (!INT_SUCCESS(status))
235  {
236  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x%016llx: 0x%08x\n",
237  mm + LIX_FIELD(MmStruct, StartCode), status);
238  continue;
239  }
240  }
241  else
242  {
243  startCode = *(QWORD *)(p + offset + LIX_FIELD(MmStruct, StartCode));
244  }
245 
246  if (startCode != gLixGuest->Layout.CodeStart)
247  {
248  continue;
249  }
250 
251  // 4. init_mm.end_code = _etext
252  if (offset + LIX_FIELD(MmStruct, EndCode) >= PAGE_SIZE)
253  {
254  status = IntKernVirtMemFetchQword(mm + LIX_FIELD(MmStruct, EndCode), &endCode);
255  if (!INT_SUCCESS(status))
256  {
257  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x%016llx: 0x%08x\n",
258  mm + LIX_FIELD(MmStruct, EndCode), status);
259  continue;
260  }
261  }
262  else
263  {
264  endCode = *(QWORD *)(p + offset + LIX_FIELD(MmStruct, EndCode));
265  }
266 
267  if (endCode != gLixGuest->Layout.CodeEnd)
268  {
269  continue;
270  }
271 
272  // 5. init_mm.start_data = 0 || _etext
273  if (offset + LIX_FIELD(MmStruct, StartData) >= PAGE_SIZE)
274  {
275  status = IntKernVirtMemFetchQword(mm + LIX_FIELD(MmStruct, StartData), &startData);
276  if (!INT_SUCCESS(status))
277  {
278  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x%016llx: 0x%08x\n",
279  mm + LIX_FIELD(MmStruct, StartData), status);
280  continue;
281  }
282  }
283  else
284  {
285  startData = *(QWORD *)(p + offset + LIX_FIELD(MmStruct, StartData));
286  }
287 
288  if (startData != 0 && startData != gLixGuest->Layout.DataStart)
289  {
290  continue;
291  }
292 
293  // 6. init_mm.start_data = 0 || _etext
294  if (offset + LIX_FIELD(MmStruct, StartData) >= PAGE_SIZE)
295  {
296  status = IntKernVirtMemFetchQword(mm + LIX_FIELD(MmStruct, StartData), &startData);
297  if (!INT_SUCCESS(status))
298  {
299  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x%016llx: 0x%08x\n",
300  mm + LIX_FIELD(MmStruct, StartData), status);
301  continue;
302  }
303  }
304  else
305  {
306  startData = *(QWORD *)(p + offset + LIX_FIELD(MmStruct, StartData));
307  }
308 
309  if (startData != 0 && startData != gLixGuest->Layout.DataStart)
310  {
311  continue;
312  }
313 
314  // 6. init_mm.end_data = 0 || _edata
315  if (offset + LIX_FIELD(MmStruct, EndData) >= PAGE_SIZE)
316  {
317  status = IntKernVirtMemFetchQword(mm + LIX_FIELD(MmStruct, EndData), &endData);
318  if (!INT_SUCCESS(status))
319  {
320  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x%016llx: 0x%08x\n",
321  mm + LIX_FIELD(MmStruct, EndData), status);
322  continue;
323  }
324  }
325  else
326  {
327  endData = *(QWORD *)(p + offset + LIX_FIELD(MmStruct, EndData));
328  }
329 
330  // There are some cases when we can't get the real _edata, and we have to approximate
331  if (endData && (endData > gLixGuest->Layout.DataEnd || endData < gLixGuest->Layout.DataStart))
332 
333  {
334  continue;
335  }
336 
337  TRACE("[LIXMM] Found init_mm @ 0x%016llx\n", mm);
338 
339  *InitMm = mm;
340 
341  found = TRUE;
342 
343  break;
344  }
345 
346  IntVirtMemUnmap(&p);
347 
348  if (found)
349  {
350  return INT_STATUS_SUCCESS;
351  }
352  }
353 
354  return INT_STATUS_NOT_FOUND;
355 }
356 
357 
358 static INTSTATUS
360  _In_ QWORD MmGva,
361  _In_ QWORD Address,
362  _Out_ QWORD *VmaGva,
363  _In_ BOOLEAN Backward
364  )
378 {
379  INTSTATUS status;
380  DWORD maxIterations = LIX_VMA_MAX_GUEST;
381  QWORD currentVma;
382  DWORD offset;
383 
384  if (Backward)
385  {
386  offset = LIX_FIELD(Vma, VmPrev);
387  }
388  else
389  {
390  offset = LIX_FIELD(Vma, VmNext);
391  }
392 
393  status = IntKernVirtMemFetchQword(MmGva + LIX_FIELD(MmStruct, Vma), &currentVma);
394  if (!INT_SUCCESS(status))
395  {
396  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x%llx: 0x%08x\n", MmGva + LIX_FIELD(MmStruct, Vma), status);
397  return status;
398  }
399 
400  while (IS_KERNEL_POINTER_LIX(currentVma) && maxIterations > 0)
401  {
402  QWORD nextVma = 0;
403  QWORD start, end;
404 
405  status = IntLixFsrInitMap(currentVma);
406  if (!INT_SUCCESS(status))
407  {
408  ERROR("[ERROR] IntLixFsrInitMap failed for vma 0x%llx: 0x%08x\n", currentVma, status);
409  return status;
410  }
411 
412  status = IntLixFsrRead(currentVma, LIX_FIELD(Vma, VmaEnd), sizeof(end), &end);
413  if (!INT_SUCCESS(status))
414  {
415  ERROR("[ERROR] Failed to read from vma 0x%llx at offset 0x%x. Status: 0x%08x\n",
416  currentVma, LIX_FIELD(Vma, VmaEnd), status);
417  goto _done_unmap;
418  }
419 
420  status = IntLixFsrRead(currentVma, LIX_FIELD(Vma, VmaStart), sizeof(start), &start);
421  if (!INT_SUCCESS(status))
422  {
423  ERROR("[ERROR] Failed to read from vma 0x%llx at offset 0x%x. Status: 0x%08x\n",
424  currentVma, LIX_FIELD(Vma, VmaStart), status);
425 
426  goto _done_unmap;
427  }
428 
429  if (IN_RANGE(Address, start, end))
430  {
431  *VmaGva = currentVma;
432 
433  status = INT_STATUS_SUCCESS;
434 
435  goto _done_unmap;
436  }
437 
438  status = IntLixFsrRead(currentVma, offset, sizeof(nextVma), &nextVma);
439  if (!INT_SUCCESS(status))
440  {
441  ERROR("[ERROR] Failed to read next vma from 0x%llx at offset 0x%x. Status: 0x%08x\n",
442  currentVma, offset, status);
443 
444  goto _done_unmap;
445  }
446 
448 
449  currentVma = nextVma;
450  maxIterations--;
451  }
452 
453  return INT_STATUS_NOT_FOUND;
454 
455 _done_unmap:
456 
458 
459  return status;
460 }
461 
462 
463 INTSTATUS
465  _In_ QWORD MmGva,
466  _In_ QWORD Address,
467  _Out_ QWORD *VmaGva
468  )
490 {
491  INTSTATUS status;
492  QWORD rbGva, vmaGva;
493  LIX_RB_NODE node;
494  QWORD vmaStart, vmaEnd;
495  QWORD maxIterations = 64;
496 
497  vmaStart = vmaEnd = rbGva = 0;
498 
499  status = IntKernVirtMemFetchQword(MmGva + LIX_FIELD(MmStruct, RbNode), &rbGva);
500  if (!INT_SUCCESS(status))
501  {
502  ERROR("[ERROR] Failed to read rb_node for mm 0x%llx. Status: 0x%08x\n", MmGva, status);
503  return status;
504  }
505 
506  while (rbGva)
507  {
508  if (!maxIterations--)
509  {
510  ERROR("[ERROR] Max iterations limit reached!\n");
511  return INT_STATUS_NOT_FOUND;
512  }
513 
514  vmaGva = rbGva - LIX_FIELD(Vma, RbNode);
515 
516  status = IntLixFsrInitMap(vmaGva);
517  if (!INT_SUCCESS(status))
518  {
519  ERROR("[ERROR] Failed to map vma 0x%llx. Status: 0x%08x\n", vmaGva, status);
520  return status;
521  }
522 
523  status = IntLixFsrRead(vmaGva, LIX_FIELD(Vma, VmaEnd), sizeof(vmaEnd), &vmaEnd);
524  if (!INT_SUCCESS(status))
525  {
526  ERROR("[ERROR] Failed to read from vma 0x%llx at offset 0x%x. Status: 0x%08x\n",
527  vmaGva, LIX_FIELD(Vma, VmaEnd), status);
528 
529  goto _done_unmap;
530  }
531 
532  status = IntLixFsrRead(vmaGva, LIX_FIELD(Vma, RbNode), sizeof(node), &node);
533  if (!INT_SUCCESS(status))
534  {
535  ERROR("[ERROR] Failed to read from vma 0x%llx at offset 0x%x. Status: 0x%08x\n",
536  vmaGva, LIX_FIELD(Vma, RbNode), status);
537 
538  goto _done_unmap;
539  }
540 
541  if (vmaEnd > Address)
542  {
543  status = IntLixFsrRead(vmaGva, LIX_FIELD(Vma, VmaStart), sizeof(vmaStart), &vmaStart);
544  if (!INT_SUCCESS(status))
545  {
546  ERROR("[ERROR] Failed to read from vma 0x%llx at offset 0x%x. Status: 0x%08x\n",
547  vmaGva, LIX_FIELD(Vma, VmaStart), status);
548  goto _done_unmap;
549  }
550 
551  if (vmaStart <= Address)
552  {
553  *VmaGva = vmaGva;
554 
555  status = INT_STATUS_SUCCESS;
556 
557  goto _done_unmap;
558  }
559 
560  rbGva = node.Left;
561  }
562  else
563  {
564  rbGva = node.Right;
565  }
566 
568  }
569 
570  return INT_STATUS_NOT_FOUND;
571 
572 _done_unmap:
573 
575 
576  return status;
577 }
578 
579 
580 INTSTATUS
582  _In_ LIX_TASK_OBJECT *Task,
583  _In_ QWORD Address,
584  _Out_ LIX_VMA *Vma
585  )
597 {
598  INTSTATUS status;
599  QWORD vmaGva;
600 
601  if (Task == NULL)
602  {
604  }
605 
606  if (NULL == Vma)
607  {
609  }
610 
611  status = IntLixMmFindVmaInRbTree(Task->MmGva, Address, &vmaGva);
612  if (INT_SUCCESS(status))
613  {
614  goto _fill;
615  }
616 
617  WARNING("[WARNING] Failed to find addr 0x%llx in rbtree for task %s (%d, 0x%llx), mm 0x%llx. Status: 0x%08x\n",
618  Address, Task->Comm, Task->Pid, Task->Gva, Task->MmGva, status);
619 
620  status = IntLixMmFindVmaInLinkedList(Task->MmGva, Address, &vmaGva, FALSE);
621  if (INT_SUCCESS(status))
622  {
623  goto _fill;
624  }
625 
626  status = IntLixMmFindVmaInLinkedList(Task->MmGva, Address, &vmaGva, TRUE);
627  if (!INT_SUCCESS(status))
628  {
629  ERROR("[ERROR] Failed to find addr in linked list\n");
630  return INT_STATUS_NOT_FOUND;
631  }
632 
633 _fill:
634 
635  return IntLixVmaFill(vmaGva, Task, Vma);
636 }
637 
638 
639 INTSTATUS
641  _In_ QWORD Gva,
642  _In_ LIX_TASK_OBJECT *Task,
643  _Out_ QWORD *VmaStart,
644  _Out_ QWORD *VmaEnd
645  )
657 {
658  LIX_VMA vad;
659  INTSTATUS status;
660 
661  if (IS_KERNEL_POINTER_LIX(Gva))
662  {
664  }
665 
666  if (NULL == Task)
667  {
669  }
670 
671  if (NULL == VmaStart)
672  {
674  }
675 
676  if (NULL == VmaEnd)
677  {
679  }
680 
681  *VmaStart = *VmaEnd = 0;
682 
683  status = IntLixMmFetchVma(Task, Gva, &vad);
684  if (!INT_SUCCESS(status))
685  {
686  ERROR("[ERROR] IntLixMmFetchVma failed for task %s(%d, 0x%llx) gva 0x%llx, mm 0x%llx. Status: 0x%08x\n",
687  Task->Comm, Task->Pid, Task->Gva, Gva, Task->MmGva, status);
688  return status;
689  }
690 
691  *VmaStart = vad.Start;
692  *VmaEnd = vad.End;
693 
694  return INT_STATUS_SUCCESS;
695 }
696 
697 
698 LIX_VMA *
700  _In_ const LIX_TASK_OBJECT *Process,
701  _In_ QWORD Address
702  )
712 {
713  for_each_vad(Process, pVma)
714  {
715  if (Address >= pVma->Start && Address < pVma->End)
716  {
717  return pVma;
718  }
719  }
720 
721  return NULL;
722 }
723 
724 
725 static LIX_VMA *
727  _In_ const LIX_TASK_OBJECT *Process,
728  _In_ QWORD Vma
729  )
739 {
740  for_each_vad(Process, pVma)
741  {
742  if (Vma == pVma->Gva)
743  {
744  return pVma;
745  }
746  }
747 
748  return NULL;
749 }
750 
751 
752 static INTSTATUS
754  _In_ QWORD VmaGva,
755  _In_opt_ LIX_TASK_OBJECT *Process,
756  _Out_ LIX_VMA *Vma
757  )
767 {
768  INTSTATUS status;
769 
770  memzero(Vma, sizeof(*Vma));
771 
772  status = IntLixFsrInitMap(VmaGva);
773  if (!INT_SUCCESS(status))
774  {
775  ERROR("[ERROR] IntLixFsrInitMap failed for vma %llx: 0x%08x\n", VmaGva, status);
776  return status;
777  }
778 
779  Vma->Gva = VmaGva;
780 
781  status = IntLixFsrRead(VmaGva, LIX_FIELD(Vma, VmaStart), sizeof(Vma->Start), &Vma->Start);
782  if (!INT_SUCCESS(status))
783  {
784  ERROR("[ERROR] Failed reading vm_area_struct->vm_start: %08x\n", status);
785  goto _done;
786  }
787 
788  status = IntLixFsrRead(VmaGva, LIX_FIELD(Vma, VmaEnd), sizeof(Vma->End), &Vma->End);
789  if (!INT_SUCCESS(status))
790  {
791  ERROR("[ERROR] Failed reading vm_area_struct->vm_end: %08x\n", status);
792  goto _done;
793  }
794 
795  status = IntLixFsrRead(VmaGva, LIX_FIELD(Vma, Flags), sizeof(Vma->Flags), &Vma->Flags);
796  if (!INT_SUCCESS(status))
797  {
798  ERROR("[ERROR] Failed reading vm_area_struct->vm_flags: %08x\n", status);
799  goto _done;
800  }
801 
802  status = IntLixFsrRead(VmaGva, LIX_FIELD(Vma, File), sizeof(Vma->File), &Vma->File);
803  if (!INT_SUCCESS(status))
804  {
805  ERROR("[ERROR] Failed reading vm_area_struct->vm_file: %08x\n", status);
806  goto _done;
807  }
808 
809  Vma->Process = Process;
810 
811  status = INT_STATUS_SUCCESS;
812 
813 _done:
815 
816  return status;
817 }
818 
819 
820 INTSTATUS
822  _In_ QWORD VmaGva,
823  _In_ LIX_TASK_OBJECT *Process,
824  _Out_ LIX_VMA **Vma
825  )
836 {
837  INTSTATUS status;
838  LIX_VMA *pVma;
839 
840  *Vma = NULL;
841 
842  pVma = HpAllocWithTag(sizeof(*pVma), IC_TAG_VMA);
843  if (NULL == pVma)
844  {
846  }
847 
848  status = IntLixVmaFill(VmaGva, Process, pVma);
849  if (!INT_SUCCESS(status))
850  {
851  goto _free_vad;
852  }
853 
854  InsertTailList(&Process->Vmas, &pVma->Link);
855 
856  *Vma = pVma;
857 
858  status = INT_STATUS_SUCCESS;
859 
860 _free_vad:
861  if (!INT_SUCCESS(status))
862  {
864  }
865 
866  return status;
867 }
868 
869 
870 LIX_VMA *
872  _In_ LIX_TASK_OBJECT *Task,
873  _In_ QWORD Vma
874  )
884 {
885  for_each_vad(Task, pVma)
886  {
887  if (pVma->Gva == Vma)
888  {
889  return pVma;
890  }
891  }
892 
893  return NULL;
894 }
895 
896 
897 static INTSTATUS
899  _In_ LIX_VMA *Vma,
900  _In_ BOOLEAN Protected
901  )
915 {
916  INTSTATUS status;
917  QWORD newFlags = 0, oldFlags = 0;
918 
919  status = IntKernVirtMemFetchQword(Vma->Gva + LIX_FIELD(Vma, Flags), &oldFlags);
920  if (!INT_SUCCESS(status))
921  {
922  ERROR("[ERROR] IntKernVirtMemFetchQword IntVirtMemFetchQwordUnmapV GVA 0x%016llx: %08x\n",
923  Vma->Gva + LIX_FIELD(Vma, Flags), status);
924  return status;
925  }
926 
927  if (Protected)
928  {
929  newFlags = oldFlags | LIX_VMA_PROT_MASK;
930  }
931  else
932  {
933  newFlags = oldFlags & (~LIX_VMA_PROT_MASK);
934  }
935 
936  if (oldFlags == newFlags)
937  {
939  }
940 
941  // NOTE: IntVirtMemSafeWrite should be used instead, but it will induce significant performance penalty.
942  status = IntKernVirtMemPatchQword(Vma->Gva + LIX_FIELD(Vma, Flags), newFlags);
943  if (!INT_SUCCESS(status))
944  {
945  ERROR("[ERROR] IntKernVirtMemPatchQword failed for GVA 0x%016llx: %08x\n",
946  Vma->Gva + LIX_FIELD(Vma, Flags), status);
947  return status;
948  }
949 
950  return INT_STATUS_SUCCESS;
951 }
952 
953 
954 static INTSTATUS
956  _In_ LIX_VMA *Vma,
957  _In_ BOOLEAN Mark
958  )
968 {
970 
971  if (Vma->Hook)
972  {
973  status = IntHookObjectRemoveRegion((HOOK_REGION_DESCRIPTOR **)&Vma->Hook, 0);
974  if (!INT_SUCCESS(status))
975  {
976  ERROR("[ERROR] IntHookObjectRemoveRegion failed: %08x\n", status);
977  }
978  }
979 
980  if (Mark)
981  {
982  status = IntVmaMarkProtection(Vma, FALSE);
983  if (!INT_SUCCESS(status))
984  {
985  ERROR("[ERROR] IntVmaMarkProtection failed: %08x\n", status);
986  return status;
987  }
988  }
989 
990  return status;
991 }
992 
993 
994 static void
996  _Inout_ LIX_VMA *Vma
997  )
1007 {
1009 
1010  RemoveEntryList(&Vma->Link);
1012 }
1013 
1014 
1015 void
1017  _In_ LIX_TASK_OBJECT *Task
1018  )
1024 {
1025  for_each_vad(Task, pVma)
1026  {
1027  IntLixVmaDestroy(pVma);
1028  }
1029 
1030  InitializeListHead(&Task->Vmas);
1031 }
1032 
1033 
1034 static INTSTATUS
1036  _In_opt_ void *Context,
1037  _In_ void *Hook,
1038  _In_ QWORD Address,
1039  _Out_ INTRO_ACTION *Action
1040  )
1072 {
1073  INTSTATUS status = INT_STATUS_SUCCESS;
1074  LIX_VMA *pVma, *pStackVma;
1075  LIX_TASK_OBJECT *pTask;
1076  IG_ARCH_REGS *regs;
1077  INSTRUX *instrux;
1078  BOOLEAN bRspOut, bIsStack;
1079  QWORD rip;
1080  QWORD scflags;
1081  BOOLEAN detected, feedback, excepted;
1084  INFO_UD_PENDING *entryPendingUD = NULL;
1085  EXCEPTION_UM_ORIGINATOR originator = {0};
1086  EXCEPTION_VICTIM_ZONE victim = {0};
1087 
1088  UNREFERENCED_PARAMETER(Hook);
1089 
1090  *Action = introGuestAllowed;
1091  detected = excepted = feedback = FALSE;
1092 
1093  regs = &gVcpu->Regs;
1094  instrux = &gVcpu->Instruction;
1095  rip = gVcpu->Gla;
1096 
1097  pVma = (LIX_VMA *)Context;
1098  pTask = pVma->Process;
1099 
1100  entryPendingUD = IntUDGetEntry(regs->Cr3, regs->Rip, pTask->Gva);
1101  if (NULL != entryPendingUD)
1102  {
1103  goto _retry_inject_ud;
1104  }
1105 
1106  bIsStack = (pVma->Flags & VM_GROWSDOWN) != 0;
1107 
1108  pStackVma = IntLixMmFindVmaByRange(pTask, regs->Rsp);
1109  if (pStackVma)
1110  {
1111  bIsStack = ((rip >= pStackVma->Start) && (rip < pStackVma->End));
1112  }
1113 
1114  bRspOut = FALSE;
1115 
1116  status = IntShcIsSuspiciousCode(rip, Address, IG_CS_TYPE_INVALID, regs, &scflags);
1117  if (!INT_SUCCESS(status))
1118  {
1119  scflags = 0;
1120  }
1121 
1122  if (bRspOut || bIsStack)
1123  {
1124  // Pivoted stack or executions on the stack trigger detection directly.
1125  detected = TRUE;
1126  }
1127  else if (0 != scflags)
1128  {
1129  detected = TRUE;
1130 
1131  // Shellcode flags (as set by the shellcode emulator) may be overridden via CAMI. A flag marked for feedback
1132  // will cause the alert to be logged & sent, but no actual detection will appear. Note that we force feedback
1133  // for shellcode flags if and only if all the reported flags are marked as feedback. If there is a single
1134  // shellcode flag set that is not feedback, a normal detection will be generated.
1135  if ((scflags & gGuest.ShemuOptions.Feedback) == scflags)
1136  {
1137  feedback = TRUE;
1138  }
1139  }
1140 
1141  // We did not find malicious activity, send context to the scan engine if we have the options set.
1142  if (!detected && !!(gGuest.CoreOptions.Current & INTRO_OPT_NOTIFY_ENGINES))
1143  {
1144  INTRO_EXEC_INFO executionInfo = { 0 };
1145  INTSTATUS status2;
1146 
1147  // We could fail the entire EPT callback because of this.
1148  status2 = IntLixTaskGetUserStack(pTask, NULL, &executionInfo.StackBase, &executionInfo.StackLimit);
1149  if (!INT_SUCCESS(status2))
1150  {
1151  ERROR("[ERROR] Failed to get user mode stack for process %s (%d, 0x%llx). Status: 0x%08x\n",
1152  pTask->Comm, pTask->Pid, pTask->Gva, status);
1153  }
1154 
1155  executionInfo.Rsp = regs->Rsp;
1156  executionInfo.Length = instrux->Length;
1157 
1158  status2 = IntLixEngExecSendNotification(pTask, regs, &executionInfo);
1159  if (!INT_SUCCESS(status2))
1160  {
1161  WARNING("[WARNING] IntLixEngExecSendNotification failed: 0x%08x\n", status2);
1162  }
1163  }
1164 
1165  if (detected)
1166  {
1167  status = IntExceptUserGetExecOriginator(pTask, &originator);
1168  if (!INT_SUCCESS(status))
1169  {
1170  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
1171  goto _send_notification;
1172  }
1173 
1174  status = IntExceptGetVictimEpt(pTask,
1175  gVcpu->Gpa,
1176  gVcpu->Gla,
1178  ZONE_EXECUTE,
1179  &victim);
1180  if (!INT_SUCCESS(status))
1181  {
1182  ERROR("[ERROR] Failed getting modified zone: 0x%08x\n", status);
1183  goto _send_notification;
1184  }
1185 
1186  IntExcept(&victim, &originator, exceptionTypeUm, &action, &reason, introEventEptViolation);
1187 
1188  if (action == introGuestAllowed)
1189  {
1190  excepted = TRUE;
1191  }
1192  else if (action == introGuestNotAllowed && feedback)
1193  {
1194  action = introGuestAllowed;
1195  reason = introReasonAllowedFeedback;
1196  }
1197  }
1198 
1199 _send_notification:
1200  if (detected && (!excepted)) // 0x7f6e0000
1201  {
1202  PEVENT_EPT_VIOLATION pEptViol = NULL;
1203  char text[ND_MIN_BUF_SIZE] = { 0 };
1204 
1205  status = NdToText(instrux, rip, ND_MIN_BUF_SIZE, text);
1206  if (!INT_SUCCESS(status))
1207  {
1208  ERROR("[ERROR] NdToText failed: 0x%08x\n", status);
1209  snprintf(text, sizeof(text), "<invalid>");
1210  }
1211 
1212  LOG("[VMANX] [CPU %d] EXPLOIT detected! Execution attempted at 0x%016llx! Instruction: %s\n",
1213  gVcpu->Index, rip, text);
1214 
1215  LOG("[VMANX] Current address: %llx, current stack: %llx, known stack: %llx/%llx\n",
1216  rip, regs->Rsp, pStackVma ? pStackVma->End : 0, pStackVma ? pStackVma->Start : 0);
1217 
1218  IntDumpCodeAndRegs(regs->Rip, Address, regs);
1219 
1220  pEptViol = &gAlert.Ept;
1221 
1222  memset(pEptViol, 0, sizeof(*pEptViol));
1223 
1224  pEptViol->Header.Action = action;
1225  pEptViol->Header.Reason = reason;
1226  pEptViol->Header.MitreID = idExploitClientExec;
1227 
1228  pEptViol->Header.Flags = IntAlertProcGetFlags(PROC_OPT_PROT_EXPLOIT, pTask, reason, 0);
1229 
1231  IntAlertFillLixProcess(pTask, &pEptViol->Header.CurrentProcess);
1232 
1233  IntAlertFillVersionInfo(&pEptViol->Header);
1234  IntAlertEptFillFromVictimZone(&victim, pEptViol);
1235 
1236  IntAlertFillExecContext(regs->Cr3, &pEptViol->ExecContext);
1237 
1238  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
1239  if (!INT_SUCCESS(status))
1240  {
1241  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
1242  }
1243 
1244  status = IntLixNetSendTaskConnections(pTask);
1245  if (!INT_SUCCESS(status))
1246  {
1247  ERROR("[ERROR] IntLixNetSendTaskConnections failed: %08x\n", status);
1248  }
1249 
1250  // Override the status returned by IntNotifyIntroEvent.
1251  status = INT_STATUS_SUCCESS;
1252 
1253  // Block by default.
1254  *Action = introGuestNotAllowed;
1255  }
1256 
1258 
1259  // Remove the exec hook if we allow the action.
1260  if (introGuestAllowed == *Action)
1261  {
1262  // Remove the hook on this region, only if we didn't block anything. If we did, we will maintain the hook in
1263  // order to block further execution attempts. We also remove the hook if we're in BETA mode - otherwise,
1264  // there will be lots & lots of alerts, that may end up hanging the process.
1265  status = IntLixVmaRemoveProtection(pVma, FALSE);
1266  if (!INT_SUCCESS(status))
1267  {
1268  ERROR("[ERROR] IntLixVmaRemoveProtection failed for vad [%llx - %llx]: %08x\n",
1269  pVma->Start, pVma->End, status);
1270  }
1271 
1272  // Since we remove the exec-hook, we can simply retry the execution of the instruction. This way, we don't
1273  // have to emulate or single step the instruction.
1274  *Action = introGuestRetry;
1275  }
1276 
1277 _retry_inject_ud:
1278  // Terminate the process, if needed.
1279  if ((INT_SUCCESS(status) && (introGuestNotAllowed == *Action) &&
1280  (0 != (pTask->Protection.Mask & PROC_OPT_KILL_ON_EXPLOIT))) ||
1281  NULL != entryPendingUD)
1282  {
1283  INTSTATUS status2;
1284 
1285  pTask->MustKill = TRUE;
1286 
1287  // If we already injected the same entry, there's no need for another injection, most probably causing an error
1288  if (entryPendingUD != NULL && gVcpu->CurrentUD == entryPendingUD)
1289  {
1290  goto _skip_inject;
1291  }
1292 
1294  if (!INT_SUCCESS(status2))
1295  {
1296  ERROR("[ERROR] IntInjectExceptionInGuest failed, process will not be killed: %08x\n", status2);
1297  }
1298  else
1299  {
1300  if (NULL == entryPendingUD)
1301  {
1302  // If not already pending, add to the list of pending UDs and store the allocated address in entryPendingUD
1303  status = IntUDAddToPendingList(regs->Cr3, regs->Rip, pTask->Gva, &entryPendingUD);
1304  if (!INT_SUCCESS(status))
1305  {
1306  ERROR("[ERROR] IntVadAddToPendingUDList failed: %08x\n", status);
1307  }
1308  }
1309 
1310  // Set gVcpu->CurrentUD pointer to the allocated address for the tuple
1311  gVcpu->CurrentUD = entryPendingUD;
1312  }
1313 _skip_inject:
1314  *Action = introGuestRetry;
1315  }
1316 
1317  return INT_STATUS_SUCCESS;
1318 }
1319 
1320 
1321 static INTSTATUS
1323  _In_ LIX_VMA *Vma
1324  )
1336 {
1337  INTSTATUS status;
1338 
1339  if (0 == (Vma->End - Vma->Start))
1340  {
1341  WARNING("[WARNING] Vma %llx [%llx - %llx] can't be protected!\n", Vma->Gva, Vma->Start, Vma->End);
1343  }
1344 
1345  if ((Vma->File && IntLixVmaGetPageCount(Vma) >= 2) || (0 == (Vma->Flags & VM_EXEC)))
1346  {
1347  // No need to log anything. This is a valid use case where we really need re-monitor some changes.
1349  }
1350 
1351  if (Vma->Hook)
1352  {
1353  LOG("[ERROR] [VMA] Special case when protecting an already protected vad [%llx - %llx]\n",
1354  Vma->Start, Vma->End);
1355 
1356  status = IntLixVmaRemoveProtection(Vma, TRUE);
1357  if (!INT_SUCCESS(status))
1358  {
1359  ERROR("[ERROR] IntLixVmaRemoveProtection failed for vad [%llx - %llx]: %08x\n",
1360  Vma->Start, Vma->End, status);
1361  }
1362  }
1363 
1364  if (__unlikely((Vma->End - Vma->Start) > ONE_GIGABYTE))
1365  {
1366  WARNING("[WARNING] Big vad [%llx - %llx] (%ld pages) in process '%s' (%d)\n",
1367  Vma->Start, Vma->End, IntLixVmaGetPageCount(Vma), Vma->Process->ProcName, Vma->Process->Pid);
1368  goto _mark_protection;
1369  }
1370 
1371  status = IntHookObjectHookRegion(Vma->Process->HookObject,
1372  Vma->Process->Cr3,
1373  Vma->Start,
1374  Vma->End - Vma->Start,
1377  Vma,
1378  0,
1379  (HOOK_REGION_DESCRIPTOR **)&Vma->Hook);
1380  if (!INT_SUCCESS(status))
1381  {
1382  ERROR("[ERROR] IntHookObjectHookRegion failed for [%llx - %llx]: %08x\n",
1383  Vma->Start, Vma->End, status);
1384  return status;
1385  }
1386 
1387 _mark_protection:
1388  status = IntVmaMarkProtection(Vma, TRUE);
1389  if (!INT_SUCCESS(status))
1390  {
1391  ERROR("[ERROR] IntVmaMarkProtection failed: %08x\n", status);
1392  return status;
1393  }
1394 
1395  return INT_STATUS_SUCCESS;
1396 }
1397 
1398 
1399 static INTSTATUS
1401  _In_ LIX_TASK_OBJECT *Process,
1402  _In_ BOOLEAN Backward
1403  )
1416 {
1417  INTSTATUS status;
1418  QWORD currentVma;
1419  DWORD offset;
1420  DWORD maxIterations;
1421 
1422  status = IntKernVirtMemFetchQword(Process->MmGva + LIX_FIELD(MmStruct, Vma), &currentVma);
1423  if (!INT_SUCCESS(status))
1424  {
1425  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", Process->MmGva, status);
1426  return status;
1427  }
1428 
1429  if (Backward)
1430  {
1431  QWORD prevVma = 0;
1432 
1433  status = IntKernVirtMemFetchQword(currentVma + LIX_FIELD(Vma, VmPrev), &prevVma);
1434  if (!INT_SUCCESS(status))
1435  {
1436  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", Process->MmGva, status);
1437  return status;
1438  }
1439 
1440  currentVma = prevVma;
1441  }
1442 
1443  maxIterations = LIX_VMA_MAX_GUEST;
1444  if (Backward)
1445  {
1446  offset = LIX_FIELD(Vma, VmPrev);
1447  }
1448  else
1449  {
1450  offset = LIX_FIELD(Vma, VmNext);
1451  }
1452 
1453  while (IS_KERNEL_POINTER_LIX(currentVma) && maxIterations > 0)
1454  {
1455  QWORD nextVma = 0;
1456  LIX_VMA *pVma = NULL;
1457  LIX_VMA vad;
1458  BOOLEAN shouldProtect;
1459 
1460  status = IntLixVmaFill(currentVma, Process, &vad);
1461  if (!INT_SUCCESS(status))
1462  {
1463  ERROR("[ERROR] IntLixVmaFill failed for vma %llx: %08x\n", currentVma, status);
1464  return status;
1465  }
1466 
1467  shouldProtect = (0 == vad.File && (vad.Flags & VM_EXEC));
1468 
1469  if (LIX_VMA_IS_VDSO(&vad))
1470  {
1471  // This is the VDSO, don't protect it for now (we will protect it globally)
1472  shouldProtect = FALSE;
1473  }
1474 
1475  if (shouldProtect)
1476  {
1477  status = IntLixVmaCreate(currentVma, Process, &pVma);
1478  if (!INT_SUCCESS(status))
1479  {
1480  ERROR("[ERROR] IntLixVmaCreate failed for vma %llx: %08x\n", currentVma, status);
1481  return status;
1482  }
1483 
1484  status = IntLixVmaProtect(pVma);
1485  if (!INT_SUCCESS(status))
1486  {
1487  ERROR("[ERROR] IntLixVmaProtect failed for vad [%llx - %llx] flags %08llx, 0x%016llx: %08x\n",
1488  pVma->Start, pVma->End, pVma->Flags, pVma->Gva, status);
1489 
1490  IntLixVmaDestroy(pVma);
1491  }
1492  }
1493 
1494  status = IntKernVirtMemFetchQword(currentVma + offset, &nextVma);
1495  if (!INT_SUCCESS(status))
1496  {
1497  ERROR("[ERROR] IntKernVirtMemFetchQword failed for vma %llx: %08x\n", currentVma, status);
1498  return status;
1499  }
1500 
1501  currentVma = nextVma;
1502  --maxIterations;
1503  }
1504 
1505  return INT_STATUS_SUCCESS;
1506 }
1507 
1508 
1509 INTSTATUS
1511  _In_ LIX_TASK_OBJECT *Task
1512  )
1523 {
1524  INTSTATUS status;
1525 
1526  if (NULL == Task)
1527  {
1529  }
1530 
1531  status = IntLixMmPopulateVmasInternal(Task, FALSE);
1532  if (!INT_SUCCESS(status))
1533  {
1534  ERROR("[ERROR] IntLixMmPopulateVmasInternal failed for forward parsing: %08x\n", status);
1535  goto _free_and_exit;
1536  }
1537 
1538  status = IntLixMmPopulateVmasInternal(Task, TRUE);
1539  if (!INT_SUCCESS(status))
1540  {
1541  ERROR("[ERROR] IntLixMmPopulateVmasInternal failed for backward parsing: %08x\n", status);
1542  goto _free_and_exit;
1543  }
1544 
1545  return INT_STATUS_SUCCESS;
1546 
1547 _free_and_exit:
1548  IntLixMmDestroyVmas(Task);
1549 
1550  return status;
1551 }
1552 
1553 
1554 static void
1556  _In_ QWORD Mm,
1557  _In_ LIX_TASK_OBJECT *Process,
1558  _In_ BOOLEAN Backward
1559  )
1570 {
1571  INTSTATUS status;
1572  QWORD currentVma;
1573  DWORD offset;
1574  DWORD maxIterations;
1575 
1576  status = IntKernVirtMemFetchQword(Mm + LIX_FIELD(MmStruct, Vma), &currentVma);
1577  if (!INT_SUCCESS(status))
1578  {
1579  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", Mm + LIX_FIELD(MmStruct, Vma), status);
1580  return;
1581  }
1582 
1583  if (Backward)
1584  {
1585  QWORD prevVma = 0;
1586 
1587  status = IntKernVirtMemFetchQword(currentVma + LIX_FIELD(Vma, VmPrev), &prevVma);
1588  if (!INT_SUCCESS(status))
1589  {
1590  ERROR("[ERROR] IntKernVirtMemFetchQword failed for %llx: 0x%08x\n", Mm, status);
1591  return;
1592  }
1593 
1594  currentVma = prevVma;
1595  }
1596 
1597  maxIterations = LIX_VMA_MAX_GUEST;
1598 
1599  if (Backward)
1600  {
1601  offset = LIX_FIELD(Vma, VmPrev);
1602  }
1603  else
1604  {
1605  offset = LIX_FIELD(Vma, VmNext);
1606  }
1607 
1608  while (IS_KERNEL_POINTER_LIX(currentVma) && maxIterations > 0)
1609  {
1610  QWORD nextVma = 0;
1611  LIX_VMA vma;
1612  char *fileName = NULL;
1613 
1614  status = IntLixVmaFill(currentVma, NULL, &vma);
1615  if (!INT_SUCCESS(status))
1616  {
1617  ERROR("[ERROR] IntLixVmaFill failed for vma 0x%016llx: %08x\n", currentVma, status);
1618  return;
1619  }
1620 
1621  status = IntLixGetFileName(vma.File, &fileName, NULL, NULL);
1622  if (!INT_SUCCESS(status))
1623  {
1624  fileName = NULL;
1625  }
1626 
1627  LOG(" [%016llx -> %016llx] : %08llx @ 0x%016llx Hooked=%d (%c%c%c) => %06ld pages '%s'\n",
1628  vma.Start, vma.End, vma.Flags, vma.Gva, vma.Hook ? 1 : 0,
1629  (vma.Flags & VM_EXEC) ? 'X' : '-',
1630  (vma.Flags & VM_WRITE) ? 'W' : '-',
1631  (vma.Flags & VM_READ) ? 'R' : '-',
1632  IntLixVmaGetPageCount(&vma),
1633  fileName);
1634 
1635  DWORD presentPages = 0;
1636  for (size_t i = 0; i < IntLixVmaGetPageCount(&vma); i++)
1637  {
1638  QWORD physAddress;
1639 
1640  status = IntTranslateVirtualAddress(vma.Start + (i * PAGE_SIZE), Process->Cr3, &physAddress);
1641  if (!INT_SUCCESS(status))
1642  {
1643  continue;
1644  }
1645 
1646  presentPages++;
1647  }
1648 
1649  LOG("-----> %d/%ld present pages\n", presentPages, IntLixVmaGetPageCount(&vma));
1650 
1651  if (fileName)
1652  {
1653  HpFreeAndNullWithTag(&fileName, IC_TAG_NAME);
1654  }
1655 
1656  status = IntKernVirtMemFetchQword(currentVma + offset, &nextVma);
1657  if (!INT_SUCCESS(status))
1658  {
1659  ERROR("[ERROR] IntKernVirtMemFetchQword failed for vma %llx: %08x\n", currentVma, status);
1660  return;
1661  }
1662 
1663  currentVma = nextVma;
1664  --maxIterations;
1665  }
1666 
1667 }
1668 
1669 
1670 void
1672  _In_ QWORD Mm,
1673  _In_ LIX_TASK_OBJECT *Process)
1674 {
1681  if (!Mm)
1682  {
1683  return;
1684  }
1685 
1686  IntLixMmListVmasInternal(Mm, Process, FALSE);
1687  IntLixMmListVmasInternal(Mm, Process, TRUE);
1688 }
1689 
1690 
1691 INTSTATUS
1693  _In_ void *Detour
1694  )
1706 {
1707  INTSTATUS status;
1708  QWORD vma = gVcpu->Regs.R8;
1709  QWORD mm = gVcpu->Regs.R9;
1710  LIX_VMA *pVma;
1711 
1712  UNREFERENCED_PARAMETER(Detour);
1713 
1714  LIX_TASK_OBJECT *pTask = IntLixTaskFindByMm(mm);
1715  if (__unlikely((NULL == pTask) || !(pTask->Protection.Mask & PROC_OPT_PROT_EXPLOIT)))
1716  {
1718  }
1719 
1720  pVma = IntLixMmFindVma(pTask, vma);
1721  if (pVma)
1722  {
1723  // It was already created by vma_adjust, no need to do anything
1725  }
1726 
1727  status = IntLixVmaCreate(vma, pTask, &pVma);
1728  if (!INT_SUCCESS(status))
1729  {
1730  ERROR("[ERROR] IntLixVmaCreate failed: %08x\n", status);
1731  return status;
1732  }
1733 
1734  if (LIX_VMA_IS_VDSO(pVma))
1735  {
1736  IntLixVmaDestroy(pVma);
1737 
1738  return INT_STATUS_SUCCESS;
1739  }
1740 
1741  status = IntLixVmaProtect(pVma);
1742  if (!INT_SUCCESS(status))
1743  {
1744  ERROR("[ERROR] IntLixVmaProtect failed: 0x%08x\n", status);
1745  IntLixVmaDestroy(pVma);
1746  }
1747 
1748  return INT_STATUS_SUCCESS;
1749 }
1750 
1751 
1752 INTSTATUS
1754  _In_ void *Detour
1755  )
1768 {
1769  INTSTATUS status;
1770  QWORD vma = gVcpu->Regs.R8;
1771  QWORD mm = gVcpu->Regs.R9;
1772  QWORD newFlags = 0;
1773  LIX_TASK_OBJECT *pTask;
1774  LIX_VMA *pVma;
1775 
1776  UNREFERENCED_PARAMETER(Detour);
1777 
1778  pTask = IntLixTaskFindByMm(mm);
1779  if (__unlikely((NULL == pTask) || !(pTask->Protection.Mask & PROC_OPT_PROT_EXPLOIT)))
1780  {
1782  }
1783 
1784  pVma = IntLixMmFindVma(pTask, vma);
1785 
1786  status = IntKernVirtMemFetchQword(vma + LIX_FIELD(Vma, Flags), &newFlags);
1787  if (!INT_SUCCESS(status))
1788  {
1789  ERROR("[ERROR] IntKernVirtMemFetchQword failed: 0x%08x\n", status);
1790  return status;
1791  }
1792 
1793  newFlags &= ~LIX_VMA_PROT_MASK;
1794 
1795  if (newFlags & VM_EXEC)
1796  {
1797  BOOLEAN newlyCreated = FALSE;
1798 
1799  if (NULL == pVma)
1800  {
1801  newlyCreated = TRUE;
1802 
1803  status = IntLixVmaCreate(vma, pTask, &pVma);
1804  if (!INT_SUCCESS(status))
1805  {
1806  ERROR("[ERROR] IntLixVmaCreate failed for vma %llx: %08x\n", vma, status);
1807  return status;
1808  }
1809  }
1810 
1811  pVma->Flags = newFlags & (~LIX_VMA_PROT_MASK);
1812 
1813  if (newlyCreated || (newFlags != pVma->Flags))
1814  {
1815  status = IntLixVmaProtect(pVma);
1816  if (!INT_SUCCESS(status))
1817  {
1818  ERROR("[ERROR] IntLixVmaProtect failed for vad [%llx - %llx] flags %08llx, 0x%016llx: %08x\n",
1819  pVma->Start, pVma->End, pVma->Flags, pVma->Gva, status);
1820 
1821  IntLixVmaDestroy(pVma);
1822 
1823  return status;
1824  }
1825  }
1826  }
1827  else if (pVma)
1828  {
1829  IntLixVmaDestroy(pVma);
1830  pVma = NULL;
1831  }
1832 
1833  if (pVma)
1834  {
1835  pVma->Flags = newFlags;
1836  }
1837 
1838  return INT_STATUS_SUCCESS;
1839 }
1840 
1841 
1842 static INTSTATUS
1844  _In_ LIX_VMA *AdjustedVma,
1845  _In_opt_ QWORD InsertVma
1846  )
1860 {
1861  INTSTATUS status;
1862 
1863  // We must remove the old protection first
1864  status = IntLixVmaRemoveProtection(AdjustedVma, FALSE);
1865  if (!INT_SUCCESS(status))
1866  {
1867  ERROR("[ERROR] IntLixVmaRemoveProtection failed for vad [%llx - %llx]: %08x\n",
1868  AdjustedVma->Start, AdjustedVma->End, status);
1869  return status;
1870  }
1871 
1872  status = IntLixVmaProtect(AdjustedVma);
1873  if (!INT_SUCCESS(status))
1874  {
1875  ERROR("[ERROR] IntLixVmaProtect failed: 0x%08x\n", status);
1876  return status;
1877  }
1878 
1879  if (InsertVma)
1880  {
1881  LIX_VMA *pInsVma;
1882 
1883  status = IntLixVmaCreate(InsertVma, AdjustedVma->Process, &pInsVma);
1884  if (!INT_SUCCESS(status))
1885  {
1886  ERROR("[ERROR] IntLixVmaCreate failed: 0x%08x\n", status);
1887  return status;
1888  }
1889 
1890  status = IntLixVmaProtect(pInsVma);
1891  if (!INT_SUCCESS(status))
1892  {
1893  ERROR("[ERROR] IntLixVmaProtect failed: 0x%08x\n", status);
1894 
1895  IntLixVmaDestroy(pInsVma);
1896 
1897  return status;
1898  }
1899  }
1900 
1901  return INT_STATUS_SUCCESS;
1902 }
1903 
1904 
1905 INTSTATUS
1907  _In_ void *Detour
1908  )
1920 {
1921  INTSTATUS status;
1922  QWORD mm;
1923  QWORD vma = gVcpu->Regs.R8;
1924  QWORD address = gVcpu->Regs.R9;
1925  LIX_TASK_OBJECT *pTask;
1926  LIX_VMA *pVma;
1927 
1928  UNREFERENCED_PARAMETER(Detour);
1929 
1930  status = IntKernVirtMemFetchQword(vma + LIX_FIELD(Vma, Mm), &mm);
1931  if (!INT_SUCCESS(status))
1932  {
1933  ERROR("[ERROR] IntKernVirtMemFetchQword failed for vma %llx: %08x\n", vma, status);
1934  return status;
1935  }
1936 
1937  pTask = IntLixTaskFindByMm(mm);
1938  if (__unlikely((NULL == pTask) || !(pTask->Protection.Mask & PROC_OPT_PROT_EXPLOIT)))
1939  {
1941  }
1942 
1943  pVma = IntLixMmFindVma(pTask, vma);
1944  if (NULL == pVma)
1945  {
1946  return INT_STATUS_SUCCESS;
1947  }
1948 
1949  if (address < pVma->Start)
1950  {
1951  QWORD oldStart = pVma->Start;
1952 
1953  pVma->Start = address;
1954 
1955  status = IntLixVmaIntervalChanged(pVma, 0);
1956  if (!INT_SUCCESS(status))
1957  {
1958  ERROR("[ERROR] IntLixVmaIntervalChanged failed for vad [%llx/%llx - %llx/%llx] flags %08llx, 0x%016llx: %08x\n",
1959  pVma->Start, oldStart, pVma->End, pVma->End, pVma->Flags, pVma->Gva, status);
1960 
1961  IntLixVmaDestroy(pVma);
1962  }
1963  }
1964 
1965  return INT_STATUS_SUCCESS;
1966 }
1967 
1968 
1969 static INTSTATUS
1971  _In_ LIX_TASK_OBJECT *Task,
1972  _In_ QWORD Vma
1973  )
1983 {
1984  INTSTATUS status;
1985  LIX_VMA *pVma;
1986  QWORD oldStart, oldEnd;
1987  QWORD addr = 0;
1988 
1989  if (NULL == Task || 0 == Vma)
1990  {
1992  }
1993 
1994  pVma = IntLixMmFindVma(Task, Vma);
1995  if (NULL == pVma)
1996  {
1998  }
1999 
2000  oldStart = pVma->Start;
2001  oldEnd = pVma->End;
2002  addr = pVma->Gva;
2003 
2004  status = IntLixFsrInitMap(addr);
2005  if (!INT_SUCCESS(status))
2006  {
2007  ERROR("[ERROR] IntLixFsrInitMap failed for Vma 0x%llx: 0x%08x\n", pVma->Gva, status);
2008  return status;
2009  }
2010 
2011  status = IntLixFsrRead(addr, LIX_FIELD(Vma, VmaStart), sizeof(QWORD), &pVma->Start);
2012  if (!INT_SUCCESS(status))
2013  {
2014  ERROR("[ERROR] Failed to read from Vma 0x%llx at offset 0x%x. Status: 0x%08x\n",
2015  pVma->Gva, LIX_FIELD(Vma, VmaStart), status);
2016 
2017  goto _done_unmap;
2018  }
2019 
2020  status = IntLixFsrRead(addr, LIX_FIELD(Vma, VmaEnd), sizeof(QWORD), &pVma->End);
2021  if (!INT_SUCCESS(status))
2022  {
2023  ERROR("[ERROR] Failed to read from Vma 0x%llx at offset 0x%x. Status: 0x%08x\n",
2024  pVma->Gva, LIX_FIELD(Vma, VmaEnd), status);
2025 
2026  goto _done_unmap;
2027  }
2028 
2029  if (oldStart != pVma->Start || oldEnd != pVma->End)
2030  {
2031  status = IntLixVmaIntervalChanged(pVma, 0);
2032  if (!INT_SUCCESS(status))
2033  {
2034  ERROR("[ERROR] IntLixVmaIntervalChanged failed for vad [%llx/%llx - %llx/%llx] flags %08llx, 0x%016llx: %08x\n",
2035  pVma->Start, oldStart, pVma->End, oldEnd, pVma->Flags, pVma->Gva, status);
2036 
2037  IntLixVmaDestroy(pVma);
2038  }
2039  }
2040 
2041  status = INT_STATUS_SUCCESS;
2042 
2043 _done_unmap:
2044 
2046 
2047  return status;
2048 }
2049 
2050 
2051 INTSTATUS
2053  _In_ void *Detour
2054  )
2066 {
2067  INTSTATUS status;
2068 
2069  QWORD vma = gVcpu->Regs.R8;
2070  QWORD mm = gVcpu->Regs.R9;
2071 
2072  QWORD next = gVcpu->Regs.R10;
2073  QWORD prev = gVcpu->Regs.R11;
2074 
2075  LIX_TASK_OBJECT *pTask;
2076 
2077  UNREFERENCED_PARAMETER(Detour);
2078 
2079  pTask = IntLixTaskFindByMm(mm);
2080  if (__unlikely((NULL == pTask) || !(pTask->Protection.Mask & PROC_OPT_PROT_EXPLOIT)))
2081  {
2083  }
2084 
2085  status = IntLixVmaAdjustInternal(pTask, vma);
2086  if (!INT_SUCCESS(status))
2087  {
2088  ERROR("[ERROR] IntLixVmaAdjustInternal failed for vma 0x%llx (mm gva: 0x%llx) from task %s (%d 0x%llx). Status: 0x%08x\n",
2089  vma, pTask->MmGva, pTask->Comm, pTask->Pid, pTask->Gva, status);
2090  }
2091 
2092  status = IntLixVmaAdjustInternal(pTask, next);
2093  if (!INT_SUCCESS(status))
2094  {
2095  ERROR("[ERROR] IntLixVmaAdjustInternal failed for vma 0x%llx (mm gva: 0x%llx) from task %s (%d 0x%llx). Status: 0x%08x\n",
2096  next, pTask->MmGva, pTask->Comm, pTask->Pid, pTask->Gva, status);
2097  }
2098 
2099  status = IntLixVmaAdjustInternal(pTask, prev);
2100  if (!INT_SUCCESS(status))
2101  {
2102  ERROR("[ERROR] IntLixVmaAdjustInternal failed for vma 0x%llx (mm gva: 0x%llx) from task %s (%d 0x%llx). Status: 0x%08x\n",
2103  prev, pTask->MmGva, pTask->Comm, pTask->Pid, pTask->Gva, status);
2104  }
2105 
2106  return INT_STATUS_SUCCESS;
2107 }
2108 
2109 
2110 INTSTATUS
2112  _In_ void *Detour
2113  )
2127 {
2128  QWORD vma = gVcpu->Regs.R8;
2129  QWORD mm = gVcpu->Regs.R9;
2130 
2131  LIX_TASK_OBJECT *pTask;
2132  LIX_VMA *pVma;
2133 
2134  UNREFERENCED_PARAMETER(Detour);
2135 
2136  pTask = IntLixTaskFindByMm(mm);
2137  if (__unlikely((NULL == pTask) || !(pTask->Protection.Mask & PROC_OPT_PROT_EXPLOIT)))
2138  {
2140  }
2141 
2142  pVma = IntLixMmFindVma(pTask, vma);
2143  if (NULL == pVma)
2144  {
2146  }
2147 
2148  IntLixVmaDestroy(pVma);
2149 
2150  return INT_STATUS_SUCCESS;
2151 }
INTSTATUS IntLixFsrRead(QWORD Gva, DWORD Offset, DWORD Size, void *Buffer)
Performs a read from a previously mapped guest virtual address.
Definition: lixfastread.c:86
#define _In_opt_
Definition: intro_sal.h:16
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
#define __unlikely(x)
Definition: common.h:64
_Bool BOOLEAN
Definition: intro_types.h:58
#define _Out_
Definition: intro_sal.h:22
LIX_VMA * IntLixMmFindVmaByRange(const LIX_TASK_OBJECT *Process, QWORD Address)
Finds if a memory address inside a process is being protected and returns the corresponding LIX_VMA s...
Definition: lixmm.c:699
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
INTSTATUS IntLixVmaCreate(QWORD VmaGva, LIX_TASK_OBJECT *Process, LIX_VMA **Vma)
Creates a LIX_VMA object.
Definition: lixmm.c:821
void IntLixMmDestroyVmas(LIX_TASK_OBJECT *Task)
Remove protection for the VMAs belonging to a process.
Definition: lixmm.c:1016
uint8_t BYTE
Definition: intro_types.h:47
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
DWORD Index
The VCPU number.
Definition: guests.h:172
#define _In_
Definition: intro_sal.h:21
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1199
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
static void IntLixMmListVmasInternal(QWORD Mm, LIX_TASK_OBJECT *Process, BOOLEAN Backward)
Logs all VMAs from a mm_struct.
Definition: lixmm.c:1555
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
DWORD MustKill
Will kill the process with the first occasion.
Definition: lixprocess.h:101
User-mode exception.
Definition: exceptions.h:60
User-mode non executable zone.
Definition: intro_types.h:247
INTSTATUS IntLixVmaExpandDownwards(void *Detour)
Detour handler for "expand_downwards" function.
Definition: lixmm.c:1906
#define VECTOR_UD
Definition: processor.h:109
QWORD Right
Definition: lixddefs.h:316
QWORD Gva
The guest virtual address of the task_struct.
Definition: lixprocess.h:42
QWORD Feedback
Options that will be forced to feedback only mode.
Definition: guests.h:255
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
INTSTATUS IntLixNetSendTaskConnections(LIX_TASK_OBJECT *Task)
Logs and sends to the integrator all connections opened by a Linux proces..
Definition: lixnet.c:413
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
#define PAGE_OFFSET
Definition: pgtable.h:32
INFO_UD_PENDING * IntUDGetEntry(const QWORD Cr3, const QWORD Rip, const QWORD Thread)
Get a UD entry for the provided Cr3, Rip and Thread ID.
Definition: udlist.c:150
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
static INTSTATUS IntLixVmaProtect(LIX_VMA *Vma)
Activates protection for a VMA.
Definition: lixmm.c:1322
#define ERROR(fmt,...)
Definition: glue.h:62
Describes a user-mode originator.
Definition: exceptions.h:994
LIX_VMA * IntLixMmFindVma(LIX_TASK_OBJECT *Task, QWORD Vma)
Finds a protected VMA inside a process VMA list.
Definition: lixmm.c:871
INTSTATUS IntShcIsSuspiciousCode(QWORD Gva, QWORD Gpa, DWORD CsType, IG_ARCH_REGS *Registers, QWORD *ShellcodeFlags)
Checks if the code located at the given guest virtual address is suspicious or not.
Definition: shellcode.c:25
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD CodeEnd
The guest virtual address where the code ends.
Definition: lixguest.h:498
QWORD CodeStart
The guest virtual address where the code starts.
Definition: lixguest.h:497
#define VM_GROWSDOWN
Definition: lixddefs.h:52
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
INTSTATUS IntInjectExceptionInGuest(BYTE Vector, QWORD Cr2, DWORD ErrorCode, DWORD CpuNumber)
Injects an exception inside the guest.
Definition: introcore.c:2264
static INTSTATUS IntLixVmaFill(QWORD VmaGva, LIX_TASK_OBJECT *Process, LIX_VMA *Vma)
Retrieves in-guest information about a VMA and stores them in a LIX_VMA structure.
Definition: lixmm.c:753
INTSTATUS IntLixVmaRemove(void *Detour)
Detour handler for functions that unmap memory for processes.
Definition: lixmm.c:2111
INTSTATUS IntDumpCodeAndRegs(QWORD Gva, QWORD Gpa, IG_ARCH_REGS *Registers)
This function dumps an entire page (textual disassembly and opcodes) as well as the values of the reg...
Definition: dumper.c:692
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
Definition: alerts.c:492
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
Definition: guests.h:88
EVENT_EPT_VIOLATION Ept
Definition: alerts.h:16
QWORD Start
Start of the memory described by the VMA.
Definition: lixmm.h:19
#define LOG(fmt,...)
Definition: glue.h:61
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
INTSTATUS IntLixEngExecSendNotification(LIX_TASK_OBJECT *Task, PIG_ARCH_REGS Registers, PINTRO_EXEC_INFO ExecInfo)
Notify the scan engines about a possible malicious code execution in a Linux guest.
Definition: scan_engines.c:215
QWORD IntAlertProcGetFlags(QWORD ProtectionFlag, const void *Process, INTRO_ACTION_REASON Reason, QWORD AdditionalFlags)
Returns the flags for an alert.
Definition: alerts.c:425
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1217
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
Exposes the functions used to schedule an asynchronous code execution scan and receives its result...
LIX_TASK_OBJECT * IntLixTaskFindByMm(QWORD MmGva)
Finds the Linux process having the provided mm guest virtual address.
Definition: lixprocess.c:999
static INTSTATUS IntLixMmPopulateVmasInternal(LIX_TASK_OBJECT *Process, BOOLEAN Backward)
Iterate the VMA linked list of a process in the given direction and protect the executable ones...
Definition: lixmm.c:1400
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
static INTSTATUS IntLixVmaHandlePageExecution(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Linux user mode page execution handler.
Definition: lixmm.c:1035
#define _Inout_
Definition: intro_sal.h:20
QWORD DataStart
The guest virtual address where the data starts.
Definition: lixguest.h:500
INTSTATUS IntLixMmGetInitMm(QWORD *InitMm)
Find the address of the "init_mm" variable inside the kernel.
Definition: lixmm.c:76
#define IC_TAG_VMA
Used for Linux VMA structs.
Definition: memtags.h:134
void IntAlertEptFillFromVictimZone(const EXCEPTION_VICTIM_ZONE *Victim, EVENT_EPT_VIOLATION *EptViolation)
Fills the victim information inside an EPT alert.
Definition: alerts.c:868
#define IS_KERNEL_POINTER_LIX(p)
Definition: lixguest.h:11
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
Definition: introcore.c:811
INTSTATUS IntLixVmaChangeProtection(void *Detour)
Detour handler for "change_protection" function.
Definition: lixmm.c:1753
struct _LINUX_GUEST::@126 Layout
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
Definition: intro_types.h:1196
#define LIX_VMA_IS_VDSO(Vma)
Checks if a Vma is a vDSO mapping.
Definition: lixmm.c:28
INTSTATUS IntLixMmFindVmaRange(QWORD Gva, LIX_TASK_OBJECT *Task, QWORD *VmaStart, QWORD *VmaEnd)
Finds the VMA limits that contain an address.
Definition: lixmm.c:640
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
#define ZONE_EXECUTE
Used for execute violation.
Definition: exceptions.h:736
#define IN_RANGE(x, start, end)
Definition: introdefs.h:167
#define memzero(a, s)
Definition: introcrt.h:35
QWORD End
End of the memory described by the VMA.
Definition: lixmm.h:20
static LIX_VMA * IntLixVmaFindByGva(const LIX_TASK_OBJECT *Process, QWORD Vma)
Finds if a VMA is being protected and returns the corresponding LIX_VMA structure.
Definition: lixmm.c:726
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
INTSTATUS IntLixMmFetchVma(LIX_TASK_OBJECT *Task, QWORD Address, LIX_VMA *Vma)
Retrieve information about a VMA structure containing a user mode address.
Definition: lixmm.c:581
static void IntLixVmaDestroy(LIX_VMA *Vma)
Destroys a LIX_VMA object.
Definition: lixmm.c:995
#define for_each_vad(Process, _var_name)
Iterator for the process VMAs.
Definition: lixmm.c:38
INTSTATUS IntTranslateVirtualAddress(QWORD Gva, QWORD Cr3, QWORD *PhysicalAddress)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1999
#define TRUE
Definition: intro_types.h:30
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
#define PROC_OPT_KILL_ON_EXPLOIT
Definition: intro_types.h:374
QWORD Gpa
The accessed guest physical address. Valid only for EPT exits.
Definition: guests.h:101
#define LIX_FIELD(Structure, Field)
Macro used to access fields inside the LIX_OPAQUE_FIELDS structure.
Definition: lixguest.h:429
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
#define TRACE(fmt,...)
Definition: glue.h:58
INFO_UD_PENDING * CurrentUD
The currently pending #UD injection on this CPU.
Definition: guests.h:123
#define VM_WRITE
Definition: lixddefs.h:42
#define VM_EXEC
Definition: lixddefs.h:43
QWORD StackLimit
The stack limit for the thread that attempted the execution.
Definition: intro_types.h:1003
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
INTSTATUS IntLixFsrInitMap(QWORD Gva)
Initialize the fast read mechanism.
Definition: lixfastread.c:17
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
Definition: intro_types.h:1309
QWORD Left
Definition: lixddefs.h:317
#define WARNING(fmt,...)
Definition: glue.h:60
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
Definition: intro_types.h:84
static void InitializeListHead(LIST_ENTRY *ListHead)
Definition: introlists.h:69
#define PAGE_SIZE
Definition: common.h:70
Describes the modified zone.
Definition: exceptions.h:893
void * Hook
The EPT hook placed on the VMA when it is being protected.
Definition: lixmm.h:29
#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 PROC_OPT_PROT_EXPLOIT
Blocks malicious execution attempts.
Definition: intro_types.h:352
uint32_t DWORD
Definition: intro_types.h:49
QWORD Flags
Flags for the VMA.
Definition: lixmm.h:25
INTSTATUS IntLixMmFindVmaInRbTree(QWORD MmGva, QWORD Address, QWORD *VmaGva)
Finds the GVA of the VMA which contains a user memory address traversing the VMA rb tree of the mm_st...
Definition: lixmm.c:464
static INTSTATUS IntLixVmaAdjustInternal(LIX_TASK_OBJECT *Task, QWORD Vma)
Checks if the VMA limits have changed and updates the protected memory range.
Definition: lixmm.c:1970
#define NO_ERRORCODE
Definition: processor.h:123
LIX_TASK_OBJECT * Process
Process owning the VMA.
Definition: lixmm.h:27
QWORD DataEnd
The guest virtual address where the data ends.
Definition: lixguest.h:501
enum _INTRO_ACTION INTRO_ACTION
Event actions.
BOOLEAN IntPolicyProcForceBetaIfNeeded(QWORD Flag, void *Process, INTRO_ACTION *Action)
Checks if a forced action should be taken even if the process log-only mode is active.
Definition: introcore.c:2773
#define INT_STATUS_INVALID_OBJECT_TYPE
Definition: introstatus.h:145
#define IC_TAG_NAME
Object name.
Definition: memtags.h:56
INTSTATUS IntLixTaskGetUserStack(LIX_TASK_OBJECT *Task, QWORD *StackPointer, QWORD *StackBase, QWORD *StackLimit)
Finds the user mode stack limits for a Linux process.
Definition: lixprocess.c:2044
The action was allowed, but it has the BETA flag (Introcore is in log-only mode). ...
Definition: intro_types.h:185
QWORD Gva
The guest virtual address of the vm_area_struct this structure is based on.
Definition: lixmm.h:17
INTSTATUS IntLixGetFileName(QWORD FileStruct, char **FileName, DWORD *NameLength, QWORD *DentryGva)
Gets the file-name that corresponds to the provided FileStruct (guest virtual address).
Definition: lixfiles.c:565
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
Definition: introcore.c:2134
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
char Comm[LIX_COMM_SIZE]
The short name of the executable.
Definition: lixprocess.h:44
INTSTATUS IntLixVmaInsert(void *Detour)
Detour handler for "__vma_link_rb" function.
Definition: lixmm.c:1692
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
QWORD MmGva
The guest virtual address of the "mm_struct".
Definition: lixprocess.h:69
DWORD Pid
The task PID.
Definition: lixprocess.h:72
void IntLixFsrUninitMap(void)
Uninitialize the fast read mechanism.
Definition: lixfastread.c:62
TIMER_FRIENDLY void IntDumpGva(QWORD Gva, DWORD Length, QWORD Cr3)
This function is a wrapper over IntDumpGvaEx (it uses RowLength = 16, ElementLength = 1...
Definition: dumper.c:273
static INTSTATUS IntLixVmaIntervalChanged(LIX_VMA *AdjustedVma, QWORD InsertVma)
Simply re-apply the protection for the given vma.
Definition: lixmm.c:1843
QWORD Rsp
The value of the guest RSP register at the moment of execution.
Definition: intro_types.h:1001
INTRO_PROT_OPTIONS ShemuOptions
Flags which describe the way shemu will give detections.
Definition: guests.h:272
void IntLixMmListVmas(QWORD Mm, LIX_TASK_OBJECT *Process)
Definition: lixmm.c:1671
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1194
Definition: lixmm.h:14
struct _LIX_TASK_OBJECT::@136 Protection
Protection specific flags.
INTSTATUS IntUDAddToPendingList(const QWORD Cr3, const QWORD Rip, const QWORD Thread, INFO_UD_PENDING **CurrentPendingUD)
Add a new UD to the list of pending injections.
Definition: udlist.c:30
Holds information about an execution attempt.
Definition: intro_types.h:999
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
INTSTATUS IntKernVirtMemPatchQword(QWORD GuestVirtualAddress, QWORD Data)
Writes 8 bytes in the guest kernel memory.
Definition: introcore.c:932
INTSTATUS IntExceptUserGetExecOriginator(void *Process, EXCEPTION_UM_ORIGINATOR *Originator)
This function is used to get the originator for heap execution.
static INTSTATUS IntLixVmaRemoveProtection(LIX_VMA *Vma, BOOLEAN Mark)
Removes the protection for a VMA.
Definition: lixmm.c:955
QWORD StackBase
The stack base for the thread that attempted the execution.
Definition: intro_types.h:1002
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1197
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
static size_t IntLixVmaGetPageCount(const LIX_VMA *Vma)
Calculate the number of pages available inside a VMA.
Definition: lixmm.c:50
Holds register state.
Definition: glueiface.h:30
#define VM_READ
Definition: lixddefs.h:41
#define ONE_GIGABYTE
Definition: introdefs.h:91
Event structure for EPT violations.
Definition: intro_types.h:1215
Execute-access hook.
Definition: glueiface.h:300
Exploitation for Client Execution.
Definition: intro_types.h:1157
DWORD Length
The length of the instruction.
Definition: intro_types.h:1004
LIST_ENTRY Link
Linked list entry.
Definition: lixmm.h:16
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
Definition: lixksym.c:1399
#define LIX_VMA_MAX_GUEST
Max VMAs allowed for a process.
Definition: lixmm.c:33
Invalid selector.
Definition: glueiface.h:185
void IntAlertFillLixProcess(const LIX_TASK_OBJECT *Task, INTRO_PROCESS *EventProcess)
Saves information about a Linux process inside an event.
Definition: alerts.c:1264
#define PAGE_MASK
Definition: pgtable.h:35
INTSTATUS IntLixMmPopulateVmas(LIX_TASK_OBJECT *Task)
Populate the Introcore VMAs linked list by iterating the one inside the guest.
Definition: lixmm.c:1510
INTSTATUS IntAlertFillExecContext(QWORD Cr3, INTRO_EXEC_CONTEXT *ExecContext)
Fills the current execution context.
Definition: alerts.c:31
#define INT_STATUS_INVALID_PARAMETER_2
Definition: introstatus.h:65
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:271
QWORD Gla
The accessed guest virtual address. Valid only for EPT exits.
Definition: guests.h:102
#define LIX_VMA_PROT_MASK
The bit in vma.vm_flags used to mark the VMA protection status.
Definition: lixmm.c:23
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
static INTSTATUS IntVmaMarkProtection(LIX_VMA *Vma, BOOLEAN Protected)
Marks the VMA as either protected or unprotected.
Definition: lixmm.c:898
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:30
static INTSTATUS IntLixMmFindVmaInLinkedList(QWORD MmGva, QWORD Address, QWORD *VmaGva, BOOLEAN Backward)
Finds the GVA of the VMA which contains a user memory address by iterating the VMAs linked list of a ...
Definition: lixmm.c:359
QWORD File
The Gva of the file this VMA maps to. Can be 0 which means this VMA is not a memory mapped file...
Definition: lixmm.h:23
INTSTATUS IntLixVmaAdjust(void *Detour)
Detour handler for in-guest functions adjusting VMA ranges.
Definition: lixmm.c:2052
#define INTRO_OPT_NOTIFY_ENGINES
Send suspicious pages to be scanned by third party scan engines.
Definition: intro_types.h:459
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
QWORD Mask
The protection flags enabled for this process.
Definition: lixprocess.h:84
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68