Home
Fix relocation issue when using -Wl,–emit-relocs (c.f. #897 / #898 by adamjseitz)
Improve the computation of the dynamic symbols thanks to adamjseitz (c.f. #922)
Add support for the LoongArch architecture thanks to loongson-zn (c.f. #921)
The fileset name is now stored in lief.MachO.Binary.fileset_name
(instead of lief.MachO.Binary.name)
Add a lief.PE.ParserConfig
interface that can be used to tweak which parts of the PE format should be parsed (#839).
config = lief.PE.ParserConfig()
# Skip parsing PE authenticode
config.parse_signature = False
pe = lief.PE.parse("pe.exe", config)
Remove the lief.Binary.name attribute
LIEF is now compiled with C++17 (the API remains C++11 compliant)
Fix overflow issue in segments (c.f. #845 found by liyansong2018)
Fix missing relationship between symbols and sections (c.f. #841)
Fix and (re)enable removing dynamic symbols (c.f. #828)
Add support for NT_GNU_BUILD_ATTRIBUTE_OPEN and NT_GNU_BUILD_ATTRIBUTE_FUNC (c.f. #816)
[CVE-2022-38497] Fix ELF core parsing issue (#766 found by CCWANG19)
[CVE-2022-38306] Fix a heap overflow found by CCWANG19 (#763)
aeflores fixed an issue when there are multiple versions associated with a symbol (see: #749 for the details).
Handle binaries compiled with the -static-pie flag correctly (see: #747)
Add support for modifying section-less binaries. The ELF Section
objects gain the lief.ELF.Section.as_frame()
method which defines the section as a framed section.
A framed section is a section that concretely does not wraps data and can be corrupted.
elf = lief.parse("/bin/ssh")
text = elf.get_section(".text").as_frame()
# We can now corrupt all the fields of the section
text.offset = 0xdeadc0de
text.size = 0xffffff
text.address = 0x123
elf.write("/tmp/out")
Add API to precisely define how the segments table should be relocated. One might want to enforce a certain ELF layout while adding sections/ segments. It is now possible to call the method: relocate_phdr_table()
to define how the segments table should be relocated for welcoming the new sections/segments:
elf = lief.parse("...")
# Enforce a specific relocation type:
# The new segments table will be shift at the end
# of the file
elf.relocate_phdr_table(Binary.PHDR_RELOC.FILE_END)
# Add sections/segments
# [...]
elf.write("out.elf")
See:
Add support for parsing Mach-O in memory
[CVE-2022-38307] Fix a segfault when the Mach-O binary does not have segments (found by CCWANG19 via #764)
Enable to create exports
Fix the layout of the binaries modified by LIEF such as they can be (re)signed.
Add support for LC_DYLD_CHAINED_FIXUPS and LC_DYLD_EXPORTS_TRIE
Global enhancement when modifying the __LINKEDIT content
Add API to get a Section
from a specified segment’s name and section’s name.
sec = bin.get_section("__DATA", "__objc_metadata")
Add API to remove a Section
from a specified segment’s name and section’s name.
sec = bin.remove_section("__DATA", "__objc_metadata")
The Python API now returns bytes objects instead of List[int]
Remove lief.PE.ResourceNode.sort_by_id()
Fix the ordering of children of ResourceNode
Remove deprecated functions related to PE hooking.
Add support for new PE LoadConfiguration structures.
Fix multiple parsing issues raised by bladchan
Move to a build system compliant with pyproject.toml
Provide typing stubs: #650
PyPI releases no longer provide source distribution (sdist)
Move to spdlog 1.11.0
Move to Pybind11 - 2.10.1
Move to nlohmann/json 3.11.2
Move to MbedTLS 3.2.1
Move to utfcpp 3.2.1
This release contains several security fixes:
ahaensler added the support to insert and assign a lief.ELF.SymbolVersionAuxRequirement
(see: #670)
Enhance the ELF parser to support corner cases described by netspooky in :
https://tmpout.sh/2/14.html (84 byte aarch64 ELF)
https://tmpout.sh/2/3.html (Some ELF Parser Bugs)
New ELF Builder which is more efficient in terms of speed and in terms of number of segments added when modifying binaries (see: https://lief-project.github.io/blog/2022-01-23-new-elf-builder/)
Clcanny improved (see #507 and #509) the reconstruction of the dynamic symbol table by sorting local symbols and non-exported symbols. It fixes the following warning when parsing a modified binary with readelf
Warning: local symbol 29 found at index >= .dynsym's sh_info value of 1
Change the layout of the binaries generated by LIEF such as they are compliant with codesign
checks
The API to configure the MachO parser has been redesigned to provide a better granularity
config = lief.MachO.ParserConfig()
config.parse_dyld_bindings = False
config.parse_dyld_exports = True
config.parse_dyld_rebases = False
lief.MachO.parse("/tmp/big.macho", config)
LucaMoroSyn added the support for the LC_FILESET_ENTRY
. This command is usually found in kernel cache files
LIEF::MachO::Binary::get_symbol
now returns a pointer (instead of a reference). If the symbol can’t be found, it returns a nullptr.
Add API to select a Binary
from a FatBinary
by its architecture. See: lief.MachO.FatBinary.take()
.
fat = lief.MachO.parse("/bin/ls")
fit = fat.take(lief.MachO.CPU_TYPES.x86_64)
Handle the 0x0D binding opcode (see: #524)
xhochy fixed performances issues in the Mach-O parser (see #579)
Adding lief.PE.OptionalHeader.computed_checksum
that re-computes the lief.PE.OptionalHeader.checksum
(c.f. issue #660)
Enable to recompute the RichHeader
(issue: #587)
Add support for PE’s delayed imports. see:
lief.PE.LoadConfiguration.reserved1
has been aliased to lief.PE.LoadConfiguration.dependent_load_flags
lief.PE.LoadConfiguration.characteristics
has been aliased to lief.PE.LoadConfiguration.size
Thanks to gdesmar, we updated the PE checks to support PE files that have a corrupted lief.PE.OptionalHeader.magic
(cf. #644)
Abstract binary imagebase for PE, ELF and Mach-O (lief.Binary.imagebase
)
Add PE imports/exports as abstracted symbols
ekilmer updated and modernized the CMake integration files through the PR: #674
Enable to use a pre-compiled version of spdlog. This feature aims at improving compilation time when developing on LIEF.
One can provide path to spdlog install through:
$ python ./setup.py --spdlog-dir=path/to/lib/cmake/spdlog [...]
# or
$ cmake -DLIEF_EXTERNAL_SPDLOG=ON -Dspdlog_DIR=path/to/lib/cmake/spdlog ...
Enable to feed LIEF’s dependencies externally (c.f. Third Party)
Replace the keywords and
, or
, not
with &&
, ||
and !
.
Upgrade to MbedTLS 3.1.0
Upgrade Catch2 to 2.13.8
The different dependencies can be linked externally (cf. above and Third Party)
New section about the errors handling (Error Handling) and the upcoming deprecation of the exceptions.
New section about how to compile LIEF for debugging/developing. See: Debugging
LIEF now exposes Section/Segment’s data through a span interface. As std::span is available in the STL from C++20 and the LIEF public API aims at being C++11 compliant, we expose this span thanks to tcbrindle/span. This new interface enables to avoid copies of std::vector<uint8_t>
which can be costly. With this new interface, the original std::vector<uint8_t>
can be retrieved as follows:
auto bin = LIEF::ELF::Parser::parse("/bin/ls");
if (const auto* section = bin->get_section(".text")) {
LIEF::span<const uint8_t> text_ref = section->content();
std::vector<uint8_t> copy = {std::begin(text_ref), std::end(text_ref)};
}
In Python, span are wrapped by a read-only memory view. The original list of bytes can be retrieved as follows:
bin = lief.parse("/bin/ls")
section = bin.get_section(".text")
if section is not None:
memory_view = section.content
list_of_bytes = list(memory_view)
Warning
We started to refactor the API and the internal design to remove C++ exceptions. These changes are described a the dedicated blog (LIEF RTTI & Exceptions)
To highlighting the content of the blog for the end users, functions that returned a reference and which threw an exception in the case of a failure are now returning a pointer that is set to nullptr in the case of a failure.
If we consider this original code:
LIEF::MachO::Binary& bin = ...;
try {
LIEF::MachO::UUIDCommand& cmd = bin.uuid();
std::cout << cmd << "\n";
} catch (const LIEF::not_found&) {
// ... dedicated processing
}
// Other option with has_uuid()
if (bin.has_uuid()) {
LIEF::MachO::UUIDCommand& cmd = bin.uuid();
std::cout << cmd << "\n";
}
It can now be written as:
LIEF::MachO::Binary& bin = ...;
if (LIEF::MachO::UUIDCommand* cmd = bin.uuid();) {
std::cout << *cmd << "\n";
} else {
// ... dedicated processing as it is a nullptr
}
// Other option with has_uuid()
if (bin.has_uuid()) { // It ensures that it is not a nullptr
LIEF::MachO::UUIDCommand& cmd = *bin.uuid();
std::cout << cmd << "\n";
}
Remove usage of not
in public headers (b8e825b)
Fix issue when computing lief.PE.Binary.sizeof_headers
(ab3f073)
Fix error on property lief.MachO.BuildVersion.sdk
(see #533)
Fix missing bound check when computing the authentihash
Add sanity check on the signature’s length that could lead to a std::bad_alloc
exception
Fix regression in the behavior of the PE section’s name. One can now access the full section’s name (with trailing bytes) through lief.PE.Section.fullname
(see: #551)
lief.PE.x509.is_trusted_by()
and lief.PE.x509.verify()
now return a better lief.PE.x509.VERIFICATION_FLAGS
instead of just lief.PE.x509.VERIFICATION_FLAGS.BADCERT_NOT_TRUSTED
(see: #532)
Fix errors in the computation of the Authentihash
aeflores added MIPS relocations support in the ELF parser
Fix issue when exporting symbols on empty-gnu-hash ELF binary (1381f9a)
Fix reconstruction issue when the binary is prelinked (cf. issue #466)
Add DF_1_PIE
flag
Fix parsing issue of the .eh_frame
section when the base address is not 0.
JanuszL enhanced the algorithm that computes the string table. It moves from a N^2
algorithm to a Nlog(N)
(1e0c4e8).
Fix .eh_frame
parsing issue (b57f323)
Add PT_GNU_PROPERTY
enum
Bug fix in the symbols table reconstruction (ELF)
Enhance PE Authenticode. See PE Authenticode
get_imphash()
can now generate the same value as pefile and Virus Total (#299)
pe = lief.parse("example.exe")
vt_imphash = lief.PE.get_imphash(pe, lief.PE.IMPHASH_MODE.PEFILE)
lief_imphash = lief.PE.get_imphash(pe, lief.PE.IMPHASH_MODE.DEFAULT)
See also
Remove the padding entry (0) from the rich header
items
now returns a dictionary for which the values are bytes (instead of str
object). This change is related to utf-16
support.
kohnakagawa fixed wrong enums values: c031250, 6ee808a, cd05f34
kohnakagawa fixed a bug in the PE resources parser (a7254d1)
Handle PE forwarded exports (issue #307)
Replace easyloggingpp
with spdlog 1.8.1
Upgrade frozen
to 1.0.0
Upgrade json
to 3.7.3
Upgrade pybind11
to 2.6.0
Upgrade mbedtls
to 2.16.6
aguinet updated the bin2lib tutorial with the support of the new glibc versions (7884e57)
Global update and enable to build the documentation out-of-tree
Changing the theme
Add Python 3.9 support
FindLIEF.cmake
deprecates LIEF_ROOT
. You should use LIEF_DIR
instead.
We changed the logging interface. The following log levels have been removed:
LOG_GLOBAL
LOG_FATAL
LOG_VERBOSE
LOG_UNKNOWN
We also moved from an class-interface based to functions.
Example:
lief.logging.disable()
lief.logging.enable()
lief.logging.set_level(lief.logging.LOGGING_LEVEL.INFO)
Note
The log functions now output on stderr
instead of stdout
Fix regression in parsing Python bytes
Add Python API to demangle strings: lief.demangle
Add build support for ELF notes
Add coredump support (9fc3a8a)
Enable to bind a relocation with a symbol (a9f3cb8)
relocation = "..."
symbol = lief.ELF.Symbol()
symbol.name = "printf123"
relocation.symbol = symbol
Add constructors (67d924a)
Expose ELF destructors (957384c)
Add remove_static_symbol
(c677970)
Add support for static relocation writing (d1b98d6)
Expose function to get strings located in the .rodata
section (02f4851)
Export ELF ABI version (8d7ec26)
Enhance Mach-O modifications by exposing an API to:
Add load commands
Add sections
Add segments
See: 406115c
Enable write()
on FAT Mach-O (1659531)
Introduce Mach-O Build Version command (6f96723)
Enable to remove Mach-O symbols (616d739)
Add support for adding LC_UNIXTHREAD
commands in a MachO (by nezetic - 64d2597)
Add partial support for Android 9 (bce9ebe)
lkollar added support for Python 3.8 in CI (Linux & OSX only)
Update Pybind11 dependency to v2.4.3
Enhance Python install (see: Since 0.10.0)
Thanks to lkollar, Linux CI now produces manylinux1-compliant wheels
Many thanks to the contributors: recvfrom, pbrunet, mackncheesiest, wisk, nezetic, lkollar, jbremer, DaLynX, 1orenz0, breadchris, 0xbf00, unratito, strazzere, aguinetqb, mingwandroid, serge-sans-paille-qb, yrp604, majin42, KOLANICH
LIEF 0.9 comes with new formats related to Android: OAT, DEX, VDEX and ART. It also fixes bugs and thanks to yd0b0N, ELF parser now supports big and little endian binaries. We also completed the JSON serialization of LIEF objects. Enable to configure the Mach-O parser for quick parsing: 880b99a Add Add Add Add Add Add API to show export-trie, rebase and binding opcodes: 5d56141 Add PE Code View: eab4a76 Parser now returns a Use frozen for some internal Features¶
lief.MachO.EncryptionInfo
command: f4e2d81lief.MachO.RPathCommand
command: 196994dlief.MachO.DataInCode
command: a16e1c4lief.MachO.SubFramework
command: 9e3b5b4lief.MachO.SegmentSplitInfo
command: 9e3b5b4lief.MachO.DyldEnvironment
command: 9e3b5b4API¶
lief.parse()
now support io
streams as inputstd::unique_ptr
instead of a raw pointer: cd1cc45Misc¶
std::map
(If C++14 is supported by the compiler)Acknowledgements¶
[Mach-O] Fix typo on comparison operator - abbc264
[ELF] Increase the upper limit of relocation number - 077bc32
LIEF 0.8.0 mainly improves the MachO parser and the ELF builder. It comes with Dockerfiles for CentOS and Android.
LibFuzzer has also been integrated in the project to enhance the parsers Add the Handle relocations of object files ( Global enhancement of the ELF builder: One can now add multiple One can now add multiple entries in the dynamic table: b2d3694 enables modification of the ELF interpreter without length restriction Enhancement of the dynamic symbols counting - 985d124 Enable editing ELF’s notes: See commit 3be9dd0 for more details Add Parse the Load Config Table into For details, see commit: 0234e3b The Binding opcodes Rebases opcodes Export trie Section relocations are now parsed into Fix enums conflicts(#32) - 66b4cd4 Fix most of the memory leaks: 88dafa8, d9b1436, 554fa15, 3602643 In the C++ API Add [Python API] Enhance the access to the abstract layer through the One can now do: Add Add: To check if a given flag is set, one can do: [Python] Segment flags: Enhancement for Enhancement for Add some operators 5666351 Add some operators: cbe8354 Add an API to configure the logger - 4600c2b Example: See: Add FindLIEF.cmake - 6dd8b10 Add ASAN, TSAN, USAN, LSAN - 7f6aeb0 Add LibFuzzer - 7a0dc28 recomposer, bearparser, IAT_patcher, PEframe, Manalyze, MachOView, elf-dissectorFeatures¶
Relocation
are now abstracted from the 3 formats - 9503f2fPIE
and NX
are abstracted through the is_pie
and has_nx
propertieslief.Section.search()
and lief.Section.search_all()
methods to look for patterns in the section’s content.DT_FLAGS
and DT_FLAGS_1
are now parsed into DynamicEntryFlags
- 754b8af.o
) - 483b8dcSection
or Segment
into an ELF:elf = lief.parse("/bin/cat")
for i in range(3):
segment = Segment()
segment.type = SEGMENT_TYPES.LOAD
segment.content = [i & 0xFF] * 0x1000
elf += segment
for i in range(3):
section = Section("lief_{:02d}".format(i))
section.content = [i & 0xFF] * 0x1000
elf += section
elf.write("foo")
$ readelf -l ./foo
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000061f8 0x00000000000061f8 R E 0x8
INTERP 0x0000000000006238 0x0000000000006238 0x0000000000006238
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000000d6d4 0x000000000000d6d4 R E 0x200000
LOAD 0x000000000000da90 0x000000000020da90 0x000000000020da90
0x0000000000000630 0x00000000000007d0 RW 0x200000
LOAD 0x000000000000f000 0x000000000040f000 0x000000000040f000
0x0000000000001000 0x0000000000001000 0x1000
LOAD 0x0000000000010000 0x0000000000810000 0x0000000000810000
0x0000000000001000 0x0000000000001000 0x1000
LOAD 0x0000000000011000 0x0000000001011000 0x0000000001011000
0x0000000000001000 0x0000000000001000 0x1000
....
$ readelf -S ./foo
...
[27] lief_00 PROGBITS 0000000002012000 00012000
0000000000001000 0000000000000000 0 0 4096
[28] lief_01 PROGBITS 0000000004013000 00013000
0000000000001000 0000000000000000 0 0 4096
[29] lief_02 PROGBITS 0000000008014000 00014000
0000000000001000 0000000000000000 0 0 4096
elf = lief.parse("/bin/cat")
elf.add_library("libfoo.so")
elf.add(DynamicEntryRunPath("$ORIGIN"))
elf.add(DynamicEntry(DYNAMIC_TAGS.INIT, 123))
elf.add(DynamicSharedObject("libbar.so"))
elf.write("foo")
$ readelf -d foo
0x0000000000000001 (NEEDED) Shared library: [libfoo.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x7b
0x000000000000000c (INIT) 0x3600
...
0x000000000000001d (RUNPATH) Bibliothèque runpath:[$ORIGIN]
0x000000000000000e (SONAME) Bibliothèque soname: [libbar.so]
elf = lief.parse("/bin/cat")
elf.interpreter = "/a/very/long/path/to/another/interpreter"
elf.write("foo")
$ readelf -l foo
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000011f8 0x00000000000011f8 R E 0x8
INTERP 0x000000000000a000 0x000000000040a000 0x000000000040a000
0x0000000000001000 0x0000000000001000 R 0x1
[Requesting program interpreter: /a/very/long/path/to/another/interpreter]
....
elf = lief.parse("/bin/ls")
build_id = elf[NOTE_TYPES.BUILD_ID]
build_id.description = [0xFF] * 20
elf.write("foo")
$ readelf -n foo
Displaying notes found in: .note.gnu.build-id
Owner Data size Description
GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)
Build ID: ffffffffffffffffffffffffffffffffffffffff
get_imphash()
and resolve_ordinals()
functions - a89bc6d, dfa8e98LoadConfiguration
(up to Windows 10 SDK 15002 with hotpatch_table_offset)from lief import to_json
import json
pe = lief.parse("some.exe")
loadconfig = to_json(pe.load_configuration)) # Using the lief.to_json function
pprint(json.loads(to_json(loadconfig)))
{'characteristics': 248,
'code_integrity': {'catalog': 0,
'catalog_offset': 0,
'flags': 0,
'reserved': 0},
'critical_section_default_timeout': 0,
'csd_version': 0,
'editlist': 0,
...
'guard_cf_check_function_pointer': 5368782848,
'guard_cf_dispatch_function_pointer': 5368782864,
'guard_cf_function_count': 15,
'guard_cf_function_table': 5368778752,
'guard_flags': 66816,
'guard_long_jump_target_count': 0,
'guard_long_jump_target_table': 0,
'guard_rf_failure_routine': 5368713280,
'guard_rf_failure_routine_function_pointer': 5368782880,
...
dyld
structure is parsed (deeply) into DyldInfo
. It includes:lief.MachO.Section.relocations
- 29c8157LC_FUNCTION_STARTS
is parsed into FunctionStarts
(18d8919)LC_SOURCE_VERSION
, LC_VERSION_MIN_MACOSX
and LC_VERSION_MIN_IPHONEOS
are parsed into SourceVersion
and VersionMin
(c359778, 0b4bb7d, 5b99311, #45)LC_THREAD
and LC_UNIXTHREAD
are now parsed into ThreadCommand
- 2325783Fixes¶
API¶
get_XXX()
getters have been renamed into XXX()
(e.g. get_header()
becomes header()
) - a4c69f7, e805669lief.Binary
gains the format
property - 9391238lief.parse()
can now takes a list of integers - f330fa8has_symbol()
and get_symbol()
to lief.Binary
- f121af5abstract
attribute - 0713854elf = lief.ELF.parse("/bin/ls") # Could be lief.MachO / lief.PE
abstract = elf.abstract # Return the lief.Binary object
lief.ELF.Binary.symbols
which return an iterator over all symbols (static and dynamic) - af6ab65Header.sizeof_section_header
has been renamed into section_header_size
- d96971b>>> if lief.ELF.ARM_EFLAGS.EABI_VER5 in lief.ELF.Header "yes" else "no"
PF_X
, PF_W
, PF_X
has been renamed into X
, W
, X
- d70ef9eDynamicEntryRpath
and DynamicEntryRunPath
: c375a47DynamicEntryArray
: 81440celief.MachO.parse()
can now takes a list of integers - f330fa8lief.MachO.parse()
now returns a FatBinary
instead of a list
of Binary
. FatBinary
has a similar API as a list - 3602643from lief import Logger
Logger.disable()
Logger.enable()
Logger.set_level(lief.LOGGING_LEVEL.INFO)
lief.Logger
Build system¶
Documentation¶
Acknowledgements¶
lief.ELF.Segment.data
has been renamed to lief.ELF.Segment.content
lief.ELF.parse()
takes an optional parameters: symbol counting - lief.ELF.DYNSYM_COUNT_METHODS
lief.PE.Binary.hook_function()
lief.PE.Binary.get_content_from_virtual_address()
takes either an Absolute virtual address or a Relative virtual address
lief.PE.Binary.section_from_virtual_address
has been renamed to lief.PE.Binary.section_from_rva()
.
lief.PE.parse_from_raw
has been removed. One can use lief.PE.parse()
.
lief.PE.Section.data
has been removed. Please use lief.PE.Section.content
elfsteem, pelook, PortEx, elfsharp, metasm, amoco, Goblin
Don’t rely on lief.ELF.Section.entry_size
to count symbols - 004c676
Philippe for the proofreading.
First public release