mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-09 17:19:26 +00:00
1671 lines
40 KiB
C++
1671 lines
40 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 "..\symbol-parser\pch.h"
|
|
|
|
//
|
|
// Global Variables
|
|
//
|
|
std::vector<PSYMBOL_LOADED_MODULE_DETAILS> g_LoadedModules;
|
|
BOOLEAN g_IsLoadedModulesInitialized = FALSE;
|
|
BOOLEAN g_AbortLoadingExecution = FALSE;
|
|
CHAR * g_CurrentModuleName = NULL;
|
|
CHAR g_NtModuleName[_MAX_FNAME] = {0};
|
|
Callback g_MessageHandler = NULL;
|
|
SymbolMapCallback g_SymbolMapForDisassembler = NULL;
|
|
|
|
/**
|
|
* @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 = (Callback)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
|
|
//
|
|
g_MessageHandler(TempMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Interpret and find module base, based on module name
|
|
* @param SearchMask
|
|
*
|
|
* @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 = NULL;
|
|
|
|
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++;
|
|
}
|
|
|
|
if (strcmp(ModuleName, "ntkrnlmp") == 0 || strcmp(ModuleName, "ntoskrnl") == 0 ||
|
|
strcmp(ModuleName, "ntkrpamp") == 0 || strcmp(ModuleName, "ntkrnlpa") == 0)
|
|
{
|
|
//
|
|
// It's "nt"
|
|
//
|
|
RtlZeroMemory(ModuleName, _MAX_FNAME);
|
|
|
|
//
|
|
// Move nt as the name
|
|
//
|
|
ModuleName[0] = 'n';
|
|
ModuleName[1] = 't';
|
|
}
|
|
}
|
|
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 of the "X" command *************
|
|
//
|
|
for (auto item : g_LoadedModules)
|
|
{
|
|
if (strcmp((const char *)item->ModuleName, ModuleName) == 0)
|
|
{
|
|
if (SetModuleNameGlobally)
|
|
{
|
|
g_CurrentModuleName = (char *)item->ModuleName;
|
|
}
|
|
|
|
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(DWORD64 Base, WCHAR * TypeName, WCHAR * FieldName, DWORD32 * 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_t 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_t[]>(
|
|
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
|
|
//
|
|
ULONG64 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 load symbol based on a file name and GUID
|
|
*
|
|
* @param BaseAddress
|
|
* @param FileName
|
|
* @param Guid
|
|
*
|
|
* @return UINT32
|
|
*/
|
|
UINT32
|
|
SymLoadFileSymbol(UINT64 BaseAddress, const char * PdbFileName)
|
|
{
|
|
BOOL Ret = FALSE;
|
|
DWORD Options = 0;
|
|
DWORD FileSize = 0;
|
|
int Index = 0;
|
|
char Ch = NULL;
|
|
char ModuleName[_MAX_FNAME] = {0};
|
|
char AlternateModuleName[_MAX_FNAME] = {0};
|
|
PSYMBOL_LOADED_MODULE_DETAILS ModuleDetails = NULL;
|
|
|
|
pdbex_main_impl_export(0, NULL);
|
|
|
|
//
|
|
// 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;
|
|
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 -1;
|
|
}
|
|
|
|
//
|
|
// 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 extension 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++;
|
|
}
|
|
|
|
//
|
|
// 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(ModuleName, ("ntkrnlmp")) == 0 || strcmp(ModuleName, ("ntoskrnl")) == 0 ||
|
|
strcmp(ModuleName, ("ntkrpamp")) == 0 || strcmp(ModuleName, ("ntkrnlpa")) == 0)
|
|
{
|
|
//
|
|
// It's "nt"
|
|
//
|
|
RtlZeroMemory(ModuleName, _MAX_FNAME);
|
|
|
|
//
|
|
// Move nt as the name
|
|
//
|
|
ModuleName[0] = 'n';
|
|
ModuleName[1] = 't';
|
|
|
|
//
|
|
// Describe it as main nt module
|
|
//
|
|
RtlZeroMemory(g_NtModuleName, _MAX_FNAME);
|
|
strcpy(g_NtModuleName, AlternateModuleName);
|
|
}
|
|
|
|
//
|
|
// 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 it
|
|
//
|
|
g_LoadedModules.push_back(ModuleDetails);
|
|
|
|
if (!g_IsLoadedModulesInitialized)
|
|
{
|
|
//
|
|
// Indicate that at least one module is loaded
|
|
//
|
|
g_IsLoadedModulesInitialized = TRUE;
|
|
}
|
|
|
|
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)
|
|
{
|
|
//
|
|
// 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;
|
|
|
|
for (auto item : g_LoadedModules)
|
|
{
|
|
//
|
|
// Unload symbols for the module
|
|
//
|
|
Ret = SymUnloadModule64(GetCurrentProcess(), item->ModuleBase);
|
|
|
|
if (!Ret)
|
|
{
|
|
ShowMessages("err, unload symbol failed (%x)\n",
|
|
GetLastError());
|
|
}
|
|
|
|
free(item);
|
|
}
|
|
|
|
//
|
|
// Clear the list
|
|
//
|
|
g_LoadedModules.clear();
|
|
|
|
//
|
|
// Uninitialize DbgHelp
|
|
//
|
|
Ret = SymCleanup(GetCurrentProcess());
|
|
|
|
if (!Ret)
|
|
{
|
|
ShowMessages("err, symbol cleanup failed (%x)\n", GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Convert function name to address
|
|
*
|
|
* @param FunctionName
|
|
* @param WasFound
|
|
*
|
|
* @return UINT64
|
|
*/
|
|
UINT64
|
|
SymConvertNameToAddress(const char * FunctionOrVariableName, PBOOLEAN WasFound)
|
|
{
|
|
BOOLEAN Found = FALSE;
|
|
UINT64 Address = NULL;
|
|
ULONG64 Buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
|
|
PSYMBOL_INFO Symbol = (PSYMBOL_INFO)Buffer;
|
|
|
|
//
|
|
// Not found by default
|
|
//
|
|
*WasFound = FALSE;
|
|
|
|
//
|
|
// Retrieve the address from name
|
|
//
|
|
Symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
Symbol->MaxNameLen = MAX_SYM_NAME;
|
|
|
|
//
|
|
// Check if it starts with 'nt!' and if starts then
|
|
// we'll remove it, because 'nt!' is not a real module
|
|
// name
|
|
//
|
|
if (strlen(FunctionOrVariableName) >= 4 &&
|
|
tolower(FunctionOrVariableName[0]) == 'n' &&
|
|
tolower(FunctionOrVariableName[1]) == 't' &&
|
|
tolower(FunctionOrVariableName[2]) == '!')
|
|
{
|
|
//
|
|
// No need to use nt!
|
|
//
|
|
memmove((char *)FunctionOrVariableName, FunctionOrVariableName + 3, strlen(FunctionOrVariableName));
|
|
}
|
|
|
|
if (SymFromName(GetCurrentProcess(), FunctionOrVariableName, 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, DWORD32 * FieldOffset)
|
|
{
|
|
BOOL Ret = FALSE;
|
|
DWORD64 ModuleBase = NULL;
|
|
UINT32 Index = 0;
|
|
|
|
//
|
|
// Find module base
|
|
//
|
|
ModuleBase = SymGetModuleBaseFromSearchMask(TypeName, TRUE)->ModuleBase;
|
|
|
|
//
|
|
// Find the module name
|
|
//
|
|
if (ModuleBase == 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 = new 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 = new wchar_t[FieldNameSize];
|
|
mbstowcs(FieldNameW, FieldName, FieldNameSize);
|
|
|
|
return SymGetFieldOffsetFromModule(ModuleBase, TypeNameW, FieldNameW, FieldOffset);
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the offset from the symbol
|
|
*
|
|
* @param SearchMask
|
|
*
|
|
* @return UINT32
|
|
*/
|
|
UINT32
|
|
SymSearchSymbolForMask(const char * SearchMask)
|
|
{
|
|
BOOL Ret = FALSE;
|
|
DWORD64 ModuleBase = NULL;
|
|
|
|
//
|
|
// Find module base
|
|
//
|
|
ModuleBase = SymGetModuleBaseFromSearchMask(SearchMask, TRUE)->ModuleBase;
|
|
|
|
//
|
|
// Find the module name
|
|
//
|
|
if (ModuleBase == NULL)
|
|
{
|
|
//
|
|
// Module not found or there was an error
|
|
//
|
|
return -1;
|
|
}
|
|
|
|
Ret = SymEnumSymbols(
|
|
GetCurrentProcess(), // Process handle of the current process
|
|
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(DWORD64 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
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
SymConvertFileToPdbPath(const char * LocalFilePath, char * ResultPath)
|
|
{
|
|
SYMSRV_INDEX_INFO SymInfo = {0};
|
|
const char * FormatStr =
|
|
"%s/%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x%x/%s";
|
|
SymInfo.sizeofstruct = sizeof(SYMSRV_INDEX_INFO);
|
|
|
|
BOOL Ret = SymSrvGetFileIndexInfo(LocalFilePath, &SymInfo, 0);
|
|
|
|
if (Ret)
|
|
{
|
|
wsprintfA(ResultPath,
|
|
FormatStr,
|
|
SymInfo.pdbfile,
|
|
SymInfo.guid.Data1,
|
|
SymInfo.guid.Data2,
|
|
SymInfo.guid.Data3,
|
|
SymInfo.guid.Data4[0],
|
|
SymInfo.guid.Data4[1],
|
|
SymInfo.guid.Data4[2],
|
|
SymInfo.guid.Data4[3],
|
|
SymInfo.guid.Data4[4],
|
|
SymInfo.guid.Data4[5],
|
|
SymInfo.guid.Data4[6],
|
|
SymInfo.guid.Data4[7],
|
|
SymInfo.age,
|
|
SymInfo.pdbfile);
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// ShowMessages("err, unable to get symbol information for %s (%x)\n", LocalFilePath, GetLastError());
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// By default, return false
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief Convert a DLL to a Microsoft Symbol details
|
|
* like pdb file path and GUID
|
|
*
|
|
* @param LocalFilePath
|
|
* @param PdbFilePath
|
|
* @param GuidAndAgeDetails
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
SymConvertFileToPdbFileAndGuidAndAgeDetails(const char * LocalFilePath, char * PdbFilePath, char * GuidAndAgeDetails)
|
|
{
|
|
SYMSRV_INDEX_INFO SymInfo = {0};
|
|
const char * FormatStrPdbFilePath = "%s";
|
|
const char * FormatStrPdbFileGuidAndAgeDetails =
|
|
"%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x%x";
|
|
SymInfo.sizeofstruct = sizeof(SYMSRV_INDEX_INFO);
|
|
|
|
BOOL Ret = SymSrvGetFileIndexInfo(LocalFilePath, &SymInfo, 0);
|
|
|
|
if (Ret)
|
|
{
|
|
wsprintfA(PdbFilePath, FormatStrPdbFilePath, SymInfo.pdbfile);
|
|
|
|
wsprintfA(GuidAndAgeDetails,
|
|
FormatStrPdbFileGuidAndAgeDetails,
|
|
SymInfo.guid.Data1,
|
|
SymInfo.guid.Data2,
|
|
SymInfo.guid.Data3,
|
|
SymInfo.guid.Data4[0],
|
|
SymInfo.guid.Data4[1],
|
|
SymInfo.guid.Data4[2],
|
|
SymInfo.guid.Data4[3],
|
|
SymInfo.guid.Data4[4],
|
|
SymInfo.guid.Data4[5],
|
|
SymInfo.guid.Data4[6],
|
|
SymInfo.guid.Data4[7],
|
|
SymInfo.age);
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// ShowMessages("err, unable to get symbol information for %s (%x)\n", LocalFilePath, GetLastError());
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// By default, return false
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* @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;
|
|
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());
|
|
}
|
|
|
|
if (SymLoadFileSymbol(BufferToStoreDetailsConverted[i].BaseAddress,
|
|
BufferToStoreDetailsConverted[i].ModuleSymbolPath) == 0)
|
|
{
|
|
if (!IsSilentLoad)
|
|
{
|
|
ShowMessages("\tloaded\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!IsSilentLoad)
|
|
{
|
|
ShowMessages("\tcould not be loaded\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// It might be a Windows symbol
|
|
//
|
|
Tmp = SymDir +
|
|
"\\" +
|
|
BufferToStoreDetailsConverted[i].ModuleSymbolPath +
|
|
"\\" +
|
|
BufferToStoreDetailsConverted[i].ModuleSymbolGuidAndAge +
|
|
"\\" +
|
|
BufferToStoreDetailsConverted[i].ModuleSymbolPath;
|
|
|
|
//
|
|
// Check if the symbol already download or not
|
|
//
|
|
if (IsFileExists(Tmp))
|
|
{
|
|
BufferToStoreDetailsConverted[i].IsSymbolPDBAvaliable = TRUE;
|
|
|
|
if (!IsSilentLoad)
|
|
{
|
|
ShowMessages("loading symbol '%s'...", Tmp.c_str());
|
|
}
|
|
|
|
if (SymLoadFileSymbol(BufferToStoreDetailsConverted[i].BaseAddress, Tmp.c_str()) == 0)
|
|
{
|
|
if (!IsSilentLoad)
|
|
{
|
|
ShowMessages("\tloaded\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!IsSilentLoad)
|
|
{
|
|
ShowMessages("\tcould not be loaded\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (DownloadIfAvailable)
|
|
{
|
|
//
|
|
// Download the symbol
|
|
//
|
|
SymbolPDBDownload(BufferToStoreDetailsConverted[i].ModuleSymbolPath,
|
|
BufferToStoreDetailsConverted[i].ModuleSymbolGuidAndAge,
|
|
SymPath,
|
|
IsSilentLoad);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief download pdb file
|
|
*
|
|
* @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 SymPath The path of symbols
|
|
* @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 'reload'ing and 'download'ing
|
|
*
|
|
* return VOID
|
|
*/
|
|
VOID
|
|
SymbolAbortLoading()
|
|
{
|
|
if (!g_AbortLoadingExecution)
|
|
{
|
|
g_AbortLoadingExecution = TRUE;
|
|
ShowMessages("\naborting, please wait...\n");
|
|
}
|
|
}
|