2012-05-08 201 views
0

我一直在編程最近的彎路和所有的它。我繞道了很多不同的功能; thiscall,stdcall,cdecl,虛函數等。但有一件事我沒有管理(這可能甚至不可能),那就是鉤住基類虛函數。例如;有一個Car類聲明一個虛函數(空)Drive。然後有3個其他車類繼承汽車並實施Drive虛擬功能和繞行

如果我勾住車內的(基類)Drive功能(使用一個簡單的「JMP」鉤)將它由Car後裔被觸發,當他們引發Drive,如果他們這樣做調用基函數?

爲了更徹底地解釋:

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

所以我不知道基方法獲取的是否叫或者是否能以某種方式被鉤住?請問功能exectution跳直接Lamborghini::Drive或是否以某種方式通過Car類,所以它的檢測,只要一個電話後裔Drive

編輯:如果基類函數是空的,它甚至可以掛鉤它,因爲它需要5個字節的空間?

+0

http://en.wikipedia.org/wiki/Virtual_method_table也是這可能幫助,因爲它你描述:http://code.google.com/p/ gmodmodules/source/browse/trunk/gm_slog/gm_slog/vfnhook.h?spec = svn74&r = 74 –

回答

5

沒有,基本方法沒有得到自動地調用。動態調度機制將檢測哪個覆蓋它需要調用,這將是被調用的函數。這通常通過虛擬表(vtable)來實現,該虛擬表存儲指向類的每個虛擬函數的最終覆蓋程序的指針。當使用動態分派時,編譯器通過該表格注入間接調用並跳轉到正確的函數。

注意,V表的呼叫轉發到前實際持有指針的thunk蹦牀可以潛在修改this(隱式的第一個參數)。使用這種方法的優點是,如果this不需要更新,編譯器可以直接跳轉到最終的覆蓋。無論如何,你可以利用這個功能的優勢和修改虛函數表指向你自己的代碼(即您可以更新每個虛函數表--one每類型 - 指針指到自己功能

+0

不錯:)完整答案! – besworland

+0

只是爲了避免任何誤解;這是可能的,我所需要做的就是修改虛擬表格?如果是這樣的話,我也想問(由於缺乏知識),vtable是否只包含4個字節的指針?或者還有什麼我現在應該(即它只是找到虛擬表和偏移量,然後取代指針指向我的'鉤')? –

+0

@ElliottDarfink是的,你只需要找到vtable並替換指針。也可能是4個字節,但可能不取決於您的計算機的體系結構。 –

0

如果我正確地得到了您的問題,將根據虛擬功能表調用蘭博基尼類中的Drive方法。如果你想調用一個基類的Drive方法,你必須寫一些類似Car::Drive;的東西。由於VTBL,基類需要一些空間。希望我沒有回答你的問題。

0

如果我理解正確的話,即使Lamborghini:Drive不直接調用基本函數,也要每次調用Lamborghini::Drive時都要調用Car::Drive

爲此,最簡單的方法是使用「內」功能,這將是虛擬的(和保護),而初始方法將非虛擬和將路由呼叫。 下面是一個例子:

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 } 
} 
+0

問題是,我正在使用預編譯的代碼,這就是爲什麼我使用彎路:) –