As you have seen, gcc produces binaries in the ELF format. All this really means is it contains data in a well defined format to tell the operating system how to execute the file.

For a managed binary, that is a binary that requires a virtual runtime like JavaVM or .NET, the instructions are in an intermediate language with minimal data to tell the OS to load the VM of choice. For a non-managed binary, the program is sent straight for execution without any intermediate steps.

The ELF structure is a datatype called a struct. A struct holds data and looks like this for 32 and 64 bit versions.

#define EI_NIDENT 16

typedef struct {
        unsigned char   e_ident[EI_NIDENT];
        Elf32_Half      e_type;
        Elf32_Half      e_machine;
        Elf32_Word      e_version;
        Elf32_Addr      e_entry;
        Elf32_Off       e_phoff;
        Elf32_Off       e_shoff;
        Elf32_Word      e_flags;
        Elf32_Half      e_ehsize;
        Elf32_Half      e_phentsize;
        Elf32_Half      e_phnum;
        Elf32_Half      e_shentsize;
        Elf32_Half      e_shnum;
        Elf32_Half      e_shstrndx;
} Elf32_Ehdr;

typedef struct {
        unsigned char   e_ident[EI_NIDENT];
        Elf64_Half      e_type;
        Elf64_Half      e_machine;
        Elf64_Word      e_version;
        Elf64_Addr      e_entry;
        Elf64_Off       e_phoff;
        Elf64_Off       e_shoff;
        Elf64_Word      e_flags;
        Elf64_Half      e_ehsize;
        Elf64_Half      e_phentsize;
        Elf64_Half      e_phnum;
        Elf64_Half      e_shentsize;
        Elf64_Half      e_shnum;
        Elf64_Half      e_shstrndx;
} Elf64_Ehdr;

e_machine here specifies the type of instruction set to use. So the Intel i860 or 80860, we would have the value 0x07 the number 7 in base 10. For a MIPS RS3000 the value would be set to 0x0A or 10 in base 10.

Here we have the ELF header as discussed above. Next we have the Program Header Table. This table is used at runtime and points to the needed segments. The Section Header Table is a table listing out the various sections available.

For linking files, the ELF bin does not require the Program header table but does require the section header table.

For Executing a binary the program header table is required but the section header table is not required.

A segment is a group of sections. There are two main segments the Text segment and the Data segment. The Text segment contains read only instructions and data and has sections like “.text,” “.hash,” and “.plt.” The Data segment contains writable data and instructions and has sections like “.data,” “.dynamic,” and “.bss.”


Execution

The program is ran on a Linux system by first calling load_elf_binary(). The header is inspected for validity and read into memory. The handler now loops over the header initializing those attributes needed. A call to flush any old data is completed, and then setup_new_exec() is called to prepare the system, signal handlers are setup, the virtual memory is now setup and processed, the credentials are processed with install_exec_creds(), finally create_elf_tables() sets up the randomized stack, finally the first call to collect the ELFs auxiliary vector once this is collected the programs new stack is assembled and the program begins execution flow.

That obviously is a very high overview of a super complex process. But it serves our needs for now, letting us continue examining the core content.

Project

Armed with this knowledge, write a C program that can take in a C program and extract the headers and sections. In fact, a header file called elf.h can be found on almost any Linux system. On Kali it is in /usr/include. Google elf.h for help as the man pages are not the best on kali.

Another helpful library (i.e. save many hours) is LibELF.

The way I would approach this project is to read elf.h and make a simple program to just verify the ELF file is valid. Next use LibELF as a much easier way to read the file and extract contents. Create different flags to achieve different objectives. Finally I would attempt to create a disassembler if you feel real saucy.