Get downloaded ELF binary address, dlopen not working properly

I am trying to get the downloaded ELF binary address, but dlopen does not work as expected:

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

It prints 0xb772d918 , but from what /proc/1510/maps says, it does not point to the loaded address of the dlfn binary, but 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] 

So, besides parsing /proc/pid/maps , is there a way to get the downloaded address of the ELF binary? (0x0848000 in this case)

+9
c linux dlopen
source share
1 answer

On Linux, dlopen does not return the address where the ELF binary was downloaded. struct link_map this it returns a struct link_map that has the member .l_addr . So you want something like:

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

However, despite what the comment says in /usr/include/link.h , .l_addr is not really a download address either. Instead, this is the difference between where the ELF image was associated with the download and where it was actually downloaded.

For the main executable without PIE, this difference is always 0. For a shared library without a link, this difference is always the download address (since shared ELF libraries without a link are associated with loading at address 0).

So how do you find the base address of the main executable? The easiest way is to use this code (associated with the main executable):

 #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; const char *cb = (const char *)&callback; const char *base = (const char *)info->dlpi_addr; const ElfW(Phdr) *first_load = NULL; for (j = 0; j < info->dlpi_phnum; j++) { const ElfW(Phdr) *phdr = &info->dlpi_phdr[j]; if (phdr->p_type == PT_LOAD) { const char *beg = base + phdr->p_vaddr; const char *end = beg + phdr->p_memsz; if (first_load == NULL) first_load = phdr; 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", base + first_load->p_vaddr, first_load->p_vaddr, info->dlpi_addr); return 1; } } } return 0; } int main(int argc, char *argv[]) { dl_iterate_phdr(callback, NULL); exit(EXIT_SUCCESS); } 

Here is what you should see on a 32-bit system:

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

(Last address: 0xf779a000 will change from start to start if you have address randomization enabled (as it should be)).

+14
source share

All Articles