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.
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.
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.
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.
Hey Jijo great thanks to you. But one ore thing if you disable RTTI option. Your program less useful. Thanks again.
this is relevant as well:
i’ve added your blog to my links section, nice work.
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.
Sorry for the late reply,
Thanks for the kind words 🙂 I enjoy reading your posts as well.
Roman.
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.
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.