02 elf 的 binary 解析

前言

需求来自于 linux binary 的执行分析, 以及一些反编译工具的实现 

比如 readelf, hopper disassemble 什么的 

主要的目的是 更加详细了解 elf 的文件格式 

为 后续的一些 理解做准备 

elf 解析 

elf 文件主要分为 四个部分 

elfHeader, programHeaders, segments, segmentHeaders

我们这里查看的 elf 为一个  简单的 HelloWorld 生成的一个 elf 文件 

#include "stdio.h"

int main(int argc, char** argv) {

int x = 2;
int y = 3;
int z = x + y;

printf(" x + y = %d\n ", z);

}

readelf 解析如下 

root@ubuntu:~# readelf -a Test01Sum 
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400430
  Start of program headers:          64 (bytes into file)
  Start of section headers:          6624 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 28

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8
       0000000000000060  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000400318  00000318
       000000000000003f  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400358  00000358
       0000000000000008  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400360  00000360
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000400380  00000380
       0000000000000018  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000400398  00000398
       0000000000000030  0000000000000018  AI       5    24     8
  [11] .init             PROGBITS         00000000004003c8  000003c8
       000000000000001a  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         00000000004003f0  000003f0
       0000000000000030  0000000000000010  AX       0     0     16
  [13] .plt.got          PROGBITS         0000000000400420  00000420
       0000000000000008  0000000000000000  AX       0     0     8
  [14] .text             PROGBITS         0000000000400430  00000430
       00000000000001b2  0000000000000000  AX       0     0     16
  [15] .fini             PROGBITS         00000000004005e4  000005e4
       0000000000000009  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         00000000004005f0  000005f0
       0000000000000012  0000000000000000   A       0     0     4
  [17] .eh_frame_hdr     PROGBITS         0000000000400604  00000604
       0000000000000034  0000000000000000   A       0     0     4
  [18] .eh_frame         PROGBITS         0000000000400638  00000638
       00000000000000f4  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       0000000000600e10  00000e10
       0000000000000008  0000000000000000  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .jcr              PROGBITS         0000000000600e20  00000e20
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .dynamic          DYNAMIC          0000000000600e28  00000e28
       00000000000001d0  0000000000000010  WA       6     0     8
  [23] .got              PROGBITS         0000000000600ff8  00000ff8
       0000000000000008  0000000000000008  WA       0     0     8
  [24] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000028  0000000000000008  WA       0     0     8
  [25] .data             PROGBITS         0000000000601028  00001028
       0000000000000010  0000000000000000  WA       0     0     8
  [26] .bss              NOBITS           0000000000601038  00001038
       0000000000000008  0000000000000000  WA       0     0     1
  [27] .comment          PROGBITS         0000000000000000  00001038
       0000000000000035  0000000000000001  MS       0     0     1
  [28] .shstrtab         STRTAB           0000000000000000  000018d2
       000000000000010c  0000000000000000           0     0     1
  [29] .symtab           SYMTAB           0000000000000000  00001070
       0000000000000648  0000000000000018          30    47     8
  [30] .strtab           STRTAB           0000000000000000  000016b8
       000000000000021a  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x000000000000072c 0x000000000000072c  R E    200000
  LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                 0x0000000000000228 0x0000000000000230  RW     200000
  DYNAMIC        0x0000000000000e28 0x0000000000600e28 0x0000000000600e28
                 0x00000000000001d0 0x00000000000001d0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x0000000000000604 0x0000000000400604 0x0000000000400604
                 0x0000000000000034 0x0000000000000034  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                 0x00000000000001f0 0x00000000000001f0  R      1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 
   03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 
   04     .dynamic 
   05     .note.ABI-tag .note.gnu.build-id 
   06     .eh_frame_hdr 
   07     
   08     .init_array .fini_array .jcr .dynamic .got 

Dynamic section at offset 0xe28 contains 24 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000c (INIT)               0x4003c8
 0x000000000000000d (FINI)               0x4005e4
 0x0000000000000019 (INIT_ARRAY)         0x600e10
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x600e18
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x400298
 0x0000000000000005 (STRTAB)             0x400318
 0x0000000000000006 (SYMTAB)             0x4002b8
 0x000000000000000a (STRSZ)              63 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x601000
 0x0000000000000002 (PLTRELSZ)           48 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x400398
 0x0000000000000007 (RELA)               0x400380
 0x0000000000000008 (RELASZ)             24 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x400360
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x400358
 0x0000000000000000 (NULL)               0x0

