日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ELF文件解析器

發布時間:2023/12/20 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ELF文件解析器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

全部代碼:https://github.com/Kakaluoto/ELFReader

前言

最近選了Linux內核原理的選修課,雖然因為課時比較短涉及到的內容只能涵蓋Linux知識的一小部分,但是老師的水平確實很高,講的知識也很深入,這次布置的小作業是編寫Linux平臺下的C語言程序實現如下功能:

模仿實現Linux下readelf工具的部分功能,能夠對ELF可執行文件進行簡單分析。(至少支持readelf工具的-h、-S、-s三個命令選項功能)

關于原理部分自認為沒有能力和大佬們講得一樣透徹清楚,所以參考文章鏈接貼在了文章的末尾,看了一定就會明白的。

1.ELF文件介紹

在 Linux 系統中,一個 ELF 文件主要用來表示 3 種類型的文件:

  • 可執行文件:被操作系統中的加載器從硬盤上讀取,載入到內存中去執行;
  • 目標文件:被鏈接器讀取,用來產生一個可執行文件或者共享庫文件;
  • 共享庫文件:在動態鏈接的時候,由 ld-linux.so 來讀取;

2.readelf命令

-a :--all 顯示全部信息,等價于 -h -l -S -s -r -d -V -A -I -h :--file-header 顯示elf文件開始的文件頭信息. -l :--program-headers ;--segments 顯示程序頭(段頭)信息(如果有的話)。 -S :--section-headers ;--sections 顯示節頭信息(如果有的話)。 -g :--section-groups 顯示節組信息(如果有的話)。 -t :--section-details 顯示節的詳細信息(-S的)。 -s :--syms ;--symbols 顯示符號表段中的項(如果有的話)。 -e :--headers 顯示全部頭信息,等價于: -h -l -S -n :--notes 顯示note段(內核注釋)的信息。 -r :--relocs 顯示可重定位段的信息。 -u :--unwind 顯示unwind段信息。當前只支持IA64 ELF的unwind段信息。 -d :--dynamic 顯示動態段的信息。 -V :--version-info 顯示版本段的信息。 -A :--arch-specific 顯示CPU構架信息。 -D :--use-dynamic 使用動態段中的符號表顯示符號,而不是使用符號段。 -x <number or name> :--hex-dump=<number or name> 以16進制方式顯示指定段內內容。number指定段表中段的索引,或字符串指定文件中的段名。 -w[liaprmfFsoR]或者 -debugdump[=line,=info,=abbrev,=pubnames,=aranges, =macro,=frames,=frames-interp,=str,=loc,=Ranges] 顯示調試段中指定的內容。 -I :--histogram 顯示符號的時候,顯示bucket list長度的柱狀圖。 -v :--version 顯示readelf的版本信息。 -H :--help 顯示readelf所支持的命令行選項。 -W :--wide 寬行輸出。

3.代碼實現

Kakaluoto/ELFReader (github.com)

這次我一共分成了5個文件header.h ; main.cpp ; readelf_symbol.cpp ; readelf_Section.cpp ; readelf_header.cpp

頭文件 header.h

#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <elf.h> #ifndef ELFREADER_HEADER_H #define ELFREADER_HEADER_H using namespace std; void readelf_h(const char* filename);void readelf_S(const char* filename);void readelf_s(const char* filename); #endif //ELFREADER_HEADER_H

主函數 main.cpp

#include "header.h"int main(int argc, char* argv[]) {if (argc < 2) { exit(0); }//argv[0]是當前可執行文件路徑//arv[1]是參數,參數以空格作為分隔符//argv[2]是被解析的可執行文件名if (strcmp(argv[1], "-h") == 0)readelf_h(argv[2]);else if (strcmp(argv[1], "-S") == 0)readelf_S(argv[2]);else if (strcmp(argv[1], "-s") == 0)readelf_s(argv[2]);elseprintf("invalid argument!\n");return 0; }

模仿readelf -h 的實現readelf_header.cpp

