arm64动态链接库通过函数名获取函数偏移

来源:互联网 发布:用java从键盘输入 编辑:程序博客网 时间:2024/06/07 15:26

基本思路是分析elf文件,

首先遍历节区头部Elf32_Shdr查看sh_type属性值,得到属性值为SHT_DYNSYM的节区。

其次通过名字遍历节区结点,找到类型为STT_FUNC并且名字与其相同的结点。

代码如下:

static void * xmalloc(size_t size){void *p;p = malloc(size);if (!p) {LOGV("Out of memory");exit(1);}return p;}static struct symlist *get_syms(int fd, Elf64_Shdr *symh, Elf64_Shdr *strh){struct symlist *sl, *ret;int rv;ret = NULL;sl = (struct symlist *) xmalloc(sizeof(struct symlist));sl->str = NULL;sl->sym = NULL;/* sanity */if (symh->sh_size % sizeof(Elf64_Sym)) { LOGV("elf_error");goto out;}/* symbol table */sl->num = symh->sh_size / sizeof(Elf64_Sym);sl->sym = (Elf64_Sym *) xmalloc(symh->sh_size);rv = pread(fd, sl->sym, symh->sh_size, symh->sh_offset);if (0 > rv) {//perror("read");goto out;}if (rv != symh->sh_size) {LOGV("elf error");goto out;}/* string table */sl->str = (char *) xmalloc(strh->sh_size);rv = pread(fd, sl->str, strh->sh_size, strh->sh_offset);if (0 > rv) {//perror("read");goto out;}if (rv != strh->sh_size) {LOGV("elf error");goto out;}ret = sl;out:return ret;}static intdo_load(int fd, symtab_t symtab){int rv;size_t size;Elf64_Ehdr ehdr;Elf64_Shdr *shdr = NULL, *p;Elf64_Shdr *dynsymh, *dynstrh;Elf64_Shdr *symh, *strh;char *shstrtab = NULL;int i;int ret = -1;/* elf header */rv = read(fd, &ehdr, sizeof(ehdr));if (0 > rv) {//perror("read");goto out;}if (rv != sizeof(ehdr)) {LOGV("elf error");goto out;}if (strncmp(ELFMAG, ehdr.e_ident, SELFMAG)) { /* sanity */LOGV("not an elf");goto out;}if (sizeof(Elf64_Shdr) != ehdr.e_shentsize) { /* sanity */LOGV("elf error");goto out;}/* section header table */size = ehdr.e_shentsize * ehdr.e_shnum;shdr = (Elf64_Shdr *) xmalloc(size);rv = pread(fd, shdr, size, ehdr.e_shoff);if (0 > rv) {//perror("read");goto out;}if (rv != size) {LOGV("elf error");goto out;}/* section header string table */size = shdr[ehdr.e_shstrndx].sh_size;shstrtab = (char *) xmalloc(size);rv = pread(fd, shstrtab, size, shdr[ehdr.e_shstrndx].sh_offset);if (0 > rv) {//perror("read");goto out;}if (rv != size) {LOGV("elf error");goto out;}/* symbol table headers */symh = dynsymh = NULL;strh = dynstrh = NULL;for (i = 0, p = shdr; i < ehdr.e_shnum; i++, p++)if (SHT_SYMTAB == p->sh_type) {if (symh) {LOGV("too many symbol tables");goto out;}symh = p;} else if (SHT_DYNSYM == p->sh_type) {if (dynsymh) {LOGV("too many symbol tables");goto out;}dynsymh = p;} else if (SHT_STRTAB == p->sh_type   && !strncmp(shstrtab+p->sh_name, ".strtab", 7)) {if (strh) {LOGV("too many string tables");goto out;}strh = p;} else if (SHT_STRTAB == p->sh_type   && !strncmp(shstrtab+p->sh_name, ".dynstr", 7)) {if (dynstrh) {LOGV("too many string tables");goto out;}dynstrh = p;}/* sanity checks */if ((!dynsymh && dynstrh) || (dynsymh && !dynstrh)) {LOGV("bad dynamic symbol table");goto out;}if ((!symh && strh) || (symh && !strh)) {LOGV("bad symbol table");goto out;}if (!dynsymh && !symh) {LOGV("no symbol table");goto out;}/* symbol tables */if (dynsymh)symtab->dyn = get_syms(fd, dynsymh, dynstrh);if (symh)symtab->st = get_syms(fd, symh, strh);ret = 0;out:free(shstrtab);free(shdr);return ret;}static symtab_tload_symtab(char *filename){int fd;symtab_t symtab;symtab = (symtab_t) xmalloc(sizeof(*symtab));memset(symtab, 0, sizeof(*symtab));fd = open(filename, O_RDONLY);if (0 > fd) {//perror("open");return NULL;}if (0 > do_load(fd, symtab)) {LOGV("Error ELF parsing %s", filename);free(symtab);symtab = NULL;}close(fd);return symtab;}static intlookup2(struct symlist *sl, unsigned char type,char *name, unsigned long *val){Elf64_Sym *p;int len;int i;len = strlen(name);for (i = 0, p = sl->sym; i < sl->num; i++, p++) {//LOGV("name:%s lookup2name: %s %x", name, sl->str+p->st_name, p->st_value);if (!strcmp(sl->str+p->st_name, name)    && ELF64_ST_TYPE(p->st_info) == type) {//if (p->st_value != 0) {*val = p->st_value;return 0;//}}}return -1;}static intlookup_sym(symtab_t s, unsigned char type,   char *name, unsigned long *val){if (s->dyn && !lookup2(s->dyn, type, name, val))return 0;if (s->st && !lookup2(s->st, type, name, val))return 0;return -1;}static intlookup_func_sym(symtab_t s, char *name, unsigned long *val){return lookup_sym(s, STT_FUNC, name, val);}static intfind_name(char* libname, char* fucname, unsigned long *addr){symtab_t s;s = load_symtab(libname);if(!s){LOGV("can't read symbol table %s", libname);return -1;}if (0 > lookup_func_sym(s, fucname, addr)) {LOGV("cannot find %s", fucname);return -1;}return 0;}


最后调用find_name函数,传入库名和函数名,即可得到函数偏移


阅读全文
0 0