CasuallyBlue's Site



Creating the program header

We start the program header right after the ELF header in our test binary. In most ELF files there are multiple program header table entries, but since we are just wanting to run some binary code we are just creating one. Here is an example of the basic C layout for the program header table:

struct ELFProgramHeaderEntry {
  uint32_t segment_type; 
  uint32_t segment_permission_flags;

  void* segment_offset;
  void* segment_virtual_address;
  void* segment_physical_address;

  uint64_t segment_size_in_file;
  uint64_t segment_size_in_memory;

  uint64_t segment_alignment;
}

Segment type and flags

We start off by defining the type of the segment. We want this segment to get loaded as code, so we use segment type one (0x01) which is a “Loadable” segment. Which means that it has data that is loaded into the program’s address space rather than being parsed by the loader itself. Like the data in the ELF header the data here is represented in a little endian format.

We next must set the permission flags for the segment. Since we are just writing a simple executable we don’t need to write any data anywhere other than registers and the stack so we can just mark all the memory as readable and executable but not writable. This is represented as the logical OR of 0x01 for the execute permission and 0x04 for the read permission giving us a permission value of 0x05.

Both of these fields are represented in the header as four bytes.

0x01 0x00 0x00 0x00 // Loadable Segment Type
0x05 0x00 0x00 0x00 // Read+Execute permission

Segment location

We want the whole executable file to get loaded into the process address space so we just fill in the offset as 0x00

The next couple header values are the offsets and locations where the segment should be loaded. We decided in the last post to load the executable at 0x400000 since that is the standard location that Linux binaries get loaded at. We will use this value for the virtual address of the binary. The physical address is not important for a linux binary, so we fill it in with 0x0.

0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // Offset in the file to load into this segment
0x00 0x00 0x40 0x00 0x00 0x00 0x00 0x00 // Virtual memory address of the start of this segment
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // Phyical memory address of the start of this segment (ignored)

Segment size

The next two entries specify how much data to read from the file and how much memory to allocate to store it in. For obvious reasons these should be the same for our executable. It needs to be at least equal to the length of the code in our executable, plus the length of the headers. To be extra safe we will use 0xFFFF as the value This will probably be more than our first couple executables, but we may want to revisit it in the future and keep its value up to date with the size of our program.

0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 // Amount of data to read from the ELF file
0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 // Amound of data to load into memory

Segment alignment

For our simple program we don’t care about the alignment of the segment in bytes so we can just put 0x00 as its value.

0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // Alignment of the segment

We now have all the data needed for our basic elf header and readelf -h should now not return any errors when we run it on our ELF file. However, there is no actual code in the executable so attempting to run it now will just cause a segmentation fault.

We can now also call readelf -l to view the program header information:

Elf file type is EXEC (Executable file)
Entry point 0x400078
There is 1 program header, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000000000
                 0x000000000000ffff 0x000000000000ffff  R E    0x0

That’s it for this post. In the next post we will add our first actual executable code.