pwnlib.elf — Working with ELF binaries

pwnlib.elf.load(*args, **kwargs)[source]

Compatibility wrapper for pwntools v1

class pwnlib.elf.ELF(path)[source]

Encapsulates information about an ELF file.

Variables:
  • path – Path to the binary on disk
  • symbols – Dictionary of {name: address} for all symbols in the ELF
  • plt – Dictionary of {name: address} for all functions in the PLT
  • got – Dictionary of {name: address} for all function pointers in the GOT
  • libs – Dictionary of {path: address} for each shared object required to load the ELF

Example

bash = ELF(which('bash'))
hex(bash.symbols['read'])
# 0x41dac0
hex(bash.plt['read'])
# 0x41dac0
u32(bash.read(bash.got['read'], 4))
# 0x41dac6
print disasm(bash.read(bash.plt['read'],16), arch='amd64')
# 0:   ff 25 1a 18 2d 00       jmp    QWORD PTR [rip+0x2d181a]        # 0x2d1820
# 6:   68 59 00 00 00          push   0x59
# b:   e9 50 fa ff ff          jmp    0xfffffffffffffa60
address[source]

Address of the lowest segment loaded in the ELF. When updated, cascades updates to segment vaddrs, section addrs, symbols, plt, and got.

>>> bash = ELF(which('bash'))
>>> old = bash.symbols['read']
>>> bash.address += 0x1000
>>> bash.symbols['read'] == old + 0x1000
True
asm(address, assembly)[source]

Assembles the specified instructions and inserts them into the ELF at the specified address.

The resulting binary can be saved with ELF.save()

bss(offset=0)[source]

Returns an index into the .bss segment

disasm(address, n_bytes)[source]

Returns a string of disassembled instructions at the specified virtual memory address

dwarf[source]

DWARF info for the elf

elfclass[source]

ELF class (32 or 64).

Note

Set during ELFFile._identify_file

elftype[source]

ELF type (EXEC, DYN, etc)

entry[source]

Entry point to the ELF

entrypoint[source]

Entry point to the ELF

executable_segments[source]

Returns – list of all segments which are executable.

static from_assembly(*a, **kw)[source]

Given an assembly listing, return a fully loaded ELF object which contains that assembly at its entry point.

Parameters:
  • assembly (str) – Assembly language listing
  • vma (int) – Address of the entry point and the module’s base address.

Example

>>> e = ELF.from_assembly('nop; foo: int 0x80', vma = 0x400000)
>>> e.symbols['foo'] = 0x400001
>>> e.disasm(e.entry, 1)
'  400000:       90                      nop'
>>> e.disasm(e.symbols['foo'], 2)
'  400001:       cd 80                   int    0x80'
static from_bytes(*a, **kw)[source]

Given a sequence of bytes, return a fully loaded ELF object which contains those bytes at its entry point.

Parameters:
  • bytes (str) – Shellcode byte string
  • vma (int) – Desired base address for the ELF.

Example

>>> e = ELF.from_bytes('\x90\xcd\x80', vma=0xc000)
>>> print(e.disasm(e.entry, 3))
    c000:       90                      nop
    c001:       cd 80                   int    0x80
get_data()[source]

Retrieve the raw data from the ELF file.

>>> bash = ELF(which('bash'))
>>> fd   = open(which('bash'))
>>> bash.get_data() == fd.read()
True
libc[source]

If the ELF imports any libraries which contain ‘libc.so’, and we can determine the appropriate path to it on the local system, returns an ELF object pertaining to that libc.so.

Otherwise, returns None.

non_writable_segments[source]

Returns – list of all segments which are NOT writeable

offset_to_vaddr(offset)[source]

Translates the specified offset to a virtual address.

Parameters:offset (int) – Offset to translate
Returns:Virtual address which corresponds to the file offset, or None

Examples

>>> bash = ELF(which('bash'))
>>> bash.address == bash.offset_to_vaddr(0)
True
>>> bash.address += 0x123456
>>> bash.address == bash.offset_to_vaddr(0)
True
read(address, count)[source]

Read data from the specified virtual address

Parameters:
  • address (int) – Virtual address to read
  • count (int) – Number of bytes to read
Returns:

A string of bytes, or None

Examples

>>> bash = ELF(which('bash'))
>>> bash.read(bash.address+1, 3)
'ELF'
rwx_segments[source]

Returns – list of all segments which are writeable and executable.

save(path)[source]

Save the ELF to a file

>>> bash = ELF(which('bash'))
>>> bash.save('/tmp/bash_copy')
>>> copy = file('/tmp/bash_copy')
>>> bash = file(which('bash'))
>>> bash.read() == copy.read()
True
search(needle, writable = False) → str generator[source]

Search the ELF’s virtual address space for the specified string.

Parameters:
  • needle (str) – String to search for.
  • writable (bool) – Search only writable sections.
Returns:

An iterator for each virtual address that matches.

Examples

>>> bash = ELF(which('bash'))
>>> bash.address + 1 == next(bash.search('ELF'))
True
>>> sh = ELF(which('bash'))
>>> # /bin/sh should only depend on libc
>>> libc_path = [key for key in sh.libs.keys() if 'libc' in key][0]
>>> libc = ELF(libc_path)
>>> # this string should be in there because of system(3)
>>> len(list(libc.search('/bin/sh'))) > 0
True
section(name)[source]

Gets data for the named section

Parameters:name (str) – Name of the section
Returns:String containing the bytes for that section
sections[source]

A list of all sections in the ELF

segments[source]

A list of all segments in the ELF

start[source]

Entry point to the ELF

vaddr_to_offset(address)[source]

Translates the specified virtual address to a file address

Parameters:address (int) – Virtual address to translate
Returns:Offset within the ELF file which corresponds to the address, or None.

Examples

>>> bash = ELF(which('bash'))
>>> 0 == bash.vaddr_to_offset(bash.address)
True
>>> bash.address += 0x123456
>>> 0 == bash.vaddr_to_offset(bash.address)
True
writable_segments[source]

Returns – list of all segments which are writeable

write(address, data)[source]

Writes data to the specified virtual address

Parameters:
  • address (int) – Virtual address to write
  • data (str) – Bytes to write
Note::
This routine does not check the bounds on the write to ensure that it stays in the same segment.

Examples

>>> bash = ELF(which('bash'))
>>> bash.read(bash.address+1, 3)
'ELF'
>>> bash.write(bash.address, "HELO")
>>> bash.read(bash.address, 4)
'HELO'
class pwnlib.elf.Core(*a, **kw) → Core[source]

Enhances the inforation available about a corefile (which is an extension of the ELF format) by permitting extraction of information about the mapped data segments, and register state.

Registers can be accessed directly, e.g. via core_obj.eax.

Mappings can be iterated in order via core_obj.mappings.

exe[source]

Return the first mapping in the executable file.

getenv(name) → int[source]

Read an environment variable off the stack, and return its address.

Parameters:name (str) – Name of the environment variable to read.
Returns:The address of the environment variable.
libc[source]

Return the first mapping in libc

maps[source]

A printable string which is similar to /proc/xx/maps.

registers[source]

A dictionary of register names to values

vdso[source]

Return the mapping for the vdso

vsyscall[source]

Return the mapping for the vdso

vvar[source]

Return the mapping for the vvar