Library to instrument executable formats including ELF, PE, Mach-O, and Android formats
—
Foundation functionality for parsing, analyzing, and modifying executable files across all supported formats. These operations provide unified interfaces that work consistently regardless of the underlying binary format.
Parse executable files from various sources with automatic format detection and unified interface access.
# Core imports required
import lief
from typing import Union, Optional, Sequence, Iterator, List
import io
import os
def parse(file: Union[str, bytes, io.IOBase, os.PathLike]) -> Optional[Binary]:
"""
Parse binary files with automatic format detection.
Args:
file: File path, raw bytes, or file-like object
Returns:
Binary object or None if parsing fails
"""
def parse(filepath: str) -> Optional[Binary]: ...
def parse(raw: bytes) -> Optional[Binary]: ...
def parse(obj: Union[io.IOBase, os.PathLike]) -> Optional[Binary]: ...Usage example:
import lief
# Parse from file path
binary = lief.parse("/bin/ls")
# Parse from bytes
with open("/bin/ls", "rb") as f:
binary = lief.parse(f.read())
# Parse from file object
with open("/bin/ls", "rb") as f:
binary = lief.parse(f)Identify binary formats before parsing for conditional processing and validation.
def is_elf(file: Union[str, Sequence[int]]) -> bool:
"""Check if file is ELF format."""
def is_pe(file: Union[str, Sequence[int]]) -> bool:
"""Check if file is PE format."""
def is_macho(file: Union[str, Sequence[int]]) -> bool:
"""Check if file is Mach-O format."""
def is_oat(file: Union[ELF.Binary, str, Sequence[int]]) -> bool:
"""Check if file is OAT format."""
def is_dex(file: Union[str, Sequence[int]]) -> bool:
"""Check if file is DEX format."""
def is_vdex(file: Union[str, Sequence[int]]) -> bool:
"""Check if file is VDEX format."""
def is_art(file: Union[str, Sequence[int]]) -> bool:
"""Check if file is ART format."""Usage example:
import lief
file_path = "/bin/bash"
if lief.is_elf(file_path):
binary = lief.ELF.parse(file_path)
elif lief.is_pe(file_path):
binary = lief.PE.parse(file_path)
elif lief.is_macho(file_path):
binary = lief.MachO.parse(file_path)Access common properties and perform analysis operations across all binary formats.
class Binary:
format: FORMATS
header: Header
sections: Iterator[Section]
symbols: Iterator[Symbol]
relocations: Iterator[Relocation]
entrypoint: int
libraries: List[Union[str, bytes]]
exported_functions: List[Function]
imported_functions: List[Function]
is_pie: bool
has_nx: bool
imagebase: int
original_size: int
debug_info: Optional[DebugInfo]
ctor_functions: List[Function]
def has_symbol(self, symbol_name: str) -> bool
def get_symbol(self, symbol_name: str) -> Symbol
def get_function_address(self, function_name: str) -> Union[int, lief_errors]
def remove_section(self, name: str, clear: bool = False) -> None
def offset_to_virtual_address(self, offset: int, slide: int = 0) -> Union[int, lief_errors]
def xref(self, virtual_address: int) -> List[int]Usage example:
binary = lief.parse("/bin/ls")
print(f"Format: {binary.format}")
print(f"Architecture: {binary.header.architecture}")
print(f"Entry point: 0x{binary.entrypoint:x}")
print(f"PIE enabled: {binary.is_pie}")
print(f"NX protection: {binary.has_nx}")
# Symbol analysis
if binary.has_symbol("main"):
main_addr = binary.get_function_address("main")
print(f"main() at: 0x{main_addr:x}")
# Section analysis
for section in binary.sections:
print(f"{section.name}: {section.size} bytes at 0x{section.virtual_address:x}")Modify binary content through unified interfaces that work across formats.
class Binary:
def patch_address(self, address: int, patch_value: Union[Sequence[int], int],
size: int = 8, va_type: VA_TYPES = VA_TYPES.AUTO) -> None:
"""Patch binary at specified address."""
def get_content_from_virtual_address(self, virtual_address: int, size: int,
va_type: VA_TYPES = VA_TYPES.AUTO) -> memoryview:
"""Read content from virtual address."""
def get_int_from_virtual_address(self, address: int, integer_size: int,
type: VA_TYPES = VA_TYPES.AUTO) -> Optional[int]:
"""Read integer from virtual address."""Usage example:
binary = lief.parse("/path/to/binary")
# Read data from virtual address
data = binary.get_content_from_virtual_address(0x1000, 16)
print(f"Data: {data.hex()}")
# Patch binary
binary.patch_address(0x1000, [0x90, 0x90, 0x90, 0x90]) # NOP sled
# Read integer from address
value = binary.get_int_from_virtual_address(0x2000, 4)
print(f"Value: {value}")Helper functions for common operations and data manipulation.
def hash(obj: Union[Object, Sequence[int], bytes, str]) -> int:
"""Compute hash of LIEF objects or data."""
def to_json(obj: Object) -> str:
"""Convert LIEF objects to JSON representation."""
def demangle(mangled: str) -> Optional[str]:
"""Demangle C++ symbol names."""
def current_platform() -> PLATFORMS:
"""Get current platform (Linux, Windows, macOS, etc.)."""
def disable_leak_warning() -> None:
"""Disable memory leak warnings."""Usage example:
import lief
binary = lief.parse("/bin/ls")
# Generate hash
binary_hash = lief.hash(binary)
print(f"Binary hash: {binary_hash}")
# Export to JSON
json_data = lief.to_json(binary)
with open("analysis.json", "w") as f:
f.write(json_data)
# Demangle symbols
for symbol in binary.symbols:
if symbol.name.startswith("_Z"):
demangled = lief.demangle(symbol.name)
print(f"{symbol.name} -> {demangled}")
# Platform detection
platform = lief.current_platform()
print(f"Running on: {platform}")Disassemble and assemble code directly from binary objects for analysis and modification.
class Binary:
def disassemble(self, address: int, size: int = None) -> Iterator[Optional[assembly.Instruction]]:
"""Disassemble instructions at address."""
def disassemble(self, function_name: str) -> Iterator[Optional[assembly.Instruction]]:
"""Disassemble entire function by name."""
def disassemble_from_bytes(self, buffer: bytes, address: int = 0) -> Iterator[Optional[assembly.Instruction]]:
"""Disassemble raw bytes."""
def assemble(self, address: int, assembly: str) -> bytes:
"""Assemble instructions and return machine code."""Usage example:
binary = lief.parse("/bin/ls")
# Disassemble function
for instruction in binary.disassemble("main"):
if instruction:
print(f"0x{instruction.address:x}: {instruction.mnemonic}")
# Disassemble at specific address
for instruction in binary.disassemble(binary.entrypoint, 32):
if instruction:
print(instruction.to_string())
# Assemble instructions
machine_code = binary.assemble(0x1000, "mov rax, 42\nret")
print(f"Machine code: {machine_code.hex()}")class range_t:
low: int
high: int
size: int
class debug_location_t:
line: int
file: str
class ok_t:
def __bool__(self) -> bool
class ok_error_t:
is_error: bool
is_value: bool
error: lief_errors
value: ok_t
def __bool__(self) -> bool
enum PLATFORMS:
UNKNOWN = 0
LINUX = 1
ANDROID = 2
WINDOWS = 3
IOS = 4
OSX = 5
enum VA_TYPES:
AUTO = 0
RVA = 1
VA = 2
enum lief_errors:
read_error = 1
not_found = 2
not_implemented = 3
not_supported = 4
corrupted = 5
conversion_error = 6
read_out_of_bound = 7
asn1_bad_tag = 8
file_error = 9
file_format_error = 10
parsing_error = 11
build_error = 12
data_too_large = 13
require_extended_version = 14Install with Tessl CLI
npx tessl i tessl/pypi-lief