0

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?

Elliott Darfink
  • 1,153
  • 14
  • 34
  • http://en.wikipedia.org/wiki/Virtual_method_table and also this might help since it does what you're describing: http://code.google.com/p/gmodmodules/source/browse/trunk/gm_slog/gm_slog/vfnhook.h?spec=svn74&r=74 – Seth Carnegie May 08 '12 at 12:29

3 Answers3

5

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)

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Just to avoid any misunderstandings; it is possible, and all I need to do is to modify the virtual table? And if that is the case, I also want to ask (because of lack of knowledge), does the vtable only consist of 4-byte pointers? Or is there anything else I should now (i.e is it only to find the vtable and the offset, then replace that pointer to point at my 'hook')? – Elliott Darfink May 08 '12 at 12:49
  • @ElliottDarfink yep, you only need to find the vtable and replace the pointer. Also it might be 4 bytes, but might not depending on your computer's architecture. – Seth Carnegie May 08 '12 at 13:24
  • 1
    @ElliottDarfink also make sure you realise that you should replace it with a _member function_ so the function doesn't think it can use the ecx register and lose the `this` pointer. – Seth Carnegie May 08 '12 at 13:27
  • The virtual table is compiler-defined. Modifying it is a really bad idea: code bloat, and not portable even accross different versions of the same compiler... – Synxis May 08 '12 at 13:27
  • @Synxis Lucky for me I only care about GCC and Linux 32bit :) – Elliott Darfink May 08 '12 at 13:54
  • One other thing. Detours rewrites the beginning of the target function address (saving the original instructions that it replaces in a location called the trampoline) which jumps to your detoured code. When you call that function from within the detoured code, it will execute the saved instructions and then jumps back to the original code. This is why it doesn't matter how big the size of the `jmp` call is. – Adrian Jun 01 '17 at 18:32
0

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.

besworland
  • 747
  • 2
  • 7
  • 17
0

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 }
}
0xAli
  • 1,059
  • 10
  • 22
Synxis
  • 9,236
  • 2
  • 42
  • 64