#include "header.h"void readelf_h(const char* filename) {FILE* fp;//定義文件指針Elf64_Ehdr elf_header;//定義elf頭用來存儲fp = fopen(filename, "r");if (fp == NULL) { exit(0); }fread(&elf_header, sizeof(Elf64_Ehdr), 1, fp);//讀headerif (elf_header.e_ident[0] != 0x7f || elf_header.e_ident[1] != 'E') { exit(0); }//判斷是否是elf文件printf("ELF Header:\n");printf(" Magic:\t");for (unsigned char i : elf_header.e_ident) {printf("%02x ", i);}printf("\n");printf(" Class:\t\t\t\t");switch (elf_header.e_ident[EI_CLASS]) {case 1:printf("ELF%d\n", 32);break;case 2:printf("ELF%d\n", 64);break;default:printf("Error!\n");}printf(" Data:\t\t\t\t\t");switch (elf_header.e_ident[EI_DATA]) {case 1:printf("2's complement, little endian\n");break;case 2:printf("2's complement, big endian\n");break;default:printf("Error!\n");}printf(" Version:\t\t\t\t%d (current)\n", elf_header.e_ident[EI_VERSION]);printf(" OS/ABI:\t\t\t\t");switch (elf_header.e_ident[EI_OSABI]) {case ELFOSABI_NONE:printf("UNIX System V ABI\n");break;case ELFOSABI_HPUX:printf("HP-UX\n");break;case ELFOSABI_NETBSD:printf("NetBSD.\n");break;case ELFOSABI_GNU:printf("Object uses GNU ELF extensions.\n");break;case ELFOSABI_SOLARIS:printf("Sun Solaris.\n");break;case ELFOSABI_AIX:printf("IBM AIX.\n");break;case ELFOSABI_IRIX:printf("SGI Irix.\n");break;case ELFOSABI_FREEBSD:printf("FreeBSD.\n");break;case ELFOSABI_TRU64:printf("Compaq TRU64 UNIX.\n");break;case ELFOSABI_MODESTO:printf("Novell Modesto.\n");break;case ELFOSABI_OPENBSD:printf("OpenBSD.\n");break;case ELFOSABI_ARM_AEABI:printf("ARM EABI\n");break;case ELFOSABI_ARM:printf("ARM\n");break;case ELFOSABI_STANDALONE:printf("Standalone (embedded) application\n");break;default:printf("Error!\n");}printf(" ABI Version:\t\t\t\t%d\n", elf_header.e_ident[EI_ABIVERSION]);printf(" Type:\t\t\t\t\t");switch (elf_header.e_type) {case ET_REL:printf("REL (Relocatable file)\n");break;case ET_EXEC:printf("EXEC (Executable file)\n");break;case ET_DYN:printf("DYN (Shared object file)\n");break;default:printf("Error!\n");}printf(" Machine:\t\t\t\t");switch (elf_header.e_machine) {case EM_NONE:printf("No Machine!\n");break;case EM_386:printf("Intel 80386\n");break;case EM_860:printf("Intel 80860\n");break;case EM_ARM:printf("ARM\n");break;case EM_X86_64:printf("AMD x86-64 architecture\n");break;case EM_AVR:printf("Atmel AVR 8-bit microcontroller\n");break;case EM_MSP430:printf("Texas Instruments msp430\n");break;case EM_ALTERA_NIOS2:printf("Altera Nios II\n");break;case EM_MICROBLAZE:printf("Xilinx MicroBlaze\n");break;case EM_8051:printf("Intel 8051 and variants\n");break;case EM_STM8:printf("STMicroelectronics STM8\n");break;case EM_CUDA:printf("NVIDIA CUDA\n");break;case EM_AMDGPU:printf("AMD GPU\n");break;case EM_RISCV:printf("RISC-V\n");break;case EM_BPF:printf("Linux BPF -- in-kernel virtual machine\n");break;default:printf("Unknown Machine!\n");}printf(" Version:\t\t\t\t%x\n", elf_header.e_ident[EI_VERSION]);printf(" Entry point address:\t\t\t0x%016lx\n", elf_header.e_entry);printf(" Start of program headers:\t\t%ld (bytes into file)\n", elf_header.e_phoff);printf(" Start of section headers:\t\t%ld (bytes into file)\n", elf_header.e_shoff);printf(" Flags:\t\t\t\t0x%x\n", elf_header.e_flags);printf(" Size of this header:\t\t\t%d (bytes)\n", elf_header.e_ehsize);printf(" Size of program headers:\t\t%d (bytes)\n", elf_header.e_phentsize);printf(" Number of program headers:\t\t%d\n", elf_header.e_phnum);printf(" Size of section headers:\t\t%d (bytes)\n", elf_header.e_shentsize);printf(" Number of section headers:\t\t%d\n", elf_header.e_shnum);printf(" Section header string table index:\t%d\n", elf_header.e_shstrndx); }

模仿readelf -S 的實現readelf_Section.cpp

