ELF全名:可执行链接格式。 这是UNIX系统实验室(USL )作为APP应用程序二进制接口(ABI )开发并公开的。 ELF文件有三种类型。
可重定位文件:包含代码和数据,可链接到可执行文件并共享目标文件以供使用。 可执行文件:包含二进制代码和数据,可直接复制到存储器中执行(/wsdgk或/usr/wsdgk目录下的文件)。 共享目标文件:在加载或运行时动态加载并链接到存储器的特殊可重定位文件。
文件的开头是ELF文件标题,其中包含整个文件的基本属性,如文件类型、版本、目标计算机类型和程序条目地址。 然后,每个段都用段表来描述。 在“链接”和“执行”视图下,段分别由Section Header Table和Program Header Table描述。
ELF头文件在/usr/include/elf.h文件中定义
typedefstructelf 64 _ HDR { unsigned chare _ ident [ ei _ ni dent ]; //魔数7f’e’’l’’f’El f64 _ halfe _ type; //文件类型Elf64_Half e_machine; //机器类型Elf64_Word e_version; //文件版本Elf64_Addr e_entry; //开始处理的虚拟地址,即系统控制转变的位置Elf64_Off e_phoff; //program header table中的文件偏移Elf64_Off e_shoff; //section header表的文件偏移Elf64_Word e_flags; //处理器相关标志Elf64_Half e_ehsize; //ELF文件头的长度Elf64_Half e_phentsize; //program header表中入口的长度Elf64_Half e_phnum; //program header表中的项数Elf64_Half e_shentsize; //section header表中入口的长度Elf64_Half e_shnum; //section header表中的项数Elf64_Half e_shstrndx; //section名表的位置。 section header表中的索引} Elf64_Ehdr; Program Header目标文件或共享文件的program header table包含系统运行程序所需的段和其他信息。 目标文件的段包含一个或多个section。 Program header只对可执行文件和共享目标文件有意义,对程序的链接没有任何意义
typedefstructelf 64 _ phdr { El f64 _ wordp _ type; //段的类型Elf64_Word p_flags; //段标志Elf64_Off p_offset; //段偏移Elf64_Addr p_vaddr; //段虚拟地址Elf64_Addr p_paddr; //段物理地址Elf64_Xword p_filesz; //段大小Elf64_Xword p_memsz; //内存占用Elf64_Xword p_align; //段对齐} Elf64_Phdr; Section Header文件的section header table可以搜索所有section
typedefstructelf 64 _ shdr { El f64 _ wordsh _ name; //段名称,值为符号表索引Elf64_Word sh_type; //类别Elf64_Xword sh_flags; //执行课程时的特性Elf64_Addr sh_addr; //出现在进程的存储器图像中时,开始的虚拟地址Elf64_Off sh_offset; Elf64_Xword sh_size; //大小尺寸Elf64_Word sh_link; //其他段的索引Elf64_Word sh_info; //信息Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; //} Elf64_Shdr; Symbol Table文件中的符号表包含放置或重新定位程序符号的定义和参照所需的信息
typedefstructelf 64 _ sym { El f64 _ wordst _ name; //符号名称unsigned charst_info; //符号类型unsigned charst_other; //其他Elf64_Half st_shndx; //段索引Elf64_Addr st_value; //符号地址值Elf64_Xword st_size; //符号大小(} Elf64_Sym; ELF文件分析创建新的hello.c文件以分析ELF文件
#includestdio.hintadd(void ) ) { int a=3; int b=2; int c=a b; 返回c; }int main () printf ) ' %dn ',add ); 返回0; }新makefile
Hello 3360 hello.ogcc-ohellohello.o hello.o : hello.cgcc-c-o hello.o hello.c执行make hello后来作为hello闻名的elf可执行法
根据输出信息可以得到魔数、机器架构、系统类型。 显示文件大小为64bytes(0x40 )的hexdump -C hello输出elf文件的二进制信息,0x0 -0x40表示标头结构中的数据范围
通过参考ELF64_hdr结构定义,可以读取信息。 例如,7f 45 4c 56 ASCII代码表示为. elf。 按02 01 01 00的顺序分别表示64位对象、小字节序、文件头版本和其他。 03 00表示该文件是共享目标文件等。
运行readelf -l hello以输出程序头信息
从以前的头部hex到e_phnum=0d 00 (小端序变换00d ) )即segment有13段,从程序头的输出信息中可以看出确实有13段。 上图显示了与第一段对应的hex代码范围。 Section to Segment mapping表示两个视图映射。
运行readelf -S hello以获取Section Header表
从以前的标题hex开始Section的数量e_shnum为1f00 (小端序变换001f )表示有31个段
段起始偏移e_shoff为98 39 00 00 00 00 00 00 (小端序转换器00 000 000 39 98 ) e_ehentsize为40 00 (小端序转换器00 40 )代码段编号16
因此,代码段地址为0x3998(0x40*0x10 )=0x3D98
现在,验证sh_name。 b9000000(000000b9 )表示段名称已由. shstrtab偏移。
运行readelf -x .shstrtab hello
00 00 00 b9中的编码确实是text。 现在,确保内存中section的虚拟地址正在执行readelf -x .text hello输出代码段信息
代码段虚拟地址sh_addr为6010,000等于从代码段的输出获得的地址信息(0x00001060 ),并且上面描述的代码段的计算是正确的。 其他段的导出也是一样。