9
votes

Modifier la commande de charge de la bibliothèque au moment de l'exécution (comme ld_preload mais pendant l'exécution)

Comment puis-je modifier la bibliothèque une charge de fonction à partir de l'heure d'exécution?

Par exemple, disons que je veux remplacer la fonction Standard Printf CODE> Fonction avec quelque chose de nouveau, je peux écrire ma propre version et Compilez-le dans une bibliothèque partagée, puis mettez "ld_preload = / My / Library.so" dans l'environnement avant d'exécuter mon exécutable. P>

Mais disons cela à la place, je veux changer ce lien de l'intérieur du programme lui-même. Sûrement cela doit être possible ... Droite? P>

Modifier strong>
Et non, ce qui suit ne fonctionne pas (mais si vous pouvez me dire comment le faire fonctionner, ce serait suffisant). P>

void* mylib = dlopen("/path/to/library.so",RTLD_NOW);
printf = dlsym(mylib,"printf");


0 commentaires

6 Réponses :


-1
votes

Il y a une variable d'environnement LD_Library_Path où la liaison recherche des bibliothèques déchiquetées, prépendez votre chemin d'accès à LD_Library_Path, j'espère que cela fonctionnerait


0 commentaires

4
votes

afaik, ce n'est pas possible. La règle générale est que si le même symbole apparaît dans deux bibliothèques, LD.SO favorisera la bibliothèque chargée en premier. Ld_preload fonctionne en veillant à ce que les bibliothèques spécifiées soient chargées avant toute bibliothèque implicitement chargée.

Donc, une fois l'exécution a commencé, toutes les bibliothèques implicitement chargées auront été chargées et il est donc trop tard pour charger votre bibliothèque avant leur.


0 commentaires

0
votes

Vous ne pouvez pas changer cela. En général * NIX, le concept de liaison (ou un manque de concept) est cueilli du premier objet où il se trouve. (Sauf pour Oddball Aix qui fonctionne plus comme OS / 2 par défaut.)

Programmatiquement Vous pouvez toujours essayer dlsym (rtld_default) et dlsym (rtld_next) . homme dlsym pour plus. Bien qu'il soit hors de main assez rapidement. Pourquoi est rarement utilisé?


3 commentaires

Pouvez-vous expliquer ce que vous voulez dire avec dlsym () ? Voir mon édition à la question initiale pour plus d'informations.


Vous ne pouvez pas printf = dlsym (myLib, "printf"); évidemment, vous devriez être capable, avec une variable globale int (* myprintf) (Const Char * FMT, ... ) = dlsym (myLib, "printf") , puis #define printf myprintf dans les unités de compilation dont vous avez besoin. J'ai pensé que printf était plus un exemple dans votre cas. Si printf est spécifiquement votre cible (et la substitution à l'heure de liaison est également une option), vous pouvez également essayer de dire à la liaison de ne pas relier les bibliothèques standard, mettre votre bibliothèque avec personnalisé printf () d'abord dans le Liste de bibliothèque - Avant de spécifier manuellement des bibliothèques standard dans lesquelles Orig Printf () est situé.


BTW, LD_PRELOAD est un moyen d'ajouter une bibliothèque avant Bibliothèques standard. Cela le fait juste pendant la période d'exécution. Pendant le temps de liaison, il s'agit de l'ordre des bibliothèques que vous donnez à la liaison définit la priorité des symboles: les symboles seraient levés de la première libère. Habituellement, des bibliothèques standard sont d'abord placées dans la liste de liaison (en fronge comme cc). Mais vous pouvez l'éteindre (-Nostdlib) et les spécifier manuellement dans l'ordre de votre choix, par exemple. En mettant votre libmy.so d'abord avant toute autre chose. Ensuite, printf () de libmy.so remplace le printf de libc.



1
votes

Il convient de dire que tenter de remplacer les fonctions de la libc de votre application a un comportement non défini conformément à la norme ISO C / POSIX, que vous le fassiez statistiquement ou dynamiquement. Cela peut fonctionner (et travaillera en grande partie sur GNU / Linux), mais il est imprudent de compter sur elle de travailler. Si vous voulez simplement utiliser le nom "Printf", mais faites-la faire quelque chose de non standard dans votre programme, le meilleur moyen de le faire est de #undef printf et #define printf my_printf Après inclure des en-têtes de système. De cette façon, vous n'interférez aucune utilisation interne de la fonction par des bibliothèques que vous utilisez ... et votre implémentation de My_PRINTF peut même appeler le système Printf si / quand il doit.

D'autre part, si votre objectif est d'interférer avec quelles bibliothèques font, dans une partie de la ligne, vous allez probablement rencontrer des problèmes de compatibilité. Une meilleure approche serait probablement déterminé pourquoi la bibliothèque ne ferait probablement pas ce que vous voulez sans redéfinir les fonctions qu'il utilise, la corrigez et soumettez des correctifs en amont si elles sont appropriées.


0 commentaires

-2
votes

Stockez le DLSYM () Résultat dans une table de recherche (tableau, table de hachage, etc.). Ensuite, #undef Imprimer et #define Imprimer Pour utiliser la version de votre table de recherche.


1 commentaires

Cela fonctionne juste bien. C'est comment Qt utilise OpenSSL, ainsi que du code de mien qui a une liaison de temps d'exécution au lieu de compilée / temps de charge.



2
votes

Il n'y a pas de solution propre mais c'est possible. Je vois deux options:

  1. remplaçant la fonction Printf Prolog avec sauter à votre fonction de remplacement. P>

    C'est une solution assez populaire pour l'accrochage de fonction dans MS Windows. Vous pouvez trouver des exemples d'accrochage de fonction par réécriture de code dans Google. P> LI>

  2. Réécrire des tables de relocalisation / de liaison elfe. P>

    voir Cet article sur CodeProject qui fait presque exactement ce que vous demandent mais seulement dans une portée des modules Dlopen () 'ED. Dans votre cas, vous souhaitez également modifier votre module principal (typiquement non-PIC). Je n'ai pas essayé, mais peut-être que c'est aussi simple que d'appeler le code fourni avec: p>

    void* handle = dlopen(NULL, RTLD_LAZY);
    void* original;
    original = elf_hook(argv[0], LIBRARY_ADDRESS_BY_HANDLE(handle), printf, my_printf);
    


0 commentaires