Task 173: .EL File Format

Task 173: .EL File Format

File Format Specifications for .EL

The .EL file format refers to the Executable and Linkable Format (ELF), a standard binary format for executables, object code, shared libraries, and core dumps on Unix-like systems (e.g., Linux). It is extensible for different architectures and data encodings. The specification is defined in the Tool Interface Standard (TIS) ELF specification. ELF files do not have a fixed extension like .EL, but the format is commonly used for files without extensions (executables) or .o, .so, etc. Here, we treat .EL as denoting ELF files for the task.

1. List of All Properties Intrinsic to This File Format

The ELF format's core properties are defined in its header, followed by program headers, sections, and section headers. These are intrinsic to how the file is structured and interpreted by the operating system and linker. Below is a comprehensive list based on the 32-bit ELF specification (ELFCLASS32); 64-bit (ELFCLASS64) is similar but uses 64-bit types for addresses/offsets.

ELF Header (Elf32_Ehdr structure, fixed size 52 bytes):

  • e_ident (array of 16 unsigned chars): Identification bytes.
  • EI_MAG0 to EI_MAG3: Magic number (0x7F, 'E', 'L', 'F').
  • EI_CLASS: File class (0 = invalid, 1 = 32-bit, 2 = 64-bit).
  • EI_DATA: Data encoding (0 = invalid, 1 = little-endian, 2 = big-endian).
  • EI_VERSION: File version (1 = current).
  • EI_OSABI: OS/ABI identification (0 = System V, 3 = Linux, etc.).
  • EI_ABIVERSION: ABI version (usually 0).
  • EI_PAD: Padding bytes (7 bytes, set to 0).
  • e_type (Elf32_Half, 2 bytes): Object file type (0 = none, 1 = relocatable, 2 = executable, 3 = shared object, 4 = core).
  • e_machine (Elf32_Half, 2 bytes): Architecture (3 = x86, 62 = x86-64, 40 = ARM, etc.).
  • e_version (Elf32_Word, 4 bytes): Object file version (1 = current).
  • e_entry (Elf32_Addr, 4 bytes): Virtual address of entry point (0 if none).
  • e_phoff (Elf32_Off, 4 bytes): Offset to program header table (0 if none).
  • e_shoff (Elf32_Off, 4 bytes): Offset to section header table (0 if none).
  • e_flags (Elf32_Word, 4 bytes): Processor-specific flags.
  • e_ehsize (Elf32_Half, 2 bytes): Size of ELF header (52 for 32-bit).
  • e_phentsize (Elf32_Half, 2 bytes): Size of each program header entry (32 for 32-bit).
  • e_phnum (Elf32_Half, 2 bytes): Number of program header entries (0 if none).
  • e_shentsize (Elf32_Half, 2 bytes): Size of each section header entry (40 for 32-bit).
  • e_shnum (Elf32_Half, 2 bytes): Number of section header entries (0 if none).
  • e_shstrndx (Elf32_Half, 2 bytes): Index of section header string table (SHN_UNDEF = 0 if none).

Program Header Table (array of Elf32_Phdr structures, each 32 bytes): Describes segments for execution.

  • p_type (Elf32_Word): Segment type (0 = null, 1 = load, 2 = dynamic, 3 = interp, 4 = note, 5 = shlib, 6 = phdr, etc.).
  • p_offset (Elf32_Off): File offset of segment.
  • p_vaddr (Elf32_Addr): Virtual address of segment.
  • p_paddr (Elf32_Addr): Physical address (ignored on most systems).
  • p_filesz (Elf32_Word): Size in file.
  • p_memsz (Elf32_Word): Size in memory.
  • p_flags (Elf32_Word): Flags (1 = execute, 2 = write, 4 = read).
  • p_align (Elf32_Word): Alignment.

