• [^] # Re: pour linux

    Posté par (site web personnel) . En réponse à la dépêche Sortie de Ultracopier 0.3 pour Noël. Évalué à 10.

    le concept est simple et peut en intéresser d'autres :

    La plus part des UNIX modernes et assimilés utilisent des librairies dynamiques qui sont liées au programme exécutable juste avant son lancement effectif.
    En général il s'agit des dépendances du programme (tout le bazard de /usr/lib).
    On peut forcer une nouvelle dépendance par le moyen de la variable d'environnement LD_PRELOAD qui contient le chemin complet vers une librairie a lier en plus.
    Le procédé et l'ordre de la phase de linkage font que les fonctions exportées explicitement de la librairie indiquée vont passer par dessus les existantes si elles ont la même signature (prototype C manglisé).
    On peut donc "remplacer" n'importe quelle fonction.
    Le hic est que pour ton cas, ce que tu remplace une fonction basse du système qui a un travail précis a faire et qu'il ne s'agit pas de corrompre. Si on se dit tiens, dans mon write je vais appeler le vrai write(2), bienvenu dans le monde merveilleux des boucles récursives infinies qui vont péter ta pile !
    Notre sauveur sera syscall(2) qui permet de raccrocher l'appel initial faisant parie du système, sans utiliser le même prototype.
    quelques numéros de syscall utiles :

    #define __NR_exit 1
    #define __NR_fork 2
    #define __NR_read 3
    #define __NR_write 4
    #define __NR_open 5
    #define __NR_close 6
    #define __NR_waitpid 7
    #define __NR_creat 8
    #define __NR_link 9
    #define __NR_unlink 10
    #define __NR_execve 11
    #define __NR_chdir 12
    #define __NR_time 13
    #define __NR_mknod 14
    #define __NR_chmod 15
    #define __NR_lchown 16
    
    

    Exemple :

    le programme de test : test.c

    int main()
    {
     write(1, "test\n", 5);
    }
    
    

    la librairie : lib.c
    #include <unistd.h>
    ssize_t write(int fd, const void *buf, size_t count)
    {
     syscall(4, 1, "INTERCEPTED : ", 14);
     return syscall(4, fd, buf, count);
    }
    
    

    dans le shell (bash ici)

    Le programme de base :

    [oktail@marelle oktail]# gcc test.c
    [oktail@marelle oktail]# ./a.out
    test

    Modifions le sans toucher au code ni même le recompiler lui :

    [oktail@marelle oktail]# gcc -shared -o write.so ./lib.c
    [oktail@marelle oktail]# export LD_PRELOAD=$PWD/write.so
    [oktail@marelle oktail]# echo $LD_PRELOAD
    /home/oktail/write.so
    [oktail@marelle oktail]# ./a.out
    INTERCEPTED : test
    ^^^^^^^^^^^^^^

    Tadaaa ...

    Reste a faire en sorte que ton appel modifié puisse informer ton produit qu'un write se passe. Si je puis te conseiller, fait en un daemon. Et pour choisir les fd interessants et leur état ... deja évite les 0, 1, et 2 mais audela de ca j'ai pas l'inspiration, encore trop de vapeurs de raclette pour réfléchir correctement ici.

    a noter que plutot que la variable LD_PRELOAD, tu peux passer par le fichier /etc/ld.so.preload

    autre remarque pour les devs de tout poils, si dans vos softs vous utilisez read (2) pour lire un passwd tapé par l'user, j'espère que vous profiterez des fêtes pour remédier a cette grosse faille !