Posted by RahimCasper in Assembly, C, C++, Featured, Hacks, Programming Language, Tips & Tricks, Tutorial, Visual Studio | 1 Comment
Directly Accessing Virtual Table
Before reading this post, make sure you have a strong grip on C, C++ & little bit of Assembly Language. To understand the content of this topic, you’ll need to have basic understanding of what “Virtual Function Table” is.
A pointer is 32bit (4 bytes) in a 32-bit architecture and 64bit (8 bytes) in a 64-bit architecture. So all instances/objects of a class or class hierarchy, where we have a virtual table (declared one or more methods as virtual in class or it was declared in one of its base class), will have additional 4 bytes in them and 8 bytes in case of a 64-bit architecture.
This pointer is called virtual table pointer, sometimes ‘vptr’. In VC++ compiler, the objects will have a pointer named ‘__vfptr’ in them and in some other compiler it’s ‘__vptr_X’, where X is the class name.
Now, __vfptr is not directly accessible from your code. For example, if you write the following code you’ll get a compiler error as the __vfptr is not available for your use.
//Creating object of class X and passing integer as parameter.
X objX( 123 );
//Trying to get __vfptr directly.
objX.__vfptr;
However, if you compile and debug the code after commenting this line:
objX.__vfptr;
you’ll see ‘objX.__vfptr’ in the variable watch window.
Okay, now we’d like to see how we can access the virtual table even if the compiler doesn’t want us to. The following code does that.
#include <iostream>
//A simple class
class X
{
private:
//Integer data member
int m_nValue;
public:
//Constructor with type integer as parameter
X( int nVal )
{
m_nValue = nVal;
}
//virtual function with no parameter & no return type
virtual void Func1( void )
{
std::cout << "Virtual Func1 Called!" << std::endl;
}
//virtual function with one integer parameter & no return type
virtual void Func2( int nParam )
{
std::cout << "Virtual Func2 Called With Parameter Value: " << nParam << std::endl;
}
//virtual function with no parameter & integer return type
virtual int Func3( void )
{
return this->m_nValue;
}
//Destructor
virtual ~X( )
{
}
};
int main( int argc, char* argv[] )
{
//Creating object of class X as pointer and passing integer as parameter.
X *pObj = new X( 123 );
//Getting virtual table pointer of object pObj and assigning it to vfptr
size_t *vfptr = *( reinterpret_cast< size_t** >( pObj ) );
//Virtual Table is filled sequentially (from top to bottom), like
//I have first declared Func1, so it will be on position '0'.
//After that Func2, so it will be on position '1' on Virtual Table. And so on...
//Now we will assign Function Addresses to its respective Function Pointers
//that matches their declared function signature.
//You can also use typedef for function pointers:
//typedef void (__stdcall *FUNC1)( void );
//FUNC1 Func1 = reinterpret_cast<FUNC1>(vfptr[0]);
void (__stdcall *Func1)( void ) = (void (__stdcall *)(void))vfptr[0];
void (__stdcall *Func2)( int nParam ) = (void (__stdcall *)(int))vfptr[1];
int (__stdcall *Func3)( void ) = (int (__stdcall *)(void))vfptr[2];
//Before directly calling methods from virtual table, we first have to pass
//this pointer.
//Assigning this pointer to ECX register. VC++ compiler uses ECX register
//to pass this pointer to its methods instead of pushing it on stack.
__asm
{
mov ecx, pObj
}
//Calling Func1
Func1( );
//Again assigning this pointer. Hmm... Again assigning this pointer. Why?
//Reason is EBX, ESI, EDI and EBP are preserved inside function call
//and EAX, ECX, EDX are freely allowed to be overwritten. So there is
//a fair chance that ECX register may have been overwritten so we are
//again assigning this pointer to ECX register.
__asm
{
mov ecx, pObj
}
//Calling Func2 and passing an integer as parameter.
Func2( 123 );
//Assigning this pointer. Same reason given above.
__asm
{
mov ecx, pObj
}
//Calling Func3 and saving its return value in nRetVal.
int nRetVal = Func3();
std::cout << "Value returned by Func3: " << nRetVal << std::endl;
return 0;
}
Note: This code will work only in VC++.
All the explaining is done in the code, the only question which may arise in your mind is why have I used ‘stdcall’ instead of ‘cdecl’ in following code:
void (__stdcall *Func1)( void ) = (void (__stdcall *)(void))vfptr[0];
void (__stdcall *Func2)( int nParam ) = (void (__stdcall *)(int))vfptr[1];
int (__stdcall *Func3)( void ) = (int (__stdcall *)(void))vfptr[2];
Well those who know Calling Convensions and know how ‘thiscall’ works have already figured out why I have used ‘stdcall’ calling convention here.
For others here is the explanation:
GCC ‘thiscall’ is similar to ‘cdecl’ but this pointer is pushed last onto the stack as if it would have been the first argument to the function. But VC++ ‘thiscall’ is similar to ‘stdcall’ but the this pointer passed in ECX. So that’s why I have used ‘stdcall’. Calling a function with the “wrong” convention will destroy the stack.








Facebook
RSS
Twitter
Directly Accessing Virtual Table – http://t.co/6xwix8oU via @cmmsol #tutorial #cplusplus #programming #cmmsol
thanks for sharing this information. great, keep it up.