Skip to content

Commit

Permalink
Add interface to tweak the PE parser (resolve #839)
Browse files Browse the repository at this point in the history
This commit also removes the Binary's name attribute.
  • Loading branch information
romainthomas committed Apr 28, 2023
1 parent 2276653 commit 8908fe4
Show file tree
Hide file tree
Showing 45 changed files with 292 additions and 166 deletions.
1 change: 0 additions & 1 deletion api/c/ELF/Binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ namespace LIEF {
namespace ELF {
void init_c_binary(Elf_Binary_t* c_binary, Binary* binary) {
c_binary->handler = reinterpret_cast<void*>(binary);
c_binary->name = binary->name().c_str();
c_binary->type = static_cast<enum LIEF_ELF_ELF_CLASS>(binary->type());
c_binary->interpreter = nullptr;
if (binary->has_interpreter()) {
Expand Down
1 change: 0 additions & 1 deletion api/c/MachO/Binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ namespace MachO {
void init_c_binary(Macho_Binary_t* c_binary, Binary* binary) {

c_binary->handler = reinterpret_cast<void*>(binary);
c_binary->name = binary->name().c_str();
c_binary->imagebase = binary->imagebase();
init_c_header(c_binary, binary);
init_c_commands(c_binary, binary);
Expand Down
1 change: 0 additions & 1 deletion api/c/PE/Binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ namespace LIEF {
namespace PE {

void init_c_binary(Pe_Binary_t* c_binary, Binary* binary) {
c_binary->name = binary->name().c_str();
c_binary->handler = reinterpret_cast<void*>(binary);

init_c_dos_header(c_binary, binary);
Expand Down
5 changes: 0 additions & 5 deletions api/python/src/Abstract/objects/pyBinary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ void create<Binary>(py::module& m) {
&Binary::has_nx,
"Check if the binary has ``NX`` protection (non executable stack)")

.def_property("name",
static_cast<getter_t<const std::string&>>(&Binary::name),
static_cast<setter_t<const std::string&>>(&Binary::name),
"Binary's name")

.def_property_readonly("header",
&Binary::header,
"Binary's abstract header (" RST_CLASS_REF(lief.Header) ")")
Expand Down
10 changes: 5 additions & 5 deletions api/python/src/Abstract/objects/pyParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ template<>
void create<Parser>(py::module& m) {

m.def("parse",
[] (py::bytes bytes, const std::string& name) {
[] (py::bytes bytes) {
std::string raw_str = bytes;
std::vector<uint8_t> raw = {
std::make_move_iterator(std::begin(raw_str)),
Expand All @@ -38,7 +38,7 @@ void create<Parser>(py::module& m) {
std::exception_ptr ep;
Py_BEGIN_ALLOW_THREADS
try {
binary = Parser::parse(std::move(raw), name);
binary = Parser::parse(std::move(raw));
} catch (...) {
ep = std::current_exception();
}
Expand All @@ -55,7 +55,7 @@ void create<Parser>(py::module& m) {
depending on the given binary format.
)delim",
"raw"_a, "name"_a = "",
"raw"_a,
py::return_value_policy::take_ownership);

m.def("parse",
Expand Down Expand Up @@ -86,7 +86,7 @@ void create<Parser>(py::module& m) {


m.def("parse",
[] (py::object byteio, const std::string& name) -> py::object {
[] (py::object byteio) -> py::object {
if (auto stream = PyIOStream::from_python(byteio)) {
auto ptr = std::make_unique<PyIOStream>(std::move(*stream));
py::object binary;
Expand All @@ -113,7 +113,7 @@ void create<Parser>(py::module& m) {
depending on the given binary format.
)delim",
"io"_a, "name"_a = "",
"io"_a,
py::return_value_policy::take_ownership);
}
}
10 changes: 5 additions & 5 deletions api/python/src/ELF/objects/pyParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void create<Parser>(py::module& m) {
py::return_value_policy::take_ownership);

m.def("parse",
static_cast<std::unique_ptr<Binary>(*)(const std::vector<uint8_t>&, const std::string&, DYNSYM_COUNT_METHODS)>(&Parser::parse),
static_cast<std::unique_ptr<Binary>(*)(const std::vector<uint8_t>&, DYNSYM_COUNT_METHODS)>(&Parser::parse),
R"delim(
Parse the ELF binary from the given **list of bytes** and return a :class:`lief.ELF.Binary` object
Expand All @@ -52,15 +52,15 @@ void create<Parser>(py::module& m) {
:attr:`lief.ELF.DYNSYM_COUNT_METHODS.COUNT_AUTO`
)delim",

"raw"_a, "name"_a = "", "dynsym_count_method"_a = DYNSYM_COUNT_METHODS::COUNT_AUTO,
"raw"_a, "dynsym_count_method"_a = DYNSYM_COUNT_METHODS::COUNT_AUTO,
py::return_value_policy::take_ownership);


m.def("parse",
[] (py::object byteio, const std::string& name, DYNSYM_COUNT_METHODS count) -> py::object {
[] (py::object byteio, DYNSYM_COUNT_METHODS count) -> py::object {
if (auto stream = PyIOStream::from_python(byteio)) {
auto ptr = std::make_unique<PyIOStream>(std::move(*stream));
return py::cast(ELF::Parser::parse(std::move(ptr), name, count));
return py::cast(ELF::Parser::parse(std::move(ptr), count));
}
logging::log(logging::LOG_ERR, "Can't create a LIEF stream interface over the provided io");
return py::none();
Expand All @@ -72,7 +72,7 @@ void create<Parser>(py::module& m) {
(:class:`lief.ELF.lief.ELF.DYNSYM_COUNT_METHODS`). By default, the value is set to
:attr:`lief.ELF.lief.ELF.DYNSYM_COUNT_METHODS.COUNT_AUTO`
)delim",
"io"_a, "name"_a = "", "dynsym_count_method"_a = DYNSYM_COUNT_METHODS::COUNT_AUTO,
"io"_a, "dynsym_count_method"_a = DYNSYM_COUNT_METHODS::COUNT_AUTO,
py::return_value_policy::take_ownership);
}
}
Expand Down
4 changes: 4 additions & 0 deletions api/python/src/MachO/objects/pyBinary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ void create<Binary>(py::module& m) {
&Binary::has_filesets,
"Return ``True`` if the binary has filesets")

.def_property_readonly("fileset_name",
&Binary::fileset_name,
"Name associated with the LC_FILESET_ENTRY binary")

.def_property_readonly("imagebase",
&Binary::imagebase,
R"delim(
Expand Down
6 changes: 2 additions & 4 deletions api/python/src/MachO/objects/pyParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,13 @@ void create<Parser>(py::module& m) {


m.def("parse",
static_cast<std::unique_ptr<FatBinary> (*) (const std::vector<uint8_t>&, const std::string&, const ParserConfig&)>(&LIEF::MachO::Parser::parse),
static_cast<std::unique_ptr<FatBinary> (*) (const std::vector<uint8_t>&, const ParserConfig&)>(&LIEF::MachO::Parser::parse),
R"delim(
Parse the given binary (from raw bytes) and return a :class:`~lief.MachO.FatBinary` object
One can configure the parsing with the ``config`` parameter. See :class:`~lief.MachO.ParserConfig`
)delim",
"raw"_a,
"name"_a = "",
"config"_a = ParserConfig::quick(),
py::return_value_policy::take_ownership);

Expand All @@ -65,7 +64,7 @@ void create<Parser>(py::module& m) {
py::return_value_policy::take_ownership);

m.def("parse",
[] (py::object byteio, std::string name, const ParserConfig& config) -> py::object {
[] (py::object byteio, const ParserConfig& config) -> py::object {
if (auto stream = PyIOStream::from_python(byteio)) {
auto ptr = std::make_unique<PyIOStream>(std::move(*stream));
return py::cast(MachO::Parser::parse(std::move(ptr), config));
Expand All @@ -79,7 +78,6 @@ void create<Parser>(py::module& m) {
One can configure the parsing with the ``config`` parameter. See :class:`~lief.MachO.ParserConfig`
)delim",
"io"_a,
"name"_a = "",
"config"_a = ParserConfig::quick(),
py::return_value_policy::take_ownership);
}
Expand Down
10 changes: 5 additions & 5 deletions api/python/src/OAT/objects/pyParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ void create<Parser>(py::module& m) {
py::return_value_policy::take_ownership);

m.def("parse",
static_cast<std::unique_ptr<Binary> (*) (std::vector<uint8_t>, const std::string&)>(&Parser::parse),
static_cast<std::unique_ptr<Binary> (*) (std::vector<uint8_t>)>(&Parser::parse),
"Parse the given raw data and return a " RST_CLASS_REF(lief.OAT.Binary) " object",
"raw"_a, "name"_a = "",
"raw"_a,
py::return_value_policy::take_ownership);


m.def("parse",
[] (py::object byteio, const std::string& name) {
[] (py::object byteio) {
const auto& io = py::module::import("io");
const auto& RawIOBase = io.attr("RawIOBase");
const auto& BufferedIOBase = io.attr("BufferedIOBase");
Expand Down Expand Up @@ -76,9 +76,9 @@ void create<Parser>(py::module& m) {
std::make_move_iterator(std::begin(raw_str)),
std::make_move_iterator(std::end(raw_str))};

return LIEF::OAT::Parser::parse(std::move(raw), name);
return LIEF::OAT::Parser::parse(std::move(raw));
},
"io"_a, "name"_a = "",
"io"_a,
py::return_value_policy::take_ownership);
}
}
Expand Down
1 change: 1 addition & 0 deletions api/python/src/PE/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ set(LIEF_PYTHON_PE_SRC
"${CMAKE_CURRENT_LIST_DIR}/objects/pyExportEntry.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyRelocation.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyParser.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyParserConfig.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyImportEntry.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDelayImport.cpp"
"${CMAKE_CURRENT_LIST_DIR}/objects/pyDelayImportEntry.cpp"
Expand Down
4 changes: 2 additions & 2 deletions api/python/src/PE/objects/pyBinary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ void create<Binary>(py::module& m) {
init_ref_iterator<Binary::it_const_signatures>(bin, "it_const_signatures");

bin
.def(py::init<const std::string&, PE_TYPE>(),
"name"_a, "type"_a)
.def(py::init<PE_TYPE>(),
"type"_a)

.def_property_readonly("sections",
static_cast<no_const_getter<Binary::it_sections>>(&Binary::sections),
Expand Down
14 changes: 7 additions & 7 deletions api/python/src/PE/objects/pyParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,29 @@ template<>
void create<Parser>(py::module& m) {

m.def("parse",
static_cast<std::unique_ptr<Binary> (*) (const std::string&)>(&Parser::parse),
static_cast<std::unique_ptr<Binary> (*) (const std::string&, const ParserConfig&)>(&Parser::parse),
"Parse the PE binary from the given **file path** and return a " RST_CLASS_REF(lief.PE.Binary) " object",
"filename"_a,
"filename"_a, "config"_a = ParserConfig::all(),
py::return_value_policy::take_ownership);

m.def("parse",
static_cast<std::unique_ptr<Binary> (*) (std::vector<uint8_t>, const std::string&)>(&Parser::parse),
static_cast<std::unique_ptr<Binary> (*) (std::vector<uint8_t>, const ParserConfig&)>(&Parser::parse),
"Parse the PE binary from the given **list of bytes** and return a :class:`lief.PE.Binary` object",
"raw"_a, "name"_a = "",
"raw"_a, "config"_a = ParserConfig::all(),
py::return_value_policy::take_ownership);


m.def("parse",
[] (py::object byteio, const std::string& name) -> py::object {
[] (py::object byteio, const ParserConfig&) -> py::object {
if (auto stream = PyIOStream::from_python(byteio)) {
auto ptr = std::make_unique<PyIOStream>(std::move(*stream));
return py::cast(PE::Parser::parse(std::move(ptr), name));
return py::cast(PE::Parser::parse(std::move(ptr)));
}
logging::log(logging::LOG_ERR, "Can't create a LIEF stream interface over the provided io");
return py::none();
},
"Parse the PE binary from the given Python IO interface and return a :class:`lief.PE.Binary` object",
"io"_a, "name"_a = "",
"io"_a, "config"_a = ParserConfig::all(),
py::return_value_policy::take_ownership);
}

Expand Down
58 changes: 58 additions & 0 deletions api/python/src/PE/objects/pyParserConfig.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* Copyright 2017 - 2023 R. Thomas
* Copyright 2017 - 2023 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 <string>

#include "LIEF/PE/ParserConfig.hpp"

#include "pyPE.hpp"

namespace LIEF {
namespace PE {

template<>
void create<ParserConfig>(py::module& m) {

py::class_<ParserConfig>(m, "ParserConfig",
R"delim(
This class is used to tweak the PE Parser (:class:`~lief.PE.Parser`)
)delim")

.def(py::init<>())
.def_readwrite("parse_signature", &ParserConfig::parse_signature,
"Parse PE Authenticode signature")

.def_readwrite("parse_exports", &ParserConfig::parse_exports,
"Parse PE Exports Directory")

.def_readwrite("parse_imports", &ParserConfig::parse_imports,
"Parse PE Import Directory")

.def_readwrite("parse_rsrc", &ParserConfig::parse_rsrc,
"Parse PE resources tree")

.def_readwrite("parse_reloc", &ParserConfig::parse_reloc,
"Parse PE relocations")

.def_property_readonly_static("all",
[] (py::object /* self */) { return ParserConfig::all(); },
R"delim(
Return a parser configuration such as all the objects supported by LIEF are parsed
)delim");

}

}
}
1 change: 1 addition & 0 deletions api/python/src/PE/pyPE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void init_python_module(py::module& m) {
}

void init_objects(py::module& m) {
CREATE(ParserConfig, m);
CREATE(Parser, m);

CREATE(DosHeader, m);
Expand Down
1 change: 1 addition & 0 deletions api/python/src/PE/pyPE.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ void init_objects(py::module&);
void init_enums(py::module&);
void init_utils(py::module&);

SPECIALIZE_CREATE(ParserConfig);
SPECIALIZE_CREATE(Parser);

SPECIALIZE_CREATE(Binary);
Expand Down
4 changes: 2 additions & 2 deletions doc/sphinx/api/cpp/macho.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
MachO
-----

Parsers
*******
Parser
******

.. doxygenclass:: LIEF::MachO::Parser
:project: lief
Expand Down
12 changes: 12 additions & 0 deletions doc/sphinx/api/cpp/pe.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
PE
--

Parser
******

.. doxygenclass:: LIEF::PE::Parser
:project: lief

.. doxygenstruct:: LIEF::PE::ParserConfig
:project: lief

----------


Binary
******

Expand Down
5 changes: 5 additions & 0 deletions doc/sphinx/api/python/pe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Parser

.. autofunction:: lief.PE.parse

.. autoclass:: lief.PE.ParserConfig
:members:
:inherited-members:
:undoc-members:


Binary
******
Expand Down
27 changes: 27 additions & 0 deletions doc/sphinx/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,33 @@ Changelog

* Fix relocation issue when using `-Wl,--emit-relocs` (c.f. :issue:`897` / :pr:`898` by :github_user:`adamjseitz`)

:MachO:

* The *fileset name* is now stored in :attr:`lief.MachO.Binary.fileset_name`
(instead of `lief.MachO.Binary.name`)

:PE:

* Add a :class:`lief.PE.ParserConfig` interface that can be used to tweak
which parts of the PE format should be parsed (:issue:`839`).

:Example:

.. code-block:: python
config = lief.PE.ParserConfig()
# Skip parsing PE authenticode
config.parse_signature = False
pe = lief.PE.parse("pe.exe", config)
:General Design:

* Remove the `lief.Binary.name` attribute



0.13.0 - April 9, 2023
----------------------

Expand Down
Loading

0 comments on commit 8908fe4

Please sign in to comment.