Elf二进制文件解析
Elf文件解析
ELF头部结构
ELF
文件头从文件的0偏移量开始,是除了文件头剩余部分文件的一个映射。
typedef struct
{unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */Elf64_Half e_type; /* Object file type */Elf64_Half e_machine; /* Architecture */Elf64_Word e_version; /* Object file version */Elf64_Addr e_entry; /* Entry point virtual address */Elf64_Off e_phoff; /* Program header table file offset */Elf64_Off e_shoff; /* Section header table file offset */Elf64_Word e_flags; /* Processor-specific flags */Elf64_Half e_ehsize; /* ELF header size in bytes */Elf64_Half e_phentsize; /* Program header table entry size */Elf64_Half e_phnum; /* Program header table entry count */Elf64_Half e_shentsize; /* Section header table entry size */Elf64_Half e_shnum; /* Section header table entry count */Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
Elf程序头
ELF
程序头是对二进制文件中段的描述,是程序装载必须的一部分。段是在内核装载是被解析的,描述了磁盘上可执行文件的内存布局以及如何映射到内存中。可以通过引用原始ELF头中成员e_phoff
(程序头表偏移量)的偏移量来获取程序头表。
typedef struct
{Elf64_Word p_type; /* Segment type */Elf64_Word p_flags; /* Segment flags */Elf64_Off p_offset; /* Segment file offset */Elf64_Addr p_vaddr; /* Segment virtual address */Elf64_Addr p_paddr; /* Segment physical address */Elf64_Xword p_filesz; /* Segment size in file */Elf64_Xword p_memsz; /* Segment size in memory */Elf64_Xword p_align; /* Segment alignment */
} Elf64_Phdr;
ELF节头
节,不是段,段是程序执行的必要组成部分,在每个段中,会有代码欧哲数据被划分成为不同的节。节头表是对这些节位置和大小的描述,主要用于链接和调试。
typedef struct
{Elf64_Word sh_name; /* Section name (string tbl index) */Elf64_Word sh_type; /* Section type */Elf64_Xword sh_flags; /* Section flags */Elf64_Addr sh_addr; /* Section virtual addr at execution */Elf64_Off sh_offset; /* Section file offset */Elf64_Xword sh_size; /* Section size in bytes */Elf64_Word sh_link; /* Link to another section */Elf64_Word sh_info; /* Additional section information */Elf64_Xword sh_addralign; /* Section alignment */Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
ELF符号
符号是对某些类型的数据或者代码(如全局变量或函数)的符号引用。如printf()
函数会在动态符号表.dynsym
中存有一个指向该函数的符号条目。在大多数共享库和动态链接可执行文件中,存在两个符号表即.dynsym
和.symtab
连个节,Elf64_Sym
中字段st_name保存了指向符号表中字符串表.dynstr
和.strtab
。
符号表对应的结构体为:
typedef struct
{Elf64_Word st_name; /* Symbol name (string tbl index) */unsigned char st_info; /* Symbol type and binding */unsigned char st_other; /* Symbol visibility */Elf64_Section st_shndx; /* Section index */Elf64_Addr st_value; /* Symbol value */Elf64_Xword st_size; /* Symbol size */
} Elf64_Sym;
ELF文件解析实现(简易readelf实现)
#include <stdlib.h>
#include <stdio.h>
#include <elf.h>
#include <string.h>
#include <error.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>/* To printf dynamic symbol */
void print_dynamic_symbol(uint8_t *mem, Elf64_Shdr *dynsym, Elf64_Shdr *dynstr)
{unsigned int i = 0;unsigned int nsym = 0;Elf64_Sym *sym = NULL;printf("%d %d\n", dynsym->sh_size, dynsym->sh_entsize);nsym = dynsym->sh_size / dynsym->sh_entsize;printf("The nsym size is %d\n", nsym);for (i = 0; i < nsym; i++) {sym = (Elf64_Sym *)(&mem[dynsym->sh_offset] + i * sizeof(Elf64_Sym));printf("sybmol -> %s\n", (&mem[dynstr->sh_offset] + sym->st_name));}printf("Nothing here\n");
}/* To printf all symbol */
void print_all_symbol(uint8_t *mem, Elf64_Shdr *symtab, Elf64_Shdr *strtab)
{unsigned int i = 0;unsigned int nsym = 0;Elf64_Sym *sym = NULL;nsym = symtab->sh_size / symtab->sh_entsize;printf("The nsym size is %d\n", nsym);for (i = 0; i < nsym; i++) {sym = (Elf64_Sym *)(&mem[symtab->sh_offset] + i * sizeof(Elf64_Sym));printf("sybmol -> %s\n", (&mem[strtab->sh_offset] + sym->st_name));}printf("Nothing here\n");
}/* gcc elfparse.c -o elfparse */
int main(int argc, char *argv[])
{int fd, i;uint8_t *mem;struct stat st;char *StringTable, *interp;Elf64_Ehdr *ehdr;Elf64_Phdr *phdr;Elf64_Shdr *shdr;Elf64_Shdr *dynsym = NULL;Elf64_Shdr *dynstr = NULL;Elf64_Shdr *symtab = NULL;Elf64_Shdr *strtab = NULL;if (argc != 2) {printf("Usage: %s <exe>\n", argv[0]); return -1;}fd = open(argv[1], O_RDONLY);if (fd <= 0) {perror("open"); return -1;}if (fstat(fd, &st) < 0) {perror("fstat"); goto close;}/* Map the executable into memory */mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);if (mem == NULL) {perror("mmap"); goto close;}/** The initial ELF Header starts at offset 0* of out mapped memory*/ehdr = (Elf64_Ehdr *)mem;/** The shdr table and phdr table offset are* given by e_shoff and e_phoff members of the Elf64_Ehdr*/phdr = (Elf64_Phdr *)&mem[ehdr->e_phoff];shdr = (Elf64_Shdr *)&mem[ehdr->e_shoff];/** Check to see if the ELF magic (The first 4 bytes)* match up as 0x7f E L F*/if (mem[0] != 0x7f && strcmp(&mem[1], "ELF")) {fprintf(stderr, "%s is not an ELF file\n", argv[1]);goto out; }/** We are only parsing executables wite this code.* so ET_EXEC marks an executable*/#if 0printf("%d\n", ehdr->e_type);if (ehdr->e_type != ET_EXEC) {fprintf(stderr, "%s is not an excutable file\n", argv[1]);return -1;}
#endifprintf("Program Entry point 0x%lx\n", ehdr->e_entry);/** We find the string table for the section header* names with e_shstrndx which gives the index of* which section holds the string table.*/StringTable = &mem[shdr[ehdr->e_shstrndx].sh_offset];/** Print each section header name and address.* Notice we get the index into the string table* that contain each section header name with * the shdr.sh_name member.*/printf("Section header list:\n\n");for (i = 1; i < ehdr->e_shnum; i++) {printf("%s: addr: 0x%lx offset: 0x%lx size: %d\n", &StringTable[shdr[i].sh_name],shdr[i].sh_addr, shdr[i].sh_offset, shdr[i].sh_entsize);if (!strcmp(&StringTable[shdr[i].sh_name], ".dynsym")) {dynsym = (Elf64_Shdr *)&shdr[i];}if (!strcmp(&StringTable[shdr[i].sh_name], ".dynstr")) {dynstr = (Elf64_Shdr *)&shdr[i];}if (!strcmp(&StringTable[shdr[i].sh_name], ".symtab")) {symtab = (Elf64_Shdr *)&shdr[i];}if (!strcmp(&StringTable[shdr[i].sh_name], ".strtab")) {strtab = (Elf64_Shdr *)&shdr[i];}}print_dynamic_symbol(mem, dynsym, dynstr);print_all_symbol(mem, symtab, strtab);/** Print out each segment name, and address.* Except for PT_INTERRP we print the path to * the dynamic linker (Interpreter)*/printf("Segment header list:\n\n");for (i = 1; i < ehdr->e_phnum; i++) {switch(phdr[i].p_type) {/* * We know that text segment statrs* at offset 0. And only one other* possible loadable segment exitis* which is the data segment.*/case PT_LOAD:if (phdr[i].p_offset == 0) {printf("Text segment: 0x%lx\n", phdr[i].p_vaddr);} else {printf("Data segment: 0x%lx\n", phdr[i].p_vaddr);}break;case PT_INTERP:interp = strdup((char *)&mem[phdr[i].p_offset]);printf("Interpreter: %s\n", interp);break;case PT_NOTE:printf("Note segment: 0x%lx\n", phdr[i].p_vaddr);break;case PT_DYNAMIC:printf("Dynamic segment: 0x%lx\n", phdr[i].p_vaddr);break;case PT_PHDR:printf("Phdr segment: 0x%lx\n", phdr[i].p_vaddr);break;} } munmap(mem, st.st_size);close(fd);return 0;out:munmap(mem, st.st_size);
close:close(fd);return -1;
}
Elf二进制文件解析相关推荐
- cfile清空文件内容_编译-链接-加载 :ELF文件格式解析
摘要:对于C++的初学者,经常在程序的编译或者加载过程中遇到很多错误,类似undefined reference to ... 和 GLIBCXX_3.4.20 not found 等.这些错误都涉及 ...
- elf文件格式_Android so(ELF) 文件解析
Android so(ELF) 文件解析 Android so(ELF) 文件解析 前言 生成 so 文件 相关工具 objdump readelf 整体结构图 头部结构 段表结构 字符串表结构 程序 ...
- Android so(ELF) 文件解析
文章目录 前言 生成 so 文件 相关工具 objdump readelf 整体结构图 头部结构 段表结构 字符串表结构 程序表结构 符号表结构 重定位表结构 其他结构 解析代码 打开 ELF 文件 ...
- Elf动态解析符号过程(转载) - *nix文件格式 - j4ckl1u
导读: 本篇文章以linux为平台为例,演示ELF动态解析符号的过程. 不正之处,还请斧正. 通常,ELF解析符号方式称为lazy MODE装载的.这种装载技术是ELF平台上 默认的方式.在不同的体系 ...
- SGX初始化中ELF文件解析
先记 ElfParser::run_parser()函数是SGX初始化<再回顾sgx_create_enclave>慢慢长征路的中间一环.比较独立又有些复杂,单独抽出来讲. ELF文件布局 ...
- 记:ELF文件解析初定义——文件头解析
0x00 概论 因为TI的DSP输出文件与传统的ELF文件不符,所以本人就顺道研究了一下现在的ELF的文件格式. 会将其陆续完成在文章中. 阅读本文之前,您需要掌握的技能有: 技能名称 技能熟练度 技 ...
- 基于UDS的BootLoader上位机源代码,支持ISO15765通信,支持PeakCAN , ZJG CAN等CAN卡, 支持S-record格式的二进制文件解析; 可二次开发或扩展应用
基于UDS的BootLoader上位机源代码(C#) 基于UDS的BootLoader上位机源代码,支持ISO15765通信,支持PeakCAN , ZJG CAN等CAN卡, 支持S-record格 ...
- elf 文件格式解析
elf案例解析 源代码 int main() {asm("movl $42, %ebx \n\t""movl $1 , %eax \n\t""int ...
- 记:ELF文件解析初定义——Section段相关讲解
0x00 概论 因为TI的DSP输出文件与传统的ELF文件不符,所以本人就顺道研究了一下现在的ELF的文件格式. 会将其陆续完成在文章中. 承接上文,上文书说到,解析文件头格式,数据段的分配定义,与数 ...
- Mach-O 二进制文件解析
0x01 Mach-O格式简单介绍 Mach-O文件格式是 OS X 与 iOS 系统上的可执行文件格式,类似于windows的 PE 文件 与 Linux(其他 Unix like)的 ELF 文 ...
最新文章
- sklearn one_hot向量输出维度第2维大小的本质
- 占内存小的qq_手机内存空间告急,这些办法就能轻松搞定!
- 【技术干货】TC基础与自动化
- OpenGL 使用FDTD求解电磁波方程
- 【Java网络编程(四)】手写TCP聊天室——控制台版
- 进销存设计之——单据的数据表结构设计
- js与c语言效率_JavaScript控制流及关键字与C语言之比较
- bootstrap评分插件 Bootstrap Star Rating Examples
- C语言丨线性查找(顺序查找)
- Hadoop基础-配置历史服务器
- 翻牌游戏如何打乱牌面java_如何游戏4Bet底池?
- 第一次做web项目购物网站项目总结
- 【建议收藏】货币交易信息爬取+筛选(Python附源码)
- BP算法推导-softmax层+交叉熵(logloss)
- 解决 Cannot uninstall 'ipython'. It is a distutils installed project and thus we cannot accurately det
- glassfish配置Oracle数据源,GlassFish链接数据库
- nginx反向代理异步传输模式(原理)
- PaddleNLP系列课程一:Taskflow、小样本学习、FasterTransformer
- c语言的文法,c语言实现First文法
- [机器学习笔记] 将数据拆分成训练集和测试集的几种方法