Android漫遊記(2)---ELF可執行檔格式

來源:互聯網
上載者:User

ELF是類Unix類系統,當然也包括Android系統上的可執行檔格式(也包括.so和.o類檔案)。可以理解為Android系統上的exe或者dll檔案格式。理解ELF檔案規格,是理解Android系統上進程載入、執行的前提。下面我們就來一步步瞭解這ELF到底是個啥玩意兒(以Arm 32 ELF格式為主)!當然,網上關於ELF的介紹已經非常多,最好的手冊還是直接看ELF官方的手冊,我這裡只是對ELF的檔案做個綱領性介紹,然後直奔主題,比如.GOT .PLT或者R_Arm_Jump_Slot,R_Arm_Relative之類的玩意兒。

還是以libc.so為例來介紹,先看通過arm-linux-androideabi-readelf產生的ELF檔案,很長,我們先看一個片段:


我們挑幾個有意思的欄位內容來說明。

首先ELF Header:顧名思義,這是所有ELF檔案都有的”頭“。裡麵包含了ELF檔案的”綱領性“資訊,如”Machine“表示當前CPU架構,該例為arm,”Start of Sections“表示”區(Section)頭”的位移位元組數等等。

而Section Headers則列出了所有包含在檔案中的Section區資訊列表。如.data表示資料區,.text表示代碼區等等。下面用一張圖來對ELF的檔案格式有個總覽:<喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"http://www.2cto.com/uploadfile/Collfiles/20140609/20140609091245187.jpg" alt="\">

左邊是靜態視圖,而右邊則是連結載入時的視圖,都是同一個檔案的兩種狀態。

/* ELF Header */typedef struct elfhdr {unsigned chare_ident[EI_NIDENT]; /* ELF Identification */Elf32_Halfe_type;/* object file type */Elf32_Halfe_machine;/* machine */Elf32_Worde_version;/* object file version */Elf32_Addre_entry;/* virtual entry point */Elf32_Offe_phoff;/* program header table offset */Elf32_Offe_shoff;/* section header table offset */Elf32_Worde_flags;/* processor-specific flags */Elf32_Halfe_ehsize;/* ELF header size */Elf32_Halfe_phentsize;/* program header entry size */Elf32_Halfe_phnum;/* number of program header entries */Elf32_Halfe_shentsize;/* section header entry size */Elf32_Halfe_shnum;/* number of section header entries */Elf32_Halfe_shstrndx;/* section header table's "section    header string table" entry offset */} Elf32_Ehdr;

其中的e_shoff就是上面我們看到的“Start of section headers”,而e_shstrndx是指Sections的名字串在串表(String Table,也是一個Section)中的起始索引位置。

下面我們再看一下Section Header的定義:

/* Section Header */typedef struct {Elf32_Wordsh_name;/* name - index into section header   string table section */Elf32_Wordsh_type;/* type */Elf32_Wordsh_flags;/* flags */Elf32_Addrsh_addr;/* address */Elf32_Offsh_offset;/* file offset */Elf32_Wordsh_size;/* section size */Elf32_Wordsh_link;/* section header table index link */Elf32_Wordsh_info;/* extra information */Elf32_Wordsh_addralign;/* address alignment */Elf32_Wordsh_entsize;/* section entry size */} Elf32_Shdr;
這個我們要詳細看看,後面能用到:

欄位:

sh_name:顧名思義,Section的名字,類型是Elf32_Word,實際上它是指向串表的索引值

sh_flags:類型。.dynsym的類型為DYNSYM表示該節區包含了要動態連結的符號等等

sh_addr:地址。該節區在記憶體中,相對於基址的位移

sh_offset:位移。表示該節區到檔案頭部的位元組位移。

sh_size:節區大小

sh_link:表示與當前section有link關係的section索引,不同類型的section,其解釋不同。如上面的libc.so,其.dynsym的link為2,而2正好是.dynstr的索引,實際上就是動態符號串表的索引

sh_info:一些附加資訊

sh_addralign:節區的地址對齊

sh_entsize:節區項的大小(bytes)

上面這麼多亂七八糟的看起來很多,實際上記住一點就可以了:所有這些資訊,都是linker在載入elf的時候要用到的“參考表”。

老習慣,我們直接寫個elf讀取的小程式,來驗證下我們的理解。