Relocation section '.rela.dyn' at offset 0x380 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000600ff8  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0

Relocation section '.rela.plt' at offset 0x398 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000601018  000100000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
000000601020  000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table '.dynsym' contains 4 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

Symbol table '.symtab' contains 67 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000400238     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000400254     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000400274     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000400298     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000004002b8     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000400318     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000400358     0 SECTION LOCAL  DEFAULT    7 
     8: 0000000000400360     0 SECTION LOCAL  DEFAULT    8 
     9: 0000000000400380     0 SECTION LOCAL  DEFAULT    9 
    10: 0000000000400398     0 SECTION LOCAL  DEFAULT   10 
    11: 00000000004003c8     0 SECTION LOCAL  DEFAULT   11 
    12: 00000000004003f0     0 SECTION LOCAL  DEFAULT   12 
    13: 0000000000400420     0 SECTION LOCAL  DEFAULT   13 
    14: 0000000000400430     0 SECTION LOCAL  DEFAULT   14 
    15: 00000000004005e4     0 SECTION LOCAL  DEFAULT   15 
    16: 00000000004005f0     0 SECTION LOCAL  DEFAULT   16 
    17: 0000000000400604     0 SECTION LOCAL  DEFAULT   17 
    18: 0000000000400638     0 SECTION LOCAL  DEFAULT   18 
    19: 0000000000600e10     0 SECTION LOCAL  DEFAULT   19 
    20: 0000000000600e18     0 SECTION LOCAL  DEFAULT   20 
    21: 0000000000600e20     0 SECTION LOCAL  DEFAULT   21 
    22: 0000000000600e28     0 SECTION LOCAL  DEFAULT   22 
    23: 0000000000600ff8     0 SECTION LOCAL  DEFAULT   23 
    24: 0000000000601000     0 SECTION LOCAL  DEFAULT   24 
    25: 0000000000601028     0 SECTION LOCAL  DEFAULT   25 
    26: 0000000000601038     0 SECTION LOCAL  DEFAULT   26 
    27: 0000000000000000     0 SECTION LOCAL  DEFAULT   27 
    28: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    29: 0000000000600e20     0 OBJECT  LOCAL  DEFAULT   21 __JCR_LIST__
    30: 0000000000400460     0 FUNC    LOCAL  DEFAULT   14 deregister_tm_clones
    31: 00000000004004a0     0 FUNC    LOCAL  DEFAULT   14 register_tm_clones
    32: 00000000004004e0     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
    33: 0000000000601038     1 OBJECT  LOCAL  DEFAULT   26 completed.7594
    34: 0000000000600e18     0 OBJECT  LOCAL  DEFAULT   20 __do_global_dtors_aux_fin
    35: 0000000000400500     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
    36: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   19 __frame_dummy_init_array_
    37: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS Test01Sum.c
    38: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    39: 0000000000400728     0 OBJECT  LOCAL  DEFAULT   18 __FRAME_END__
    40: 0000000000600e20     0 OBJECT  LOCAL  DEFAULT   21 __JCR_END__
    41: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 
    42: 0000000000600e18     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_end
    43: 0000000000600e28     0 OBJECT  LOCAL  DEFAULT   22 _DYNAMIC
    44: 0000000000600e10     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_start
    45: 0000000000400604     0 NOTYPE  LOCAL  DEFAULT   17 __GNU_EH_FRAME_HDR
    46: 0000000000601000     0 OBJECT  LOCAL  DEFAULT   24 _GLOBAL_OFFSET_TABLE_
    47: 00000000004005e0     2 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
    48: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
    49: 0000000000601028     0 NOTYPE  WEAK   DEFAULT   25 data_start
    50: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   25 _edata
    51: 00000000004005e4     0 FUNC    GLOBAL DEFAULT   15 _fini
    52: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.5
    53: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    54: 0000000000601028     0 NOTYPE  GLOBAL DEFAULT   25 __data_start
    55: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    56: 0000000000601030     0 OBJECT  GLOBAL HIDDEN    25 __dso_handle
    57: 00000000004005f0     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
    58: 0000000000400570   101 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
    59: 0000000000601040     0 NOTYPE  GLOBAL DEFAULT   26 _end
    60: 0000000000400430    42 FUNC    GLOBAL DEFAULT   14 _start
    61: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   26 __bss_start
    62: 0000000000400526    67 FUNC    GLOBAL DEFAULT   14 main
    63: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    64: 0000000000601038     0 OBJECT  GLOBAL HIDDEN    25 __TMC_END__
    65: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    66: 00000000004003c8     0 FUNC    GLOBAL DEFAULT   11 _init