#include "header.h"void readelf_S(const char* filename) {FILE* fp;Elf64_Ehdr elf_header;fp = fopen(filename, "r");if (fp == NULL) { exit(0); }fread(&elf_header, sizeof(Elf64_Ehdr), 1, fp);if (elf_header.e_ident[0] != 0x7f || elf_header.e_ident[1] != 'E') { exit(0); }//定義數組用來存儲段表里每一個section_header,段的數目:elf_header.e_shnumElf64_Shdr* sec_headers = new Elf64_Shdr[elf_header.e_shnum];//將指針移動到段表起始地址,段起始地址elf_header.e_shoff即相對于整個elf文件的偏移量,SEEK_SET從文件起始開始偏移fseek(fp, elf_header.e_shoff, SEEK_SET);//讀section_header,每一個header大小為sizeof(Elf64_Shdr),一共讀elf_header.e_shnum個段表頭fread(sec_headers, sizeof(Elf64_Shdr), elf_header.e_shnum, fp);printf("There are %d section headers, starting at offset 0x%lx\n\n", elf_header.e_shnum, elf_header.e_shoff);printf("Section Headers:\n");int str_tab_ind = elf_header.e_shstrndx;//獲取字符串表在段表中的索引elf_header.e_shstrndx,用來讀取段名fseek(fp, sec_headers[str_tab_ind].sh_offset, SEEK_SET);//將指針移動到字符串表char* string_table = new char[sec_headers[str_tab_ind].sh_size];//構造字符數組用來存儲字符串表里的字符fread(string_table, 1, sec_headers[str_tab_ind].sh_size, fp);//將字符串表里面的字符全部讀出來//獲取section段的類型,輸入類型對應的數值,返回字符串型的類型名auto get_sh_type = [](int sh_type, string& sec_header_name) {switch (sh_type) {case SHT_NULL:sec_header_name = "NULL";break;case SHT_PROGBITS:sec_header_name = "PROGBITS";break;case SHT_SYMTAB:sec_header_name = "SYMTAB";break;case SHT_STRTAB:sec_header_name = "STRTAB";break;case SHT_RELA:sec_header_name = "RELA";break;case SHT_HASH:sec_header_name = "HASH";break;case SHT_DYNAMIC:sec_header_name = "DYNAMIC";break;case SHT_NOTE:sec_header_name = "NOTE";break;case SHT_NOBITS:sec_header_name = "NOBITS";break;case SHT_REL:sec_header_name = "REL";break;case SHT_SHLIB:sec_header_name = "SHLIB";break;case SHT_DYNSYM:sec_header_name = "DYNSYM";break;case SHT_INIT_ARRAY:sec_header_name = "INIT_ARRAY";break;case SHT_FINI_ARRAY:sec_header_name = "FINI_ARRAY";break;case SHT_PREINIT_ARRAY:sec_header_name = "PREINIT_ARRAY";break;case SHT_GROUP:sec_header_name = "GROUP";break;case SHT_SYMTAB_SHNDX:sec_header_name = "SYMTAB_SHNDX";break;case SHT_NUM:sec_header_name = "NUM";break;case SHT_GNU_HASH:sec_header_name = "GNU_HASH";break;case SHT_GNU_versym:sec_header_name = "VERSYM";break;case SHT_GNU_verneed:sec_header_name = "VERNEED";break;default:sec_header_name = "UnknownType";}};//獲取section段的標志flag,輸入類型對應的數值,返回字符串型的flag//因為可能同時滿足多個flag,所以根據對應位是否為1來判斷是否滿足對應的flag滿足就將flag字符串拼湊auto get_sh_flags = [](unsigned int sh_flags, string& sec_header_name) {if ((sh_flags & SHF_WRITE) >> 0)sec_header_name += "W";if ((sh_flags & SHF_ALLOC) >> 1)sec_header_name += "A";if ((sh_flags & SHF_EXECINSTR) >> 2)sec_header_name += "X";if ((sh_flags & SHF_MERGE) >> 4)sec_header_name += "M";if ((sh_flags & SHF_STRINGS) >> 5)sec_header_name += "S";if ((sh_flags & SHF_INFO_LINK) >> 6)sec_header_name += "I";if ((sh_flags & SHF_LINK_ORDER) >> 7)sec_header_name += "L";if ((sh_flags & SHF_OS_NONCONFORMING) >> 8)sec_header_name += "O";if ((sh_flags & SHF_GROUP) >> 9)sec_header_name += "G";if ((sh_flags & SHF_TLS) >> 10)sec_header_name += "T";if ((sh_flags & SHF_COMPRESSED) >> 11)sec_header_name += "C";//特殊flag因為對應的位和上面的flag對應的位不重疊,所以可以單獨處理switch (sh_flags) {case SHF_MASKOS:sec_header_name = "o";break;case SHF_MASKPROC:sec_header_name = "p";break;case SHF_EXCLUDE:sec_header_name = "E";break;}};printf(" [Nr]\tName\t\t\tType\t\tAddr\t\tOffset\t\tSize\t\t""EntSize\t\tFlags\tLink\tInfo\tAlign\n");//遍歷section_headers段表里的每個section,輸出相應的信息for (int i = 0; i < elf_header.e_shnum; i++) {printf(" [%2d]\t", i);printf("%-24s", &string_table[sec_headers[i].sh_name]);string sh_type;get_sh_type(sec_headers[i].sh_type, sh_type);printf("%-16s", sh_type.data());printf("0x%08lx\t", sec_headers[i].sh_addr);printf("0x%08lx\t", sec_headers[i].sh_offset);printf("0x%08lx\t", sec_headers[i].sh_size);printf("0x%08lx\t", sec_headers[i].sh_entsize);string sh_flags;get_sh_flags(sec_headers[i].sh_flags, sh_flags);printf("%-8s", sh_flags.data());printf("%-8d", sec_headers[i].sh_link);printf("%-8d", sec_headers[i].sh_info);printf("%-8ld", sec_headers[i].sh_addralign);printf("\n");}printf("Key to Flags:\n""\tW (write), A (alloc), X (execute), M (merge), S (strings), I (info),\n""\tL (link order), O (extra OS processing required), G (group), T (TLS),\n""\tC (compressed), x (unknown), o (OS specific), E (exclude),\n""\tl (large), p (processor specific)\n");//釋放堆內存delete[] string_table;delete[] sec_headers;fclose(fp); }