/* *  elf32 reader *  Created on: 2014-6 *  Author: Chris.Z */#include #include #include #include #include #ifdef __x86_64    #define Elf_Ehdr Elf64_Ehdr    #define Elf_Shdr Elf64_Shdr    #define Elf_Sym Elf64_Sym    #define Elf_Rel Elf64_Rela    #define ELF_R_SYM ELF64_R_SYM    #define REL_DYN ".rela.dyn"    #define REL_PLT ".rela.plt"#else    #define Elf_Ehdr Elf32_Ehdr    #define Elf_Shdr Elf32_Shdr    #define Elf_Sym Elf32_Sym    #define Elf_Rel Elf32_Rel    #define ELF_R_SYM ELF32_R_SYM    #define REL_DYN ".rel.dyn"    #define REL_PLT ".rel.plt"#endif#define LOG(...) printf(__VA_ARGS__);/** * lookup the start address of a specific module(libc.so...) within current process * return 0 if FAILED */static uint32_t get_module_base(pid_t pid, const char *module_path) {FILE *fp = NULL;char *pch = NULL;char filename[32];char line[512];uint32_t addr = 0;LOG("[+] get libc base...\n");if (pid < 0)snprintf(filename, sizeof(filename), "/proc/self/maps");elsesnprintf(filename, sizeof(filename), "/proc/%d/maps", pid);if ((fp = fopen(filename, "r")) == NULL) {LOG("[-]open %s failed!", filename);return 0;}while (fgets(line, sizeof(line), fp)) {if (strstr(line, module_path)) {pch = strtok(line, "-");addr = strtoul(pch, NULL, 16);break;}}fclose(fp);LOG("[+] libc base:0x%x...\n",addr);return addr;}/** * read the elf header * return 0 if SUCCESS */static int read_header(int d, Elf_Ehdr **header)//read elf header structure{    *header = (Elf_Ehdr *)malloc(sizeof(Elf_Ehdr));    if (lseek(d, 0, SEEK_SET) < 0)//seek to the begin of file    {        free(*header);        return errno;    }    if (read(d, *header, sizeof(Elf_Ehdr)) <= 0)//read from begin,read sizof(Elf_Ehdr) bytes ==> header    {        free(*header);        return errno = EINVAL;    }    return 0;}/** * read the section header * return 0 if SUCCESS */static int read_section_table(int d, Elf_Ehdr const *header, Elf_Shdr **table)//read elf header,find section header base address{    size_t size;    if (NULL == header)        return EINVAL;    size = header->e_shnum * sizeof(Elf_Shdr);//section numbers and total size    *table = (Elf_Shdr *)malloc(size);    if (lseek(d, header->e_shoff, SEEK_SET) < 0)//point to section header,offset 0    {        free(*table);        return errno;    }    if (read(d, *table, size) <= 0)//read section header structure to **table    {        free(*table);        return errno = EINVAL;    }    return 0;}/** * read the string section table * return 0 if SUCCESS */static int read_string_table(int d, Elf_Shdr const *section, char const **strings){    if (NULL == section)//section == > .dynstr section        return EINVAL;    *strings = (char const *)malloc(section->sh_size);    if (lseek(d, section->sh_offset, SEEK_SET) < 0)    {        free((void *)*strings);        return errno;    }    if (read(d, (char *)*strings, section->sh_size) <= 0)//strings include all strings in .dynstr sections    {        free((void *)*strings);        return errno = EINVAL;    }    return 0;}int main(){    LOG("[+]Arm ELF32 reader...\n");    uint32_t lic_base = get_module_base(-1,"/system/lib/libc.so");    int descriptor = open("/system/lib/libc.so", O_RDONLY);//open libc.so,and return the handle    Elf_Ehdr *header = NULL;//elf header    Elf_Shdr *section_header = NULL;//section header array ptr    char const *strings = NULL;//string table ptr    read_header(descriptor,&header);    LOG("[+]libc.so elf header:\n");    LOG("[+]e_ident[EI_NIDENT]:   %s\n",header->e_ident);    LOG("[+]e_type:%d(ET_DYN:%d,DYN (Shared object file))\n",header->e_type,ET_DYN);    LOG("[+]e_machine:%d(EM_ARM:%d,Advanced RISC Machines)\n",header->e_machine,EM_ARM);    LOG("[+]e_shoff:%d bytes\n",header->e_shoff);    LOG("[+]libc.so section header:\n");    read_section_table(descriptor,header,§ion_header);    read_string_table(descriptor,§ion_header[header->e_shstrndx], &strings);//header->e_shstrndx ==>the index of string section header in section headers    int i = 0;    for(i = 0;ie_shnum;++i)    {        LOG("Section[%d] name:%s,type:%d,addr:0x%x,offset:0x%x,size:%dbytes,etc...\n",i,&strings[section_header[i].sh_name],section_header[i].sh_type,section_header[i].sh_addr,section_header[i].sh_offset,section_header[i].sh_size);    }    close(descriptor);    return 0;}

我們看看運行結果:



對照看一下readelf產生的結果,果然如此,Enjoy IT!

轉載請註明出處:生活秀

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.