Library to instrument executable formats including ELF, PE, Mach-O, and Android formats
—
Comprehensive support for ELF (Executable and Linkable Format) files including executables, shared libraries, object files, and core dumps. ELF is the standard binary format for Linux and Unix systems, providing rich metadata for dynamic linking, debugging, and system integration.
Parse ELF files with format-specific configuration options and validation.
def parse(filename: str, config: ParserConfig = None) -> Optional[Binary]:
"""Parse ELF file from filesystem path."""
def parse(raw: Sequence[int], config: ParserConfig = None) -> Optional[Binary]:
"""Parse ELF from raw bytes."""
def parse(obj: Union[io.IOBase, os.PathLike], config: ParserConfig = None) -> Optional[Binary]:
"""Parse ELF from file-like object."""
class ParserConfig:
parse_relocations: bool
parse_dyn_symbols: bool
parse_static_symbols: bool
parse_symbol_versions: bool
parse_notes: bool
parse_overlay: boolUsage example:
import lief.ELF as ELF
# Basic parsing
binary = ELF.parse("/bin/ls")
# Parse with configuration
config = ELF.ParserConfig()
config.parse_relocations = True
config.parse_dyn_symbols = True
binary = ELF.parse("/lib/x86_64-linux-gnu/libc.so.6", config)ELF-specific binary manipulation with support for dynamic linking, symbol management, and section operations.
class Binary(lief.Binary):
header: Header
sections: Iterator[Section]
segments: Iterator[Segment]
dynamic_entries: Iterator[DynamicEntry]
symbols: Iterator[Symbol]
relocations: Iterator[Relocation]
gnu_hash: Optional[GnuHash]
sysv_hash: Optional[SysvHash]
notes: Iterator[Note]
interpreter: str
def add_section(self, section: Section) -> Section
def remove_section(self, name: str, clear: bool = False) -> None
def add_segment(self, segment: Segment) -> Segment
def add_library(self, library: str) -> DynamicEntryLibrary
def remove_library(self, library: str) -> None
def add_dynamic_entry(self, entry: DynamicEntry) -> DynamicEntry
def get_dynamic_entry(self, tag: DYNAMIC_TAGS) -> Optional[DynamicEntry]
def add_symbol(self, symbol: Symbol) -> Symbol
def get_relocation(self, address: int) -> Optional[Relocation]
def add_relocation(self, relocation: Relocation) -> RelocationUsage example:
binary = ELF.parse("/bin/ls")
# Add new library dependency
lib_entry = binary.add_library("libcustom.so")
print(f"Added library: {lib_entry.name}")
# Add new section
section = ELF.Section()
section.name = ".custom"
section.type = ELF.SECTION_TYPES.PROGBITS
section.flags = ELF.SECTION_FLAGS.ALLOC | ELF.SECTION_FLAGS.WRITE
section.content = b"Custom data"
binary.add_section(section)
# Symbol manipulation
symbol = ELF.Symbol()
symbol.name = "custom_function"
symbol.value = 0x1000
symbol.size = 64
symbol.type = ELF.SYMBOL_TYPES.FUNC
binary.add_symbol(symbol)Analyze ELF header information including architecture, ABI, and file type details.
class Header(lief.Object):
file_type: E_TYPE
machine_type: ARCH
object_file_version: VERSION
entry_point: int
program_header_offset: int
section_header_offset: int
processor_flags: int
header_size: int
program_header_size: int
program_header_num: int
section_header_size: int
section_header_num: int
section_name_table_idx: int
identity_class: ELF_CLASS
identity_data: ELF_DATA
identity_version: VERSION
identity_os_abi: OS_ABI
identity_abi_version: int
enum E_TYPE:
NONE = 0
REL = 1
EXEC = 2
DYN = 3
CORE = 4
enum ARCH:
NONE = 0
I386 = 3
ARM = 40
X86_64 = 62
AARCH64 = 183
RISCV = 243Usage example:
binary = ELF.parse("/bin/bash")
header = binary.header
print(f"File type: {header.file_type}")
print(f"Architecture: {header.machine_type}")
print(f"Entry point: 0x{header.entry_point:x}")
print(f"ABI: {header.identity_os_abi}")
print(f"Class: {header.identity_class}") # 32-bit or 64-bitManipulate ELF sections with format-specific properties and operations.
class Section(lief.Section):
type: SECTION_TYPES
flags: SECTION_FLAGS
link: int
information: int
alignment: int
entry_size: int
original_size: int
def clear(self, value: int = 0) -> None
enum SECTION_TYPES:
SHT_NULL = 0
SHT_PROGBITS = 1
SHT_SYMTAB = 2
SHT_STRTAB = 3
SHT_RELA = 4
SHT_HASH = 5
SHT_DYNAMIC = 6
SHT_NOTE = 7
SHT_NOBITS = 8
SHT_REL = 9
SHT_DYNSYM = 11
SHT_GNU_HASH = 0x6ffffff6
enum SECTION_FLAGS:
SHF_WRITE = 0x1
SHF_ALLOC = 0x2
SHF_EXECINSTR = 0x4
SHF_MERGE = 0x10
SHF_STRINGS = 0x20
SHF_INFO_LINK = 0x40
SHF_LINK_ORDER = 0x80
SHF_OS_NONCONFORMING = 0x100
SHF_GROUP = 0x200
SHF_TLS = 0x400Usage example:
binary = ELF.parse("/lib/x86_64-linux-gnu/libc.so.6")
# Analyze sections
for section in binary.sections:
print(f"Section: {section.name}")
print(f" Type: {section.type}")
print(f" Flags: {section.flags}")
print(f" Address: 0x{section.virtual_address:x}")
print(f" Size: {section.size}")
# Check for executable sections
if section.flags & ELF.SECTION_FLAGS.EXECINSTR:
print(f" Executable section with {section.size} bytes")Manage dynamic linking information, dependencies, and runtime configuration.
class DynamicEntry(lief.Object):
tag: DYNAMIC_TAGS
value: int
class DynamicEntryLibrary(DynamicEntry):
name: str
class DynamicEntryRpath(DynamicEntry):
paths: List[str]
class DynamicEntryRunPath(DynamicEntry):
paths: List[str]
enum DYNAMIC_TAGS:
DT_NULL = 0
DT_NEEDED = 1
DT_PLTRELSZ = 2
DT_PLTGOT = 3
DT_HASH = 4
DT_STRTAB = 5
DT_SYMTAB = 6
DT_RELA = 7
DT_RELASZ = 8
DT_RELAENT = 9
DT_STRSZ = 10
DT_SYMENT = 11
DT_INIT = 12
DT_FINI = 13
DT_SONAME = 14
DT_RPATH = 15
DT_SYMBOLIC = 16
DT_REL = 17
DT_RELSZ = 18
DT_RELENT = 19
DT_PLTREL = 20
DT_DEBUG = 21
DT_TEXTREL = 22
DT_JMPREL = 23
DT_RUNPATH = 29Usage example:
binary = ELF.parse("/usr/bin/python3")
# List library dependencies
print("Library dependencies:")
for entry in binary.dynamic_entries:
if entry.tag == ELF.DYNAMIC_TAGS.NEEDED:
lib_entry = ELF.DynamicEntryLibrary(entry)
print(f" {lib_entry.name}")
# Check for RPATH/RUNPATH
rpath_entry = binary.get_dynamic_entry(ELF.DYNAMIC_TAGS.RPATH)
if rpath_entry:
rpath = ELF.DynamicEntryRpath(rpath_entry)
print(f"RPATH: {':'.join(rpath.paths)}")
runpath_entry = binary.get_dynamic_entry(ELF.DYNAMIC_TAGS.RUNPATH)
if runpath_entry:
runpath = ELF.DynamicEntryRunPath(runpath_entry)
print(f"RUNPATH: {':'.join(runpath.paths)}")Advanced symbol table analysis with binding, visibility, and versioning support.
class Symbol(lief.Symbol):
type: SYMBOL_TYPES
binding: SYMBOL_BINDINGS
visibility: SYMBOL_VISIBILITY
shndx: int
symbol_version: Optional[SymbolVersion]
def is_static(self) -> bool
def is_function(self) -> bool
def is_variable(self) -> bool
enum SYMBOL_TYPES:
STT_NOTYPE = 0
STT_OBJECT = 1
STT_FUNC = 2
STT_SECTION = 3
STT_FILE = 4
STT_COMMON = 5
STT_TLS = 6
STT_GNU_IFUNC = 10
enum SYMBOL_BINDINGS:
STB_LOCAL = 0
STB_GLOBAL = 1
STB_WEAK = 2
STB_GNU_UNIQUE = 10
enum SYMBOL_VISIBILITY:
STV_DEFAULT = 0
STV_INTERNAL = 1
STV_HIDDEN = 2
STV_PROTECTED = 3Usage example:
binary = ELF.parse("/lib/x86_64-linux-gnu/libc.so.6")
# Analyze exported functions
print("Exported functions:")
for symbol in binary.symbols:
if (symbol.binding == ELF.SYMBOL_BINDINGS.GLOBAL and
symbol.type == ELF.SYMBOL_TYPES.FUNC and
symbol.shndx != 0): # Not undefined
print(f" {symbol.name} @ 0x{symbol.value:x}")
# Check symbol version if available
if symbol.symbol_version:
print(f" Version: {symbol.symbol_version.symbol_version_auxiliary.name}")Parse and analyze ELF note sections containing build information, ABI details, and system metadata.
class Note(lief.Object):
name: str
type: int
description: memoryview
class NoteAbi(Note):
version: List[int] # ABI version tuple
class AndroidIdent(Note):
sdk_version: int
ndk_version: str
ndk_build_number: str
class CoreFile(Note):
count: int
page_size: int
file_mapping: Iterator[CoreFileEntry]
class CorePrStatus(Note):
info: CorePrStatus.siginfo_t
cursig: int
sigpend: int
sighold: int
pid: int
ppid: int
pgrp: int
sid: int
register_values: memoryviewUsage example:
binary = ELF.parse("/bin/ls")
# Analyze note sections
for note in binary.notes:
print(f"Note: {note.name} (type: {note.type})")
# Check for GNU build ID
if note.name == "GNU" and note.type == 3: # NT_GNU_BUILD_ID
build_id = note.description.hex()
print(f" Build ID: {build_id}")
# Check for ABI information
elif isinstance(note, ELF.NoteAbi):
print(f" ABI version: {'.'.join(map(str, note.version))}")class Segment(lief.Object):
type: SEGMENT_TYPES
flags: SEGMENT_FLAGS
file_offset: int
virtual_address: int
physical_address: int
physical_size: int
virtual_size: int
alignment: int
sections: Iterator[Section]
enum SEGMENT_TYPES:
PT_NULL = 0
PT_LOAD = 1
PT_DYNAMIC = 2
PT_INTERP = 3
PT_NOTE = 4
PT_SHLIB = 5
PT_PHDR = 6
PT_TLS = 7
PT_GNU_EH_FRAME = 0x6474e550
PT_GNU_STACK = 0x6474e551
PT_GNU_RELRO = 0x6474e552
enum SEGMENT_FLAGS:
PF_X = 0x1 # Execute
PF_W = 0x2 # Write
PF_R = 0x4 # Read
class GnuHash(lief.Object):
nb_buckets: int
symbol_index: int
shift2: int
bloom_filters: List[int]
buckets: List[int]
hash_values: List[int]
class SysvHash(lief.Object):
nbucket: int
nchain: int
buckets: List[int]
chains: List[int]
class Builder:
def build(self) -> None
def write(self, output: str) -> None
def get_build_warnings(self) -> List[str]Install with Tessl CLI
npx tessl i tessl/pypi-lief