Version symbols section '.gnu.version' contains 4 entries:
 Addr: 0000000000400358  Offset: 0x000358  Link: 5 (.dynsym)
  000:   0 (*local*)       2 (GLIBC_2.2.5)   2 (GLIBC_2.2.5)   0 (*local*)    

Version needs section '.gnu.version_r' contains 1 entries:
 Addr: 0x0000000000400360  Offset: 0x000360  Link: 6 (.dynstr)
  000000: Version: 1  File: libc.so.6  Cnt: 1
  0x0010:   Name: GLIBC_2.2.5  Flags: none  Version: 2

Displaying notes found at file offset 0x00000254 with length 0x00000020:
  Owner                 Data size	Description
  GNU                  0x00000010	NT_GNU_ABI_TAG (ABI version tag)
    OS: Linux, ABI: 2.6.32

Displaying notes found at file offset 0x00000274 with length 0x00000024:
  Owner                 Data size	Description
  GNU                  0x00000014	NT_GNU_BUILD_ID (unique build ID bitstring)
    Build ID: 676de8fa9bce03059433028da409bb25c151f668

hopper disassemble 解析如下, 截取片段 

相关实体

ElfFile 

/**
 * ElfFile
 *
 * @author Jerry.X.He <[email protected]>
 * @version 1.0
 * @date 2022-09-25 11:08
 */
@Data
public class ElfFile implements Serializable {

    private ElfHeader header;
    private List<ElfProgramHeader> programHeaders;
    private Integer[] sectionBytes;
    private List<ElfSegment> segments;
    private List<ElfSectionHeader> sectionHeaders;

    @Field(sort = 0, name = "header", dataType = DataType.GENERIC_BEAN, desc = "header", version = {1})
    public ElfHeader getHeader() {
        return header;
    }

    @Field(sort = 10, name = "programHeaders", dataType = DataType.GENERIC_BEAN_COLLECTION, desc = "programHeaders", version = {1})
    public List<ElfProgramHeader> getprogramHeaders() {
        return programHeaders;
    }

    @Field(sort = 20, name = "sectionBytes", dataType = DataType.BYTE_ARRAY, desc = "sectionBytes", version = {1})
    public Integer[] getSectionBytes() {
        return sectionBytes;
    }

    public void setSegments(List<ElfSegment> segments) {
        this.segments = segments;
    }

    @Field(sort = 30, name = "sectionHeaders", dataType = DataType.GENERIC_BEAN_COLLECTION, desc = "sectionHeaders", version = {1})
    public List<ElfSectionHeader> getSectionHeaders() {
        return sectionHeaders;
    }

}

ElfHeader

/**
 * ElfHeader
 *
 * @author Jerry.X.He <[email protected]>
 * @version 1.0
 * @date 2022-09-25 11:08
 */
@Data
public class ElfHeader implements Serializable {

    private String ident;
    private Integer type;
    private Integer machine;
    private Integer version;
    private Long entry;
    private Long phoff;
    private Long shoff;
    private Integer flags;
    private Integer ehsize;
    private Integer phentsize;
    private Integer phnum;
    private Integer shentsize;
    private Integer shnum;
    private Integer shstrndx;

    private Long offsetInFile;

    @Field(sort = 0, name = "ident", dataType = DataType.CHARSET_ENCODING_WITH_FIXED_LEN_STRING, lengthInBytes = 16, desc = "ident", version = {1})
    public String getIdent() {
        return ident;
    }

    @Field(sort = 10, name = "type", dataType = DataType.UNSIGNED_WORD, desc = "type", bigEndian = false, version = {1})
    public Integer getType() {
        return type;
    }

    @Field(sort = 20, name = "machine", dataType = DataType.UNSIGNED_WORD, desc = "machine", bigEndian = false, version = {1})
    public Integer getMachine() {
        return machine;
    }