Section Header Table (array of Elf32_Shdr structures, each 40 bytes): Describes sections for linking.

  • sh_name (Elf32_Word): Name index in string table.
  • sh_type (Elf32_Word): Type (0 = null, 1 = progbits, 2 = symtab, 3 = strtab, 4 = rela, etc.).
  • sh_flags (Elf32_Word): Flags (1 = writable, 2 = alloc, 4 = execinstr, etc.).
  • sh_addr (Elf32_Addr): Virtual address.
  • sh_offset (Elf32_Off): File offset.
  • sh_size (Elf32_Word): Section size.
  • sh_link (Elf32_Word): Link to another section.
  • sh_info (Elf32_Word): Extra info.
  • sh_addralign (Elf32_Word): Address alignment.
  • sh_entsize (Elf32_Word): Entry size if section has table.

Other Intrinsic Properties:

  • Special Section Indexes: SHN_UNDEF = 0 (undefined), SHN_LORESERVE = 0xff00 to SHN_HIRESERVE = 0xffff (reserved).
  • Data Alignment: 4-byte for 32-bit objects.
  • Byte Order: Determined by EI_DATA.
  • Hash Table (optional, for dynamic linking): Includes nbucket, nchain, bucket array, chain array.
  • Procedure Linkage Table (PLT), Global Offset Table (GOT)**: For dynamic linking.
  1. https://wildfire.paloaltonetworks.com/publicapi/test/elf (Sample ELF malware test file from Palo Alto Networks).
  2. https://github.com/0scarB/hello.elf/raw/main/hello.elf (Hello World ELF executable from GitHub).

3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .EL File Dump

ELF File Properties Dumper
Drag and drop .EL (ELF) file here

4. Python Class for .EL File

import struct
import os

class ElfFile:
    ELF_HEADER_FORMAT = '<4sBBBBB7sHHLLLLLHHHHHH'
    HEADER_SIZE = struct.calcsize(ELF_HEADER_FORMAT)

    def __init__(self, filepath):
        self.filepath = filepath
        self.header = None

    def read(self):
        with open(self.filepath, 'rb') as f:
            data = f.read(self.HEADER_SIZE)
            if len(data) < self.HEADER_SIZE:
                raise ValueError("File too small for ELF header")
            self.header = struct.unpack(self.ELF_HEADER_FORMAT, data)
            if self.header[0] != b'\x7fELF':
                raise ValueError("Not a valid ELF file")

    def print_properties(self):
        if not self.header:
            self.read()
        props = [
            f"Magic: {self.header[0]}",
            f"Class: {self.header[1]}",
            f"Data: {self.header[2]}",
            f"Version: {self.header[3]}",
            f"OS/ABI: {self.header[4]}",
            f"ABI Version: {self.header[5]}",
            f"Type: {self.header[7]}",
            f"Machine: {self.header[8]}",
            f"Version: {self.header[9]}",
            f"Entry point: 0x{self.header[10]:x}",
            f"Program header offset: {self.header[11]}",
            f"Section header offset: {self.header[12]}",
            f"Flags: 0x{self.header[13]:x}",
            f"Header size: {self.header[14]}",
            f"Program header entry size: {self.header[15]}",
            f"Program header count: {self.header[16]}",
            f"Section header entry size: {self.header[17]}",
            f"Section header count: {self.header[18]}",
            f"String table index: {self.header[19]}"
        ]
        print('\n'.join(props))

    def write(self, new_filepath=None):
        if not self.header:
            self.read()
        filepath = new_filepath or self.filepath + '.copy'
        with open(self.filepath, 'rb') as fin:
            data = fin.read()
        with open(filepath, 'wb') as fout:
            fout.write(data)
        print(f"Written to {filepath}")

# Example usage:
# elf = ElfFile('example.el')
# elf.print_properties()
# elf.write()

5. Java Class for .EL File

import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;

public class ElfFile {
    private static final int HEADER_SIZE = 52;
    private String filepath;
    private ByteBuffer header;

    public ElfFile(String filepath) {
        this.filepath = filepath;
    }

