Wednesday, May 14, 2014

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.
Now we could use the

DWORD64 WINAPI SymLoadModuleEx(
  _In_  HANDLE hProcess,
  _In_  HANDLE hFile,
  _In_  PCTSTR ImageName,
  _In_  PCTSTR ModuleName,
  _In_  DWORD64 BaseOfDll,
  _In_  DWORD DllSize,
  _In_  PMODLOAD_DATA Data,
  _In_  DWORD Flags
);

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.

BOOL WINAPI CreateProcess(
  _In_opt_     LPCTSTR lpApplicationName,
  _Inout_opt_  LPTSTR lpCommandLine,
  _In_opt_     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  _In_opt_     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_         BOOL bInheritHandles,
  _In_         DWORD dwCreationFlags, <------------------------------------- DEBUG_PROCESS
  _In_opt_     LPVOID lpEnvironment,
  _In_opt_     LPCTSTR lpCurrentDirectory,
  _In_         LPSTARTUPINFO lpStartupInfo,
  _Out_        LPPROCESS_INFORMATION lpProcessInformation
);


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

No comments:

Post a Comment