模仿readelf -s 的實現readelf_symbol.cpp

#include "header.h"void readelf_s(const char* filename) {FILE* fp;Elf64_Ehdr elf_header;fp = fopen(filename, "r");if (fp == NULL) { exit(0); }fread(&elf_header, sizeof(Elf64_Ehdr), 1, fp);if (elf_header.e_ident[0] != 0x7f || elf_header.e_ident[1] != 'E') { exit(0); }Elf64_Shdr* sec_headers = new Elf64_Shdr[elf_header.e_shnum];//存放每個section_header的數組fseek(fp, elf_header.e_shoff, SEEK_SET);//移動指針到段表對應的偏移地址fread(sec_headers, sizeof(Elf64_Shdr), elf_header.e_shnum, fp);//將段表數據讀到開辟的數組sec_headers里int str_tab_ind = elf_header.e_shstrndx;//獲取字符串表.shstrtab在段表中的索引fseek(fp, sec_headers[str_tab_ind].sh_offset, SEEK_SET);//移動指針到字符串表.shstrtab對應的偏移地址char* string_table = new char[sec_headers[str_tab_ind].sh_size];//開辟堆內存用來存放字符串表.shstrtabfread(string_table, 1, sec_headers[str_tab_ind].sh_size, fp);//將字符串表.shstrtab對應地址處的數據讀到字符串數組里int dynsym_ind = -1;//默認.dynsym符號表索引為-1int symtab_ind = -1;//默認.symtab符號表索引為-1int dynstr_ind = -1;//默認.dynstr字符串表索引為-1int strtab_ind = -1;//默認.strtab字符串索引為-1//遍歷段表section_headers獲取符號表.dynsym;.symtab;.dynstr;.strtab四張表在段表中的索引for (int i = 0; i < elf_header.e_shnum; i++) {if (sec_headers[i].sh_type == SHT_DYNSYM)//是.dynsym符號表dynsym_ind = i;else if (sec_headers[i].sh_type == SHT_SYMTAB)//是.symtab符號表symtab_ind = i;if (strcmp(&string_table[sec_headers[i].sh_name], ".strtab") == 0)//是.strtab字符串表strtab_ind = i;else if (strcmp(&string_table[sec_headers[i].sh_name], ".dynstr") == 0)//是.dynstr字符串表dynstr_ind = i;}//獲取符號表entry對應的st_info段,用來計算符號類型和綁定信息auto get_st_info = [](unsigned int st_info, string& symbol_type, string& symbol_binding) {unsigned char st_type = st_info & 0x0000000f;//低4位表示符號類型unsigned char st_binding = (st_info & (~0x0000000f)) >> 4;//高28位表示符號綁定信息switch (st_binding) {case STB_LOCAL:symbol_binding = "LOCAL";break;case STB_GLOBAL:symbol_binding = "GLOBAL";break;case STB_WEAK:symbol_binding = "WEAK";break;case STB_NUM:symbol_binding = "NUM";break;case STB_LOOS:symbol_binding = "LOOS";break;case STB_HIOS:symbol_binding = "HIOS";break;case STB_LOPROC:symbol_binding = "LOPROC";break;case STB_HIPROC:symbol_binding = "HIPROC";break;default:symbol_binding = "UnknownType";}switch (st_type) {case STT_NOTYPE:symbol_type = "NOTYPE";break;case STT_OBJECT:symbol_type = "OBJECT";break;case STT_FUNC:symbol_type = "FUNC";break;case STT_SECTION:symbol_type = "SECTION";break;case STT_FILE:symbol_type = "FILE";break;case STT_COMMON:symbol_type = "COMMON";break;case STT_TLS:symbol_type = "TLS";break;case STT_NUM:symbol_type = "NUM";break;case STT_LOOS:symbol_type = "LOOS";break;case STT_HIOS:symbol_type = "HIOS";break;case STT_LOPROC:symbol_type = "LOPROC";break;case STT_HIPROC:symbol_type = "HIPROC";break;default:symbol_type = "UnknownBinding";}};//獲取符號所在的段在段表的索引,并對特殊符號進行特殊處理auto get_st_shndx = [](unsigned int st_shndx, string& Ndx) {switch (st_shndx) {case SHN_UNDEF:Ndx = "UNDEF";break;case SHN_COMMON:Ndx = "COMMON";break;case SHN_ABS:Ndx = "ABS";break;default:Ndx = to_string(st_shndx);}};//輸出符號表信息,輸入符號表在段表中的索引sym_ind,符號表entry數目entry_num,符號表對應的字符串表string_tableauto show_symbol_table = [&](int sym_ind, unsigned long entry_num, char* string_table) {fseek(fp, sec_headers[sym_ind].sh_offset, SEEK_SET);//將指針移動到符號表對應的偏移地址Elf64_Sym* sym_entries = new Elf64_Sym[entry_num];//開辟堆內存用來存儲符號表中所有entryfread(sym_entries, sizeof(Elf64_Sym), entry_num, fp);//讀符號表printf(" Num:\t\tValue\t\tSize\tType\tBind\tVis\t""Ndx\t\tName\n");//遍歷符號表里的每個entry,并且輸出entry的信息for (int i = 0; i < entry_num; i++) {printf(" %3d:\t", i);printf("0x%016lx:\t", sym_entries[i].st_value);printf("%4ld\t", sym_entries[i].st_size);string symbol_type;string symbol_binding;get_st_info(sym_entries[i].st_info, symbol_type, symbol_binding);printf("%s\t", symbol_type.data());printf("%s\t", symbol_binding.data());printf("DEFAULT\t");string Ndx;get_st_shndx(sym_entries[i].st_shndx, Ndx);printf("%4s\t", Ndx.data());//根據entry的st_name屬性在符號表對應的字符串表表里找到entry的nameprintf("%s", &string_table[sym_entries[i].st_name]);printf("\n");}//釋放堆內存delete[] sym_entries;};//如果.dynsym段存在,且.dynstr存在if ((dynsym_ind != -1) && (dynstr_ind != -1)) {//符號表大小sec_headers[dynsym_ind].sh_size每個entry大小sec_headers[dynsym_ind].sh_entsize// 計算entry數目entry_numunsigned long entry_num = sec_headers[dynsym_ind].sh_size / sec_headers[dynsym_ind].sh_entsize;printf("Symbol table '.dynsym' contains %ld entries\n", entry_num);fseek(fp, sec_headers[dynstr_ind].sh_offset, SEEK_SET);//將指針移動到.dynstr字符串表對應的偏移地址//開辟堆內存用來存儲字符串表char* dynstr_string_table = new char[sec_headers[dynstr_ind].sh_size];//將數據讀到字符串表里fread(dynstr_string_table, 1, sec_headers[dynstr_ind].sh_size, fp);show_symbol_table(dynsym_ind, entry_num, dynstr_string_table);//釋放字符串表delete[] dynstr_string_table;} else {printf("No Dynamic linker symbol table!\n");}printf("\n");//如果.symtab段存在,且.strtab存在if ((symtab_ind != -1) && (strtab_ind != -1)) {unsigned long entry_num = sec_headers[symtab_ind].sh_size / sec_headers[symtab_ind].sh_entsize;printf("Symbol table '.symtab' contains %ld entries\n", entry_num);fseek(fp, sec_headers[strtab_ind].sh_offset, SEEK_SET);char* strtab_string_table = new char[sec_headers[strtab_ind].sh_size];fread(strtab_string_table, 1, sec_headers[strtab_ind].sh_size, fp);show_symbol_table(symtab_ind, entry_num, strtab_string_table);delete[] strtab_string_table;} else {printf("No symbol table!\n");}//釋放delete[] string_table;delete[] sec_headers;fclose(fp); }

