2010-08-06 7 views
3

Je suis en train d'effectuer un reverse engineering d'un exécutable Windows. J'ai trouvé une classe que je veux utiliser à partir d'un code que j'injecte dans l'exécutable (thread différent, propre pile). Comment procéder pour déclarer une telle classe, des adresses de méthodes données et une structure de variables membres?Utilisation de classes non documentées en C++

Par exemple, disons que je trouve une classe appelée foo, avec son constructeur @ 0x4012D30 et une fonction doTheMario @ 40125D4. Je sais aussi qu'il contient trois DWORD de données privées. Étant donné que les deux méthodes sont _thiscalls, je déclare une classe comme si dans mon code:

class GuessedFoo { 
    private: 
     int bar; 
     char *cafebabe; 
     float deadbeef; 
    public: 
     GuessedFoo(int a, int b); 
     void doTheMario(); 
}; 

Maintenant, c'est une classe parfaitement dandy, mais est maintenant il un moyen de faire le compilateur/éditeur de liens lier les méthodes de classe à les deux adresses précédentes que j'ai indiquées? Bien sûr, je peux écrire un wrapper asm pour convertir un stdcall en thiscall pour chaque méthode que j'ai besoin d'utiliser, puis utiliser structs au lieu de classes, mais il doit y avoir un meilleur moyen.

J'utilise gcc/g ++ pour le moment, mais je peux passer à VC++ (depuis l'assembleur en ligne de gcc me donne des maux de tête de toute façon).

+0

Vous pouvez utiliser la syntaxe intel dans GCC avec '-masm = intel' et' .intel_syntax noprefix', si la mémoire est là ... –

+0

Oui, mais même la syntaxe GAS ressemblant à un puke n'est rien par rapport à la façon dont vous devez tripoter autour lors de la liaison des variables de pile et des arguments du code C/C++ avec l'assemblage en ligne. Avec le bloc '__asm ​​{}' de VC++, tout cela est tellement plus facile. – Serge

Répondre

4

Si la classe n'a pas vtable, vous pouvez, en principe, créer une telle classe dans votre propre code, où tous les appels de fonction les implémentations réelles invoquent appropriées. Vous pouvez le faire en tordant les fonctions membres comme naked functions contenant une instruction de saut d'assemblage à l'implémentation réelle.

Si la classe a un vtable, les choses risquent d'être beaucoup plus complexes; vous aurez probablement besoin de créer explicitement le vtable comme une structure de pointeurs de fonction, et de faire appel à vos stubs de fonction. Cela signifie des fonctions de compensation plus complexes; une simple fonction nue avec un saut peut ne pas suffire, et il peut être préférable d'aller avec une vraie fonction. Rappelez-vous, cependant, que les fonctions membres sur win32 utilisent un different calling convention; Cela signifie qu'un appel de fonction membre ordinaire ne fonctionnera pas. Vous pouvez être en mesure d'échapper à la construction de pointeurs-à-fonctions-membres, mais gardez à l'esprit qu'ils ont un rather strange structure à eux, et vous aurez besoin de faire correspondre avec quelque chose qui a la même représentation que les pointeurs vtable. Bonne chance!

+0

Les fonctions nues feront l'affaire, la plupart des classes du code original ne sont pas héritées, donc il n'y a pas de fonctions virtuelles, donc il n'y a pas de vtables. Merci beaucoup! – Serge

0

Je ne suis pas tout à fait sûr que je vous comprends bien, mais de toute façon: Je pense que la voie la plus facile à des méthodes « main-localisation » est en utilisant la fonction pointeurs.

+0

Oui, mais ils sont thiscalls. Je n'ai pas envie de convertir chacun d'entre eux en stdcall avec un wrapper asm (en sautant le premier argument et en le déplaçant vers ecx, en appelant la fonction). Je préférerais faire GuessedFoo f = new GuessedFoo (42, 18); au lieu de GuessedFoo_GuessedFoo ((void *) data, 42, 18); – Serge

0

C++ ne définit aucun type d'interface binaire, ce qui rend pratiquement impossible l'implémentation de tout type de liaison dynamique pour les classes C++. Le meilleur que vous pouvez faire est de déclarer deux structs - l'un contenant c typedefs de fonction pour chaque méthode, l'autre reflète la disposition des données de classe. Bien sûr, parce que __thiscall sur une méthode de classe passe 'this' via le registre ecs, je ne crois pas que vous puissiez réellement faire une déclaration de fonction c explicite qui aura le même effet, donc vous devrez peut-être effectuer tous les appelle via un "CallThisCallMethodWithParameters" personnalisé que vous avez écrit dans assembly.

+1

Les interfaces binaires de C++ sont définies - tout comme C ou tout autre langage, elles varient selon la plate-forme et sont définies dans la documentation de la plateforme. On peut certainement implémenter une liaison dynamique pour C++, c'est juste un peu complexe quand on doit gérer les types de templates dans les paramètres et etc, donc il y a peu (voire pas) de systèmes de liaison dynamiques complets qui ne puntent le dur labeur C++ compilateur à la fin. – bdonlan

1

Vous faites de l'ingénierie inverse ici, par conséquent (presque, probablement) forcé de descendre plus bas quand il s'agit d'interagir avec le code existant. J'appellerais cette fonction un code d'assemblage pur.
Si l'adresse de base du fichier EXE est corrigée, c'est encore plus simple.
code Exemple:

void main() 
{ 
    int bar = 5; 
    int * cafebabe = &bar; 
    __asm 
    { 
     push [bar]; 
     push [cafebabe]; 
     mov eax, 123456; // address of the function 
     call eax; 
    } 
} 

vérifier simplement comment cette fonction est appelée par le code d'origine pour voir l'ordre dans lequel vous devez pousser des arguments. N'oubliez pas que certains arguments peuvent devoir passer par des registres!

+1

Oui, "this" est passé par ecx lors de l'appel d'une méthode d'objet. Je sais que je peux écrire l'assemblage et C pour créer un environnement amusant et amusant pour utiliser le code original, mais cela devient fastidieux quand il y a quelques douzaines de classes avec chacune une douzaine de méthodes. Merci quand même! – Serge

Questions connexes