HyperDbg/hyperdbg/symbol-parser/code/symbol-parser.cpp
2026-06-07 16:57:53 +02:00

2334 lines
60 KiB
C++

/**
* @file symbol-parser.cpp
* @author Alee Amini (alee@hyperdbg.org)
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief symbol parser
* @details
* @version 0.1
* @date 2021-05-29
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
#include "header/pdb-identity.h"
//
// Global Variables
//
std::vector<PSYMBOL_LOADED_MODULE_DETAILS> g_LoadedModules;
BOOLEAN g_IsLoadedModulesInitialized = FALSE;
BOOLEAN g_AbortLoadingExecution = FALSE;
CHAR * g_CurrentModuleName = NULL;
PVOID g_MessageHandler = NULL;
SymbolMapCallback g_SymbolMapForDisassembler = NULL;
/**
* @brief Reads the contents of a file into a byte vector
*
* @param LocalFilePath The path to the local file to read
* @param FileBytes An output reference to a vector that will receive the file bytes on success; will be cleared on failure
*
* @return BOOLEAN TRUE if the file was successfully read, FALSE on failure (e.g. file not found, access denied, read error)
*/
static BOOLEAN
SymReadFileBytes(const char * LocalFilePath, std::vector<BYTE> & FileBytes)
{
FileBytes.clear();
if (LocalFilePath == NULL)
{
return FALSE;
}
HANDLE FileHandle = CreateFileA(LocalFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
LARGE_INTEGER FileSize = {0};
if (!GetFileSizeEx(FileHandle, &FileSize) || FileSize.QuadPart <= 0 || (ULONGLONG)FileSize.QuadPart > FileBytes.max_size())
{
CloseHandle(FileHandle);
return FALSE;
}
FileBytes.resize((SIZE_T)FileSize.QuadPart);
BYTE * WriteCursor = FileBytes.data();
SIZE_T Remaining = FileBytes.size();
while (Remaining != 0)
{
DWORD ChunkSize = Remaining > MAXDWORD ? MAXDWORD : (DWORD)Remaining;
DWORD BytesRead = 0;
if (!ReadFile(FileHandle, WriteCursor, ChunkSize, &BytesRead, NULL) || BytesRead == 0)
{
CloseHandle(FileHandle);
FileBytes.clear();
return FALSE;
}
WriteCursor += BytesRead;
Remaining -= BytesRead;
}
CloseHandle(FileHandle);
return TRUE;
}
/**
* @brief Fallback callback function to retrieve PDB file name, GUID, and age information using SymSrvGetFileIndexInfo when the primary extractor fails
*
* @param Context A context pointer that is expected to be a string representing the file path to query with SymSrvGetFileIndexInfo
* @param PdbFile An output buffer to receive the base name of the PDB file extracted from SymSrvGetFileIndexInfo. Must be at least PdbFileSize bytes
* @param PdbFileSize The size of the PdbFile buffer in bytes
* @param Guid An output pointer to receive the GUID extracted from SymSrvGetFileIndexInfo
* @param Age An output pointer to receive the age extracted from SymSrvGetFileIndexInfo
*
* @return BOOLEAN TRUE if the information was successfully retrieved and output buffers were filled as requested, FALSE otherwise (e.g., if Context is invalid or SymSrvGetFileIndexInfo fails)
*/
static BOOLEAN
SymSrvGetFileIndexInfoFallback(PVOID Context, CHAR * PdbFile, SIZE_T PdbFileSize, GUID * Guid, DWORD * Age)
{
SYMSRV_INDEX_INFO SymInfo = {0};
SymInfo.sizeofstruct = sizeof(SYMSRV_INDEX_INFO);
if (Context == NULL || PdbFile == NULL || Guid == NULL || Age == NULL)
{
return FALSE;
}
if (!SymSrvGetFileIndexInfo((const char *)Context, &SymInfo, 0))
{
return FALSE;
}
if (FAILED(StringCchCopyA(PdbFile, PdbFileSize, SymInfo.pdbfile)))
{
return FALSE;
}
*Guid = SymInfo.guid;
*Age = SymInfo.age;
return TRUE;
}
/**
* @brief Set the function callback that will be called if any message
* needs to be shown
*
* @param Handler Function that handles the messages
*/
void
SymSetTextMessageCallback(PVOID Handler)
{
g_MessageHandler = Handler;
//
// Set the pdbex's message handler
//
pdbex_set_logging_method_export(Handler);
}
/**
* @brief Show messages
*
* @param Fmt format string message
*/
VOID
ShowMessages(const char * Fmt, ...)
{
va_list ArgList;
va_list Args;
if (g_MessageHandler == NULL)
{
va_start(Args, Fmt);
vprintf(Fmt, Args);
va_end(Args);
}
else
{
char TempMessage[COMMUNICATION_BUFFER_SIZE + TCP_END_OF_BUFFER_CHARS_COUNT] = {0};
va_start(ArgList, Fmt);
INT SprintfResult = vsprintf_s(TempMessage, Fmt, ArgList);
va_end(ArgList);
if (SprintfResult != -1)
{
//
// There is another handler
//
((SendMessageWithParamCallback)g_MessageHandler)(TempMessage);
}
}
}
/**
* @brief Interpret and find module base, based on module name
* @param SearchMask the search mask to find module
* @param SetModuleNameGlobally whether to set module name globally
*
* @return PSYMBOL_LOADED_MODULE_DETAILS NULL means error or not found,
* otherwise it returns the instance of loaded module based on search mask
*/
PSYMBOL_LOADED_MODULE_DETAILS
SymGetModuleBaseFromSearchMask(const char * SearchMask, BOOLEAN SetModuleNameGlobally)
{
string Token;
char ModuleName[_MAX_FNAME] = {0};
int Index = 0;
char Ch = '\0';
if (!g_IsLoadedModulesInitialized || SearchMask == NULL)
{
//
// no module is loaded or search mask is invalid
//
return NULL;
}
//
// Convert search mask to string
//
string SearchMaskString(SearchMask);
//
// Check if the string contains '!'
//
char Delimiter = '!';
if (SearchMaskString.find(Delimiter) != std::string::npos)
{
//
// Found
//
Token = SearchMaskString.substr(0, SearchMaskString.find(Delimiter));
strcpy(ModuleName, Token.c_str());
if (ModuleName[0] == '\0')
{
//
// Invalid name
//
return NULL;
}
//
// Convert module name to lowercase
//
while (ModuleName[Index])
{
Ch = ModuleName[Index];
//
// convert ch to lowercase using toLower()
//
ModuleName[Index] = tolower(Ch);
Index++;
}
}
else
{
//
// There is no '!' in the middle of the search mask so,
// we assume that the module is nt
//
RtlZeroMemory(ModuleName, _MAX_FNAME);
ModuleName[0] = 'n';
ModuleName[1] = 't';
}
//
// ************* Interpret based on remarks type name *************
//
for (auto item : g_LoadedModules)
{
//
// Check for the module name
//
if (strcmp((const char *)item->ModuleName, ModuleName) == 0)
{
if (SetModuleNameGlobally)
{
g_CurrentModuleName = (char *)item->ModuleName;
}
return item;
}
//
// Check for alternative module name
//
if (strcmp((const char *)item->ModuleAlternativeName, ModuleName) == 0)
{
if (SetModuleNameGlobally)
{
g_CurrentModuleName = (char *)item->ModuleAlternativeName;
}
return item;
}
}
//
// If the function continues until here then it means
// that the module not found
//
return NULL;
}
/**
* @brief Get the offset of a field from the top of a structure
* @param Base
* @param TypeName
* @param FieldName
* @param FieldOffset
* @details This function is derived from: https://github.com/0vercl0k/sic/blob/master/src/sic/sym.cc
*
* @return BOOLEAN Whether the module is found successfully or not
*/
BOOLEAN
SymGetFieldOffsetFromModule(UINT64 Base, WCHAR * TypeName, WCHAR * FieldName, UINT32 * FieldOffset)
{
BOOLEAN Found = FALSE;
//
// Allocate a buffer to back the SYMBOL_INFO structure
//
const DWORD SizeOfStruct =
sizeof(SYMBOL_INFOW) + ((MAX_SYM_NAME - 1) * sizeof(wchar_t));
UINT8 SymbolInfoBuffer[SizeOfStruct];
auto SymbolInfo = PSYMBOL_INFOW(SymbolInfoBuffer);
//
// Initialize the fields that need initialization
//
SymbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);
SymbolInfo->MaxNameLen = MAX_SYM_NAME;
//
// Retrieve a type index for the type we're after
//
if (!SymGetTypeFromNameW(GetCurrentProcess(), Base, TypeName, SymbolInfo))
{
// ShowMessages("err, SymGetTypeFromName failed (%x)\n",
// GetLastError());
return FALSE;
}
//
// Now that we have a type, we need to enumerate its children to find the
// field we're after. First step is to get the number of children
//
const ULONG TypeIndex = SymbolInfo->TypeIndex;
DWORD ChildrenCount = 0;
if (!SymGetTypeInfo(GetCurrentProcess(), Base, TypeIndex, TI_GET_CHILDRENCOUNT, &ChildrenCount))
{
// ShowMessages("err, SymGetTypeInfo failed (%x)\n",
// GetLastError());
return FALSE;
}
//
// Allocate enough memory to receive the children ids
//
auto FindChildrenParamsBacking = std::make_unique<UINT8[]>(
sizeof(_TI_FINDCHILDREN_PARAMS) + ((ChildrenCount - 1) * sizeof(ULONG)));
auto FindChildrenParams =
(_TI_FINDCHILDREN_PARAMS *)FindChildrenParamsBacking.get();
//
// Initialize the structure with the children count
//
FindChildrenParams->Count = ChildrenCount;
//
// Get all the children ids
//
if (!SymGetTypeInfo(GetCurrentProcess(), Base, TypeIndex, TI_FINDCHILDREN, FindChildrenParams))
{
// ShowMessages("err, SymGetTypeInfo failed (%x)\n",
// GetLastError());
return FALSE;
}
//
// Now that we have all the ids, we can walk them and find the one that
// matches the field we're looking for
//
for (DWORD ChildIdx = 0; ChildIdx < ChildrenCount; ChildIdx++)
{
//
// Grab the child name
//
const ULONG ChildId = FindChildrenParams->ChildId[ChildIdx];
WCHAR * ChildName = nullptr;
SymGetTypeInfo(GetCurrentProcess(), Base, ChildId, TI_GET_SYMNAME, &ChildName);
//
// Grab the child size - this is useful to know if a field is a bit or a
// normal field
//
UINT64 ChildSize = 0;
SymGetTypeInfo(GetCurrentProcess(), Base, ChildId, TI_GET_LENGTH, &ChildSize);
//
// Does this child's name match the field we're looking for?
//
Found = FALSE;
if (wcscmp(ChildName, FieldName) == 0)
{
//
// If we have found the field, now we need to find its offset if
// it's a normal field, or its bit position if it is a bit
//
const IMAGEHLP_SYMBOL_TYPE_INFO Info =
(ChildSize == 1) ? TI_GET_BITPOSITION : TI_GET_OFFSET;
SymGetTypeInfo(GetCurrentProcess(), Base, ChildId, Info, FieldOffset);
Found = TRUE;
}
//
// Even if we have found a match, we need to clean up the memory
//
LocalFree(ChildName);
ChildName = nullptr;
//
// We can now break out of the loop if we have what we came looking for
//
if (Found)
{
break;
}
}
return Found;
}
/**
* @brief Get the size of a data type (structure)
* @param Base
* @param TypeName
* @param TypeSize
*
* @return BOOLEAN Whether the module is found successfully or not
*/
BOOLEAN
SymGetDataTypeSizeFromModule(UINT64 Base, WCHAR * TypeName, UINT64 * TypeSize)
{
//
// Allocate a buffer to back the SYMBOL_INFO structure
//
const DWORD SizeOfStruct =
sizeof(SYMBOL_INFOW) + ((MAX_SYM_NAME - 1) * sizeof(wchar_t));
UINT8 SymbolInfoBuffer[SizeOfStruct];
auto SymbolInfo = PSYMBOL_INFOW(SymbolInfoBuffer);
//
// Initialize the fields that need initialization
//
SymbolInfo->SizeOfStruct = sizeof(SYMBOL_INFOW);
SymbolInfo->MaxNameLen = MAX_SYM_NAME;
//
// Retrieve a type index for the type we're after
//
if (!SymGetTypeFromNameW(GetCurrentProcess(), Base, TypeName, SymbolInfo))
{
// ShowMessages("err, SymGetTypeFromName failed (%x)\n",
// GetLastError());
return FALSE;
}
if (!SymGetTypeInfo(GetCurrentProcess(), Base, SymbolInfo->TypeIndex, TI_GET_LENGTH, TypeSize))
{
// ShowMessages("err, SymGetTypeInfo failed (%x)\n",
// GetLastError());
return FALSE;
}
// ShowMessages("type size : %llx\n", TypeSize);
return TRUE;
}
/**
* @brief initialize the DbgHelp symbols
*
* @return BOOLEAN
*/
BOOLEAN
SymInit()
{
BOOL Ret = FALSE;
DWORD Options = 0;
//
// Get options
//
Options = SymGetOptions();
//
// SYMOPT_DEBUG option asks DbgHelp to print additional troubleshooting
// messages to debug output - use the debugger's Debug Output window
// to view the messages
//
Options |= SYMOPT_DEBUG;
Options |= SYMOPT_CASE_INSENSITIVE;
SymSetOptions(Options);
//
// Initialize DbgHelp and load symbols for all modules of the current process
//
Ret = SymInitialize(
GetCurrentProcess(), // Process handle of the current process
NULL, // No user-defined search path -> use default
FALSE // Do not load symbols for modules in the current process
);
if (!Ret)
{
ShowMessages("err, symbol init failed (%x)\n",
GetLastError());
return FALSE;
}
//
// Indicate that at least one module is loaded
//
g_IsLoadedModulesInitialized = TRUE;
return TRUE;
}
/**
* @brief Remove wow64 extension to the module names
*
* @param ModuleAddress
* @param PdbFileName
*
* @return BOOLEAN
*/
BOOLEAN
SymCheckAndRemoveWow64Prefix(const char * ModuleAddress, const char * PdbFileName, std::string & CustomModuleName)
{
char ModuleName[_MAX_FNAME] = {0};
char PdbModuleName[_MAX_FNAME] = {0};
//
// Determine the name of the file
//
_splitpath(ModuleAddress, NULL, NULL, ModuleName, NULL);
_splitpath(PdbFileName, NULL, NULL, PdbModuleName, NULL);
//
// Convert ModuleName to lowercase
//
std::transform(ModuleName, ModuleName + strlen(ModuleName), ModuleName, [](unsigned char c) { return std::tolower(c); });
//
// Convert PdbModuleName to lowercase
//
std::transform(PdbModuleName, PdbModuleName + strlen(PdbModuleName), PdbModuleName, [](unsigned char c) { return std::tolower(c); });
//
// Compare the lowercase strings
//
if (std::strcmp(ModuleName, PdbModuleName) == 0)
{
return FALSE;
}
else
{
// Convert ModuleAddress to lowercase
std::string LowerModuleAddress(ModuleAddress);
std::transform(LowerModuleAddress.begin(), LowerModuleAddress.end(), LowerModuleAddress.begin(), [](unsigned char c) { return std::tolower(c); });
if (PdbModuleName[0] == 'w' && LowerModuleAddress.find(":\\windows\\system32") != std::string::npos)
{
//
// Set CustomModuleName to lowercase ModuleName
//
CustomModuleName = std::string(ModuleName);
return TRUE;
}
else
{
return FALSE;
}
}
}
/**
* @brief Check for alternative name of ntoskrn;
*
* @param PdbFileName
* @param CustomModuleName
*
* @return BOOLEAN
*/
BOOLEAN
SymCheckNtoskrnlPrefix(const char * PdbFileName, std::string & CustomModuleName)
{
char PdbModuleName[_MAX_FNAME] = {0};
//
// Determine the name of the file
//
_splitpath(PdbFileName, NULL, NULL, PdbModuleName, NULL);
//
// Convert PdbModuleName to lowercase
//
std::transform(PdbModuleName, PdbModuleName + strlen(PdbModuleName), PdbModuleName, [](unsigned char c) { return std::tolower(c); });
//
// Is it "nt" module or not
//
// Names of kernel
// NTOSKRNL.EXE : 1 CPU
// NTKRNLMP.EXE : N CPU, SMP
// NTKRNLPA.EXE : 1 CPU, PAE
// NTKRPAMP.EXE : N CPU SMP, PAE
//
if (strcmp(PdbModuleName, ("ntkrnlmp")) == 0 || strcmp(PdbModuleName, ("ntoskrnl")) == 0 ||
strcmp(PdbModuleName, ("ntkrpamp")) == 0 || strcmp(PdbModuleName, ("ntkrnlpa")) == 0)
{
CustomModuleName = "nt";
return TRUE;
}
//
// Not nt module
//
return FALSE;
}
/**
* @brief load symbol based on a file name and GUID
*
* @param BaseAddress
* @param PdbFileName
* @param CustomModuleName
*
* @return UINT32
*/
UINT32
SymLoadFileSymbol(UINT64 BaseAddress, const char * PdbFileName, const char * CustomModuleName)
{
DWORD FileSize = 0;
int Index = 0;
char Ch = '\0';
char ModuleName[_MAX_FNAME] = {0};
char AlternateModuleName[_MAX_FNAME] = {0};
PSYMBOL_LOADED_MODULE_DETAILS ModuleDetails = NULL;
//
// Check if the loaded modules are initialized or not
//
if (!g_IsLoadedModulesInitialized)
{
//
// Initialize the symbol table
//
SymInit();
}
//
// Determine the base address and the file size
//
if (!SymGetFileParams(PdbFileName, FileSize))
{
ShowMessages("err, cannot obtain file parameters (internal error)\n");
return -1;
}
//
// Determine the name of the file
//
_splitpath(PdbFileName, NULL, NULL, ModuleName, NULL);
//
// Move to alternate list
//
strcpy(AlternateModuleName, ModuleName);
//
// Convert module name to lowercase
//
while (ModuleName[Index])
{
Ch = ModuleName[Index];
//
// convert ch to lowercase using toLower()
//
ModuleName[Index] = tolower(Ch);
Index++;
}
//
// Allocate buffer to store the details
//
ModuleDetails = (SYMBOL_LOADED_MODULE_DETAILS *)malloc(sizeof(SYMBOL_LOADED_MODULE_DETAILS));
if (ModuleDetails == NULL)
{
ShowMessages("err, allocating buffer for storing symbol details (%x)\n",
GetLastError());
return -1;
}
RtlZeroMemory(ModuleDetails, sizeof(SYMBOL_LOADED_MODULE_DETAILS));
ModuleDetails->ModuleBase = SymLoadModule64(
GetCurrentProcess(), // Process handle of the current process
NULL, // Handle to the module's image file (not needed)
PdbFileName, // Path/name of the file
NULL, // User-defined short name of the module (it can be NULL)
BaseAddress, // Base address of the module (cannot be NULL if .PDB file is
// used, otherwise it can be NULL)
FileSize // Size of the file (cannot be NULL if .PDB file is used,
// otherwise it can be NULL)
);
if (ModuleDetails->ModuleBase == NULL)
{
ShowMessages("err, loading symbols failed (%x)\n",
GetLastError());
free(ModuleDetails);
return -1;
}
#ifndef DoNotShowDetailedResult
//
// Load symbols for the module
//
ShowMessages("loading symbols for: %s\n", PdbFilePath);
ShowMessages("load address: %I64x\n", ModuleDetails.ModuleBase);
//
// Obtain and display information about loaded symbols
//
SymShowSymbolInfo(ModuleDetails.ModuleBase);
#endif // !DoNotShowDetailedResult
//
// Make the details (to save)
//
ModuleDetails->BaseAddress = BaseAddress;
strcpy((char *)ModuleDetails->ModuleName, ModuleName);
strcpy((char *)ModuleDetails->PdbFilePath, PdbFileName);
//
// Save the custom module name (if any)
//
if (CustomModuleName != NULL)
{
strcpy((char *)ModuleDetails->ModuleAlternativeName, CustomModuleName);
}
//
// Save it
//
g_LoadedModules.push_back(ModuleDetails);
return 0;
}
/**
* @brief Unload one module symbol
*
* @param ModuleName
*
* @return UINT32
*/
UINT32
SymUnloadModuleSymbol(char * ModuleName)
{
BOOLEAN OneModuleFound = FALSE;
BOOL Ret = FALSE;
UINT32 Index = 0;
for (auto item : g_LoadedModules)
{
Index++;
if (strcmp(item->ModuleName, ModuleName) == 0 || strcmp(item->ModuleAlternativeName, ModuleName) == 0)
{
//
// Unload symbol for the module
//
Ret = SymUnloadModule64(GetCurrentProcess(), item->ModuleBase);
if (!Ret)
{
ShowMessages("err, unload symbol failed (%x)\n",
GetLastError());
return -1;
}
OneModuleFound = TRUE;
free(item);
break;
}
}
if (!OneModuleFound)
{
//
// Not found
//
return -1;
}
//
// Remove it from the vector
//
std::vector<PSYMBOL_LOADED_MODULE_DETAILS>::iterator it = g_LoadedModules.begin();
std::advance(it, --Index);
g_LoadedModules.erase(it);
//
// Success
//
return 0;
}
/**
* @brief Unload all the symbols
*
* @return UINT32
*/
UINT32
SymUnloadAllSymbols()
{
BOOL Ret = FALSE;
BOOLEAN IsAnythingLoaded = FALSE;
//
// Check if it's already initialized
//
if (!g_IsLoadedModulesInitialized)
{
return 0;
}
for (auto item : g_LoadedModules)
{
//
// At least one module is loaded
//
IsAnythingLoaded = TRUE;
//
// Unload symbols for the module
//
Ret = SymUnloadModule64(GetCurrentProcess(), item->ModuleBase);
if (!Ret)
{
// ShowMessages("err, unload symbol failed (%x)\n",
// GetLastError());
}
free(item);
}
//
// Check if there is at least one module is loaded
//
if (!IsAnythingLoaded)
{
//
// Nothing is loaded yet!
//
return 0;
}
//
// Clear the list
//
g_LoadedModules.clear();
//
// Uninitialize DbgHelp
//
Ret = SymCleanup(GetCurrentProcess());
if (!Ret)
{
ShowMessages("err, symbol cleanup failed (%x)\n", GetLastError());
return 0;
}
//
// It's not initialized anymore
//
g_IsLoadedModulesInitialized = FALSE;
return 0;
}
/**
* @brief Convert function name to address
*
* @param FunctionOrVariableName the name of the function or variable to convert
* @param WasFound
*
* @return UINT64
*/
UINT64
SymConvertNameToAddress(const char * FunctionOrVariableName, PBOOLEAN WasFound)
{
BOOLEAN Found = FALSE;
UINT64 Address = NULL;
UINT64 Buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR) + sizeof(UINT64) - 1) / sizeof(UINT64)];
PSYMBOL_INFO Symbol = (PSYMBOL_INFO)Buffer;
string FinalModuleName;
string TempName(FunctionOrVariableName);
string ExtractedModuleName;
string FunctionName;
//
// Not found by default
//
*WasFound = FALSE;
//
// Retrieve the address from name
//
Symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
Symbol->MaxNameLen = MAX_SYM_NAME;
//
// *** Check if the module has an alternative name, then replace the
// original name with alternative name ***
//
//
// Check if '!' is present in the function or variable name
//
SIZE_T FoundIndex = TempName.find('!');
if (FoundIndex != std::string::npos)
{
ExtractedModuleName = TempName.substr(0, FoundIndex);
FunctionName = TempName.substr(FoundIndex + 1);
//
// Convert module name to lower-case
//
std::transform(ExtractedModuleName.begin(), ExtractedModuleName.end(), ExtractedModuleName.begin(), [](unsigned char c) {
return std::tolower(c);
});
//
// Check if the we find it with an alternative module name or not
//
for (auto item : g_LoadedModules)
{
//
// Check for the module name
//
if (strcmp((const char *)item->ModuleName, ExtractedModuleName.c_str()) == 0)
{
string ModuleName(item->ModuleName);
FinalModuleName = ModuleName + "!" + FunctionName;
break;
}
//
// Check for the alternative module name
//
if (strcmp((const char *)item->ModuleAlternativeName, ExtractedModuleName.c_str()) == 0)
{
//
// Replace the alternative module name with original module name
//
string ModuleName(item->ModuleName);
FinalModuleName = ModuleName + "!" + FunctionName;
break;
}
}
}
else
{
//
// It doesn't contain a module name, so we'll use 'nt' by default
//
for (auto item : g_LoadedModules)
{
//
// Check for the module name
//
if (strcmp((const char *)item->ModuleAlternativeName, "nt") == 0)
{
//
// Replace the alternative module name with original module name
//
string ModuleName(item->ModuleName);
FinalModuleName = ModuleName + "!" + TempName;
break;
}
}
}
//
// Check if the final module name is not empty
//
if (FinalModuleName.empty())
{
*WasFound = FALSE;
return NULL;
}
if (SymFromName(GetCurrentProcess(), FinalModuleName.c_str(), Symbol))
{
//
// SymFromName returned success
//
Found = TRUE;
Address = Symbol->Address;
}
else
{
//
// SymFromName failed
//
Found = FALSE;
//
// ShowMessages("symbol not found (%x)\n", GetLastError());
//
}
*WasFound = Found;
return Address;
}
/**
* @brief Search and show symbols
* @details mainly used by the 'x' command
*
* @param TypeName
* @param FieldName
* @param FieldOffset
*
* @return BOOLEAN Whether the module is found successfully or not
*/
BOOLEAN
SymGetFieldOffset(CHAR * TypeName, CHAR * FieldName, UINT32 * FieldOffset)
{
BOOL Ret = FALSE;
UINT32 Index = 0;
PSYMBOL_LOADED_MODULE_DETAILS SymbolInfo = NULL;
BOOLEAN Result = FALSE;
//
// Find module info
//
SymbolInfo = SymGetModuleBaseFromSearchMask(TypeName, TRUE);
//
// Check if module is found
//
if (SymbolInfo == NULL)
{
//
// Module not found or there was an error
//
return FALSE;
}
//
// Remove the *!Name from TypeName as it not supports module name
// at the beginning of a type name
//
while (TypeName[Index] != '\0')
{
if (TypeName[Index] == '!')
{
TypeName = (CHAR *)(TypeName + Index + 1);
break;
}
Index++;
}
//
// Convert TypeName to wide-char, it's because SymGetTypeInfo supports
// wide-char
//
const SIZE_T TypeNameSize = strlen(TypeName) + 1;
WCHAR * TypeNameW = (WCHAR *)malloc(sizeof(wchar_t) * TypeNameSize);
if (TypeNameW == NULL)
{
printf("err, could not allocate buffer");
return FALSE;
}
RtlZeroMemory(TypeNameW, sizeof(wchar_t) * TypeNameSize);
mbstowcs(TypeNameW, TypeName, TypeNameSize);
//
// Convert FieldName to wide-char, it's because SymGetTypeInfo supports
// wide-char
//
const SIZE_T FieldNameSize = strlen(FieldName) + 1;
WCHAR * FieldNameW = (WCHAR *)malloc(sizeof(wchar_t) * FieldNameSize);
if (FieldNameW == NULL)
{
printf("err, could not allocate buffer");
free(TypeNameW);
return FALSE;
}
RtlZeroMemory(FieldNameW, sizeof(wchar_t) * FieldNameSize);
mbstowcs(FieldNameW, FieldName, FieldNameSize);
Result = SymGetFieldOffsetFromModule(SymbolInfo->ModuleBase, TypeNameW, FieldNameW, FieldOffset);
free(TypeNameW);
free(FieldNameW);
return Result;
}
/**
* @brief Get the size of structures from the symbols
*
* @param TypeName the type (structure) name to query
* @param TypeSize pointer to receive the size of the data type
*
* @return BOOLEAN Whether the module is found successfully or not
*/
BOOLEAN
SymGetDataTypeSize(CHAR * TypeName, UINT64 * TypeSize)
{
BOOL Ret = FALSE;
UINT32 Index = 0;
PSYMBOL_LOADED_MODULE_DETAILS SymbolInfo = NULL;
BOOLEAN Result = FALSE;
//
// Find module info
//
SymbolInfo = SymGetModuleBaseFromSearchMask(TypeName, TRUE);
//
// Check if module is found
//
if (SymbolInfo == NULL)
{
//
// Module not found or there was an error
//
return FALSE;
}
//
// Remove the *!Name from TypeName as it not supports module name
// at the beginning of a type name
//
while (TypeName[Index] != '\0')
{
if (TypeName[Index] == '!')
{
TypeName = (CHAR *)(TypeName + Index + 1);
break;
}
Index++;
}
//
// Convert FieldName to wide-char, it's because SymGetTypeInfo supports
// wide-char
//
const SIZE_T TypeNameSize = strlen(TypeName) + 1;
WCHAR * TypeNameW = (WCHAR *)malloc(sizeof(wchar_t) * TypeNameSize);
if (TypeNameW == NULL)
{
printf("err, could not allocate buffer");
return FALSE;
}
RtlZeroMemory(TypeNameW, sizeof(wchar_t) * TypeNameSize);
mbstowcs(TypeNameW, TypeName, TypeNameSize);
Result = SymGetDataTypeSizeFromModule(SymbolInfo->ModuleBase, TypeNameW, TypeSize);
free(TypeNameW);
return Result;
}
/**
* @brief Gets the offset from the symbol
*
* @param SearchMask
*
* @return UINT32
*/
UINT32
SymSearchSymbolForMask(const char * SearchMask)
{
BOOL Ret = FALSE;
PSYMBOL_LOADED_MODULE_DETAILS SymbolInfo = NULL;
//
// Get the module info
//
SymbolInfo = SymGetModuleBaseFromSearchMask(SearchMask, TRUE);
//
// Check to see if module info is found
//
if (SymbolInfo == NULL)
{
//
// Module not found or there was an error
//
return -1;
}
Ret = SymEnumSymbols(
GetCurrentProcess(), // Process handle of the current process
SymbolInfo->ModuleBase, // Base address of the module
SearchMask, // Mask (NULL -> all symbols)
SymDisplayMaskSymbolsCallback, // The callback function
NULL // A used-defined context can be passed here, if necessary
);
if (!Ret)
{
ShowMessages("err, symbol enum failed (%x)\n",
GetLastError());
}
return 0;
}
/**
* @brief Create symbol table for disassembler
* @details mainly used by disassembler for 'u' command
*
* @param CallbackFunction
*
* @return BOOLEAN
*/
BOOLEAN
SymCreateSymbolTableForDisassembler(void * CallbackFunction)
{
BOOL Ret = FALSE;
BOOLEAN Result = TRUE;
//
// Set the callback function to deliver the name of module!ObjectName
//
g_SymbolMapForDisassembler = (SymbolMapCallback)CallbackFunction;
//
// Create a symbol table from all modules
//
for (auto item : g_LoadedModules)
{
//
// Set module name
//
g_CurrentModuleName = (char *)item->ModuleName;
//
// Call the callback for the current module
//
Ret = SymEnumSymbols(
GetCurrentProcess(), // Process handle of the current process
item->BaseAddress, // Base address of the module
NULL, // Mask (NULL -> all symbols)
SymDeliverDisassemblerSymbolMapCallback, // The callback function
NULL // A used-defined context can be passed here, if necessary
);
if (!Ret)
{
//
// A module did not added correctly
//
// ShowMessages("err, symbol enum failed (%x)\n", GetLastError());
Result = FALSE;
}
}
return Result;
}
/**
* @brief add ` between 64 bit values and convert them to string
*
* @param Value
* @return string
*/
string
SymSeparateTo64BitValue(UINT64 Value)
{
ostringstream OstringStream;
string Temp;
OstringStream << setw(16) << setfill('0') << hex << Value;
Temp = OstringStream.str();
Temp.insert(8, 1, '`');
return Temp;
}
/**
* @brief Get symbol file parameters
*
* @param FileName
* @param BaseAddr
* @param FileSize
*
* @return BOOL
*/
BOOL
SymGetFileParams(const char * FileName, DWORD & FileSize)
{
//
// Check parameters
//
if (FileName == 0)
{
return FALSE;
}
//
// Determine the extension of the file
//
char FileExt[_MAX_EXT] = {0};
_splitpath(FileName, NULL, NULL, NULL, FileExt);
//
// Is it .PDB file?
//
if (strcmp(FileExt, (".pdb")) == 0 || strcmp(FileExt, (".PDB")) == 0)
{
//
// Yes, it is a .PDB file
// Determine its size, and use a dummy base address
//
if (!SymGetFileSize(FileName, FileSize))
{
return FALSE;
}
}
else
{
//
// It is not a .PDB file
// Base address and file size can be 0
//
FileSize = 0;
return FALSE;
}
return TRUE;
}
/**
* @brief Get symbol file size
*
* @param FileName
* @param FileSize
*
* @return BOOL
*/
BOOL
SymGetFileSize(const char * FileName, DWORD & FileSize)
{
//
// Check parameters
//
if (FileName == 0)
{
return FALSE;
}
//
// Open the file
//
HANDLE HFile = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (HFile == INVALID_HANDLE_VALUE)
{
ShowMessages("err, unable to open symbol file (%x)\n", GetLastError());
return FALSE;
}
//
// Obtain the size of the file
//
FileSize = GetFileSize(HFile, NULL);
if (FileSize == INVALID_FILE_SIZE)
{
ShowMessages("err, unable to get symbol file size (%x)\n", GetLastError());
//
// and continue ...
//
}
//
// Close the file
//
if (!CloseHandle(HFile))
{
ShowMessages("err, unable to close symbol file (%x)\n", GetLastError());
//
// and continue ...
//
}
return (FileSize != INVALID_FILE_SIZE);
}
/**
* @brief Show symbol info
*
* @param ModuleBase
*
* @return VOID
*/
VOID
SymShowSymbolInfo(UINT64 ModuleBase)
{
//
// Get module information
//
IMAGEHLP_MODULE64 ModuleInfo;
memset(&ModuleInfo, 0, sizeof(ModuleInfo));
ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
BOOL Ret = SymGetModuleInfo64(GetCurrentProcess(), ModuleBase, &ModuleInfo);
if (!Ret)
{
ShowMessages("err, unable to get symbol file information (%x)\n",
GetLastError());
return;
}
//
// Display information about symbols
// Kind of symbols
//
switch (ModuleInfo.SymType)
{
case SymNone:
ShowMessages("no symbols available for the module\n");
break;
case SymExport:
ShowMessages("loaded symbols: Exports\n");
break;
case SymCoff:
ShowMessages("loaded symbols: COFF\n");
break;
case SymCv:
ShowMessages("loaded symbols: CodeView\n");
break;
case SymSym:
ShowMessages("loaded symbols: SYM\n");
break;
case SymVirtual:
ShowMessages("loaded symbols: Virtual\n");
break;
case SymPdb:
ShowMessages("loaded symbols: PDB\n");
break;
case SymDia:
ShowMessages("loaded symbols: DIA\n");
break;
case SymDeferred:
//
// not actually loaded
//
ShowMessages("loaded symbols: Deferred\n");
break;
default:
ShowMessages("loaded symbols: Unknown format\n");
break;
}
//
// Image name
//
if (ModuleInfo.ImageName[0] != '\0')
{
ShowMessages("image name: %s\n", ModuleInfo.ImageName);
}
//
// Loaded image name
//
if (ModuleInfo.LoadedImageName[0] != '\0')
{
ShowMessages("loaded image name: %s\n", ModuleInfo.LoadedImageName);
}
//
// Loaded PDB name
//
if (ModuleInfo.LoadedPdbName[0] != '\0')
{
ShowMessages("PDB file name: %s\n", ModuleInfo.LoadedPdbName);
}
//
// Is debug information unmatched?
// (It can only happen if the debug information is contained
// in a separate file (.DBG or .PDB)
//
if (ModuleInfo.PdbUnmatched || ModuleInfo.DbgUnmatched)
{
ShowMessages("warning, unmatched symbols\n");
}
//
// *** Contents ***
//
//
// Line numbers available?
//
ShowMessages("line numbers: %s\n",
ModuleInfo.LineNumbers ? "available" : "not available");
//
// Global symbols available?
//
ShowMessages("global symbols: %s\n",
ModuleInfo.GlobalSymbols ? "available" : "not available");
//
// Type information available?
//
ShowMessages("type information: %s\n",
ModuleInfo.TypeInfo ? ("Available") : ("Not available"));
//
// Source indexing available?
//
ShowMessages("source indexing: %s\n",
ModuleInfo.SourceIndexed ? "yes" : "no");
//
// Public symbols available?
//
ShowMessages("public symbols: %s\n",
ModuleInfo.Publics ? "available" : "not available");
}
/**
* @brief Callback for showing and enumerating symbols
*
* @param SymInfo
* @param SymbolSize
* @param UserContext
*
* @return BOOL
*/
BOOL CALLBACK
SymDisplayMaskSymbolsCallback(SYMBOL_INFO * SymInfo, ULONG SymbolSize, PVOID UserContext)
{
if (SymInfo != 0)
{
SymShowSymbolDetails(*SymInfo);
}
//
// Continue enumeration
//
return TRUE;
}
/**
* @brief Callback for delivering module!ObjectName to disassembler symbol map
*
* @param SymInfo
* @param SymbolSize
* @param UserContext
*
* @return BOOL
*/
BOOL CALLBACK
SymDeliverDisassemblerSymbolMapCallback(SYMBOL_INFO * SymInfo, ULONG SymbolSize, PVOID UserContext)
{
if (SymInfo != 0 && g_SymbolMapForDisassembler != NULL)
{
//
// Call the remote callback
//
g_SymbolMapForDisassembler(SymInfo->Address, g_CurrentModuleName, SymInfo->Name, SymInfo->Size);
}
//
// Continue enumeration
//
return TRUE;
}
/**
* @brief Show symbols details
*
* @param SymInfo
*
* @return VOID
*/
VOID
SymShowSymbolDetails(SYMBOL_INFO & SymInfo)
{
if (g_CurrentModuleName == NULL)
{
//
// Name Address
//
ShowMessages("%s ", SymSeparateTo64BitValue(SymInfo.Address).c_str());
}
else
{
//
// Module!Name Address
//
ShowMessages("%s %s!", SymSeparateTo64BitValue(SymInfo.Address).c_str(), g_CurrentModuleName);
}
//
// Name
//
ShowMessages("%s\n", SymInfo.Name);
#ifndef DoNotShowDetailedResult
//
// Size
//
ShowMessages(" size: %u", SymInfo.Size);
//
// Kind of symbol (tag)
//
ShowMessages(" symbol: %s ", SymTagStr(SymInfo.Tag));
#endif // !DoNotShowDetailedResult
}
/**
* @brief Interpret different tags for pdbs
*
* @param Tag
*
* @return const char *
*/
const char *
SymTagStr(ULONG Tag)
{
switch (Tag)
{
case SymTagNull:
return ("Null");
case SymTagExe:
return ("Exe");
case SymTagCompiland:
return ("Compiland");
case SymTagCompilandDetails:
return ("CompilandDetails");
case SymTagCompilandEnv:
return ("CompilandEnv");
case SymTagFunction:
return ("Function");
case SymTagBlock:
return ("Block");
case SymTagData:
return ("Data");
case SymTagAnnotation:
return ("Annotation");
case SymTagLabel:
return ("Label");
case SymTagPublicSymbol:
return ("PublicSymbol");
case SymTagUDT:
return ("UDT");
case SymTagEnum:
return ("Enum");
case SymTagFunctionType:
return ("FunctionType");
case SymTagPointerType:
return ("PointerType");
case SymTagArrayType:
return ("ArrayType");
case SymTagBaseType:
return ("BaseType");
case SymTagTypedef:
return ("Typedef");
case SymTagBaseClass:
return ("BaseClass");
case SymTagFriend:
return ("Friend");
case SymTagFunctionArgType:
return ("FunctionArgType");
case SymTagFuncDebugStart:
return ("FuncDebugStart");
case SymTagFuncDebugEnd:
return ("FuncDebugEnd");
case SymTagUsingNamespace:
return ("UsingNamespace");
case SymTagVTableShape:
return ("VTableShape");
case SymTagVTable:
return ("VTable");
case SymTagCustom:
return ("Custom");
case SymTagThunk:
return ("Thunk");
case SymTagCustomType:
return ("CustomType");
case SymTagManagedType:
return ("ManagedType");
case SymTagDimension:
return ("Dimension");
default:
return ("Unknown");
}
return ("");
}
/**
* @brief Convert a DLL to a Microsoft Symbol path
*
* @param LocalFilePath
* @param ResultPath
* @param ResultPathSize the size of the result path buffer
*
* @return BOOLEAN
*/
BOOLEAN
SymConvertFileToPdbPath(const char * LocalFilePath, char * ResultPath, SIZE_T ResultPathSize)
{
std::vector<BYTE> FileBytes;
if (LocalFilePath == NULL && ResultPath == NULL)
{
return FALSE;
}
SymReadFileBytes(LocalFilePath, FileBytes);
return SymFormatPdbIdentityFromPeImageOrFallback(FileBytes.empty() ? NULL : FileBytes.data(),
FileBytes.size(),
ResultPath,
ResultPathSize,
NULL,
0,
NULL,
0,
SymSrvGetFileIndexInfoFallback,
(PVOID)LocalFilePath);
}
/**
* @brief Convert redirection of 32-bit compatibility path
*
* @param LocalFilePath
* @param Wow64ConvertedPath the converted path for Wow64 compatibility
*
* @return VOID
*/
VOID
SymConvertWow64CompatibilityPaths(const char * LocalFilePath, std::string & Wow64ConvertedPath)
{
std::string FilePath(LocalFilePath);
// Convert the path to lowercase
std::transform(FilePath.begin(), FilePath.end(), FilePath.begin(), ::tolower);
// Replace "\windows\system32" with "\windows\syswow64"
SIZE_T Pos = FilePath.find(":\\windows\\system32");
if (Pos != std::string::npos)
{
FilePath.replace(Pos, 18, ":\\windows\\syswow64");
}
// Replace "\program files" with "\program files (x86)"
Pos = FilePath.find(":\\program files");
if (Pos != std::string::npos)
{
FilePath.replace(Pos, 15, ":\\program files (x86)");
}
//
// Copy path to destination
//
Wow64ConvertedPath = FilePath;
}
/**
* @brief Convert a DLL to a Microsoft Symbol details
* like pdb file path and GUID
*
* @param LocalFilePath
* @param PdbFilePath
* @param GuidAndAgeDetails
* @param Is32BitModule
*
* @return BOOLEAN
*/
BOOLEAN
SymConvertFileToPdbFileAndGuidAndAgeDetails(const char * LocalFilePath, char * PdbFilePath, char * GuidAndAgeDetails, BOOLEAN Is32BitModule)
{
std::string Wow64ConvertedPath;
std::vector<BYTE> FileBytes;
const char * ActualLocalFilePath = NULL;
if (Is32BitModule)
{
SymConvertWow64CompatibilityPaths(LocalFilePath, Wow64ConvertedPath);
ActualLocalFilePath = Wow64ConvertedPath.c_str();
// ShowMessages("local file path: %s | final file path: %s\n", LocalFilePath, ActualLocalFilePath);
}
else
{
ActualLocalFilePath = LocalFilePath;
}
// ShowMessages("the final (actual) address is: %s\n", ActualLocalFilePath);
SymReadFileBytes(ActualLocalFilePath, FileBytes);
return SymFormatPdbIdentityFromPeImageOrFallback(FileBytes.empty() ? NULL : FileBytes.data(),
FileBytes.size(),
NULL,
0,
PdbFilePath,
MAX_PATH,
GuidAndAgeDetails,
MAXIMUM_GUID_AND_AGE_SIZE,
SymSrvGetFileIndexInfoFallback,
(PVOID)ActualLocalFilePath);
}
BOOLEAN
SymConvertLoadedModuleToPdbFileAndGuidAndAgeDetails(const BYTE * LoadedImageBytes,
SIZE_T LoadedImageSize,
const char * LocalFilePath,
char * PdbFilePath,
char * GuidAndAgeDetails,
BOOLEAN Is32BitModule)
{
std::string Wow64ConvertedPath;
const char * ActualLocalFilePath = NULL;
if (Is32BitModule)
{
SymConvertWow64CompatibilityPaths(LocalFilePath, Wow64ConvertedPath);
ActualLocalFilePath = Wow64ConvertedPath.c_str();
// ShowMessages("local file path: %s | final file path: %s\n", LocalFilePath, ActualLocalFilePath);
}
else
{
ActualLocalFilePath = LocalFilePath;
}
// ShowMessages("the final (actual) address is: %s\n", ActualLocalFilePath);
return SymFormatPdbIdentityFromLoadedPeImageOrFallback(LoadedImageBytes,
LoadedImageSize,
NULL,
0,
PdbFilePath,
MAX_PATH,
GuidAndAgeDetails,
MAXIMUM_GUID_AND_AGE_SIZE,
SymSrvGetFileIndexInfoFallback,
(PVOID)ActualLocalFilePath);
}
/**
* @brief check if the pdb files of loaded symbols are available or not
*
* @param BufferToStoreDetails Pointer to a buffer to store the symbols details
* this buffer will be allocated by this function and needs to be freed by caller
* @param StoredLength The length that stored on the BufferToStoreDetails
* @param DownloadIfAvailable Download the file if its available online
* @param SymbolPath The path of symbols
* @param IsSilentLoad
*
* @return BOOLEAN
*/
BOOLEAN
SymbolInitLoad(PVOID BufferToStoreDetails,
UINT32 StoredLength,
BOOLEAN DownloadIfAvailable,
const char * SymbolPath,
BOOLEAN IsSilentLoad)
{
string Tmp, SymDir, CustomModuleNameStr;
const char * CustomModuleName = NULL;
string SymPath(SymbolPath);
PMODULE_SYMBOL_DETAIL BufferToStoreDetailsConverted = (PMODULE_SYMBOL_DETAIL)BufferToStoreDetails;
vector<string> SplitedSymPath = Split(SymPath, '*');
if (SplitedSymPath.size() < 2)
return FALSE;
if (SplitedSymPath[1].find(":\\") == string::npos)
return FALSE;
Tmp = SymDir = SplitedSymPath[1];
//
// Split each module and details
//
for (SIZE_T i = 0; i < StoredLength / sizeof(MODULE_SYMBOL_DETAIL); i++)
{
//
// Check for abort
//
if (g_AbortLoadingExecution)
{
g_AbortLoadingExecution = FALSE;
return FALSE;
}
//
// Check if symbol pdb detail is available in the module
//
if (!BufferToStoreDetailsConverted[i].IsSymbolDetailsFound)
{
//
// Ignore the module
//
continue;
}
//
// Check if it's a local path (a path) or a microsoft symbol
//
if (BufferToStoreDetailsConverted[i].IsLocalSymbolPath)
{
//
// If this is a local driver, then load the pdb
//
if (IsFileExists(BufferToStoreDetailsConverted[i].ModuleSymbolPath))
{
BufferToStoreDetailsConverted[i].IsSymbolPDBAvaliable = TRUE;
//
// Load symbol locally
//
if (!IsSilentLoad)
{
ShowMessages("loading symbol '%s'...", Tmp.c_str());
}
//
// Check if we need an alternative module name (in 32-bit modules)
//
CustomModuleName = NULL;
// ShowMessages("name: %s , is 32-bit? %s\n", BufferToStoreDetailsConverted[i].FilePath, BufferToStoreDetailsConverted[i].Is32Bit ? "true" : "false");
//
// Check for alternative module names
//
if (BufferToStoreDetailsConverted[i].Is32Bit &&
SymCheckAndRemoveWow64Prefix(BufferToStoreDetailsConverted[i].FilePath,
BufferToStoreDetailsConverted[i].ModuleSymbolPath,
CustomModuleNameStr))
{
//
// The name of the module contains a prefix which should be removed
//
CustomModuleName = CustomModuleNameStr.c_str();
}
else if (!BufferToStoreDetailsConverted[i].Is32Bit &&
SymCheckNtoskrnlPrefix(BufferToStoreDetailsConverted[i].ModuleSymbolPath, CustomModuleNameStr))
{
//
// This is an nt module
//
CustomModuleName = CustomModuleNameStr.c_str();
}
if (SymLoadFileSymbol(BufferToStoreDetailsConverted[i].BaseAddress,
BufferToStoreDetailsConverted[i].ModuleSymbolPath,
CustomModuleName) == 0)
{
if (!IsSilentLoad)
{
ShowMessages("\tloaded\n");
}
}
else
{
if (!IsSilentLoad)
{
ShowMessages("\tnot loaded (already loaded?)\n");
}
}
}
}
else
{
//
// It might be a Windows symbol
//
Tmp = SymDir +
"\\" +
BufferToStoreDetailsConverted[i].ModuleSymbolPath +
"\\" +
BufferToStoreDetailsConverted[i].ModuleSymbolGuidAndAge +
"\\" +
BufferToStoreDetailsConverted[i].ModuleSymbolPath;
//
// Download the symbols file if not available
//
if (DownloadIfAvailable && IsFileExists(Tmp) == FALSE)
{
//
// Download the symbol
//
SymbolPdbDownload(BufferToStoreDetailsConverted[i].ModuleSymbolPath,
BufferToStoreDetailsConverted[i].ModuleSymbolGuidAndAge,
SymPath,
IsSilentLoad);
}
//
// Check again to see if the symbol already download or not
//
if (IsFileExists(Tmp))
{
BufferToStoreDetailsConverted[i].IsSymbolPDBAvaliable = TRUE;
if (!IsSilentLoad)
{
ShowMessages("loading symbol '%s'...", Tmp.c_str());
}
//
// Check if we need an alternative module name (in 32-bit modules)
//
CustomModuleName = NULL;
// ShowMessages("name: %s , is 32-bit? %s\n", BufferToStoreDetailsConverted[i].FilePath, BufferToStoreDetailsConverted[i].Is32Bit ? "true" : "false");
//
// Check for alternative module names
//
if (BufferToStoreDetailsConverted[i].Is32Bit &&
SymCheckAndRemoveWow64Prefix(BufferToStoreDetailsConverted[i].FilePath,
Tmp.c_str(),
CustomModuleNameStr))
{
//
// The name of the module contains a prefix which should be removed
//
CustomModuleName = CustomModuleNameStr.c_str();
}
else if (!BufferToStoreDetailsConverted[i].Is32Bit &&
SymCheckNtoskrnlPrefix(Tmp.c_str(), CustomModuleNameStr))
{
//
// This is an nt module
//
CustomModuleName = CustomModuleNameStr.c_str();
}
if (SymLoadFileSymbol(BufferToStoreDetailsConverted[i].BaseAddress, Tmp.c_str(), CustomModuleName) == 0)
{
if (!IsSilentLoad)
{
ShowMessages("\tloaded\n");
}
}
else
{
if (!IsSilentLoad)
{
ShowMessages("\tnot loaded (already loaded?)\n");
}
}
}
}
}
return TRUE;
}
/**
* @brief download pdb file
*
* @param SymName the name of the symbol (pdb file name)
* @param GUID the GUID and age string identifying the symbol version
* @param SymPath the symbol search path
* @param IsSilentLoad download without any message
*
* @return BOOLEAN
*/
BOOLEAN
SymbolPdbDownload(std::string SymName, const std::string & GUID, const std::string & SymPath, BOOLEAN IsSilentLoad)
{
vector<string> SplitedSymPath = Split(SymPath, '*');
if (SplitedSymPath.size() < 2)
return FALSE;
if (SplitedSymPath[1].find(":\\") == string::npos)
return FALSE;
if (SplitedSymPath[2].find("http:") == string::npos && SplitedSymPath[2].find("https:") == string::npos)
return FALSE;
string SymDir = SplitedSymPath[1];
string SymDownloadServer = SplitedSymPath[2];
string DownloadURL = SymDownloadServer + "/" + SymName + "/" + GUID + "/" + SymName;
string SymFullDir = SymDir + "\\" + SymName + "\\" + GUID + "\\";
if (!CreateDirectoryRecursive(SymFullDir))
{
if (!IsSilentLoad)
{
ShowMessages("err, unable to create sympath directory '%s'\n", SymFullDir.c_str());
}
return FALSE;
}
if (!IsSilentLoad)
{
ShowMessages("downloading symbol '%s'...", SymName.c_str());
}
HRESULT Result = URLDownloadToFileA(NULL, DownloadURL.c_str(), (SymFullDir + "\\" + SymName).c_str(), 0, NULL);
if (Result == S_OK)
{
if (!IsSilentLoad)
{
ShowMessages("\tdownloaded\n");
}
return TRUE;
}
else
{
if (!IsSilentLoad)
{
ShowMessages("\tcould not be downloaded (%x) \n", Result);
}
}
return FALSE;
}
/**
* @brief In the case of pressing CTRL+C, it sets a flag
* to abort the execution of the 'reload'ing and the 'download'ing
*
* @return VOID
*/
VOID
SymbolAbortLoading()
{
if (!g_AbortLoadingExecution)
{
g_AbortLoadingExecution = TRUE;
ShowMessages("\naborting, please wait...\n");
}
}
/**
* @brief Perform task for showing structures and data
* @details used by dt command
*
* @param TypeName
* @param Address
* @param IsStruct
* @param BufferAddress
* @param AdditionalParameters
*
* @return BOOLEAN
*/
BOOLEAN
SymShowDataBasedOnSymbolTypes(const char * TypeName,
UINT64 Address,
BOOLEAN IsStruct,
PVOID BufferAddress,
const char * AdditionalParameters)
{
vector<string> SplitedSymPath;
char ** ArgvArray = NULL;
PSYMBOL_LOADED_MODULE_DETAILS SymbolInfo = NULL;
UINT32 SizeOfArgv = 0;
UINT32 TypeNameIndex = 0;
//
// Find the symbol info (to get the PDB address)
//
SymbolInfo = SymGetModuleBaseFromSearchMask(TypeName, FALSE);
if (!SymbolInfo)
{
//
// Symbol not found
//
ShowMessages("err, couldn't resolve error at '%s'\n", TypeName);
return FALSE;
}
//
// Convert char* to string
//
std::string AdditionalParametersString(AdditionalParameters);
//
// Split the arguments by space
//
SplitPathAndArgs(SplitedSymPath, AdditionalParametersString);
//
// Allocate buffer to convert it to the char*
// + 3 is because of
// 1. file name
// 2. type (structure) name
// 3. PDB file location
//
SizeOfArgv = (UINT32)SplitedSymPath.size() + 3;
ArgvArray = (char **)malloc(SizeOfArgv * sizeof(char *));
if (ArgvArray == NULL)
{
return FALSE;
}
RtlZeroMemory(ArgvArray, SizeOfArgv * sizeof(char *));
//
// First argument is the file name, we let it blank
//
ArgvArray[0] = (char *)NULL;
//
// Remove the module name (if any)
//
while (TypeName[TypeNameIndex] != NULL)
{
if (TypeName[TypeNameIndex] == '!')
{
TypeName = &TypeName[++TypeNameIndex];
break;
}
TypeNameIndex++;
}
//
// Second argument is the type (structure) name
//
ArgvArray[1] = (char *)TypeName;
//
// Third argument is the PDB file location
//
ArgvArray[2] = SymbolInfo->PdbFilePath;
//
// Fill the parameter with char array
//
for (SIZE_T i = 3; i < SizeOfArgv; i++)
{
ArgvArray[i] = (char *)SplitedSymPath.at(i - 3).c_str();
}
//
// Call the pdbex wrapper
//
if (IsStruct)
{
pdbex_export(SizeOfArgv, ArgvArray, true, BufferAddress);
}
else
{
pdbex_export(SizeOfArgv, ArgvArray, false, BufferAddress);
}
//
// Free the buffer allocated for argv
//
free(ArgvArray);
return TRUE;
}