    @Field(sort = 30, name = "version", dataType = DataType.DWORD, desc = "version", bigEndian = false, version = {1})
    public Integer getVersion() {
        return version;
    }

    @Field(sort = 40, name = "entry", dataType = DataType.QWORD, desc = "entry", bigEndian = false, version = {1})
    public Long getEntry() {
        return entry;
    }

    @Field(sort = 50, name = "phoff", dataType = DataType.QWORD, desc = "phoff", bigEndian = false, version = {1})
    public Long getPhoff() {
        return phoff;
    }

    @Field(sort = 60, name = "shoff", dataType = DataType.QWORD, desc = "shoff", bigEndian = false, version = {1})
    public Long getShoff() {
        return shoff;
    }

    @Field(sort = 70, name = "flags", dataType = DataType.DWORD, desc = "flags", bigEndian = false, version = {1})
    public Integer getFlags() {
        return flags;
    }

    @Field(sort = 80, name = "ehsize", dataType = DataType.UNSIGNED_WORD, desc = "ehsize", bigEndian = false, version = {1})
    public Integer getEhsize() {
        return ehsize;
    }

    @Field(sort = 90, name = "phentsize", dataType = DataType.UNSIGNED_WORD, desc = "phentsize", bigEndian = false, version = {1})
    public Integer getPhentsize() {
        return phentsize;
    }

    @Field(sort = 100, name = "phnum", dataType = DataType.UNSIGNED_WORD, desc = "phnum", bigEndian = false, version = {1})
    public Integer getPhnum() {
        return phnum;
    }

    @Field(sort = 110, name = "shentsize", dataType = DataType.UNSIGNED_WORD, desc = "shentsize", bigEndian = false, version = {1})
    public Integer getShentsize() {
        return shentsize;
    }

    @Field(sort = 120, name = "shnum", dataType = DataType.UNSIGNED_WORD, desc = "shnum", bigEndian = false, version = {1})
    public Integer getShnum() {
        return shnum;
    }

    @Field(sort = 130, name = "shstrndx", dataType = DataType.UNSIGNED_WORD, desc = "shstrndx", bigEndian = false, version = {1})
    public Integer getShstrndx() {
        return shstrndx;
    }

    public JSONObject getHexRelated() {
        JSONObject result = new JSONObject();
        result.put("entry", "0x" + Long.toHexString(entry));
        result.put("phoff", "0x" + Long.toHexString(phoff));
        result.put("shoff", "0x" + Long.toHexString(shoff));
        return result;
    }

    public String toString() {
        return JSON.toJSONString(this);
    }

}

ElfProgramHeader

/**
 * ElfPhHeader
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 10:18
 */
@Data
public class ElfProgramHeader implements Serializable {

    private Integer type;
    private Integer flags;
    private Long offset;
    private Long vaddr;
    private Long paddr;
    private Long fileSz;
    private Long memSz;
    private Long align;

    private Long offsetInFile;

    @Field(sort = 0, name = "type", dataType = DataType.DWORD, desc = "type", bigEndian = false, version = {1})
    public Integer getType() {
        return type;
    }

    @Field(sort = 10, name = "flags", dataType = DataType.DWORD, desc = "flags", bigEndian = false, version = {1})
    public Integer getFlags() {
        return flags;
    }

    @Field(sort = 20, name = "offset", dataType = DataType.QWORD, desc = "offset", bigEndian = false, version = {1})
    public Long getOffset() {
        return offset;
    }

    @Field(sort = 30, name = "vaddr", dataType = DataType.QWORD, desc = "vaddr", bigEndian = false, version = {1})
    public Long getVaddr() {
        return vaddr;
    }

    @Field(sort = 40, name = "paddr", dataType = DataType.QWORD, desc = "paddr", bigEndian = false, version = {1})
    public Long getPaddr() {
        return paddr;
    }

    @Field(sort = 50, name = "fileSz", dataType = DataType.QWORD, desc = "fileSz", bigEndian = false, version = {1})
    public Long getFileSz() {
        return fileSz;
    }

    @Field(sort = 60, name = "memSz", dataType = DataType.QWORD, desc = "memSz", bigEndian = false, version = {1})
    public Long getMemSz() {
        return memSz;
    }

    @Field(sort = 70, name = "align", dataType = DataType.QWORD, desc = "align", bigEndian = false, version = {1})
    public Long getAlign() {
        return align;
    }

