summaryrefslogtreecommitdiff
path: root/md/writeup/create_elf_file_from_scratch.md
diff options
context:
space:
mode:
Diffstat (limited to 'md/writeup/create_elf_file_from_scratch.md')
-rw-r--r--md/writeup/create_elf_file_from_scratch.md187
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