Print C++ Vtables Using Gdb

Print C++ vtables using GDB


(gdb) set $i = 0
(gdb) while $i < 10
>print $i
>p /a (*(void ***)obj)[$i]
>set $i = $i + 1
>end

Where "obj" is the object whose vtable you'd like to print, and 10 is the number of methods.

How to print virtual function of the VTable at a specific address when debugging with GDB

You need to load the function pointer from the vtable. Assuming the vtable is at address 0x555555755d48

(gdb) info symbol 0x0000555555755d48
vtable for Derived in section .data.rel.ro of /tmp/a.out

I can obtain the name of the virtual function like this:

(gdb) print ((void **)0x0000555555755d48)[2]
$3 = (void *) 0x555555554bca <Derived::Foo()>

Obviously, this will need debugging information. Exported vtables do not include names because they are identified by offset only (even if exported functions have names).

How to watch the vtable in gdb in a C++ program?

You can use the -fdump-class-hierarchy option of gcc which will give you the vtable information, however the output can be very verbose and hard to read.

For instance, given the following trivial classes:

class Base {                                                                            
public:
virtual int method() = 0;
};

class Derived : public Base {
public:
int method() {
return 10;
}
};

the relevant output is

Vtable for Base
Base::_ZTV4Base: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI4Base)
16 (int (*)(...))__cxa_pure_virtual

Class Base
size=8 align=8
base size=8 base align=8
Base (0x7f14c308ccc0) 0 nearly-empty
vptr=((& Base::_ZTV4Base) + 16u)

Vtable for Derived
Derived::_ZTV7Derived: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI7Derived)
16 (int (*)(...))Derived::method

Class Derived
size=8 align=8
base size=8 base align=8
Derived (0x7f14c2ee7208) 0 nearly-empty
vptr=((& Derived::_ZTV7Derived) + 16u)
Base (0x7f14c308cd20) 0 nearly-empty
primary-for Derived (0x7f14c2ee7208)

This should give you an idea which address ranges to expect during debuggng etc.

How to navigate through methods of a vtable?

The vTable is just an array of function pointers, so just an array of pointers. If the target process is x86 then just add 0x4 to the address of the first pointer and you will get the second pointer in the vtable. If the target process is x64, add 0x8 because that's the size of a pointer on that architecture.

Secondly, you're defining these as cdecl function which isn't going to work how you've planned. Virtual functions / member functions are __thiscall, which require the this pointer to be passed in ECX. So you need to typedef the function pointers correctly and pass the thisptr as the first argument.

Tested working:

typedef int(__thiscall *firstFun)(void* thisptr);
typedef int(__thiscall *secondFun)(void* thisptr, int);

class B
{
public:
virtual int first() = 0;
virtual int second(int) = 0;
};

class D : public B
{
public:
virtual int first() { return 42; }
virtual int second(int x)
{
return first() + x;
}
};

void pb(B* object, int x)
{
unsigned int adressVTable = *(unsigned int*)object;
unsigned int adressVTable2 = adressVTable + 0x4;
firstFun bFirst = (firstFun)(*(unsigned int*)(adressVTable));
secondFun bSecond = (secondFun)(*(unsigned int*)(adressVTable2));
int f = bFirst(object);
int s = bSecond(object, x);
printf("First: %d, second: %d", f, s);
}

int main()
{
D obj;

pb(&obj, 5);

getchar();

return 0;
}


Related Topics



Leave a reply



Submit