diff --git a/api/python/PE/objects/pyBinary.cpp b/api/python/PE/objects/pyBinary.cpp index f951d21..5a7e543 100644 --- a/api/python/PE/objects/pyBinary.cpp +++ b/api/python/PE/objects/pyBinary.cpp @@ -135,6 +135,9 @@ void create(py::module& m) { .def_property_readonly("has_signature", &Binary::has_signature, "``True`` if the binary is signed (" RST_CLASS_REF(lief.PE.Signature) ")") + .def_property_readonly("is_reproducible_build", &Binary::is_reproducible_build, + "``True`` if the binary was compiled with a reproducible build directive (" RST_CLASS_REF(lief.PE.Debug) ")") + .def_property_readonly("functions", &Binary::functions, "**All** " RST_CLASS_REF(lief.Function) " found in the binary") @@ -153,10 +156,9 @@ void create(py::module& m) { "Return the " RST_CLASS_REF(lief.PE.Signature) " object", py::return_value_policy::reference) - .def_property_readonly("debug", - static_cast(&Binary::debug), - "Return the " RST_CLASS_REF(lief.PE.Debug) " object", + static_cast(&Binary::debug), + "Return the " RST_CLASS_REF(lief.PE.Debug) "", py::return_value_policy::reference) .def_property_readonly("load_configuration", diff --git a/api/python/PE/pyEnums.cpp b/api/python/PE/pyEnums.cpp index 87e47b5..e0bf2c2 100644 --- a/api/python/PE/pyEnums.cpp +++ b/api/python/PE/pyEnums.cpp @@ -253,7 +253,12 @@ void init_enums(py::module& m) { .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_OMAP_TO_SRC)) .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC)) .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_BORLAND)) - .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_CLSID)); + .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_CLSID)) + .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_VC_FEATURE)) + .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_POGO)) + .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_ILTCG)) + .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_MPX)) + .value(PY_ENUM(LIEF::PE::DEBUG_TYPES::IMAGE_DEBUG_TYPE_REPRO)); LIEF::enum_(m, "RESOURCE_TYPES") diff --git a/examples/cpp/pe_reader.cpp b/examples/cpp/pe_reader.cpp index 31d54c4..709c409 100644 --- a/examples/cpp/pe_reader.cpp +++ b/examples/cpp/pe_reader.cpp @@ -89,7 +89,9 @@ int main(int argc, char **argv) { if (binary->has_debug()) { std::cout << "== Debug ==" << std::endl; - std::cout << binary->debug() << std::endl; + for (const Debug& debug : binary->debug()) { + std::cout << debug << std::endl; + } } diff --git a/include/LIEF/PE/Binary.hpp b/include/LIEF/PE/Binary.hpp index 6c687f0..dd75e8e 100644 --- a/include/LIEF/PE/Binary.hpp +++ b/include/LIEF/PE/Binary.hpp @@ -144,6 +144,11 @@ class LIEF_API Binary : public LIEF::Binary { //! @brief Check if the current binary has a load configuration bool has_configuration(void) const; + //! @brief Check if the current binary has been built has reproducible, replacing timestamps by a compile hash. + //! + //! @see Debug + bool is_reproducible_build(void) const; + //! @brief Return the Signature object if the bianry is signed const Signature& signature(void) const; @@ -237,9 +242,9 @@ class LIEF_API Binary : public LIEF::Binary { bool has(DATA_DIRECTORY index) const; - //! @brief Return the Debug object - Debug& debug(void); - const Debug& debug(void) const; + //! @brief Return the debug_entries_t object + debug_entries_t& debug(void); + const debug_entries_t& debug(void) const; //! @brief Retrun the LoadConfiguration object const LoadConfiguration& load_configuration(void) const; @@ -431,6 +436,7 @@ class LIEF_API Binary : public LIEF::Binary { bool has_relocations_; bool has_debug_; bool has_configuration_; + bool is_reproducible_build_; Signature signature_; TLS tls_; @@ -442,7 +448,7 @@ class LIEF_API Binary : public LIEF::Binary { ResourceNode* resources_; imports_t imports_; Export export_; - Debug debug_; + debug_entries_t debug_; std::vector overlay_; std::vector dos_stub_; diff --git a/include/LIEF/PE/Parser.hpp b/include/LIEF/PE/Parser.hpp index 897fabd..7147f79 100644 --- a/include/LIEF/PE/Parser.hpp +++ b/include/LIEF/PE/Parser.hpp @@ -85,7 +85,7 @@ class LIEF_API Parser : public LIEF::Parser { void parse_export_table(void); void parse_debug(void); - void parse_debug_code_view(void); + void parse_debug_code_view(Debug& debug_info); template void parse_tls(void); diff --git a/include/LIEF/PE/enums.inc b/include/LIEF/PE/enums.inc index 0f35313..30cae9a 100644 --- a/include/LIEF/PE/enums.inc +++ b/include/LIEF/PE/enums.inc @@ -266,6 +266,7 @@ enum _LIEF_EN(DEBUG_TYPES) { _LIEF_EI(IMAGE_DEBUG_TYPE_OMAP_TO_SRC) = 7, ///< The mapping from an RVA in image to an RVA in source image. _LIEF_EI(IMAGE_DEBUG_TYPE_OMAP_FROM_SRC) = 8, ///< The mapping from an RVA in source image to an RVA in image. _LIEF_EI(IMAGE_DEBUG_TYPE_BORLAND) = 9, ///< Reserved for Borland. + _LIEF_EI(IMAGE_DEBUG_TYPE_RESERVED10) = 10, ///< Reserved for future use. _LIEF_EI(IMAGE_DEBUG_TYPE_CLSID) = 11, _LIEF_EI(IMAGE_DEBUG_TYPE_VC_FEATURE) = 12, _LIEF_EI(IMAGE_DEBUG_TYPE_POGO) = 13, diff --git a/include/LIEF/PE/type_traits.hpp b/include/LIEF/PE/type_traits.hpp index b8fd5d0..b5f6179 100644 --- a/include/LIEF/PE/type_traits.hpp +++ b/include/LIEF/PE/type_traits.hpp @@ -65,6 +65,10 @@ using export_entries_t = std::vector; using it_export_entries = ref_iterator; using it_const_export_entries = const_ref_iterator; +using debug_entries_t = std::vector; +using it_debug_entries = ref_iterator; +using it_const_debug_entries = const_ref_iterator; + using symbols_t = std::vector; using it_symbols = ref_iterator; using it_const_symbols = const_ref_iterator; diff --git a/include/LIEF/PE/undef.h b/include/LIEF/PE/undef.h index aaefc70..fd1b98f 100644 --- a/include/LIEF/PE/undef.h +++ b/include/LIEF/PE/undef.h @@ -242,6 +242,7 @@ #undef IMAGE_DEBUG_TYPE_OMAP_TO_SRC #undef IMAGE_DEBUG_TYPE_OMAP_FROM_SRC #undef IMAGE_DEBUG_TYPE_BORLAND +#undef IMAGE_DEBUG_TYPE_RESERVED10 #undef IMAGE_DEBUG_TYPE_CLSID #undef IMAGE_DEBUG_TYPE_VC_FEATURE #undef IMAGE_DEBUG_TYPE_POGO diff --git a/src/PE/Binary.cpp b/src/PE/Binary.cpp index 55cb71e..3c84a35 100644 --- a/src/PE/Binary.cpp +++ b/src/PE/Binary.cpp @@ -92,6 +92,7 @@ Binary::Binary(void) : has_relocations_{false}, has_debug_{false}, has_configuration_{false}, + is_reproducible_build_{false}, tls_{}, sections_{}, data_directories_{}, @@ -358,6 +359,9 @@ bool Binary::has_debug(void) const { return this->has_debug_; } +bool Binary::is_reproducible_build(void) const { + return this->is_reproducible_build_; +} bool Binary::has_configuration(void) const { return this->has_configuration_ and this->load_configuration_ != nullptr; @@ -978,12 +982,12 @@ it_const_data_directories Binary::data_directories(void) const { } -Debug& Binary::debug(void) { - return const_cast(static_cast(this)->debug()); +debug_entries_t& Binary::debug(void) { + return const_cast(static_cast(this)->debug()); } -const Debug& Binary::debug(void) const { +const debug_entries_t& Binary::debug(void) const { return this->debug_; } @@ -1410,7 +1414,9 @@ std::ostream& Binary::print(std::ostream& os) const { if (this->has_debug()) { os << "Debug" << std::endl; os << "=====" << std::endl; - os << this->debug() << std::endl; + for (const Debug& debug : this->debug()) { + os << debug << std::endl; + } os << std::endl; } diff --git a/src/PE/EnumToString.cpp b/src/PE/EnumToString.cpp index be9b525..c39e297 100644 --- a/src/PE/EnumToString.cpp +++ b/src/PE/EnumToString.cpp @@ -385,7 +385,7 @@ const char* to_string(RELOCATIONS_BASE_TYPES e) { const char* to_string(DEBUG_TYPES e) { - CONST_MAP(DEBUG_TYPES, const char*, 16) enumStrings { + CONST_MAP(DEBUG_TYPES, const char*, 17) enumStrings { { DEBUG_TYPES::IMAGE_DEBUG_TYPE_UNKNOWN, "UNKNOWN" }, { DEBUG_TYPES::IMAGE_DEBUG_TYPE_COFF, "COFF" }, { DEBUG_TYPES::IMAGE_DEBUG_TYPE_CODEVIEW, "CODEVIEW" }, @@ -396,6 +396,7 @@ const char* to_string(DEBUG_TYPES e) { { DEBUG_TYPES::IMAGE_DEBUG_TYPE_OMAP_TO_SRC, "SRC" }, { DEBUG_TYPES::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC, "SRC" }, { DEBUG_TYPES::IMAGE_DEBUG_TYPE_BORLAND, "BORLAND" }, + { DEBUG_TYPES::IMAGE_DEBUG_TYPE_RESERVED10, "RESERVED" }, { DEBUG_TYPES::IMAGE_DEBUG_TYPE_CLSID, "CLSID" }, { DEBUG_TYPES::IMAGE_DEBUG_TYPE_VC_FEATURE, "VC_FEATURE" }, { DEBUG_TYPES::IMAGE_DEBUG_TYPE_POGO, "POGO" }, diff --git a/src/PE/Parser.cpp b/src/PE/Parser.cpp index 02ae574..9b88d55 100644 --- a/src/PE/Parser.cpp +++ b/src/PE/Parser.cpp @@ -565,28 +565,37 @@ void Parser::parse_debug(void) { uint32_t debugRVA = this->binary_->data_directory(DATA_DIRECTORY::DEBUG).RVA(); uint32_t debugoffset = this->binary_->rva_to_offset(debugRVA); - //uint32_t debugsize = this->binary_->dataDirectories_[DATA_DIRECTORY::DEBUG]->size(); + uint32_t debugsize = this->binary_->data_directory(DATA_DIRECTORY::DEBUG).size(); - const pe_debug& debug_struct = this->stream_->peek(debugoffset); + for (size_t i = 0; (i + 1) * sizeof(pe_debug) <= debugsize; i++) { - this->binary_->debug_ = &debug_struct; + const pe_debug& debug_struct = this->stream_->peek(debugoffset + i * sizeof(pe_debug)); + this->binary_->debug_.push_back(&debug_struct); - DEBUG_TYPES type = this->binary_->debug().type(); + DEBUG_TYPES type = this->binary_->debug().back().type(); - switch (type) { - case DEBUG_TYPES::IMAGE_DEBUG_TYPE_CODEVIEW: - { - this->parse_debug_code_view(); - } - default: - { - } + switch (type) { + case DEBUG_TYPES::IMAGE_DEBUG_TYPE_CODEVIEW: + { + this->parse_debug_code_view(this->binary_->debug().back()); + break; + } + + case DEBUG_TYPES::IMAGE_DEBUG_TYPE_REPRO: + { + this->binary_->is_reproducible_build_ = true; + break; + } + + default: + {} + } } } -void Parser::parse_debug_code_view() { +void Parser::parse_debug_code_view(Debug& debug_info) { VLOG(VDEBUG) << "Parsing Debug Code View"; - Debug& debug_info = this->binary_->debug(); + //Debug& debug_info = this->binary_->debug(); const uint32_t debug_off = debug_info.pointerto_rawdata(); if (not this->stream_->can_read(debug_off)) { diff --git a/src/PE/hash.cpp b/src/PE/hash.cpp index 7145d9c..38f0efc 100644 --- a/src/PE/hash.cpp +++ b/src/PE/hash.cpp @@ -39,7 +39,7 @@ void Hash::visit(const Binary& binary) { process(std::begin(binary.symbols()), std::end(binary.symbols())); if (binary.has_debug()) { - process(binary.debug()); + process(std::begin(binary.debug()), std::end(binary.debug())); } if (binary.has_exports()) { diff --git a/src/PE/json.cpp b/src/PE/json.cpp index 355e370..a02c716 100644 --- a/src/PE/json.cpp +++ b/src/PE/json.cpp @@ -108,9 +108,13 @@ void JsonVisitor::visit(const Binary& binary) { // Debug if (binary.has_debug()) { - JsonVisitor visitor; - visitor(binary.debug()); - this->node_["debug"] = visitor.get(); + std::vector debug_entries; + for (const Debug& debug : binary.debug()) { + JsonVisitor visitor; + visitor(debug); + debug_entries.emplace_back(visitor.get()); + } + this->node_["debug"] = debug_entries; } // Imports diff --git a/tests/pe/test_pe.py b/tests/pe/test_pe.py index d530831..f83003d 100644 --- a/tests/pe/test_pe.py +++ b/tests/pe/test_pe.py @@ -41,10 +41,10 @@ class TestPe(TestCase): self.assertTrue(sample.has_debug) - debug = sample.debug - - self.assertTrue(debug.has_code_view) + debug_code_view = list(filter(lambda deb: deb.has_code_view, sample.debug)) + self.assertTrue(len(debug_code_view) == 1) + debug = debug_code_view[0] code_view = debug.code_view self.assertEqual(code_view.cv_signature, lief.PE.CODE_VIEW_SIGNATURES.PDB_70)