Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Improve parser API
API Changes:
  - lief.parse() can takes a list of integer as entry
  - LIEF::MachO::parse can take a std::vector<uint8_t> as entry

Related to #49
  • Loading branch information
romainthomas committed Jul 27, 2017
1 parent b09efa1 commit f330fa8
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 22 deletions.
8 changes: 7 additions & 1 deletion api/python/Abstract/objects/pyParser.cpp
Expand Up @@ -22,8 +22,14 @@
void init_LIEF_Parser_class(py::module& m) {

m.def("parse",
&LIEF::Parser::parse,
static_cast<LIEF::Binary* (*) (const std::string&)>(&LIEF::Parser::parse),
"Parse the given binary and return a " RST_CLASS_REF(lief.Binary) " object",
"filepath"_a,
py::return_value_policy::take_ownership);

m.def("parse",
static_cast<LIEF::Binary* (*) (const std::vector<uint8_t>&, const std::string&)>(&LIEF::Parser::parse),
"Parse the given binary and return a " RST_CLASS_REF(lief.Binary) " object",
"raw"_a, "name"_a = "",
py::return_value_policy::take_ownership);
}
13 changes: 12 additions & 1 deletion api/python/MachO/objects/pyParser.cpp
Expand Up @@ -24,6 +24,17 @@ void init_MachO_Parser_class(py::module& m) {

// Parser (Parser)
m.def("parse",
&LIEF::MachO::Parser::parse,
static_cast<std::vector<Binary*> (*) (const std::string&)>(&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<std::vector<Binary*> (*) (const std::vector<uint8_t>&, 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);


}
31 changes: 26 additions & 5 deletions api/python/pyUtils.cpp
Expand Up @@ -24,19 +24,40 @@ void init_utils_functions(py::module& m) {
#if defined(LIEF_PE_MODULE)
m.def("is_pe",
static_cast<bool (*)(const std::string&)>(&LIEF::PE::is_pe),
"Check if the given file is a ``PE``");
"Check if the given file is a ``PE`` (from filename)",
"filename"_a);

m.def("is_pe",
static_cast<bool (*)(const std::vector<uint8_t>&)>(&LIEF::PE::is_pe),
"Check if the given raw data is a ``PE``",
"raw"_a);
#endif

#if defined(LIEF_ELF_MODULE)
m.def("is_elf",
&LIEF::ELF::is_elf,
"Check if the given file is an ``ELF``");
static_cast<bool (*)(const std::string&)>(&LIEF::ELF::is_elf),
"Check if the given file is an ``ELF``",
"filename"_a);


m.def("is_elf",
static_cast<bool (*)(const std::vector<uint8_t>&)>(&LIEF::ELF::is_elf),
"Check if the given raw data is an ``ELF``",
"raw"_a);
#endif

#if defined(LIEF_MACHO_MODULE)
m.def("is_macho",
&LIEF::MachO::is_macho,
"Check if the given binary is ``MachO``");
static_cast<bool (*)(const std::string&)>(&LIEF::MachO::is_macho),
"Check if the given file is a ``MachO`` (from filename)",
"filename"_a);


m.def("is_macho",
static_cast<bool (*)(const std::vector<uint8_t>&)>(&LIEF::MachO::is_macho),
"Check if the given raw data is a ``MachO``",
"raw"_a);

#endif

}
12 changes: 12 additions & 0 deletions doc/sphinx/api/cpp/elf.rst
Expand Up @@ -149,6 +149,18 @@ Note
----------


Utilities
*********

.. doxygenfunction:: LIEF::ELF::is_elf(const std::string &)
:project: lief

.. doxygenfunction:: LIEF::ELF::is_elf(const std::vector< uint8_t > &)
:project: lief

----------



Enums
*****
Expand Down
20 changes: 20 additions & 0 deletions doc/sphinx/api/cpp/macho.rst
Expand Up @@ -151,6 +151,26 @@ Relocation

----------

Utilities
*********

.. doxygenfunction:: LIEF::MachO::is_macho(const std::string &)
:project: lief

.. doxygenfunction:: LIEF::MachO::is_macho(const std::vector< uint8_t > &)
:project: lief

.. doxygenfunction:: LIEF::MachO::is_fat(const std::string &)
:project: lief

.. doxygenfunction:: LIEF::MachO::is_64(const std::string &)
:project: lief

