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二进制文件解析相关推荐

  1. cfile清空文件内容_编译-链接-加载 :ELF文件格式解析

    摘要:对于C++的初学者,经常在程序的编译或者加载过程中遇到很多错误,类似undefined reference to ... 和 GLIBCXX_3.4.20 not found 等.这些错误都涉及 ...

  2. elf文件格式_Android so(ELF) 文件解析

    Android so(ELF) 文件解析 Android so(ELF) 文件解析 前言 生成 so 文件 相关工具 objdump readelf 整体结构图 头部结构 段表结构 字符串表结构 程序 ...

  3. Android so(ELF) 文件解析

    文章目录 前言 生成 so 文件 相关工具 objdump readelf 整体结构图 头部结构 段表结构 字符串表结构 程序表结构 符号表结构 重定位表结构 其他结构 解析代码 打开 ELF 文件 ...

  4. Elf动态解析符号过程(转载) - *nix文件格式 - j4ckl1u

    导读: 本篇文章以linux为平台为例,演示ELF动态解析符号的过程. 不正之处,还请斧正. 通常,ELF解析符号方式称为lazy MODE装载的.这种装载技术是ELF平台上 默认的方式.在不同的体系 ...

  5. SGX初始化中ELF文件解析

    先记 ElfParser::run_parser()函数是SGX初始化<再回顾sgx_create_enclave>慢慢长征路的中间一环.比较独立又有些复杂,单独抽出来讲. ELF文件布局 ...

  6. 记:ELF文件解析初定义——文件头解析

    0x00 概论 因为TI的DSP输出文件与传统的ELF文件不符,所以本人就顺道研究了一下现在的ELF的文件格式. 会将其陆续完成在文章中. 阅读本文之前,您需要掌握的技能有: 技能名称 技能熟练度 技 ...

  7. 基于UDS的BootLoader上位机源代码,支持ISO15765通信,支持PeakCAN , ZJG CAN等CAN卡, 支持S-record格式的二进制文件解析; 可二次开发或扩展应用

    基于UDS的BootLoader上位机源代码(C#) 基于UDS的BootLoader上位机源代码,支持ISO15765通信,支持PeakCAN , ZJG CAN等CAN卡, 支持S-record格 ...

  8. elf 文件格式解析

    elf案例解析 源代码 int main() {asm("movl $42, %ebx \n\t""movl $1 , %eax \n\t""int ...

  9. 记:ELF文件解析初定义——Section段相关讲解

    0x00 概论 因为TI的DSP输出文件与传统的ELF文件不符,所以本人就顺道研究了一下现在的ELF的文件格式. 会将其陆续完成在文章中. 承接上文,上文书说到,解析文件头格式,数据段的分配定义,与数 ...

  10. Mach-O 二进制文件解析

    0x01  Mach-O格式简单介绍 Mach-O文件格式是 OS X 与 iOS 系统上的可执行文件格式,类似于windows的 PE 文件 与 Linux(其他 Unix like)的 ELF 文 ...

最新文章

  1. sklearn one_hot向量输出维度第2维大小的本质
  2. 占内存小的qq_手机内存空间告急,这些办法就能轻松搞定!
  3. 【技术干货】TC基础与自动化
  4. OpenGL 使用FDTD求解电磁波方程
  5. 【Java网络编程(四)】手写TCP聊天室——控制台版
  6. 进销存设计之——单据的数据表结构设计
  7. js与c语言效率_JavaScript控制流及关键字与C语言之比较
  8. bootstrap评分插件 Bootstrap Star Rating Examples
  9. C语言丨线性查找(顺序查找)
  10. Hadoop基础-配置历史服务器
  11. 翻牌游戏如何打乱牌面java_如何游戏4Bet底池?
  12. 第一次做web项目购物网站项目总结
  13. 【建议收藏】货币交易信息爬取+筛选(Python附源码)
  14. BP算法推导-softmax层+交叉熵(logloss)
  15. 解决 Cannot uninstall 'ipython'. It is a distutils installed project and thus we cannot accurately det
  16. glassfish配置Oracle数据源,GlassFish链接数据库
  17. nginx反向代理异步传输模式(原理)
  18. PaddleNLP系列课程一:Taskflow、小样本学习、FasterTransformer
  19. c语言的文法,c语言实现First文法
  20. [机器学习笔记] 将数据拆分成训练集和测试集的几种方法

热门文章

  1. 格兰杰检验的基本步骤_Toda-Yamamoto 格兰杰因果检验 TY-Granger方法
  2. 水面船舶雷达监视-信天翁雷达监视系统
  3. matlab生成的图显示数据类型,matlab中数据类型及图像显示
  4. 数学建模:人口增长模型
  5. oracle instantclient 64,instantclient 64位
  6. 数字图像处理实验九维纳滤波
  7. 如何在linux下观看需vodplayer播放的电影
  8. Java 产品与软件下载
  9. 在线考试系统架构设计
  10. 学校计算机房主机系统,学校机房电脑系统恢复的方法