4.使用CMake-Make編譯并執行

進入ELFReader所在目錄執行如下命令即可

./ELFReader -h filename ./ELFReader -S filename ./ELFReader -s filename

其中filename是被解析的elf文件所在路徑。

示例:

在build文件夾下執行cmake … 再make最后工程目錄結構如下,ELFReader是elf文件解析器,libMylib.so共享庫和helloworld可執行文件是待解析測試文件

. ├── build │ ├── bin │ │ ├── ELFReader │ │ ├── helloworld │ │ └── libMylib.so ...... ├── CMakeLists.txt ├── readme.md └── src├── CMakeLists.txt├── header.h├── main.cpp├── readefl_h.cpp├── readelf_s.cpp└── readelf_S.cpp

根目錄CMakeLists.txt

cmake_minimum_required(VERSION 3.10) project(ELFReader) set(CMAKE_CXX_STANDARD 11) ADD_SUBDIRECTORY(./src)

src目錄下CMakeLists.txt

cmake_minimum_required(VERSION 3.10)SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) AUX_SOURCE_DIRECTORY(./ DIR_SRCS) ADD_EXECUTABLE(ELFReader ${DIR_SRCS})

進入bin目錄并執行

cd build/bin/ ./ELFReader -h helloworld

輸出:

ELF Header:Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64Data: 2's complement, little endianVersion: 1 (current)OS/ABI: UNIX System V ABIABI Version: 0Type: DYN (Shared object file)Machine: AMD x86-64 architectureVersion: 1Entry point address: 0x00000000000010c0Start of program headers: 64 (bytes into file)Start of section headers: 36440 (bytes into file)Flags: 0x0Size of this header: 64 (bytes)Size of program headers: 56 (bytes)Number of program headers: 13Size of section headers: 64 (bytes)Number of section headers: 36Section header string table index: 35

