diff options
Diffstat (limited to 'md/writeup/create_elf_file_from_scratch.md')
-rw-r--r-- | md/writeup/create_elf_file_from_scratch.md | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/md/writeup/create_elf_file_from_scratch.md b/md/writeup/create_elf_file_from_scratch.md new file mode 100644 index 0000000..2bed7bc --- /dev/null +++ b/md/writeup/create_elf_file_from_scratch.md @@ -0,0 +1,187 @@ +title:Create ELF file from scratch +keywords:elf,linux + +# Create ELF file from scratch +## Creating smallest possible elf file. + +### Structure of ELF file: +Elf header +Program header +Code Part +Data Part + +C structure of ELF header /usr/include/elf.h: + +```c +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; +``` + +Structure of Program header file /usr/include/elf.h: + +```c +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; +``` + +This structures is all what we need to make our ELF file. +Now we will look inside kernel source and see that +we need only one program header for our program. All big programs +using usually two program headers one for code and one for data. + +/linux-3.3.1/fs/binfmt_elf.c:605 + +```c +if (loc->elf_ex.e_phnum < 1 || + loc->elf_ex.e_phnum > 65536U / sizeof(struct elf_phdr)) + goto out; +``` + +Step by step there should be filled all +fields of the ELF header structure. + +```c +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* default values of ELFMAG,ELFCLASS64,ELFDATA2LSB */ + Elf64_Half e_type; /* we making executable then it would be ET_EXEC */ + Elf64_Half e_machine; /* Architecture is 0x3e(EM_X86_64) + (not from elf header + from /binutils/include/elf/common.h) */ + Elf64_Word e_version; /* Object file version EV_CURRENT */ + Elf64_Addr e_entry; /* Entry point virtual address points to + main function it is with label entrypoint */ + Elf64_Off e_phoff; /* Program header table file offset */ + offset of program header sizeof(Elf64_Ehdr) + Elf64_Off e_shoff; /* Section header table file offset + there is no section header */ + Elf64_Word e_flags; /* No processor-specific flags + */ + Elf64_Half e_ehsize; /* ELF header size in bytes + 0x40 sizeof(Elf64_Ehdr) + Elf64_Half e_phentsize; /* Program header table entry size + 0x38 sizeof(Elf64_Phdr) */ + Elf64_Half e_phnum; /* Program header table entry count + 0x01 */ + Elf64_Half e_shentsize; /* Section header table entry size + I put 0x40 */ + Elf64_Half e_shnum; /* Section header table entry count + 0x00 */ + Elf64_Half e_shstrndx; /* There is no section header and + string table index is 0x0 then */ +} Elf64_Ehdr; +``` + +With program header we will tell kernel how to load our file in memory +and with part of file will be mmaped to needed address. As our data +and code is placed in one address space and kernel ELF source says +that there is enough with 1 program header then we will use only 1. + +```c +typedef struct +{ + Elf64_Word p_type; /* Segment type PT_LOAD */ + Elf64_Word p_flags; /* Segment flags PF_X,PF_R,PF_W + as our memory should be readable, writable and + executable as it contains code and data */ + Elf64_Off p_offset; /* Segment file offset + point to offset of entry point label offset + in file */ + Elf64_Addr p_vaddr; /* Segment virtual address + 64bits programs is usually at 0x400000+code_file_offset*/ + Elf64_Addr p_paddr; /* Segment physical address + same as above*/ + Elf64_Xword p_filesz; /* Segment size in file + size of code and data if file */ + Elf64_Xword p_memsz; /* Segment size in memory + same as above */ + Elf64_Xword p_align; /* Segment alignment + same as all programs have on my CPU*/ +} Elf64_Phdr; +``` + +Now everything is ready. Only thing that is left is code some small code +that uses data. And it would be hello world + +```asm +mov eax, 1 +mov edx, 12 +mov rsi, qword 0x040009c ;address of string +mov edi, 1 +syscall + +xor edi, edi +mov eax, 60 +syscall + +msg db 'Hello World',0xA +``` + +To calculate offsets of code and data labels is used macro: + +```asm +macro doffset +{ + bits = 16 + display ' 0x' + repeat bits/4 + d = '0' + $ shr (bits-%*4) and 0Fh + if d > '9' + d = d + 'A'-'9'-1 + end if + display d + end repeat + display 13,10 +} +``` + + +Total size of executable on 64bit system: +ELF header size 0x40 +Program header 0x38 +Code size 0x24 +Data size 0xc +Total: 168 bytes + +If 32 bit system is used then need to find definitions of data structures +and retype some bytes. Also architecture variable need to be changed. + +## Future plans: +Add some shared libs and compile smallest possible program using +SDL graphics lib. + +## Code +Code is written and tested on x86_64. + + + +## Links +http://refspecs.freestandards.org/elf/elf.pdf + +## Source + +http://archive.main.lv/files/writeup/create_elf_file_from_scratch/small_elf_file.zip
\ No newline at end of file |