博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
elf文件解析(cpp版)
阅读量:6690 次
发布时间:2019-06-25

本文共 13952 字,大约阅读时间需要 46 分钟。

Elf.h

#ifndef H_ELF_PARSER#define H_ELF_PARSER#include 
#include
#include
#include
#include
/* O_RDONLY */#include
/* For the size of the file. , fstat */#include
/* mmap, MAP_PRIVATE */#include
#include
// Elf64_Shdr#include
//-----说明通过sections Header定位的以下称为节,通过Program Header定位的以下称为段 -----//namespace elf_parser {//节typedef struct { //当前节的索引 int section_index = 0; //节的偏移,虚拟地址 std::intptr_t section_offset, section_addr; //节名称 std::string section_name; //节类型 std::string section_type; //节大小 ,节中单个表项的大小,节对齐方式 int section_size, section_ent_size, section_addr_align;} section_t;//段typedef struct { //段类型,段的权限属性标志 std::string segment_type, segment_flags; //段的偏移,段的内存线性地址,段的内存物理地址,段在文件中的大小,段在内存中的大小 long segment_offset, segment_virtaddr, segment_physaddr, segment_filesize, segment_memsize; //段的内存中的对齐方式 int segment_align;} segment_t;//符号typedef struct { //符号索引 std::string symbol_index; //符号的值 std::intptr_t symbol_value; //符号表项顺序 ,大小 int symbol_num = 0, symbol_size = 0; //符号类型,绑定信息,其它,名称,所属节名称 std::string symbol_type, symbol_bind, symbol_visibility, symbol_name, symbol_section; } symbol_t;//重定位typedef struct { //指向需要进行重定位操作的位置 ,信息,值 std::intptr_t relocation_offset, relocation_info, relocation_symbol_value; //类型,名称,所属字名称 std::string relocation_type, relocation_symbol_name, relocation_section_name; //单个重定位条目所在地址 std::intptr_t relocation_plt_address;} relocation_t;//ELFclass Elf_parser { public: Elf_parser (std::string &program_path): m_program_path{program_path} { load_memory_map(); } //获取所有的节信息 std::vector
get_sections(); //获取所有的段信息 std::vector
get_segments(); //获取所有符号信息 std::vector
get_symbols(); //获取所有重位条目信息 std::vector
get_relocations(); //获取映射内存地址 uint8_t *get_memory_map(); private: //申请映射 void load_memory_map(); //获取节类型 std::string get_section_type(int tt); //获取段类型 std::string get_segment_type(uint32_t &seg_type); //获取段的权限属性 std::string get_segment_flags(uint32_t &seg_flags); //获取符号类型 std::string get_symbol_type(uint8_t &sym_type); //获取符号绑定信息 std::string get_symbol_bind(uint8_t &sym_bind); //获取符号其它信息 std::string get_symbol_visibility(uint8_t &sym_vis); //获取符号在字符串的中索引 std::string get_symbol_index(uint16_t &sym_idx); //获取重定位类型 std::string get_relocation_type(uint64_t &rela_type); //获取重定位值(在符号表中找) std::intptr_t get_rel_symbol_value(uint64_t &sym_idx, std::vector
&syms); //获取重定位的名称(在符号表中找) std::string get_rel_symbol_name( uint64_t &sym_idx, std::vector
&syms); //文件路径 std::string m_program_path; //映射内存首地址 uint8_t *m_mmap_program;};}#endif

Elf.cpp

