2013-10-18 7 views
8

Ich versuche, die geladene Adresse eines ELF-Binaries zu bekommen, but dlopen doesn't wie erwartet:Erhalten geladen Adresse eines ELF-Binaries, dlopen funktioniert nicht wie erwartet

void *elf = (char *)dlopen (0, RTLD_NOW); 
printf ("%p\n", elf); 
sleep (100); 

Er druckt 0xb772d918, aber von dem, was /proc/1510/maps sagt, es zeigt nicht auf die geladene Adresse des dlfn binär, aber die ld-2.15.so,

08048000-08049000 r-xp 00000000 fc:00 1379  /root/dlfn 
08049000-0804a000 r--p 00000000 fc:00 1379  /root/dlfn 
0804a000-0804b000 rw-p 00001000 fc:00 1379  /root/dlfn 
b7550000-b7552000 rw-p 00000000 00:00 0 
b7552000-b76f5000 r-xp 00000000 fc:00 9275  /lib/i386-linux-gnu/libc-2.15.so 
b76f5000-b76f7000 r--p 001a3000 fc:00 9275  /lib/i386-linux-gnu/libc-2.15.so 
b76f7000-b76f8000 rw-p 001a5000 fc:00 9275  /lib/i386-linux-gnu/libc-2.15.so 
b76f8000-b76fb000 rw-p 00000000 00:00 0 
b76fb000-b76fe000 r-xp 00000000 fc:00 9305  /lib/i386-linux-gnu/libdl-2.15.so 
b76fe000-b76ff000 r--p 00002000 fc:00 9305  /lib/i386-linux-gnu/libdl-2.15.so 
b76ff000-b7700000 rw-p 00003000 fc:00 9305  /lib/i386-linux-gnu/libdl-2.15.so 
b7708000-b770b000 rw-p 00000000 00:00 0 
b770b000-b770c000 r-xp 00000000 00:00 0   [vdso] 
b770c000-b772c000 r-xp 00000000 fc:00 9299  /lib/i386-linux-gnu/ld-2.15.so 
b772c000-b772d000 r--p 0001f000 fc:00 9299  /lib/i386-linux-gnu/ld-2.15.so 
b772d000-b772e000 rw-p 00020000 fc:00 9299  /lib/i386-linux-gnu/ld-2.15.so 
bfc34000-bfc55000 rw-p 00000000 00:00 0   [stack] 

Also, anders als /proc/pid/maps Parsen, ist es eine Möglichkeit, die geladene Adresse eines ELF-Binaries abzurufen? (0x0848000 in diesem Fall)

Antwort

11

Unter Linux gibt dlopen nicht die Adresse zurück, wo die ELF-Binärdatei geladen wurde. Es gibt stattdessen struct link_map zurück, das .l_addr Mitglied hat. So sollten Sie so etwas wie:

struct link_map *lm = (struct link_map*) dlopen(0, RTLD_NOW); 
printf("%p\n", lm->l_addr); 

jedoch trotz allem, was Kommentar in /usr/include/link.h sagt, .l_addr ist eigentlich keine Last-Adresse entweder. Stattdessen ist es die Differenz zwischen wo und ELF-Bild wurde geladen zu laden, und wo es tatsächlich geladen wurde.

Für Nicht-PIE-Hauptdatei ausführbar, ist diese Differenz immer 0. Bei nicht vorgemerkener gemeinsam genutzter Bibliothek ist diese Differenz immer die Ladeadresse (weil nicht vorgelagerte gemeinsam genutzte ELF-Bibliotheken zum Laden unter Adresse 0 verknüpft sind).

Wie finden Sie die Basisadresse der Hauptdatei? Die einfachste Methode ist, diesen Code zu verwenden (in ausführbarem Haupt verknüpft):

#ifndef _GNU_SOURCE 
#define _GNU_SOURCE 
#endif 

#include <link.h> 
#include <stdio.h> 
#include <stdlib.h> 

static int 
callback(struct dl_phdr_info *info, size_t size, void *data) 
{ 
    int j; 
    for (j = 0; j < info->dlpi_phnum; j++) { 
    if (info->dlpi_phdr[j].p_type == PT_LOAD) { 
     const char *beg = (const char*) info->dlpi_addr + info->dlpi_phdr[j].p_vaddr; 
     const char *end = beg + info->dlpi_phdr[j].p_memsz; 
     const char *cb = (const char *)&callback; 
     if (beg < cb && cb < end) { 
     // Found PT_LOAD that "covers" callback(). 
     printf("ELF header is at %p, image linked at 0x%zx, relocation: 0x%zx\n", 
       beg, info->dlpi_phdr[j].p_vaddr, info->dlpi_addr); 
     return 1; 
     } 
     return 0; 
    } 
    } 
    return 0; 
} 

int 
main(int argc, char *argv[]) 
{ 
    dl_iterate_phdr(callback, NULL); 
    exit(EXIT_SUCCESS); 
} 

Hier ist, was Sie auf einem 32-Bit-System sehen sollen:

$ gcc -g t.c -ldl -m32 && ./a.out 
ELF header is at 0x8048000, image linked at 0x8048000, relocation: 0x0 
$ gcc -g t.c -ldl -m32 -pie -fPIE && ./a.out 
ELF header is at 0xf779a000, image linked at 0x0, relocation: 0xf779a000 

(Die letzte Adresse: 0xf779a000 variieren von run to run, wenn Sie die Adressrandomisierung aktiviert haben (wie Sie sollten)).

+0

Interessant ... das wurde nicht einmal in 'dlopen (3)' erwähnt. Vielen Dank! – daisy

+1

Sehr nützlich. Wenn Sie dies unter Android tun möchten, ist dl_iterate_phdr ab der Plattformversion 21 verfügbar. – sheltond