CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-lief

Library to instrument executable formats including ELF, PE, Mach-O, and Android formats

Pending
Overview
Eval results
Files

elf-format.mddocs/

ELF Format

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.

Capabilities

ELF Parsing

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: bool

Usage 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 Binary Operations

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) -> Relocation

Usage 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)

ELF Header Analysis

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 = 243

Usage 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-bit

Section Management

Manipulate 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 = 0x400

Usage 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")

Dynamic Linking

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 = 29

Usage 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)}")

Symbol Analysis

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 = 3

Usage 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}")

Note Sections

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: memoryview

Usage 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))}")

Types

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

docs

android-formats.md

assembly-engine.md

core-operations.md

debug-info.md

elf-format.md

extended-features.md

index.md

macho-format.md

pe-format.md

tile.json