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 #define KSYM_MARKERS_RANGE_MAX 0x3000
14 
15 typedef struct _KALLSYMS_BUFFERS
20 {
21 
23 
27  union
28  {
31  };
32 
35 
36  char *NamesBuffer;
38 
39  union
40  {
43  };
44 
45  char *TokenTable;
47 
49 
52 
53 
58 
59 
60 static DWORD
62  _In_ DWORD Offset,
63  _In_ DWORD MaxLength,
64  _Out_ char *Name
65  )
77 {
78  BOOLEAN skipped = FALSE;
79  char *pKallsymsNames = NULL;
80  const BYTE *pData = NULL;
81  BYTE length = 0;
82  DWORD nextOffset = 0;
83 
84  if (Offset >= gKallsymsBuffers.NamesBufferSize)
85  {
86  ERROR("[ERROR] The provided offset is greater than the size of names buffer\n");
87  return 0;
88  }
89 
90  pKallsymsNames = gKallsymsBuffers.NamesBuffer + Offset;
91  pData = (const BYTE *)pKallsymsNames;
92  length = *pData;
93 
94  if (0 == length)
95  {
96  WARNING("[WARNING] Wrong symbol size %d\n", length);
97  return 0;
98  }
99 
100  pData++;
101  nextOffset = Offset + length + 1;
102 
103  if (Offset + length >= gKallsymsBuffers.NamesBufferSize)
104  {
105  ERROR("[ERROR] The length of symbol exceeds the names buffer\n");
106  return 0;
107  }
108 
109  if (nextOffset >= gKallsymsBuffers.NamesBufferSize)
110  {
111  ERROR("[ERROR] The next offset exceeds the names buffer\n");
112  return 0;
113  }
114 
115  while (length)
116  {
117  char *tptr = NULL;
118  const DWORD idx = gKallsymsBuffers.TokenIndex[*pData];
119 
120  if (idx >= gKallsymsBuffers.TokenTableSize)
121  {
122  ERROR("[ERROR] The token_index is greater than the size of token table\n");
123  return 0;
124  }
125 
126  tptr = &gKallsymsBuffers.TokenTable[idx];
127  pData++;
128  length--;
129 
130  while (*tptr && ((QWORD)tptr < (QWORD)gKallsymsBuffers.TokenTable + gKallsymsBuffers.TokenTableSize))
131  {
132  if (skipped)
133  {
134  if (MaxLength <= 1)
135  {
136  goto _tail;
137  }
138 
139  *Name = *tptr;
140  Name++;
141  MaxLength--;
142  }
143  else
144  {
145  skipped = TRUE;
146  }
147 
148  ++tptr;
149  }
150  }
151 
152 _tail:
153  if (MaxLength)
154  {
155  // Put the final NULL-terminator
156  *Name = '\0';
157  }
158 
159  return nextOffset;
160 }
161 
162 
163 static QWORD
165  _In_ INT32 Index
166  )
174 {
175  if (!LIX_FIELD(Info, HasKsymRelative))
176  {
177  return gKallsymsBuffers.AddressesBuffer[Index];
178  }
179 
180  if (!LIX_FIELD(Info, HasKsymAbsolutePercpu))
181  {
182  return gKallsymsBuffers.RelativeBase + (DWORD)gKallsymsBuffers.IndexesBuffer[Index];
183  }
184 
185  if (gKallsymsBuffers.IndexesBuffer[Index] >= 0)
186  {
187  return gKallsymsBuffers.IndexesBuffer[Index];
188  }
189 
190  return gKallsymsBuffers.RelativeBase - 1 - gKallsymsBuffers.IndexesBuffer[Index];
191 }
192 
193 
194 static INTSTATUS
196  _Out_ QWORD *Address
197  )
208 {
209  INTSTATUS status = INT_STATUS_SUCCESS;
210  QWORD currentAddr = gLixGuest->Layout.RoDataStart & PAGE_MASK;
211  QWORD startAddr = 0;
212  INT32 *ptr = NULL;
213 
215  if (!ptr)
216  {
218  }
219 
220  for (; currentAddr < gLixGuest->Layout.RoDataEnd; currentAddr += PAGE_SIZE)
221  {
222  INT32 *pPage = NULL;
223 
224  status = IntVirtMemMap(currentAddr, PAGE_SIZE, gGuest.Mm.SystemCr3, 0, &pPage);
225  if (!INT_SUCCESS(status))
226  {
227  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
228  break;
229  }
230 
231  for (DWORD i = 0; i < (PAGE_SIZE / 4) - 16; i++)
232  {
233  if (pPage[i] < 0)
234  {
235  continue;
236  }
237 
238  // 16 ordered int's (assume they are > 0)
239  if (pPage[i] > pPage[i + 1] ||
240  pPage[i + 1] >= pPage[i + 2] ||
241  pPage[i + 2] >= pPage[i + 3] ||
242  pPage[i + 3] >= pPage[i + 4] ||
243  pPage[i + 4] >= pPage[i + 5] ||
244  pPage[i + 5] >= pPage[i + 6] ||
245  pPage[i + 6] >= pPage[i + 7] ||
246  pPage[i + 7] >= pPage[i + 8] ||
247  pPage[i + 8] >= pPage[i + 9] ||
248  pPage[i + 9] >= pPage[i + 10] ||
249  pPage[i + 10] >= pPage[i + 11] ||
250  pPage[i + 11] >= pPage[i + 12] ||
251  pPage[i + 12] >= pPage[i + 13] ||
252  pPage[i + 13] >= pPage[i + 14] ||
253  pPage[i + 14] >= pPage[i + 15])
254  {
255  continue;
256  }
257 
258  startAddr = currentAddr + i * 4ull;
259 
260  break;
261  }
262 
263  if (startAddr)
264  {
265  status = IntVirtMemRead(startAddr, PAGE_SIZE, gGuest.Mm.SystemCr3, ptr, NULL);
266  if (!INT_SUCCESS(status))
267  {
268  ERROR("[ERROR] IntVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", startAddr, status);
269 
270  IntVirtMemUnmap(&pPage);
271 
272  break;
273  }
274 
275  for (DWORD i = 1; i < PAGE_SIZE / 4 - 3; i++)
276  {
277  // Is this is the startup_64/_text ?
278  if (LIX_FIELD(Info, HasKsymAbsolutePercpu))
279  {
280  if (ptr[i] == -1 && ptr[i + 1] == -1)
281  {
282  break;
283  }
284  }
285  else
286  {
287  if (ptr[i] == 0 && ptr[i + 1] == 0)
288  {
289  break;
290  }
291  }
292 
293  // everything must be ordered
294  if (ptr[i] < ptr[i - 1])
295  {
296  startAddr = 0;
297  break;
298  }
299  }
300  }
301 
302  IntVirtMemUnmap(&pPage);
303 
304  if (startAddr)
305  {
306  TRACE("[KALLSYMS RELATIVE] Found indexes start @%llx\n", startAddr);
307  break;
308  }
309  }
310 
312 
313  if (!INT_SUCCESS(status))
314  {
315  return status;
316  }
317 
318  if (!startAddr)
319  {
320  return INT_STATUS_NOT_FOUND;
321  }
322 
323  *Address = startAddr;
324 
325  return INT_STATUS_SUCCESS;
326 }
327 
328 
329 static INTSTATUS
331  _In_ QWORD StartAddress
332  )
345 {
346  INTSTATUS status = INT_STATUS_SUCCESS;
347  QWORD currentAddr = 0;
348  QWORD endAddr = 0;
349  BOOLEAN firstNegative = FALSE;
350  BOOLEAN firstPositive = FALSE;
351 
352  for (currentAddr = StartAddress; currentAddr < gLixGuest->Layout.RoDataEnd;)
353  {
354  INT32 *pPage = NULL;
355  DWORD offset = currentAddr & PAGE_OFFSET;
356 
357  status = IntVirtMemMap(currentAddr, PAGE_SIZE - offset, gGuest.Mm.SystemCr3, 0, &pPage);
358  if (!INT_SUCCESS(status))
359  {
360  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
361  return status;
362  }
363 
364  for (DWORD i = 0; i < ((PAGE_SIZE - offset) / 4) - 1; i++)
365  {
366  if (pPage[i] == -1 && pPage[i + 1] == -1)
367  {
368  firstNegative = TRUE;
369  continue;
370  }
371 
372  if (!firstNegative)
373  {
374  continue;
375  }
376 
377  if (!firstPositive && pPage[i] > 0)
378  {
379  firstPositive = TRUE;
380  continue;
381  }
382 
383  if (*(QWORD *)(pPage + i) == gGuest.KernelVa)
384  {
385  endAddr = currentAddr + i * 4ull;
386  break;
387  }
388 
389  if (pPage[i] == 0)
390  {
391  endAddr = currentAddr + i * 4ull;
392  break;
393  }
394 
395  if (LIX_FIELD(Info, HasKsymAbsolutePercpu))
396  {
397  if ((!firstPositive && pPage[i] < 0) ||
398  (firstPositive && pPage[i + 1] >= pPage[i]))
399  {
400  continue;
401  }
402  }
403  else
404  {
405  if (pPage[i] <= pPage[i + 1])
406  {
407  continue;
408  }
409  }
410 
411  endAddr = currentAddr + i * 4ull;
412  break;
413  }
414 
415  IntVirtMemUnmap(&pPage);
416 
417  currentAddr += PAGE_SIZE - offset;
418 
419  if (endAddr)
420  {
421  QWORD relativeBase = 0;
422  DWORD numberOfNames = 0;
423  DWORD foundNames = (DWORD)(endAddr - StartAddress) / 4;
424 
425  status = IntKernVirtMemFetchQword(ALIGN_UP(endAddr, 8), &relativeBase);
426  if (!INT_SUCCESS(status))
427  {
428  ERROR("[ERROR] IntKernVirtMemFetchQword failed for GVA 0x%016llx with status: 0x%08x\n",
429  endAddr, status);
430  endAddr = 0;
431  continue;
432  }
433 
434  if (relativeBase != gGuest.KernelVa)
435  {
436  endAddr = 0;
437  continue;
438  }
439 
440  if (LIX_FIELD(Info, HasKsymSize))
441  {
442  // Skip the sizes region
443  // * 2 because each offset entry is 4 bytes long and the size of a kallsmys_size entry is 8 bytes.
444  endAddr += (endAddr - StartAddress) * 2;
445  }
446 
447  status = IntKernVirtMemFetchDword(ALIGN_UP(endAddr, 8) + 8, &numberOfNames);
448  if (!INT_SUCCESS(status))
449  {
450  ERROR("[ERROR] IntKernVirtMemFetchDword failed for GVA 0x%016llx with status: 0x%08x\n",
451  endAddr, status);
452  endAddr = 0;
453  continue;
454  }
455 
456  TRACE("[KALLSYMS] num_symbols (found): %d\n", foundNames);
457 
458  // Did we parsed too much or too little (assume an error of 0x40)
459  if ((foundNames > numberOfNames &&
460  foundNames - numberOfNames > 0x40) ||
461  (foundNames < numberOfNames &&
462  numberOfNames - foundNames > 0x40))
463  {
464  endAddr = 0;
465  continue;
466  }
467 
468  if (numberOfNames > KSYM_NUM_SYMBOLS_CAP)
469  {
470  ERROR("[ERROR] Kallsyms number of names exceeds the limit: %u vs %u",
471  numberOfNames, KSYM_NUM_SYMBOLS_CAP);
472  continue;
473  }
474 
475  gKallsymsBuffers.RelativeBase = relativeBase;
476 
477  gKallsymsBuffers.NumberOfNames = numberOfNames;
478  gKallsymsBuffers.Indexes = ALIGN_DOWN(endAddr - numberOfNames * 4ull, 8);
479 
480  if (LIX_FIELD(Info, HasKsymSize))
481  {
482  // Also skip the sizes region ( 8 * numberOfSymbols)
483  gKallsymsBuffers.Indexes -= numberOfNames * 8ull;
484  }
485 
486  gKallsymsBuffers.Names = ALIGN_UP(endAddr, 8) + 16;
487 
488  break;
489  }
490  }
491 
492  if (0 == gKallsymsBuffers.NumberOfNames)
493  {
494  return INT_STATUS_NOT_FOUND;
495  }
496 
497  return INT_STATUS_SUCCESS;
498 }
499 
500 
501 static INTSTATUS
503  void
504  )
511 {
512  INTSTATUS status = INT_STATUS_SUCCESS;
513  QWORD tableOffsetsStartAddr = 0;
514 
515  status = IntKsymRelativeFindOffsetTableStart(&tableOffsetsStartAddr);
516  if (!INT_SUCCESS(status))
517  {
518  ERROR("[ERROR] IntKsymRelativeFindOffsetTableStart failed with status: 0x%08x\n", status);
519  return status;
520  }
521 
522  status = IntKsymRelativeFindOffsetTableEnd(tableOffsetsStartAddr);
523  if (!INT_SUCCESS(status))
524  {
525  ERROR("[ERROR] IntKsymRelativeFindOffsetTableEnd failed with status: 0x%08x\n", status);
526  return status;
527  }
528 
529  return INT_STATUS_SUCCESS;
530 }
531 
532 
533 static INTSTATUS
535  void
536  )
543 {
544  INTSTATUS status = INT_STATUS_SUCCESS;
546  QWORD addrStart = 0;
547  QWORD numGva = 0;
548  QWORD prev = 0;
549  INT32 num = 0;
550  QWORD *pPage = NULL;
551  BOOLEAN foundStart = FALSE;
552 
553  while (gvaStart < gLixGuest->Layout.RoDataEnd)
554  {
555  BOOLEAN redoPage = FALSE;
556 
557  status = IntVirtMemMap(gvaStart, PAGE_SIZE, gGuest.Mm.SystemCr3, 0, &pPage);
558  if (!INT_SUCCESS(status))
559  {
560  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", gvaStart, status);
561  return status;
562  }
563 
564  if (!foundStart)
565  {
566  for (DWORD i = 0; i < (PAGE_SIZE / 8) - 8; i++)
567  {
568  // Make sure each of the eight pointers point inside the code section...
569  if ((pPage[i] < gLixGuest->Layout.CodeStart || pPage[i] > gLixGuest->Layout.CodeEnd) ||
570  (pPage[i + 1] < gLixGuest->Layout.CodeStart || pPage[i + 1] > gLixGuest->Layout.CodeEnd) ||
571  (pPage[i + 2] < gLixGuest->Layout.CodeStart || pPage[i + 2] > gLixGuest->Layout.CodeEnd) ||
572  (pPage[i + 3] < gLixGuest->Layout.CodeStart || pPage[i + 3] > gLixGuest->Layout.CodeEnd) ||
573  (pPage[i + 4] < gLixGuest->Layout.CodeStart || pPage[i + 4] > gLixGuest->Layout.CodeEnd) ||
574  (pPage[i + 5] < gLixGuest->Layout.CodeStart || pPage[i + 5] > gLixGuest->Layout.CodeEnd) ||
575  (pPage[i + 6] < gLixGuest->Layout.CodeStart || pPage[i + 6] > gLixGuest->Layout.CodeEnd) ||
576  (pPage[i + 7] < gLixGuest->Layout.CodeStart || pPage[i + 7] > gLixGuest->Layout.CodeEnd))
577  {
578  continue;
579  }
580 
581  // ... and each one points inside the first two pages...
582  if (pPage[i] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
583  pPage[i + 1] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
584  pPage[i + 2] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
585  pPage[i + 3] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
586  pPage[i + 4] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
587  pPage[i + 5] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
588  pPage[i + 6] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE ||
589  pPage[i + 7] - gLixGuest->Layout.CodeStart > 3 * PAGE_SIZE)
590  {
591  continue;
592  }
593 
594  // ... and they are ordered.
595  if (pPage[i] < pPage[i + 1] &&
596  pPage[i + 1] < pPage[i + 2] &&
597  pPage[i + 2] < pPage[i + 3] &&
598  pPage[i + 3] < pPage[i + 4] &&
599  pPage[i + 4] < pPage[i + 5] &&
600  pPage[i + 5] < pPage[i + 6] &&
601  pPage[i + 6] < pPage[i + 7])
602  {
603  addrStart = gvaStart + i * 8ull;
604  prev = pPage[i];
605 
606  foundStart = TRUE;
607 
608  break;
609  }
610  }
611  }
612  else
613  {
614  for (DWORD i = 0; i < PAGE_SIZE / 8; i++)
615  {
616  QWORD val = pPage[i];
617 
618  if ((val > 0) && (val < 0x3FFFF))
619  {
620  num = (INT32)val;
621  numGva = gvaStart + i * 8ull;
622  TRACE("[INFO] Found num_symbols start at 0x%016llx: %d\n", gvaStart + i * 8ull, num);
623  break;
624  }
625 
626  // Is the pointer still good ?!
627  if (IS_KERNEL_POINTER_LIX(val) && prev <= val)
628  {
629  prev = val;
630  continue;
631  }
632 
633  if (IS_KERNEL_POINTER_LIX(val) && prev > val)
634  {
635  WARNING("[WARNING] Unordered list: 0x%016llx 0x%016llx\n", prev, val);
636  }
637 
638  redoPage = TRUE;
639  foundStart = FALSE;
640  addrStart = num = 0;
641 
642  WARNING("[WARNING] Found an invalid pointer (prev 0x%016llx) 0x%016llx @ 0x%016llx\n",
643  prev, val, gvaStart + i * 8ull);
644  break;
645  }
646  }
647 
648  IntVirtMemUnmap(&pPage);
649 
650  if (addrStart && num)
651  {
652  break;
653  }
654 
655  if (!redoPage)
656  {
657  gvaStart += PAGE_SIZE;
658  }
659  }
660 
661  if (!addrStart || !num)
662  {
663  return INT_STATUS_NOT_FOUND;
664  }
665 
666  // Now it's the to calculate and determine addresses
667  gKallsymsBuffers.NumberOfNames = num;
668  gKallsymsBuffers.Addresses = numGva - num * 8ull;
669  gKallsymsBuffers.Names = numGva + 8;
670 
671  return INT_STATUS_SUCCESS;
672 }
673 
674 
675 static INTSTATUS
677  _In_ QWORD StartAddress,
678  _Out_ QWORD *EndAddress
679  )
691 {
692  INTSTATUS status = INT_STATUS_SUCCESS;
693  QWORD *pMarkers = NULL;
694  QWORD *pAddr = NULL;
695  QWORD currentAddr = StartAddress;
696  QWORD prevAddr = 0;
697 
698  if (StartAddress % sizeof(QWORD) != 0)
699  {
700  ERROR("[ERROR] The provided address is not aligned (0x%016llx)!\n", StartAddress);
702  }
703 
704  // Skip all the QWORDS until we have a one bigger than 0xffffffff (that's where the token table starts)
705  for (DWORD i = 0; i < 2 * PAGE_SIZE / 8; i++)
706  {
707  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
708  {
709  status = IntVirtMemMap(currentAddr, PAGE_REMAINING(currentAddr & PAGE_OFFSET), gGuest.Mm.SystemCr3, 0, &pMarkers);
710  if (!INT_SUCCESS(status))
711  {
712  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
713  return status;
714  }
715 
716  pAddr = pMarkers;
717  }
718 
719  if (pMarkers == NULL)
720  {
721  return INT_STATUS_NOT_FOUND;
722  }
723 
724  if (*pMarkers > 0xffffffff)
725  {
726  *EndAddress = currentAddr;
727 
728  status = INT_STATUS_SUCCESS;
729  goto _exit;
730  }
731 
732  prevAddr = currentAddr;
733  currentAddr += 8;
734 
735  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
736  {
737  IntVirtMemUnmap(&pAddr);
738  pMarkers = NULL;
739  }
740  else
741  {
742  pMarkers++;
743  }
744  }
745 
746  status = INT_STATUS_NOT_FOUND;
747 
748 _exit:
749  if (pMarkers != NULL)
750  {
751  IntVirtMemUnmap(&pMarkers);
752  }
753 
754  return status;
755 }
756 
757 static INTSTATUS
759  _In_ QWORD StartAddress,
760  _In_ QWORD *EndAddress
761  )
775 {
776  INTSTATUS status = INT_STATUS_SUCCESS;
777  DWORD *pMarkers = NULL;
778  DWORD *pAddr = NULL;
779  DWORD size = 0;
780  DWORD remaining = 0;
781  QWORD currentAddr = StartAddress;
782 
783  if (StartAddress % sizeof(DWORD) != 0)
784  {
785  ERROR("[ERROR] The provided address is not aligned (0x%016llx)!\n", StartAddress);
787  }
788 
789  // We iterate max 2048 integers to find the end of kallsyms_markers table.
790  for (DWORD i = 0; i < (2 * PAGE_SIZE) / sizeof(*pMarkers); i++)
791  {
792  if (NULL == pMarkers)
793  {
794  // Because we compare pMarkers[i] with pMarkers[i + 1] we have to make sure that we are always mapping
795  // at least 2 * sizeof(*pMarkers) bytes.
796  size = PAGE_REMAINING(currentAddr);
797 
798  // This is ok, because size will never be 0, and any currentAddr is always incremented by sizeof(DWORD).
799  // StartAddress is also aligned to 8-bytes.
800  if (size == sizeof(*pMarkers))
801  {
802  // Here, we can actually add PAGE_SIZE, but it will then go through the slow IntVirtMemMap mechanism
803  // which copies the mapped memory into an allocated buffer, because the memory will be split into two
804  // pages. It should be faster to do it this way, because we avoid the huge memcpy and the mapping is
805  // cached, so for the second page another call to xen will not be issued.
806  size += sizeof(*pMarkers);
807  }
808 
809  remaining = size - sizeof(*pMarkers);
810 
811  status = IntVirtMemMap(currentAddr, size, gGuest.Mm.SystemCr3, 0, &pAddr);
812  if (!INT_SUCCESS(status))
813  {
814  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
815  return status;
816  }
817 
818  pMarkers = pAddr;
819  }
820 
821  currentAddr += sizeof(*pMarkers);
822  remaining -= sizeof(*pMarkers);
823 
824  if ((*pMarkers >= * (pMarkers + 1)) || ((*(pMarkers + 1) - *pMarkers) >= KSYM_MARKERS_RANGE_MAX))
825  {
826  *EndAddress = currentAddr;
827 
828  status = INT_STATUS_SUCCESS;
829  goto _exit;
830  }
831 
832  pMarkers++;
833 
834  if (remaining == 0)
835  {
836  IntVirtMemUnmap(&pAddr);
837  pMarkers = NULL;
838  }
839  }
840 
841  status = INT_STATUS_NOT_FOUND;
842 
843 _exit:
844  if (pMarkers != NULL)
845  {
846  IntVirtMemUnmap(&pMarkers);
847  }
848 
849  return status;
850 }
851 
852 
853 static INTSTATUS
855  _In_ QWORD StartAddress,
856  _In_ QWORD *EndAddress
857  )
870 {
871  INTSTATUS status = INT_STATUS_SUCCESS;
872  BYTE *pSymbol = NULL;
873  QWORD prevAddr = 0;
874  QWORD currentAddr = StartAddress;
875 
876  for (INT32 i = 0; i < gKallsymsBuffers.NumberOfNames; i++)
877  {
878  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
879  {
880  status = IntVirtMemMap(currentAddr, PAGE_REMAINING(currentAddr & PAGE_OFFSET), gGuest.Mm.SystemCr3, 0, &pSymbol);
881  if (!INT_SUCCESS(status))
882  {
883  ERROR("[ERROR] IntVirtMemMap failed for 0x%016llx: 0x%08x\n", currentAddr, status);
884  return status;
885  }
886  }
887 
888  if (pSymbol == NULL)
889  {
890  return INT_STATUS_NOT_FOUND;
891  }
892 
893  prevAddr = currentAddr;
894  currentAddr += *pSymbol + 1ull;
895 
896  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
897  {
898  IntVirtMemUnmap(&pSymbol);
899  pSymbol = NULL;
900  }
901  else
902  {
903  pSymbol += *pSymbol + 1ull;
904  }
905  }
906 
907  if (NULL != pSymbol)
908  {
909  IntVirtMemUnmap(&pSymbol);
910  }
911 
912  *EndAddress = currentAddr;
913 
914  return INT_STATUS_SUCCESS;
915 }
916 
917 
918 static INTSTATUS
920  _In_ QWORD TokenTableStart,
921  _Out_ QWORD *IndexesTableStart
922  )
935 {
936  INTSTATUS status = INT_STATUS_SUCCESS;
937  WORD indexes[0x5] = { 0 };
938  char tokenSlice[0x30] = { 0 };
939  DWORD remainingTokenLength = (DWORD)sizeof(tokenSlice);
940  QWORD currentAddr = TokenTableStart;
941  QWORD prevAddr = 0;
942  WORD *pIndex = NULL;
943 
944  status = IntKernVirtMemRead(TokenTableStart, sizeof(tokenSlice), tokenSlice, NULL);
945  if (!INT_SUCCESS(status))
946  {
947  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", TokenTableStart, status);
948  return status;
949  }
950 
951  indexes[0] = 0;
952  for (DWORD i = 1; i < ARRAYSIZE(indexes); i++)
953  {
954  WORD length = (WORD)strlen_s(&tokenSlice[indexes[i - 1]], remainingTokenLength) + 1;
955  indexes[i] = indexes[i - 1] + length;
956  remainingTokenLength -= length;
957 
958  if ((int)remainingTokenLength < 0)
959  {
960  ERROR("[ERROR] %zu bytes not enough to find indexes. Stopped at %d!\n", sizeof(tokenSlice), i);
962  }
963  }
964 
965  // Now search the indexes in memory, WORD by WORD
966  for (DWORD i = 0; i < PAGE_SIZE / 8; i++)
967  {
968  WORD idx[sizeof(indexes) / sizeof(indexes[0])];
969  DWORD j;
970  BOOLEAN found = FALSE;
971 
972  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
973  {
974  status = IntVirtMemMap(currentAddr, PAGE_REMAINING(currentAddr & PAGE_OFFSET), gGuest.Mm.SystemCr3, 0, &pIndex);
975  if (!INT_SUCCESS(status))
976  {
977  ERROR("[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
978  return status;
979  }
980  }
981 
982  if (PAGE_FRAME_NUMBER(currentAddr + sizeof(idx)) != PAGE_FRAME_NUMBER(currentAddr))
983  {
984  status = IntKernVirtMemRead(currentAddr, sizeof(idx), idx, NULL);
985  if (!INT_SUCCESS(status))
986  {
987  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
988  break;
989  }
990  }
991  else
992  {
993  if (pIndex == NULL)
994  {
995  return INT_STATUS_NOT_FOUND;
996  }
997 
998  memcpy(idx, pIndex, sizeof(idx));
999  }
1000 
1001  found = TRUE;
1002  for (j = 0; j < ARRAYSIZE(idx); j++)
1003  {
1004  if (idx[j] != indexes[j])
1005  {
1006  found = FALSE;
1007  break;
1008  }
1009  }
1010 
1011  if (found)
1012  {
1013  *IndexesTableStart = currentAddr;
1014 
1015  status = INT_STATUS_SUCCESS;
1016  goto _exit;
1017  }
1018 
1019  prevAddr = currentAddr;
1020  currentAddr += 8;
1021 
1022  if (PAGE_FRAME_NUMBER(prevAddr) != PAGE_FRAME_NUMBER(currentAddr))
1023  {
1024  IntVirtMemUnmap(&pIndex);
1025  pIndex = NULL;
1026  }
1027  else
1028  {
1029  pIndex = (WORD *)((BYTE *)pIndex + 8);
1030  }
1031  }
1032 
1033  status = INT_STATUS_NOT_FOUND;
1034 
1035 _exit:
1036  if (pIndex != NULL)
1037  {
1038  IntVirtMemUnmap(&pIndex);
1039  }
1040 
1041  return status;
1042 }
1043 
1044 
1045 INTSTATUS
1047  void
1048  )
1064 {
1065  INTSTATUS status = INT_STATUS_SUCCESS;
1066  QWORD currentAddr = 0;
1067  QWORD tokenTableStart = 0;
1068  DWORD size = 0;
1069  char *pTokenTable = NULL;
1070  char *pNames = NULL;
1071  QWORD *pAddresses = NULL;
1072 
1073  if (gGuest.OSType != introGuestLinux)
1074  {
1075  BUG_ON(TRUE);
1076 
1078  }
1079 
1080  if (LIX_FIELD(Info, HasKsymRelative))
1081  {
1082  status = IntKsymInitRelative();
1083  if (!INT_SUCCESS(status))
1084  {
1085  ERROR("[ERROR] IntKsymInitRelative failed: %08x\n", status);
1086  return status;
1087  }
1088 
1089  TRACE("[KALLSYMS] indexes : 0x%016llx\n", gKallsymsBuffers.Indexes);
1090  TRACE("[KALLSYMS] rel_base : 0x%016llx\n", gKallsymsBuffers.RelativeBase);
1091  }
1092  else
1093  {
1094  status = IntKsymInitAbsolute();
1095  if (!INT_SUCCESS(status))
1096  {
1097  ERROR("[ERROR] IntKsymInitAbsolute failed: %08x\n", status);
1098  return status;
1099  }
1100 
1101  TRACE("[KALLSYMS] addresses : 0x%016llx\n", gKallsymsBuffers.Addresses);
1102  }
1103 
1104  TRACE("[KALLSYMS] num_symbols : %d\n", gKallsymsBuffers.NumberOfNames);
1105  TRACE("[KALLSYMS] names : 0x%016llx\n", gKallsymsBuffers.Names);
1106 
1107  status = IntKsymFindNamesTableEnd(gKallsymsBuffers.Names, &currentAddr);
1108  if(!INT_SUCCESS(status))
1109  {
1110  ERROR("[ERROR] IntKsymFindNamesTableEnd failed with status: 0x%08x\n", status);
1111  }
1112 
1113  currentAddr = ALIGN_UP(currentAddr, 8);
1114 
1115  if (LIX_FIELD(Info, HasKsymReducedSize))
1116  {
1117  status = IntKsymFindMarkersReducedTableEnd(currentAddr, &currentAddr);
1118  }
1119  else
1120  {
1121  status = IntKsymFindMarkersTableEnd(currentAddr, &currentAddr);
1122  }
1123 
1124  if (!INT_SUCCESS(status))
1125  {
1126  ERROR("[ERROR] Failed finding the start of token_table!\n");
1127  return INT_STATUS_NOT_FOUND;
1128  }
1129 
1130  tokenTableStart = ALIGN_UP(currentAddr, 8);
1131  TRACE("[KALLSYMS] token_table : 0x%016llx\n", tokenTableStart);
1132 
1133  status = IntKsymFindIndexesTableStart(tokenTableStart, &currentAddr);
1134  if (!INT_SUCCESS(status))
1135  {
1136  ERROR("[ERROR] IntKsymFindIndexesTableStart failed with status: 0x%08x\n", status);
1137  return status;
1138  }
1139 
1140  gKallsymsBuffers.TokenTableSize = (DWORD)(currentAddr - tokenTableStart);
1141 
1142  if (gKallsymsBuffers.TokenTableSize > KSYM_TOKEN_TABLE_SIZE_CAP)
1143  {
1144  ERROR("[ERROR] Tokens table size exceeds the introcore limit: %u vs %u\n",
1145  gKallsymsBuffers.TokenTableSize, KSYM_TOKEN_TABLE_SIZE_CAP);
1146 
1148  }
1149 
1150  TRACE("[KALLSYMS] token_size : %08x\n", gKallsymsBuffers.TokenTableSize);
1151  TRACE("[KALLSYMS] token_index : 0x%016llx\n", currentAddr);
1152 
1153  status = IntKernVirtMemRead(currentAddr,
1154  sizeof(gKallsymsBuffers.TokenIndex),
1155  gKallsymsBuffers.TokenIndex,
1156  NULL);
1157  if (!INT_SUCCESS(status))
1158  {
1159  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1160  return status;
1161  }
1162 
1163  pTokenTable = HpAllocWithTag(gKallsymsBuffers.TokenTableSize, IC_TAG_KSYM);
1164  if (NULL == pTokenTable)
1165  {
1167  }
1168 
1169  status = IntKernVirtMemRead(tokenTableStart, gKallsymsBuffers.TokenTableSize, pTokenTable, NULL);
1170  if (!INT_SUCCESS(status))
1171  {
1172  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1173  goto _exit;
1174  }
1175 
1176  size = (DWORD)(tokenTableStart - gKallsymsBuffers.Names);
1177 
1178  if (size > KSYM_NAMES_CACHE_SIZE_CAP)
1179  {
1180  ERROR("[ERROR] Kallsyms names size exceeds the introcore limit: %u vs %u",
1182 
1184  goto _exit;
1185  }
1186 
1187  // Cache the names. Ubuntu 16.04 takes ~1.1MB
1188 
1189  TRACE("[INFO] Cache kallsyms names: %d bytes\n", size);
1190 
1191  pNames = HpAllocWithTag(size, IC_TAG_KSYM);
1192  if (NULL == pNames)
1193  {
1195  goto _exit;
1196  }
1197 
1198  status = IntKernVirtMemRead(gKallsymsBuffers.Names, size, pNames, NULL);
1199  if (!INT_SUCCESS(status))
1200  {
1201  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1202  goto _exit;
1203  }
1204 
1205  gKallsymsBuffers.NamesBufferSize = size;
1206 
1207  // Cache the addresses (an array of sorted QWORDS). Ubuntu 16.04 takes ~800kb
1208 
1209  size = (DWORD)(gKallsymsBuffers.NumberOfNames * 8);
1210 
1211  TRACE("[INFO] Cache kallsyms addresses: %d bytes\n", size);
1212 
1213  pAddresses = HpAllocWithTag(size, IC_TAG_KSYM);
1214  if (NULL == pAddresses)
1215  {
1217  goto _exit;
1218  }
1219 
1220  status = IntKernVirtMemRead(gKallsymsBuffers.Addresses, size, pAddresses, NULL);
1221  if (!INT_SUCCESS(status))
1222  {
1223  ERROR("[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1224  goto _exit;
1225  }
1226 
1227  gKallsymsBuffers.TokenTable = pTokenTable;
1228  gKallsymsBuffers.AddressesBuffer = pAddresses;
1229  gKallsymsBuffers.NamesBuffer = pNames;
1230 
1231  gKallsymsBuffers.Initialized = TRUE;
1232 
1233  return INT_STATUS_SUCCESS;
1234 
1235 _exit:
1236  if (NULL != pTokenTable)
1237  {
1238  HpFreeAndNullWithTag(&pTokenTable, IC_TAG_KSYM);
1239  }
1240 
1241  if (NULL != pAddresses)
1242  {
1243  HpFreeAndNullWithTag(&pAddresses, IC_TAG_KSYM);
1244  }
1245 
1246  if (NULL != pNames)
1247  {
1249  }
1250 
1251  return status;
1252 }
1253 
1254 
1255 void
1257  void
1258  )
1262 {
1263  if (NULL != gKallsymsBuffers.TokenTable)
1264  {
1265  HpFreeAndNullWithTag(&gKallsymsBuffers.TokenTable, IC_TAG_KSYM);
1266  }
1267 
1268  if (NULL != gKallsymsBuffers.AddressesBuffer)
1269  {
1270  HpFreeAndNullWithTag(&gKallsymsBuffers.AddressesBuffer, IC_TAG_KSYM);
1271  }
1272 
1273  if (NULL != gKallsymsBuffers.NamesBuffer)
1274  {
1275  HpFreeAndNullWithTag(&gKallsymsBuffers.NamesBuffer, IC_TAG_KSYM);
1276  }
1277 
1278  gKallsymsBuffers.Initialized = FALSE;
1279 }
1280 
1281 
1282 INTSTATUS
1284  _In_ QWORD Gva,
1285  _In_ DWORD Length,
1286  _Out_ char *SymName,
1287  _Out_opt_ QWORD *SymStart,
1288  _Out_opt_ QWORD *SymEnd
1289  )
1309 {
1310  DWORD offset;
1311  QWORD symStart;
1312 
1313  INT32 high, low;
1314 
1315  if (NULL == SymName)
1316  {
1318  }
1319 
1320  if (!gKallsymsBuffers.Initialized)
1321  {
1323  }
1324 
1325  // Directly return if we are outside of the kernel
1326  if (Gva > gGuest.KernelVa + gGuest.KernelSize)
1327  {
1328  return INT_STATUS_NOT_FOUND;
1329  }
1330 
1331  low = 0;
1332  offset = 0;
1333  high = gKallsymsBuffers.NumberOfNames;
1334 
1335  while (high - low > 1)
1336  {
1337  INT32 mid = low + (high - low) / 2;
1338 
1339  if (IntKsymGetAddress(mid) <= Gva)
1340  {
1341  low = mid;
1342  }
1343  else
1344  {
1345  high = mid;
1346  }
1347  }
1348 
1349  // Search for the first aliased symbol. Aliased symbols are symbols with the same address.
1350  while (low && IntKsymGetAddress(low - 1) == IntKsymGetAddress(low))
1351  {
1352  --low;
1353  }
1354 
1355  symStart = IntKsymGetAddress(low);
1356 
1357  if (SymEnd)
1358  {
1359  INT32 next = low + 1;
1360 
1361  // Skip until the next one is bigger
1362  while (next < gKallsymsBuffers.NumberOfNames &&
1363  symStart == IntKsymGetAddress(next))
1364  {
1365  ++next;
1366  }
1367 
1368  *SymEnd = IntKsymGetAddress(next);
1369  }
1370 
1371  if (SymStart)
1372  {
1373  *SymStart = symStart;
1374  }
1375 
1376  for (INT32 i = 0; i < low; i++)
1377  {
1378  // When using 0 as symbol length, it just gets the next offset.
1379  offset = IntKsymExpandSymbol(offset, 0, SymName);
1380  if (!offset)
1381  {
1382  ERROR("[ERROR] Failed expanding symbol (offset: %d)!\n", offset);
1383  return INT_STATUS_UNSUCCESSFUL;
1384  }
1385  }
1386 
1387  offset = IntKsymExpandSymbol(offset, Length, SymName);
1388  if (!offset)
1389  {
1390  ERROR("[ERROR] Failed expanding symbol (offset: %d)!\n", offset);
1391  return INT_STATUS_UNSUCCESSFUL;
1392  }
1393 
1394  return INT_STATUS_SUCCESS;
1395 }
1396 
1397 
1398 QWORD
1400  _In_ const char *Name,
1401  _Out_opt_ QWORD *SymEnd
1402  )
1412 //
1415 {
1416  DWORD next = 0;
1417  size_t nameLen;
1418  BOOLEAN regexp;
1419  QWORD start;
1420 
1421  if (gGuest.OSType != introGuestLinux || !gKallsymsBuffers.Initialized)
1422  {
1423  BUG_ON(TRUE);
1424 
1425  return 0;
1426  }
1427 
1428  if (NULL == Name)
1429  {
1430  return 0;
1431  }
1432 
1433  if (SymEnd)
1434  {
1435  *SymEnd = 0;
1436  }
1437 
1438  nameLen = strlen(Name);
1439  regexp = Name[nameLen - 1] == '*';
1440 
1441  for (INT32 i = 0; i < gKallsymsBuffers.NumberOfNames; i++)
1442  {
1443  CHAR symName[LIX_SYMBOL_NAME_LEN] = { 0 };
1444 
1445  next = IntKsymExpandSymbol(next, sizeof(symName), symName);
1446  if (!next)
1447  {
1448  ERROR("[ERROR] Failed expanding symbol\n");
1449  return 0;
1450  }
1451 
1452  if ((!regexp && 0 == strcmp(Name, symName)) ||
1453  (regexp && strlen(symName) >= nameLen && 0 == memcmp(Name, symName, nameLen - 1)))
1454  {
1455  start = IntKsymGetAddress(i);
1456 
1457  if (SymEnd)
1458  {
1459  ++i;
1460 
1461  while (i < gKallsymsBuffers.NumberOfNames && start == IntKsymGetAddress(i))
1462  {
1463  ++i;
1464  }
1465 
1466  *SymEnd = IntKsymGetAddress(i);
1467  }
1468 
1469  return start;
1470  }
1471  }
1472 
1473  return 0;
1474 }
#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:502
#define IC_TAG_KSYM
Kallsym cache.
Definition: memtags.h:101
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:61
#define _In_
Definition: intro_sal.h:21
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#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:284
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:1283
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:19
WORD TokenIndex[KSYM_TOKEN_ARRAY_CACHE_SIZE]
The tokens array cached internally.
Definition: lixksym.c:48
static INTSTATUS IntKsymFindMarkersTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of &#39;kallsyms_markers&#39; table.
Definition: lixksym.c:676
QWORD RoDataStart
The guest virtual address where the read-only data starts.
Definition: lixguest.h:503
#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:498
QWORD CodeStart
The guest virtual address where the code starts.
Definition: lixguest.h:497
#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:1046
static INTSTATUS IntKsymRelativeFindOffsetTableEnd(QWORD StartAddress)
Finds the end of &#39;kallsyms_offsets&#39; memory region.
Definition: lixksym.c:330
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
static INTSTATUS IntKsymFindNamesTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of &#39;kallsyms_names&#39; table.
Definition: lixksym.c:854
char * NamesBuffer
The internal name cache used for a faster symbol lookup.
Definition: lixksym.c:36
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
Definition: lixksym.c:1399
char * TokenTable
The internal tokens table.
Definition: lixksym.c:45
static INTSTATUS IntKsymRelativeFindOffsetTableStart(QWORD *Address)
Finds the start of &#39;kallsyms_offsets&#39; memory region.
Definition: lixksym.c:195
#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:919
static INTSTATUS IntKsymFindMarkersReducedTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of &#39;kallsyms_markers&#39; table.
Definition: lixksym.c:758
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
struct _LINUX_GUEST::@126 Layout
#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:33
#define TRUE
Definition: intro_types.h:30
BOOLEAN Initialized
The flag that marks whether the kallsyms module is initialized or not.
Definition: lixksym.c:50
#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
#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:46
QWORD RelativeBase
Definition: lixksym.c:22
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:283
#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:1256
#define LIX_SYMBOL_NAME_LEN
The max length of the ksym as defined by Linux kernel.
Definition: lixguest.h:585
#define PAGE_SIZE
Definition: common.h:70
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:57
QWORD RoDataEnd
The guest virtual address where the read-only data ends.
Definition: lixguest.h:504
QWORD * AddressesBuffer
The internal addresses buffer.
Definition: lixksym.c:41
__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
static QWORD IntKsymGetAddress(INT32 Index)
Returns the address of the symbol located at the given index in the symbols table.
Definition: lixksym.c:164
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
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:534
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
#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:29
INT32 * IndexesBuffer
The Internal indexes buffer.
Definition: lixksym.c:42
QWORD Indexes
The guest virtual address of Indexes table.
Definition: lixksym.c:30
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
char CHAR
Definition: intro_types.h:56
#define KSYM_MARKERS_RANGE_MAX
The maximum value for [ksym_marker, ksym_marker + 1] range.
Definition: lixksym.c:13
#define PAGE_MASK
Definition: pgtable.h:35
QWORD Names
The guest virtual address of the names table.
Definition: lixksym.c:34
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:30
#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
DWORD NamesBufferSize
The size of NamesBuffer.
Definition: lixksym.c:37
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68
struct _KALLSYMS_BUFFERS * PKALLSYMS_BUFFERS