.. doxygenfunction:: LIEF::MachO::decode_uleb128(const std::string &)
:project: lief

----------


Enums
*****
Expand Down
9 changes: 8 additions & 1 deletion doc/sphinx/api/python/index.rst
Expand Up @@ -4,9 +4,16 @@ Python
======

.. toctree::
:maxdepth: 2
:caption: Common
:maxdepth: 1

utilities.rst
abstract.rst

.. toctree::
:caption: Formats specific
:maxdepth: 2

elf.rst
pe.rst
macho.rst
Expand Down
8 changes: 8 additions & 0 deletions doc/sphinx/api/python/utilities.rst
@@ -0,0 +1,8 @@
Utilities
---------

.. autofunction:: lief.is_pe

.. autofunction:: lief.is_elf

.. autofunction:: lief.is_macho
8 changes: 8 additions & 0 deletions include/LIEF/Abstract/Parser.hpp
Expand Up @@ -34,6 +34,14 @@ class DLL_PUBLIC Parser
//! @see LIEF::MachO::Parser::parse
static Binary* parse(const std::string& filename);


//! @brief Construct an LIEF::Binary from the given raw data
//!
//! @warning If the target file is a FAT Mach0, it will
//! return the **last** one
//! @see LIEF::MachO::Parser::parse
static Binary* parse(const std::vector<uint8_t>& raw, const std::string& name = "");

protected:
Parser(const std::string& file);
uint64_t binary_size_;
Expand Down
5 changes: 5 additions & 0 deletions include/LIEF/ELF/utils.hpp
Expand Up @@ -17,6 +17,7 @@
#define LIEF_ELF_UTILS_H_

#include <string>
#include <vector>

