This page is a combination tutorial/documentary about my attempts at creating the smallest x86 ELF binary that would execute saying Hello World on Ubuntu Linux. My first attempts started with C then progressed to x86 assembly and finally to a hexeditor. I ended up compromising and switching to a "Hi World" app instead in order to fit the string data into the elf magic number. The final result is a completely corrupted x86 ELF Binary that still runs.
From start to finish.
The first thing you need to do is get an a proper environment setup.
Install Ubuntu (or a distro of your choice)
run: sudo apt-get install g++ gcc nasm
My first attempts started with C, the following is what I used for chello.c
My initial executable was 6363 bytes.
You can use readelf to dump the ELF header from the executable.
ldd is useful for showing all the dynamic libraries an executable is linked to.
file will give you a description of what a file is.
The "not stripped" returned from the file command means that the debugging symbols haven't been stripped from the excutable.
After stripping the executable was now 2984 bytes, still unacceptable! Time to take drastic measures...
I scratched the C attempt and dropped using printf, instead opting for nasm x86 assembly.
Before stripping the file was 770 bytes after stripping 448 bytes. However there is still useless headers and sections to destroy.
Open the binary in your favorite hex editor, I use the curses hexeditor and ghex2.
Delete everything including and past offset 0xAD, this will drop it down to 173 bytes
Move 0xA4-0xAC to 0x7 and Change offset 0x86 from 0xA4 to its new location 0x07. Delete 0xA2 and 0xA3
The file should be 164 bytes and now its time to enter the twilight zone... The rest is a lot to explain, basically I attempted to find what I could change in the elf head with out having it segfault on me.I added some jmps and completely corrupted the executable, however it still runs :). Here is some useful information: In x86 0xD9D0 is nop or no operation, useful for just filling space if you need to. 0xEB followed by a single signed byte is a relative jmp. Really you should read the intel docs on x86 instructions A-MN-Z .
I am certain that there are ways to get it even smaller. There may also be more things that can be removed from the header to increase size, but I didn't spend the enough time fully researching the ELF header format. Another option might be to use the a.out format instead of ELF may allow you to get even smaller.
Comments, suggestions, and critical criticism accepted: henszey@gmail.com