LIEF extended exposes a user-friendly API to disassemble code in different places of executable formats for the following architectures: x86/x86-64, ARM, AArch64, RISC-V, Mips, PowerPC, eBPF.
import lief
elf = lief.ELF.parse("/bin/hello")
inst: lief.assembly.Instruction = ...
for inst in elf.disassemble(0x400120):
print(inst)
auto pe = LIEF::PE::Parser::parse("cmd.exe");
std::unique_ptr<LIEF::assembly::Instruction> inst;
for (inst : pe->disassemble("_WinRT")) {
std::cout << inst->to_string() << '\n';
}
let elf = lief::elf::Binary::parse("/bin/ls");
for inst in elf.disassemble_address(0x400) {
println!("{}", inst.to_string());
}
Thus, when calling elf.disassemble_address(0x400)
, nothing is disassembled until the iterator is processed.
In Python, one can check the effective type of a lief.assembly.Instruction
with isinstance(...)
:
inst: lief.assembly.Instruction = ...
if isinstance(inst, lief.assembly.riscv.Instruction):
opcode: lief.assemble.riscv.OPCODE = inst.opcode
In C++, downcasting can be done using the function: LIEF::assembly::Instruction::as()
:
std::unique_ptr<LIEF::assembly::Instruction> inst = ...;
if (const auto* riscv_inst = inst->as<LIEF::assembly::riscv::Instruction>())
{
LIEF::assembly::riscv::OPCODE opcode = riscv_inst->opcode();
}
In Rust, instructions are represented by the enum lief::assembly::Instructions
. Thus, you can write:
fn check_opcode(inst: &lief::assembly::Instructions) {
if let lief::assembly::Instructions::RiscV(riscv) = inst {
println!("{:?}", riscv.opcode());
}
}
Note
You can also check the assembler documentation here: Assembler
Warning
.dSYM
files.import lief
elf = lief.ELF.parse("/bin/hello")
main = elf.debug_info.find_function("main")
for inst in .instructions:
print(inst)
auto elf = LIEF::ELF::Parser::parse("/bin/hello");
if (const auto* dwarf = elf->debug_info()->as<LIEF::dwarf::DebugInfo>())
{
std::unique_ptr<LIEF::dwarf::Function> _main = dwarf->find_function("main");
for (const auto& inst : _main->instructions()) {
std::cout << inst->to_string() << '\n';
}
}
let elf = lief::elf::Binary::parse("/bin/ls");
if let Some(lief::DebugInfo::Dwarf(dwarf)) = elf.debug_info() {
if Some(func) = dwarf.find_function("main") {
for inst in func.instructions() {
println!("{}", inst.to_string());
}
}
}
The disassembler is based on the LLVM’s MC layer which is known to be efficient and accurate for disassembling code. This LLVM’s MC layer has already been used by other projects like capstone or more recently Nyxstone.
Compared to Capstone, LIEF uses a mainstream LLVM version without any modification on the MC layer. On the other hand, it does not expose a C API, supports fewer architectures than Capstone, and does not expose a standalone API.
Compared to Nyxstone’s disassembler, LLVM is hidden from the public API which means that LLVM does not need to be installed on the system. On the other hand, it does not expose a standalone API.
Rust API: lief::assembly