    public void read() throws IOException {
        try (RandomAccessFile raf = new RandomAccessFile(filepath, "r")) {
            FileChannel channel = raf.getChannel();
            header = ByteBuffer.allocate(HEADER_SIZE).order(ByteOrder.LITTLE_ENDIAN);
            channel.read(header);
            header.flip();
            if (header.getInt(0) != 0x464c457f) {
                throw new IOException("Not a valid ELF file");
            }
        }
    }

    public void printProperties() throws IOException {
        if (header == null) read();
        header.position(0);
        System.out.println("Magic: \\x7F ELF");
        System.out.println("Class: " + header.get(4));
        System.out.println("Data: " + header.get(5));
        System.out.println("Version: " + header.get(6));
        System.out.println("OS/ABI: " + header.get(7));
        System.out.println("ABI Version: " + header.get(8));
        header.position(16);
        System.out.println("Type: " + header.getShort());
        System.out.println("Machine: " + header.getShort());
        System.out.println("Version: " + header.getInt());
        System.out.println("Entry point: 0x" + Integer.toHexString(header.getInt()));
        System.out.println("Program header offset: " + header.getInt());
        System.out.println("Section header offset: " + header.getInt());
        System.out.println("Flags: 0x" + Integer.toHexString(header.getInt()));
        System.out.println("Header size: " + header.getShort());
        System.out.println("Program header entry size: " + header.getShort());
        System.out.println("Program header count: " + header.getShort());
        System.out.println("Section header entry size: " + header.getShort());
        System.out.println("Section header count: " + header.getShort());
        System.out.println("String table index: " + header.getShort());
    }

    public void write(String newFilepath) throws IOException {
        if (header == null) read();
        try (FileInputStream fis = new FileInputStream(filepath);
             FileOutputStream fos = new FileOutputStream(newFilepath == null ? filepath + ".copy" : newFilepath)) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
        }
        System.out.println("Written to " + (newFilepath == null ? filepath + ".copy" : newFilepath));
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     ElfFile elf = new ElfFile("example.el");
    //     elf.printProperties();
    //     elf.write(null);
    // }
}

6. JavaScript Class for .EL File

class ElfFile {
  constructor(filepath) {
    this.filepath = filepath;
    this.header = null;
  }

  async read() {
    const fs = require('fs').promises;
    const data = await fs.readFile(this.filepath);
    this.header = new DataView(data.buffer);
    if (this.header.getUint32(0, false) !== 0x7F454C46) {
      throw new Error('Not a valid ELF file');
    }
  }

  async printProperties() {
    if (!this.header) await this.read();
    const props = [
      `Magic: \\x7F ELF`,
      `Class: ${this.header.getUint8(4)}`,
      `Data: ${this.header.getUint8(5)}`,
      `Version: ${this.header.getUint8(6)}`,
      `OS/ABI: ${this.header.getUint8(7)}`,
      `ABI Version: ${this.header.getUint8(8)}`,
      `Type: ${this.header.getUint16(16, true)}`,
      `Machine: ${this.header.getUint16(18, true)}`,
      `Version: ${this.header.getUint32(20, true)}`,
      `Entry point: 0x${this.header.getUint32(24, true).toString(16)}`,
      `Program header offset: ${this.header.getUint32(28, true)}`,
      `Section header offset: ${this.header.getUint32(32, true)}`,
      `Flags: 0x${this.header.getUint32(36, true).toString(16)}`,
      `Header size: ${this.header.getUint16(40, true)}`,
      `Program header entry size: ${this.header.getUint16(42, true)}`,
      `Program header count: ${this.header.getUint16(44, true)}`,
      `Section header entry size: ${this.header.getUint16(46, true)}`,
      `Section header count: ${this.header.getUint16(48, true)}`,
      `String table index: ${this.header.getUint16(50, true)}`
    ];
    console.log(props.join('\n'));
  }

  async write(newFilepath = this.filepath + '.copy') {
    if (!this.header) await this.read();
    const fs = require('fs').promises;
    const data = await fs.readFile(this.filepath);
    await fs.writeFile(newFilepath, data);
    console.log(`Written to ${newFilepath}`);
  }
}

