From 3602643f5d02a1c78c4de609cc47f193f3a8840f Mon Sep 17 00:00:00 2001 From: Romain Thomas Date: Fri, 29 Sep 2017 09:57:00 +0200 Subject: [PATCH] Fix memory leaks in the MachO Python API and create FatBinary API Changes: LIEF::MachO::Parser won't return a 'std::vector' of MachO::Binary* but a pointer to MachO::FatBinary object It's a kind of wrapper on std::vector --- CMakeLists.txt | 3 +- api/c/MachO/Parser.cpp | 12 +-- api/python/MachO/CMakeLists.txt | 1 + api/python/MachO/objects/pyFatBinary.cpp | 60 ++++++++++++++ api/python/MachO/objects/pyParser.cpp | 4 +- api/python/MachO/pyMachO.cpp | 3 +- api/python/MachO/pyMachO.hpp | 1 + api/python/pyIterators.cpp | 1 + doc/sphinx/api/cpp/macho.rst | 8 ++ doc/sphinx/api/python/macho.rst | 11 +++ examples/cpp/macho_builder.cpp | 10 +-- examples/cpp/macho_instrumentation.cpp | 15 ++-- examples/cpp/macho_reader.cpp | 30 +++---- fuzzing/CMakeLists.txt | 16 ++-- fuzzing/macho_fuzzer.cpp | 7 +- include/LIEF/MachO/FatBinary.hpp | 73 ++++++++++++++++ include/LIEF/MachO/Parser.hpp | 5 +- include/LIEF/MachO/type_traits.hpp | 5 ++ include/LIEF/PE/Parser.hpp | 9 +- src/Abstract/Parser.cpp | 22 +++-- src/BinaryStream/VectorStream.cpp | 8 +- src/ELF/Parser.cpp | 2 +- src/ELF/Parser.tcc | 32 ++++--- src/MachO/BinaryParser.cpp | 2 +- src/MachO/BinaryParser.tcc | 66 ++++++--------- src/MachO/CMakeLists.txt | 2 + src/MachO/FatBinary.cpp | 101 +++++++++++++++++++++++ src/MachO/Parser.cpp | 8 +- src/PE/Parser.cpp | 24 +++--- src/PE/Parser.tcc | 49 ++++++----- tests/CMakeLists.txt | 8 +- tests/run_python_test.bat.in | 2 +- 32 files changed, 430 insertions(+), 170 deletions(-) create mode 100644 api/python/MachO/objects/pyFatBinary.cpp create mode 100644 include/LIEF/MachO/FatBinary.hpp create mode 100644 src/MachO/FatBinary.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c3d0e0..2a44f85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,7 +242,8 @@ set(LIBFUZZER_SRC_FILES) if (LIEF_FUZZING) message(STATUS "Fuzzing Enabled") - set(LIBFUZZER_URL "http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer") + set(LIBFUZZER_VERSION 314494) + set(LIBFUZZER_URL "http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer/") #\?p=${LIBFUZZER_VERSION}") ExternalProject_Add(lief_libfuzzer SVN_REPOSITORY ${LIBFUZZER_URL} CONFIGURE_COMMAND "" diff --git a/api/c/MachO/Parser.cpp b/api/c/MachO/Parser.cpp index 6907820..f7afa67 100644 --- a/api/c/MachO/Parser.cpp +++ b/api/c/MachO/Parser.cpp @@ -23,18 +23,18 @@ using namespace LIEF::MachO; Macho_Binary_t** macho_parse(const char *file) { - std::vector macho_binaries{Parser::parse(file)}; + FatBinary* macho_binaries = Parser::parse(file); Macho_Binary_t** c_macho_binaries = static_cast( - malloc((macho_binaries.size() + 1) * sizeof(Macho_Binary_t**))); + malloc((macho_binaries->size() + 1) * sizeof(Macho_Binary_t**))); - for (size_t i = 0; i < macho_binaries.size(); ++i) { - Binary* binary = macho_binaries [i]; + for (size_t i = 0; i < macho_binaries->size(); ++i) { + Binary& binary = (*macho_binaries)[i]; c_macho_binaries[i] = static_cast(malloc(sizeof(Macho_Binary_t))); - init_c_binary(c_macho_binaries[i], binary); + init_c_binary(c_macho_binaries[i], &binary); } - c_macho_binaries[macho_binaries.size()] = nullptr; + c_macho_binaries[macho_binaries->size()] = nullptr; return c_macho_binaries; } diff --git a/api/python/MachO/CMakeLists.txt b/api/python/MachO/CMakeLists.txt index aab059d..3591b38 100644 --- a/api/python/MachO/CMakeLists.txt +++ b/api/python/MachO/CMakeLists.txt @@ -2,6 +2,7 @@ set(LIEF_PYTHON_MACHO_SRC "${CMAKE_CURRENT_LIST_DIR}/pyMachO.cpp" "${CMAKE_CURRENT_LIST_DIR}/objects/pyDylibCommand.cpp" "${CMAKE_CURRENT_LIST_DIR}/objects/pyBinary.cpp" + "${CMAKE_CURRENT_LIST_DIR}/objects/pyFatBinary.cpp" "${CMAKE_CURRENT_LIST_DIR}/objects/pyLoadCommand.cpp" "${CMAKE_CURRENT_LIST_DIR}/objects/pySegmentCommand.cpp" "${CMAKE_CURRENT_LIST_DIR}/objects/pyHeader.cpp" diff --git a/api/python/MachO/objects/pyFatBinary.cpp b/api/python/MachO/objects/pyFatBinary.cpp new file mode 100644 index 0000000..538a1ba --- /dev/null +++ b/api/python/MachO/objects/pyFatBinary.cpp @@ -0,0 +1,60 @@ +/* Copyright 2017 R. Thomas + * Copyright 2017 Quarkslab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include "LIEF/MachO/FatBinary.hpp" + +#include "pyMachO.hpp" + + +void init_MachO_FatBinary_class(py::module& m) { + + + py::class_(m, "FatBinary") + + .def_property_readonly("size", + &FatBinary::size, + "Number of " RST_CLASS_REF(lief.MachO.Binary) " registred") + + .def("at", + static_cast(&FatBinary::at), + "Return the " RST_CLASS_REF(lief.MachO.Binary) " at the given index", + "index"_a) + + .def("__len__", + &FatBinary::size) + + + .def("__getitem__", + static_cast(&FatBinary::operator[]), + "", + py::return_value_policy::reference) + + .def("__iter__", + static_cast(&FatBinary::begin), + py::return_value_policy::reference_internal) + + .def("__str__", + [] (const FatBinary& fat_binary) + { + std::ostringstream stream; + stream << fat_binary; + std::string str = stream.str(); + return str; + }); + +} + diff --git a/api/python/MachO/objects/pyParser.cpp b/api/python/MachO/objects/pyParser.cpp index 2dbb4c7..b79cf43 100644 --- a/api/python/MachO/objects/pyParser.cpp +++ b/api/python/MachO/objects/pyParser.cpp @@ -24,14 +24,14 @@ void init_MachO_Parser_class(py::module& m) { // Parser (Parser) m.def("parse", - static_cast (*) (const std::string&)>(&LIEF::MachO::Parser::parse), + static_cast(&LIEF::MachO::Parser::parse), "Parse the given binary and return a **list** of " RST_CLASS_REF(lief.MachO.Binary) " objects", "filename"_a, py::return_value_policy::take_ownership); m.def("parse", - static_cast (*) (const std::vector&, const std::string&)>(&LIEF::MachO::Parser::parse), + static_cast&, const std::string&)>(&LIEF::MachO::Parser::parse), "Parse the given binary (from raw) and return a **list** of " RST_CLASS_REF(lief.MachO.Binary) " objects", py::arg("raw"), py::arg("name") = "", py::return_value_policy::take_ownership); diff --git a/api/python/MachO/pyMachO.cpp b/api/python/MachO/pyMachO.cpp index 006770b..50be72c 100644 --- a/api/python/MachO/pyMachO.cpp +++ b/api/python/MachO/pyMachO.cpp @@ -23,10 +23,9 @@ void init_MachO_module(py::module& m) { py::module LIEF_MachO_module = m.def_submodule("MachO", "Python API for MachO"); - py::bind_vector>(m, "macho_list"); - // Objects init_MachO_Parser_class(LIEF_MachO_module); + init_MachO_FatBinary_class(LIEF_MachO_module); init_MachO_Binary_class(LIEF_MachO_module); init_MachO_Header_class(LIEF_MachO_module); init_MachO_LoadCommand_class(LIEF_MachO_module); diff --git a/api/python/MachO/pyMachO.hpp b/api/python/MachO/pyMachO.hpp index e5aed2e..7a36faf 100644 --- a/api/python/MachO/pyMachO.hpp +++ b/api/python/MachO/pyMachO.hpp @@ -27,6 +27,7 @@ using namespace LIEF::MachO; PYBIND11_MAKE_OPAQUE(std::vector) void init_MachO_Parser_class(py::module&); +void init_MachO_FatBinary_class(py::module&); void init_MachO_Binary_class(py::module&); void init_MachO_Header_class(py::module&); void init_MachO_LoadCommand_class(py::module&); diff --git a/api/python/pyIterators.cpp b/api/python/pyIterators.cpp index 9fe7c73..2ea36ea 100644 --- a/api/python/pyIterators.cpp +++ b/api/python/pyIterators.cpp @@ -63,6 +63,7 @@ void init_LIEF_iterators(py::module& m) { // MachO // ===== #if defined(LIEF_MACHO_MODULE) + init_ref_iterator(m); init_ref_iterator(m); init_ref_iterator(m); init_ref_iterator(m); diff --git a/doc/sphinx/api/cpp/macho.rst b/doc/sphinx/api/cpp/macho.rst index 1e110a7..3674780 100644 --- a/doc/sphinx/api/cpp/macho.rst +++ b/doc/sphinx/api/cpp/macho.rst @@ -13,6 +13,14 @@ Parsers ---------- +FatBinary +********* + +.. doxygenclass:: LIEF::MachO::FatBinary + :project: lief + +---------- + Binary ****** diff --git a/doc/sphinx/api/python/macho.rst b/doc/sphinx/api/python/macho.rst index fa49299..1a4eb96 100644 --- a/doc/sphinx/api/python/macho.rst +++ b/doc/sphinx/api/python/macho.rst @@ -10,6 +10,17 @@ Parser ---------- +FatBinary +********* + +.. autoclass:: lief.MachO.FatBinary + :members: + :inherited-members: + :undoc-members: + +---------- + + .. _python-macho-binary-api-ref: Binary diff --git a/examples/cpp/macho_builder.cpp b/examples/cpp/macho_builder.cpp index 33a27c0..1c56d36 100644 --- a/examples/cpp/macho_builder.cpp +++ b/examples/cpp/macho_builder.cpp @@ -38,13 +38,9 @@ int main(int argc, char **argv) { return -1; } - std::vector binaries = MachO::Parser::parse(argv[1]); - MachO::Binary* binary = binaries.back(); - binary->write(argv[2]); - - for (MachO::Binary *b : binaries) { - delete b; - } + std::unique_ptr binaries{MachO::Parser::parse(argv[1])}; + MachO::Binary& binary = binaries->back(); + binary.write(argv[2]); return 0; } diff --git a/examples/cpp/macho_instrumentation.cpp b/examples/cpp/macho_instrumentation.cpp index a962e4d..64f6a0a 100644 --- a/examples/cpp/macho_instrumentation.cpp +++ b/examples/cpp/macho_instrumentation.cpp @@ -30,10 +30,10 @@ int main(int argc, char **argv) { return -1; } - std::vector binaries = MachO::Parser::parse(argv[1]); - MachO::Binary* binary = binaries.back(); - auto segments = binary->segments(); - auto itSegment = std::find_if( + std::unique_ptr binaries{MachO::Parser::parse(argv[1])}; + MachO::Binary& binary = binaries->back(); + auto&& segments = binary.segments(); + auto&& itSegment = std::find_if( std::begin(segments), std::end(segments), [] (const MachO::SegmentCommand& segment) { @@ -64,7 +64,7 @@ int main(int argc, char **argv) { segment_header.segname[segment_name.size()] = 0; segment_header.vmaddr = 0x200050000; segment_header.vmsize = 0x2000; - segment_header.fileoff = binary->original_size(); + segment_header.fileoff = binary.original_size(); segment_header.filesize = payload.size(); segment_header.maxprot = 7; segment_header.initprot = 3; @@ -82,11 +82,8 @@ int main(int argc, char **argv) { reinterpret_cast(&segment_header) + sizeof(segment_header) }); //binary->insert_command(std::move(segment)); - binary->write(argv[2]); + binary.write(argv[2]); - for (MachO::Binary *b : binaries) { - delete b; - } return 0; } diff --git a/examples/cpp/macho_reader.cpp b/examples/cpp/macho_reader.cpp index d16729a..d062ead 100644 --- a/examples/cpp/macho_reader.cpp +++ b/examples/cpp/macho_reader.cpp @@ -20,23 +20,23 @@ using namespace LIEF::MachO; -void print_binary(const Binary* binary) { - std::cout << binary->header() << std::endl; +void print_binary(const Binary& binary) { + std::cout << binary.header() << std::endl; std::cout << "== Library ==" << std::endl; - for (const DylibCommand& library : binary->libraries()) { + for (const DylibCommand& library : binary.libraries()) { std::cout << library << std::endl; } std::cout << std::endl; std::cout << "== Sections ==" << std::endl; - for (const Section& section : binary->sections()) { + for (const Section& section : binary.sections()) { std::cout << section << std::endl; } //std::cout << "== Segments ==" << std::endl; - //for (SegmentCommand& segment : binary->segments()) { + //for (SegmentCommand& segment : binary.segments()) { // std::cout << segment << std::endl; // if (segment.sections().size() > 0) { // //std::cout << std::hex; @@ -61,31 +61,31 @@ void print_binary(const Binary* binary) { //} //std::cout << std::endl; - //auto commands = binary->commands(); - for (const LoadCommand& cmd : binary->commands()) { + //auto commands = binary.commands(); + for (const LoadCommand& cmd : binary.commands()) { std::cout << cmd << std::endl; std::cout << "======================" << std::endl; } std::cout << "== Symbols ==" << std::endl; - for (const Symbol& symbol : binary->symbols()) { + for (const Symbol& symbol : binary.symbols()) { std::cout << symbol << std::endl; } std::cout << "== Exported symbols ==" << std::endl; - for (const Symbol& symbol : binary->exported_symbols()) { + for (const Symbol& symbol : binary.exported_symbols()) { std::cout << symbol << std::endl; } std::cout << "== Imported symbols ==" << std::endl; - for (const Symbol& symbol : binary->imported_symbols()) { + for (const Symbol& symbol : binary.imported_symbols()) { std::cout << symbol << std::endl; } std::cout << "== Relocations ==" << std::endl; - for (const Relocation& relocation : binary->relocations()) { + for (const Relocation& relocation : binary.relocations()) { std::cout << relocation << std::endl; } @@ -99,16 +99,12 @@ int main(int argc, char **argv) { std::cerr << "Usage: " << argv[0] << " " << std::endl; return -1; } - std::vector binaries = Parser::parse(argv[1]); - for (const Binary* binary : binaries) { + std::unique_ptr binaries{Parser::parse(argv[1])}; + for (const Binary& binary : *binaries) { print_binary(binary); std::cout << std::endl; } - for (Binary* binary : binaries) { - delete binary; - } - return 0; } diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 5c0db65..5a487e8 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -1,3 +1,4 @@ +include(ProcessorCount) set(LIEF_FUZZER_SRC elf_fuzzer.cpp pe_fuzzer.cpp @@ -33,7 +34,8 @@ ExternalProject_Add(lief_fuzzer_corpus INSTALL_COMMAND "" GIT_REPOSITORY ${SAMPLES_GIT_URL} GIT_TAG ${SAMPLES_TAG} - UPDATE_COMMAND ${GIT_EXECUTABLE} pull + #UPDATE_COMMAND ${GIT_EXECUTABLE} pull + UPDATE_COMMAND "" ) ExternalProject_Get_Property(lief_fuzzer_corpus source_dir) @@ -41,7 +43,9 @@ set(LIEF_CORUPUS_DIRECTORY "${source_dir}" CACHE INTERNAL "Path to LIEF samples" message(STATUS "Samples directory: ${LIEF_CORUPUS_DIRECTORY}") - +ProcessorCount(N) +set(LIB_FUZZER_ARGS -detect_leaks=1 -rss_limit_mb=0 -print_final_stats=1 -jobs=${N}) +set(ASAN_OPTIONS allocator_may_return_null=1) # ELF # === set(ELF_WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR}/elf-output) @@ -50,7 +54,7 @@ add_custom_target(build-elf-fuzz-output COMMAND ${CMAKE_COMMAND} -E make_directory ${ELF_WORKING_DIR}) add_custom_target("fuzz-elf" - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/elf_fuzzer ${LIEF_CORUPUS_DIRECTORY}/ELF -detect_leaks=1 -print_final_stats=1 + COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS=${ASAN_OPTIONS} ${CMAKE_CURRENT_BINARY_DIR}/elf_fuzzer ${LIEF_CORUPUS_DIRECTORY}/ELF ${LIB_FUZZER_ARGS} DEPENDS elf_fuzzer LIB_LIEF_STATIC build-elf-fuzz-output lief_fuzzer_corpus WORKING_DIRECTORY ${ELF_WORKING_DIR} COMMENT "Run ELF fuzzer") @@ -64,7 +68,7 @@ add_custom_target(build-pe-fuzz-output COMMAND ${CMAKE_COMMAND} -E make_directory ${PE_WORKING_DIR}) add_custom_target("fuzz-pe" - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pe_fuzzer ${LIEF_CORUPUS_DIRECTORY}/PE -detect_leaks=1 -print_final_stats=1 + COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS="${ASAN_OPTIONS}" ${CMAKE_CURRENT_BINARY_DIR}/pe_fuzzer ${LIEF_CORUPUS_DIRECTORY}/PE ${LIB_FUZZER_ARGS} DEPENDS pe_fuzzer LIB_LIEF_STATIC build-pe-fuzz-output lief_fuzzer_corpus WORKING_DIRECTORY ${PE_WORKING_DIR} COMMENT "Run PE fuzzer") @@ -74,10 +78,10 @@ add_custom_target("fuzz-pe" set(MACHO_WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR}/macho-output) add_custom_target(build-macho-fuzz-output - COMMAND ${CMAKE_COMMAND} -E make_directory ${MACHO_WORKING_DIR}) + COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS=${ASAN_OPTIONS} ${CMAKE_COMMAND} -E make_directory ${MACHO_WORKING_DIR}) add_custom_target("fuzz-macho" - COMMAND ${CMAKE_CURRENT_BINARY_DIR}/macho_fuzzer ${LIEF_CORUPUS_DIRECTORY}/MachO -detect_leaks=1 -print_final_stats=1 + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/macho_fuzzer ${LIEF_CORUPUS_DIRECTORY}/MachO ${LIB_FUZZER_ARGS} DEPENDS macho_fuzzer LIB_LIEF_STATIC build-macho-fuzz-output lief_fuzzer_corpus WORKING_DIRECTORY ${MACHO_WORKING_DIR} COMMENT "Run MachO fuzzer") diff --git a/fuzzing/macho_fuzzer.cpp b/fuzzing/macho_fuzzer.cpp index 4c1e2af..7f85927 100644 --- a/fuzzing/macho_fuzzer.cpp +++ b/fuzzing/macho_fuzzer.cpp @@ -4,14 +4,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { std::vector raw = {data, data + size}; - std::vector binaries; + std::unique_ptr binaries; try { - binaries = LIEF::MachO::Parser::parse(raw); + binaries = std::unique_ptr(LIEF::MachO::Parser::parse(raw)); } catch (const LIEF::exception& e) { std::cout << e.what() << std::endl; } - for (LIEF::MachO::Binary* b: binaries) { - delete b; - } return 0; } diff --git a/include/LIEF/MachO/FatBinary.hpp b/include/LIEF/MachO/FatBinary.hpp new file mode 100644 index 0000000..74dc339 --- /dev/null +++ b/include/LIEF/MachO/FatBinary.hpp @@ -0,0 +1,73 @@ +/* Copyright 2017 R. Thomas + * Copyright 2017 Quarkslab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LIEF_MACHO_FAT_BINARY_H_ +#define LIEF_MACHO_FAT_BINARY_H_ + +#include + +#include "LIEF/types.hpp" +#include "LIEF/visibility.h" + +#include "LIEF/MachO/Binary.hpp" + + +namespace LIEF { +class Parser; +namespace MachO { + +class Parser; +class Builder; + +class DLL_PUBLIC FatBinary { + + friend class LIEF::Parser; + friend class Parser; + friend class Builder; + + public: + FatBinary(const FatBinary&) = delete; + + virtual ~FatBinary(void); + + //! @brief Number of @link MachO::Binary binary @endlink registred + size_t size(void) const; + + it_binaries begin(void); + it_const_binaries begin(void) const; + + it_binaries end(void); + it_const_binaries end(void) const; + + Binary& at(size_t index); + const Binary& at(size_t index) const; + + Binary& back(void); + const Binary& back(void) const; + + Binary& operator[](size_t index); + const Binary& operator[](size_t index) const; + + DLL_PUBLIC friend std::ostream& operator<<(std::ostream& os, const FatBinary& fatbinary); + + private: + FatBinary(void); + FatBinary(const std::vector& binaries); + binaries_t binaries_; +}; + +} // namespace MachO +} // namespace LIEF +#endif diff --git a/include/LIEF/MachO/Parser.hpp b/include/LIEF/MachO/Parser.hpp index 4cdea61..99b2cd2 100644 --- a/include/LIEF/MachO/Parser.hpp +++ b/include/LIEF/MachO/Parser.hpp @@ -26,6 +26,7 @@ #include "LIEF/MachO/Structures.hpp" #include "LIEF/MachO/Binary.hpp" +#include "LIEF/MachO/FatBinary.hpp" namespace LIEF { @@ -37,8 +38,8 @@ class DLL_PUBLIC Parser : public LIEF::Parser { ~Parser(void); - static std::vector parse(const std::string& filename); - static std::vector parse(const std::vector& data, const std::string& name = ""); + static FatBinary* parse(const std::string& filename); + static FatBinary* parse(const std::vector& data, const std::string& name = ""); private: Parser(const std::string& file); diff --git a/include/LIEF/MachO/type_traits.hpp b/include/LIEF/MachO/type_traits.hpp index eafc326..b03c796 100644 --- a/include/LIEF/MachO/type_traits.hpp +++ b/include/LIEF/MachO/type_traits.hpp @@ -38,6 +38,11 @@ struct KeyCmp { }; +using binaries_t = std::vector; +using it_binaries = ref_iterator; +using it_const_binaries = const_ref_iterator; + + using buffer_t = std::vector; ///< Container used to store raw data using commands_t = std::vector; diff --git a/include/LIEF/PE/Parser.hpp b/include/LIEF/PE/Parser.hpp index 9c45411..367c7fa 100644 --- a/include/LIEF/PE/Parser.hpp +++ b/include/LIEF/PE/Parser.hpp @@ -21,6 +21,7 @@ #include "LIEF/exception.hpp" #include "LIEF/visibility.h" +#include "LIEF/utils.hpp" #include "LIEF/Abstract/Parser.hpp" @@ -41,7 +42,13 @@ namespace PE { class DLL_PUBLIC Parser : public LIEF::Parser { //! @brief Minimum size for a DLL's name - constexpr static unsigned MIN_DLL_NAME_SIZE = 4; + static constexpr unsigned MIN_DLL_NAME_SIZE = 4; + + //! @brief Maximum size of the data read + static constexpr size_t MAX_DATA_SIZE = 3_GB; + + static constexpr size_t MAX_TLS_CALLBACKS = 3000; + public: static Binary* parse(const std::string& filename); diff --git a/src/Abstract/Parser.cpp b/src/Abstract/Parser.cpp index 4f297b9..120c385 100644 --- a/src/Abstract/Parser.cpp +++ b/src/Abstract/Parser.cpp @@ -51,14 +51,13 @@ Binary* Parser::parse(const std::string& filename) { #if defined(LIEF_MACHO_MODULE) if (MachO::is_macho(filename)) { // For fat binary we take the last one... - std::vector binaries = MachO::Parser::parse(filename); - MachO::Binary* binary_return = binaries.back(); - binaries.pop_back(); + MachO::FatBinary* binaries = MachO::Parser::parse(filename); + MachO::Binary& binary_return = (*binaries)[0]; // delete others - for (MachO::Binary* binary : binaries) { - delete binary; + for (size_t i = 1; i < binaries->size(); ++i) { + delete binaries->binaries_[i]; } - return binary_return; + return &binary_return; } #endif @@ -84,14 +83,13 @@ Binary* Parser::parse(const std::vector& raw, const std::string& name) #if defined(LIEF_MACHO_MODULE) if (MachO::is_macho(raw)) { // For fat binary we take the last one... - std::vector binaries = MachO::Parser::parse(raw, name); - MachO::Binary* binary_return = binaries.back(); - binaries.pop_back(); + MachO::FatBinary* binaries = MachO::Parser::parse(raw, name); + MachO::Binary& binary_return = (*binaries)[0]; // delete others - for (MachO::Binary* binary : binaries) { - delete binary; + for (size_t i = 1; i < binaries->size(); ++i) { + delete binaries->binaries_[i]; } - return binary_return; + return &binary_return; } #endif diff --git a/src/BinaryStream/VectorStream.cpp b/src/BinaryStream/VectorStream.cpp index d53a9cd..ab5e708 100644 --- a/src/BinaryStream/VectorStream.cpp +++ b/src/BinaryStream/VectorStream.cpp @@ -101,11 +101,13 @@ std::string VectorStream::get_string(uint64_t offset, uint64_t size) const { throw LIEF::read_out_of_bound(offset); } - uint64_t max_size = this->size() - (offset + size); + size_t max_size = static_cast(this->size() - (offset + size)); if (size > 0) { - max_size = std::min(max_size, size); + max_size = std::min(max_size, size); } - std::string tmp{this->read_string(offset, max_size), max_size}; + const char* str = this->read_string(offset); + const char* it_null = std::find(str, str + max_size, '\0'); + std::string tmp{str, it_null}; return tmp.c_str(); } diff --git a/src/ELF/Parser.cpp b/src/ELF/Parser.cpp index 9132ff8..0a1bb24 100644 --- a/src/ELF/Parser.cpp +++ b/src/ELF/Parser.cpp @@ -299,7 +299,7 @@ void Parser::parse_notes(uint64_t offset, uint64_t size) { break; } - std::string name = {this->stream_->read_string(current_offset, namesz), namesz - 1}; + std::string name = this->stream_->get_string(current_offset, namesz); VLOG(VDEBUG) << "Name: " << name << std::endl; current_offset += namesz; current_offset = align(current_offset, sizeof(uint32_t)); diff --git a/src/ELF/Parser.tcc b/src/ELF/Parser.tcc index 151feca..26b909a 100644 --- a/src/ELF/Parser.tcc +++ b/src/ELF/Parser.tcc @@ -837,8 +837,8 @@ void Parser::parse_sections(void) { const Section* string_section = this->binary_->sections_[section_string_index]; for (Section* section : this->binary_->sections_) { try { - section->name({this->stream_->read_string( - string_section->file_offset() + section->name_idx())}); + section->name(this->stream_->get_string( + string_section->file_offset() + section->name_idx())); } catch (const LIEF::read_out_of_bound&) { LOG(WARNING) << "Section's name is corrupted"; } @@ -884,7 +884,7 @@ void Parser::parse_segments(void) { this->stream_->read(offset_to_content, size)); segment->content({content, content + size}); if (segment->type() == SEGMENT_TYPES::PT_INTERP) { - this->binary_->interpreter_ = this->stream_->read_string(offset_to_content, segment->physical_size()); + this->binary_->interpreter_ = this->stream_->get_string(offset_to_content, segment->physical_size()); } } catch (const LIEF::read_out_of_bound&) { @@ -957,8 +957,8 @@ void Parser::parse_static_symbols(uint64_t offset, uint32_t nbSymbols, const Sec for (uint32_t i = 0; i < nbSymbols; ++i) { std::unique_ptr symbol{new Symbol{&symbol_headers[i]}}; try { - std::string symbol_name = {this->stream_->read_string( - string_section->file_offset() + symbol_headers[i].st_name)}; + std::string symbol_name = this->stream_->get_string( + string_section->file_offset() + symbol_headers[i].st_name); symbol->name(symbol_name); } catch (const LIEF::read_out_of_bound& e) { LOG(WARNING) << e.what(); @@ -994,7 +994,7 @@ void Parser::parse_dynamic_symbols(uint64_t offset) { if (symbol_headers->st_name > 0) { try { std::string name{ - this->stream_->read_string(string_offset + symbol_headers->st_name)}; + this->stream_->get_string(string_offset + symbol_headers->st_name)}; symbol->name(name); } catch (const exception& e) { VLOG(VDEBUG) << e.what(); @@ -1046,8 +1046,7 @@ void Parser::parse_dynamic_entries(uint64_t offset, uint64_t size) { if (dynamic_string_offset == 0) { LOG(WARNING) << "Unable to find the .dynstr section"; } else { - std::string library_name = { - this->stream_->read_string(dynamic_string_offset + dynamic_entry->value())}; + std::string library_name = this->stream_->get_string(dynamic_string_offset + dynamic_entry->value()); dynamic_entry->name(library_name); } break; @@ -1061,8 +1060,7 @@ void Parser::parse_dynamic_entries(uint64_t offset, uint64_t size) { if (dynamic_string_offset == 0) { LOG(WARNING) << "Unable to find the .dynstr section"; } else { - std::string sharename = { - this->stream_->read_string(dynamic_string_offset + dynamic_entry->value())}; + std::string sharename = this->stream_->get_string(dynamic_string_offset + dynamic_entry->value()); dynamic_entry->name(sharename); } break; @@ -1075,8 +1073,7 @@ void Parser::parse_dynamic_entries(uint64_t offset, uint64_t size) { if (dynamic_string_offset == 0) { LOG(WARNING) << "Unable to find the .dynstr section"; } else { - std::string name = { - this->stream_->read_string(dynamic_string_offset + dynamic_entry->value())}; + std::string name = this->stream_->get_string(dynamic_string_offset + dynamic_entry->value()); dynamic_entry->name(name); } break; @@ -1090,8 +1087,7 @@ void Parser::parse_dynamic_entries(uint64_t offset, uint64_t size) { if (dynamic_string_offset == 0) { LOG(WARNING) << "Unable to find the .dynstr section"; } else { - std::string name = { - this->stream_->read_string(dynamic_string_offset + dynamic_entry->value())}; + std::string name = this->stream_->get_string(dynamic_string_offset + dynamic_entry->value()); dynamic_entry->name(name); } break; @@ -1378,8 +1374,8 @@ void Parser::parse_symbol_version_requirement(uint64_t offset, uint32_t nb_entri std::unique_ptr symbol_version_requirement{new SymbolVersionRequirement{header}}; if (string_offset != 0) { - symbol_version_requirement->name({ - this->stream_->read_string(string_offset + header->vn_file)}); + symbol_version_requirement->name( + this->stream_->get_string(string_offset + header->vn_file)); } const uint32_t nb_symbol_aux = header->vn_cnt; @@ -1401,7 +1397,7 @@ void Parser::parse_symbol_version_requirement(uint64_t offset, uint32_t nb_entri std::unique_ptr svar{new SymbolVersionAuxRequirement{aux_header}}; if (string_offset != 0) { - svar->name({this->stream_->read_string(string_offset + aux_header->vna_name)}); + svar->name(this->stream_->get_string(string_offset + aux_header->vna_name)); } symbol_version_requirement->symbol_version_aux_requirement_.push_back(svar.release()); @@ -1463,7 +1459,7 @@ void Parser::parse_symbol_version_definition(uint64_t offset, uint32_t nb_entrie offset + next_symbol_offset + svd_header->vd_aux + next_aux_offset, sizeof(Elf_Verdaux))); if (string_offset != 0) { - std::string name = {this->stream_->read_string(string_offset + svda_header->vda_name)}; + std::string name = this->stream_->get_string(string_offset + svda_header->vda_name); symbol_version_definition->symbol_version_aux_.push_back(new SymbolVersionAux{name}); } diff --git a/src/MachO/BinaryParser.cpp b/src/MachO/BinaryParser.cpp index 7531c41..d96ae07 100644 --- a/src/MachO/BinaryParser.cpp +++ b/src/MachO/BinaryParser.cpp @@ -161,7 +161,7 @@ void BinaryParser::parse_export_trie(uint64_t start, uint64_t current_offset, ui const uint8_t nb_children = this->stream_->read_integer(children_offset); children_offset += sizeof(uint8_t); for (size_t i = 0; i < nb_children; ++i) { - std::string suffix = this->stream_->read_string(children_offset); + std::string suffix = this->stream_->get_string(children_offset); std::string name = prefix + suffix; children_offset += suffix.size() + 1; diff --git a/src/MachO/BinaryParser.tcc b/src/MachO/BinaryParser.tcc index 6b69abf..ec44c8d 100644 --- a/src/MachO/BinaryParser.tcc +++ b/src/MachO/BinaryParser.tcc @@ -152,7 +152,7 @@ void BinaryParser::parse_load_commands(void) { load_command = std::unique_ptr{new DylibCommand{cmd}}; const uint32_t str_name_offset = cmd->dylib.name; - std::string name = {this->stream_->read_string(loadcommands_offset + str_name_offset)}; + std::string name = this->stream_->get_string(loadcommands_offset + str_name_offset); dynamic_cast(load_command.get())->name(name); break; @@ -182,9 +182,9 @@ void BinaryParser::parse_load_commands(void) { this->stream_->read(loadcommands_offset, sizeof(dylinker_command))); const uint32_t linker_name_offset = cmd->name; - std::string name = {this->stream_->read_string( + std::string name = this->stream_->get_string( loadcommands_offset + - linker_name_offset)}; + linker_name_offset); load_command = std::unique_ptr{new DylinkerCommand{cmd}}; dynamic_cast(load_command.get())->name(name); @@ -204,9 +204,9 @@ void BinaryParser::parse_load_commands(void) { this->stream_->read(loadcommands_offset, sizeof(prebound_dylib_command))); - std::string name = {this->stream_->read_string( + std::string name = this->stream_->get_string( loadcommands_offset + - cmd->name)}; + cmd->name); //uint32_t sizeof_linked_modules = (cmd->nmodules / 8) + (cmd->nmodules % 8); @@ -308,7 +308,7 @@ void BinaryParser::parse_load_commands(void) { uint32_t idx = nlist[j].n_strx; if (idx > 0) { symbol->name( - this->stream_->read_string(cmd->stroff + idx)); + this->stream_->get_string(cmd->stroff + idx)); } this->binary_->symbols_.push_back(symbol.release()); } @@ -879,7 +879,7 @@ void BinaryParser::parse_dyldinfo_generic_bind() { case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: { - symbol_name = this->stream_->read_string(current_offset); + symbol_name = this->stream_->get_string(current_offset); current_offset += symbol_name.size() + 1; if ((imm & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0) { @@ -1069,7 +1069,7 @@ void BinaryParser::parse_dyldinfo_weak_bind() { case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: { - symbol_name = this->stream_->read_string(current_offset); + symbol_name = this->stream_->get_string(current_offset); current_offset += symbol_name.size() + 1; if ((imm & BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) != 0) { @@ -1289,7 +1289,7 @@ void BinaryParser::parse_dyldinfo_lazy_bind() { case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: { - symbol_name = this->stream_->read_string(current_offset); + symbol_name = this->stream_->get_string(current_offset); current_offset += symbol_name.size() + 1; if ((imm & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0) { @@ -1366,26 +1366,17 @@ void BinaryParser::do_bind(BINDING_CLASS cls, // Address to bind uint64_t address = segment.virtual_address() + segment_offset; - // Check if a relocation already exists: - Relocation* reloc = nullptr; - std::unique_ptr new_relocation{nullptr}; - bool reloc_exists = false; - - auto&& it_reloc = std::find_if( - std::begin(segment.relocations_), - std::end(segment.relocations_), - [address] (const Relocation* r) { - return r->address() == address; - }); - - if (it_reloc != std::end(segment.relocations_)) { - reloc = *it_reloc; - reloc_exists = true; + std::unique_ptr new_relocation{new RelocationDyld{address, type}}; + auto&& result = segment.relocations_.emplace(new_relocation.get()); + Relocation* reloc = *result.first; + if (result.second) { + new_relocation.release(); } else { - new_relocation = std::unique_ptr{new RelocationDyld{address, type}}; - reloc = new_relocation.get(); + delete new_relocation.release(); } + + reloc->architecture_ = this->binary_->header().cpu_type(); switch (static_cast(type)) { @@ -1445,9 +1436,7 @@ void BinaryParser::do_bind(BINDING_CLASS cls, LOG(ERROR) << "New symbol found: " << symbol_name; } - if (not reloc_exists) { - segment.relocations_.emplace(new_relocation.release()); - } + this->binary_->dyld_info().binding_info_.push_back(binding_info.release()); VLOG(VDEBUG) << to_string(cls) << segment.name() << " - " << symbol_name; } @@ -1467,15 +1456,13 @@ void BinaryParser::do_rebase(uint8_t type, uint8_t segment_idx, uint64_t segment uint64_t address = segment.virtual_address() + segment_offset; // Check if a relocation already exists: - Relocation* reloc = nullptr; - bool reloc_exists = false; - - reloc = new RelocationDyld{address, type}; - auto&& it_reloc = segment.relocations_.find(reloc); - if (it_reloc != std::end(segment.relocations_)) { - delete reloc; - reloc = *it_reloc; - reloc_exists = true; + std::unique_ptr new_relocation{new RelocationDyld{address, type}}; + auto&& result = segment.relocations_.emplace(new_relocation.get()); + Relocation* reloc = *result.first; + if (result.second) { + new_relocation.release(); + } else { + delete new_relocation.release(); } reloc->architecture_ = this->binary_->header().cpu_type(); @@ -1500,9 +1487,6 @@ void BinaryParser::do_rebase(uint8_t type, uint8_t segment_idx, uint64_t segment LOG(ERROR) << "Unsuported relocation type: 0x" << std::hex << type; } } - if (not reloc_exists) { - segment.relocations_.insert(it_reloc, reloc); - } } diff --git a/src/MachO/CMakeLists.txt b/src/MachO/CMakeLists.txt index 447f4ce..3f2a428 100644 --- a/src/MachO/CMakeLists.txt +++ b/src/MachO/CMakeLists.txt @@ -18,6 +18,7 @@ set(LIEF_MACHO_SRC "${CMAKE_CURRENT_LIST_DIR}/Binary.cpp" "${CMAKE_CURRENT_LIST_DIR}/UUIDCommand.cpp" "${CMAKE_CURRENT_LIST_DIR}/Symbol.cpp" + "${CMAKE_CURRENT_LIST_DIR}/FatBinary.cpp" "${CMAKE_CURRENT_LIST_DIR}/EnumToString.cpp" "${CMAKE_CURRENT_LIST_DIR}/Header.cpp" "${CMAKE_CURRENT_LIST_DIR}/DynamicSymbolCommand.cpp" @@ -47,6 +48,7 @@ set(LIEF_MACHO_SRC ) set(LIEF_MACHO_INCLUDE_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/FatBinary.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/Binary.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/BinaryParser.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/LIEF/MachO/Builder.hpp" diff --git a/src/MachO/FatBinary.cpp b/src/MachO/FatBinary.cpp new file mode 100644 index 0000000..24878b8 --- /dev/null +++ b/src/MachO/FatBinary.cpp @@ -0,0 +1,101 @@ +/* Copyright 2017 R. Thomas + * Copyright 2017 Quarkslab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include "LIEF/MachO/FatBinary.hpp" + +namespace LIEF { +namespace MachO { + +FatBinary::FatBinary(void) : + binaries_{} +{} + + +FatBinary::FatBinary(const std::vector& binaries) : + binaries_{binaries} +{} + + +size_t FatBinary::size(void) const { + return this->binaries_.size(); +} + + +it_binaries FatBinary::begin(void) { + return this->binaries_; +} + +it_const_binaries FatBinary::begin(void) const { + return this->binaries_; +} + + +it_binaries FatBinary::end(void) { + return it_binaries{this->binaries_}.end(); +} + +it_const_binaries FatBinary::end(void) const { + return it_const_binaries{this->binaries_}.end(); +} + + +Binary& FatBinary::at(size_t index) { + return const_cast(static_cast(this)->at(index)); +} +const Binary& FatBinary::at(size_t index) const { + if (index >= this->size()) { + throw std::out_of_range("Bad index"); + } + return *this->binaries_[index]; +} + + +Binary& FatBinary::back(void) { + return const_cast(static_cast(this)->back()); +} +const Binary& FatBinary::back(void) const { + return *this->binaries_.back(); +} + +Binary& FatBinary::operator[](size_t index) { + return const_cast(static_cast(this)->operator[](index)); +} + +const Binary& FatBinary::operator[](size_t index) const { + return this->at(index); +} + + +std::ostream& operator<<(std::ostream& os, const FatBinary& fatbinary) { + for (const Binary& binary : fatbinary) { + os << binary; + os << std::endl << std::endl; + } + + return os; +} + +FatBinary::~FatBinary(void) { + for (Binary* b : this->binaries_) { + delete b; + } +} + + +} +} diff --git a/src/MachO/Parser.cpp b/src/MachO/Parser.cpp index d342ba3..ff9b84c 100644 --- a/src/MachO/Parser.cpp +++ b/src/MachO/Parser.cpp @@ -51,13 +51,13 @@ Parser::Parser(const std::string& file) : } -std::vector Parser::parse(const std::string& filename) { +FatBinary* Parser::parse(const std::string& filename) { if (not is_macho(filename)) { throw bad_file("'" + filename + "' is not a MachO binary"); } Parser parser{filename}; - return parser.binaries_; + return new FatBinary{parser.binaries_}; } // From Vector @@ -73,13 +73,13 @@ Parser::Parser(const std::vector& data, const std::string& name) : } -std::vector Parser::parse(const std::vector& data, const std::string& name) { +FatBinary* Parser::parse(const std::vector& data, const std::string& name) { if (not is_macho(data)) { throw bad_file("'" + name + "' is not a MachO binary"); } Parser parser{data, name}; - return parser.binaries_; + return new FatBinary{parser.binaries_}; } diff --git a/src/PE/Parser.cpp b/src/PE/Parser.cpp index 9750506..2838b8c 100644 --- a/src/PE/Parser.cpp +++ b/src/PE/Parser.cpp @@ -210,14 +210,18 @@ void Parser::build_sections(void) { try { - const uint8_t* ptr_to_rawdata = reinterpret_cast(this->stream_->read( - offset, - size_to_read)); + if (size_to_read > Parser::MAX_DATA_SIZE) { + LOG(WARNING) << "Section '" << section->name() << "' data is too large!"; + } else { + const uint8_t* ptr_to_rawdata = reinterpret_cast(this->stream_->read( + offset, + size_to_read)); - section->content_ = { - ptr_to_rawdata, - ptr_to_rawdata + size_to_read - }; + section->content_ = { + ptr_to_rawdata, + ptr_to_rawdata + size_to_read + }; + } } catch (const std::bad_alloc& e) { LOG(WARNING) << "Section " << section->name() << " corrupted: " << e.what(); } catch (const read_out_of_bound& e) { @@ -464,7 +468,7 @@ void Parser::build_symbols(void) { this->binary_->header().numberof_symbols() * STRUCT_SIZES::Symbol16Size + offset; try { - symbol.name_ = this->stream_->read_string(offset_name); + symbol.name_ = this->stream_->get_string(offset_name); } catch (const LIEF::read_out_of_bound&) { // Corrupted LOG(WARNING) << "Symbol name is corrupted"; } @@ -577,7 +581,7 @@ void Parser::build_exports(void) { uint32_t name_offset = this->binary_->rva_to_offset(export_directory_table->NameRVA); try { - export_object.name_ = this->stream_->read_string(name_offset); + export_object.name_ = this->stream_->get_string(name_offset); } catch (const LIEF::read_out_of_bound& e) { LOG(WARNING) << e.what(); } @@ -617,7 +621,7 @@ void Parser::build_exports(void) { ExportEntry entry; try { - entry.name_ = this->stream_->read_string(name_offset); + entry.name_ = this->stream_->get_string(name_offset); } catch (const LIEF::read_out_of_bound& e) { LOG(WARNING) << e.what(); } diff --git a/src/PE/Parser.tcc b/src/PE/Parser.tcc index 41d0065..3a14115 100644 --- a/src/PE/Parser.tcc +++ b/src/PE/Parser.tcc @@ -271,7 +271,7 @@ void Parser::build_import_table(void) { } // Offset to the Import (Library) name const uint64_t offsetName = this->binary_->rva_to_offset(import.name_RVA_); - import.name_ = this->stream_->read_string(offsetName); + import.name_ = this->stream_->get_string(offsetName); // We assume that a DLL name should be at least 4 length size and "printable @@ -329,7 +329,7 @@ void Parser::build_import_table(void) { if(not entry.is_ordinal()) { - entry.name_ = this->stream_->read_string( + entry.name_ = this->stream_->get_string( this->binary_->rva_to_offset(entry.hint_name_rva()) + sizeof(uint16_t)); entry.hint_ = *reinterpret_cast( @@ -368,19 +368,26 @@ void Parser::build_tls(void) { const uint64_t imagebase = this->binary_->optional_header().imagebase(); - try { - const uint64_t startDataRVA = tls_header->RawDataStartVA - imagebase; - const uint64_t stopDataRVA = tls_header->RawDataEndVA - imagebase; - const uint__ offsetStartTemplate = this->binary_->rva_to_offset(startDataRVA); - const uint__ offsetEndTemplate = this->binary_->rva_to_offset(stopDataRVA); + const uint64_t start_data_rva = tls_header->RawDataStartVA - imagebase; + const uint64_t stop_data_rva = tls_header->RawDataEndVA - imagebase; - const uint8_t* template_ptr = reinterpret_cast( - this->stream_->read(offsetStartTemplate, offsetEndTemplate - offsetStartTemplate)); - std::vector templateData = { - template_ptr, - template_ptr + offsetEndTemplate - offsetStartTemplate - }; - tls.data_template(templateData); + const uint__ start_template_offset = this->binary_->rva_to_offset(start_data_rva); + const uint__ end_template_offset = this->binary_->rva_to_offset(stop_data_rva); + + const size_t size_to_read = end_template_offset - start_template_offset; + + try { + if (size_to_read > Parser::MAX_DATA_SIZE) { + LOG(WARNING) << "TLS's template is too large!"; + } else { + const uint8_t* template_ptr = reinterpret_cast( + this->stream_->read(start_template_offset, size_to_read)); + std::vector template_data = { + template_ptr, + template_ptr + size_to_read + }; + tls.data_template(std::move(template_data)); + } } catch (const read_out_of_bound&) { throw corrupted("TLS corrupted (data template)"); @@ -388,13 +395,15 @@ void Parser::build_tls(void) { throw corrupted("TLS corrupted (data template)"); } - const uint64_t offsetToCallbacks = this->binary_->rva_to_offset(tls.addressof_callbacks() - imagebase); - const uint__ *rvaCallbacksAddress = reinterpret_cast( - this->stream_->read(offsetToCallbacks, sizeof(uint__))); + uint64_t callbacks_offset = this->binary_->rva_to_offset(tls.addressof_callbacks() - imagebase); + uint__ callback_rva = this->stream_->read_integer(callbacks_offset); + callbacks_offset += sizeof(uint__); - while (*rvaCallbacksAddress != 0) { - tls.callbacks_.push_back(static_cast(*rvaCallbacksAddress)); - rvaCallbacksAddress++; + size_t count = 0; + while (callback_rva > 0 and count < Parser::MAX_TLS_CALLBACKS) { + tls.callbacks_.push_back(static_cast(callback_rva)); + callback_rva = this->stream_->read_integer(callbacks_offset); + callbacks_offset += sizeof(uint__); } tls.directory_ = &(this->binary_->data_directory(DATA_DIRECTORY::TLS_TABLE)); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e35d6d7..814d46c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +include(ProcessorCount) find_package(Git REQUIRED) enable_testing() @@ -329,6 +330,11 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/macho") # /!\ Bad Hack /!\ add_dependencies(LIB_LIEF_STATIC lief_samples) add_dependencies(LIB_LIEF_SHARED lief_samples) +ProcessorCount(N) +if(N EQUAL 0) + set(N 1) +endif() -add_custom_target(check-lief COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + +add_custom_target(check-lief COMMAND ${CMAKE_CTEST_COMMAND} --parallel 1 --output-on-failure DEPENDS lief_samples) diff --git a/tests/run_python_test.bat.in b/tests/run_python_test.bat.in index ba783a2..75877ea 100644 --- a/tests/run_python_test.bat.in +++ b/tests/run_python_test.bat.in @@ -1,4 +1,4 @@ -@echo off +@echo on set PYTHONPATH=%PYTHONPATH%;@PROJECT_BINARY_DIR@/api/python