2009-10-09 8 views
11

Ich würde gerne wissen, wie man die Adresse von Test, die in der virtuellen Tabelle ist mit der von HackedVTable ändern.Wie hackt man die virtuelle Tabelle?

void HackedVtable() 
{ 
    cout << "Hacked V-Table" << endl; 
} 

class Base 
{  
public: 
    virtual Test() { cout <<"base"; } 
    virtual Test1() { cout << "Test 1"; } 
    void *prt; 
    Base(){} 
}; 

class Derived : public Base 
{ 
public: 
    Test() 
    { 
     cout <<"derived"; 
    } 
}; 

int main() 
{  
    Base b1; 

    b1.Test(); // how to change this so that `HackedVtable` should be called instead of `Test`? 

    return 0; 
} 

Antwort wird sehr geschätzt.

Vielen Dank im Voraus.

+5

Es ist mir egal, warum Sie das tun möchten. Es ist eine schlechte Idee. Tu es nicht. – abelenky

+5

@abelenky, dies ist nur für die Erziehungszwecke nur. Ich wollte wissen, wie die Dinge funktionieren. :) – mahesh

+0

@ Martins Kommentar ist der beste Rat, den Sie für Bildungszwecke bekommen können. Ansonsten - gib einfach auf, der Compiler ist besser für diesen Job. – LiraNuna

Antwort

15

Dies funktioniert für 32-Bit-MSVC-Builds (es ist eine sehr vereinfachte Version eines Produktionscodes, der seit über einem Jahr verwendet wird). Beachten Sie, dass Ihre Ersetzungsmethode explizit den Parameter this (Zeiger) angeben muss.

// you can get the VTable location either by dereferencing the 
// first pointer in the object or by analyzing the compiled binary. 
unsigned long VTableLocation = 0U; 
// then you have to figure out which slot the function is in. this is easy 
// since they're in the same order as they are declared in the class definition. 
// just make sure to update the index if 1) the function declarations are 
// re-ordered and/or 2) virtual methods are added/removed from any base type. 
unsigned VTableOffset = 0U; 
typedef void (__thiscall Base::*FunctionType)(const Base*); 
FunctionType* vtable = reinterpret_cast<FunctionType*>(VTableLocation); 

bool hooked = false; 
HANDLE process = ::GetCurrentProcess(); 
DWORD protection = PAGE_READWRITE; 
DWORD oldProtection; 
if (::VirtualProtectEx(process, &vtable[VTableOffset], sizeof(int), protection, &oldProtection)) 
{ 
    vtable[VTableOffset] = static_cast<FunctionType>(&ReplacementMethod); 

    if (::VirtualProtectEx(process, &vtable[VTableOffset], sizeof(int), oldProtection, &oldProtection)) 
     hooked = true; 
} 
+0

Vielen Dank. :) – mahesh

+1

NP. Ich musste es verwenden, um eine fehlerhafte Parameterüberprüfung zu korrigieren, die auf meiner Maschinenkonfiguration in einer Anwendung von Drittanbietern auftauchte, die jedes Mal einen Absturz verursachte, wenn ich versuchte, das Programm zu verwenden. –

8

Die V-Tabelle ist ein Implementierungsdetail.

Der Compiler ist nicht erforderlich, um einen zu verwenden (es ist einfach der einfachste Weg, um virtuelle Funktionen zu implementieren). Aber sagen, dass jeder Compiler es leicht anders implementieren kann (und tut), als Ergebnis gibt es keine Antwort auf Ihre Frage.

Wenn Sie fragen, wie kann ich eine VTable für ein Programm zu hacken gebaut mit:

Compiler < X> Version < Y> Build < Z>

Dann kann jemand die Antwort kennen.

+3

Gut gesagt. Darüber hinaus erzeugen selbst Compiler, die eine V-Tabelle verwenden, manchmal Code mit statischer Verknüpfung, wenn die Semantik des Programms dies zulässt. – mjv

2

Ich glaube nicht, dass es einen tragbaren Weg gibt. Meistens wegen der Compiler-Optimierung und der unterschiedlichen Architektur-ABI zwischen jedem Ziel.

Aber C++ bietet Ihnen genau die gleiche Fähigkeit, warum nicht verwenden?

void HackedVtable() 
{ 
    cout << "Hacked V-Table" << endl; 
} 

class Base 
{ 
public: 
     virtual Test() { cout <<"base"; } 
     virtual Test1() { cout << "Test 1"; } 
     void *prt; 
     Base(){} 
}; 

class Derived : public Base 
{ 
    public: 
      Test() 
      { 
       HackedVtable(); // <-- NOTE 
      } 
}; 

int main() 
{ 
    Derived b1; // <-- NOTE 

    b1.Test(); 

    return 0; 
} 
+0

Ich wollte wissen, um die Adresse in vtable – mahesh

+2

ändern Sie wollen es nicht wissen. Selbst für Bildungszwecke ist die Theorie in diesem Fall * gut *. Der Compiler kennt viel mehr als Sie über Ihr Programm, als Sie vielleicht denken, also ist es eine schlechte Idee, mit einer Tabelle zu experimentieren, die möglicherweise existiert oder nicht existiert (in diesem Fall niemals, da sie nicht verwendet wird) Du bist ein schlechter Programmierer, indem du zu viel segfaulst. Nicht. – LiraNuna

0

