ELF 文件格式

segments(runtime) & sections(link time)
A segment points to an absolute address in the memory, and specify how many bytes are contained in that segment. The section works in a similar way, and if and the memory segment and section pointing to can have overlaps.

The segment also specifies where the memory should be loaded into virtual or physical memory. Segment tells OS how to map parts of ELF file into memory.

Executable -> at least has two segments: data segment(initialized globals and other initialized data, and usually use space more than it required for uninitialized data), and code segment(executable code will be loaded into memory).

ELF 文件格式

Convert executable file to txt file in hex:

gcc hello.c -o hello
hexdump -C hello > output.txt

# or in linux
readelf -h hello
# in mac
greadelf -a hello  

ELF 文件格式
First 16 bytes is corresponding to e_ident[EI_NIDENT]. The first 4 bytes represent a magic number, which is same for all elf file. The next byte specify the class of ELF : 0 = None(invalid), 1 = 32bits Object, 2 = 64bits Object. The 6th byte indicates is the least significant byte or most significant byte come first. The following bytes are for Version, OS ABI, ABI version and zero padding.

#define EI_NIDENT 16

 // Elf32_Half -> uint16_t
 // Elf32_Word -> uint32_t
 // Elf32_Addr -> uint32_t
 // Elf64_Addr -> uint64_t
 // Elf32_Off -> uint32_t
 // Elf64_Off -> uint64_t

typedef struct
{
/*
      program header table (pointed by e_phoff)
                header 1
                header 2
                header 3 (number of entry -> e_phnum, size of entry -> e_ehsize)
*/
  unsigned char    e_ident[EI_NIDENT];        /* Magic number and other info */ // 16 bytes to describe how ELF to be parsed
  Elf32_Half        e_type;                        /* Object file type */
  Elf32_Half        e_machine;                /* Architecture 0xF3 for risc-v */
  Elf32_Word        e_version;                /* Object file version : always 1 */
  Elf32_Addr        e_entry;                /* Entry point virtual address : entry point for executables or constructor for shared_library */
  // All program headers are in an array directly behind each other in the ELF file
  Elf32_Off        e_phoff;                /* Program header table file offset : location of program header table */
  Elf32_Off        e_shoff;                /* Section header table file offset */
  Elf32_Word        e_flags;                /* Processor-specific flags */
  Elf32_Half        e_ehsize;                /* ELF header size in bytes */
  Elf32_Half        e_phentsize;                /* Program header table entry size */
  Elf32_Half        e_phnum;                /* Program header table entry count */
  Elf32_Half        e_shentsize;                /* Section header table entry size */
  Elf32_Half        e_shnum;                /* Section header table entry count */
  Elf32_Half        e_shstrndx;                /* Section header string table index : used to resolve the names of sections contained in the file*/
} Elf32_Ehdr;

