Bitdefender Hypervisor Memory Introspection
lixksym.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixksym.h"
6 #include "guests.h"
7 
8 
9 #define KSYM_NUM_SYMBOLS_CAP 200000
10 #define KSYM_TOKEN_TABLE_SIZE_CAP 2000
11 #define KSYM_NAMES_CACHE_SIZE_CAP 2000000
12 #define KSYM_TOKEN_ARRAY_CACHE_SIZE 256
13 
14 typedef struct _KALLSYMS_BUFFERS
19 {
20 
22 
26  union
27  {
30  };
31 
34 
35  char *NamesBuffer;
36 
37  union
38  {
41  };
42 
43  char *TokenTable;
45 
47 
50 
51 
56 
57 
58 static DWORD
60  _In_ DWORD Offset,
61  _In_ DWORD MaxLength,
62  _Out_ char *Name
63  )
75 {
76  BOOLEAN skipped = FALSE;
77  const char *pKallsymsNames = gKallsymsBuffers.NamesBuffer + Offset;
78  const BYTE *pData = (const BYTE *)pKallsymsNames;
79  BYTE length = *pData;
80  DWORD nextOffset = 0;
81 
82  if (0 == length)
83  {
84  WARNING("[WARNING] Wrong symbol size %d. \n", length);
85  return 0;
86  }
87 
88  pData++;
89  nextOffset = Offset + length + 1;
90 
91  while (length)
92  {
93  const char *tptr = &gKallsymsBuffers.TokenTable[gKallsymsBuffers.TokenIndex[*pData]];
94  pData++;
95  length--;
96 
97  while (*tptr)
98  {
99  if (skipped)
100  {
101  if (MaxLength <= 1)
102  {
103  goto _tail;
104  }
105 
106  *Name = *tptr;
107  Name++;
108  MaxLength--;
109  }
110  else
111  {
112  skipped = TRUE;
113  }
114 
115  ++tptr;
116  }
117  }
118 
119 _tail:
120  if (MaxLength)
121  {
122  // Put the final NULL-terminator
123  *Name = '\0';
124  }
125 
126  return nextOffset;
127 }
128 
129 
130 static QWORD
132  _In_ INT32 Index
133  )
141 {
142  if (!LIX_FIELD(Info, HasKsymRelative))
143  {
144  return gKallsymsBuffers.AddressesBuffer[Index];
145  }
146 
147  if (!LIX_FIELD(Info, HasKsymAbsolutePercpu))
148  {
149  return gKallsymsBuffers.RelativeBase + (DWORD)gKallsymsBuffers.IndexesBuffer[Index];
150  }
151 
152  if (gKallsymsBuffers.IndexesBuffer[Index] >= 0)
153  {
154  return gKallsymsBuffers.IndexesBuffer[Index];
155  }
156 
157  return gKallsymsBuffers.RelativeBase - 1 - gKallsymsBuffers.IndexesBuffer[Index];
158 }
159 
160 
161 static INTSTATUS
163  _Out_ QWORD *Address
164  )
175 {
176  INTSTATUS status = INT_STATUS_SUCCESS;
177  QWORD currentAddr = gLixGuest->Layout.RoDataStart & PAGE_MASK;
178  QWORD startAddr = 0;
179  INT32 *ptr = NULL;
180 
182  if (!ptr)
183  {
185  }
186 
187  for (; currentAddr < gLixGuest->Layout.RoDataEnd; currentAddr += PAGE_SIZE)
188  {
189  INT32 *pPage = NULL;
190 
191  status = IntVirtMemMap(currentAddr, PAGE_SIZE, gGuest.Mm.SystemCr3, 0, &pPage);
192  if (!INT_SUCCESS(status))
193  {
194  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
195  break;
196  }
197 
198  for (DWORD i = 0; i < (PAGE_SIZE / 4) - 16; i++)
199  {
200  if (pPage[i] < 0)
201  {
202  continue;
203  }
204 
205  // 16 ordered int's (assume they are > 0)
206  if (pPage[i] > pPage[i + 1] ||
207  pPage[i + 1] >= pPage[i + 2] ||
208  pPage[i + 2] >= pPage[i + 3] ||
209  pPage[i + 3] >= pPage[i + 4] ||
210  pPage[i + 4] >= pPage[i + 5] ||
211  pPage[i + 5] >= pPage[i + 6] ||
212  pPage[i + 6] >= pPage[i + 7] ||
213  pPage[i + 7] >= pPage[i + 8] ||
214  pPage[i + 8] >= pPage[i + 9] ||
215  pPage[i + 9] >= pPage[i + 10] ||
216  pPage[i + 10] >= pPage[i + 11] ||
217  pPage[i + 11] >= pPage[i + 12] ||
218  pPage[i + 12] >= pPage[i + 13] ||
219  pPage[i + 13] >= pPage[i + 14] ||
220  pPage[i + 14] >= pPage[i + 15])
221  {
222  continue;
223  }
224 
225  startAddr = currentAddr + i * 4ull;
226 
227  break;
228  }
229 
230  if (startAddr)
231  {
232  status = IntVirtMemRead(startAddr, PAGE_SIZE, gGuest.Mm.SystemCr3, ptr, NULL);
233  if (!INT_SUCCESS(status))
234  {
235  ERROR("[ERROR] IntVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", startAddr, status);
236  break;
237  }
238 
239  for (DWORD i = 1; i < PAGE_SIZE / 4 - 3; i++)
240  {
241  // Is this is the startup_64/_text ?
242  if (LIX_FIELD(Info, HasKsymAbsolutePercpu))
243  {
244  if (ptr[i] == -1 && ptr[i + 1] == -1)
245  {
246  break;
247  }
248  }
249  else
250  {
251  if (ptr[i] == 0 && ptr[i + 1] == 0)
252  {
253  break;
254  }
255  }
256 
257  // everything must be ordered
258  if (ptr[i] < ptr[i - 1])
259  {
260  startAddr = 0;
261  break;
262  }
263  }
264  }
265 
266  IntVirtMemUnmap(&pPage);
267 
268  if (startAddr)
269  {
270  TRACE("[KALLSYMS RELATIVE] Found indexes start @%llx\n", startAddr);
271  break;
272  }
273  }
274 
276 
277  if (!INT_SUCCESS(status))
278  {
279  return status;
280  }
281 
282  if (!startAddr)
283  {
284  return INT_STATUS_NOT_FOUND;
285  }
286 
287  *Address = startAddr;
288 
289  return INT_STATUS_SUCCESS;
290 }
291 
292 
293 static INTSTATUS
295  _In_ QWORD StartAddress
296  )
309 {
310  INTSTATUS status = INT_STATUS_SUCCESS;
311  QWORD currentAddr = 0;
312  QWORD endAddr = 0;
313  BOOLEAN firstNegative = FALSE;
314  BOOLEAN firstPositive = FALSE;
315 
316  for (currentAddr = StartAddress; currentAddr < gLixGuest->Layout.RoDataEnd;)
317  {
318  INT32 *pPage = NULL;
319  DWORD offset = currentAddr & PAGE_OFFSET;
320 
321  status = IntVirtMemMap(currentAddr, PAGE_SIZE - offset, gGuest.Mm.SystemCr3, 0, &pPage);
322  if (!INT_SUCCESS(status))
323  {
324  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
325  return status;
326  }
327 
328  for (DWORD i = 0; i < ((PAGE_SIZE - offset) / 4) - 1; i++)
329  {
330  if (pPage[i] == -1 && pPage[i + 1] == -1)
331  {
332  firstNegative = TRUE;
333  continue;
334  }
335 
336  if (!firstNegative)
337  {
338  continue;
339  }
340 
341  if (!firstPositive && pPage[i] > 0)
342  {
343  firstPositive = TRUE;
344  continue;
345  }
346 
347  if (*(QWORD *)(pPage + i) == gGuest.KernelVa)
348  {
349  endAddr = currentAddr + i * 4ull;
350  break;
351  }
352 
353  if (pPage[i] == 0)
354  {
355  endAddr = currentAddr + i * 4ull;
356  break;
357  }
358 
359  if (LIX_FIELD(Info, HasKsymAbsolutePercpu))
360  {
361  if ((!firstPositive && pPage[i] < 0) ||
362  (firstPositive && pPage[i + 1] >= pPage[i]))
363  {
364  continue;
365  }
366  }
367  else
368  {
369  if (pPage[i] <= pPage[i + 1])
370  {
371  continue;
372  }
373  }
374 
375  endAddr = currentAddr + i * 4ull;
376  break;
377  }
378 
379  IntVirtMemUnmap(&pPage);
380 
381  currentAddr += PAGE_SIZE - offset;
382 
383  if (endAddr)
384  {
385  QWORD relativeBase = 0;
386  DWORD numberOfNames = 0;
387  DWORD foundNames = (DWORD)(endAddr - StartAddress) / 4;
388 
389  status = IntKernVirtMemFetchQword(ALIGN_UP(endAddr, 8), &relativeBase);
390  if (!INT_SUCCESS(status))
391  {
392  ERROR("[ERROR] IntKernVirtMemFetchQword failed for GVA 0x%016llx with status: 0x%08x\n",
393  endAddr, status);
394  endAddr = 0;
395  continue;
396  }
397 
398  if (relativeBase != gGuest.KernelVa)
399  {
400  endAddr = 0;
401  continue;
402  }
403 
404  if (LIX_FIELD(Info, HasKsymSize))
405  {
406  // Skip the sizes region
407  // * 2 because each offset entry is 4 bytes long and the size of a kallsmys_size entry is 8 bytes.
408  endAddr += (endAddr - StartAddress) * 2;
409  }
410 
411  status = IntKernVirtMemFetchDword(ALIGN_UP(endAddr, 8) + 8, &numberOfNames);
412  if (!INT_SUCCESS(status))
413  {
414  ERROR("[ERROR] IntKernVirtMemFetchDword failed for GVA 0x%016llx with status: 0x%08x\n",
415  endAddr, status);
416  endAddr = 0;
417  continue;
418  }
419 
420  TRACE("[KALLSYMS] num_symbols (found): %d\n", foundNames);
421 
422  // Did we parsed too much or too little (assume an error of 0x40)
423  if ((foundNames > numberOfNames &&
424  foundNames - numberOfNames > 0x40) ||
425  (foundNames < numberOfNames &&
426  numberOfNames - foundNames > 0x40))
427  {
428  endAddr = 0;
429  continue;
430  }
431 
432  if (numberOfNames > KSYM_NUM_SYMBOLS_CAP)
433  {
434  ERROR("[ERROR] Kallsyms number of names exceeds the limit: %u vs %u",
435  numberOfNames, KSYM_NUM_SYMBOLS_CAP);
436  continue;
437  }
438 
439  gKallsymsBuffers.RelativeBase = relativeBase;
440 
441  gKallsymsBuffers.NumberOfNames = numberOfNames;
442  gKallsymsBuffers.Indexes = ALIGN_DOWN(endAddr - numberOfNames * 4ull, 8);
443 
444  if (LIX_FIELD(Info, HasKsymSize))
445  {
446  // Also skip the sizes region ( 8 * numberOfSymbols)
447  gKallsymsBuffers.Indexes -= numberOfNames * 8ull;
448  }
449 
450  gKallsymsBuffers.Names = ALIGN_UP(endAddr, 8) + 16;
451 
452  break;
453  }
454  }
455 
456  if (0 == gKallsymsBuffers.NumberOfNames)
457  {
458  return INT_STATUS_NOT_FOUND;
459  }
460 
461  return INT_STATUS_SUCCESS;
462 }
463 
464 
465 static INTSTATUS
467  void
468  )
475 {
476  INTSTATUS status = INT_STATUS_SUCCESS;
477  QWORD tableOffsetsStartAddr = 0;
478 
479  status = IntKsymRelativeFindOffsetTableStart(&tableOffsetsStartAddr);
480  if (!INT_SUCCESS(status))
481  {
482  ERROR("[ERROR] IntKsymRelativeFindOffsetTableStart failed with status: 0x%08x\n", status);
483  return status;
484  }
485 
486  status = IntKsymRelativeFindOffsetTableEnd(tableOffsetsStartAddr);
487  if (!INT_SUCCESS(status))
488  {
489  ERROR("[ERROR] IntKsymRelativeFindOffsetTableEnd failed with status: 0x%08x\n", status);
490  return status;
491  }
492 
493  return INT_STATUS_SUCCESS;
494 }
495 
496 
497 static INTSTATUS
499  void
500  )
507 {
508  INTSTATUS status = INT_STATUS_SUCCESS;
510  QWORD addrStart = 0;
511  QWORD numGva = 0;
512  QWORD prev = 0;
513  INT32 num = 0;
514  QWORD *pPage = NULL;
515  BOOLEAN foundStart = FALSE;
516 
517  while (gvaStart < gLixGuest->Layout.RoDataEnd)
518  {
519  BOOLEAN redoPage = FALSE;
520 
521  status = IntVirtMemMap(gvaStart, PAGE_SIZE, gGuest.Mm.SystemCr3, 0, &pPage);
522  if (!INT_SUCCESS(status))
523  {
524  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", gvaStart, status);
525  return status;
526  }
527 
528  if (!foundStart)
529  {
530  for (DWORD i = 0; i < (PAGE_SIZE / 8) - 8; i++)
531  {
532  // Make sure each of the eight pointers point inside the code section...
533  if ((pPage[i] < gLixGuest->Layout.CodeStart || pPage[i] > gLixGuest->Layout.CodeEnd) ||
534  (pPage[i + 1] < gLixGuest->Layout.CodeStart || pPage[i + 1] > gLixGuest->Layout.CodeEnd) ||
535  (pPage[i + 2] < gLixGuest->Layout.CodeStart || pPage[i + 2] > gLixGuest->Layout.CodeEnd) ||
536  (pPage[i + 3] < gLixGuest->Layout.CodeStart || pPage[i + 3] > gLixGuest->Layout.CodeEnd) ||
537  (pPage[i + 4] < gLixGuest->Layout.CodeStart || pPage[i + 4] > gLixGuest->Layout.CodeEnd) ||
538  (pPage[i + 5] < gLixGuest->Layout.CodeStart || pPage[i + 5] > gLixGuest->Layout.CodeEnd) ||
539  (pPage[i + 6] < gLixGuest->Layout.CodeStart || pPage[i + 6] > gLixGuest->Layout.CodeEnd) ||
540  (pPage[i + 7] < gLixGuest->Layout.CodeStart || pPage[i + 7] > gLixGuest->Layout.CodeEnd))
541  {
542  continue;
543  }
544 
545  // ... and each one points inside the first two pages...
546  if (pPage[i] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
547  pPage[i + 1] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
548  pPage[i + 2] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
549  pPage[i + 3] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
550  pPage[i + 4] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
551  pPage[i + 5] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
552  pPage[i + 6] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
553  pPage[i + 7] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE)
554  {
555  continue;
556  }
557 
558  // ... and they are ordered.
559  if (pPage[i] < pPage[i + 1] &&
560  pPage[i + 1] < pPage[i + 2] &&
561  pPage[i + 2] < pPage[i + 3] &&
562  pPage[i + 3] < pPage[i + 4] &&
563  pPage[i + 4] < pPage[i + 5] &&
564  pPage[i + 5] < pPage[i + 6] &&
565  pPage[i + 6] < pPage[i + 7])
566  {
567  addrStart = gvaStart + i * 8ull;
568  prev = pPage[i];
569 
570  foundStart = TRUE;
571 
572  break;
573  }
574  }
575  }
576  else
577  {
578  for (DWORD i = 0; i < PAGE_SIZE / 8; i++)
579  {
580  QWORD val = pPage[i];
581 
582  if ((val > 0) && (val < 0x3FFFF))
583  {
584  num = (INT32)val;
585  numGva = gvaStart + i * 8ull;
586  TRACE("[INFO] Found num_symbols start at 0x%016llx: %d\n", gvaStart + i * 8ull, num);
587  break;
588  }
589 
590  // Is the pointer still good ?!
591  if (IS_KERNEL_POINTER_LIX(val) && prev <= val)
592  {
593  prev = val;
594  continue;
595  }
596 
597  if (IS_KERNEL_POINTER_LIX(val) && prev > val)
598  {
599  WARNING("[WARNING] Unordered list: 0x%016llx 0x%016llx\n", prev, val);
600  }
601 
602  redoPage = TRUE;
603  foundStart = FALSE;
604  addrStart = num = 0;
605 
606  WARNING("[WARNING] Found an invalid pointer (prev 0x%016llx) 0x%016llx @ 0x%016llx\n",
607  prev, val, gvaStart + i * 8ull);
608  break;
609  }
610  }
611 
612  IntVirtMemUnmap(&pPage);
613 
614  if (addrStart && num)
615  {
616  break;
617  }
618 
619  if (!redoPage)
620  {
621  gvaStart += PAGE_SIZE;
622  }
623  }
624 
625  if (!addrStart || !num)
626  {
627  return INT_STATUS_NOT_FOUND;
628  }
629 
630  // Now it's the to calculate and determine addresses
631  gKallsymsBuffers.NumberOfNames = num;
632  gKallsymsBuffers.Addresses = numGva - num * 8ull;
633  gKallsymsBuffers.Names = numGva + 8;
634 
635  return INT_STATUS_SUCCESS;
636 }
637 
638 
639 static INTSTATUS
641  _In_ QWORD StartAddress,
642  _Out_ QWORD *EndAddress
643  )
655 {
656  INTSTATUS status = INT_STATUS_SUCCESS;
657  QWORD *pMarkers = NULL;
658  QWORD *pAddr = NULL;
659  QWORD currentAddr = StartAddress;
660  QWORD prevAddr = 0;
661 
662  if (StartAddress % sizeof(QWORD) != 0)
663  {
664  ERROR("[ERROR] The provided address is not aligned (0x%016llx)!\n", StartAddress);
666  }
667 
668  // Skip all the QWORDS until we have a one bigger than 0xffffffff (that's where the token table starts)
669  for (DWORD i = 0; i < 2 * PAGE_SIZE / 8; i++)
670  {
671  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
672  {
673  status = IntVirtMemMap(currentAddr, PAGE_REMAINING(currentAddr & PAGE_OFFSET), gGuest.Mm.SystemCr3, 0, &pMarkers);
674  if (!INT_SUCCESS(status))
675  {
676  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
677  return status;
678  }
679 
680  pAddr = pMarkers;
681  }
682 
683  if (pMarkers == NULL)
684  {
685  return INT_STATUS_NOT_FOUND;
686  }
687 
688  if (*pMarkers > 0xffffffff)
689  {
690  *EndAddress = currentAddr;
691 
692  status = INT_STATUS_SUCCESS;
693  goto _exit;
694  }
695 
696  prevAddr = currentAddr;
697  currentAddr += 8;
698 
699  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
700  {
701  IntVirtMemUnmap(&pAddr);
702  pMarkers = NULL;
703  }
704  else
705  {
706  pMarkers++;
707  }
708  }
709 
710  status = INT_STATUS_NOT_FOUND;
711 
712 _exit:
713  if (pMarkers != NULL)
714  {
715  IntVirtMemUnmap(&pMarkers);
716  }
717 
718  return status;
719 }
720 
721 static INTSTATUS
723  _In_ QWORD StartAddress,
724  _In_ QWORD *EndAddress
725  )
739 {
740  INTSTATUS status = INT_STATUS_SUCCESS;
741  DWORD *pMarkers = NULL;
742  DWORD *pAddr = NULL;
743  DWORD size = 0;
744  DWORD remaining = 0;
745  QWORD currentAddr = StartAddress;
746 
747  if (StartAddress % sizeof(DWORD) != 0)
748  {
749  ERROR("[ERROR] The provided address is not aligned (0x%016llx)!\n", StartAddress);
751  }
752 
753  // We iterate max 2048 integers to find the end of kallsyms_markers table.
754  for (DWORD i = 0; i < (2 * PAGE_SIZE) / sizeof(*pMarkers); i++)
755  {
756  if (NULL == pMarkers)
757  {
758  // Because we compare pMarkers[i] with pMarkers[i + 1] we have to make sure that we are always mapping
759  // at least 2 * sizeof(*pMarkers) bytes.
760  size = PAGE_REMAINING(currentAddr);
761 
762  // This is ok, because size will never be 0, and any currentAddr is always incremented by sizeof(DWORD).
763  // StartAddress is also aligned to 8-bytes.
764  if (size == sizeof(*pMarkers))
765  {
766  // Here, we can actually add PAGE_SIZE, but it will then go through the slow IntVirtMemMap mechanism
767  // which copies the mapped memory into an allocated buffer, because the memory will be split into two
768  // pages. It should be faster to do it this way, because we avoid the huge memcpy and the mapping is
769  // cached, so for the second page another call to xen will not be issued.
770  size += sizeof(*pMarkers);
771  }
772 
773  remaining = size - sizeof(*pMarkers);
774 
775  status = IntVirtMemMap(currentAddr, size, gGuest.Mm.SystemCr3, 0, &pAddr);
776  if (!INT_SUCCESS(status))
777  {
778  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
779  return status;
780  }
781 
782  pMarkers = pAddr;
783  }
784 
785  currentAddr += sizeof(*pMarkers);
786  remaining -= sizeof(*pMarkers);
787 
788  if (*pMarkers >= * (pMarkers + 1))
789  {
790  *EndAddress = currentAddr;
791 
792  status = INT_STATUS_SUCCESS;
793  goto _exit;
794  }
795 
796  pMarkers++;
797 
798  if (remaining == 0)
799  {
800  IntVirtMemUnmap(&pAddr);
801  pMarkers = NULL;
802  }
803  }
804 
805  status = INT_STATUS_NOT_FOUND;
806 
807 _exit:
808  if (pMarkers != NULL)
809  {
810  IntVirtMemUnmap(&pMarkers);
811  }
812 
813  return status;
814 }
815 
816 
817 static INTSTATUS
819  _In_ QWORD StartAddress,
820  _In_ QWORD *EndAddress
821  )
834 {
835  INTSTATUS status = INT_STATUS_SUCCESS;
836  BYTE *pSymbol = NULL;
837  QWORD prevAddr = 0;
838  QWORD currentAddr = StartAddress;
839 
840  for (INT32 i = 0; i < gKallsymsBuffers.NumberOfNames; i++)
841  {
842  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
843  {
844  status = IntVirtMemMap(currentAddr, PAGE_REMAINING(currentAddr & PAGE_OFFSET), gGuest.Mm.SystemCr3, 0, &pSymbol);
845  if (!INT_SUCCESS(status))
846  {
847  ERROR("[ERROR] IntVirtMemMap failed for 0x%016llx: 0x%08x\n", currentAddr, status);
848  return status;
849  }
850  }
851 
852  if (pSymbol == NULL)
853  {
854  return INT_STATUS_NOT_FOUND;
855  }
856 
857  prevAddr = currentAddr;
858  currentAddr += *pSymbol + 1ull;
859 
860  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
861  {
862  IntVirtMemUnmap(&pSymbol);
863  pSymbol = NULL;
864  }
865  else
866  {
867  pSymbol += *pSymbol + 1ull;
868  }
869  }
870 
871  if (NULL != pSymbol)
872  {
873  IntVirtMemUnmap(&pSymbol);
874  }
875 
876  *EndAddress = currentAddr;
877 
878  return INT_STATUS_SUCCESS;
879 }
880 
881 
882 static INTSTATUS
884  _In_ QWORD TokenTableStart,
885  _Out_ QWORD *IndexesTableStart
886  )
899 {
900  INTSTATUS status = INT_STATUS_SUCCESS;
901  WORD indexes[0x5] = { 0 };
902  char tokenSlice[0x30] = { 0 };
903  DWORD remainingTokenLength = (DWORD)sizeof(tokenSlice);
904  QWORD currentAddr = TokenTableStart;
905  QWORD prevAddr = 0;
906  WORD *pIndex = NULL;
907 
908  status = IntKernVirtMemRead(TokenTableStart, sizeof(tokenSlice), tokenSlice, NULL);
909  if (!INT_SUCCESS(status))
910  {
911  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", TokenTableStart, status);
912  return status;
913  }
914 
915  indexes[0] = 0;
916  for (DWORD i = 1; i < ARRAYSIZE(indexes); i++)
917  {
918  WORD length = (WORD)strlen_s(&tokenSlice[indexes[i - 1]], remainingTokenLength) + 1;
919  indexes[i] = indexes[i - 1] + length;
920  remainingTokenLength -= length;
921 
922  if ((int)remainingTokenLength < 0)
923  {
924  ERROR("[ERROR] %zu bytes not enough to find indexes. Stopped at %d!\n", sizeof(tokenSlice), i);
926  }
927  }
928 
929  // Now search the indexes in memory, WORD by WORD
930  for (DWORD i = 0; i < PAGE_SIZE / 8; i++)
931  {
932  WORD idx[sizeof(indexes) / sizeof(indexes[0])];
933  DWORD j;
934  BOOLEAN found = FALSE;
935 
936  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
937  {
938  status = IntVirtMemMap(currentAddr, PAGE_REMAINING(currentAddr & PAGE_OFFSET), gGuest.Mm.SystemCr3, 0, &pIndex);
939  if (!INT_SUCCESS(status))
940  {
941  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
942  return status;
943  }
944  }
945 
946  if (PAGE_FRAME_NUMBER(currentAddr + sizeof(idx)) != PAGE_FRAME_NUMBER(currentAddr))
947  {
948  status = IntKernVirtMemRead(currentAddr, sizeof(idx), idx, NULL);
949  if (!INT_SUCCESS(status))
950  {
951  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
952  break;
953  }
954  }
955  else
956  {
957  if (pIndex == NULL)
958  {
959  return INT_STATUS_NOT_FOUND;
960  }
961 
962  memcpy(idx, pIndex, sizeof(idx));
963  }
964 
965  found = TRUE;
966  for (j = 0; j < ARRAYSIZE(idx); j++)
967  {
968  if (idx[j] != indexes[j])
969  {
970  found = FALSE;
971  break;
972  }
973  }
974 
975  if (found)
976  {
977  *IndexesTableStart = currentAddr;
978 
979  status = INT_STATUS_SUCCESS;
980  goto _exit;
981  }
982 
983  prevAddr = currentAddr;
984  currentAddr += 8;
985 
986  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
987  {
988  IntVirtMemUnmap(&pIndex);
989  pIndex = NULL;
990  }
991  else
992  {
993  pIndex = (WORD *)((BYTE *)pIndex + 8);
994  }
995  }
996 
997  status = INT_STATUS_NOT_FOUND;
998 
999 _exit:
1000  if (pIndex != NULL)
1001  {
1002  IntVirtMemUnmap(&pIndex);
1003  }
1004 
1005  return status;
1006 }
1007 
1008 
1009 INTSTATUS
1011  void
1012  )
1028 {
1029  INTSTATUS status = INT_STATUS_SUCCESS;
1030  QWORD currentAddr = 0;
1031  QWORD tokenTableStart = 0;
1032  DWORD size = 0;
1033  char *pTokenTable = NULL;
1034  char *pNames = NULL;
1035  QWORD *pAddresses = NULL;
1036 
1037  if (gGuest.OSType != introGuestLinux)
1038  {
1039  BUG_ON(TRUE);
1040 
1042  }
1043 
1044  if (LIX_FIELD(Info, HasKsymRelative))
1045  {
1046  status = IntKsymInitRelative();
1047  if (!INT_SUCCESS(status))
1048  {
1049  ERROR("[ERROR] IntKsymInitRelative failed: %08x\n", status);
1050  return status;
1051  }
1052 
1053  TRACE("[KALLSYMS] indexes : 0x%016llx\n", gKallsymsBuffers.Indexes);
1054  TRACE("[KALLSYMS] rel_base : 0x%016llx\n", gKallsymsBuffers.RelativeBase);
1055  }
1056  else
1057  {
1058  status = IntKsymInitAbsolute();
1059  if (!INT_SUCCESS(status))
1060  {
1061  ERROR("[ERROR] IntKsymInitAbsolute failed: %08x\n", status);
1062  return status;
1063  }
1064 
1065  TRACE("[KALLSYMS] addresses : 0x%016llx\n", gKallsymsBuffers.Addresses);
1066  }
1067 
1068  TRACE("[KALLSYMS] num_symbols : %d\n", gKallsymsBuffers.NumberOfNames);
1069  TRACE("[KALLSYMS] names : 0x%016llx\n", gKallsymsBuffers.Names);
1070 
1071  status = IntKsymFindNamesTableEnd(gKallsymsBuffers.Names, &currentAddr);
1072  if(!INT_SUCCESS(status))
1073  {
1074  ERROR("[ERROR] IntKsymFindNamesTableEnd failed with status: 0x%08x\n", status);
1075  }
1076 
1077  currentAddr = ALIGN_UP(currentAddr, 8);
1078 
1079  if (LIX_FIELD(Info, HasKsymReducedSize))
1080  {
1081  status = IntKsymFindMarkersReducedTableEnd(currentAddr, &currentAddr);
1082  }
1083  else
1084  {
1085  status = IntKsymFindMarkersTableEnd(currentAddr, &currentAddr);
1086  }
1087 
1088  if (!INT_SUCCESS(status))
1089  {
1090  ERROR("[ERROR] Failed finding the start of token_table!\n");
1091  return INT_STATUS_NOT_FOUND;
1092  }
1093 
1094  tokenTableStart = ALIGN_UP(currentAddr, 8);
1095  TRACE("[KALLSYMS] token_table : 0x%016llx\n", tokenTableStart);
1096 
1097  status = IntKsymFindIndexesTableStart(tokenTableStart, &currentAddr);
1098  if (!INT_SUCCESS(status))
1099  {
1100  ERROR("[ERROR] IntKsymFindIndexesTableStart failed with status: 0x%08x\n", status);
1101  return status;
1102  }
1103 
1104  gKallsymsBuffers.TokenTableSize = (DWORD)(currentAddr - tokenTableStart);
1105 
1106  if (gKallsymsBuffers.TokenTableSize > KSYM_TOKEN_TABLE_SIZE_CAP)
1107  {
1108  ERROR("[ERROR] Tokens table size exceeds the introcore limit: %u vs %u\n",
1109  gKallsymsBuffers.TokenTableSize, KSYM_TOKEN_TABLE_SIZE_CAP);
1110 
1112  }
1113 
1114  TRACE("[KALLSYMS] token_size : %08x\n", gKallsymsBuffers.TokenTableSize);
1115  TRACE("[KALLSYMS] token_index : 0x%016llx\n", currentAddr);
1116 
1117  status = IntKernVirtMemRead(currentAddr,
1118  sizeof(gKallsymsBuffers.TokenIndex),
1119  gKallsymsBuffers.TokenIndex,
1120  NULL);
1121  if (!INT_SUCCESS(status))
1122  {
1123  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1124  return status;
1125  }
1126 
1127  pTokenTable = HpAllocWithTag(gKallsymsBuffers.TokenTableSize, IC_TAG_KSYM);
1128  if (NULL == pTokenTable)
1129  {
1131  }
1132 
1133  status = IntKernVirtMemRead(tokenTableStart, gKallsymsBuffers.TokenTableSize, pTokenTable, NULL);
1134  if (!INT_SUCCESS(status))
1135  {
1136  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1137  goto _exit;
1138  }
1139 
1140  size = (DWORD)(tokenTableStart - gKallsymsBuffers.Names);
1141 
1142  if (size > KSYM_NAMES_CACHE_SIZE_CAP)
1143  {
1144  ERROR("[ERROR] Kallsyms names size exceeds the introcore limit: %u vs %u",
1146 
1148  goto _exit;
1149  }
1150 
1151  // Cache the names. Ubuntu 16.04 takes ~1.1MB
1152 
1153  TRACE("[INFO] Cache kallsyms names: %d bytes\n", size);
1154 
1155  pNames = HpAllocWithTag(size, IC_TAG_KSYM);
1156  if (NULL == pNames)
1157  {
1159  goto _exit;
1160  }
1161 
1162  status = IntKernVirtMemRead(gKallsymsBuffers.Names, size, pNames, NULL);
1163  if (!INT_SUCCESS(status))
1164  {
1165  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1166  goto _exit;
1167  }
1168 
1169  // Cache the addresses (an array of sorted QWORDS). Ubuntu 16.04 takes ~800kb
1170 
1171  size = (DWORD)(gKallsymsBuffers.NumberOfNames * 8);
1172 
1173  TRACE("[INFO] Cache kallsyms addresses: %d bytes\n", size);
1174 
1175  pAddresses = HpAllocWithTag(size, IC_TAG_KSYM);
1176  if (NULL == pAddresses)
1177  {
1179  goto _exit;
1180  }
1181 
1182  status = IntKernVirtMemRead(gKallsymsBuffers.Addresses, size, pAddresses, NULL);
1183  if (!INT_SUCCESS(status))
1184  {
1185  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1186  goto _exit;
1187  }
1188 
1189  gKallsymsBuffers.TokenTable = pTokenTable;
1190  gKallsymsBuffers.AddressesBuffer = pAddresses;
1191  gKallsymsBuffers.NamesBuffer = pNames;
1192 
1193  gKallsymsBuffers.Initialized = TRUE;
1194 
1195  return INT_STATUS_SUCCESS;
1196 
1197 _exit:
1198  if (NULL != pTokenTable)
1199  {
1200  HpFreeAndNullWithTag(&pTokenTable, IC_TAG_KSYM);
1201  }
1202 
1203  if (NULL != pAddresses)
1204  {
1205  HpFreeAndNullWithTag(&pAddresses, IC_TAG_KSYM);
1206  }
1207 
1208  if (NULL != pNames)
1209  {
1211  }
1212 
1213  return status;
1214 }
1215 
1216 
1217 void
1219  void
1220  )
1224 {
1225  if (NULL != gKallsymsBuffers.TokenTable)
1226  {
1227  HpFreeAndNullWithTag(&gKallsymsBuffers.TokenTable, IC_TAG_KSYM);
1228  }
1229 
1230  if (NULL != gKallsymsBuffers.AddressesBuffer)
1231  {
1232  HpFreeAndNullWithTag(&gKallsymsBuffers.AddressesBuffer, IC_TAG_KSYM);
1233  }
1234 
1235  if (NULL != gKallsymsBuffers.NamesBuffer)
1236  {
1237  HpFreeAndNullWithTag(&gKallsymsBuffers.NamesBuffer, IC_TAG_KSYM);
1238  }
1239 
1240  gKallsymsBuffers.Initialized = FALSE;
1241 }
1242 
1243 
1244 INTSTATUS
1246  _In_ QWORD Gva,
1247  _In_ DWORD Length,
1248  _Out_ char *SymName,
1249  _Out_opt_ QWORD *SymStart,
1250  _Out_opt_ QWORD *SymEnd
1251  )
1271 {
1272  DWORD offset;
1273  QWORD symStart;
1274 
1275  INT32 high, low;
1276 
1277  if (NULL == SymName)
1278  {
1280  }
1281 
1282  if (!gKallsymsBuffers.Initialized)
1283  {
1285  }
1286 
1287  // Directly return if we are outside of the kernel
1288  if (Gva > gGuest.KernelVa + gGuest.KernelSize)
1289  {
1290  return INT_STATUS_NOT_FOUND;
1291  }
1292 
1293  low = 0;
1294  offset = 0;
1295  high = gKallsymsBuffers.NumberOfNames;
1296 
1297  while (high - low > 1)
1298  {
1299  INT32 mid = low + (high - low) / 2;
1300 
1301  if (IntKsymGetAddress(mid) <= Gva)
1302  {
1303  low = mid;
1304  }
1305  else
1306  {
1307  high = mid;
1308  }
1309  }
1310 
1311  // Search for the first aliased symbol. Aliased symbols are symbols with the same address.
1312  while (low && IntKsymGetAddress(low - 1) == IntKsymGetAddress(low))
1313  {
1314  --low;
1315  }
1316 
1317  symStart = IntKsymGetAddress(low);
1318 
1319  if (SymEnd)
1320  {
1321  INT32 next = low + 1;
1322 
1323  // Skip until the next one is bigger
1324  while (next < gKallsymsBuffers.NumberOfNames &&
1325  symStart == IntKsymGetAddress(next))
1326  {
1327  ++next;
1328  }
1329 
1330  *SymEnd = IntKsymGetAddress(next);
1331  }
1332 
1333  if (SymStart)
1334  {
1335  *SymStart = symStart;
1336  }
1337 
1338  for (INT32 i = 0; i < low; i++)
1339  {
1340  // When using 0 as symbol length, it just gets the next offset.
1341  offset = IntKsymExpandSymbol(offset, 0, SymName);
1342  if (!offset)
1343  {
1344  ERROR("[ERROR] Failed expanding symbol (offset: %d)!\n", offset);
1345  return INT_STATUS_UNSUCCESSFUL;
1346  }
1347  }
1348 
1349  offset = IntKsymExpandSymbol(offset, Length, SymName);
1350  if (!offset)
1351  {
1352  ERROR("[ERROR] Failed expanding symbol (offset: %d)!\n", offset);
1353  return INT_STATUS_UNSUCCESSFUL;
1354  }
1355 
1356  return INT_STATUS_SUCCESS;
1357 }
1358 
1359 
1360 QWORD
1362  _In_ const char *Name,
1363  _Out_opt_ QWORD *SymEnd
1364  )
1374 //
1377 {
1378  DWORD next = 0;
1379  size_t nameLen;
1380  BOOLEAN regexp;
1381  QWORD start;
1382 
1383  if (gGuest.OSType != introGuestLinux || !gKallsymsBuffers.Initialized)
1384  {
1385  BUG_ON(TRUE);
1386 
1387  return 0;
1388  }
1389 
1390  if (NULL == Name)
1391  {
1392  return 0;
1393  }
1394 
1395  if (SymEnd)
1396  {
1397  *SymEnd = 0;
1398  }
1399 
1400  nameLen = strlen(Name);
1401  regexp = Name[nameLen - 1] == '*';
1402 
1403  for (INT32 i = 0; i < gKallsymsBuffers.NumberOfNames; i++)
1404  {
1405  CHAR symName[LIX_SYMBOL_NAME_LEN] = { 0 };
1406 
1407  next = IntKsymExpandSymbol(next, sizeof(symName), symName);
1408  if (!next)
1409  {
1410  ERROR("[ERROR] Failed expanding symbol\n");
1411  return 0;
1412  }
1413 
1414  if ((!regexp && 0 == strcmp(Name, symName)) ||
1415  (regexp && strlen(symName) >= nameLen && 0 == memcmp(Name, symName, nameLen - 1)))
1416  {
1417  start = IntKsymGetAddress(i);
1418 
1419  if (SymEnd)
1420  {
1421  ++i;
1422 
1423  while (i < gKallsymsBuffers.NumberOfNames && start == IntKsymGetAddress(i))
1424  {
1425  ++i;
1426  }
1427 
1428  *SymEnd = IntKsymGetAddress(i);
1429  }
1430 
1431  return start;
1432  }
1433  }
1434 
1435  return 0;
1436 }
#define _Out_
Definition: intro_sal.h:22
_Bool BOOLEAN
Definition: intro_types.h:58
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
#define KSYM_NUM_SYMBOLS_CAP
The maximum number of symbols allowed to be in kallsyms.
Definition: lixksym.c:9
#define ALIGN_UP(x, a)
Definition: introdefs.h:164
static INTSTATUS IntKsymInitRelative(void)
Initializes the kallsyms subsystem for kernels compiled with CONFIG_KALLSYMS_BASE_RELATIVE.
Definition: lixksym.c:466
#define IC_TAG_KSYM
Kallsym cache.
Definition: memtags.h:99
uint8_t BYTE
Definition: intro_types.h:47
static DWORD IntKsymExpandSymbol(DWORD Offset, DWORD MaxLength, char *Name)
Expands a kallsyms symbol name.
Definition: lixksym.c:59
#define _In_
Definition: intro_sal.h:21
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:207
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
#define PAGE_REMAINING(addr)
Definition: pgtable.h:163
uint16_t WORD
Definition: intro_types.h:48
DWORD KernelSize
The size of the kernel.
Definition: guests.h:280
INTSTATUS IntKsymFindByAddress(QWORD Gva, DWORD Length, char *SymName, QWORD *SymStart, QWORD *SymEnd)
Finds the symbol which is located at the given address.
Definition: lixksym.c:1245
struct _KALLSYMS_BUFFERS KALLSYMS_BUFFERS
Describes the structure of the internal kallsyms buffers and other data required for the semantic rec...
Describes the structure of the internal kallsyms buffers and other data required for the semantic rec...
Definition: lixksym.c:18
WORD TokenIndex[KSYM_TOKEN_ARRAY_CACHE_SIZE]
The tokens array cached internally.
Definition: lixksym.c:46
static INTSTATUS IntKsymFindMarkersTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of &#39;kallsyms_markers&#39; table.
Definition: lixksym.c:640
QWORD RoDataStart
The guest virtual address where the read-only data starts.
Definition: lixguest.h:500
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define BUG_ON(cond)
Definition: introdefs.h:236
#define PAGE_OFFSET
Definition: pgtable.h:32
#define ARRAYSIZE(A)
Definition: introdefs.h:101
int32_t INT32
Definition: intro_types.h:44
#define ERROR(fmt,...)
Definition: glue.h:62
#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:495
QWORD CodeStart
The guest virtual address where the code starts.
Definition: lixguest.h:494
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
INTSTATUS IntKsymInit(void)
Initialize the kallsyms subsystem based on the os info provided by LIX_FIELD(Info, HasKsym*).
Definition: lixksym.c:1010
static INTSTATUS IntKsymRelativeFindOffsetTableEnd(QWORD StartAddress)
Finds the end of &#39;kallsyms_offsets&#39; memory region.
Definition: lixksym.c:294
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:274
static INTSTATUS IntKsymFindNamesTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of &#39;kallsyms_names&#39; table.
Definition: lixksym.c:818
char * NamesBuffer
The internal name cache used for a faster symbol lookup.
Definition: lixksym.c:35
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
Definition: lixksym.c:1361
char * TokenTable
The internal tokens table.
Definition: lixksym.c:43
static INTSTATUS IntKsymRelativeFindOffsetTableStart(QWORD *Address)
Finds the start of &#39;kallsyms_offsets&#39; memory region.
Definition: lixksym.c:162
#define PAGE_FRAME_NUMBER(addr)
Definition: pgtable.h:181
static INTSTATUS IntKsymFindIndexesTableStart(QWORD TokenTableStart, QWORD *IndexesTableStart)
Finds the start of &#39;kallsyms_token_index&#39; table.
Definition: lixksym.c:883
static INTSTATUS IntKsymFindMarkersReducedTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of &#39;kallsyms_markers&#39; table.
Definition: lixksym.c:722
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
Definition: introcore.c:829
#define _Out_opt_
Definition: intro_sal.h:30
#define IS_KERNEL_POINTER_LIX(p)
Definition: lixguest.h:11
#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
#define INT_STATUS_UNSUCCESSFUL
Definition: introstatus.h:335
#define KSYM_TOKEN_TABLE_SIZE_CAP
The maximum size allowed for the tokens table size.
Definition: lixksym.c:10
unsigned long long QWORD
Definition: intro_types.h:53
INT32 NumberOfNames
The number of symbols available in kallsyms.
Definition: lixksym.c:32
#define TRUE
Definition: intro_types.h:30
BOOLEAN Initialized
The flag that marks whether the kallsyms module is initialized or not.
Definition: lixksym.c:48
#define LIX_FIELD(Structure, Field)
Macro used to access fields inside the LIX_OPAQUE_FIELDS structure.
Definition: lixguest.h:426
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
#define TRACE(fmt,...)
Definition: glue.h:58
#define INT_STATUS_INVALID_DATA_STATE
Definition: introstatus.h:183
#define INT_STATUS_INVALID_INTERNAL_STATE
Definition: introstatus.h:272
DWORD TokenTableSize
The size of the internal tokens table.
Definition: lixksym.c:44
QWORD RelativeBase
Definition: lixksym.c:21
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:279
#define KSYM_TOKEN_ARRAY_CACHE_SIZE
The size of tokens array cache.
Definition: lixksym.c:12
#define WARNING(fmt,...)
Definition: glue.h:60
void IntKsymUninit(void)
Definition: lixksym.c:1218
#define LIX_SYMBOL_NAME_LEN
The max length of the ksym as defined by Linux kernel.
Definition: lixguest.h:582
#define PAGE_SIZE
Definition: common.h:53
uint32_t DWORD
Definition: intro_types.h:49
#define strlen_s(s, n)
Definition: introcrt.h:34
static KALLSYMS_BUFFERS gKallsymsBuffers
Contains information about kallsyms required for the semantic reconstruction.
Definition: lixksym.c:55
QWORD RoDataEnd
The guest virtual address where the read-only data ends.
Definition: lixguest.h:501
QWORD * AddressesBuffer
The internal addresses buffer.
Definition: lixksym.c:39
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
Definition: introcore.c:2134
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:370
static QWORD IntKsymGetAddress(INT32 Index)
Returns the address of the symbol located at the given index in the symbols table.
Definition: lixksym.c:131
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:48
INTSTATUS IntVirtMemRead(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer, DWORD *RetLength)
Reads data from a guest virtual memory range.
Definition: introcore.c:627
#define IC_TAG_ALLOC
Memory allocation.
Definition: memtags.h:28
static INTSTATUS IntKsymInitAbsolute(void)
Initializes the kallsyms subsystem for kernels compiled without CONFIG_KALLSYMS_BASE_RELATIVE.
Definition: lixksym.c:498
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
struct _LINUX_GUEST::@123 Layout
#define KSYM_NAMES_CACHE_SIZE_CAP
The maximum size allowed for the names.
Definition: lixksym.c:11
QWORD Addresses
The guest virtual address of Addresses table.
Definition: lixksym.c:28
INT32 * IndexesBuffer
The Internal indexes buffer.
Definition: lixksym.c:40
QWORD Indexes
The guest virtual address of Indexes table.
Definition: lixksym.c:29
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
char CHAR
Definition: intro_types.h:56
#define PAGE_MASK
Definition: pgtable.h:35
QWORD Names
The guest virtual address of the names table.
Definition: lixksym.c:33
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:29
#define INT_STATUS_INVALID_DATA_SIZE
Definition: introstatus.h:142
#define FALSE
Definition: intro_types.h:34
#define ALIGN_DOWN(x, a)
Definition: introdefs.h:165
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68
struct _KALLSYMS_BUFFERS * PKALLSYMS_BUFFERS