Questions about this topic? Sign up to ask in the talk tab.
Difference between revisions of "User:Hatter/ELF format"
From NetSec
(Created page with "The '''E'''xtecutable and '''L'''inkable '''F'''ormat (ELF) is used to construct binary executables for the Linux Operating System. == Reading ELF files == A variety of...") |
(→Parsing elf files) |
||
(8 intermediate revisions by one other user not shown) | |||
Line 10: | Line 10: | ||
== Parsing elf files == | == Parsing elf files == | ||
− | It is relatively trivial to find your imagebase at runtime using some small assembly: | + | It is relatively trivial to find your imagebase at runtime using some small assembly, but more difficult to actually parse out the ELF image. Here's an unstable (no error or size checking) assembly code that will dump its own symbols: |
{{code|text=<source lang="asm"> | {{code|text=<source lang="asm"> | ||
.section .data | .section .data | ||
Line 20: | Line 20: | ||
jmp startup | jmp startup | ||
− | getpc: | + | strlen: |
+ | xor %rdx, %rdx | ||
+ | |||
+ | next_byte: | ||
+ | inc %rdx | ||
+ | cmpb $0x00, (%rsi,%rdx,1); | ||
+ | jne next_byte | ||
+ | ret | ||
+ | |||
+ | getpc: | ||
mov (%rsp), %rax | mov (%rsp), %rax | ||
ret | ret | ||
+ | |||
startup: | startup: | ||
+ | xor %r15, %r15 | ||
+ | push $0x0a0a0a | ||
+ | mov %rsp, %r15 | ||
call getpc | call getpc | ||
dec %rax | dec %rax | ||
xor %rcx, %rcx | xor %rcx, %rcx | ||
+ | push $0x2 | ||
+ | pop %rsi | ||
+ | |||
find_header: | find_header: | ||
cmpl $0x464c457f, (%rax,%rcx,4) # Did we find our ELF base pointer? | cmpl $0x464c457f, (%rax,%rcx,4) # Did we find our ELF base pointer? | ||
Line 32: | Line 48: | ||
dec %rax | dec %rax | ||
jmp find_header | jmp find_header | ||
+ | |||
find_sections: | find_sections: | ||
# %rax now = base pointer of ELF image. | # %rax now = base pointer of ELF image. | ||
− | .. | + | xor %rbx, %rbx |
+ | add $0x28, %bl | ||
+ | xorl (%rax,%rbx,1), %ecx # %rcx = offset to section headers | ||
+ | addq %rax, %rcx # %rcx = absolute address to section headers | ||
+ | |||
+ | # each section header is 0x40 bytes in length. | ||
+ | next_section: | ||
+ | xor %rbx, %rbx | ||
+ | xor %rbp, %rbp | ||
+ | add $0x40, %rcx | ||
+ | # %rcx now = address to first entry | ||
+ | add $0x04, %bl | ||
+ | xor (%rcx,%rbx,1), %ebp # %rbp now contains type | ||
+ | cmp $0x02, %bpl | ||
+ | jne next_section | ||
+ | |||
+ | found_symbols: | ||
+ | xor %r8, %r8 | ||
+ | mov %rcx, %r8 # %rcx = pointer to top of symbol section header | ||
+ | add $0x40, %r8 # %r8 = pointer to top of string table section header | ||
+ | |||
+ | xor %rbx, %rbx | ||
+ | xor $0x18, %bl # pointer to actual section is $0x18 bytes from header base | ||
+ | |||
+ | xor %r9, %r9 | ||
+ | xor %r10, %r10 | ||
+ | xor (%rcx,%rbx,1), %r9 | ||
+ | xor (%r8,%rbx,1), %r10 | ||
+ | addq %rax, %r9 # r9 should now point to the first symbol | ||
+ | addq %rax, %r10 # r10 should now point to the first string | ||
+ | addq $0x18, %r9 | ||
+ | |||
+ | next_symbol: | ||
+ | addq $0x18,%r9 | ||
+ | xor %rcx, %rcx | ||
+ | xor %rbp, %rbp | ||
+ | xor %rdi, %rdi | ||
+ | xor (%r9,%rcx,1), %ebp # %rbp now contains string offset. | ||
+ | cmp %rbp, %rdi | ||
+ | je next_symbol | ||
+ | |||
+ | print_symbol_name: | ||
+ | mov %rbp, %rsi | ||
+ | addq %r10, %rsi # %rsi should now be a pointer to a string | ||
+ | push $0x01 | ||
+ | pop %rax | ||
+ | push %rax | ||
+ | pop %rdi | ||
+ | call strlen | ||
+ | syscall | ||
+ | |||
+ | push $0x01 | ||
+ | pop %rax | ||
+ | push %rax | ||
+ | pop %rdi | ||
+ | push $0x02 | ||
+ | pop %rdx | ||
+ | push %r15 | ||
+ | pop %rsi | ||
+ | syscall | ||
+ | jmp next_symbol | ||
</source>}} | </source>}} | ||
+ | |||
+ | [hatter@bha soinject]$ ./test_parser | ||
+ | startup | ||
+ | |||
+ | getpc | ||
+ | |||
+ | find_header | ||
+ | |||
+ | find_sections | ||
+ | |||
+ | next_section | ||
+ | |||
+ | found_symbols | ||
+ | |||
+ | next_symbol | ||
+ | |||
+ | print_symbol_name | ||
+ | |||
+ | strlen | ||
+ | |||
+ | next_byte | ||
+ | |||
+ | _start | ||
+ | |||
+ | __bss_start | ||
+ | |||
+ | _edata | ||
+ | |||
+ | _end | ||
+ | |||
+ | '''Segmentation fault''' | ||
+ | |||
+ | == Headers == | ||
+ | * '''Diagram of a 64-bit ELF Header:''' | ||
+ | 0x0 - 0xf = "ELF Format Information" | ||
+ | Entry-point = 0x18 - 0x1f | ||
+ | Start of section headers = 0x28 - 0x2f | ||
+ | Size of each section = 0x3a - 0x3b | ||
+ | Number of section headers = 0x3c - 0x3d | ||
+ | |||
+ | |||
+ | * '''Diagram of a 64-bit section header:''' ''(length defined in ELF header)'' | ||
+ | [0x0-0x3] shstrtab offset for section name. | ||
+ | shstrtab is defined between the end of | ||
+ | .text and the beginning of the section | ||
+ | headers | ||
+ | |||
+ | [0x4-0x7] section type - 0 is null, 1 is progbits, 2 is symtab, 3 is strtab | ||
+ | [0x8-0xf] section flags | ||
+ | [0x10-0x17] section address | ||
+ | [0x18-0x1f] section offset | ||
+ | [0x20-0x27] section size | ||
+ | [0x28-0x2b] Section Link | ||
+ | [0x2c-0x2f] Section Info | ||
+ | [0x30-0x37] Section Align | ||
+ | [0x38-0x3f] Section EntSize | ||
+ | |||
+ | |||
+ | == Symbol Tables == | ||
+ | * '''Diagram of a 64-bit symbol table entry:''' ''(0x18 bytes in length)'' | ||
+ | |||
+ | [0x0-0x3] Name offset from next string table | ||
+ | [0x4-0x5] Bind | ||
+ | [0x6-0x7] Ndx | ||
+ | [0x8-0xf] Symbol pointer (Function pointer, data pointer, etc) | ||
+ | [0x10-0x17] Null barrier |
Latest revision as of 05:59, 19 September 2012
The Extecutable and Linkable Format (ELF) is used to construct binary executables for the Linux Operating System.
Reading ELF files
A variety of applications, debuggers, disassemblers, and resource viewers are available to read ELF formatted binaries:
- hexdump
- readelf
- objdump
Parsing elf files
It is relatively trivial to find your imagebase at runtime using some small assembly, but more difficult to actually parse out the ELF image. Here's an unstable (no error or size checking) assembly code that will dump its own symbols:
.section .data .section .text .globl _start _start: jmp startup strlen: xor %rdx, %rdx next_byte: inc %rdx cmpb $0x00, (%rsi,%rdx,1); jne next_byte ret getpc: mov (%rsp), %rax ret startup: xor %r15, %r15 push $0x0a0a0a mov %rsp, %r15 call getpc dec %rax xor %rcx, %rcx push $0x2 pop %rsi find_header: cmpl $0x464c457f, (%rax,%rcx,4) # Did we find our ELF base pointer? je find_sections dec %rax jmp find_header find_sections: # %rax now = base pointer of ELF image. xor %rbx, %rbx add $0x28, %bl xorl (%rax,%rbx,1), %ecx # %rcx = offset to section headers addq %rax, %rcx # %rcx = absolute address to section headers # each section header is 0x40 bytes in length. next_section: xor %rbx, %rbx xor %rbp, %rbp add $0x40, %rcx # %rcx now = address to first entry add $0x04, %bl xor (%rcx,%rbx,1), %ebp # %rbp now contains type cmp $0x02, %bpl jne next_section found_symbols: xor %r8, %r8 mov %rcx, %r8 # %rcx = pointer to top of symbol section header add $0x40, %r8 # %r8 = pointer to top of string table section header xor %rbx, %rbx xor $0x18, %bl # pointer to actual section is $0x18 bytes from header base xor %r9, %r9 xor %r10, %r10 xor (%rcx,%rbx,1), %r9 xor (%r8,%rbx,1), %r10 addq %rax, %r9 # r9 should now point to the first symbol addq %rax, %r10 # r10 should now point to the first string addq $0x18, %r9 next_symbol: addq $0x18,%r9 xor %rcx, %rcx xor %rbp, %rbp xor %rdi, %rdi xor (%r9,%rcx,1), %ebp # %rbp now contains string offset. cmp %rbp, %rdi je next_symbol print_symbol_name: mov %rbp, %rsi addq %r10, %rsi # %rsi should now be a pointer to a string push $0x01 pop %rax push %rax pop %rdi call strlen syscall push $0x01 pop %rax push %rax pop %rdi push $0x02 pop %rdx push %r15 pop %rsi syscall jmp next_symbol |
[hatter@bha soinject]$ ./test_parser startup getpc find_header find_sections next_section found_symbols next_symbol print_symbol_name strlen next_byte _start __bss_start _edata _end Segmentation fault
Headers
- Diagram of a 64-bit ELF Header:
0x0 - 0xf = "ELF Format Information" Entry-point = 0x18 - 0x1f Start of section headers = 0x28 - 0x2f Size of each section = 0x3a - 0x3b Number of section headers = 0x3c - 0x3d
- Diagram of a 64-bit section header: (length defined in ELF header)
[0x0-0x3] shstrtab offset for section name. shstrtab is defined between the end of .text and the beginning of the section headers
[0x4-0x7] section type - 0 is null, 1 is progbits, 2 is symtab, 3 is strtab [0x8-0xf] section flags [0x10-0x17] section address [0x18-0x1f] section offset [0x20-0x27] section size [0x28-0x2b] Section Link [0x2c-0x2f] Section Info [0x30-0x37] Section Align [0x38-0x3f] Section EntSize
Symbol Tables
- Diagram of a 64-bit symbol table entry: (0x18 bytes in length)
[0x0-0x3] Name offset from next string table [0x4-0x5] Bind [0x6-0x7] Ndx [0x8-0xf] Symbol pointer (Function pointer, data pointer, etc) [0x10-0x17] Null barrier