// Example usage:
// const elf = new ElfFile('example.el');
// await elf.printProperties();
// await elf.write();

7. C "Class" (Struct and Functions) for .EL File

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define HEADER_SIZE 52

typedef struct {
  uint8_t e_ident[16];
  uint16_t e_type;
  uint16_t e_machine;
  uint32_t e_version;
  uint32_t e_entry;
  uint32_t e_phoff;
  uint32_t e_shoff;
  uint32_t e_flags;
  uint16_t e_ehsize;
  uint16_t e_phentsize;
  uint16_t e_phnum;
  uint16_t e_shentsize;
  uint16_t e_shnum;
  uint16_t e_shstrndx;
} ElfHeader;

typedef struct {
  char* filepath;
  ElfHeader header;
} ElfFile;

ElfFile* elf_create(const char* filepath) {
  ElfFile* elf = malloc(sizeof(ElfFile));
  elf->filepath = strdup(filepath);
  return elf;
}

void elf_read(ElfFile* elf) {
  FILE* f = fopen(elf->filepath, "rb");
  if (!f) {
    perror("Open failed");
    exit(1);
  }
  uint8_t buf[HEADER_SIZE];
  if (fread(buf, 1, HEADER_SIZE, f) != HEADER_SIZE) {
    fprintf(stderr, "Read failed\n");
    fclose(f);
    exit(1);
  }
  fclose(f);
  if (memcmp(buf, "\x7fELF", 4) != 0) {
    fprintf(stderr, "Not ELF\n");
    exit(1);
  }
  memcpy(elf->header.e_ident, buf, 16);
  memcpy(&elf->header.e_type, buf + 16, sizeof(elf->header) - 16);
}

void elf_print_properties(ElfFile* elf) {
  printf("Magic: \\x7F ELF\n");
  printf("Class: %u\n", elf->header.e_ident[4]);
  printf("Data: %u\n", elf->header.e_ident[5]);
  printf("Version: %u\n", elf->header.e_ident[6]);
  printf("OS/ABI: %u\n", elf->header.e_ident[7]);
  printf("ABI Version: %u\n", elf->header.e_ident[8]);
  printf("Type: %u\n", elf->header.e_type);
  printf("Machine: %u\n", elf->header.e_machine);
  printf("Version: %u\n", elf->header.e_version);
  printf("Entry point: 0x%x\n", elf->header.e_entry);
  printf("Program header offset: %u\n", elf->header.e_phoff);
  printf("Section header offset: %u\n", elf->header.e_shoff);
  printf("Flags: 0x%x\n", elf->header.e_flags);
  printf("Header size: %u\n", elf->header.e_ehsize);
  printf("Program header entry size: %u\n", elf->header.e_phentsize);
  printf("Program header count: %u\n", elf->header.e_phnum);
  printf("Section header entry size: %u\n", elf->header.e_shentsize);
  printf("Section header count: %u\n", elf->header.e_shnum);
  printf("String table index: %u\n", elf->header.e_shstrndx);
}

void elf_write(ElfFile* elf, const char* new_filepath) {
  char* path = new_filepath ? strdup(new_filepath) : strcat(strdup(elf->filepath), ".copy");
  FILE* fin = fopen(elf->filepath, "rb");
  FILE* fout = fopen(path, "wb");
  if (!fin || !fout) {
    perror("File operation failed");
    exit(1);
  }
  uint8_t buf[1024];
  size_t len;
  while ((len = fread(buf, 1, sizeof(buf), fin)) > 0) {
    fwrite(buf, 1, len, fout);
  }
  fclose(fin);
  fclose(fout);
  printf("Written to %s\n", path);
  free(path);
}

void elf_destroy(ElfFile* elf) {
  free(elf->filepath);
  free(elf);
}

// Example usage:
// int main() {
//   ElfFile* elf = elf_create("example.el");
//   elf_read(elf);
//   elf_print_properties(elf);
//   elf_write(elf, NULL);
//   elf_destroy(elf);
//   return 0;
// }