ELF - A Common Lisp library for manipulating ELF files


 

Abstract

ELF is a common lisp library for the manipulation of ELF files, which can be used to read, inspect, modify and write elf files.

The code is available under the GNU General Public License.

Source: http://github.com/eschulte/elf.
 

Contents

  1. Source
  2. Introduction
  3. The ELF dictionary
    1. *class*
    2. *endian*
    3. addralign
    4. address
    5. align
    6. alignment
    7. binding
    8. bytes-to-int
    9. copy-elf
    10. data
    11. elf
    12. elf
    13. elf-p
    14. entsize
    15. filesz
    16. flags
    17. generic-copy
    18. header
    19. info
    20. int-to-bytes
    21. link
    22. magic-number
    23. mapslots
    24. memsz
    25. name
    26. named-section
    27. named-symbol
    28. objdump
    29. objdump-parse
    30. offset
    31. ordering
    32. other
    33. paddr
    34. parse-addresses
    35. ph
    36. program-table
    37. ptr
    38. read-elf
    39. read-value
    40. rel-info
    41. rel-sym
    42. rel-type
    43. section-table
    44. sections
    45. sh
    46. shndx
    47. show-dynamic
    48. show-file-layout
    49. show-memory-layout
    50. show-symbols
    51. size
    52. sym-name
    53. symbols
    54. type
    55. un-type
    56. vaddr
    57. val
    58. value
    59. vma
    60. write-elf
    61. write-value
  4. Acknowledgements

 

Source

ELF together with this documentation can be found at http://github.com/eschulte/elf.
 

Introduction

See ELF.txt for more information on the elf format. Much of the code in elf.lisp is a direct translation of the elf data structures described in the ELF.txt document augmented with specific information translated from /usr/include/elf.h.

Example Usage

load the elf library

First load the up the elf library.

(require :elf)
(in-package :elf)

create a simple elf binary and confirm it is an elf file

For the remainder of this example, we'll use a simple elf binary executable named =hello=, compiled from the following C code.

echo 'main(){puts("hello world");}'|gcc -x c - -o hello

We can check that this is indeed an elf file by checking the magic number at the start of the file.

(elf-p "hello") ; => T

read an elf object, and view it's header information

Then we read the binary file into an elf object.

(defvar *elf* (read-elf "hello"))

Using the show-it function from the elf package we can inspect the header at the top of the elf file.

(elf::show-it (header *elf*) :out nil)

view section-table and program-table information

We can list the names of the sections of the elf file.

