/** * @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 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 & 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( 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::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 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 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 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 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 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; }