    public JSONObject getHexRelated() {
        JSONObject result = new JSONObject();
        result.put("offset", "0x" + Long.toHexString(offset));
        result.put("vaddr", "0x" + Long.toHexString(vaddr));
        result.put("paddr", "0x" + Long.toHexString(paddr));
        result.put("fileSz", "0x" + Long.toHexString(fileSz));
        result.put("memSz", "0x" + Long.toHexString(memSz));
        result.put("offsetInFile", "0x" + Long.toHexString(offsetInFile));
        return result;
    }

    public String toString() {
        return JSON.toJSONString(this);
    }

}

ElfSegment

/**
 * ElfSegment
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 14:30
 */
@Data
public class ElfSegment implements Serializable {

    protected String name;

    protected Integer[] bytes;

    protected Long offsetInFile;

    @Override
    public String toString() {
        List<String> toStringNames = Arrays.asList(".comment", ".dynstr", ".shstrtab", ".strtab");
        if (toStringNames.contains(name)) {
            return name + " " + ElfFileCodec.formatOffset(getOffsetInFile()) + " " + new String(ElfFileCodec.transferBytes(bytes));
        }

        return name + " " + ElfFileCodec.formatOffset(getOffsetInFile()) + " " + ElfFileCodec.toString(bytes);
    }

}

ElfSectionHeader 

/**
 * ElfPhHeader
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 10:18
 */
@Data
public class ElfSectionHeader implements Serializable {

    private Integer name;
    private Integer type;
    private Long flags;
    private Long address;
    private Long offset;
    private Long size;
    private Integer link;
    private Integer info;
    private Long addrAlign;
    private Long entrySize;

    @Field(sort = 0, name = "name", dataType = DataType.DWORD, desc = "name", bigEndian = false, version = {1})
    public Integer getName() {
        return name;
    }

    @Field(sort = 10, name = "type", dataType = DataType.DWORD, desc = "type", bigEndian = false, version = {1})
    public Integer getType() {
        return type;
    }

    @Field(sort = 20, name = "flags", dataType = DataType.QWORD, desc = "flags", bigEndian = false, version = {1})
    public Long getFlags() {
        return flags;
    }

    @Field(sort = 30, name = "address", dataType = DataType.QWORD, desc = "address", bigEndian = false, version = {1})
    public Long getAddress() {
        return address;
    }

    @Field(sort = 40, name = "offset", dataType = DataType.QWORD, desc = "offset", bigEndian = false, version = {1})
    public Long getOffset() {
        return offset;
    }

    @Field(sort = 50, name = "size", dataType = DataType.QWORD, desc = "size", bigEndian = false, version = {1})
    public Long getSize() {
        return size;
    }

    @Field(sort = 60, name = "link", dataType = DataType.DWORD, desc = "link", bigEndian = false, version = {1})
    public Integer getLink() {
        return link;
    }

    @Field(sort = 70, name = "info", dataType = DataType.DWORD, desc = "info", bigEndian = false, version = {1})
    public Integer getInfo() {
        return info;
    }

    @Field(sort = 80, name = "addrAlign", dataType = DataType.QWORD, desc = "addrAlign", bigEndian = false, version = {1})
    public Long getAddrAlign() {
        return addrAlign;
    }

    @Field(sort = 90, name = "entrySize", dataType = DataType.QWORD, desc = "entrySize", bigEndian = false, version = {1})
    public Long getEntrySize() {
        return entrySize;
    }

    public JSONObject getHexRelated() {
        JSONObject result = new JSONObject();
        result.put("address", "0x" + Long.toHexString(address));
        result.put("offset", "0x" + Long.toHexString(offset));
        result.put("size", "0x" + Long.toHexString(size));
        result.put("entrySize", "0x" + Long.toHexString(entrySize));
        return result;
    }

    public String toString() {
        return JSON.toJSONString(this);
    }

}

ElfSegment 有多类实现, 这里不一一列举 

ElfNoteSegment

/**
 * ElfInterpSegment
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 14:31
 */
@Data
@ToString(callSuper = true)
public class ElfNoteSegment extends ElfSegment {

    private Integer nameSize;
    private Integer descSize;
    private Integer type;
    private String nameInNote;
    private Integer[] desc;

}

ElfDynamicSymSegment

/**
 * ElfDynamicSymSegment
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 14:31
 */
