Comment pirater la table virtuelle?

Je voudrais savoir comment changer l’adresse de Test qui est dans la table virtuelle avec celle de HackedVTable .

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

La réponse sera grandement appréciée.

Merci d’avance.

Cela fonctionne pour les versions MSVC 32 bits (c’est une version très simplifiée de certains codes de production utilisés depuis plus d’un an). Notez que votre méthode de remplacement doit spécifier explicitement le paramètre this (pointeur).

 // you can get the VTable location either by dereferencing the // first pointer in the object or by analyzing the comstackd 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(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(&ReplacementMethod); if ( ::VirtualProtectEx( process, &vtable[VTableOffset], sizeof(int), oldProtection, &oldProtection ) ) hooked = true; } 

La V-Table est un détail d’implémentation.

Le compilateur n’est pas obligé d’en utiliser un (c’est la méthode la plus simple pour implémenter des fonctions virtuelles). Mais en disant que chaque compilateur peut (et fait) l’implémenter légèrement différemment, il n’ya pas de réponse à votre question.

Si vous demandez comment puis-je pirater un vtable pour un programme construit avec:

Compilateur Version Construire

Alors quelqu’un peut connaître la réponse.

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

Je ne pense pas qu’il existe un moyen portable. Principalement en raison de l’optimisation du compilateur et de l’architecture différente ABI entre chaque cible.

Mais C ++ vous offre exactement la même capacité, pourquoi ne pas l’utiliser?

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

Une autre façon de réaliser la même chose est de vérifier un code similaire:

GObject:

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

Facile:

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

Vala:

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

Ces gars-là voulaient travailler avec un langage de programmation orienté object et classe, mais “C ++” ne correspondait pas à leurs besoins. Ensuite, ils ont pris “plain C” et simulé des objects avec des enregistrements et des pointeurs, y compris des tables de méthodes virtuelles. Finalement, ils ont eu un langage similaire appelé “Vala”, leur propre langage similaire “C ++” (avec leur propre VMT).

Un autre lien connexe:

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

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

À votre santé.

Sous Mac OS X 10.10.3 + gcc 4.8.3, le code suivant fonctionne bien.

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

Sa sortie:

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

Je teste le même code sous Ubuntu 12.04 + g ++ 4.9.0. Cependant, cela ne fonctionne pas et pose un problème de segmentation. Il semble que Linux assigne la table des fonctions virtuelles dans une zone de lecture seule (par exemple, une rodata) pour interdire le piratage.

Eh bien, il est assez facile à comprendre. Trouver le pointeur VTAble (Dans Visual Studio, ce sont les premiers 4/8 octets). Puis entrez dans un appel normal de Test (dans l’assembleur) et vous le verrez sauter à Vtable, puis à votre fonction de test. Pour remplacer le test, remplacez simplement le pointeur d’où vous avez sauté dans la VTable.

Cela s’appelle généralement “accrochage de table virtuelle” ou quelque chose comme ça. Si vous comptez l’utiliser beaucoup, je suggère la bibliothèque SourceHook . Il a été développé pour le piratage des moteurs de jeux à sources fermées dans les mods du jeu. Par exemple, il était utilisé dans The Dark Mod avant qu’idTech4 ne devienne une source ouverte.

Je ne pense pas que la vTable soit en lecture seule car elle est remplie de manière dynamic. Cela ne peut échouer que lorsque le compilateur sait avec certitude quelle implémentation sera appelée lors de la compilation et ignore la recherche de la vTable avec un appel direct à une fonction (dé-virtualisation).