#include "LIEF/types.hpp"
#include "LIEF/visibility.h"
Expand All @@ -26,6 +27,10 @@ namespace ELF {

//! @brief Check if the given file is an ELF one.
DLL_PUBLIC bool is_elf(const std::string& file);

//! @brief check if the raw data is a ELF file
DLL_PUBLIC bool is_elf(const std::vector<uint8_t>& raw);

DLL_PUBLIC unsigned long hash32(const char* name);
DLL_PUBLIC unsigned long hash64(const char* name);
DLL_PUBLIC uint32_t dl_new_hash(const char* name);
Expand Down
3 changes: 2 additions & 1 deletion include/LIEF/MachO/Parser.hpp
Expand Up @@ -38,10 +38,11 @@ class DLL_PUBLIC Parser : public LIEF::Parser {
~Parser(void);

static std::vector<Binary*> parse(const std::string& filename);
static std::vector<Binary*> parse(const std::vector<uint8_t>& data, const std::string& name = "");

private:
Parser(const std::string& file);
Parser(const std::vector<uint8_t>& data);
Parser(const std::vector<uint8_t>& data, const std::string& name);
Parser(void);

void build(void);
Expand Down
4 changes: 4 additions & 0 deletions include/LIEF/MachO/utils.hpp
Expand Up @@ -20,10 +20,14 @@
#include "LIEF/visibility.h"

#include <string>
#include <vector>

namespace LIEF {
namespace MachO {
DLL_PUBLIC bool is_macho(const std::string& file);

DLL_PUBLIC bool is_macho(const std::vector<uint8_t>& raw);

DLL_PUBLIC bool is_fat(const std::string& file);
DLL_PUBLIC bool is_64(const std::string& file);
DLL_PUBLIC uint64_t decode_uleb128(const std::string& file);
Expand Down
38 changes: 37 additions & 1 deletion src/Abstract/Parser.cpp
Expand Up @@ -28,7 +28,10 @@

namespace LIEF {
Parser::~Parser(void) = default;
Parser::Parser(void) = default;
Parser::Parser(void) :
binary_size_{0},
binary_name_{""}
{}

Binary* Parser::parse(const std::string& filename) {

Expand Down Expand Up @@ -63,6 +66,39 @@ Binary* Parser::parse(const std::string& filename) {

}

Binary* Parser::parse(const std::vector<uint8_t>& raw, const std::string& name) {

#if defined(LIEF_ELF_MODULE)
if (ELF::is_elf(raw)) {
return ELF::Parser::parse(raw, name);
}
#endif


#if defined(LIEF_PE_MODULE)
if (PE::is_pe(raw)) {
return PE::Parser::parse(raw, name);
}
#endif

#if defined(LIEF_MACHO_MODULE)
if (MachO::is_macho(raw)) {
// For fat binary we take the last one...
std::vector<MachO::Binary*> binaries = MachO::Parser::parse(raw, name);
MachO::Binary* binary_return = binaries.back();
binaries.pop_back();
// delete others
for (MachO::Binary* binary : binaries) {
delete binary;
}
return binary_return;
}
#endif

throw bad_file("Unknown format");

}

Parser::Parser(const std::string& filename) :
binary_size_{0},
binary_name_{filename}
Expand Down
13 changes: 9 additions & 4 deletions src/ELF/Parser.cpp
Expand Up @@ -55,10 +55,6 @@ Parser::Parser(const std::string& file, DYNSYM_COUNT_METHODS count_mtd) :
type_{0},
count_mtd_{count_mtd}
{
if (not is_elf(file)) {
throw LIEF::bad_format("'" + file + "' is not an ELF");
}

this->stream_ = std::unique_ptr<VectorStream>(new VectorStream{file});
this->init(filesystem::path(file).filename());
}
Expand Down Expand Up @@ -97,6 +93,10 @@ void Parser::init(const std::string& name) {
}

Binary* Parser::parse(const std::string& filename, DYNSYM_COUNT_METHODS count_mtd) {
if (not is_elf(filename)) {
throw LIEF::bad_format("'" + filename + "' is not an ELF");
}

Parser parser{filename, count_mtd};
return parser.binary_;
}
Expand All @@ -105,6 +105,11 @@ Binary* Parser::parse(
const std::vector<uint8_t>& data,
const std::string& name,
DYNSYM_COUNT_METHODS count_mtd) {

if (not is_elf(data)) {
throw LIEF::bad_format("'" + name + "' is not an ELF");
}

Parser parser{data, name, count_mtd};
return parser.binary_;
}
Expand Down
17 changes: 17 additions & 0 deletions src/ELF/utils.cpp
Expand Up @@ -39,6 +39,23 @@ bool is_elf(const std::string& file) {
return std::equal(std::begin(magic), std::end(magic), std::begin(ElfMagic));
}

bool is_elf(const std::vector<uint8_t>& raw) {

char magic[sizeof(ElfMagic)];

if (raw.size() < sizeof(ElfMagic)) {
return false;
}


std::copy(
reinterpret_cast<const uint8_t*>(raw.data()),
reinterpret_cast<const uint8_t*>(raw.data()) + sizeof(ElfMagic),
magic);

return std::equal(std::begin(magic), std::end(magic), std::begin(ElfMagic));
}

//! SYSV hash function
unsigned long hash32(const char* name) {
unsigned long h = 0, g;
Expand Down
41 changes: 33 additions & 8 deletions src/MachO/Parser.cpp
Expand Up @@ -36,29 +36,54 @@ namespace MachO {
Parser::Parser(void) = default;
Parser::~Parser(void) = default;


// From File
Parser::Parser(const std::string& file) :
LIEF::Parser{file}
LIEF::Parser{file},
stream_{std::unique_ptr<VectorStream>(new VectorStream{file})},
binaries_{}
{

if (not is_macho(file)) {
throw bad_file("'" + file + "' is not a MachO binary");
this->build();
for (Binary* binary : this->binaries_) {
binary->name(filesystem::path(file).filename());
}

this->stream_ = std::unique_ptr<VectorStream>(new VectorStream{file});
this->build();
}


std::vector<Binary*> Parser::parse(const std::string& filename) {
if (not is_macho(filename)) {
throw bad_file("'" + filename + "' is not a MachO binary");
}

Parser parser{filename};
for (Binary* binary : parser.binaries_) {
binary->name(filesystem::path(filename).filename());
return parser.binaries_;
}

// From Vector
Parser::Parser(const std::vector<uint8_t>& data, const std::string& name) :
stream_{std::unique_ptr<VectorStream>(new VectorStream{data})},
binaries_{}
{
this->build();

for (Binary* binary : this->binaries_) {
binary->name(name);
}
}


std::vector<Binary*> Parser::parse(const std::vector<uint8_t>& 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_;
}



void Parser::build_fat(void) {

const fat_header *header = reinterpret_cast<const fat_header*>(
Expand Down

0 comments on commit f330fa8

Please sign in to comment.