@Data
@ToString(callSuper = true)
public class ElfDynamicSymSegment extends ElfSegment {

    private List<ElfSymTabElement> list;

    @Field(sort = 0, name = "list", dataType = DataType.GENERIC_BEAN_COLLECTION, desc = "list", version = {1})
    public List<ElfSymTabElement> getList() {
        return list;
    }

}


/**
 * ElfSymTabElement
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 14:31
 */
@Data
public class ElfSymTabElement {

    private String name;
    // 4bytes
    private Integer nameIdx;
    // 1byte, bind + type
    private Integer info;
    // 1byte, 可见属性
    private Integer other;

    // segment idx
    private Integer shNIdx;
    // 8bytes
    private Long value;
    // 8bytes
    private Long size;


    @Field(sort = 0, name = "nameIdx", dataType = DataType.DWORD, desc = "nameIdx", bigEndian = false, version = {1})
    public Integer getNameIdx() {
        return nameIdx;
    }

    @Field(sort = 10, name = "info", dataType = DataType.BYTE, desc = "info", bigEndian = false, version = {1})
    public Integer getInfo() {
        return info;
    }

    @Field(sort = 20, name = "other", dataType = DataType.BYTE, desc = "other", bigEndian = false, version = {1})
    public Integer getOther() {
        return other;
    }

    @Field(sort = 30, name = "shNIdx", dataType = DataType.WORD, desc = "shNIdx", bigEndian = false, version = {1})
    public Integer getShNIdx() {
        return shNIdx;
    }

    @Field(sort = 40, name = "value", dataType = DataType.QWORD, desc = "value", bigEndian = false, version = {1})
    public Long getValue() {
        return value;
    }

    @Field(sort = 50, name = "size", dataType = DataType.QWORD, desc = "size", bigEndian = false, version = {1})
    public Long getSize() {
        return size;
    }

    @Override
    public String toString() {
        JSONObject result = new JSONObject();
        result.put("name", name);
        result.put("info", info);
        result.put("other", other);
        result.put("shNIdx", shNIdx);
        result.put("value", Long.toHexString(value));
        result.put("size", size);
        return result.toString();
    }
}

相关实体的编码解码如下 

ElfFileCodec

/**
 * ElfFileCodec
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 10:23
 */
public class ElfFileCodec extends AbstractCodec<ElfFile, ElfFile> {

    private AbstractCodec<ElfHeader, ElfHeader> headerCodec = CodecUtils.createCodecForClazz(ElfHeader.class, 1);
    private AbstractCodec<ElfProgramHeader, ElfProgramHeader> phHeaderCodec = CodecUtils.createCodecForClazz(ElfProgramHeader.class, 1);
    private AbstractCodec<ElfSectionHeader, ElfSectionHeader> sectionHeaderCodec = CodecUtils.createCodecForClazz(ElfSectionHeader.class, 1);
    private ElfSegmentCodec segmentCodec = new ElfSegmentCodec();

    @Override
    public void encode(ElfFile entity, ByteBuf buf) {

    }

