Tonight I will discuss some more on function pointer to symbol translation using displacement from base. because we found that such translation seems difficult without SymInitialize method that takes the handle of the target process. We will look at getting that information from dumps. MSDN says that the handle passed to SymInitialize must be the same value passed to all other symbol handlers functions called by the process. It is the handle that the functions use to identify the caller and locate the correct symbol information. Only that a process that acts like a debugger should not call the GetCurrentProcess to provide the handle and instead provide the handle of the target process. Thus the handle merely seems to be a token for a context. The other parameters to this function are UserSearchPath and fInvadeProcess. The UserSearchPath are the series of paths to be searched for a symbol file. This is an optional parameter. The fInvadeProcess when enumerates the loaded module for the process.
When you try out the SymInitialize with a bogus non-zero handle and follow it with a SymFromAddr call, it returns the error indicating that the handle is invalid.
but that method also doesn't help us specify the handle of a non-existent process.
So the only option left is to try creating a process with CreateProcess and DEBUG_PROCESS flag to specify that the created process is in debugging mode.
_In_ DWORD dwCreationFlags, <------------------------------------- DEBUG_PROCESS
So I tried out with :
// Raw2Sym.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "windows.h"
#include "dbghelp.h"
#pragma comment(lib, "dbghelp.lib")
int _tmain(int argc, _TCHAR* argv[])
{
//HMODULE hDbgModule = LoadLibrary(L"dbghelp.dll");
if (argc < 3)
{
printf("Usage: raw2sym base_addr func_ptr func_ptr ...\r\n");
return -1;
}
DWORD error = 0;
HANDLE hProcess = 0;
bool initialized = false;
hProcess = GetCurrentProcess();
printf ("hProcess = %ld\r\n", hProcess);
_TCHAR wszPath[MAX_PATH+1] = {0};
WCHAR szImageName[MAX_PATH] = TEXT("foo.exe");
DWORD64 dwBaseAddr = _tcstoui64(argv[1], NULL, 16);
printf("Base Address: %p\r\n", dwBaseAddr);
HANDLE hExe = 0;
HANDLE hFile = 0;
if (!GetCurrentDirectory(MAX_PATH, wszPath))
{
error = GetLastError();
printf("GetCurrentDirectory returned error: %d\r\n", error);
goto exit;
}
else
{
wprintf(L"Current directory is %s\r\n", wszPath);
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if(!CreateProcess(L"foo.exe", NULL,
NULL, NULL, false,DEBUG_PROCESS, NULL, wszPath, &si, &pi))
{
error = GetLastError();
printf("CreateProcess returned error: %d\r\n", error);
goto exit;
}
hExe = pi.hProcess;
if(!hExe)
{
printf("raw2sym must have splunkd exe and pdb in the same folder as the tool.\r\n");
return -1;
}
else
{
printf ("hExe = 0x%x\r\n", hExe);
}
if (!SymInitializeW(hExe, wszPath, FALSE))
{
// SymInitialize failed
error = GetLastError();
printf("SymInitialize returned error : %d\r\n", error);
goto exit;
}
else
{
initialized = true;
}
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
hFile = CreateFile(L"foo.pdb", 0, 0, NULL, 0, 0, NULL);
DWORD64 loadedAddress = SymLoadModuleEx(hExe, hFile, "foo.pdb", NULL,dwBaseAddr , 0, NULL, SLMFLAG_VIRTUAL);
if(loadedAddress == 0)
{
// SymLoadModuleEx failed
error = GetLastError();
printf("SymLoadModuleEx returned error : %d\n", error);
goto exit;
}
else
{
printf("Loaded Address is %p: \r\n", loadedAddress);
}
for (int i = 2 ; i < argc; i++)
{
DWORD64 dwDisplacement = 0;
DWORD64 dwAddress = _tcstoui64(argv[i], NULL, 16);
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
if (!SymSetScopeFromAddr(hProcess, loadedAddress))
{
DWORD error = GetLastError();
printf("SymSetScopeFromAddr for %s returned error : %d\r\n", argv[i], error);
}
if (SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol))
{
printf("%s\r\n", &(pSymbol->Name));
}
else
{
// SymFromAddr failed
DWORD error = GetLastError();
printf("SymFromAddr for %s returned error : %d\r\n", argv[i], error);
}
}
exit:
if (initialized && hExe)
SymCleanup(hExe);
if (hExe)
CloseHandle(hExe);
if (hProcess)
CloseHandle(hProcess);
if (hFile)
CloseHandle(hFile);
return 0;
}
But that returns an error:
c:\downloads\Raw2Sym\x64\Release>Raw2Sym.exe 000007f79b1b0000 000007f79b1bbb90
hProcess = -1
Base Address: 000007F79B1B0000
Current directory is c:\downloads\Raw2Sym\x64\Release
hExe = 0x34
Loaded Address is 000007F79B1B0000:
SymSetScopeFromAddr for 0 returned error : 6
SymFromAddr for 0 returned error : 6
Error code: (Win32) 0x6 (6) - The handle is invalid.
Instead found a helpful resource here : http://www.debuginfo.com/examples/dbghelpexamples.html
and giving it a try. The code mentioned under SymLoadFromPdb.cpp gives some suggestions but doesn't work either.
c:\downloads\Raw2Sym\x64\Release>Raw2Sym.exe c:\downloads\Raw2Sym\x64\Release\splunkd.pdb 00
1b0000 000007f79b1bbb90
Loading symbols for: c:\downloads\Raw2Sym\x64\Release\splunkd.pdb ...
Error: SymLoadModule64() failed. Error code: 0
A better option might be to use DIA sdk instead as mentioned here : http://msdn.microsoft.com/en-us/library/4sy4ebfw.aspx .
Conceptually, I don't know if any technique will allow this method since the process/dump needs to be available in memory or disk to associate the base address and the offset. The instruction set is unchanged after the compile so the pdb and exe will be the same. Resolving the symbols from the instruction doesn't vary
As Dia SDK shows here in the article querying the pdb:
http://msdn.microsoft.com/en-us/library/eee38t3h.aspx