3

After a some googling I found a way to modify the VTable of a Class, but in my case I just have a pointer to my class as well as an interface to cast it to. I need to redirect one of those functions (in a DLL; no source code) to one of my functions. Problem is I don't know on which index the function is on, so in order to find it I tried scanning the VTable for the pointer to that function.

Is there any way to do this?

Here is my code so far:

typedef DWORD (__thiscall *CW_FUNC)();

class ClassWriter
{
public:
    PVOID m_hObj;
    PVOID *__vfptr;
    PVOID m_old[256];
    void SetObj(PVOID hObj)
    {
        m_hObj = hObj;
        __vfptr = *(PVOID **)hObj;
    }
    void AddOverride(int offset, PVOID newfunc)
    {
        DWORD dwNull;
        m_old[offset] = __vfptr[offset];
        VirtualProtect(__vfptr + offset * 4, 4, PAGE_EXECUTE_READWRITE, &dwNull);
        __vfptr[offset] = newfunc;
    }
    int GetOffset(PVOID func)
    {
        for (int i = 0; __vfptr[i] != NULL; i++)
        {
            if (func == __vfptr[i]) return i;
        }
    }
    CW_FUNC GetFunc(int offset)
    {
        return (CW_FUNC)m_old[offset];
    }
};

void WINAPI ChangeFunc()
{
    ClassWriter cw;
    HMODULE hMod = GetModuleHandle("dll_to_change.dll");
    IMyInterface *myObj = (IMyInterface*)GetProcAddress(hMod, "GetMyClass")();
    cw.SetObj(myObj);
    int d = cw.GetOffset(myObj->MyFunction);
    cw.AddOverride(d, OverrideFunction);
}
Arjan
  • 22,808
  • 11
  • 61
  • 71
JINX
  • 43
  • 6
  • you don't have the source for that external class? – greatwolf Jul 20 '13 at 10:56
  • No, i just have an interface and the dll – JINX Jul 20 '13 at 10:57
  • 1
    Scanning for the function should work. Of course, it does assume that it is actually a virtual function [and where you care about, it is called as a virtual function, and not directly]. – Mats Petersson Jul 20 '13 at 10:58
  • Problem is i can't create a pointer to myObj->MyFunction – JINX Jul 20 '13 at 10:59
  • "can't" meaning what? – Mats Petersson Jul 20 '13 at 11:01
  • 'IMyInterface::MyFunction': function call missing argument list, use '&IMyInterface::MyFunction' to create a pointer to member – JINX Jul 20 '13 at 11:02
  • And you tried adding `&`? – Mats Petersson Jul 20 '13 at 11:05
  • Thanks Arjan! An yes when adding & it is also wrong, probably because it is an interface meaning that all functions are virtual – JINX Jul 20 '13 at 11:14
  • (Please edit additional information into the question as well, and see [How do comment `@replies` work?](http://meta.stackexchange.com/questions/43019/how-do-comment-replies-work/43020#43020) to alert @Mats -- which I now did for you. Success!) – Arjan Jul 20 '13 at 11:17
  • @JINX: Ah, yes. You'll need to reverse engineer a little further then - for example, write some code that calls the function and check what offset it fetches in the assembler code. The offset isn't likely to change.... – Mats Petersson Jul 20 '13 at 11:20
  • @Mats Fortunately my class is sort of static it is always at the same place, so finding the function with ollydbg should be possible. – JINX Jul 20 '13 at 11:30
  • @Mats different question: When i have a PVOID value and do +4 is it +4 bytes or +4 ints? – JINX Jul 20 '13 at 14:22
  • @JINX: Eh, technically, adding to a `void *` is not a correct thing to do... It may add 4, 0 or 16 or something else. See: http://stackoverflow.com/questions/6449935/increment-void-pointer-by-one-byte-by-two – Mats Petersson Jul 20 '13 at 18:51

1 Answers1

1

So for all that view this question and don't really know how to do it now:

I'm using ollydbg, but you can use any other debugger/dumper.

Best way of doing this is putting your code into a dll. Make sure to execute your function, else the compiler won't compile it (at least for me)

void OverrideFunction()
{
    HMODULE hMod = GetModuleHandle("mydll.dll"); // If not loaded yet use LoadLibrary()
    IMyInterface *myObj = (IMyInterface*)GetProcAddress(hMod, "GetMyObject")(); // Get the pointer to your object
    char buffer[64];
    sprintf_s(buffer, "0x%X", OverrideFunction); // Print position of current function into buffer
    MessageBox(0, buffer, "", 0);
    myObj->MyFunction(); // Put in your function
}

Now either execute your code until the MessageBox() and open that address in your debugger or if your compiler created an export function you can just go to YourDll.OverrideFunction

Look for a line below, that is something like this (if your compiler detects names)

CALL DWORD PTR DS:[<&USER32.MessageBoxA>]

or

CALL DWORD PTR [YourDll._imp__MessageBoxA]

the next CALL after that should be your class function, in my case:

CALL DWORD PTR DS:[EAX+34]

Your offset is 0x34 which would be 52 (remember always to calculate the hex numbers). To get the index in the VTable you have to divide by 4 (size of a pointer) which would be 13 in my case.

void __fastcall NewFunc(IMyInterface *myObj, int null, (additional params)) // fastcall stores the first 2 params int ECX and EDX, thiscall stores the this-object in ECX
{
//  Your code
}

void OverrideFunction()
{
    DWORD dwNull;
    HMODULE hMod = GetModuleHandle("mydll.dll"); // If not loaded yet use LoadLibrary()
    IMyInterface *myObj = (IMyInterface*)GetProcAddress(hMod, "GetMyObject")(); // Get the pointer to your object
    PVOID *vtable = *(PVOID**)myObj; // The first int in your object is a pointer to the vtable
//  OldFunc = vtable[13]; // You might want to call your old function again, so save the pointer
    VirtualProtect(&vtable[13], 4, PAGE_EXECUTE_READWRITE, &dwNull); // Always unprotect the memory
    vtable[13] = NewFunc;
}

Now everytime MyObject calls MyFunction, NewFunc will be executed instead

JINX
  • 43
  • 6