    @Override
    public ElfFile decode(ByteBuf buf) {
        debugCurrentBufReaderIdx(buf, "before elf header codec");
        long offsetInFile = buf.readerIndex();
        ElfHeader header = headerCodec.decode(buf);
        header.setOffsetInFile(offsetInFile);
        debugCurrentBufReaderIdx(buf, "after elf header codec");
        int programNum = header.getPhnum(), sectionNum = header.getShnum();
        int sectionHeaderSz = sectionHeaderCodec.length() * sectionNum;

        debugCurrentBufReaderIdx(buf, "before program header codec");
        List<ElfProgramHeader> programHeaders = new ArrayList<>();
        for (int i = 0; i < programNum; i++) {
            offsetInFile = buf.readerIndex();
            ElfProgramHeader phHeader = phHeaderCodec.decode(buf);
            phHeader.setOffsetInFile(offsetInFile);
            programHeaders.add(phHeader);
        }
        debugCurrentBufReaderIdx(buf, "after program header codec");

        debugCurrentBufReaderIdx(buf, "before sections codec");
        int allRemaining = buf.readableBytes();
        int sectionBytesSz = allRemaining - sectionHeaderSz;
        ByteArrayWithExactlyLenCodec byteArrayCodec = new ByteArrayWithExactlyLenCodec(sectionBytesSz);
        Integer[] sectionBytesInInteger = byteArrayCodec.decode(buf);
        debugCurrentBufReaderIdx(buf, "after sections codec");

        debugCurrentBufReaderIdx(buf, "before section header codec");
        List<ElfSectionHeader> sectionHeaders = new ArrayList<>();
        for (int i = 0; i < sectionNum; i++) {
            sectionHeaders.add(sectionHeaderCodec.decode(buf));
        }
        debugCurrentBufReaderIdx(buf, "after section header codec");

        // section headers
        List<ElfSegment> segments = new ArrayList<>();
        for (ElfSectionHeader secHeader : sectionHeaders) {
            int sectionSize = secHeader.getSize().intValue();
            ByteArrayWithExactlyLenCodec sectionByteArrayCodec = new ByteArrayWithExactlyLenCodec(sectionSize);
            Integer[] sectionBytes = new Integer[]{};
            if (secHeader.getOffset() > 0) {
                buf.readerIndex(secHeader.getOffset().intValue());
                sectionBytes = (sectionByteArrayCodec.decode(buf));
            }

            segmentCodec.setSecHeader(secHeader);
            ElfSegment elfSegment = segmentCodec.decode(Unpooled.wrappedBuffer(transferBytes(sectionBytes)));
            elfSegment.setBytes(sectionBytes);
            elfSegment.setOffsetInFile(secHeader.getOffset());
            segments.add(elfSegment);
        }

        // resolve xx names
        resolveRelatedNames(header, sectionHeaders, segments);

        ElfFile result = new ElfFile();
        result.setHeader(header);
        result.setProgramHeaders(programHeaders);
        result.setSectionBytes(sectionBytesInInteger);
        result.setSegments(segments);
        result.setSectionHeaders(sectionHeaders);
        return result;
    }

    private void resolveRelatedNames(ElfHeader header, List<ElfSectionHeader> sectionHeaders, List<ElfSegment> segments) {
        ElfSegment segStrTab = segments.get(header.getShstrndx());
        // fill segment name
        for (int i = 0; i < segments.size(); i++) {
            ElfSegment segment = segments.get(i);
            ElfSectionHeader secHeader = sectionHeaders.get(i);
            String segName = lookStringInStrTab(segStrTab.getBytes(), secHeader.getName());
            segment.setName(segName);
        }

        ElfDynStrSegment strTab = (ElfDynStrSegment) lookUpSegment(segments, ".strtab");
        ElfDynStrSegment dynStrTab = (ElfDynStrSegment) lookUpSegment(segments, ".dynstr");
        // fill symtab name
        ElfSymTabSegment symTab = (ElfSymTabSegment) lookUpSegment(segments, ".symtab");
        for (int i = 0; i < symTab.getList().size(); i++) {
            ElfSymTabElement symtabEle = symTab.getList().get(i);
            String eleName = lookStringInStrTab(strTab.getBytes(), symtabEle.getNameIdx());
            symtabEle.setName(eleName);
        }

        // fill dynsym name
        ElfDynamicSymSegment dynSymTab = (ElfDynamicSymSegment) lookUpSegment(segments, ".dynsym");
        for (int i = 0; i < dynSymTab.getList().size(); i++) {
            ElfSymTabElement symtabEle = dynSymTab.getList().get(i);
            String eleName = lookStringInStrTab(dynStrTab.getBytes(), symtabEle.getNameIdx());
            symtabEle.setName(eleName);
        }

        // rela.dyn
        ElfRelaSegment relaDynTab = (ElfRelaSegment) lookUpSegment(segments, ".rela.dyn");
        for (int i = 0; i < relaDynTab.getList().size(); i++) {
            ElfRelaElement symtabEle = relaDynTab.getList().get(i);
            String eleName = dynStrTab.getList().get(symtabEle.getNameIdx());
            symtabEle.setName(eleName);
        }

        // rela.plt
        ElfRelaSegment relaPltTab = (ElfRelaSegment) lookUpSegment(segments, ".rela.plt");
        for (int i = 0; i < relaPltTab.getList().size(); i++) {
            ElfRelaElement symtabEle = relaPltTab.getList().get(i);
            String eleName = dynStrTab.getList().get(symtabEle.getNameIdx());
            symtabEle.setName(eleName);
        }

    }

