Questions about this topic? Sign up to ask in the talk tab.

Difference between revisions of "User:Hatter/ELF format"

From NetSec
Jump to: navigation, search
(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