(mapcar #'name (sections *elf*))
;; => ("" ".interp" ".note.ABI-tag" ".note.gnu.build-id"...

We can list the segments in the program table, and view both the layout of the elements of the elf file, both in it's binary file and when it is an executable image in memory.

;; looking at the program table
(mapc #'elf::show-it (program-table *elf*))
TYPE:PHDR FLAGS:5 OFFSET:64 VADDR:4194368 PADDR:4194368 FILE...
TYPE:INTERP FLAGS:4 OFFSET:512 VADDR:4194816 PADDR:4194816 F...
TYPE:LOAD FLAGS:5 OFFSET:0 VADDR:4194304 PADDR:4194304 FILES...
TYPE:LOAD FLAGS:6 OFFSET:1744 VADDR:6293200 PADDR:6293200 FI...
TYPE:DYNAMIC FLAGS:6 OFFSET:1768 VADDR:6293224 PADDR:6293224...
TYPE:NOTE FLAGS:4 OFFSET:540 VADDR:4194844 PADDR:4194844 FIL...
TYPE:GNU_EH_FRAME FLAGS:4 OFFSET:1472 VADDR:4195776 PADDR:41...
TYPE:GNU_STACK FLAGS:6 OFFSET:0 VADDR:0 PADDR:0 FILESZ:0 MEM...

;; view the contents of elf, as they exist in the file
(show-file-layout *elf*)
START    OFFSET   CONTENTS           END     
0        NONE     HEADER             64      
64       NONE     PROGRAM-TABLE      512     
512      512      .interp            540     
540      540      .note.ABI-tag      572     
572      572      .note.gnu.build-id 608     
608      608      .gnu.hash          636     
636      NONE     FILLER             640     
640      640      .dynsym            736     
736      736      .dynstr            797     
...

;; view the contents of elf, as they exist in the file
(show-memory-layout *elf*)
addr     contents          end     
-------------------------------------
0x400000 LOAD               0x4006CC
0x400040 PHDR               0x400200
0x400200 INTERP             0x40021C
0x400200 .interp            0x40021C
0x40021C NOTE               0x400260
0x40021C .note.ABI-tag      0x40023C
...

write an elf object to disk

We can write out the elf file to disk.

;; write out the elf file, the results should be identical to
;; the original
(write-elf *elf* "hello2")

The resulting file will be identical to the original file from which the elf object was read.

diff hello hello2

manipulate the contents of an elf object

We can manipulate these elf objects, and then write the results back out to disk. For example we can change the code in the .text section of the file, and then write the results back out to disk.

;; change the .text section -- this doesn't break the program
(aref (data (named-section *elf* ".text")) 40) ; => 144
(setf (aref (data (named-section *elf* ".text")) 40) #xc3)
(aref (data (named-section *elf* ".text")) 40) ; => 195

;; When we write the modified elf to a file, the resulting file
;; will be different than the original hello (in one byte) but
;; will still execute since we changed a byte off of the
;; execution path
(write-elf *elf* "hello2")

Meta information like the relevant program and section headers, as well as symbol information in the .dynamic section of the file will be automatically updated.

(let ((text (named-section *elf* ".text")))
  (setf (data text)
        (concatenate 'vector
                     (data text)
                     (make-array 16 :initial-element #x90))))
(write-elf *elf* "hello3")

Note however that the resulting file will segfault on evaluation, because even though the meta-data of the elf file is updated automatically, there are hard-coded offsets and memory locations in the compiled data contained in the elf file, which can not be automatically updated.


 

The ELF dictionary


[Special variable]
*class*


Word size of the machine, (e.g. :32-bit or :64-bit).


[Special variable]
*endian*


Controls the endianness of how bytes are read.


[Generic accessor]
addralign object => result
(setf (addralign object) new-value)



[Specialized accessor]
addralign (object section-header) => result
(setf (addralign (object section-header)) new-value)


automatically generated reader method


[Generic accessor]
address object => result
(setf (address object) new-value)



[Specialized accessor]
address (object section-header) => result
(setf (address (object section-header)) new-value)


automatically generated reader method


[Generic accessor]
align object => result
(setf (align object) new-value)



[Specialized accessor]
align (object program-header-64) => result
(setf (align (object program-header-64)) new-value)


automatically generated reader method


[Specialized accessor]
align (object program-header-32) => result
(setf (align (object program-header-32)) new-value)


automatically generated reader method


[Generic accessor]
alignment sec => result
(setf (alignment sec) new)



[Specialized accessor]
alignment (sec section) => result
(setf (alignment (sec section)) new)



[Generic function]
binding sym => result



[Method]
binding (sym elf-sym) => result



[Function]
bytes-to-int bytes &optional signed-p &aux steps => result



[Function]
copy-elf elf => result



[Generic accessor]
data object => result
(setf (data sec) new)



[Specialized accessor]
data (object section) => result
(setf (data (sec section)) new)


automatically generated reader method


[Standard class]
elf



[Generic accessor]
elf object => result
(setf (elf object) new-value)



[Specialized accessor]
elf (object section) => result
(setf (elf (object section)) new-value)


automatically generated reader method


[Function]
elf-p file => result


Return t if file is an ELF file (using the magic number test).


[Generic accessor]
entsize object => result
(setf (entsize object) new-value)



[Specialized accessor]
entsize (object section-header) => result
(setf (entsize (object section-header)) new-value)


automatically generated reader method


[Generic accessor]
filesz object => result
(setf (filesz object) new-value)



[Specialized accessor]
filesz (object program-header-64) => result
(setf (filesz (object program-header-64)) new-value)


automatically generated reader method


[Specialized accessor]
filesz (object program-header-32) => result
(setf (filesz (object program-header-32)) new-value)


automatically generated reader method


[Generic accessor]
flags object => result
(setf (flags object) new-value)



[Specialized accessor]
flags (object section) => result
(setf (flags (object section)) new-value)



[Specialized accessor]
flags (object program-header-64) => result
(setf (flags (object program-header-64)) new-value)


automatically generated reader method


[Specialized accessor]
flags (object program-header-32) => result
(setf (flags (object program-header-32)) new-value)


automatically generated reader method


[Specialized accessor]
flags (object section-header) => result
(setf (flags (object section-header)) new-value)


automatically generated reader method


[Specialized accessor]
flags (object elf-header) => result
(setf (flags (object elf-header)) new-value)


automatically generated reader method


[Function]
generic-copy obj &optional trace => result


A generic copy method, may run way too long on partially circular elements.


[Generic accessor]
header object => result
(setf (header object) new-value)



[Specialized accessor]
header (object elf) => result
(setf (header (object elf)) new-value)


automatically generated reader method


[Generic accessor]
info object => result
(setf (info object) new-value)



[Specialized accessor]
info (object elf-sym-64) => result
(setf (info (object elf-sym-64)) new-value)


automatically generated reader method


[Specialized accessor]
info (object elf-sym-32) => result
(setf (info (object elf-sym-32)) new-value)


automatically generated reader method


[Specialized accessor]
info (object elf-rela-64) => result
(setf (info (object elf-rela-64)) new-value)


automatically generated reader method


[Specialized accessor]
info (object elf-rela-32) => result
(setf (info (object elf-rela-32)) new-value)


automatically generated reader method


[Specialized accessor]
info (object elf-rel-64) => result
(setf (info (object elf-rel-64)) new-value)


automatically generated reader method


[Specialized accessor]
info (object elf-rel-32) => result
(setf (info (object elf-rel-32)) new-value)


automatically generated reader method


[Specialized accessor]
info (object section-header) => result
(setf (info (object section-header)) new-value)


automatically generated reader method


[Function]
int-to-bytes int size &optional signed-p &aux steps => result



[Generic accessor]
link object => result
(setf (link object) new-value)



[Specialized accessor]
link (object section-header) => result
(setf (link (object section-header)) new-value)


automatically generated reader method


[Generic accessor]
magic-number object => result
(setf (magic-number object) new-value)



[Specialized accessor]
magic-number (object elf-header) => result
(setf (magic-number (object elf-header)) new-value)


automatically generated reader method


[Function]
mapslots func obj => result


Map func over the slots of the clos object OBJ.


[Generic accessor]
memsz object => result
(setf (memsz object) new-value)



[Specialized accessor]
memsz (object program-header-64) => result
(setf (memsz (object program-header-64)) new-value)


automatically generated reader method


[Specialized accessor]
memsz (object program-header-32) => result
(setf (memsz (object program-header-32)) new-value)


automatically generated reader method


[Generic accessor]
name object => result
(setf (name object) new-value)



[Specialized accessor]
name (object section) => result
(setf (name (object section)) new-value)


automatically generated reader method


[Specialized accessor]
name (object elf-sym-64) => result
(setf (name (object elf-sym-64)) new-value)


automatically generated reader method


[Specialized accessor]
name (object elf-sym-32) => result
(setf (name (object elf-sym-32)) new-value)


automatically generated reader method


[Specialized accessor]
name (object section-header) => result
(setf (name (object section-header)) new-value)


automatically generated reader method


[Function]
named-section elf name => result


Return the section in ELF named NAME.


[Function]
named-symbol elf name => result


Return the symbol in ELF named NAME.


[Generic function]
objdump sec => result



[Method]
objdump (sec section) => result


Use objdump to return the disassembly of SEC.


[Function]
objdump-parse output => result


Parse the output of objdump returning the disassembly by symbol.


[Generic accessor]
offset object => result
(setf (offset object) new-value)



[Specialized accessor]
offset (object section) => result
(setf (offset (object section)) new-value)



[Specialized accessor]
offset (object elf-rela-64) => result
(setf (offset (object elf-rela-64)) new-value)


automatically generated reader method


[Specialized accessor]
offset (object elf-rela-32) => result
(setf (offset (object elf-rela-32)) new-value)


automatically generated reader method


[Specialized accessor]
offset (object elf-rel-64) => result
(setf (offset (object elf-rel-64)) new-value)


automatically generated reader method


[Specialized accessor]
offset (object elf-rel-32) => result
(setf (offset (object elf-rel-32)) new-value)


automatically generated reader method


[Specialized accessor]
offset (object program-header-64) => result
(setf (offset (object program-header-64)) new-value)


automatically generated reader method


[Specialized accessor]
offset (object program-header-32) => result
(setf (offset (object program-header-32)) new-value)


automatically generated reader method


[Specialized accessor]
offset (object section-header) => result
(setf (offset (object section-header)) new-value)


automatically generated reader method


[Generic accessor]
ordering object => result
(setf (ordering object) new-value)



[Specialized accessor]
ordering (object elf) => result
(setf (ordering (object elf)) new-value)


automatically generated reader method


[Generic accessor]
other object => result
(setf (other object) new-value)



[Specialized accessor]
other (object elf-sym-64) => result
(setf (other (object elf-sym-64)) new-value)


automatically generated reader method


[Specialized accessor]
other (object elf-sym-32) => result
(setf (other (object elf-sym-32)) new-value)


automatically generated reader method


[Generic accessor]
paddr object => result
(setf (paddr object) new-value)



[Specialized accessor]
paddr (object program-header-64) => result
(setf (paddr (object program-header-64)) new-value)


automatically generated reader method


[Specialized accessor]
paddr (object program-header-32) => result
(setf (paddr (object program-header-32)) new-value)


automatically generated reader method


[Function]
parse-addresses lines => result


Parse addresses from lines of objdump output.


[Generic accessor]
ph object => result
(setf (ph object) new-value)



[Specialized accessor]
ph (object section) => result
(setf (ph (object section)) new-value)


automatically generated reader method


[Generic accessor]
program-table object => result
(setf (program-table object) new-value)



[Specialized accessor]
program-table (object elf) => result
(setf (program-table (object elf)) new-value)


automatically generated reader method


[Generic accessor]
ptr dyn => result
(setf (ptr dyn) new)



[Specialized accessor]
ptr (dyn elf-dyn) => result
(setf (ptr (dyn elf-dyn)) new)



[Function]
read-elf file => result



[Generic function]
read-value type stream &key character-type length bytes swap terminator bytes bits-per-byte => result


Read a value of the given type from the stream.


[Function]
rel-info sym type => result


Convert a symbol and type back into the info field of an elf-rel.


[Generic function]
rel-sym rel => result



[Method]
rel-sym (rel elf-rel) => result



[Generic function]
rel-type rel header => result



[Method]
rel-type (rel elf-rel) (header elf-header) => result


The interpretation of the type is machine specific.


[Generic accessor]
section-table object => result
(setf (section-table object) new-value)



[Specialized accessor]
section-table (object elf) => result
(setf (section-table (object elf)) new-value)


automatically generated reader method


[Generic accessor]
sections object => result
(setf (sections object) new-value)



[Specialized accessor]
sections (object elf) => result
(setf (sections (object elf)) new-value)


automatically generated reader method


[Generic accessor]
sh object => result
(setf (sh object) new-value)



[Specialized accessor]
sh (object section) => result
(setf (sh (object section)) new-value)


automatically generated reader method


[Generic accessor]
shndx object => result
(setf (shndx object) new-value)



[Specialized accessor]
shndx (object elf-sym-64) => result
(setf (shndx (object elf-sym-64)) new-value)


automatically generated reader method


[Specialized accessor]
shndx (object elf-sym-32) => result
(setf (shndx (object elf-sym-32)) new-value)


automatically generated reader method


[Function]
show-dynamic elf => result


Show the dynamic symbols of ELF in a manner similar to readelf.


[Function]
show-file-layout elf => result


Show the layout of the elements of an elf file with binary offset.


[Function]
show-memory-layout elf => result


Show the layout of the elements of an elf file with binary offset.


[Function]
show-symbols elf => result


Show all symbols in ELF in a manner similar to readelf.


[Generic accessor]
size object => result
(setf (size object) new-value)



[Specialized accessor]
size (object section) => result
(setf (size (object section)) new-value)



[Specialized accessor]
size (object elf-sym-64) => result
(setf (size (object elf-sym-64)) new-value)


automatically generated reader method


[Specialized accessor]
size (object elf-sym-32) => result
(setf (size (object elf-sym-32)) new-value)


automatically generated reader method


[Specialized accessor]
size (object section-header) => result
(setf (size (object section-header)) new-value)


automatically generated reader method


[Generic accessor]
sym-name object => result
(setf (sym-name object) new-value)



[Specialized accessor]
sym-name (object elf-sym) => result
(setf (sym-name (object elf-sym)) new-value)


automatically generated reader method


[Generic function]
symbols elf => result



[Method]
symbols (elf elf) => result


Return the symbols contained in ELF.


[Generic accessor]
type object => result
(setf (type object) new-value)



[Specialized accessor]
type (object section) => result
(setf (type (object section)) new-value)



[Method]
type (object elf-sym) => result



[Specialized accessor]
type (object program-header-64) => result
(setf (type (object program-header-64)) new-value)


automatically generated reader method


[Specialized accessor]
type (object program-header-32) => result
(setf (type (object program-header-32)) new-value)


automatically generated reader method


[Specialized accessor]
type (object section-header) => result
(setf (type (object section-header)) new-value)


automatically generated reader method


[Specialized accessor]
type (object elf-header) => result
(setf (type (object elf-header)) new-value)


automatically generated reader method


[Generic function]
un-type dyn => result



[Method]
un-type (dyn elf-dyn) => result



[Generic accessor]
vaddr object => result
(setf (vaddr object) new-value)



[Specialized accessor]
vaddr (object program-header-64) => result
(setf (vaddr (object program-header-64)) new-value)


automatically generated reader method


[Specialized accessor]
vaddr (object program-header-32) => result
(setf (vaddr (object program-header-32)) new-value)


automatically generated reader method


[Generic accessor]
val dyn => result
(setf (val dyn) new)



[Specialized accessor]
val (dyn elf-dyn) => result
(setf (val (dyn elf-dyn)) new)



[Generic accessor]
value object => result
(setf (value object) new-value)



[Specialized accessor]
value (object elf-sym-64) => result
(setf (value (object elf-sym-64)) new-value)


automatically generated reader method


[Specialized accessor]
value (object elf-sym-32) => result
(setf (value (object elf-sym-32)) new-value)


automatically generated reader method


[Generic accessor]
vma sec => result
(setf (vma sec) new)



[Specialized accessor]
vma (sec section) => result
(setf (vma (sec section)) new)



[Function]
write-elf elf file => result



[Generic function]
write-value type stream value &key character-type length bytes swap terminator bytes bits-per-byte => result


Write a value as the given type to the stream.

 

Acknowledgements

This documentation was prepared with a hacked up version of DOCUMENTATION-TEMPLATE.