0

I was reversing some C++ code and encountered following function.

sub_106C0A0 proc near

var_10= dword ptr -10h
var_C= dword ptr -0Ch
var_4= dword ptr -4

push    0FFFFFFFFh
push    offset SEH_106C0A0
mov     eax, large fs:0
push    eax
mov     large fs:0, esp
push    ecx
push    esi
mov     esi, ecx
push    edi
lea     edi, [esi+4]
push    30h
mov     ecx, edi
mov     [esp+1Ch+var_10], esi
mov     dword ptr [esi], offset off_12C0680
call    struc_13_ctor
mov     dword ptr [edi], offset off_12C057C ; another vtable init ?

This function passes this pointer of some object (struc_13), which is esi+4, to the struc_13_ctor. Inside the struc_13_ctor function, it initializes the vtable pointer and other member variables.

; int __thiscall struc_13_ctor(struc_13 *this, __int16 a2)
struc_13_ctor proc near

arg_0= word ptr  4

mov     dx, [esp+arg_0]
mov     eax, ecx
xor     ecx, ecx
mov     dword ptr [eax], offset struc_13_vtable
mov     [eax+4], ecx
mov     [eax+8], ecx
mov     [eax+0Ch], dx
mov     [eax+0Eh], cx
mov     [eax+14h], ecx
mov     [eax+10h], ecx
retn    4
struc_13_ctor endp

However after returning from struc_13_ctor, it overwrites the vtable pointer with the new value, which is off_12C057C in this case.

call    struc_13_ctor
mov     dword ptr [edi], offset off_12C057C ; another vtable init ?

I have seen this kind of behaviors a lot while looking at ctor functions, but never understood why this happens.

  • Seems like assembly code, that you've pasted, does everything ok. What is exactly overwritten(edi?), when return value is in eax? If I remember correctly, return value may use in any future instruction and, as soon as you pasted only one instruction after function return, I can not say exactly what is happening then. – see ya Jul 14 '14 at 11:02
  • my question is that although ctor func initializes the vtable ptr of the struc_13, after returning vtable ptr of the struc_13 is re-initialized to a different value. edi points to the vtable ptr inside the struc_13 in the caller func – Jaewon Min Jul 14 '14 at 16:11
  • @seeya: The value of edi in the main function gets moved to ecx, then moved to eax in the struc_13_ctor function. So the mov dword ptr [eax], offset struc_13_vtable in the called function and the mov dword ptr [edi], offset off_12C057C access the same memory address. The OP's question was, why does the outer function overwrite the vtable? – Guntram Blohm supports Monica Jul 14 '14 at 17:45
0

I think the c++ code would look something like this:

// has vtbl struc_13_vtable
// has constructor struc_13_ctor
struct struc_13 {
    int  a,b;
    short c,d;
    int e,f;

    struc_13(short x)
       : a(0), b(0), c(x), d(0), e(0), f(0)
    { }

    virtual void someotherfn();
};

// has vtbl off_12C057C
// has inlined constructor
struct derivedmember : struc_13 {
    derivedmember() : struc_13(0x30)
    { }
    virtual void someotherfn();
};

// has vtbl off_12C0680
// has constructor sub_106C0A0
struct A {
    derivedmember  member;
    virtual void somefn();
};
1

The class of which sub_106C0A0 is a member function contains another class as a member. Assuming ecx is the class pointer, then it's ecx+4, not ecx, that gets passed to the inner constructor. So the inner class pointer is behind the vtable pointer of the outer class, which suggests something like:

class a {
    int i1, i2;
    short s1, s2;
    int i3, i4;

    a::a(int x) {
        i1=0; i2=0;
        s1=x;
        s2=0; i3=0; i4=0;
    } 
}

class b : public a {
    // whatever;
}

class outer {
    class b someelement;
    // more variables;

    outer::outer() {
        someelement=(b) new a(48);
    }
}

I'd assume the sub_106C0A0 function allocates a class instance, then casts that to another class. The cast to the other class makes the compiler replace a's vtable with b's vtable. However, i'm not 100% sure how that makes sense - if b is a real superclass of a, then casting a to b isn't safe, because the additional members aren't there; if b is a subclass of a, then there's no reason to replace the vtable when casting.

Looking at the size and entries of the vtables might help - maybe the programmer used some weird method of abstract classes and implementation classes, where the class members of one class are the abstract classes (b), but what gets instantiated by new() are the implementations (a). (That still wouldn't be a good reason to replace the implementation vtable with the abstract class vtable, however).

  • sub_106C0A0 does not allocate, it constructs. – Willem Hengeveld Jul 14 '14 at 18:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.