Solution 2: Loading symbol information using
EnumerateModules64 and SymLoadModule64.
Until know, we discussed how to load
symbols using SymInitialize.
As stated earlier, this method can actually only be used if you are
debugging a local process. Next we will discuss a solution without
this limitation.
We can also let the tool request
information about the loaded modules from the game when symbol
information is required. Console platforms with only a single loaded
image can simply return the image base and image name. Other
platforms having multiple loaded images can return a list of loaded
modules, along with their image bases. What we need to do now is
mimic the behaviour of SymInitialize.
We can enumerate all loaded modules for a process by using
EnumerateModules64.
Using this function, we can find the image bases for all of the
loaded modules, their names and even the location of the PDB file.
Listing 5 shows exactly that:
The program output shows the
information that we retrieved from the active modules:
This information can be sent to the
tool. Note that this way of requesting image information by the tool
does require the network connection to support two-way traffic.
Now that we have the names of our
program databases we can load them using SymLoadModule64.
The previous article contains a code snippet that loads information
using SymLoadModule64.
|
|
#include "stdafx.h"
#include
#include
#include
#include
std::string GetSymbolTypeString(SYM_TYPE symType)
{
std::string result;
switch(symType)
{
case SymCoff:
result = "COFF symbols.";
break;
case SymCv:
result = "CodeView symbols.";
break;
case SymDeferred:
result = "Symbol loading deferred.";
break;
case SymDia:
result = "DIA symbols.";
break;
case SymExport:
result = "Symbols generated from a DLL export table.";
break;
case SymNone:
result = "No symbols are loaded.";
break;
case SymPdb:
result = "PDB symbols.";
break;
case SymSym:
result = ".sym file.";
break;
case SymVirtual:
result = "Virtual module.";
break;
}
return result;
}
BOOL CALLBACK Enumerate(
PSTR moduleName,
DWORD64 moduleBase,
ULONG moduleSize,
PVOID userContext)
{
HANDLE currentProcess = GetCurrentProcess();
DWORD64 imageBase = ::SymLoadModule64(
currentProcess,
NULL,
moduleName,
NULL,
moduleBase,
moduleSize);
IMAGEHLP_MODULE64 moduleInfo;
memset(&moduleInfo, 0, sizeof(moduleInfo));
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
::SymGetModuleInfo64(currentProcess, imageBase, &moduleInfo);
::SymUnloadModule64(currentProcess, imageBase);
std::string symbolTypeString = GetSymbolTypeString(moduleInfo.SymType);
std::cout <<
"name: " << moduleName << std::endl <<
" base: " << moduleBase << std::endl <<
" size: " << moduleSize <<<
" symbol type: " << symbolTypeString.c_str() << std::endl <<
" pdb: " << moduleInfo.LoadedPdbName << std::endl <<
std::endl;
return true;
}
void EnumAllModules()
{
char path[_MAX_PATH];
::GetModuleFileNameA(GetModuleHandle(NULL), path, sizeof(path));
char file[_MAX_FNAME], ext[_MAX_EXT];
_splitpath_s(path, NULL, 0, NULL, 0,
file, sizeof(file), ext, sizeof(ext));
strcat_s(file, sizeof(file), ext);
::EnumerateLoadedModules64(GetCurrentProcess(),
(PENUMLOADED_MODULES_CALLBACK64)Enumerate, file);
}
int main(int argc, char* argv[])
{
HANDLE currentProcess = GetCurrentProcess();
::SymInitialize(currentProcess, NULL, FALSE);
EnumAllModules();
::SymCleanup(currentProcess);
return 0;
}
|
 |
 |
 |
Listing 5: EnumerateModuleInfo program.
|
name:
D:\work\Tests\DisplayLoadedModules\debug\DisplayLoadededModules.exe
base:
4194304
size:
118784
symbol
type: PDB symbols.
pdb:
.\DisplayLoadedModules.pdb
name:
C:\WINDOWS\system32\ntdll.dll
base:
2089811968
size:
745472
symbol
type: Symbols generated from a DLL export table.
pdb:
name:
C:\WINDOWS\system32\kernel32.dll
base:
2088763392
size:
1040384
symbol
type: Symbols generated from a DLL export table.
pdb:
name:
D:\work\Tests\DisplayLoadedModules\debug\dbghelp.dll
base:
50331648
size:
1134592
symbol
type: Symbols generated from a DLL export table.
pdb:
Note: I wasn’t kidding about
downloading the latest version of DbgHelp.dll. I have wasted a lot of
time on the bugs from older DbgHelp.dlls. Listing 5 contains a call
to SymGetModuleInfo64
and that function simply always returned zero on the 5.1 version of
the DLL. Error handling is bad in this library. In the latest version
of the DLL, which is 6.6 at the time of writing, there is no way I
can get the function SymGetSymbolFile
to work. So, I advice you to pay attention when programming for the
DbgHelp library, and don’t forget to use the latest DLL.
|