c++classvirtual-table

How to get the base class offset of an inherited struct without creating an instance


Consider this code:

struct A {
    int64 member;
    int32 member2;
    virtual void f();
};

struct B {
    int16 member3;

    virtual void b();
};

struct C : A, B {
    virtual void b() override;
};

I'm interested in finding the offset of B in C. Previously with other structs with no virtual inheritance and only one base class offsetof of the first member seemed to work. I have decompiled some code (in IDA) and the base classes are nicely highlighted (hex) here:

screenshot

In a function those exact baseclass offsets are used to cast void*'s to derived classes by adding the offset to the void* (by casting to a char*). The structs A, B and C are similar to the one in the compiled code, which include classes with virtual functions and multiple base classes.

My question is how did they do that, and how can I do that? I've tried something like i32 offset = (i64)((B*)((C*)NULL)); but no luck.


Solution

  • I tried the following, and it worked:

    (char*)(B*)(C*)0x100 - (char*)(C*)0x100
    

    It casts C* to B*; this is supposed to do the work. All the rest is support. I used an arbitrary number 0x100; it seems to work with all numbers except 0.

    Why it doesn't work for 0: it sees a null-pointer of type C*; to convert it to a null-pointer of type B*, it should still be null. A special case.

    Of course, this uses undefined behavior. It seems to work in Visual Studio in my short test program; no guarantee it will work anywhere else.