How to Parse Virtual Table?

7 05 2009

Virtual Table is one of the most fascinating stuff for C++ programmer. Well, did you ever  peek into virtual table, which is the real engine of virtual functions?

virtualfunction


The first 4 bytes of an objects points to another pointer which points to virtual table. Casting it to DWORD*, we can parse all virtual functions. Once you get function address, you can get the function name by calling – SymFromAddr(). Have a look at code snippet.

virtualfunction2

#include <ImageHlp.h>
...
// Get list of virtual functions.
void CRabbitDlg::ParseVtable()
{
    // Initialize symbols.
    InitializeSymbols();

    // We are going to parse vtable of CWinApp object.
    DWORD* pBase = (DWORD*)(AfxGetApp());
    DWORD* pVptr = (DWORD*)*pBase;

    // Iterate through VirtualTable.
    DWORD Index = 0;
    DWORD FnAddr = pVptr[Index];
    while( FnAddr )
    {
        // Translate FunctionAddress to FunctionName.
        CString FunctionName;
        GetSymbolNameFromAddr( FnAddr, FunctionName );

        // Format and add to list.
        CString Final;
        Final.Format( _T("%0x - %s"), FnAddr, FunctionName.operator LPCTSTR());
        m_List.AddString( Final );

        // Next function pointer.
        FnAddr = pVptr[++Index];
    }
}

// Initialize Symbol engine.
void CRabbitDlg::InitializeSymbols()
{
    DWORD Options = SymGetOptions();
    Options |= SYMOPT_DEBUG;
    Options |= SYMOPT_UNDNAME; 

    ::SymSetOptions( Options ); 

    // Initialize symbols.
    ::SymInitialize ( GetCurrentProcess(),
                      NULL,
                      TRUE );
}

// Get symbol name from address.
void CRabbitDlg::GetSymbolNameFromAddr( DWORD SymbolAddress, CString& csSymbolName )
{
    DWORD64 Displacement = 0;
    SYMBOL_INFO_PACKAGE SymbolInfo = {0};
    SymbolInfo.si.SizeOfStruct  = sizeof( SYMBOL_INFO );
    SymbolInfo.si.MaxNameLen = sizeof(SymbolInfo.name);

    // Get symbol from address.
    ::SymFromAddr( GetCurrentProcess(),
                   SymbolAddress,
                   &Displacement,
                   &SymbolInfo.si );

    csSymbolName = SymbolInfo.si.Name;
}


Don’t forget to include ImageHlp.lib to project settings.


Targeted Audiance – Intermediate.


Actions

Information

9 responses

30 07 2009
Marko

Hey Jijo. I tried your code. But always failed. Compilation finished well but runtime object occurse acces violation. Im writing code here.

#define WINVER 0x0601

#define WIN32_LEAN_AND_MEAN
#include
//#include
#include
#include
#include

#pragma comment( lib, “dbghelp.lib” )

using namespace std;

void ParseVtable( void* obj );
void InitializeSymbols();
void GetSymbolNameFromAddr( DWORD SymbolAddress, string& csSymbolName );

std::queue m_List;

// Get list of virtual functions.
void ParseVtable( void* obj )
{
// Initialize symbols.
InitializeSymbols();

// We are going to parse vtable of CWinApp object.
DWORD* pBase = (DWORD*)( obj ); // This line gives error
DWORD* pVptr = (DWORD*)*pBase;

// Iterate through VirtualTable.
DWORD Index = 0;
DWORD FnAddr = pVptr[Index];
while( FnAddr )
{
// Translate FunctionAddress to FunctionName.
string FunctionName;
GetSymbolNameFromAddr( FnAddr, FunctionName );

// Format and add to list.
CHAR Final[ 4096 ]; //CString Final;
sprintf_s( Final, _countof(Final), “%0x – %s”, FnAddr, FunctionName.c_str() );//Final.Format( _T(“%0x – %s”), FnAddr, FunctionName.c_str() );
m_List.push( Final );//m_List.AddString( Final );

// Next function pointer.
FnAddr = pVptr[++Index];
}
}

// Initialize Symbol engine.
void InitializeSymbols()
{
DWORD Options = SymGetOptions();
Options |= SYMOPT_DEBUG;
Options |= SYMOPT_UNDNAME;

::SymSetOptions( Options );

// Initialize symbols.
::SymInitialize ( GetCurrentProcess(),
NULL,
TRUE );
}

// Get symbol name from address.
void GetSymbolNameFromAddr( DWORD SymbolAddress, string& csSymbolName )
{
DWORD64 Displacement = 0;
SYMBOL_INFO_PACKAGE SymbolInfo = {0};
SymbolInfo.si.SizeOfStruct = sizeof( SYMBOL_INFO );
SymbolInfo.si.MaxNameLen = sizeof(SymbolInfo.name);

// Get symbol from address.
::SymFromAddr( GetCurrentProcess(),
SymbolAddress,
&Displacement,
&SymbolInfo.si );

csSymbolName = SymbolInfo.si.Name;
}

int wmain()
{
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF );
_wsetlocale( LC_ALL, L”trk” );
SetConsoleTitleW( L”Howto Parse VTable” );

std::wstring wString = L”Sallama”;

ParseVtable( (void*)&wString );

_CrtDumpMemoryLeaks();
return wcin.get();
}

DWORD* pBase = (DWORD*)( obj ); // This line gives error

I dont know why but i assume you can answer well. Thansk.

31 07 2009
Jijo.Raj

Hi Marco,

The line “DWORD* pBase = (DWORD*)( obj );” is already present in ParseVtable() function. So it can be removed. If you put it outside, pBase become global variable and it needs obj to compile. Thats why compiler is popping error.

If the compilation gives more error feel free to post. I’ll try to help you.

Regards,
Jijo.

5 08 2009
Marko

Hey Jijo Great thanks to you. But some problems stay with me.

Here corrected code: http://tinyurl.com/lt8c6y
I reuploaded to code share sites. Also you can view here: http://www.copypastecode.com/8327/

Here problems. When i build with debug mode and debug code then everyting works without problems but in release mode i cannot see what i saw in debug mod. I Dont know. I will also upload pics. Thanks.

10 08 2009
Marko

Hey Jijo great thanks to you. But one ore thing if you disable RTTI option. Your program less useful. Thanks again.

15 08 2009
xpertz

this is relevant as well:

Changing the vtable pointer

i’ve added your blog to my links section, nice work.

6 10 2009
Jijo.Raj

Hi Xpertz,

Thanks for the sharing the link.
And thanks a lot for adding my blog to your links section, buddy.

Are you the author of cpptalk? Its pretty nice blog!

Best Regards,
Jijo.

13 10 2009
rmn

Sorry for the late reply,
Thanks for the kind words 🙂 I enjoy reading your posts as well.

Roman.

12 09 2009
Janson lee

Hi JiJo

This is not directly related to parsing the virtual table but it is related to the dbghelp.dll

I noticed on the msdn site

http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/488135b1-2f92-4d3a-aafb-f9eb56b1736f

that you suggested to use the SymFromName routine to obtain
the SYMBOL_Info.address and cast it to a function pointer to call the function directly.

This does not seem to work for me, Is there some step that has to be applied to SYMBOL_Info.Address before it can be used as a function pointer.

16 09 2009
Jijo.Raj

Hi Janson,

You have to initialize the DebugHelp library by calling SymInitialize().
And make sure that you have enabled debug symbols for your project.

Hope it helps!

Best Regards,
Jijo.

Leave a reply to Jijo.Raj Cancel reply