mirror of
https://github.com/jdu2600/Get-InjectedThreadEx
synced 2026-06-08 14:59:49 +00:00
155 lines
5.8 KiB
C++
155 lines
5.8 KiB
C++
#include "Get-InjectedThreadEx.h"
|
|
|
|
typedef struct _SYMBOL_INFO_FULL : SYMBOL_INFO {
|
|
CHAR NameBuffer[MAX_SYM_NAME - 1];
|
|
} SYMBOL_INFO_FULL;
|
|
#define INIT_FAILED ((HANDLE)-3)
|
|
|
|
constexpr auto SYMOPTS = SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES;
|
|
|
|
constexpr auto MicrosoftPublicSymbols = L"srv**https://msdl.microsoft.com/download/symbols";
|
|
|
|
static HANDLE GetUniqueIdForSymbols() {
|
|
// Initialise once - note we're only resolving symbols locally.
|
|
static HANDLE s_hUniqueId = NULL; // INVALID_HANDLE_VALUE == GetCurrentProcess()!
|
|
if (NULL == s_hUniqueId) {
|
|
if (!SymSetOptions(SymGetOptions() | SYMOPTS))
|
|
LogError("SymSetOptions() failed with 0x%x", GetLastError());
|
|
s_hUniqueId = GetCurrentProcess();
|
|
if (!SymInitializeW(s_hUniqueId, MicrosoftPublicSymbols, FALSE)) {
|
|
LogError("SymInitialize() failed with 0x%x", GetLastError());
|
|
s_hUniqueId = INIT_FAILED;
|
|
}
|
|
else
|
|
{
|
|
// Check that we're using public symbols - not just exports
|
|
auto hNtdll = GetModuleHandleW(L"ntdll.dll");
|
|
std::wstring ntdllPath;
|
|
if (!GetMappedFileNameAsDosPath(GetCurrentProcess(), hNtdll, ntdllPath))
|
|
LogError("GetMappedFilename(ntdll) failed");
|
|
if(!SymLoadModuleExW(s_hUniqueId, NULL, ntdllPath.c_str(), NULL, (DWORD64)hNtdll, 0, NULL, 0))
|
|
LogError("SymLoadModule(ntdll) failed");
|
|
if (!GetSymbolAddress("ntdll!TppWorkerThread"))
|
|
LogError("WARNING Symbols not found - falling back to exports");
|
|
|
|
auto hKernel32 = GetModuleHandleW(L"kernel32.dll");
|
|
std::wstring kernel32Path;
|
|
if (!GetMappedFileNameAsDosPath(GetCurrentProcess(), hKernel32, kernel32Path))
|
|
LogError("GetMappedFilename(kernel32) failed");
|
|
if (!SymLoadModuleExW(s_hUniqueId, NULL, kernel32Path.c_str(), NULL, (DWORD64)hKernel32, 0, NULL, 0))
|
|
LogError("SymLoadModule(kernel32) failed");
|
|
}
|
|
}
|
|
return s_hUniqueId;
|
|
}
|
|
|
|
PVOID GetSymbolAddress(const char symbol[]) {
|
|
const auto hUniqueId = GetUniqueIdForSymbols();
|
|
if (INIT_FAILED == hUniqueId)
|
|
return NULL;
|
|
|
|
SYMBOL_INFO_FULL symbolInfo{};
|
|
symbolInfo.SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
symbolInfo.MaxNameLen = MAX_SYM_NAME;
|
|
if (!SymFromName(hUniqueId, symbol, &symbolInfo))
|
|
return NULL;
|
|
|
|
return (PVOID)symbolInfo.Address;
|
|
}
|
|
|
|
|
|
// pretty print <module>!<symbol>[+<displacement>]
|
|
void GetPrettySymbol(HANDLE hProcess, PVOID address, std::wstring& modulePath, std::string& symbol, bool bIncludeDisplacement) {
|
|
symbol.resize(128);
|
|
symbol = std::filesystem::path(modulePath).filename().string();
|
|
|
|
SYMBOL_INFO_FULL symbolInfo{};
|
|
symbolInfo.SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
symbolInfo.MaxNameLen = MAX_SYM_NAME;
|
|
DWORD64 displacement = 0;
|
|
if (SymFromAddr(hProcess, (DWORD64)address, &displacement, &symbolInfo)) {
|
|
symbol += "!" + std::string(symbolInfo.Name);
|
|
}
|
|
else if (bIncludeDisplacement) {
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
if (VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi)))
|
|
displacement = (DWORD64)address - (DWORD64)mbi.AllocationBase;
|
|
}
|
|
|
|
if (bIncludeDisplacement && displacement) {
|
|
char buffer[_MAX_U64TOSTR_BASE16_COUNT];
|
|
_ui64toa_s(displacement, buffer, sizeof(buffer), 16);
|
|
symbol += "+0x" + std::string(buffer);
|
|
}
|
|
|
|
symbol.resize(strlen(symbol.c_str()));
|
|
}
|
|
|
|
BOOL GetNearestSymbolWithPdb(HANDLE hProcess, PVOID address, std::string& symbol, bool bIncludeDisplacement) {
|
|
if (!SymSetOptions(SymGetOptions() | SYMOPTS))
|
|
LogError("SymSetOptions() failed with 0x%x", GetLastError());
|
|
|
|
if (!SymInitializeW(hProcess, MicrosoftPublicSymbols, FALSE)) {
|
|
LogError("SymInitialize() failed with 0x%x", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
std::wstring modulePath;
|
|
if (!GetMappedFileNameAsDosPath(hProcess, address, modulePath)) {
|
|
if (symbol.empty()) {
|
|
char buffer[_MAX_U64TOSTR_BASE16_COUNT];
|
|
_ui64toa_s((DWORD64)address, buffer, sizeof(buffer), 16);
|
|
symbol = "0x" + std::string(buffer);
|
|
}
|
|
(void)SymCleanup(hProcess);
|
|
return TRUE;
|
|
}
|
|
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
if (!VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi)) ||
|
|
!SymLoadModuleExW(hProcess, NULL, modulePath.c_str(), NULL, (DWORD64)mbi.AllocationBase, 0, NULL, 0))
|
|
{
|
|
(void)SymCleanup(hProcess);
|
|
// fallback to best-effort
|
|
const auto hUniqueId = GetUniqueIdForSymbols();
|
|
GetPrettySymbol(hUniqueId, address, modulePath, symbol, bIncludeDisplacement);
|
|
return FALSE;
|
|
}
|
|
|
|
GetPrettySymbol(hProcess, address, modulePath, symbol, bIncludeDisplacement);
|
|
|
|
(void)SymCleanup(hProcess);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL GetNearestSymbol(HANDLE hProcess, PVOID address, std::string& symbol, bool bIncludeDisplacement) {
|
|
const auto hUniqueId = GetUniqueIdForSymbols();
|
|
if (INIT_FAILED == hUniqueId)
|
|
return FALSE;
|
|
|
|
// Maintain a cache of symbols in shared image allocations
|
|
static std::unordered_map<PVOID, std::string> s_SymbolCache;
|
|
const auto it = s_SymbolCache.find(address);
|
|
if (it != s_SymbolCache.end()) {
|
|
symbol = it->second;
|
|
return TRUE;
|
|
}
|
|
|
|
// module name (from remote process)
|
|
std::wstring modulePath;
|
|
if (!GetMappedFileNameAsDosPath(hProcess, address, modulePath)) {
|
|
char buffer[_MAX_U64TOSTR_BASE16_COUNT];
|
|
_ui64toa_s((DWORD64)address, buffer, sizeof(buffer), 16);
|
|
symbol = "0x" + std::string(buffer);
|
|
return TRUE;
|
|
}
|
|
|
|
GetPrettySymbol(hUniqueId, address, modulePath, symbol, bIncludeDisplacement);
|
|
|
|
if (InSystemImageRange(address))
|
|
s_SymbolCache.insert(std::make_pair(address, symbol));
|
|
|
|
return TRUE;
|
|
}
|