gut ist es ziemlich einfach herauszufinden. Finde den VTAble-Zeiger (Im Visual Studio sind es die ersten 4/8 Bytes). Dann treten Sie in einen normalen Aufruf von Test (in den Assembler) und Sie werden sehen, dass es zur VTable und dann zu Ihrer Testfunktion springt. Um den Test zu überschreiben, ersetzen Sie einfach den Zeiger, von dem Sie in VTable gesprungen sind.

+0

Sie meinen, dass MSVC offensichtliche Überschreibungen nicht optimiert (wenn nicht verwendet, zum Beispiel)? – LiraNuna

7
void HackedVtable() 
{ 
    cout << "Hacked V-Table" << endl; 
} 

class Base 
{ 

public: 
     virtual Test() { cout <<"base"; } 
     virtual Test1() { cout << "Test 1"; } 
     void *prt; 
     Base(){} 
}; 

class Derived:public Base 
{ 
    public: 
      Test() 
      { 
        cout <<"derived"; 
      } 
}; 

typedef void (*FUNPTR)(); 
typedef struct 
{ 
    FUNPTR funptr; 
} VTable; 


int main() 
{ 

    Base b1; 
    Base *b1ptr = &b; 

    VTable vtable; 
    vtable.funptr = HackedVtable; 

    VTable *vptr = &vtable; 
    memcpy (&b1, &vptr, sizeof(long)); 

    b1ptr->Test(); 

    //b1.Test(); // how to change this so that HackedVtable() should be called instead of Test() 

    return 0; 
} 
+0

@Ganesh, Vielen Dank..einfach und elegant. :) – mahesh

+1

@mahesh, das ist * komplett * andere resultierende Funktionalität als meine. Hier ersetzt es die Funktionen für eine einzelne Instanz (b1). In meinem ersetzt es die Funktionen für * alle * Instanzen eines bestimmten Typs. –

1

Ein anderer Weg, um die gleiche Sache zu erreichen, ist durch cheking ähnlichen Code:

GObject:

http://en.wikipedia.org/wiki/Gobject

GLib:

http://en.wikipedia.org/wiki/GLib

Vala:

http://en.wikipedia.org/wiki/Vala_%28programming_language%29

Die Jungs wollten mit einem Objekt und Klasse orientierte Programmiersprache arbeiten, aber „C++“, haben ihre Requisiten nicht passen. Dann nahmen sie "einfaches C" und simulierten Objekte mit Records & Zeigern, einschließlich Virtual Method Tables. Schließlich bekam eine ähnliche Sprache namens "Vala", ihre eigene "C++" ähnliche Sprache (mit ihrer eigenen V.M.T.).

Weitere Links zum Thema:

http://en.wikipedia.org/wiki/Virtual_method_table

http://www.artima.com/insidejvm/ed2/jvmP.html

Beifall.

1

Unter Mac OS X 10.10.3 + gcc 4.8.3 funktioniert der folgende Code gut.

void HackedVtable() 
{ 
    cout << "Hacked V-Table" << endl; 
} 

class Base 
{  
public: 
    virtual void Test() { cout << "base" << endl; } 
    virtual void Test1() { cout << "Test 1" << endl; } 
    void *prt; 
    Base(){} 
}; 

class Derived : public Base 
{ 
public: 
    void Test() 
    { 
     cout << "derived" << endl; 
    } 
}; 

int main() 
{  
    Base b1; 
    Base* pb1 = &b1; 

    *(*(void***)pb1) = (void*) HackedVtable; 
    pb1->Test(); 

    //It works for all the Base instance 
    Base b2; 
    Base* pb2 = &b2; 
    pb2->Test(); 

    //But Derived's virtual function table is separated from Base's 
    Derived d1; 
    Derived* pd1 = &d1; 
    pd1->Test(); 
    *(*(void***)pd1) = (void*) HackedVtable; 
    pd1->Test(); 

    return 0; 
} 

Sein Ausgang:

$ g++ h.cpp; ./a.out 
Hacked V-Table 
Hacked V-Table 
derived 
Hacked V-Table 

teste ich den gleichen Code unter Ubuntu 12.04 + g ++ 4.9.0. Es funktioniert jedoch nicht und es tritt ein Segmentierungsfehler auf. Es scheint, dass Linux die virtuelle Funktionstabelle in einem schreibgeschützten Bereich (z. B. rodata) zuweist, um Hacking zu verbieten.

-1

Ich glaube nicht, dass die vTable im schreibgeschützten Bereich ist, weil es dynamisch bevölkert ist. Der einzige Weg, wie es scheitern kann, ist, wenn der Compiler absolut sicher ist, welche Implementierung zur Kompilierungszeit aufgerufen wird und die vTable-Suche mit direktem Funktionsaufruf (De-Virtualisierung) überspringt.

+0

Es tut uns leid, aber kann noch keine Kommentare posten. Fühlen Sie sich frei, diesen Beitrag zu löschen, wenn es nicht nützlich ist ... –

0

Dies wird normalerweise "virtuelle Tabelle Hooking" oder so ähnlich genannt. Wenn Sie es viel verwenden, dann schlage ich die SourceHook Bibliothek vor. Es wurde entwickelt, um Closed Source Game Engines in Game Mods zu hacken. Zum Beispiel wurde es in The Dark Mod verwendet, bevor idTech4 Open Source wurde.

Verwandte Themen