[FR] Le hooking de function

Aujourd’hui j’ai voulu faire un petit thread sur le hooking.

Le hooking de fonction est le fait de rediriger l’exécution d’une fonction d’un exécutable vers du code qui n’est pas le sien.

Ceci peut être fait en deux étapes :

  • L’injection de notre code dans le process (en runtime)
  • La redirection de la fonction quand elle est appelée

Pour l’injection de notre code, je vais utiliser une technique appelée injection de DLL, c’est une technique très utilisée quand on doit injecter du code dans un exécutable en runtime, et le rendre plus ou moins caché (exemple cheat, malware).

L’injection du code dans le process peut se faire de plusieurs manières, dans mon exemple, je ne vais faire que des injections en runtime (depuis un exécutable externe, vers un exécutable lancé) mais il est possible de rendre le load continue lorsque l’exécutable ciblé se lance.

Le principe de l’injection est de faire en sorte que le process visé load un DLL (librairie) qui contient notre code.

Notre but est donc de faire exécuter la fonction LoadLibraryA au process pour que l’exécutable cible load notre librairie avec notre code.

Ensuite, nous redirigerons depuis le process cible, la fonction que nous voulons hook.

Note : L'ASLR est bien évidemment désactivé

L’injection de notre code dans le process

Notre but va être de faire exécuter la fonction LoadLibraryA a notre exécutable cible. Nous devons donc étudier comment la fonction doit être appelée (Documentation LoadLibraryA)

Cette fonction est donc appelée avec un argument qui est le chemin (path) de notre librairie a load.

Nous devons donc dans un premier temps, allouer et écrire le path de notre DLL dans le process cible pour créer l’argument de la fonction LoadLibraryA que nous allons appeler dans celui-ci.

Puis, nous allons créer un thread a l’adresse de la fonction LoadLibraryA dans le process cible avec l’adresse de notre path en argument pour exécuter LoadLibraryA avec notre argument.

Ce qui va donner l’exécution de la fonction LoadLibraryA("C:\\pasBien.dll") par le process cible

Cette fonction va ensuite load le DLL dans son process et va exécuter l’entrypoint du DLL

Nous allons d’abord prendre l’adresse de la fonction LoadLibraryA dans la library kernel32.dll (vu que chaque exécutable qui load kernel32.dll, load le même fichier, et que c’est une librairie Windows, l’imageBase est la même peut importe l’exécutable)

Ensuite nous devons obtenir le HANDLE du process où nous allons faire l’injection, dans mon exemple je vais récupérer le process id a partir du titre de la fenêtre.

Dès que nous avons le HANDLE du process et l’adresse de la fonction LoadLibraryA, nous pouvons donc appeler le load de la librairie, mais avant nous devons définir son argument qui est le chemin de notre DLL. Nous allons donc allouer de l’espace au process de la taille du chemin.

Une fois l’espace alloué, nous pouvons écrire le path a cet endroit

Et maintenant, nous allons call la fonction LoadLibraryA pour loader notre DLL, il suffit de créer un thread a l’adresse de LoadLibraryA et de donner l’adresse de notre path en argument.

Voici un DLL de test, le DLL a un entrypoint qui s’exécute en fonction du load de celui-ci, par exemple ici, si un process load notre DLL, le message “Injected” apparaîtra.

Voilà le résultat

Il existe beaucoup de techniques d’injection de DLL plus discrètes, un exemple avec l’hijack d’un thread de l’application cible pour faire exécuter un shellcode, qui va loader le DLL mappé manuellement dans le process.

Example : https://github.com/D4stiny/ThreadJect

La redirection des fonctions

Maintenant que notre DLL est dans le process cible nous allons écrire une instruction assembleur qui va faire un jump de la fonction que l’on veut hook vers notre fonction contenue dans le DLL

A chaque fois que le process va exécuter la fonction, c’est notre fonction qui va donc être exécutée

Note : si les instructions après le jmp ont changé, c’est parce que nous avons écrit une instruction de 5 bytes (le jmp) sur les instructions de la fonction. Vu que les deux premières instructions étaient push et mov (3 bytes en tout), elles ont été réécrites par notre jump. Et vu que pour continuer à écrire notre jmp il faut encore deux bytes. L’instruction d’après (sub qui fait 6 bytes) va être réécrite aussi, mais que sur 2 bytes. Donc cela va créer une instruction invalide.

On va donc commencer par créer un nouveau thread depuis le DLL

En premier nous avons a calculer l’adresse relative de notre fonction par rapport à la fonction que l’on va hook

Dans le code (hook étant notre fonction et functionAddress la fonction cible) :

Nous changeons encore une fois les attributs de la plage mémoire sur laquelle nous allons écrire le jump. Et nous les conservons pour pouvoir les restaurer plus tard.

Puis nous écrivons notre instruction jmp vers notre fonction (5 bytes) a l’adresse de la fonction à hook. L’instruction JMP rel32 est représentée comme ceci, 1 byte qui indique l’instruction avec le format 0xE9 = JMP rel32, et les 4 autres bytes vont être l’adresse relative (sur 32 bits) de notre fonction.

Enfin nous restaurons l’ancien attribut de place mémoire

Maintenant que la fonction qui va setup notre hook est terminée, nous pouvons écrire notre fonction qui va remplacer celle de l’exécutable.

Et nous n’avons plus qu’a trouver l’adresse de la fonction à hook avec du reverse engineering

Après quoi :

:)

NOTE : je n’ai pas pris compte des problemes liés au stack après le jump, vu que chaque fonction peut avoir une convention d’appel différente (du moins en x86), il faut en tenir compte dans votre hook.

Nous avons fait un hook manuel, mais évidement des implémentations beaucoup plus propres existent, notamment detour, easyHook, polyHook, MinHook pour les api, etc..

J’ai commit le code source de mon exemple ici : https://github.com/wherethef2ckisr0da/HookingDemo/

~r0da