代码
直接晒代码
- external.h
/*
* external.h
*
* Created on: 2016年12月7日
* Author: lyz
*/
#ifndef BASE_ELF_READER_EXTERNAL_H_
#define BASE_ELF_READER_EXTERNAL_H_
/* ELF support for BFD.
Copyright 1991, 1992, 1993, 1995, 1997, 1998, 1999, 2001, 2003, 2005,
2008 Free Software Foundation, Inc.
Written by Fred Fish @ Cygnus Support, from information published
in "UNIX System V Release 4, Programmers Guide: ANSI C and
Programming Support Tools".
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
/* This file is part of ELF support for BFD, and contains the portions
that describe how ELF is represented externally by the BFD library.
I.E. it describes the in-file representation of ELF. It requires
the elf/common.h file which contains the portions that are common to
both the internal and external representations. */
/* The 64-bit stuff is kind of random. Perhaps someone will publish a
spec someday. */
/* Special section indices, which may show up in st_shndx fields, among
other places. */
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */
#define SHN_HIPROC 0xFF1F /* End range of appl-specific */
#define SHN_LOOS 0xFF20 /* OS specific semantics, lo */
#define SHN_HIOS 0xFF3F /* OS specific semantics, hi */
#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */
#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */
#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */
/* ELF Header (32-bit implementations) */
typedef struct {
unsigned char e_ident[16]; /* ELF "magic number" */
unsigned char e_type[2]; /* Identifies object file type */
unsigned char e_machine[2]; /* Specifies required architecture */
unsigned char e_version[4]; /* Identifies object file version */
unsigned char e_entry[4]; /* Entry point virtual address */
unsigned char e_phoff[4]; /* Program header table file offset */
unsigned char e_shoff[4]; /* Section header table file offset */
unsigned char e_flags[4]; /* Processor-specific flags */
unsigned char e_ehsize[2]; /* ELF header size in bytes */
unsigned char e_phentsize[2]; /* Program header table entry size */
unsigned char e_phnum[2]; /* Program header table entry count */
unsigned char e_shentsize[2]; /* Section header table entry size */
unsigned char e_shnum[2]; /* Section header table entry count */
unsigned char e_shstrndx[2]; /* Section header string table index */
} Elf32_External_Ehdr;
typedef struct {
unsigned char e_ident[16]; /* ELF "magic number" */
unsigned char e_type[2]; /* Identifies object file type */
unsigned char e_machine[2]; /* Specifies required architecture */
unsigned char e_version[4]; /* Identifies object file version */
unsigned char e_entry[8]; /* Entry point virtual address */
unsigned char e_phoff[8]; /* Program header table file offset */
unsigned char e_shoff[8]; /* Section header table file offset */
unsigned char e_flags[4]; /* Processor-specific flags */
unsigned char e_ehsize[2]; /* ELF header size in bytes */
unsigned char e_phentsize[2]; /* Program header table entry size */
unsigned char e_phnum[2]; /* Program header table entry count */
unsigned char e_shentsize[2]; /* Section header table entry size */
unsigned char e_shnum[2]; /* Section header table entry count */
unsigned char e_shstrndx[2]; /* Section header string table index */
} Elf64_External_Ehdr;
/* Program header */
typedef struct {
unsigned char p_type[4]; /* Identifies program segment type */
unsigned char p_offset[4]; /* Segment file offset */
unsigned char p_vaddr[4]; /* Segment virtual address */
unsigned char p_paddr[4]; /* Segment physical address */
unsigned char p_filesz[4]; /* Segment size in file */
unsigned char p_memsz[4]; /* Segment size in memory */
unsigned char p_flags[4]; /* Segment flags */
unsigned char p_align[4]; /* Segment alignment, file & memory */
} Elf32_External_Phdr;
typedef struct {
unsigned char p_type[4]; /* Identifies program segment type */
unsigned char p_flags[4]; /* Segment flags */
unsigned char p_offset[8]; /* Segment file offset */
unsigned char p_vaddr[8]; /* Segment virtual address */
unsigned char p_paddr[8]; /* Segment physical address */
unsigned char p_filesz[8]; /* Segment size in file */
unsigned char p_memsz[8]; /* Segment size in memory */
unsigned char p_align[8]; /* Segment alignment, file & memory */
} Elf64_External_Phdr;
/* Section header */
typedef struct {
unsigned char sh_name[4]; /* Section name, index in string tbl */
unsigned char sh_type[4]; /* Type of section */
unsigned char sh_flags[4]; /* Miscellaneous section attributes */
unsigned char sh_addr[4]; /* Section virtual addr at execution */
unsigned char sh_offset[4]; /* Section file offset */
unsigned char sh_size[4]; /* Size of section in bytes */
unsigned char sh_link[4]; /* Index of another section */
unsigned char sh_info[4]; /* Additional section information */
unsigned char sh_addralign[4]; /* Section alignment */
unsigned char sh_entsize[4]; /* Entry size if section holds table */
} Elf32_External_Shdr;
typedef struct {
unsigned char sh_name[4]; /* Section name, index in string tbl */
unsigned char sh_type[4]; /* Type of section */
unsigned char sh_flags[8]; /* Miscellaneous section attributes */
unsigned char sh_addr[8]; /* Section virtual addr at execution */
unsigned char sh_offset[8]; /* Section file offset */
unsigned char sh_size[8]; /* Size of section in bytes */
unsigned char sh_link[4]; /* Index of another section */
unsigned char sh_info[4]; /* Additional section information */
unsigned char sh_addralign[8]; /* Section alignment */
unsigned char sh_entsize[8]; /* Entry size if section holds table */
} Elf64_External_Shdr;
/* Symbol table entry */
typedef struct {
unsigned char st_name[4]; /* Symbol name, index in string tbl */
unsigned char st_value[4]; /* Value of the symbol */
unsigned char st_size[4]; /* Associated symbol size */
unsigned char st_info[1]; /* Type and binding attributes */
unsigned char st_other[1]; /* No defined meaning, 0 */
unsigned char st_shndx[2]; /* Associated section index */
} Elf32_External_Sym;
typedef struct {
unsigned char st_name[4]; /* Symbol name, index in string tbl */
unsigned char st_info[1]; /* Type and binding attributes */
unsigned char st_other[1]; /* No defined meaning, 0 */
unsigned char st_shndx[2]; /* Associated section index */
unsigned char st_value[8]; /* Value of the symbol */
unsigned char st_size[8]; /* Associated symbol size */
} Elf64_External_Sym;
typedef struct {
unsigned char est_shndx[4]; /* Section index */
} Elf_External_Sym_Shndx;
/* Note segments */
typedef struct {
unsigned char namesz[4]; /* Size of entry's owner string */
unsigned char descsz[4]; /* Size of the note descriptor */
unsigned char type[4]; /* Interpretation of the descriptor */
char name[1]; /* Start of the name+desc data */
} Elf_External_Note;
/* Relocation Entries */
typedef struct {
unsigned char r_offset[4]; /* Location at which to apply the action */
unsigned char r_info[4]; /* index and type of relocation */
} Elf32_External_Rel;
typedef struct {
unsigned char r_offset[4]; /* Location at which to apply the action */
unsigned char r_info[4]; /* index and type of relocation */
unsigned char r_addend[4]; /* Constant addend used to compute value */
} Elf32_External_Rela;
typedef struct {
unsigned char r_offset[8]; /* Location at which to apply the action */
unsigned char r_info[8]; /* index and type of relocation */
} Elf64_External_Rel;
typedef struct {
unsigned char r_offset[8]; /* Location at which to apply the action */
unsigned char r_info[8]; /* index and type of relocation */
unsigned char r_addend[8]; /* Constant addend used to compute value */
} Elf64_External_Rela;
/* dynamic section structure */
typedef struct {
unsigned char d_tag[4]; /* entry tag value */
union {
unsigned char d_val[4];
unsigned char d_ptr[4];
} d_un;
} Elf32_External_Dyn;
typedef struct {
unsigned char d_tag[8]; /* entry tag value */
union {
unsigned char d_val[8];
unsigned char d_ptr[8];
} d_un;
} Elf64_External_Dyn;
/* The version structures are currently size independent. They are
named without a 32 or 64. If that ever changes, these structures
will need to be renamed. */
/* This structure appears in a SHT_GNU_verdef section. */
typedef struct {
unsigned char vd_version[2];
unsigned char vd_flags[2];
unsigned char vd_ndx[2];
unsigned char vd_cnt[2];
unsigned char vd_hash[4];
unsigned char vd_aux[4];
unsigned char vd_next[4];
} Elf_External_Verdef;
/* This structure appears in a SHT_GNU_verdef section. */
typedef struct {
unsigned char vda_name[4];
unsigned char vda_next[4];
} Elf_External_Verdaux;
/* This structure appears in a SHT_GNU_verneed section. */
typedef struct {
unsigned char vn_version[2];
unsigned char vn_cnt[2];
unsigned char vn_file[4];
unsigned char vn_aux[4];
unsigned char vn_next[4];
} Elf_External_Verneed;
/* This structure appears in a SHT_GNU_verneed section. */
typedef struct {
unsigned char vna_hash[4];
unsigned char vna_flags[2];
unsigned char vna_other[2];
unsigned char vna_name[4];
unsigned char vna_next[4];
} Elf_External_Vernaux;
/* Structure for syminfo section. */
typedef struct
{
unsigned char si_boundto[2];
unsigned char si_flags[2];
} Elf_External_Syminfo;
/* This structure appears on the stack and in NT_AUXV core file notes. */
typedef struct
{
unsigned char a_type[4];
unsigned char a_val[4];
} Elf32_External_Auxv;
typedef struct
{
unsigned char a_type[8];
unsigned char a_val[8];
} Elf64_External_Auxv;
/* Size of SHT_GROUP section entry. */
#define GRP_ENTRY_SIZE 4
#define EI_NIDENT 16 /* Size of e_ident[] */
typedef unsigned long bfd_vma;
typedef unsigned long bfd_size_type;
typedef unsigned long file_ptr;
typedef struct elf_internal_ehdr {
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
unsigned long e_phoff; /* Program header table file offset */
unsigned long e_shoff; /* Section header table file offset */
unsigned long e_version; /* Identifies object file version */
unsigned long e_flags; /* Processor-specific flags */
unsigned short e_type; /* Identifies object file type */
unsigned short e_machine; /* Specifies required architecture */
unsigned int e_ehsize; /* ELF header size in bytes */
unsigned int e_phentsize; /* Program header table entry size */
unsigned int e_phnum; /* Program header table entry count */
unsigned int e_shentsize; /* Section header table entry size */
unsigned int e_shnum; /* Section header table entry count */
unsigned int e_shstrndx; /* Section header string table index */
} Elf_Internal_Ehdr;
typedef struct elf_internal_shdr {
unsigned int sh_name; /* Section name, index in string tbl */
unsigned int sh_type; /* Type of section */
bfd_vma sh_flags; /* Miscellaneous section attributes */
bfd_vma sh_addr; /* Section virtual addr at execution */
file_ptr sh_offset; /* Section file offset */
bfd_size_type sh_size; /* Size of section in bytes */
unsigned int sh_link; /* Index of another section */
unsigned int sh_info; /* Additional section information */
bfd_vma sh_addralign; /* Section alignment */
bfd_size_type sh_entsize; /* Entry size if section holds table */
/* The internal rep also has some cached info associated with it. */
unsigned char *contents; /* Section contents. */
} Elf_Internal_Shdr;
struct elf_internal_phdr {
unsigned long p_type; /* Identifies program segment type */
unsigned long p_flags; /* Segment flags */
bfd_vma p_offset; /* Segment file offset */
bfd_vma p_vaddr; /* Segment virtual address */
bfd_vma p_paddr; /* Segment physical address */
bfd_vma p_filesz; /* Segment size in file */
bfd_vma p_memsz; /* Segment size in memory */
bfd_vma p_align; /* Segment alignment, file & memory */
};
typedef struct elf_internal_phdr Elf_Internal_Phdr;
#define BYTE_GET(field) byte_get (field, sizeof (field))
typedef unsigned long long dwarf_vma;
typedef unsigned long long dwarf_size_type;
struct elf_internal_sym {
bfd_vma st_value; /* Value of the symbol */
bfd_vma st_size; /* Associated symbol size */
unsigned long st_name; /* Symbol name, index in string tbl */
unsigned char st_info; /* Type and binding attributes */
unsigned char st_other; /* Visibilty, and target specific */
unsigned int st_shndx; /* Associated section index */
};
typedef struct elf_internal_sym Elf_Internal_Sym;
#define GET_ELF_SYMBOLS(file, section) \
(is_32bit_elf ? get_32bit_elf_symbols (file, section) \
: get_64bit_elf_symbols (file, section))
#endif /* BASE_ELF_READER_EXTERNAL_H_ */
- LibraryReader.h
/**
* @ name unpacker
* @ author xiaobaiyey
* @ email xiaobaiyey@outlook.com
* @ time 2018/11/20 5:04 PM
* @ class describe
*/
#ifndef UNPACKER_LIBRARYREADER_H
#define UNPACKER_LIBRARYREADER_H
#include <string>
#include "external.h"
#include <map>
#include <elf.h>
enum LIBRARYTYPE {
FROMFILE,
FROMMEMORY
};
/**
*so文件太大 个人感觉,在主线程中可能不能太适用
* 具体没试过时间消耗
*/
class LibraryReader {
public:
LibraryReader(const char *path, LIBRARYTYPE= FROMFILE);
LibraryReader();
unsigned long get_symbol_offset(const char *symbol);
unsigned long get_symbol_address(const char *symbol);
void print_symbol();
static unsigned long get_so_address(const char *sopath);
static uint32_t calculate_elf_hash(const char *name);
private:
LIBRARYTYPE librarytype;
std::string path;
int is_32bit_elf;
bool elf_parse_pass;
bool _lock = true;
unsigned long min_vaddr = 0xffffffff;
Elf_Internal_Ehdr elf_header;
Elf_Internal_Phdr *program_headers;
Elf_Internal_Shdr *section_headers;
Elf_Internal_Shdr *symtab_shndx_hdr;
std::map<std::string, bfd_vma> symbol_maps;
private:
//读取头文件
bool read_elf_file_header(FILE *file);
//读取program_headers
bool process_program_headers(FILE *file);
bool read_program_headers(FILE *file);
bool get_32bit_program_headers(FILE *file, Elf_Internal_Phdr *program_headers);
bool get_64bit_program_headers(FILE *file, Elf_Internal_Phdr *program_headers);
//读取section_headers
bool process_section_headers(FILE *file);
bool get_32bit_section_headers(FILE *file, unsigned int num);
bool get_64bit_section_headers(FILE *file, unsigned int num);
//读取解析数据
bool process_symbol_table(FILE *file);
Elf_Internal_Sym *get_32bit_elf_symbols(FILE *file, Elf_Internal_Shdr *section);
Elf_Internal_Sym *get_64bit_elf_symbols(FILE *file, Elf_Internal_Shdr *section);
};
#endif //UNPACKER_LIBRARYREADER_H
- LibraryReader.cpp
/**
* @ name unpacker
* @ author xiaobaiyey
* @ email xiaobaiyey@outlook.com
* @ time 2018/11/20 5:04 PM
* @ class describe
*/
#include "LibraryReader.h"
#include <elf.h>
#include <thread>
#define DEBUG
#ifdef DEBUG
#define LOGI(...) printf(__VA_ARGS__);printf("\n")
#define LOGW(...) printf(__VA_ARGS__);printf("\n")
#define LOGE(...) printf(__VA_ARGS__);printf("\n")
#define LOGD(...)
#else
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, __FUNCTION__, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, __FUNCTION__, __VA_ARGS__))
#define LOGD(...)
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, __FUNCTION__, __VA_ARGS__))
#endif
#define ABORT(...)
static dwarf_vma byte_get_little_endian(unsigned char *field, int size) {
switch (size) {
case 1:
return *field;
case 2:
return ((unsigned int) (field[0])) | (((unsigned int) (field[1])) << 8);
case 4:
return ((unsigned long) (field[0])) | (((unsigned long) (field[1])) << 8) |
(((unsigned long) (field[2])) << 16) | (((unsigned long) (field[3])) << 24);
case 8:
if (sizeof(dwarf_vma) == 8)
return ((dwarf_vma) (field[0])) | (((dwarf_vma) (field[1])) << 8) |
(((dwarf_vma) (field[2])) << 16) | (((dwarf_vma) (field[3])) << 24)
| (((dwarf_vma) (field[4])) << 32) | (((dwarf_vma) (field[5])) << 40) |
(((dwarf_vma) (field[6])) << 48) | (((dwarf_vma) (field[7])) << 56);
else if (sizeof(dwarf_vma) == 4)
/* We want to extract data from an 8 byte wide field and
place it into a 4 byte wide field. Since this is a little
endian source we can just use the 4 byte extraction code. */
return ((unsigned long) (field[0])) | (((unsigned long) (field[1])) << 8) |
(((unsigned long) (field[2])) << 16)
| (((unsigned long) (field[3])) << 24);
else {
ABORT("error size (%d)", size);
}
default:
ABORT("error size (%d)", size);
}
return *field;
}
static dwarf_vma byte_get_big_endian(unsigned char *field, int size) {
switch (size) {
case 1:
return *field;
case 2:
return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
case 4:
return ((unsigned long) (field[3])) | (((unsigned long) (field[2])) << 8) |
(((unsigned long) (field[1])) << 16) | (((unsigned long) (field[0])) << 24);
case 8:
if (sizeof(dwarf_vma) == 8)
return ((dwarf_vma) (field[7])) | (((dwarf_vma) (field[6])) << 8) |
(((dwarf_vma) (field[5])) << 16) | (((dwarf_vma) (field[4])) << 24)
| (((dwarf_vma) (field[3])) << 32) | (((dwarf_vma) (field[2])) << 40) |
(((dwarf_vma) (field[1])) << 48) | (((dwarf_vma) (field[0])) << 56);
else if (sizeof(dwarf_vma) == 4) {
/* Although we are extracing data from an 8 byte wide field,
we are returning only 4 bytes of data. */
field += 4;
return ((unsigned long) (field[3])) | (((unsigned long) (field[2])) << 8) |
(((unsigned long) (field[1])) << 16)
| (((unsigned long) (field[0])) << 24);
} else {
ABORT("error size (%d)", size);
}
default:
//error (_("Unhandled data length: %d\n"), size);
ABORT("error size (%d)", size);
}
return *field;
}
static void *
get_data(void *var, FILE *file, long offset, size_t size, size_t nmemb, const char *reason) {
void *mvar;
if (size == 0 || nmemb == 0)
return NULL;
if (fseek(file, offset, SEEK_SET)) {
LOGE("Unable to seek to 0x%lx for %s\n", (unsigned long) offset, reason);
return NULL;
}
mvar = var;
if (mvar == NULL) {
/* Check for overflow. */
if (nmemb < (~(size_t) 0 - 1) / size)
/* + 1 so that we can '\0' terminate invalid string table sections. */
mvar = malloc(size * nmemb + 1);
if (mvar == NULL) {
LOGE("Out of memory allocating 0x%lx bytes for %s\n", (unsigned long) (size * nmemb),
reason);
return NULL;
}
((char *) mvar)[size * nmemb] = '\0';
}
if (fread(mvar, size, nmemb, file) != nmemb) {
LOGE("Unable to read in 0x%lx bytes of %s\n", (unsigned long) (size * nmemb), reason);
if (mvar != var)
free(mvar);
return NULL;
}
return mvar;
}
dwarf_vma (*byte_get)(unsigned char *, int);
LibraryReader::LibraryReader(const char *path, LIBRARYTYPE librarytype) {
this->librarytype = librarytype;
this->path = path;
if (this->librarytype == FROMFILE) {
FILE *file = fopen(path, "rb");
if (file == nullptr) {
LOGE("read %s fail", path);
elf_parse_pass = false;
return;
}
LOGD("read file over");
if (!read_elf_file_header(file)) {
LOGE("read_elf_file_header fail");
elf_parse_pass = false;
}
LOGD("read_elf_file_header over");
if (!process_program_headers(file)) {
LOGE("process_program_headers fail");
elf_parse_pass = false;
}
LOGD("process_program_headers over");
if (!process_section_headers(file)) {
LOGE("process_section_headers fail");
elf_parse_pass = false;
}
LOGD("process_section_headers over");
if (!process_symbol_table(file)) {
LOGE("process_symbol_table fail");
elf_parse_pass = false;
}
LOGD("process_symbol_table over");
fclose(file);
elf_parse_pass = true;
} else {
}
}
bool LibraryReader::read_elf_file_header(FILE *file) {
unsigned char e_ident[EI_NIDENT];
if (fread(e_ident, EI_NIDENT, 1, file) != 1) {
LOGE("read EI_NIDENT fail");
return false;
}
switch (e_ident[EI_DATA]) {
default: /* fall through */
case ELFDATANONE: /* fall through */
case ELFDATA2LSB:
byte_get = byte_get_little_endian;
break;
case ELFDATA2MSB:
byte_get = byte_get_big_endian;
break;
}
is_32bit_elf = (e_ident[EI_CLASS] != ELFCLASS64);
if (is_32bit_elf) {
Elf32_External_Ehdr ehdr32;
if (fread(ehdr32.e_type, sizeof(ehdr32) - EI_NIDENT, 1, file) != 1) {
LOGE("read ehdr32.e_type fail");
return false;
}
elf_header.e_type = BYTE_GET(ehdr32.e_type);
elf_header.e_machine = BYTE_GET(ehdr32.e_machine);
elf_header.e_version = BYTE_GET(ehdr32.e_version);
elf_header.e_phoff = BYTE_GET(ehdr32.e_phoff);
elf_header.e_shoff = BYTE_GET(ehdr32.e_shoff);
elf_header.e_flags = BYTE_GET(ehdr32.e_flags);
elf_header.e_ehsize = BYTE_GET(ehdr32.e_ehsize);
elf_header.e_phentsize = BYTE_GET(ehdr32.e_phentsize);
elf_header.e_phnum = BYTE_GET(ehdr32.e_phnum);
elf_header.e_shentsize = BYTE_GET(ehdr32.e_shentsize);
elf_header.e_shnum = BYTE_GET(ehdr32.e_shnum);
elf_header.e_shstrndx = BYTE_GET(ehdr32.e_shstrndx);
} else {
Elf64_External_Ehdr ehdr64;
if (fread(ehdr64.e_type, sizeof(ehdr64) - EI_NIDENT, 1, file) != 1) {
LOGE("read ehdr64.e_type fail");
return false;
}
elf_header.e_type = BYTE_GET(ehdr64.e_type);
elf_header.e_machine = BYTE_GET(ehdr64.e_machine);
elf_header.e_version = BYTE_GET(ehdr64.e_version);
elf_header.e_phoff = BYTE_GET(ehdr64.e_phoff);
elf_header.e_shoff = BYTE_GET(ehdr64.e_shoff);
elf_header.e_flags = BYTE_GET(ehdr64.e_flags);
elf_header.e_ehsize = BYTE_GET(ehdr64.e_ehsize);
elf_header.e_phentsize = BYTE_GET(ehdr64.e_phentsize);
elf_header.e_phnum = BYTE_GET(ehdr64.e_phnum);
elf_header.e_shentsize = BYTE_GET(ehdr64.e_shentsize);
elf_header.e_shnum = BYTE_GET(ehdr64.e_shnum);
elf_header.e_shstrndx = BYTE_GET(ehdr64.e_shstrndx);
}
return true;
}
bool LibraryReader::read_program_headers(FILE *file) {
Elf_Internal_Phdr *phdrs;
/* Check cache of prior read. */
if (program_headers != NULL)
return true;
phdrs = (Elf_Internal_Phdr *) malloc(elf_header.e_phnum * sizeof(Elf_Internal_Phdr));
if (phdrs == NULL) {
return false;
}
if (is_32bit_elf ? get_32bit_program_headers(file, phdrs) : get_64bit_program_headers(file,
phdrs)) {
program_headers = phdrs;
return true;
}
free(phdrs);
return false;
}
bool LibraryReader::get_32bit_program_headers(FILE *file, Elf_Internal_Phdr *program_headers) {
Elf32_External_Phdr *phdrs;
Elf32_External_Phdr *external;
Elf_Internal_Phdr *internal;
unsigned int i;
phdrs = (Elf32_External_Phdr *) get_data(NULL, file, elf_header.e_phoff, elf_header.e_phentsize,
elf_header.e_phnum, "program headers");
if (!phdrs)
return false;
for (i = 0, internal = program_headers, external = phdrs;
i < elf_header.e_phnum; i++, internal++, external++) {
internal->p_type = BYTE_GET(external->p_type);
internal->p_offset = BYTE_GET(external->p_offset);
internal->p_vaddr = BYTE_GET(external->p_vaddr);
internal->p_paddr = BYTE_GET(external->p_paddr);
internal->p_filesz = BYTE_GET(external->p_filesz);
internal->p_memsz = BYTE_GET(external->p_memsz);
internal->p_flags = BYTE_GET(external->p_flags);
internal->p_align = BYTE_GET(external->p_align);
}
free(phdrs);
return true;
}
bool LibraryReader::get_64bit_program_headers(FILE *file, Elf_Internal_Phdr *program_headers) {
Elf64_External_Phdr *phdrs;
Elf64_External_Phdr *external;
Elf_Internal_Phdr *internal;
unsigned int i;
phdrs = (Elf64_External_Phdr *) get_data(NULL, file, elf_header.e_phoff, elf_header.e_phentsize,
elf_header.e_phnum, "program headers");
if (!phdrs)
return false;
for (i = 0, internal = program_headers, external = phdrs;
i < elf_header.e_phnum; i++, internal++, external++) {
internal->p_type = BYTE_GET(external->p_type);
internal->p_flags = BYTE_GET(external->p_flags);
internal->p_offset = BYTE_GET(external->p_offset);
internal->p_vaddr = BYTE_GET(external->p_vaddr);
internal->p_paddr = BYTE_GET(external->p_paddr);
internal->p_filesz = BYTE_GET(external->p_filesz);
internal->p_memsz = BYTE_GET(external->p_memsz);
internal->p_align = BYTE_GET(external->p_align);
}
free(phdrs);
return true;
}
bool LibraryReader::process_program_headers(FILE *file) {
Elf_Internal_Phdr *segment;
unsigned int i;
if (elf_header.e_phnum == 0) {
return 0;
}
if (!read_program_headers(file))
return false;
for (i = 0, segment = program_headers; i < elf_header.e_phnum; i++, segment++) {
if (segment->p_type == PT_LOAD) {
if ((unsigned long) segment->p_vaddr < min_vaddr) {
min_vaddr = (unsigned long) segment->p_vaddr;
}
}
}
return true;
}
bool LibraryReader::get_32bit_section_headers(FILE *file, unsigned int num) {
Elf32_External_Shdr *shdrs;
Elf_Internal_Shdr *internal;
unsigned int i;
shdrs = (Elf32_External_Shdr *) get_data(NULL, file, elf_header.e_shoff, elf_header.e_shentsize,
num, "section headers");
if (!shdrs)
return false;
section_headers = (Elf_Internal_Shdr *) malloc(num * sizeof(Elf_Internal_Shdr));
if (section_headers == NULL) {
LOGE("Out of memory\n");
return false;
}
for (i = 0, internal = section_headers; i < num; i++, internal++) {
internal->sh_name = BYTE_GET(shdrs[i].sh_name);
internal->sh_type = BYTE_GET(shdrs[i].sh_type);
internal->sh_flags = BYTE_GET(shdrs[i].sh_flags);
internal->sh_addr = BYTE_GET(shdrs[i].sh_addr);
internal->sh_offset = BYTE_GET(shdrs[i].sh_offset);
internal->sh_size = BYTE_GET(shdrs[i].sh_size);
internal->sh_link = BYTE_GET(shdrs[i].sh_link);
internal->sh_info = BYTE_GET(shdrs[i].sh_info);
internal->sh_addralign = BYTE_GET(shdrs[i].sh_addralign);
internal->sh_entsize = BYTE_GET(shdrs[i].sh_entsize);
}
free(shdrs);
return true;
}
bool LibraryReader::get_64bit_section_headers(FILE *file, unsigned int num) {
Elf64_External_Shdr *shdrs;
Elf_Internal_Shdr *internal;
unsigned int i;
shdrs = (Elf64_External_Shdr *) get_data(NULL, file, elf_header.e_shoff, elf_header.e_shentsize,
num, "section headers");
if (!shdrs)
return false;
section_headers = (Elf_Internal_Shdr *) malloc(num * sizeof(Elf_Internal_Shdr));
if (section_headers == NULL) {
LOGE("Out of memory\n");
return false;
}
for (i = 0, internal = section_headers; i < num; i++, internal++) {
internal->sh_name = BYTE_GET(shdrs[i].sh_name);
internal->sh_type = BYTE_GET(shdrs[i].sh_type);
internal->sh_flags = BYTE_GET(shdrs[i].sh_flags);
internal->sh_addr = BYTE_GET(shdrs[i].sh_addr);
internal->sh_size = BYTE_GET(shdrs[i].sh_size);
internal->sh_entsize = BYTE_GET(shdrs[i].sh_entsize);
internal->sh_link = BYTE_GET(shdrs[i].sh_link);
internal->sh_info = BYTE_GET(shdrs[i].sh_info);
internal->sh_offset = BYTE_GET(shdrs[i].sh_offset);
internal->sh_addralign = BYTE_GET(shdrs[i].sh_addralign);
}
free(shdrs);
return true;
}
bool LibraryReader::process_section_headers(FILE *file) {
if (elf_header.e_shoff) {
/* There may be some extensions in the first section header. Don't
bomb if we can't read it. */
if (is_32bit_elf)
return get_32bit_section_headers(file, elf_header.e_shnum);
else
return get_64bit_section_headers(file, elf_header.e_shnum);
}
return false;
}
bool LibraryReader::process_symbol_table(FILE *file) {
unsigned int i;
Elf_Internal_Shdr *section;
unsigned long result = 0;
for (i = 0, section = section_headers; i < elf_header.e_shnum; i++, section++) {
unsigned int si;
char *strtab = NULL;
unsigned long int strtab_size = 0;
Elf_Internal_Sym *symtab;
Elf_Internal_Sym *psym;
if (section->sh_type != SHT_SYMTAB && section->sh_type != SHT_DYNSYM) {
continue;
}
symtab = GET_ELF_SYMBOLS(file, section);
if (symtab == NULL)
continue;
if (section->sh_link == elf_header.e_shstrndx) {
continue;
} else if (section->sh_link < elf_header.e_shnum) {
Elf_Internal_Shdr *string_sec;
string_sec = section_headers + section->sh_link;
strtab = (char *) get_data(NULL, file, string_sec->sh_offset, 1, string_sec->sh_size,
"string table");
strtab_size = strtab != NULL ? string_sec->sh_size : 0;
}
int number = section->sh_size / section->sh_entsize;
for (si = 0, psym = symtab; si < number; si++, psym++) {
const char *name = psym->st_name < strtab_size ? strtab + psym->st_name : "<corrupt>";
if (name != nullptr && strlen(name) > 0 && psym->st_value != 0) {
symbol_maps.insert(std::make_pair(std::string(name), psym->st_value));
}
}
free(symtab);
}
return true;
}
Elf_Internal_Sym *LibraryReader::get_32bit_elf_symbols(FILE *file, Elf_Internal_Shdr *section) {
unsigned long number;
Elf32_External_Sym *esyms;
Elf_External_Sym_Shndx *shndx;
Elf_Internal_Sym *isyms;
Elf_Internal_Sym *psym;
unsigned int j;
esyms = (Elf32_External_Sym *) get_data(NULL, file, section->sh_offset, 1, section->sh_size,
"symbols");
if (!esyms)
return NULL;
shndx = NULL;
if (symtab_shndx_hdr != NULL &&
(symtab_shndx_hdr->sh_link == (unsigned long) (section - section_headers))) {
shndx = (Elf_External_Sym_Shndx *) get_data(NULL, file, symtab_shndx_hdr->sh_offset, 1,
symtab_shndx_hdr->sh_size, "symtab shndx");
if (!shndx) {
free(esyms);
return NULL;
}
}
number = section->sh_size / section->sh_entsize;
isyms = (Elf_Internal_Sym *) malloc(number * sizeof(Elf_Internal_Sym));
if (isyms == NULL) {
LOGE("Out of memory\n");
if (shndx)
free(shndx);
free(esyms);
return NULL;
}
for (j = 0, psym = isyms; j < number; j++, psym++) {
psym->st_name = BYTE_GET(esyms[j].st_name);
psym->st_value = BYTE_GET(esyms[j].st_value);
psym->st_size = BYTE_GET(esyms[j].st_size);
psym->st_shndx = BYTE_GET(esyms[j].st_shndx);
if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL)
psym->st_shndx = byte_get((unsigned char *) &shndx[j], sizeof(shndx[j]));
else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff))
psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
psym->st_info = BYTE_GET(esyms[j].st_info);
psym->st_other = BYTE_GET(esyms[j].st_other);
}
if (shndx)
free(shndx);
free(esyms);
return isyms;
}
Elf_Internal_Sym *LibraryReader::get_64bit_elf_symbols(FILE *file, Elf_Internal_Shdr *section) {
unsigned long number;
Elf64_External_Sym *esyms;
Elf_External_Sym_Shndx *shndx;
Elf_Internal_Sym *isyms;
Elf_Internal_Sym *psym;
unsigned int j;
esyms = (Elf64_External_Sym *) get_data(NULL, file, section->sh_offset, 1, section->sh_size,
"symbols");
if (!esyms)
return NULL;
shndx = NULL;
if (symtab_shndx_hdr != NULL &&
(symtab_shndx_hdr->sh_link == (unsigned long) (section - section_headers))) {
shndx = (Elf_External_Sym_Shndx *) get_data(NULL, file, symtab_shndx_hdr->sh_offset, 1,
symtab_shndx_hdr->sh_size, "symtab shndx");
if (!shndx) {
free(esyms);
return NULL;
}
}
number = section->sh_size / section->sh_entsize;
isyms = (Elf_Internal_Sym *) malloc(number * sizeof(Elf_Internal_Sym));
if (isyms == NULL) {
LOGE("Out of memory\n");
if (shndx)
free(shndx);
free(esyms);
return NULL;
}
for (j = 0, psym = isyms; j < number; j++, psym++) {
psym->st_name = BYTE_GET(esyms[j].st_name);
psym->st_info = BYTE_GET(esyms[j].st_info);
psym->st_other = BYTE_GET(esyms[j].st_other);
psym->st_shndx = BYTE_GET(esyms[j].st_shndx);
if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL)
psym->st_shndx = byte_get((unsigned char *) &shndx[j], sizeof(shndx[j]));
else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff))
psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
psym->st_value = BYTE_GET(esyms[j].st_value);
psym->st_size = BYTE_GET(esyms[j].st_size);
}
if (shndx)
free(shndx);
free(esyms);
return isyms;
}
void LibraryReader::print_symbol() {
if (!elf_parse_pass) {
LOGE("elf_parse_pass false");
return;
}
std::map<std::string, bfd_vma>::iterator iterator;
for (iterator = symbol_maps.begin(); iterator != symbol_maps.end(); iterator++) {
std::string symbol = iterator->first;
bfd_vma bfd_vma1 = iterator->second;
LOGI("symbol:%s offset:0x%x", symbol.c_str(), bfd_vma1);
}
}
unsigned long LibraryReader::get_symbol_offset(const char *symbol) {
if (!elf_parse_pass) {
LOGE("elf_parse_pass false");
return 0;
}
// clock_t start =clock();
std::string str(symbol);
auto it = symbol_maps.find(str);
if (it == symbol_maps.end()) {
return 0;
}
/* clock_t end = clock();
clock_t duration = (end - start);
//LOGI( "%ld seconds", duration );*/
return it->second;
}
LibraryReader::LibraryReader() {
}
unsigned long LibraryReader::get_so_address(const char *sopath) {
char line[1024] = {0};
FILE *fp;
unsigned long addr = 0;
char *pch;
if ((fp = fopen("/proc/self/maps", "r")) == NULL) {
LOGE("/proc/self/maps open failed (%s)", strerror(errno));
return 0;
}
while (fgets(line, sizeof(line), fp)) {
if (strstr(line, sopath)) {
pch = strtok(line, "-");
addr = strtoul(pch, NULL, 16);
break;
}
}
fclose(fp);
return addr;
}
unsigned long LibraryReader::get_symbol_address(const char *symbol) {
if (!elf_parse_pass) {
LOGE("elf_parse_pass false");
return 0;
}
// clock_t start =clock();
std::string str(symbol);
auto it = symbol_maps.find(str);
if (it == symbol_maps.end()) {
return 0;
}
/* clock_t end = clock();
clock_t duration = (end - start);
//LOGI( "%ld seconds", duration );*/
return it->second + get_so_address(this->path.c_str());
}
uint32_t LibraryReader::calculate_elf_hash(const char *name) {
const uint8_t *name_bytes = reinterpret_cast<const uint8_t *>(name);
uint32_t h = 0, g;
while (*name_bytes) {
h = (h << 4) + *name_bytes++;
g = h & 0xf0000000;
h ^= g;
h ^= g >> 24;
}
return h;
}
网友评论