---
title: "LIEF v0.17.0"
description: "LIEF 0.17.0: Binary Ninja and Ghidra plugins, contextual assembly patching, a refactored PE module with TLS, import, and export editing, lief-patchelf, and COFF support."
canonical_url: "https://lief.re/blog/2025-09-14-lief-0-17-0/"
markdown_url: "https://lief.re/blog/2025-09-14-lief-0-17-0/index.md"
authors: ["Romain Thomas"]
date_published: "2025-09-14T00:00:00Z"
date_modified: "2025-09-14T00:00:00Z"
language: "en-US"
section: "blog"
tags: ["release","PE","COFF","assembler","Binary Ninja","Ghidra","patchelf"]
categories: []
---

# LIEF v0.17.0

> LIEF 0.17.0: Binary Ninja and Ghidra plugins, contextual assembly patching, a refactored PE module with TLS, import, and export editing, lief-patchelf, and COFF support.

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:


![Comparison: before](https://lief.re/blog/2025-09-14-lief-0-17-0/chpe_metadata_before.svg)

![Comparison: after](https://lief.re/blog/2025-09-14-lief-0-17-0/chpe_metadata_after.svg)


This `IMAGE_ARM64EC_METADATA` structure contains the `ExtraRFE` attribute, which
is used to reference an exception table that is specific to the ARM64EC:


![Comparison: before](https://lief.re/blog/2025-09-14-lief-0-17-0/rdata_before.svg)

![Comparison: after](https://lief.re/blog/2025-09-14-lief-0-17-0/rdata_after.svg)


As for the `x86_64` architecture, this table can be used to increase the coverage
of functions recognized by BinaryNinja:


![Comparison: before](https://lief.re/blog/2025-09-14-lief-0-17-0/featmap_before.svg)

![Comparison: after](https://lief.re/blog/2025-09-14-lief-0-17-0/featmap_after.svg)


The source code of these plugins is located in the main LIEF repository under
the following directories:

- [plugins/binaryninja](https://github.com/lief-project/LIEF/tree/main/plugins/binaryninja)
- [plugins/ghidra](https://github.com/lief-project/LIEF/tree/main/plugins/ghidra)

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](https://lief.re/doc/latest/extended/intro.html)


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:

```python
elf = lief.ELF.parse("libdexprotector.so")
elf.assemble(
    elf.get_function_address("libdp_init"),
    """
    adrp x4, g_protections_conf
    add x4, x4, :lo12:g_protections_conf
    strb wzr, [x4, 0xe] // Disable debug check.
    """
)
```


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:

```python {linenos=inline hl_lines=["1-11", 22]}
class Config(lief.assembly.AssemblerConfig):
    def __init__(self, target: lief.Binary):
        super().__init__()
        self._target = target

    def resolve_symbol(self, name: str) -> int | None:
        dwarf_info: lief.dwarf.DebugInfo = self._target.debug_info
        if var := dwarf_info.find_variable(name):
            print(f"'{name}' is located at address: 0x{var.address:016x}")
            return var.address
        return super().resolve_symbol(name)

elf = lief.ELF.parse("libdexprotector.so")

config = Config(elf)
elf.assemble(
    elf.get_function_address("libdp_init"),
    """
    adrp x4, g_protections_conf
    add x4, x4, :lo12:g_protections_conf
    strb wzr, [x4, 0xe] // Disable debug check.
    """, config
)
```

The logic of the `resolve_symbol` function depends on DWARF information that is
generated by BinaryNinja (see: [ BinaryNinja - DWARF Plugin](https://lief.re/doc/latest/plugins/binaryninja/dwarf/index.html#export-as-dwarf))

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:


![Comparison: before](https://lief.re/blog/2025-09-14-lief-0-17-0/dxp_lhs.svg)

![Comparison: after](https://lief.re/blog/2025-09-14-lief-0-17-0/dxp_rhs.svg)


For more details about the API, you can check: https://lief.re/doc/latest/extended/assembler/index.html#contextual-assembly-patching

## PE Refactoring

![MSVC PE import table layout showing the IAT, ILT, headers, and string table](https://lief.re/blog/2025-09-14-lief-0-17-0/msvc_layout.webp)

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](https://github.com/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:

```python
import lief
coff: lief.COFF.Binary = lief.COFF.parse(r"C:\Users\romain\test.obj")

# Access symbols and aux info
for symbol in coff.symbols:
    print(symbol.name)
    for aux in symbol.auxiliary_symbols:
        assert str(aux) == """
          AuxiliaryCLRToken {
            Aux Type: 1
            Reserved: 1
            Symbol index: 10
            Symbol: ??0CppInlineNamespaceAttribute@?A0xb81de522@vc.cppcli.attributes@@$$FQE$AAM@PE$[...]
            Rgb reserved:
              +---------------------------------------------------------------------+
              | 00 00 00 00 00 00 00 00 00 00 00 00              | ............     |
              +---------------------------------------------------------------------+
          }
          """

# Disassembler support
for inst in coff.disassemble("?foo@@YAHHH@Z")
    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

[^llvm-engine]: Based on LLVM 21: https://lief.re/doc/latest/extended/intro.html#lief-extended-llvm
