Pregunta

I've been programming with detours lately and all that comes with it. I have detoured a lot of different functions; thiscall, stdcall, cdecl, virtual functions etc. But there is one thing I haven't managed (which might not even be possible), and that is to hook a base class virtual function. For example; there is a Car class which declares a virtual function (empty) Drive. Then there are 3 other car classes which inherits car and implements Drive.

If I hook the Car's (base class) Drive function (using a simple 'jmp' hook) would it be triggered by the descendants of Car, when they trigger Drive, if they do not call the base function?

To explain even more thoroughly:

class Car
{
   virtual void Drive(void) { } // Empty virtual function
}

class Lamborghini : public Car
{
   void Drive(void) { // does lots of stuff, but does NOT call base function }
}

So I'm wondering whether the base method get's called or if it can be hooked somehow? Does the function exectution jump directly to Lamborghini::Drive or does it somehow pass through the Car class so it's detectable whenever a descendant calls Drive?

EDIT: And if the base class function is empty, is it even possible to hook it, since it requires 5 bytes of space?

¿Fue útil?

Solución

No, the base method does not get automagically called. The dynamic dispatch mechanism will detect which override it needs to call and that will be the function that gets called. This is usually implemented by means of a virtual table (vtable) that stores the pointers to the final overriders for each virtual function in a class. When dynamic dispatch is used, the compiler injects an indirect call through that table and jumps to the proper function.

Note that the vtable actually holds pointers to thunks or trampolines that can potentially modify this (implicit first argument) before forwarding the call. The advantage of using this approach is that if this does not need to be updated, the compiler can jump directly into the final overrider. At any rate, you can take advantage of this feature and modify the vtables to point to your own code (i.e. you can update the pointer in each vtable --one per type-- to refer to your own thunk or function)

Otros consejos

If I got your question correctly, method Drive in your Lamborghini class will be called based on table of virtual functions. If you want to call a Drive method of a base class, you must write something like Car::Drive;. And base class needs some space because of the VTBL. Hope I've unanswered on your question.

If I understand it right, you want Car::Drive to be called each time Lamborghini::Drive is called, even if Lamborghini:Drive does not call directly the base function ?

For that, the simplest method is to use an 'inner' function, which will be virtual (and protected), whereas the initial method will be non-virtual and will route the call. Here's an example:

class Car
{
    void Drive(void)
    {
        // ...
        Car::innerDrive(); // Base function call
        // ...
        this->innerDrive(); // 'Derived' function call
        // ...
    }
protected:
    virtual void innerDrive(void) { } // Empty virtual function
}

class Lamborghini : public Car
{
protected:
    void innerDrive(void) { // does lots of stuff, but does NOT call base function }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top