//-----说明通过sections Header定位的以下称为节,通过Program Header定位的以下称为段 -----//#include "elf_parser.hpp"using namespace elf_parser;//获取所有节std::vector
Elf_parser::get_sections() { //ELF头 Elf64_Ehdr *ehdr = (Elf64_Ehdr*)m_mmap_program; //Section Header Table Elf64_Shdr *shdr = (Elf64_Shdr*)(m_mmap_program + ehdr->e_shoff); //Section Header Table个数 int shnum = ehdr->e_shnum; //字符串表 Elf64_Shdr *sh_strtab = &shdr[ehdr->e_shstrndx]; //字符串表在文件中的偏移 const char *const sh_strtab_p = (char*)m_mmap_program + sh_strtab->sh_offset; //保存所有的节 std::vector
sections; //循环遍历所有节表 for (int i = 0; i < shnum; ++i) { section_t section; //当前节在所有节中在顺序 section.section_index= i; //节的名称 sh_strtab_p字符串表的起始地址 + 节的名称的在字符串中的索引(偏移) section.section_name = std::string(sh_strtab_p + shdr[i].sh_name); //节的类型 section.section_type = get_section_type(shdr[i].sh_type); //节的虚拟地址 section.section_addr = shdr[i].sh_addr; //节的文件偏移 section.section_offset = shdr[i].sh_offset; //节的大小 section.section_size = shdr[i].sh_size; //节中表项的大小 section.section_ent_size = shdr[i].sh_entsize; //节对齐方式 section.section_addr_align = shdr[i].sh_addralign; //保存起来 sections.push_back(section); } //返回所有节向量 return sections;}//获取所有段std::vector
Elf_parser::get_segments() { //映射基址 Elf64_Ehdr *ehdr = (Elf64_Ehdr*)m_mmap_program; //程序头基址 Elf64_Phdr *phdr = (Elf64_Phdr*)(m_mmap_program + ehdr->e_phoff); //程序头表的数量 int phnum = ehdr->e_phnum; //节表基址 Elf64_Shdr *shdr = (Elf64_Shdr*)(m_mmap_program + ehdr->e_shoff); //字符串表索引 Elf64_Shdr *sh_strtab = &shdr[ehdr->e_shstrndx]; //字符串表基址 const char *const sh_strtab_p = (char*)m_mmap_program + sh_strtab->sh_offset; //声名保存所有段的向量 std::vector
segments; //遍历所有段 for (int i = 0; i < phnum; ++i) { segment_t segment; //段的类型 segment.segment_type = get_segment_type(phdr[i].p_type); //段的偏移 segment.segment_offset = phdr[i].p_offset; //段的内存线性地址 segment.segment_virtaddr = phdr[i].p_vaddr; //段的内存物理地址 segment.segment_physaddr = phdr[i].p_paddr; //段在文件中的大小 segment.segment_filesize = phdr[i].p_filesz; //段在内存中的大小 segment.segment_memsize = phdr[i].p_memsz; //段的权限属性标志 segment.segment_flags = get_segment_flags(phdr[i].p_flags); //段的内存中的对齐方式 segment.segment_align = phdr[i].p_align; //保存段 segments.push_back(segment); } //返回所有节向量 return segments;}//获取所有符号std::vector
Elf_parser::get_symbols() { //先获取所有节 std::vector
secs = get_sections(); // get headers for offsets Elf64_Ehdr *ehdr = (Elf64_Ehdr*)m_mmap_program; //获取所有节表头基址 Elf64_Shdr *shdr = (Elf64_Shdr*)(m_mmap_program + ehdr->e_shoff); //符号字符串表 // get strtab char *sh_strtab_p = nullptr; //遍历所有的节 for(auto &sec: secs) { //判断节的类型与名称 if((sec.section_type == "SHT_STRTAB") && (sec.section_name == ".strtab")){ //获取符号基址 sh_strtab_p = (char*)m_mmap_program + sec.section_offset; break; } } //动态符号字符串表 // get dynstr char *sh_dynstr_p = nullptr; //遍历所有的节 for(auto &sec: secs) { //判断节的类型与名称 if((sec.section_type == "SHT_STRTAB") && (sec.section_name == ".dynstr")){ //获取符号基址 sh_dynstr_p = (char*)m_mmap_program + sec.section_offset; break; } } //用于保存所有符号 std::vector
symbols; //遍历所有节 for(auto &sec: secs) { //判断类型 if((sec.section_type != "SHT_SYMTAB") && (sec.section_type != "SHT_DYNSYM")) continue; //计算节中的所有符号个数 auto total_syms = sec.section_size / sizeof(Elf64_Sym); //符号节的基址 auto syms_data = (Elf64_Sym*)(m_mmap_program + sec.section_offset); //遍历符号表 for (int i = 0; i < total_syms; ++i) { symbol_t symbol; //符号表序号 symbol.symbol_num = i; //符号的值 symbol.symbol_value = syms_data[i].st_value; //符号的大小 (字节) symbol.symbol_size = syms_data[i].st_size; //获取符号的类型 (info表示相关信息,低4字节表示符号类型,可以用宏获取) symbol.symbol_type = get_symbol_type(syms_data[i].st_info); //获取符号绑定信息 symbol.symbol_bind = get_symbol_bind(syms_data[i].st_info); //获取符号其它信息(可见性) symbol.symbol_visibility= get_symbol_visibility(syms_data[i].st_other); //符号索引 symbol.symbol_index = get_symbol_index(syms_data[i].st_shndx); //符号所在节的名称 symbol.symbol_section = sec.section_name; //判断字符串表 if(sec.section_type == "SHT_SYMTAB") symbol.symbol_name = std::string(sh_strtab_p + syms_data[i].st_name); //判断动态字符串表 if(sec.section_type == "SHT_DYNSYM") symbol.symbol_name = std::string(sh_dynstr_p + syms_data[i].st_name); //保存起来 symbols.push_back(symbol); } } //返回向量 return symbols;}//获取所有重定位表std::vector
Elf_parser::get_relocations() { //获取所有节 auto secs = get_sections(); //获取所有字符串表 auto syms = get_symbols(); //plt 节表项大小 int plt_entry_size = 0; //plt 节的虚拟地址 long plt_vma_address = 0; //遍历所有的节 for (auto &sec : secs) { //判断节名称 if(sec.section_name == ".plt") { //节中表项的大小 plt_entry_size = sec.section_ent_size; //节的虚拟地址 plt_vma_address = sec.section_addr; break; } } //用于保存所有重定位表 std::vector
relocations; //遍历所有的节 for (auto &sec : secs) { //判断节的类型 if(sec.section_type != "SHT_RELA") continue; //计算节的所有重定位条目数 auto total_relas = sec.section_size / sizeof(Elf64_Rela); //重定位节的基址 auto relas_data = (Elf64_Rela*)(m_mmap_program + sec.section_offset); //遍历所有的重定位条目 for (int i = 0; i < total_relas; ++i) { relocation_t rel; //指向需要进行重定位操作的位置 //解释: //表示重定位地址,对应可重定位目标文件来说,表示重定位位置相对于被重定位段的基址的偏移,而对于 //可执行文件或共享目标文件来说,表示重定位位置对应的线性地址,这个与动态相关。 rel.relocation_offset = static_cast
(relas_data[i].r_offset); //重定位相关信息 //描述了重定位类型和符号,低8位表示重定位类型,高24位表示重定位符号对应符号表项在符号表内的索引 //不同的处理器体系结构都属于自己的一套重定位类型。 rel.relocation_info = static_cast
(relas_data[i].r_info); //类型 rel.relocation_type = \ get_relocation_type(relas_data[i].r_info); //值 (在字符串表中找) rel.relocation_symbol_value = \ get_rel_symbol_value(relas_data[i].r_info, syms); //符号名称(存字符串表中找) rel.relocation_symbol_name = \ get_rel_symbol_name(relas_data[i].r_info, syms); // plt项的地址 rel.relocation_plt_address = plt_vma_address + (i + 1) * plt_entry_size; //节名称 rel.relocation_section_name = sec.section_name; //保存起来 relocations.push_back(rel); } } //返回向量 return relocations;}//获取映射内存首地址uint8_t *Elf_parser::get_memory_map() { return m_mmap_program;}//申请内存映射void Elf_parser::load_memory_map() { int fd, i; struct stat st; //打开文件 if ((fd = open(m_program_path.c_str(), O_RDONLY)) < 0) { printf("Err: open\n"); exit(-1); } //获取文件大小 if (fstat(fd, &st) < 0) { printf("Err: fstat\n"); exit(-1); } //映射内存 m_mmap_program = static_cast
(mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)); //判断是否成功 if (m_mmap_program == MAP_FAILED) { printf("Err: mmap\n"); exit(-1); } auto header = (Elf64_Ehdr*)m_mmap_program; //判断是否为64位ELF文件 if (header->e_ident[EI_CLASS] != ELFCLASS64) { printf("Only 64-bit files supported\n"); exit(1); }}//获取节的类型(参数为类型值)std::string Elf_parser::get_section_type(int tt) { if(tt < 0) return "UNKNOWN"; switch(tt) { case 0: return "SHT_NULL"; /* Section header table entry unused */ case 1: return "SHT_PROGBITS"; /* Program data */ case 2: return "SHT_SYMTAB"; /* Symbol table */ case 3: return "SHT_STRTAB"; /* String table */ case 4: return "SHT_RELA"; /* Relocation entries with addends */ case 5: return "SHT_HASH"; /* Symbol hash table */ case 6: return "SHT_DYNAMIC"; /* Dynamic linking information */ case 7: return "SHT_NOTE"; /* Notes */ case 8: return "SHT_NOBITS"; /* Program space with no data (bss) */ case 9: return "SHT_REL"; /* Relocation entries, no addends */ case 11: return "SHT_DYNSYM"; /* Dynamic linker symbol table */ default: return "UNKNOWN"; } return "UNKNOWN";}//段的类型std::string Elf_parser::get_segment_type(uint32_t &seg_type) { switch(seg_type) { case PT_NULL: return "NULL"; /* Program header table entry unused */ case PT_LOAD: return "LOAD"; /* Loadable program segment */ case PT_DYNAMIC: return "DYNAMIC"; /* Dynamic linking information */ case PT_INTERP: return "INTERP"; /* Program interpreter */ case PT_NOTE: return "NOTE"; /* Auxiliary information */ case PT_SHLIB: return "SHLIB"; /* Reserved */ case PT_PHDR: return "PHDR"; /* Entry for header table itself */ case PT_TLS: return "TLS"; /* Thread-local storage segment */ case PT_NUM: return "NUM"; /* Number of defined types */ case PT_LOOS: return "LOOS"; /* Start of OS-specific */ case PT_GNU_EH_FRAME: return "GNU_EH_FRAME"; /* GCC .eh_frame_hdr segment */ case PT_GNU_STACK: return "GNU_STACK"; /* Indicates stack executability */ case PT_GNU_RELRO: return "GNU_RELRO"; /* Read-only after relocation */ //case PT_LOSUNW: return "LOSUNW"; case PT_SUNWBSS: return "SUNWBSS"; /* Sun Specific segment */ case PT_SUNWSTACK: return "SUNWSTACK"; /* Stack segment */ //case PT_HISUNW: return "HISUNW"; case PT_HIOS: return "HIOS"; /* End of OS-specific */ case PT_LOPROC: return "LOPROC"; /* Start of processor-specific */ case PT_HIPROC: return "HIPROC"; /* End of processor-specific */ default: return "UNKNOWN"; }}//获取段的权限属性std::string Elf_parser::get_segment_flags(uint32_t &seg_flags) { std::string flags; //读 if(seg_flags & PF_R) flags.append("R"); //写 if(seg_flags & PF_W) flags.append("W"); //执行 if(seg_flags & PF_X) flags.append("E"); return flags;}//获取符号的类型 (info表示相关信息,低4字节表示符号类型,可以用宏获取)std::string Elf_parser::get_symbol_type(uint8_t &sym_type) { //判断符号类型 switch(ELF32_ST_TYPE(sym_type)) { case 0: return "NOTYPE"; case 1: return "OBJECT"; case 2: return "FUNC"; case 3: return "SECTION"; case 4: return "FILE"; case 6: return "TLS"; case 7: return "NUM"; case 10: return "LOOS"; case 12: return "HIOS"; default: return "UNKNOWN"; }}//获取符号的绑定信息 (info表示相关信息,低4字节表示符号类型,可以用宏获取)std::string Elf_parser::get_symbol_bind(uint8_t &sym_bind) { //判断符号的绑定信息 switch(ELF32_ST_BIND(sym_bind)) { case 0: return "LOCAL"; case 1: return "GLOBAL"; case 2: return "WEAK"; case 3: return "NUM"; case 10: return "UNIQUE"; case 12: return "HIOS"; case 13: return "LOPROC"; default: return "UNKNOWN"; }}//符号的其它信息std::string Elf_parser::get_symbol_visibility(uint8_t &sym_vis) { switch(ELF32_ST_VISIBILITY(sym_vis)) { case 0: return "DEFAULT"; case 1: return "INTERNAL"; case 2: return "HIDDEN"; case 3: return "PROTECTED"; default: return "UNKNOWN"; }}//索引std::string Elf_parser::get_symbol_index(uint16_t &sym_idx) { switch(sym_idx) { case SHN_ABS: return "ABS"; case SHN_COMMON: return "COM"; case SHN_UNDEF: return "UND"; case SHN_XINDEX: return "COM"; default: return std::to_string(sym_idx); }}//重定位的类型std::string Elf_parser::get_relocation_type(uint64_t &rela_type) { switch(ELF64_R_TYPE(rela_type)) { case 1: return "R_X86_64_32"; case 2: return "R_X86_64_PC32"; case 5: return "R_X86_64_COPY"; case 6: return "R_X86_64_GLOB_DAT"; case 7: return "R_X86_64_JUMP_SLOT"; default: return "OTHERS"; }}//获取符中的值std::intptr_t Elf_parser::get_rel_symbol_value( uint64_t &sym_idx, std::vector
&syms) { std::intptr_t sym_val = 0; //遍历所有符号表项 for(auto &sym: syms) { //判断(高 24位表示重定位符号对应符号表项在符号表内的索引 //符号表序号 //symbol.symbol_num = i; if(sym.symbol_num == ELF64_R_SYM(sym_idx)) { //取其值 sym_val = sym.symbol_value; break; } } return sym_val;}//符号名称std::string Elf_parser::get_rel_symbol_name( uint64_t &sym_idx, std::vector
&syms) { std::string sym_name; for(auto &sym: syms) { //判断(高 24位表示重定位符号对应符号表项在符号表内的索引 //符号表序号 //symbol.symbol_num = i; if(sym.symbol_num == ELF64_R_SYM(sym_idx)) { //取其名称 sym_name = sym.symbol_name; break; } } return sym_name;}

转载于:https://blog.51cto.com/haidragon/2134231

你可能感兴趣的文章
javascript中this指向的理解(转载)
查看>>
linux 二级域名设置
查看>>
微信多客服插件获取openid
查看>>
java获得CPU使用率,系统内存,虚拟机内存等情况
查看>>
Vue项目搭建
查看>>
shell基础 -- 基本正则表达式
查看>>
METO CODE 223 拉力赛
查看>>
修改NavigationView中的Item的Icon大小
查看>>
协议类接口 - I2C
查看>>
Java生成二维码--QRGen
查看>>
数据集搜集整理
查看>>
总结:树与二叉树的学习
查看>>
easyui中对数据的判断来显示,formatter控制
查看>>
李刚与你畅谈Java编程人生(讲座)
查看>>
老男孩和门户网站学生聊天整理
查看>>
Microsoft Azure部署MYSQL-MMM(2)配置主主复制
查看>>
Surface体验WS2012中RDS的RemoteFX虚拟桌面
查看>>
因为有你,所以精彩
查看>>
K8S集群中使用Helm管理应用分发
查看>>
<進階&高級>ADT線上視頻&PPT課件
查看>>