Gold mine of Visual C++ tricks!
How to Parse Virtual Table?
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?

![]()
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.

#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.
| Print article | This entry was posted by Jijo Raj on May 7, 2009 at 4:47 pm, and is filed under Uncategorized. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |
about 1 year ago
Hey Jijo. I tried your code. But always failed. Compilation finished well but runtime object occurse acces violation. Im writing code here.
#define WINVER 0×0601
#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.
about 1 year ago
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.
about 1 year ago
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.
about 1 year ago
Hey Jijo great thanks to you. But one ore thing if you disable RTTI option. Your program less useful. Thanks again.
about 1 year ago
this is relevant as well:
http://cpptalk.wordpress.com/2009/08/14/changing-the-vtable-pointer/
i’ve added your blog to my links section, nice work.
about 11 months ago
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.
about 10 months ago
Sorry for the late reply,
I enjoy reading your posts as well.
Thanks for the kind words
Roman.
about 11 months ago
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.
about 11 months ago
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.