1
0
Fork 0
x64dbg/x64_dbg_dbg/symbolinfo.cpp

304 lines
9.1 KiB
C++

/**
@file symbolinfo.cpp
@brief Implements the symbolinfo class.
*/
#include "symbolinfo.h"
#include "debugger.h"
#include "console.h"
#include "module.h"
#include "label.h"
struct SYMBOLCBDATA
{
CBSYMBOLENUM cbSymbolEnum;
void* user;
};
static BOOL CALLBACK EnumSymbols(PSYMBOL_INFO SymInfo, ULONG SymbolSize, PVOID UserContext)
{
SYMBOLINFO curSymbol;
memset(&curSymbol, 0, sizeof(SYMBOLINFO));
curSymbol.addr = (duint)SymInfo->Address;
curSymbol.decoratedSymbol = (char*)BridgeAlloc(strlen(SymInfo->Name) + 1);
curSymbol.undecoratedSymbol = (char*)BridgeAlloc(MAX_SYM_NAME);
strcpy_s(curSymbol.decoratedSymbol, strlen(SymInfo->Name) + 1, SymInfo->Name);
// Skip bad ordinals
if(strstr(SymInfo->Name, "Ordinal"))
{
// Does the symbol point to the module base?
if(SymInfo->Address == SymInfo->ModBase)
return TRUE;
}
// Convert a mangled/decorated C++ name to a readable format
if(!SafeUnDecorateSymbolName(SymInfo->Name, curSymbol.undecoratedSymbol, MAX_SYM_NAME, UNDNAME_COMPLETE))
{
BridgeFree(curSymbol.undecoratedSymbol);
curSymbol.undecoratedSymbol = nullptr;
}
else if(!strcmp(curSymbol.decoratedSymbol, curSymbol.undecoratedSymbol))
{
BridgeFree(curSymbol.undecoratedSymbol);
curSymbol.undecoratedSymbol = nullptr;
}
SYMBOLCBDATA* cbData = (SYMBOLCBDATA*)UserContext;
cbData->cbSymbolEnum(&curSymbol, cbData->user);
return TRUE;
}
void SymEnum(uint Base, CBSYMBOLENUM EnumCallback, void* UserData)
{
SYMBOLCBDATA symbolCbData;
symbolCbData.cbSymbolEnum = EnumCallback;
symbolCbData.user = UserData;
// Enumerate every single symbol for the module in 'base'
if(!SafeSymEnumSymbols(fdProcessInfo->hProcess, Base, "*", EnumSymbols, &symbolCbData))
dputs("SymEnumSymbols failed!");
}
bool SymGetModuleList(std::vector<SYMBOLMODULEINFO>* List)
{
//
// Inline lambda enum
//
auto EnumModules = [](LPCTSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) -> BOOL
{
SYMBOLMODULEINFO curModule;
curModule.base = (duint)BaseOfDll;
// Terminate module name if one isn't found
if(!ModNameFromAddr(curModule.base, curModule.name, true))
curModule.name[0] = '\0';
((std::vector<SYMBOLMODULEINFO>*)UserContext)->push_back(curModule);
return TRUE;
};
// Execute the symbol enumerator (Force cast to STDCALL)
if(!SafeSymEnumerateModules64(fdProcessInfo->hProcess, EnumModules, List))
{
dputs("SymEnumerateModules64 failed!");
return false;
}
return true;
}
void SymUpdateModuleList()
{
// Build the vector of modules
std::vector<SYMBOLMODULEINFO> modList;
if(!SymGetModuleList(&modList))
{
GuiSymbolUpdateModuleList(0, nullptr);
return;
}
// Create a new array to be sent to the GUI thread
size_t moduleCount = modList.size();
SYMBOLMODULEINFO* data = (SYMBOLMODULEINFO*)BridgeAlloc(moduleCount * sizeof(SYMBOLMODULEINFO));
// Direct copy from std::vector data
memcpy(data, modList.data(), moduleCount * sizeof(SYMBOLMODULEINFO));
// Send the module data to the GUI for updating
GuiSymbolUpdateModuleList((int)moduleCount, data);
}
void SymDownloadAllSymbols(const char* SymbolStore)
{
// Default to Microsoft's symbol server
if(!SymbolStore)
SymbolStore = "http://msdl.microsoft.com/download/symbols";
// Build the vector of modules
std::vector<SYMBOLMODULEINFO> modList;
if(!SymGetModuleList(&modList))
return;
// Skip loading if there aren't any found modules
if(modList.size() <= 0)
return;
// Backup the current symbol search path
wchar_t oldSearchPath[MAX_PATH];
if(!SafeSymGetSearchPathW(fdProcessInfo->hProcess, oldSearchPath, MAX_PATH))
{
dputs("SymGetSearchPathW failed!");
return;
}
// Use the custom server path and directory
char customSearchPath[MAX_PATH * 2];
sprintf_s(customSearchPath, "SRV*%s*%s", szSymbolCachePath, SymbolStore);
if(!SafeSymSetSearchPathW(fdProcessInfo->hProcess, StringUtils::Utf8ToUtf16(customSearchPath).c_str()))
{
dputs("SymSetSearchPathW (1) failed!");
return;
}
// Reload
for(auto & module : modList)
{
dprintf("Downloading symbols for %s...\n", module.name);
wchar_t modulePath[MAX_PATH];
if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)module.base, modulePath, MAX_PATH))
{
dprintf("GetModuleFileNameExW(" fhex ") failed!\n", module.base);
continue;
}
if(!SafeSymUnloadModule64(fdProcessInfo->hProcess, (DWORD64)module.base))
{
dprintf("SymUnloadModule64(" fhex ") failed!\n", module.base);
continue;
}
if(!SafeSymLoadModuleEx(fdProcessInfo->hProcess, 0, StringUtils::Utf16ToUtf8(modulePath).c_str(), 0, (DWORD64)module.base, 0, 0, 0))
{
dprintf("SymLoadModuleEx(" fhex ") failed!\n", module.base);
continue;
}
}
// Restore the old search path
if(!SafeSymSetSearchPathW(fdProcessInfo->hProcess, oldSearchPath))
dputs("SymSetSearchPathW (2) failed!");
}
bool SymAddrFromName(const char* Name, uint* Address)
{
if(!Name || Name[0] == '\0')
return false;
if(!Address)
return false;
// Skip 'OrdinalXXX'
if(!_strnicmp(Name, "Ordinal", 7))
return false;
// According to MSDN:
// Note that the total size of the data is the SizeOfStruct + (MaxNameLen - 1) * sizeof(TCHAR)
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(char)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)&buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_LABEL_SIZE;
if(!SafeSymFromName(fdProcessInfo->hProcess, Name, symbol))
return false;
*Address = (uint)symbol->Address;
return true;
}
const char* SymGetSymbolicName(uint Address)
{
//
// This resolves an address to a module and symbol:
// [modname.]symbolname
//
char label[MAX_SYM_NAME];
// User labels have priority, but if one wasn't found,
// default to a symbol lookup
if(!LabelGet(Address, label))
{
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(char)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_LABEL_SIZE;
// Perform a symbol lookup
DWORD64 displacement = 0;
if(!SafeSymFromAddr(fdProcessInfo->hProcess, (DWORD64)Address, &displacement, symbol))
return nullptr;
// If the symbol wasn't at offset 0 (start from the beginning) ignore it
if(displacement != 0)
return nullptr;
// Terminate the string for sanity
symbol->Name[symbol->MaxNameLen - 1] = '\0';
if(!bUndecorateSymbolNames || !SafeUnDecorateSymbolName(symbol->Name, label, MAX_SYM_NAME, UNDNAME_COMPLETE))
strcpy_s(label, symbol->Name);
}
// TODO: FIXME: STATIC VARIABLE
static char symbolicname[MAX_MODULE_SIZE + MAX_SYM_NAME];
char modname[MAX_MODULE_SIZE];
if(ModNameFromAddr(Address, modname, false))
sprintf_s(symbolicname, "%s.%s", modname, label);
else
sprintf_s(symbolicname, "<%s>", label);
return symbolicname;
}
bool SymGetSourceLine(uint Cip, char* FileName, int* Line)
{
IMAGEHLP_LINEW64 lineInfo;
memset(&lineInfo, 0, sizeof(IMAGEHLP_LINE64));
lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
// Perform a symbol lookup from a specific address
DWORD displacement;
if(!SymGetLineFromAddrW64(fdProcessInfo->hProcess, Cip, &displacement, &lineInfo))
return false;
String NewFile = StringUtils::Utf16ToUtf8(lineInfo.FileName);
// Copy line number if requested
if(Line)
*Line = lineInfo.LineNumber;
// Copy file name if requested
if(FileName)
{
// Check if it was a full path
if(NewFile[1] == ':' && NewFile[2] == '\\')
{
// Success: no more parsing
strcpy_s(FileName, MAX_STRING_SIZE, NewFile.c_str());
return true;
}
// Construct full path from pdb path
IMAGEHLP_MODULE64 modInfo;
memset(&modInfo, 0, sizeof(IMAGEHLP_MODULE64));
modInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
if(!SafeSymGetModuleInfo64(fdProcessInfo->hProcess, Cip, &modInfo))
return false;
// Strip the name, leaving only the file directory
char* pdbFileName = strrchr(modInfo.LoadedPdbName, '\\');
if(pdbFileName)
pdbFileName[1] = '\0';
// Copy back to the caller's buffer
strcpy_s(FileName, MAX_STRING_SIZE, modInfo.LoadedPdbName);
strcat_s(FileName, MAX_STRING_SIZE, NewFile.c_str());
}
return true;
}