Tl;DR
LIEF v0.11.1 fixes some issues related to PE Authentihash computation. The new packages are available on PyPI and the SDKs can be downloaded on the official website.Enjoy!
LIEF 0.11.0 missed handling some cases in the processing of the PE Authentihash. This new release addresses these issues and the following blog post explains the cases we did not handle.
PE section’s names are stored in a fixed char array (8 bytes) which means that a section’s name can contain trailing bytes after the null char:
1struct pe_section {
2 char name[8];
3 uint32_t RVA;
4 // ...
5};
Before v0.11.1, LIEF didn’t take into account the trailing bytes and stopped to read the section’s name on the first null char:
1this->name_ = std::string(header->name, sizeof(header->name)).c_str();
This implementation has two drawbacks. First, we lose information since we don’t store the extra trailing bytes. Regular binaries have zero trailing bytes after the first null char but some of them might use this spot to hide data.
Secondly, the full section name (i.e the whole 8 bytes) is used to compute the Authentihash. Therefore, if the first null char is followed by trailing bytes different from zero, the computed hash is inconsistent.
According to the PE specifications 1 the last entry of the data directory table must contain a null entry (i.e. an entry with an RVA and size set to 0).
It turns out that this requirement is
not enforced by the loader. In the case of the binary (bc203f2b6a…)
the last entry is set to 0x02b7bc68/0x01a7a0
(used for watermarking?).
In the previous versions of LIEF we assumed that the last entry of the data directory table was always zero. Since the last entry is used to compute the Authentihash value, it led to a bad signature while it was effectively correct.
This issue has been addressed in the commit 3c65ffe
verify_signature()
As noticed by Cedric Halbronn in the issue issues/532,
the return value of LIEF::PE::Binary::verify_signature
lacks of information when the verification failed. The return value was either
VERIFICATION_FLAGS.OK
or VERIFICATION_FLAGS.BAD_SIGNATURE
because of a fail-fast implementation
of the verification flag.
The function now returns flags as follows:
VERIFICATION_FLAGS.BAD_DIGEST | VERIFICATION_FLAGS.BAD_SIGNATURE | VERIFICATION_FLAGS.CERT_EXPIRED
One of the critical issues raised by imidoriya and fixed in the new version is the processing of the overlay data when the “data directory signature” is located in this area (c.f. 463bb0ec3…). This kind of layout triggers a memory error on this part of the processing Binary.cpp#L1174-L1187. It has been addressed in the commit 05103f5
Thanks to Andrew Williams for providing the different samples that raised some of these errors! Thank you also to Cedric Halbronn and the CERT Gouvernemental of Luxembourg for their feedback about the API.