Ghidra: Override type for C++ vTable for Derived Classes (with Base Class located at 0x0 of Class); c++ polymorphism

171 views Asked by At

I am new to ghidra and reverse engineering, but i have watched this series text and read text. And encountered following problem with ghidra:

When you have a Base class with members and virtual functions and a Derived class and the base class is located at 0x0 inside the Derived class for example, then the vTable for Derived class is colliding with the base vTable:

class Base {
    int var1;
    int var2;
public:
    virtual void virtual_func_1(void);
    virtual void virtual_func_2(void);
};

resulting in:

class Base size(12):
  +---
0 | {base_vTable}
4 | var1
8 | var2
  +---

and:

class Derived: public Base {
    int var3;
public:
    void virtual_func_3();
};

resulting in:

class Derived size(16):
+---
|  +--- (base class Base)
0  | | {base_vTable}
4  | | var1
8  | | var2
|  +---
12 | var3
+---

So far so good. The resulting assembly code (reinterpreted in C code) could look something like this:

void __thiscall Derived::Derived_constructor(Derived* this) {
  Base::Base_constructor((Base*) this);//the base class is located at 0x0 of Derived

  this->var3 = 0;
  (this->base).base_vTable = &PTR_FUN_004af9f4;//PTR_FUN_004af9f4 being the address of the Derived vTable <- this is where my problem arises, as it would be of type BaseVtable (in case 1, see below) but actually is of type DerivedVtable (casted to BaseVtable)
}

void __thiscall Base::Base_constructor(Base* this) {
  this->var1 = 0;
  this->var2 = 0;
  this->base_vTable = &PTR_FUN_004bf966;//PTR_FUN_004bf966 being the address of the Base vTable
}

Now i would create some structs:

BaseVtable {0x0: pointer virtual_func_1; 0x4: pointer virtual_func_2;}; 

Base {0x0: BaseVtable* base_vTable; 0x4: int var1; 0x8: int var2;}

DerivedVtable {0x0: BaseVtable base_vTable; 0x8: pointer virtual_func_3;};
//as far as i know all entries in a derived vTable must include or override all entries of the base vTable in the same order therefor this should work...

and:

Derived{0x0: Base baseClass; 0xc: int var3;}; //(Case 1)

or

Derived{0x0: DerivedVtable* derived_vTable; 0x4: int var1; 0x8: int var2; 0xc: int var3;}; //(Case 2)

In case 1 if i reverse engineer a member all derived classes will be updated because all derived classes have a copy of Base and all virtual functions from Base would match, but because 0x0 of Derived class is of type is Base.base_vTable it is of type BaseVtable and no new/overriden virtual functions of Derived class would be there.

In case 2 all virtual functions of derived class will be correct but var1/var2 which are actually from Base class wont be updated for all derived classes of Base and would have to be edited manually after RE the Base class...

Is there a way to use case 1 but interpret 0x0 of derived class (base class) as DerivedVtable*, but 0x4 (var1) /0x8 (var2) to be from Base class 0x4/0x8?

I could separate the actuall vTable from the variables but that would double the classes for all derived classes:

Base_member{0x0: int var1; 0x4: int var2;}

Base_Derived{0x0: DerivedVtable* derived_vTable; 0x4: Base_member base_member}
Derived{0x0: Base_Derived base; 0xc: int var3;}

Base_otherDerived{0x0: OhterDerivedVtable* otherDerived_vTable; 0x4: Base_member base_member}
OtherDerived{0x0: Base_otherDerived base; /*...*/}

Am i missing something?

0

There are 0 answers