Exports Modification

PE Resources Overview

LIEF provides extensive support for modifying the PE export table, enabling you to add, remove, or modify export entries, or create an entire export table for a PE binary.

Creating Export Entries

Creating a is useful for exposing a “hidden” function by its address, allowing it to be used like a standard linker-generated export.

This could be used for code lifting or fuzzing.

import lief

pe: lief.PE.Binary = ...

exp: lief.PE.Export = pe.get_export()

# Remove an entry
exp.remove_entry("my_exported_name")

# Add a new export
exp.add_entry("fuzz_me", 0x10010)

config = lief.PE.Builder.config_t()
config.exports = True
config.export_section = ".myedata" # optional

pe.write("out.dll", config)

Creating an Export Table

This section introduces the API for creating an export table. We’ll explore a scenario where we want to convert a PE executable into a DLL.

Note

The process of converting an executable to a library is also detailed for ELF binaries in the tutorial: 08 - Transforming an ELF executable into a library.

First, we must update the PE headers to ensure they are compliant with the DLL format:

import lief

pe: lief.PE.Binary = ...

pe.header.add_characteristic(lief.PE.Header.CHARACTERISTICS.DLL)
pe.optional_header.addressof_entrypoint = 0

Then, we can start creating and populating a new export table:

exp = lief.PE.Export("lib_exe2dll.dll", [
    lief.PE.ExportEntry("cbk1", 0x0001000),
    lief.PE.ExportEntry("cbk2", 0x0001010),
])

pe.set_export(exp)

config = lief.PE.Builder.config_t()
config.exports = True

pe.write("lib_exe2dll.dll")

Limitations

This binary-to-library example assumes that the original executable was compiled to be position-independent, meaning it contains relocations.

Within a Python environment, we can verify that lib_exe2dll.dll can be loaded as a DLL and that we can call cbk1 and cbk2:

import ctypes

lib = ctypes.windll.LoadLibrary("lib_exe2dll.dll")

assert lib.cbk1() >= 0
assert lib.cbk2() >= 0