0

I have an assignment for university which requires me to access the vtable of a class. I need to write a function (here called pb) which takes a pointer to an object as an argument as well as an integer, and then just prints the output of the methods of the class. I have managed to access the first function, but I don't know how to access the second function. Here's the code I have so far:

typedef int(*firstFun)();
typedef int(*secondFun)(int);

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

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

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

In conclusion, how to get bSecond to work for second(int) like bFirst works for first()?

F. Kukec
  • 15
  • 7

1 Answers1

1

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;
}
GuidedHacking
  • 3,628
  • 1
  • 9
  • 59
  • I tried those but it didn't work. I'm getting an exception: Exception thrown at 0x00000000 in L1Z5_ooup.exe: 0xC0000005: Access violation executing location 0x00000000 when i add 0x8. When i add 0x4, I'm getting a read access violation. – F. Kukec Apr 02 '20 at 16:21
  • @F.Kukec that's because they aren't cdecl functions, they're __thiscall functions, you have to define them as _thiscall and pass the thisptr as the first argument – GuidedHacking Apr 02 '20 at 17:50
  • I like to think of the vtable as a struct, not an array. You never iterate through the vtable. – curiousguy Apr 02 '20 at 20:56