{
  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;

e_type : type of ELF file
ELF 文件格式
Relocatable file -> compile only mode : gcc -c
ELF with ET_EXEC :
it will not support ASLR(Address space layout randomization), as the EXEC type does not support position independent executable, and a modern compiler will disable PIE explicitly

program header

https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-83432/index.html
Each segment is defined by a small program header structure.
ELF 文件格式

typedef struct elf32_phdr {
          Elf32_Word p_type;
          Elf32_Off p_offset;
          Elf32_Addr p_vaddr;
          Elf32_Addr p_paddr;
          Elf32_Word p_filesz;
          Elf32_Word p_memsz;
          Elf32_Word p_flags;
          Elf32_Word p_align;
} Elf32_Phdr;

// p_offset: wherein the elf file of the content of segment is located
// p_vaddr: where is the first byte of the segment in memory
// p_paddr: used in context where physical addr is relevant: firmware file
// p_filesz: the size of the segment in the file, if it is 0, the segment is defined exclusively by the program header
// p_memsz: the size of the segment in memory if it is larger than the size in the file
// p_flags: permission of the segment, readable, writable or executable
// p_align: alignment requirement of the segment

typedef struct elf64_phdr {
       Elf64_Word p_type;
       Elf64_Word p_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, file & memory */
} Elf64_Phdr;

p_type : segment type

/* These constants are for the segment types stored in the image headers */
/* for p_type*/
#define PT_NULL    0 // place holder & also a simple way to disable the segment
#define PT_LOAD    1 // segment of this type will be loaded into memory, also can used to create zero initialize segments
#define PT_DYNAMIC 2  // load shared library related to executables
#define PT_INTERP  3    // position independent executable and shared library have an ELF type of dynamic,
                                          // this macro helps to differenciate between both
#define PT_NOTE    4   // segment that holds this has auxiliary information for debugger 
#define PT_SHLIB   5   // shared_lib but never used
#define PT_PHDR    6  // this segment specifies where program header table can be loaded 
#define PT_TLS     7        /* Thread local storage segment */
#define PT_LOOS    0x60000000   /* OS-specific */ // e.g. which part of memory should be marked as readonly
#define PT_HIOS    0x6fffffff   /* OS-specific */
#define PT_LOPROC  0x70000000
#define PT_HIPROC  0x7fffffff
#define PT_GNU_EH_FRAME     0x6474e550
#define PT_GNU_STACK    (PT_LOOS + 0x474e551)

Explore the segment

# in Linux
readelf --segment hello 
# in mac
greadelf --segment hello 

ELF 文件格式

section

ELF 文件格式

sections also have section headers. Sections are mainly used when linking or by the debugger. It is ok to remove sections from ELF when you just want to run a program. (sstrip)

typedef struct elf32_shdr {
      Elf32_Word    sh_name;
      Elf32_Word    sh_type;
      Elf32_Word    sh_flags;
      Elf32_Addr    sh_addr;
      Elf32_Off sh_offset;
      Elf32_Word    sh_size;
      Elf32_Word    sh_link;
      Elf32_Word    sh_info;
      Elf32_Word    sh_addralign;
      Elf32_Word    sh_entsize;
} Elf32_Shdr;

typedef struct elf64_shdr {
      Elf64_Word sh_name;       /* Section name, index in string tbl (e_shstrndx in ELF32_Ehdr), point to a string table containing the name of the section*/
      Elf64_Word sh_type;       /* Type of section */
      Elf64_Xword sh_flags;     /* Miscellaneous section attributes */
      Elf64_Addr sh_addr;       /* Section virtual addr at execution */
      Elf64_Off sh_offset;      /* Section file offset */
      Elf64_Xword sh_size;      /* Size of section in bytes */
      Elf64_Word sh_link;       /* Index of 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;

sh_type

 /* sh_type */
#define SHT_NULL    0
#define SHT_PROGBITS    1 // progbits section contains data for the program, code or variable
#define SHT_SYMTAB  2      // symbol table -> local or global symbol
#define SHT_STRTAB  3      // string table section
#define SHT_RELA    4        // relocation section type : how to modify different sections when assembling an executable
#define SHT_HASH    5
#define SHT_DYNAMIC 6
#define SHT_NOTE    7
#define SHT_NOBITS  8     // uninitialized data
#define SHT_REL     9
#define SHT_SHLIB   10
#define SHT_DYNSYM  11
#define SHT_NUM     12
#define SHT_LOPROC  0x70000000
#define SHT_HIPROC  0x7fffffff
#define SHT_LOUSER  0x80000000
#define SHT_HIUSER  0xffffffff

sh_flags

/* sh_flags */
#define SHF_WRITE   0x1 // section is writable
#define SHF_ALLOC   0x2
#define SHF_EXECINSTR   0x4
#define SHF_MASKPROC    0xf0000000

Explore the section

# in Linux
readelf --sections hello 
# in mac
greadelf --sections hello 

ELF 文件格式

上一篇:目标文件里有什么?


下一篇:RE套路 - 关于pyinstaller打包文件的复原