    public static ElfSegment lookUpSegment(List<ElfSegment> segments, String name) {
        for (ElfSegment segment : segments) {
            if (Objects.equals(name, segment.getName())) {
                return segment;
            }
        }
        return null;
    }

    public static byte[] transferBytes(Integer[] bytes) {
        byte[] result = new byte[bytes.length];
        int idx = 0;
        for (Integer b : bytes) {
            result[idx++] = b.byteValue();
        }
        return result;
    }

    public static String formatOffset(Long offset) {
        return String.format("0x00%s", Long.toHexString(offset));
    }

    public static String toString(Integer[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String part = ByteBufUtil.hexDump(
                    new byte[]{bytes[i].byteValue()}
            );
            sb.append(" ");
            sb.append(part);
        }
        return sb.toString();
    }

    public static String toAddress(Integer[] bytes) {
        StringBuilder sb = new StringBuilder();
        sb.append("0x");
        for (int i = bytes.length - 1; i >= 0; i--) {
            String part = ByteBufUtil.hexDump(
                    new byte[]{bytes[i].byteValue()}
            );
            sb.append(" ");
            sb.append(part);
        }
        return sb.toString();
    }

    public static String lookStringInStrTab(Integer[] bytes, int offset) {
        StringBuilder sb = new StringBuilder();
        for (int i = offset; i < bytes.length; i++) {
            if (bytes[i] == 0x00) {
                break;
            }
            sb.append((char) bytes[i].intValue());
        }
        return sb.toString();
    }

    @Override
    public boolean isFixedLength() {
        return false;
    }

    @Override
    public int length() {
        return 0;
    }

    public void debugCurrentBufReaderIdx(ByteBuf buf, String title) {
        System.out.println(title + " -> " + buf.readerIndex() + " - 0x" + Integer.toHexString(buf.readerIndex()));
    }

}

ElfSegment 有多类实现, 这里不一一列举 

ElfNoteSegmentCodec

/**
 * ElfAbiTagSegmentCodec
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 14:34
 */
public class ElfNoteSegmentCodec extends AbstractCodec<ElfNoteSegment, ElfNoteSegment> {

    private DWordCodec dWordCodec = new DWordCodec(ByteOrder.LITTLE_ENDIAN);
    private CharsetEncodingStringCodec stringCodec = new CharsetEncodingStringCodec(Constants.CHARSET_UTF8);

    @Override
    public void encode(ElfNoteSegment entity, ByteBuf buf) {

    }

    @Override
    public ElfNoteSegment decode(ByteBuf buf) {
        Integer nameSize = dWordCodec.decode(buf);
        Integer descSize = dWordCodec.decode(buf);
        Integer type = dWordCodec.decode(buf);

        CharsetEncodingStringWithFixedLenCodec nameCodec = new CharsetEncodingStringWithFixedLenCodec(nameSize);
        String name = nameCodec.decode(buf);

        ByteArrayWithFixedLenCodec descCodec = new ByteArrayWithFixedLenCodec(descSize);
        Integer[] desc = descCodec.decode(buf);

        ElfNoteSegment result = new ElfNoteSegment();
        result.setNameSize(nameSize);
        result.setDescSize(descSize);
        result.setType(type);
        result.setNameInNote(name);
        result.setDesc(desc);
        return result;
    }

    @Override
    public boolean isFixedLength() {
        return false;
    }

    @Override
    public int length() {
        return 0;
    }
}

ElfDynamicSymSegmentCodec

/**
 * ElfDynamicSymSegmentCodec
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2022/9/27 14:34
 */
public class ElfDynamicSymSegmentCodec extends AbstractCodec<ElfDynamicSymSegment, ElfDynamicSymSegment> {

    AbstractCodec<ElfDynamicSymSegment, ElfDynamicSymSegment> codec = CodecUtils.createCodecForClazz(ElfDynamicSymSegment.class, 1);

    @Override
    public void encode(ElfDynamicSymSegment entity, ByteBuf buf) {

    }

    @Override
    public ElfDynamicSymSegment decode(ByteBuf buf) {
        return codec.decode(buf);
    }

    @Override
    public boolean isFixedLength() {
        return false;
    }

    @Override
    public int length() {
        return 0;
    }
}

解析结果

猜你喜欢

转载自blog.csdn.net/u011039332/article/details/127459759