Code:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dbghelp.h>
#include <iostream>
#include <cstring>
#include <new>
// here be typedefs and definitions of imported functions
typedef DWORD (WINAPI*SetOptsFunc)(DWORD);
typedef BOOL (WINAPI*InitFunc)(HANDLE, LPCSTR, BOOL);
typedef DWORD64 (WINAPI*LoadFunc)(HANDLE, HANDLE, LPCSTR, LPCSTR, DWORD64, DWORD, PMODLOAD_DATA, DWORD);
typedef BOOL (WINAPI*EnumFunc)(HANDLE, DWORD64, LPCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
typedef BOOL (WINAPI*CleanupFunc)(HANDLE);
SetOptsFunc symSetOptions = NULL;
InitFunc symInitialize = NULL;
LoadFunc symLoadModuleEx = NULL;
EnumFunc symEnumSymbols = NULL;
CleanupFunc symCleanup = NULL;
bool LoadImports(HMODULE hDbghelp)
{
symSetOptions = reinterpret_cast<SetOptsFunc>(GetProcAddress(hDbghelp, "SymSetOptions"));
symInitialize = reinterpret_cast<InitFunc>(GetProcAddress(hDbghelp, "SymInitialize"));
symLoadModuleEx = reinterpret_cast<LoadFunc>(GetProcAddress(hDbghelp, "SymLoadModuleEx"));
symEnumSymbols = reinterpret_cast<EnumFunc>(GetProcAddress(hDbghelp, "SymEnumSymbols"));
symCleanup = reinterpret_cast<CleanupFunc>(GetProcAddress(hDbghelp, "SymCleanup"));
return symSetOptions && symInitialize && symLoadModuleEx && symEnumSymbols && symCleanup;
}
void DisplayFlags(PSYMBOL_INFO pSym, std::ostream& out)
{
DWORD flags = pSym->Flags;
if(flags & SYMFLAG_REGISTER)
{
out << "\tregister\n";
}
if(flags & SYMFLAG_PARAMETER)
{
out << "\tfunction parameter\n";
}
if(flags & SYMFLAG_LOCAL)
{
out << "\tlocal variable\n";
}
if(flags & SYMFLAG_CONSTANT)
{
out << "\tconstant of value " << pSym->Value << '\n';
}
if(flags & SYMFLAG_EXPORT)
{
out << "\tmodule export\n";
}
if(flags & SYMFLAG_FORWARDER)
{
out << "\ta forwarder\n";
}
if(flags & SYMFLAG_FUNCTION)
{
out << "\tfunction\n";
}
if(flags & SYMFLAG_THUNK)
{
out << "\tthunk\n";
}
if(flags & SYMFLAG_TLSREL)
{
out << "\toffset into the TLS area\n";
}
if(flags & SYMFLAG_SLOT)
{
out << "\tmanaged code slot\n";
}
if(flags & SYMFLAG_ILREL)
{
out << "\taddress relative to the IL block\n";
}
if(flags & SYMFLAG_METADATA)
{
out << "\tchunk of managed metadata\n";
}
if(flags & SYMFLAG_CLR_TOKEN)
{
out << "\tCLR token\n";
}
}
// see http://msdn.microsoft.com/en-us/library/bkedss5f.aspx for more
// info on what the typeTags mean
const char* typeTags[] = {
"",
"Executable (Global)",
"Compiland",
"CompilandDetails",
"CompilandEnv",
"Function",
"Block",
"Data",
"Unused",
"Labe",
"PublicSymbol",
"UDT",
"Enum",
"FunctionType",
"PointerType",
"ArrayType",
"BaseType",
"Typedef",
"BaseClass",
"Friend",
"FunctionArgType",
"FuncDebugStart",
"FuncDebugEnd",
"UsingNamespace",
"VTableShape",
"VTable",
"Custom",
"Thunk",
"CustomType",
""
};
BOOL CALLBACK SymFound(PSYMBOL_INFO pSymInfo, ULONG, PVOID pFoundFlag)
{
*(static_cast<bool*>(pFoundFlag)) = true;
std::cout << "Found symbol\n";
std::cout << "Name: " << pSymInfo->Name << '\n';
if(pSymInfo->Address)
{
std::cout << "Address: 0x" << std::hex << pSymInfo->Address << '\n';
}
if(pSymInfo->Flags)
{
std::cout << "Type Flags: ";
DisplayFlags(pSymInfo, std::cout);
}
std::cout << "Type Tag: " << typeTags[pSymInfo->Tag] << '\n';
std::cout << '\n';
return TRUE;
}
int main(int argc, char** argv)
{
if(argc >= 2)
{
HMODULE hDbghelp = LoadLibrary(L"dbghelp_6.9.dll");
if(hDbghelp && LoadImports(hDbghelp))
{
HANDLE hProc = GetCurrentProcess();
symSetOptions(SYMOPT_ALLOW_ZERO_ADDRESS | SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE |
SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME |
SYMOPT_OMAP_FIND_NEAREST);
if(symInitialize(hProc, 0, FALSE))
{
HANDLE hFile = CreateFileA(argv[1], GENERIC_READ, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
DWORD64 baseAddress = 0;
if((baseAddress = symLoadModuleEx(hProc, hFile, argv[1],
NULL, 0, GetFileSize(hFile, NULL), NULL, 0)))
{
bool anyFound = false;
const char* matchString = argv[2] ? argv[2] : "*";
if(symEnumSymbols(hProc, baseAddress, matchString, &SymFound, &anyFound))
{
if(!anyFound)
{
std::cout << "No symbols of pattern " << matchSymbolBuf << " found\n";
}
}
else std::cout << "Failed to enumerate symbols - error " << GetLastError() << '\n';
}
else std::cout << "Couldn't load image module and symbols - error " << GetLastError();
CloseHandle(hFile);
}
else std::cout << "Couldn't open image file - error " << GetLastError();
symCleanup(hProc);
FreeLibrary(hDbghelp);
}
else std::cout << "Couldn't load or find symbols in dbghelp.dll";
}
else std::cout << "Couldn't initialize the symbol handler";
}
else
{
// symbol name is case insensitive and can take
// multiple wildcards so that "MySym", "*Sym" and "*Sym*"
// are all valid and will match MySym and mysym
std::cout << "Usage: SymFinder [image file] <optional symbol name>";
}
std::cout << std::endl;
}