LIEF v0.17.0
This blog post highlights the different changes introduced in LIEF 0.17.0

This new version of LIEF introduces several improvements and features that expand the scope of LIEF’s use cases.
Reverse Engineering Plugins
Reverse engineering frameworks like Binary Ninja and Ghidra provide excellent support for analyzing instructions and functions. However, they might lack an in-depth analysis of all structures associated with executable formats.
For example, the latest version of Ghidra (11.4.2) and Binary Ninja (5.1.8104)
are not able to accurately process Windows ARM64EC binaries, which combine ARM64 code
with x86_64. ARM64EC binaries use specific structures such as IMAGE_ARM64EC_METADATA, that
are not (yet) recognized by most of the reverse engineering frameworks:
This IMAGE_ARM64EC_METADATA structure contains the ExtraRFE attribute, which
is used to reference an exception table that is specific to the ARM64EC:
As for the x86_64 architecture, this table can be used to increase the coverage
of functions recognized by BinaryNinja:
The source code of these plugins is located in the main LIEF repository under the following directories:
This new release of LIEF introduces official and maintained support for both Binary Ninja and Ghidra, enhancing the analysis capabilities and type definitions for these frameworks.
Contextual Assembly Patching
Note
The feature is only available in LIEF Extended
When patching assembly code, we frequently need to refer to external data or functions within our assembly listing.
For instance, we might want to naturally write:
1elf = lief.ELF.parse("libdexprotector.so")
2elf.assemble(
3 elf.get_function_address("libdp_init"),
4 """
5 adrp x4, g_protections_conf
6 add x4, x4, :lo12:g_protections_conf
7 strb wzr, [x4, 0xe] // Disable debug check.
8 """
9)
In this code snippet, we assume that the address of g_protections_conf is known.
With the latest release, the assembler engine has introduced support for dynamically
resolving symbols referenced in an assembly listing.
This functionality works by providing an additional configuration parameter:
1class Config(lief.assembly.AssemblerConfig):
2 def __init__(self, target: lief.Binary):
3 super().__init__()
4 self._target = target
5
6 def resolve_symbol(self, name: str) -> int | None:
7 dwarf_info: lief.dwarf.DebugInfo = self._target.debug_info
8 if var := dwarf_info.find_variable(name):
9 print(f"'{name}' is located at address: 0x{var.address:016x}")
10 return var.address
11 return super().resolve_symbol(name)
12
13elf = lief.ELF.parse("libdexprotector.so")
14
15config = Config(elf)
16elf.assemble(
17 elf.get_function_address("libdp_init"),
18 """
19 adrp x4, g_protections_conf
20 add x4, x4, :lo12:g_protections_conf
21 strb wzr, [x4, 0xe] // Disable debug check.
22 """, config
23)
The logic of the resolve_symbol function depends on DWARF information that is
generated by BinaryNinja (see: BinaryNinja - DWARF Plugin)
After patching, we can see the final results, which show that the adrp
instructions have been correctly generated to access the g_protections_conf.debug_check variable:
For more details about the API, you can check: https://lief.re/doc/latest/extended/assembler/index.html#contextual-assembly-patching
PE Refactoring

LIEF’s PE module has been significantly refactored, including improvements to the parser, builder, and documentation. These improvements bring this format to a level of maturity comparable to other formats (ELF/Mach-O). The most notable enhancements involve the ability to modify TLS, as well as manage imports and exports. It also provides support for ARM64EC and ARM64X binaries.
For more details, please refer to:
- this blog post: https://lief.re/blog/2025-02-16-arm64ec-pe-support/
- this dedicated changelog: https://lief.re/doc/latest/changelog/pe-0-17-0.html#pe-0170-changelog
lief-patchelf
For this release, I started to bootstrap LIEF-based tools (mostly CLI) that aim to
provide specific functionalities using LIEF. The first tool of this bootstrap is
lief-patchelf, which provides a drop-in replacement for the well-known NixOS/patchelf.
You can find insight about this tool in this blog post: https://lief.re/blog/2025-07-13-patchelf/
COFF Format
The COFF format is now supported by LIEF, but it does not support modifications yet. The API is really similar to the other formats and available in C++/Rust/Python:
1import lief
2coff: lief.COFF.Binary = lief.COFF.parse(r"C:\Users\romain\test.obj")
3
4# Access symbols and aux info
5for symbol in coff.symbols:
6 print(symbol.name)
7 for aux in symbol.auxiliary_symbols:
8 assert str(aux) == """
9 AuxiliaryCLRToken {
10 Aux Type: 1
11 Reserved: 1
12 Symbol index: 10
13 Symbol: ??0CppInlineNamespaceAttribute@?A0xb81de522@vc.cppcli.attributes@@$$FQE$AAM@PE$[...]
14 Rgb reserved:
15 +---------------------------------------------------------------------+
16 | 00 00 00 00 00 00 00 00 00 00 00 00 | ............ |
17 +---------------------------------------------------------------------+
18 }
19 """
20
21# Disassembler support
22for inst in coff.disassemble("?foo@@YAHHH@Z")
23 print(inst)
The documentation for this format is here: https://lief.re/doc/latest/formats/coff/index.html
Final Word
Version 0.17.0 is the latest release in the 0.X.Y series.
With significant improvements to the PE format and the global scale at which
LIEF is used, I believe the project is now ready for its upcoming 1.0 version.
The complete changelog is here: https://lief.re/doc/latest/changelog.html
Happy LIEF,
Romain