
在Linux上,
dlopen不返回加载ELF二进制文件的地址。而是返回
structlink_map具有
.l_addr成员的成员。因此,您需要以下内容:
struct link_map *lm = (struct link_map*) dlopen(0, RTLD_NOW);printf("%pn", 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 intcallback(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%zxn", base + first_load->p_vaddr, first_load->p_vaddr, info->dlpi_addr); return 1; } } } return 0;}intmain(int argc, char *argv[]){ dl_iterate_phdr(callback, NULL); exit(EXIT_SUCCESS);}这是在32位系统上应该看到的内容:
$ gcc -g t.c -ldl -m32 && ./a.outELF header is at 0x8048000, image linked at 0x8048000, relocation: 0x0$ gcc -g t.c -ldl -m32 -pie -fPIE && ./a.outELF header is at 0xf779a000, image linked at 0x0, relocation: 0xf779a000
(最后一个地址:
0xf779a000如果启用了地址随机化,则每次运行都会有所不同(应如此))。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)