/* Copyright 2017 - 2021 R. Thomas * Copyright 2017 - 2021 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 "LIEF/PE/Parser.hpp" #include "LIEF/PE/Builder.hpp" #include "LIEF/PE/Binary.hpp" #include "LIEF/Abstract/Binary.hpp" #include "pyPE.hpp" namespace LIEF { namespace PE { template using no_const_func = T (Binary::*)(P); template using no_const_getter = T (Binary::*)(void); template using getter_t = T (Binary::*)(void) const; template using setter_t = void (Binary::*)(T); template<> void create(py::module& m) { py::class_(m, "Binary") .def(py::init()) .def_property_readonly("sections", static_cast>(&Binary::sections), "Return binary's " RST_CLASS_REF(lief.PE.Section) " sections", py::return_value_policy::reference) .def_property_readonly("dos_header", static_cast(&Binary::dos_header), "Return " RST_CLASS_REF(lief.PE.DosHeader) "", py::return_value_policy::reference) .def_property_readonly("header", static_cast(&Binary::header), "Return " RST_CLASS_REF(lief.PE.Header) "", py::return_value_policy::reference) .def_property_readonly("optional_header", static_cast(&Binary::optional_header), "Return " RST_CLASS_REF(lief.PE.OptionalHeader) "", py::return_value_policy::reference) .def_property_readonly("virtual_size", &Binary::virtual_size, "Binary size when mapped in memory.\n\n" "This value should matches :attr:`~lief.PE.OptionalHeader.sizeof_image`") .def_property_readonly("sizeof_headers", &Binary::sizeof_headers, "Size of all PE headers") .def("rva_to_offset", &Binary::rva_to_offset, "rva_address"_a, "Convert a relative virtual address to an offset") .def("va_to_offset", &Binary::va_to_offset, "va_address"_a, "Convert a **absolute** virtual address to an offset") .def("section_from_offset", static_cast(&Binary::section_from_offset), "Return the " RST_CLASS_REF(lief.PE.Section) " which contains the offset", "offset"_a, py::return_value_policy::reference) .def("section_from_rva", static_cast(&Binary::section_from_rva), "Return the " RST_CLASS_REF(lief.PE.Section) " which contains the **relative** virtual address", "rva"_a, py::return_value_policy::reference) .def_property("tls", static_cast(&Binary::tls), static_cast(&Binary::tls), "" RST_CLASS_REF(lief.PE.TLS) " object (if present)", py::return_value_policy::reference) .def_property("rich_header", static_cast(&Binary::rich_header), static_cast(&Binary::rich_header), "" RST_CLASS_REF(lief.PE.RichHeader) " object (if present)", py::return_value_policy::reference) .def_property_readonly("has_rich_header", &Binary::has_rich_header, "``True`` if the current binary has a " RST_CLASS_REF(lief.PE.RichHeader) " object") .def_property_readonly("has_debug", &Binary::has_debug, "``True`` if the current binary has a " RST_CLASS_REF(lief.PE.Debug) " object") .def_property_readonly("has_tls", &Binary::has_tls, "``True`` if the current binary has a " RST_CLASS_REF(lief.PE.TLS) " object") .def_property_readonly("has_imports", &Binary::has_imports, "``True`` if the current binary import libraries (" RST_CLASS_REF(lief.PE.Import) ")") .def_property_readonly("has_exports", &Binary::has_exports, "``True`` if the current binary has a " RST_CLASS_REF(lief.PE.Export) " object") .def_property_readonly("has_resources", &Binary::has_resources, "``True`` if the current binary has a " RST_CLASS_REF(lief.PE.Resources) " object") .def_property_readonly("has_exceptions", &Binary::has_exceptions, "``True`` if the current binary has ``Exceptions``") .def_property_readonly("has_relocations", &Binary::has_relocations, "``True`` if the current binary use " RST_CLASS_REF(lief.PE.Relocation) "") .def_property_readonly("has_configuration", &Binary::has_configuration, "``True`` if the current binary has " RST_CLASS_REF(lief.PE.LoadConfiguration) "") .def_property_readonly("has_signatures", &Binary::has_signatures, "``True`` if the binary has signatures (" 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") .def_property_readonly("exception_functions", &Binary::exception_functions, "" RST_CLASS_REF(lief.Function) " found in the Exception directory") .def("predict_function_rva", static_cast(&Binary::predict_function_rva), "Try to predict the RVA of the given function name in the given import library name", "library"_a, "function"_a) .def_property_readonly("signatures", static_cast(&Binary::signatures), "Return an iterator over the " RST_CLASS_REF(lief.PE.Signature) " objects", py::return_value_policy::reference) .def("authentihash", [] (const Binary& bin, ALGORITHMS algo) { const std::vector& data = bin.authentihash(algo); return py::bytes(reinterpret_cast(data.data()), data.size()); }, "Compute the authentihash according to the " RST_CLASS_REF(lief.PE.ALGORITHMS) " " "given in the first parameter", "algorithm"_a) .def("verify_signature", static_cast(&Binary::verify_signature), R"delim( Verify the binary against the embedded signature(s) (if any) Firstly, it checks that the embedded signatures are correct (c.f. :meth:`lief.PE.Signature.check`) and then it checks that the authentihash matches :attr:`lief.PE.ContentInfo.digest` One can tweak the verification process with the :class:`lief.PE.Signature.VERIFICATION_CHECKS` flags .. seealso:: :meth:`lief.PE.Signature.check` )delim", "checks"_a = Signature::VERIFICATION_CHECKS::DEFAULT) .def("verify_signature", static_cast(&Binary::verify_signature), R"delim( Verify the binary with the Signature object provided in the first parameter It can be used to verify a detached signature: .. code-block:: python detached = lief.PE.Signature.parse("sig.pkcs7") binary.verify_signature(detached) )delim", "signature"_a, "checks"_a = Signature::VERIFICATION_CHECKS::DEFAULT) .def_property_readonly("authentihash_md5", [] (const Binary& bin) { const std::vector& data = bin.authentihash(ALGORITHMS::MD5); return py::bytes(reinterpret_cast(data.data()), data.size()); }, "Authentihash **MD5** value") .def_property_readonly("authentihash_sha1", [] (const Binary& bin) { const std::vector& data = bin.authentihash(ALGORITHMS::SHA_1); return py::bytes(reinterpret_cast(data.data()), data.size()); }, "Authentihash **SHA1** value") .def_property_readonly("authentihash_sha256", [] (const Binary& bin) { const std::vector& data = bin.authentihash(ALGORITHMS::SHA_256); return py::bytes(reinterpret_cast(data.data()), data.size()); }, "Authentihash **SHA-256** value") .def_property_readonly("authentihash_sha512", [] (const Binary& bin) { const std::vector& data = bin.authentihash(ALGORITHMS::SHA_512); return py::bytes(reinterpret_cast(data.data()), data.size()); }, "Authentihash **SHA-512** value") .def_property_readonly("debug", static_cast(&Binary::debug), "Return the " RST_CLASS_REF(lief.PE.Debug) "", py::return_value_policy::reference) .def_property_readonly("load_configuration", static_cast(&Binary::load_configuration), "Return the " RST_CLASS_REF(lief.PE.LoadConfiguration) " object", py::return_value_policy::reference) .def("get_export", static_cast(&Binary::get_export), "Return a " RST_CLASS_REF(lief.PE.Export) " object", py::return_value_policy::reference) .def_property_readonly("symbols", static_cast& (Binary::*)(void)>(&Binary::symbols), "Return binary's " RST_CLASS_REF(lief.PE.Symbol) "", py::return_value_policy::reference) .def("get_section", static_cast>(&Binary::get_section), "Return the " RST_CLASS_REF(lief.PE.Section) " object from the given name", "section_name"_a, py::return_value_policy::reference) .def("add_section", &Binary::add_section, "Add a " RST_CLASS_REF(lief.PE.Section) " to the binary.", "section"_a, py::arg("type") = PE_SECTION_TYPES::UNKNOWN, py::return_value_policy::reference) //.def("get_import_section", // static_cast>(&Binary::get_import_section), // py::return_value_policy::reference_internal) .def_property_readonly("relocations", static_cast>(&Binary::relocations), "Return an iterator on the " RST_CLASS_REF(lief.PE.Relocation) "", py::return_value_policy::reference) .def("add_relocation", &Binary::add_relocation, "Add a " RST_CLASS_REF(lief.PE.Relocation) " to the binary", "relocation"_a) .def("remove_all_relocations", &Binary::remove_all_relocations) .def("remove", static_cast(&Binary::remove), "Remove the " RST_CLASS_REF(lief.PE.Section) " given in first parameter", "section"_a, "clear"_a = false) .def_property_readonly("data_directories", static_cast>(&Binary::data_directories), "Return an iterator on the " RST_CLASS_REF(lief.PE.DataDirectory) "", py::return_value_policy::reference) .def("data_directory", static_cast(&Binary::data_directory), "Return the " RST_CLASS_REF(lief.PE.DataDirectory) " object from the given " RST_CLASS_REF(lief.PE.DATA_DIRECTORY) " type", "type"_a, py::return_value_policy::reference) .def_property_readonly("imports", static_cast>(&Binary::imports), "Return an iterator on the " RST_CLASS_REF(lief.PE.Import) " libraries", py::return_value_policy::reference) .def("has_import", &Binary::has_import, "``True`` if the binary import the given library name", "import_name"_a) .def("get_import", static_cast>(&Binary::get_import), "Returns the " RST_CLASS_REF(lief.PE.Import) " from the given name", "import_name"_a, py::return_value_policy::reference) .def_property_readonly("resources_manager", static_cast>(&Binary::resources_manager), "Return the " RST_CLASS_REF(lief.PE.ResourcesManager) " to manage resources") .def_property_readonly("resources", static_cast>(&Binary::resources), "Return the " RST_CLASS_REF(lief.PE.ResourceNode) " tree", py::return_value_policy::reference) .def_property_readonly("overlay", static_cast&>>(&Binary::overlay), "Return the overlay content as a ``list`` of bytes", py::return_value_policy::reference) .def_property("dos_stub", static_cast&>>(&Binary::dos_stub), static_cast&>>(&Binary::dos_stub), "DOS stub content as a ``list`` of bytes") .def("add_import_function", &Binary::add_import_function, "Add a function to the given " RST_CLASS_REF(lief.PE.Import) " name", "import_name"_a, "function_name"_a, py::return_value_policy::reference) .def("add_library", &Binary::add_library, "Add an " RST_CLASS_REF(lief.PE.Import) " by name", "import_name"_a, py::return_value_policy::reference) .def("remove_library", &Binary::remove_library, "Remove the " RST_CLASS_REF(lief.PE.Import) " from the given name", "import_name"_a) .def("hook_function", static_cast(&Binary::hook_function), "Hook the given function name\n\n" ".. note:: \n\n" "\tWhen using this function, the :class:`~lief.PE.Builder` should be configured as follow:\n\n" "\t.. code-block:: python\n\n" "\t\t\n\n" "\t\tbuilder.build_imports(True).patch_imports(True)\n\n", "function_name"_a, "hook_address"_a) .def("hook_function", static_cast(&Binary::hook_function), "Hook the function name from the given library name", "library_name"_a, "function_name"_a, "hook_address"_a) .def("remove_all_libraries", &Binary::remove_all_libraries, "Remove all imported libraries") .def("write", &Binary::write, "Build the binary and write the result to the given ``output``", "output_path"_a) .def("__str__", [] (const Binary& binary) { std::ostringstream stream; stream << binary; std::string str = stream.str(); return str; }); } } }