0

Say you need to hook/detour a function that is the __thiscall type on x86 Windows and in order to do that, you need to pass a void* to the shim function. Yes this is technically "horrible abuse" of C++, but this is function hooking, not an exercise in coding a portable application.

For example, say you need to hook a function such as this:

void __thiscall SomeClass::MemberFunction(int b) { this->somevar = b; }

Obviously it's well known that you can just create a __fastcall function that uses an extra arg to dispose of EDX, but that's a bit... lame.

So the question is: What trickery can you think of to be able to convert the type of a non-static C++ class member function to a void* variable?

Olipro
  • 3,489
  • 19
  • 25

2 Answers2

3

I have a couple of solutions already for this, so here we go:

the first is arguably the quickest:

__declspec(naked) __cdecl void* MemberFuncToPtr(...) {
    __asm {
        mov eax, [esp+4]
        retn
    }
}
void* ptr = MemberFuncToPtr(&MyClass::TheMemberFunction);

And an alternative that's asm-free but requires an unused argument:

void* MemberFuncToPtr(char i, ...) {
    va_list v;
    va_start(v,i);
    void* ret = va_arg(v, void*);
    va_end(v);
    return ret;
}
void* ptr = MemberFuncToPtr(0, &MyClass::TheMemberFunction);
Olipro
  • 3,489
  • 19
  • 25
0

Here's an additional way that does the same thing as the other examples - slicing off sizeof(void*) bytes from a memory location that holds the pseudo-structure representing the member pointer.

/// Func pointer to Void pointer.
/// Assumes first four bytes hold the address.
template<typename T> void* FTOV(T func)
{// truncates T to 4 bytes
    return( *(void**)&func );
}

This will work in simple cases, but will crash horribly in code with multiple inheritance, virtual functions and re-basing. There, even getting the address of your own function is a problem, since &obj::func could generate a helper stub, and calling it could involve automatic re-basing. In that case, the only way out is to do a manual __asm setup of the call, and to obtain your function's true address from your own debug symbols (a weird thing to do).

theultramage
  • 350
  • 1
  • 4
  • 11