2015-07-11 3 views
2

J'écris un petit programme qui retrace tous les appels système et syscall d'un fichier binaire (elf) en utilisant ptrace (singlestep, getregs, pick_text, comparaison d'opcodes, etc). Jusqu'à présent, j'ai réussi à tracer des appels système et des appels simples comme des fonctions définies par l'utilisateur.Printf Symbol Resolution

Mais je n'ai pas réussi à obtenir le nom du symbole printf à partir de l'adresse que je choisis grâce à ptrace.

Ma question est: Pour la fonction liée dynamique comme printf, strlen, etc, comment puis-je récupérer dans le fichier elf le nom du symbole de l'adresse?

Avec des appels simples, c'est un peu facile, je cours dans la section .strtab et quand une adresse correspond, je retourne la str correspondante.

Mais pour printf, le symbole est connu dans le fichier .strtab mais a l'adresse "0". Objdump -d réussi à lier un appel à printf avec son adresse.

Avez-vous une idée?

+0

La liaison dynamique est-elle impliquée? – fuz

+1

Dans la glibc, le symbole de 'printf' s'appelle en fait' __printf_chk' à cause du patch fortification. Lancez 'nm' sur un fichier objet qui appelle' printf' et vous verrez. Généralement, jetez un oeil à la libelf comme pour comment analyser les fichiers elf. Je vous recommande de ne pas les analyser manuellement. – fuz

+0

J'utilise déjà la libelf. Et en fait, si j'utilise nm, je peux voir le symbole "printf" mais pas son adresse et le symbole est marqué avec la lettre "U" pour "Undefined". C'est mon problème, j'utilise l'adresse de la fonction pour récupérer son nom. Mais si l'adresse n'est pas stockée dans l'elfe je ne peux pas récupérer le nom. Et oui, la libc est liée dynamiquement je suppose –

Répondre

2

Je pense que vous devrez peut-être lire un peu plus sur la liaison dynamique. Prenons le strlen comme symbole d'exemple car printf est un peu spécial (trucs de fortification).

Votre problème est (je pense) que vous voulez prendre l'adresse d'un symbole et le traduire dans une adresse. Vous essayez de le faire en analysant le fichier ELF du programme que vous déboguez. Cela fonctionne avec les symboles qui se trouvent dans votre programme, mais pas avec les symboles liés dynamiquement tels que strlen. Et vous voulez savoir comment résoudre cela.

La raison en est que l'adresse des symboles tels que strlen ne sont pas conservés dans votre programme ELF. Ils sont à la place des références non résolues qui sont résolues dynamiquement lorsque le programme charge. En effet, Linux moderne chargera (je crois) les bibliothèques dynamiques (qui contiennent un code indépendant de la position) dans un ordre aléatoire et à des adresses aléatoires, donc l'emplacement de ces symboles ne sera pas connu avant le chargement du programme.

Pour les bibliothèques que vous avez ouvertes avec dlopen() (à savoir où vous vous faites la charger dans le programme), vous pouvez récupérer l'adresse de ces symboles à l'aide dlsym(); ce n'est pas très bien s'ils sont liés au programme au moment de la compilation/liaison.

Sur gcc, pour résoudre la position des symboles en général, utilisez l'extension gcc dladdr(). De la page de manuel:

The function dladdr() takes a function pointer and tries to 
    resolve name and file where it is located. Information is 
    stored in the Dl_info structure: 

     typedef struct { 
      const char *dli_fname; /* Pathname of shared object that 
             contains address */ 
      void  *dli_fbase; /* Address at which shared object 
             is loaded */ 
      const char *dli_sname; /* Name of nearest symbol with address 
             lower than addr */ 
      void  *dli_saddr; /* Exact address of symbol named 
             in dli_sname */ 
     } Dl_info; 

    If no symbol matching addr could be found, then dli_sname and 
    dli_saddr are set to NULL. 

    dladdr() returns 0 on error, and nonzero on success. 

Je crois que cela fonctionnera pour vous.

Pour plus d'informations, je vous suggère de regarder la source à ltrace qui trace les appels bibliothèque, et comment backtrace_symbols (et here) fonctionne; Notez que cela ne sera pas fiable en particulier pour les symboles non globaux, et notez le commentaire concernant l'ajout de -r dynamic à la ligne de lien. Vous pouvez également regarder addr2line et ses source.