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 79 char *pKallsymsNames = NULL;
80 const BYTE *pData = NULL;
86 ERROR(
"[ERROR] The provided offset is greater than the size of names buffer\n");
90 pKallsymsNames = gKallsymsBuffers.
NamesBuffer + Offset;
91 pData = (
const BYTE *)pKallsymsNames;
96 WARNING(
"[WARNING] Wrong symbol size %d\n", length);
101 nextOffset = Offset + length + 1;
105 ERROR(
"[ERROR] The length of symbol exceeds the names buffer\n");
111 ERROR(
"[ERROR] The next offset exceeds the names buffer\n");
122 ERROR(
"[ERROR] The token_index is greater than the size of token table\n");
180 if (!
LIX_FIELD(Info, HasKsymAbsolutePercpu))
227 ERROR(
"[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
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])
258 startAddr = currentAddr + i * 4ull;
268 ERROR(
"[ERROR] IntVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", startAddr, status);
278 if (
LIX_FIELD(Info, HasKsymAbsolutePercpu))
280 if (ptr[i] == -1 && ptr[i + 1] == -1)
287 if (ptr[i] == 0 && ptr[i + 1] == 0)
294 if (ptr[i] < ptr[i - 1])
306 TRACE(
"[KALLSYMS RELATIVE] Found indexes start @%llx\n", startAddr);
323 *Address = startAddr;
347 QWORD currentAddr = 0;
360 ERROR(
"[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
366 if (pPage[i] == -1 && pPage[i + 1] == -1)
368 firstNegative =
TRUE;
377 if (!firstPositive && pPage[i] > 0)
379 firstPositive =
TRUE;
385 endAddr = currentAddr + i * 4ull;
391 endAddr = currentAddr + i * 4ull;
395 if (
LIX_FIELD(Info, HasKsymAbsolutePercpu))
397 if ((!firstPositive && pPage[i] < 0) ||
398 (firstPositive && pPage[i + 1] >= pPage[i]))
405 if (pPage[i] <= pPage[i + 1])
411 endAddr = currentAddr + i * 4ull;
421 QWORD relativeBase = 0;
422 DWORD numberOfNames = 0;
423 DWORD foundNames = (
DWORD)(endAddr - StartAddress) / 4;
428 ERROR(
"[ERROR] IntKernVirtMemFetchQword failed for GVA 0x%016llx with status: 0x%08x\n",
444 endAddr += (endAddr - StartAddress) * 2;
450 ERROR(
"[ERROR] IntKernVirtMemFetchDword failed for GVA 0x%016llx with status: 0x%08x\n",
456 TRACE(
"[KALLSYMS] num_symbols (found): %d\n", foundNames);
459 if ((foundNames > numberOfNames &&
460 foundNames - numberOfNames > 0x40) ||
461 (foundNames < numberOfNames &&
462 numberOfNames - foundNames > 0x40))
470 ERROR(
"[ERROR] Kallsyms number of names exceeds the limit: %u vs %u",
483 gKallsymsBuffers.
Indexes -= numberOfNames * 8ull;
513 QWORD tableOffsetsStartAddr = 0;
518 ERROR(
"[ERROR] IntKsymRelativeFindOffsetTableStart failed with status: 0x%08x\n", status);
525 ERROR(
"[ERROR] IntKsymRelativeFindOffsetTableEnd failed with status: 0x%08x\n", status);
553 while (gvaStart < gLixGuest->Layout.RoDataEnd)
560 ERROR(
"[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", gvaStart, status);
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])
603 addrStart = gvaStart + i * 8ull;
616 QWORD val = pPage[i];
618 if ((val > 0) && (val < 0x3FFFF))
621 numGva = gvaStart + i * 8ull;
622 TRACE(
"[INFO] Found num_symbols start at 0x%016llx: %d\n", gvaStart + i * 8ull, num);
635 WARNING(
"[WARNING] Unordered list: 0x%016llx 0x%016llx\n", prev, val);
642 WARNING(
"[WARNING] Found an invalid pointer (prev 0x%016llx) 0x%016llx @ 0x%016llx\n",
643 prev, val, gvaStart + i * 8ull);
650 if (addrStart && num)
661 if (!addrStart || !num)
668 gKallsymsBuffers.
Addresses = numGva - num * 8ull;
669 gKallsymsBuffers.
Names = numGva + 8;
693 QWORD *pMarkers = NULL;
695 QWORD currentAddr = StartAddress;
698 if (StartAddress %
sizeof(
QWORD) != 0)
700 ERROR(
"[ERROR] The provided address is not aligned (0x%016llx)!\n", StartAddress);
712 ERROR(
"[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
719 if (pMarkers == NULL)
724 if (*pMarkers > 0xffffffff)
726 *EndAddress = currentAddr;
732 prevAddr = currentAddr;
749 if (pMarkers != NULL)
777 DWORD *pMarkers = NULL;
781 QWORD currentAddr = StartAddress;
783 if (StartAddress %
sizeof(
DWORD) != 0)
785 ERROR(
"[ERROR] The provided address is not aligned (0x%016llx)!\n", StartAddress);
792 if (NULL == pMarkers)
800 if (size ==
sizeof(*pMarkers))
806 size +=
sizeof(*pMarkers);
809 remaining = size -
sizeof(*pMarkers);
814 ERROR(
"[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
821 currentAddr +=
sizeof(*pMarkers);
822 remaining -=
sizeof(*pMarkers);
826 *EndAddress = currentAddr;
844 if (pMarkers != NULL)
872 BYTE *pSymbol = NULL;
874 QWORD currentAddr = StartAddress;
883 ERROR(
"[ERROR] IntVirtMemMap failed for 0x%016llx: 0x%08x\n", currentAddr, status);
893 prevAddr = currentAddr;
894 currentAddr += *pSymbol + 1ull;
903 pSymbol += *pSymbol + 1ull;
912 *EndAddress = currentAddr;
937 WORD indexes[0x5] = { 0 };
938 char tokenSlice[0x30] = { 0 };
939 DWORD remainingTokenLength = (
DWORD)
sizeof(tokenSlice);
940 QWORD currentAddr = TokenTableStart;
947 ERROR(
"[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", TokenTableStart, status);
954 WORD length = (
WORD)
strlen_s(&tokenSlice[indexes[i - 1]], remainingTokenLength) + 1;
955 indexes[i] = indexes[i - 1] + length;
956 remainingTokenLength -= length;
958 if ((
int)remainingTokenLength < 0)
960 ERROR(
"[ERROR] %zu bytes not enough to find indexes. Stopped at %d!\n",
sizeof(tokenSlice), i);
968 WORD idx[
sizeof(indexes) /
sizeof(indexes[0])];
977 ERROR(
"[ERROR] IntVirtMemMap failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
987 ERROR(
"[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
998 memcpy(idx, pIndex,
sizeof(idx));
1004 if (idx[j] != indexes[j])
1013 *IndexesTableStart = currentAddr;
1019 prevAddr = currentAddr;
1029 pIndex = (
WORD *)((
BYTE *)pIndex + 8);
1066 QWORD currentAddr = 0;
1067 QWORD tokenTableStart = 0;
1069 char *pTokenTable = NULL;
1070 char *pNames = NULL;
1071 QWORD *pAddresses = NULL;
1085 ERROR(
"[ERROR] IntKsymInitRelative failed: %08x\n", status);
1089 TRACE(
"[KALLSYMS] indexes : 0x%016llx\n", gKallsymsBuffers.
Indexes);
1097 ERROR(
"[ERROR] IntKsymInitAbsolute failed: %08x\n", status);
1101 TRACE(
"[KALLSYMS] addresses : 0x%016llx\n", gKallsymsBuffers.
Addresses);
1105 TRACE(
"[KALLSYMS] names : 0x%016llx\n", gKallsymsBuffers.
Names);
1110 ERROR(
"[ERROR] IntKsymFindNamesTableEnd failed with status: 0x%08x\n", status);
1113 currentAddr =
ALIGN_UP(currentAddr, 8);
1115 if (
LIX_FIELD(Info, HasKsymReducedSize))
1126 ERROR(
"[ERROR] Failed finding the start of token_table!\n");
1130 tokenTableStart =
ALIGN_UP(currentAddr, 8);
1131 TRACE(
"[KALLSYMS] token_table : 0x%016llx\n", tokenTableStart);
1136 ERROR(
"[ERROR] IntKsymFindIndexesTableStart failed with status: 0x%08x\n", status);
1144 ERROR(
"[ERROR] Tokens table size exceeds the introcore limit: %u vs %u\n",
1151 TRACE(
"[KALLSYMS] token_index : 0x%016llx\n", currentAddr);
1159 ERROR(
"[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1164 if (NULL == pTokenTable)
1172 ERROR(
"[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1176 size = (
DWORD)(tokenTableStart - gKallsymsBuffers.
Names);
1180 ERROR(
"[ERROR] Kallsyms names size exceeds the introcore limit: %u vs %u",
1189 TRACE(
"[INFO] Cache kallsyms names: %d bytes\n", size);
1201 ERROR(
"[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1211 TRACE(
"[INFO] Cache kallsyms addresses: %d bytes\n", size);
1214 if (NULL == pAddresses)
1223 ERROR(
"[ERROR] IntKernVirtMemRead failed for GVA 0x%016llx with status: 0x%08x\n", currentAddr, status);
1236 if (NULL != pTokenTable)
1241 if (NULL != pAddresses)
1286 _Out_ char *SymName,
1315 if (NULL == SymName)
1335 while (high - low > 1)
1337 INT32 mid = low + (high - low) / 2;
1359 INT32 next = low + 1;
1373 *SymStart = symStart;
1376 for (
INT32 i = 0; i < low; i++)
1382 ERROR(
"[ERROR] Failed expanding symbol (offset: %d)!\n", offset);
1390 ERROR(
"[ERROR] Failed expanding symbol (offset: %d)!\n", offset);
1400 _In_ const char *Name,
1438 nameLen = strlen(Name);
1439 regexp = Name[nameLen - 1] ==
'*';
1448 ERROR(
"[ERROR] Failed expanding symbol\n");
1452 if ((!regexp && 0 == strcmp(Name, symName)) ||
1453 (regexp && strlen(symName) >= nameLen && 0 == memcmp(Name, symName, nameLen - 1)))
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
#define KSYM_NUM_SYMBOLS_CAP
The maximum number of symbols allowed to be in kallsyms.
static INTSTATUS IntKsymInitRelative(void)
Initializes the kallsyms subsystem for kernels compiled with CONFIG_KALLSYMS_BASE_RELATIVE.
static DWORD IntKsymExpandSymbol(DWORD Offset, DWORD MaxLength, char *Name)
Expands a kallsyms symbol name.
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
#define PAGE_REMAINING(addr)
DWORD KernelSize
The size of the kernel.
INTSTATUS IntKsymFindByAddress(QWORD Gva, DWORD Length, char *SymName, QWORD *SymStart, QWORD *SymEnd)
Finds the symbol which is located at the given address.
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...
WORD TokenIndex[KSYM_TOKEN_ARRAY_CACHE_SIZE]
The tokens array cached internally.
static INTSTATUS IntKsymFindMarkersTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of 'kallsyms_markers' table.
QWORD RoDataStart
The guest virtual address where the read-only data starts.
#define INT_SUCCESS(Status)
#define HpAllocWithTag(Len, Tag)
int INTSTATUS
The status data type.
QWORD CodeEnd
The guest virtual address where the code ends.
QWORD CodeStart
The guest virtual address where the code starts.
#define INT_STATUS_NOT_FOUND
INTSTATUS IntKsymInit(void)
Initialize the kallsyms subsystem based on the os info provided by LIX_FIELD(Info, HasKsym*).
static INTSTATUS IntKsymRelativeFindOffsetTableEnd(QWORD StartAddress)
Finds the end of 'kallsyms_offsets' memory region.
INTRO_GUEST_TYPE OSType
The type of the guest.
static INTSTATUS IntKsymFindNamesTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of 'kallsyms_names' table.
char * NamesBuffer
The internal name cache used for a faster symbol lookup.
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
char * TokenTable
The internal tokens table.
static INTSTATUS IntKsymRelativeFindOffsetTableStart(QWORD *Address)
Finds the start of 'kallsyms_offsets' memory region.
#define PAGE_FRAME_NUMBER(addr)
static INTSTATUS IntKsymFindIndexesTableStart(QWORD TokenTableStart, QWORD *IndexesTableStart)
Finds the start of 'kallsyms_token_index' table.
static INTSTATUS IntKsymFindMarkersReducedTableEnd(QWORD StartAddress, QWORD *EndAddress)
Finds the end of 'kallsyms_markers' table.
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
#define IS_KERNEL_POINTER_LIX(p)
#define INT_STATUS_NOT_INITIALIZED
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
struct _LINUX_GUEST::@126 Layout
#define INT_STATUS_UNSUCCESSFUL
#define KSYM_TOKEN_TABLE_SIZE_CAP
The maximum size allowed for the tokens table size.
INT32 NumberOfNames
The number of symbols available in kallsyms.
BOOLEAN Initialized
The flag that marks whether the kallsyms module is initialized or not.
#define LIX_FIELD(Structure, Field)
Macro used to access fields inside the LIX_OPAQUE_FIELDS structure.
#define HpFreeAndNullWithTag(Add, Tag)
#define INT_STATUS_INVALID_DATA_STATE
#define INT_STATUS_INVALID_INTERNAL_STATE
DWORD TokenTableSize
The size of the internal tokens table.
QWORD KernelVa
The guest virtual address at which the kernel image.
#define KSYM_TOKEN_ARRAY_CACHE_SIZE
The size of tokens array cache.
#define LIX_SYMBOL_NAME_LEN
The max length of the ksym as defined by Linux kernel.
static KALLSYMS_BUFFERS gKallsymsBuffers
Contains information about kallsyms required for the semantic reconstruction.
QWORD RoDataEnd
The guest virtual address where the read-only data ends.
QWORD * AddressesBuffer
The internal addresses buffer.
__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.
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
static QWORD IntKsymGetAddress(INT32 Index)
Returns the address of the symbol located at the given index in the symbols table.
GUEST_STATE gGuest
The current guest state.
INTSTATUS IntVirtMemRead(QWORD Gva, DWORD Length, QWORD Cr3, void *Buffer, DWORD *RetLength)
Reads data from a guest virtual memory range.
static INTSTATUS IntKsymInitAbsolute(void)
Initializes the kallsyms subsystem for kernels compiled without CONFIG_KALLSYMS_BASE_RELATIVE.
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
#define KSYM_NAMES_CACHE_SIZE_CAP
The maximum size allowed for the names.
QWORD Addresses
The guest virtual address of Addresses table.
INT32 * IndexesBuffer
The Internal indexes buffer.
QWORD Indexes
The guest virtual address of Indexes table.
#define INT_STATUS_NOT_SUPPORTED
#define KSYM_MARKERS_RANGE_MAX
The maximum value for [ksym_marker, ksym_marker + 1] range.
QWORD Names
The guest virtual address of the names table.
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
#define INT_STATUS_INVALID_DATA_SIZE
DWORD NamesBufferSize
The size of NamesBuffer.
#define INT_STATUS_INSUFFICIENT_RESOURCES
#define INT_STATUS_INVALID_PARAMETER_3
struct _KALLSYMS_BUFFERS * PKALLSYMS_BUFFERS