subhook icon indicating copy to clipboard operation
subhook copied to clipboard

Question: Supports class methods?

Open brjoha opened this issue 6 years ago • 6 comments

The README example illustrated hooks for global functions. Do hooks work for instanced class methods (virtual and non-virtual), and method overloads?

brjoha avatar Jun 02 '19 17:06 brjoha

It would probably work if you somehow obtain a pointer to the member function that you wish to hook and declare your function with __thiscall or something similar, but I haven't tried that to be honest.

Zeex avatar Jun 02 '19 21:06 Zeex

Short: Yes.

Long: I had to recast the member function pointer, because my gcc refuses converting it directly to a void * (I casted it to a normal function pointer first).

It gets a little bit tricky if the function is a virtual one, because than the member function pointer is an index of the function in the vtable (at least in my gcc version). So you have to get the correct function pointer out of the vtable.

You also have some work to do, if the function is private, and you want to set the hook from outside. (Google for "C++ how to access of private members")

If you have everything up and running, you get the this pointer as first function argument. Of course you can only use the public members/methods, because you are outside in your C-function.

badbyte7 avatar Apr 21 '20 11:04 badbyte7

Short: Yes.

Long: I had to recast the member function pointer, because my gcc refuses converting it directly to a void * (I casted it to a normal function pointer first).

Hey there,

Can you go into more detail on how you typecasted a class function to a void* poiner? That is usually considered an invalid conversion or UB, vast majority of compilers straight-up error it out, so I'm curious if there's a "correct" way of accomplishing it.

SvarunSoda avatar Apr 07 '24 05:04 SvarunSoda

#include <stdint.h>
#include <iostream>

using namespace std;

class C
{
public:
    void foo(int bar)
    {
        cout << reinterpret_cast<uintptr_t>(this) << " -> " << bar << endl;
    }
};

typedef void (C::*cvifptr_t)(int);
typedef void (*vifptr_t)(int, int);

int main(int argc, char **argv)
{
    C c;
    cvifptr_t zup = &C::foo;
    cout << zup << endl;
    vifptr_t baz = reinterpret_cast<vifptr_t>(zup);
    cout << baz << endl;
    (c.*zup)(123);
    (*baz)(1234, 321);
    return 0;
}

attilabody avatar Apr 08 '24 13:04 attilabody

#include <stdint.h>
#include <iostream>

using namespace std;

class C
{
public:
    void foo(int bar)
    {
        cout << reinterpret_cast<uintptr_t>(this) << " -> " << bar << endl;
    }
};

typedef void (C::*cvifptr_t)(int);
typedef void (*vifptr_t)(int, int);

int main(int argc, char **argv)
{
    C c;
    cvifptr_t zup = &C::foo;
    cout << zup << endl;
    vifptr_t baz = reinterpret_cast<vifptr_t>(zup);
    cout << baz << endl;
    (c.*zup)(123);
    (*baz)(1234, 321);
    return 0;
}

Thanks for your reply; however the line vifptr_t baz = reinterpret_cast<vifptr_t>(zup); fails to compile with both VS and cl.exe with error C2440: 'reinterpret_cast': cannot convert from 'cvifptr_t' to 'vifptr_t' note: There is no context in which this conversion is possible.

I see that you're converting the class function pointer zup to a standalone function pointer baz, and the calling it with 2 arguments. Is this supposed to represent the behaviour of the __thiscall convention, where the first argument is the this pointer to the class?

SvarunSoda avatar Apr 08 '24 18:04 SvarunSoda

Thanks for your reply; however the line vifptr_t baz = reinterpret_cast<vifptr_t>(zup); fails to compile with both VS and cl.exe with error C2440: 'reinterpret_cast': cannot convert from 'cvifptr_t' to 'vifptr_t' note: There is no context in which this conversion is possible.

I'm sorry to hear that, it compiles with a warning (which can be suppressed with -Wno-pmf-conversions) using GCC 13.2 on Linux (I recommend experimenting with different compilers on godbolt.org)

I see that you're converting the class function pointer zup to a standalone function pointer baz, and the calling it with 2 arguments. Is this supposed to represent the behaviour of the __thiscall convention, where the first argument is the this pointer to the class?

Exactly.

https://godbolt.org/z/qMqTWGn14

attilabody avatar Apr 09 '24 07:04 attilabody