Saturday, March 06, 2010

Modifying class VTABLE at runtime

First of all, I am very grateful to Jaydeep Bhalerao and Vijay Balani for sharing
such cool stuff with me. Thanks a lot guys.

Disclaimer : This code is meant for experimental purposes only. Use it at your own risk.
I am not responsible for any consequences (good or bad)that may result due
the use of the code given herein.

The compiler generates a separate VTABLE for each class that either
defines its own virtual methods or inherits virtual methods from
another class or both. The VTABLE is used by the runtime environment
to dispatch virtual method calls at runtime. Another thing to note is
that the VTABLE is shared by ALL the objects of a class.

I wont go into the details of VTABLES here, for a more in-depth
discussion of VTABLES and their implementation use Wikipedia
entry for "VTABLE".

Here's another link : http://www.relisoft.com/book/lang/poly/2implem.html


Now here, I am going present some (very platform dependent) code
that changes the contents of a class' virtual table at runtime.

This works ONLY on Windows.

We start with a class that defines some virtual methods, as follows,

class Base
{

public:
virtual void fun1(){cout<<"\nfun1";}
virtual void fun2(){cout<<"\nfun2";}

};

Next up we shall define global function that shall later find a place in the Base class VTABLE,

static void fun3()
{

printf("\nThis is the modified virtual function");

}


Now that we have these two things in place. In the main function we need a Base object

Base* ptr = new Base;

Calling these virtual functions gives expected results,

ptr->fun1();
ptr->fun2();

Now comes the ugly part. We use the Win32 VirtualQuery function to retrieve information about the range of pages in the virtual address space of the calling process used by the VTABLE. The VirtualQuery function requires a pointer to a struct of type MEMORY_BASIC_INFORMATION to fill information about the pages.

LPDWORD* lpVtabl = (LPDWORD*)ptr;
lpVtabl = (LPDWORD*)*lpVtabl ;
MEMORY_BASIC_INFORMATION mbi1;

if(VirtualQuery( (LPVOID)(lpVtabl), &mbi1,
sizeof(mbi1)) != sizeof(mbi1))

return -1;


Now get the base address of the VTABLE,

PVOID pvRgnBaseAddress1 = mbi1.BaseAddress;

Normally, the protion of the virtual address space where the VTABLE resides is write protected, if we have to modify the VTABLE we must subvert this protection mechanism. The Win32 VirtualProtect function allows you change the read-write access permissions of a range of pages. We pass it the base address of the VTABLE and the flag PAGE_EXECUTE_READWRITE to make it writable.

if(FALSE == ::VirtualProtect( pvRgnBaseAddress1, 4,
PAGE_EXECUTE_READWRITE, &dwOldProtect11))
return -1;

Now the code that follows changes the VTABLE contents, substituting address of function "fun3" in place of a virtual member function,

DWORD dw = reinterpret_cast(fun3);
memcpy((LPVOID)(lpVtabl + 0), (LPVOID)(lpVtabl + 1), 4);
memcpy((LPVOID)(lpVtabl + 1), (LPVOID)&dw, 4);

Voila, there you go. Now try calling the virtual methods,

ptr->fun1();
ptr->fun2();

The output is as follows,

fun2
This is the modified virtual function

If anybody wants the full code, leave your email address in the comment, I will mail it to you.

No comments: