編輯:關於Android編程
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的文件格式有個總覽:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20140609/20140609091245187.jpg" alt="\">
左邊是靜態視圖,而右邊則是鏈接加載時的視圖,都是同一個文件的兩種狀態。
/* ELF Header */ typedef struct elfhdr { unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ Elf32_Half e_type; /* object file type */ Elf32_Half e_machine; /* machine */ Elf32_Word e_version; /* object file version */ Elf32_Addr e_entry; /* virtual entry point */ Elf32_Off e_phoff; /* program header table offset */ Elf32_Off e_shoff; /* section header table offset */ Elf32_Word e_flags; /* processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size */ Elf32_Half e_phentsize; /* program header entry size */ Elf32_Half e_phnum; /* number of program header entries */ Elf32_Half e_shentsize; /* section header entry size */ Elf32_Half e_shnum; /* number of section header entries */ Elf32_Half e_shstrndx; /* section header table's "section header string table" entry offset */ } Elf32_Ehdr;
下面我們再看一下Section Header的定義:
/* Section Header */ typedef struct { Elf32_Word sh_name; /* name - index into section header string table section */ Elf32_Word sh_type; /* type */ Elf32_Word sh_flags; /* flags */ Elf32_Addr sh_addr; /* address */ Elf32_Off sh_offset; /* file offset */ Elf32_Word sh_size; /* section size */ Elf32_Word sh_link; /* section header table index link */ Elf32_Word sh_info; /* extra information */ Elf32_Word sh_addralign; /* address alignment */ Elf32_Word sh_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"); else snprintf(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;i e_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!
轉載請注明出處:生活秀
圖片異步加載。可以備注圖片是否緩存、緩存狀態。1、緩存-SD卡,路徑可設置2、圖片壓縮3、可加載本地和網絡圖片4、url為本地視頻文件可以顯示縮略圖5、中文url圖片地址
GridView組件是以網格的形式顯示所有的組件,例如:在制作相冊的時候,所有的圖片都會以相同大小顯示在不同的格子之中,就可以依靠此組件完成,
Activity是最基本的模塊,一般稱之為活動,在應用程序中,一個Activity通常就是一個單獨的屏幕。簡單理解,Activity代表一個用戶所能看到的屏幕,主要用於處
Android ADB 用法adb 全稱是 Android Debug Bridge, 就是起到調試橋的作用。 用來操作android設備的閱讀目錄 adb