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.
*class**endian*addralignaddressalignalignmentbindingbytes-to-intcopy-elfdataelfelfelf-pentsizefileszflagsgeneric-copyheaderinfoint-to-byteslinkmagic-numbermapslotsmemsznamenamed-sectionnamed-symbolobjdumpobjdump-parseoffsetorderingotherpaddrparse-addressesphprogram-tableptrread-elfread-valuerel-inforel-symrel-typesection-tablesectionsshshndxshow-dynamicshow-file-layoutshow-memory-layoutshow-symbolssizesym-namesymbolstypeun-typevaddrvalvaluevmawrite-elfwrite-valueSee 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.
First load the up the elf library.
(require :elf)
(in-package :elf)
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
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)
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
...
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
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.
[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 ofobjdumpreturning 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.
This documentation was prepared with a hacked up version of DOCUMENTATION-TEMPLATE.