autistic456
autistic456

Reputation: 183

How to embed machine code inside ELF header? Err: Exec format error

According to this tutorial: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html, I can embed so piece of code inside a elf header structure.

One step before, where my code and elf header were separate (also in the tutorial), it works. But after that, it does not.

This is my source:

BITS 32
    org 0x08048000
ehdr:
    db 0x7F, "ELF"
    db 1,1,1,0 ;e_indent = magic numbers, 32objects, 2compl, arch
    ;times 8 db 0 ; to the end of e_indent buffer (e_indent[16])
    ;PROGRAM EMBEDDED IN ELF HEADER
_start:
    mov bl, 42
    xor eax, eax
    inc eax
    int 0x80
    dw 2; e_type (2 == executable type)
    dw 3; e_machine (3 == intel_80386)
    dd 1; e_version (1 == current_version)
    dd _start; e_entry
    dd phdr - $$; e_phoff (size between this struct and struct phdr)
    dd 0; e_shoff -----> why is offset 0? == org ?
    dd 0; e_flags (should some processor specific flags, do not know value 0)
    dw ehdr_size; e_ehsize
    dw phdr_size; e_phentsize
    dw 1; e_phnum (real number of program headers, do not know what it means)
    dw 0; e_shentsize (because e_shoff == 0)
    dw 0; e_shnum
    dw 0; e_shstrndx

ehdr_size equ $ - ehdr

phdr:
    dd 1; p_type (1 == loadable program segment)
    dd 0; p_offset (segment file offset, but why 0, beginning?)
    dd $$; p_vaddr (segment virtual address, $$ == org)
    dd $$; p_paddr (segment physical address, $$ == org)
    dd file_size; p_filesz (segment size in file)
    dd file_size; p_memsz (segment size in memory)
    dd 5; p_flags (((1<<0) | (1<<2))) == segment is readable and executable)
    dd 0x1000; p_align (segment alignment - 4096 page alignment)

phdr_size equ $ - phdr
file_size equ $ - $$

There are just my comments after viewing the meanings of members of the struct in elf.h file.

Compiled as:

nasm -fbin -o a.out a.s
chmod +x a.out
./a.out
bash: ./a.out: cannot execute binary file: Exec format error

As I said, before, it was separated, but work. After "merging", it stops working. Some ideas why?

Upvotes: 1

Views: 224

Answers (1)

Peter Cordes
Peter Cordes

Reputation: 364190

You're not embedding source code (ASCII text), you're trying to embed machine code instructions into the ELF header.

Yours assembles to 83 bytes, but the article has an 84 byte version. It seems you changed something vs. the article's version, breaking it. Compare the binaries or source to figure out what you broke that makes the ELF headers invalid.

 (after assembling both your source and the working source from the article)
$ file tiny-84
tiny-84: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, no section header
$ file tiny-bad
tiny-bad: ELF 32-bit LSB *unknown arch 0x100* (SYSV)
$ cmp tiny-84 tiny-bad
tiny-84 tiny-bad differ: byte 9, line 1

Turns out the difference is on the 2nd data line of the ehdr:

both versions        db      0x7F, "ELF"                     ;   e_ident
-theirs              db      1, 1, 1, 0, 0
+yours               db      1, 1, 1, 0    ;e_indent = magic numbers, 32objects, 2compl, arch

(diff formatting hand tweaked to line them up)

So you left out one byte, misaligning all later bytes relative to their intended position in the ELF header. Obviously this breaks it, but fortunately having a known-good example to binary-compare against made it easy to find the problem.


In practice I used cmp -l tiny-84 tiny-bad to print the mismatching bytes of the binary. When it spewed a lot of differences, that plus the file size mismatch was strong evidence of a missing bytes skewing everything, rather than just 1 field having the wrong value. Also you can visually see the skew:

$ cmp -l tiny-84 tiny-bad
 9   0 263
10 263  52
11  52  61
12  61 300
13 300 100
14 100 315
15 315 200
16 200   2
17   2   0
...

Upvotes: 1

Related Questions