更改外部类的VTable

时间:2013-07-20 10:54:14

标签: c++ class vtable

经过一些谷歌搜索后,我发现了一种修改类的VTable的方法,但在我的情况下,我只有一个指向我的类的指针以及一个用于转换它的接口。我需要将其中一个函数(在DLL中;没有源代码)重定向到我的一个函数。问题是我不知道函数在哪个索引上,所以为了找到它我尝试扫描VTable以获取指向该函数的指针。

有没有办法做到这一点?

到目前为止,这是我的代码:

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);
}

1 个答案:

答案 0 :(得分:1)

所以,对于所有看到这个问题并且现在不知道该怎么做的人来说:

我正在使用ollydbg,但您可以使用任何其他调试器/转储器。

这样做的最佳方式是将代码放入dll中。确保执行你的函数,否则编译器不会编译它(至少对我来说)

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
}

现在执行代码直到MessageBox()并在调试器中打开该地址,或者如果编译器创建了导出函数,您只需转到YourDll.OverrideFunction

在下面找一行,就是这样(如果你的编译器检测到名字)

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

CALL DWORD PTR [YourDll._imp__MessageBoxA]

之后的下一个CALL应该是你的类函数,在我的情况下:

CALL DWORD PTR DS:[EAX+34]

您的偏移量为0x34,即52(记住始终要计算十六进制数)。要获得VTable中的索引,你必须除以4(指针大小),在我的情况下为13。

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;
}

现在每次MyObject调用MyFunction时,都会执行NewFunc