執行-S命令

./ELFReader -S helloworld

輸出:

There are 36 section headers, starting at offset 0x8e58Section Headers:[Nr] Name Type Addr Offset Size EntSize Flags Link Info Align[ 0] NULL 0x00000000 0x00000000 0x00000000 0x00000000 0 0 0 [ 1] .interp PROGBITS 0x00000318 0x00000318 0x0000001c 0x00000000 A 0 0 1 [ 2] .note.gnu.property NOTE 0x00000338 0x00000338 0x00000020 0x00000000 A 0 0 8 [ 3] .note.gnu.build-id NOTE 0x00000358 0x00000358 0x00000024 0x00000000 A 0 0 4 [ 4] .note.ABI-tag NOTE 0x0000037c 0x0000037c 0x00000020 0x00000000 A 0 0 4 [ 5] .gnu.hash GNU_HASH 0x000003a0 0x000003a0 0x00000028 0x00000000 A 6 0 8 [ 6] .dynsym DYNSYM 0x000003c8 0x000003c8 0x00000138 0x00000018 A 7 1 8 [ 7] .dynstr STRTAB 0x00000500 0x00000500 0x00000163 0x00000000 A 0 0 1 [ 8] .gnu.version VERSYM 0x00000664 0x00000664 0x0000001a 0x00000002 A 6 0 2 [ 9] .gnu.version_r VERNEED 0x00000680 0x00000680 0x00000040 0x00000000 A 7 2 8 [10] .rela.dyn RELA 0x000006c0 0x000006c0 0x00000120 0x00000018 A 6 0 8 [11] .rela.plt RELA 0x000007e0 0x000007e0 0x00000060 0x00000018 AI 6 24 8 [12] .init PROGBITS 0x00001000 0x00001000 0x0000001b 0x00000000 AX 0 0 4 [13] .plt PROGBITS 0x00001020 0x00001020 0x00000050 0x00000010 AX 0 0 16 [14] .plt.got PROGBITS 0x00001070 0x00001070 0x00000010 0x00000010 AX 0 0 16 [15] .plt.sec PROGBITS 0x00001080 0x00001080 0x00000040 0x00000010 AX 0 0 16 [16] .text PROGBITS 0x000010c0 0x000010c0 0x00000205 0x00000000 AX 0 0 16 [17] .fini PROGBITS 0x000012c8 0x000012c8 0x0000000d 0x00000000 AX 0 0 4 [18] .rodata PROGBITS 0x00002000 0x00002000 0x00000013 0x00000000 A 0 0 4 [19] .eh_frame_hdr PROGBITS 0x00002014 0x00002014 0x00000054 0x00000000 A 0 0 4 [20] .eh_frame PROGBITS 0x00002068 0x00002068 0x00000148 0x00000000 A 0 0 8 [21] .init_array INIT_ARRAY 0x00003d78 0x00002d78 0x00000010 0x00000008 WA 0 0 8 [22] .fini_array FINI_ARRAY 0x00003d88 0x00002d88 0x00000008 0x00000008 WA 0 0 8 [23] .dynamic DYNAMIC 0x00003d90 0x00002d90 0x00000200 0x00000010 WA 7 0 8 [24] .got PROGBITS 0x00003f90 0x00002f90 0x00000070 0x00000008 WA 0 0 8 [25] .data PROGBITS 0x00004000 0x00003000 0x00000010 0x00000000 WA 0 0 8 [26] .bss NOBITS 0x00004040 0x00003010 0x00000118 0x00000000 WA 0 0 64 [27] .comment PROGBITS 0x00000000 0x00003010 0x0000002a 0x00000001 MS 0 0 1 [28] .debug_aranges PROGBITS 0x00000000 0x0000303a 0x00000030 0x00000000 0 0 1 [29] .debug_info PROGBITS 0x00000000 0x0000306a 0x00002c34 0x00000000 0 0 1 [30] .debug_abbrev PROGBITS 0x00000000 0x00005c9e 0x00000649 0x00000000 0 0 1 [31] .debug_line PROGBITS 0x00000000 0x000062e7 0x00000406 0x00000000 0 0 1 [32] .debug_str PROGBITS 0x00000000 0x000066ed 0x00001b08 0x00000001 MS 0 0 1 [33] .symtab SYMTAB 0x00000000 0x000081f8 0x00000780 0x00000018 34 55 8 [34] .strtab STRTAB 0x00000000 0x00008978 0x00000381 0x00000000 0 0 1 [35] .shstrtab STRTAB 0x00000000 0x00008cf9 0x0000015a 0x00000000 0 0 1 Key to Flags:W (write), A (alloc), X (execute), M (merge), S (strings), I (info),L (link order), O (extra OS processing required), G (group), T (TLS),C (compressed), x (unknown), o (OS specific), E (exclude),l (large), p (processor specific)

