Comment hook une fonction standarde avec LD_PRELOAD
Futex m'a parlé il y a peu d'un trick unix qui m'était inconnu jusqu'alors : poser un hook avec LD_PRELOAD. Pour faire simple, LD_PRELOAD permet de charger une lib avec celles standardes. Cette méthode peut être utile si vous voulez modifier le comportement d'un programme de manière simple mais efficace. Pour cela, il suffit de créer une fausse lib contenant votre fonction maison ayant le même nom que celle que vous voulez hook et renseigner le chemin d'accès vers celle-ci dans la variable d'environnement LD_PRELOAD.
La méthode est applicable seulement si le programme cible a été compiler pour pouvoir utiliser des lib partagées. C'est généralement le cas puisque les fonctions standardes de C comme printf, strcmp, etc. sont contenues dans ce type de lib. Donc si la cible les utilise alors vous pouvez appliquer ce trick. Pour en être certain il suffit d'utiliser le tool file et de regarder si c'est le cas.
$ file example example: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x24a0e0e2aa5e5603263aa9f6e89d839dc1eb4090, not stripped
Mis en pratique
Je pense que le meilleur moyen de bien saisir l'affaire est de l'appliquer. Comme exemple je propose le programme suivant :
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argv, char *argc[]) { if (argv < 2) { printf("need argument\n"); return 0; } else { if (!strcmp(argc[1], "password")) printf("good job!\n"); else printf("bad password!\n"); } return 0; }
Si on lance notre programme avec un argument quelconque, on obtient un joli bad password!.
$ ./example test bad password!
Création de la fake lib
Notre but ici est de modifier le comportement de strcmp et bypasser la comparaison. On écrit alors une autre fonction strcmp qui retournera toujours 0 et affichera aussi les deux paramètres.
#include <stdio.h> int strcmp(char *str1, char *str2) { printf("hook of strcmp\n"); printf("str1: %s\n", str1); printf("str2: %s\n", str2); return 0; }
On compile notre fake lib avec la commande suivante :
gcc -fPIC -shared fake_strcmp.c -o fake_strcmp.so
Il faut encore modifier la variable LD_PRELOAD pour la faire pointer vers notre lib fraichement compilée.
$ export LD_PRELOAD=./fake_strcmp.so
Relançons le programme d'exemple pour voir ce que ça donne :
$ ./example test hook of strcmp str1: test str2: password good job!
La comparaison faite par strcmp est bien bypassée. Le trick a été appliqué avec succès !