ELF, PE, Mach-O binaries share similar characteristics like an entrypoint, imported/exported functions, etc.
These shared characteristics are represented in an abstract layer that is represented by an inheritance relationship in C++/Python and by a trait in Rust.
target: lief.Binary = lief.parse("/tmp/some.elf")
target: lief.Binary = lief.parse("/Users/demo/some.macho")
target: lief.Binary = lief.parse(r"C:\some.pe.exe")
std::unique_ptr<LIEF::Binary> target = LIEF::Parser::parse("some.elf");
std::unique_ptr<LIEF::Binary> target = LIEF::Parser::parse("some.macho");
std::unique_ptr<LIEF::Binary> target = LIEF::Parser::parse("some.exe");
Because of the dynamical polymorphism aspect of Python, the return value of lief.parse()
is automatically casted into either: lief.ELF.Binary
, lief.PE.Binary
or lief.MachO.Binary
. To upcast this object into a lief.Binary
object, one can use the attribute: lief.Binary.abstract
which effectively returns a lief.Binary
instance:
import lief
target = lief.parse("some.elf")
assert type(target) is lief.ELF.Binary
abstract = target.abstract
assert type(abstract) is lief.Binary
In C++, one can downcast a LIEF::Binary
instance into its effective type using the classof
idiom:
std::unique_ptr<LIEF::Binary> target = LIEF::Parser::parse("some.elf");
if (LIEF::ELF::Binary::classof(target.get())) {
auto& elf = static_cast<LIEF::ELF::Binary&>(*target);
}