執行-s命令

./ELFReader -s helloworld

輸出:

Symbol table '.dynsym' contains 13 entriesNum: Value Size Type Bind Vis Ndx Name0: 0x0000000000000000: 0 NOTYPE LOCAL DEFAULT UNDEF 1: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_2: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF __cxa_atexit3: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc4: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZNSolsEPFRSoS_E5: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZNSt8ios_base4InitC1Ev6: 0x0000000000000000: 0 NOTYPE WEAK DEFAULT UNDEF _ITM_deregisterTMCloneTable7: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF __libc_start_main8: 0x0000000000000000: 0 NOTYPE WEAK DEFAULT UNDEF __gmon_start__9: 0x0000000000000000: 0 NOTYPE WEAK DEFAULT UNDEF _ITM_registerTMCloneTable10: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZNSt8ios_base4InitD1Ev11: 0x0000000000000000: 0 FUNC WEAK DEFAULT UNDEF __cxa_finalize12: 0x0000000000004040: 272 OBJECT GLOBAL DEFAULT 26 _ZSt4coutSymbol table '.symtab' contains 80 entriesNum: Value Size Type Bind Vis Ndx Name0: 0x0000000000000000: 0 NOTYPE LOCAL DEFAULT UNDEF 1: 0x0000000000000318: 0 SECTION LOCAL DEFAULT 1 2: 0x0000000000000338: 0 SECTION LOCAL DEFAULT 2 3: 0x0000000000000358: 0 SECTION LOCAL DEFAULT 3 4: 0x000000000000037c: 0 SECTION LOCAL DEFAULT 4 5: 0x00000000000003a0: 0 SECTION LOCAL DEFAULT 5 6: 0x00000000000003c8: 0 SECTION LOCAL DEFAULT 6 7: 0x0000000000000500: 0 SECTION LOCAL DEFAULT 7 8: 0x0000000000000664: 0 SECTION LOCAL DEFAULT 8 9: 0x0000000000000680: 0 SECTION LOCAL DEFAULT 9 10: 0x00000000000006c0: 0 SECTION LOCAL DEFAULT 10 11: 0x00000000000007e0: 0 SECTION LOCAL DEFAULT 11 12: 0x0000000000001000: 0 SECTION LOCAL DEFAULT 12 13: 0x0000000000001020: 0 SECTION LOCAL DEFAULT 13 14: 0x0000000000001070: 0 SECTION LOCAL DEFAULT 14 15: 0x0000000000001080: 0 SECTION LOCAL DEFAULT 15 16: 0x00000000000010c0: 0 SECTION LOCAL DEFAULT 16 17: 0x00000000000012c8: 0 SECTION LOCAL DEFAULT 17 18: 0x0000000000002000: 0 SECTION LOCAL DEFAULT 18 19: 0x0000000000002014: 0 SECTION LOCAL DEFAULT 19 20: 0x0000000000002068: 0 SECTION LOCAL DEFAULT 20 21: 0x0000000000003d78: 0 SECTION LOCAL DEFAULT 21 22: 0x0000000000003d88: 0 SECTION LOCAL DEFAULT 22 23: 0x0000000000003d90: 0 SECTION LOCAL DEFAULT 23 24: 0x0000000000003f90: 0 SECTION LOCAL DEFAULT 24 25: 0x0000000000004000: 0 SECTION LOCAL DEFAULT 25 26: 0x0000000000004040: 0 SECTION LOCAL DEFAULT 26 27: 0x0000000000000000: 0 SECTION LOCAL DEFAULT 27 28: 0x0000000000000000: 0 SECTION LOCAL DEFAULT 28 29: 0x0000000000000000: 0 SECTION LOCAL DEFAULT 29 30: 0x0000000000000000: 0 SECTION LOCAL DEFAULT 30 31: 0x0000000000000000: 0 SECTION LOCAL DEFAULT 31 32: 0x0000000000000000: 0 SECTION LOCAL DEFAULT 32 33: 0x0000000000000000: 0 FILE LOCAL DEFAULT ABS crtstuff.c34: 0x00000000000010f0: 0 FUNC LOCAL DEFAULT 16 deregister_tm_clones35: 0x0000000000001120: 0 FUNC LOCAL DEFAULT 16 register_tm_clones36: 0x0000000000001160: 0 FUNC LOCAL DEFAULT 16 __do_global_dtors_aux37: 0x0000000000004150: 1 OBJECT LOCAL DEFAULT 26 completed.806038: 0x0000000000003d88: 0 OBJECT LOCAL DEFAULT 22 __do_global_dtors_aux_fini_array_entry39: 0x00000000000011a0: 0 FUNC LOCAL DEFAULT 16 frame_dummy40: 0x0000000000003d78: 0 OBJECT LOCAL DEFAULT 21 __frame_dummy_init_array_entry41: 0x0000000000000000: 0 FILE LOCAL DEFAULT ABS main.cpp42: 0x0000000000002004: 1 OBJECT LOCAL DEFAULT 18 _ZStL19piecewise_construct43: 0x0000000000004151: 1 OBJECT LOCAL DEFAULT 26 _ZStL8__ioinit44: 0x00000000000011e0: 77 FUNC LOCAL DEFAULT 16 _Z41__static_initialization_and_destruction_0ii45: 0x000000000000122d: 25 FUNC LOCAL DEFAULT 16 _GLOBAL__sub_I_main46: 0x0000000000000000: 0 FILE LOCAL DEFAULT ABS crtstuff.c47: 0x00000000000021ac: 0 OBJECT LOCAL DEFAULT 20 __FRAME_END__48: 0x0000000000000000: 0 FILE LOCAL DEFAULT ABS 49: 0x0000000000002014: 0 NOTYPE LOCAL DEFAULT 19 __GNU_EH_FRAME_HDR50: 0x0000000000001000: 0 FUNC LOCAL DEFAULT 12 _init51: 0x0000000000003d90: 0 OBJECT LOCAL DEFAULT 23 _DYNAMIC52: 0x0000000000003d88: 0 NOTYPE LOCAL DEFAULT 21 __init_array_end53: 0x0000000000003d78: 0 NOTYPE LOCAL DEFAULT 21 __init_array_start54: 0x0000000000003f90: 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_55: 0x0000000000004010: 0 NOTYPE GLOBAL DEFAULT 25 _edata56: 0x0000000000004000: 0 NOTYPE WEAK DEFAULT 25 data_start57: 0x0000000000002000: 4 OBJECT GLOBAL DEFAULT 18 _IO_stdin_used58: 0x0000000000000000: 0 FUNC WEAK DEFAULT UNDEF __cxa_finalize@@GLIBC_2.2.559: 0x00000000000011a9: 55 FUNC GLOBAL DEFAULT 16 main60: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.461: 0x0000000000004008: 0 OBJECT GLOBAL DEFAULT 25 __dso_handle62: 0x00000000000012c8: 0 FUNC GLOBAL DEFAULT 17 _fini63: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF __cxa_atexit@@GLIBC_2.2.564: 0x00000000000010c0: 47 FUNC GLOBAL DEFAULT 16 _start65: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.466: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZNSolsEPFRSoS_E@@GLIBCXX_3.467: 0x0000000000004010: 0 OBJECT GLOBAL DEFAULT 25 __TMC_END__68: 0x0000000000004040: 272 OBJECT GLOBAL DEFAULT 26 _ZSt4cout@@GLIBCXX_3.469: 0x0000000000004000: 0 NOTYPE GLOBAL DEFAULT 25 __data_start70: 0x0000000000004158: 0 NOTYPE GLOBAL DEFAULT 26 _end71: 0x0000000000004010: 0 NOTYPE GLOBAL DEFAULT 26 __bss_start72: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.473: 0x0000000000001250: 101 FUNC GLOBAL DEFAULT 16 __libc_csu_init74: 0x0000000000000000: 0 NOTYPE WEAK DEFAULT UNDEF _ITM_deregisterTMCloneTable75: 0x00000000000012c0: 5 FUNC GLOBAL DEFAULT 16 __libc_csu_fini76: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF __libc_start_main@@GLIBC_2.2.577: 0x0000000000000000: 0 NOTYPE WEAK DEFAULT UNDEF __gmon_start__78: 0x0000000000000000: 0 NOTYPE WEAK DEFAULT UNDEF _ITM_registerTMCloneTable79: 0x0000000000000000: 0 FUNC GLOBAL DEFAULT UNDEF _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4

參考文章

ELF文件結構描述 - yooooooo - 博客園 (cnblogs.com)

Linux系統中編譯、鏈接的基石-ELF文件:扒開它的層層外衣,從字節碼的粒度來探索 (qq.com)

C/C++ 實現ELF結構解析工具 - lyshark - 博客園 (cnblogs.com)

C語言實現ELF文件解析_Yuhan的博客-CSDN博客_elf文件讀取

《程序員的自我修養——鏈接、裝載與庫》俞甲子,石凡,潘愛民

總結

以上是生活随笔為你收集整理的ELF文件解析器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。