获取一个ELF二进制文件的加载地址,dlopen不能正常工作

我试图得到一个ELF二进制文件的加载地址, 但是dlopen不能按预期工作:

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

它打印0xb772d918 ,但是从/proc/1510/maps可以0xb772d918 ,它并不指向dlfn二进制文件的加载地址,而是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] 

所以,除了parsing/proc/pid/maps ,是否有一种方法可以检索ELF二进制文件的加载地址? (在这种情况下是0x0848000)

Solutions Collecting From Web of "获取一个ELF二进制文件的加载地址,dlopen不能正常工作"

在Linux上, dlopen不会返回加载ELF二进制文件的地址。 它返回struct link_map ,它具有.l_addr成员。 所以你需要像这样的东西:

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

然而,尽管/usr/include/link.h有什么评论, .l_addr实际上也不是一个加载地址。 相反,这是ELF图像与加载链接的位置和实际加载的位置之间的区别

对于非PIE主要可执行文件,该差别总是0.对于非预先链接的共享库,该差异始终是加载地址(因为非预先链接的ELF共享库链接到地址0加载)。

那么如何找到主要可执行文件的基地址呢? 最简单的方法是使用这个代码(链接到主要的可执行文件):

 #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); } 

以下是您应该在32位系统上看到的内容:

 $ 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 

(最后一个地址: 0xf779a000如果您启用了地址随机化(如您应该那样),则从运行到运行会有所不同)。