Skip to content
Permalink
Browse files
Fully handle section-less ELF binaries
  * Fix #25
  * ELF `tiny` binaries are now handled (see #7)
  * Computation of dynamic symbols can be done with differents methods:
    hash table, sections and relocations. (See LIEF::ELF::DYNSYM_COUNT_METHODS)
  * ELF parser can be configured to use one of the DYNSYM_COUNT_METHODS
  * Improve tests
  • Loading branch information
romainthomas committed May 6, 2017
1 parent a569cc1 commit de40c06
Show file tree
Hide file tree
Showing 19 changed files with 449 additions and 60 deletions.
@@ -23,14 +23,17 @@ void init_ELF_Parser_class(py::module& m) {

// Parser (Parser)
m.def("parse",
static_cast<Binary* (*) (const std::string&)>(&Parser::parse),
"Parse the given binary and return a " RST_CLASS_REF(lief.ELF.Binary) " object",
static_cast<Binary* (*) (const std::string&, DYNSYM_COUNT_METHODS)>(&Parser::parse),
"Parse the given binary and return a " RST_CLASS_REF(lief.ELF.Binary) " object\n\n"
"For *weird* binaries (e.g sectionless) you can choose which method use to count dynamic symbols "
" (" RST_CLASS_REF(lief.ELF.DYNSYM_COUNT_METHODS) ")",
"filename"_a, py::arg("dynsym_count_method") = DYNSYM_COUNT_METHODS::COUNT_AUTO,
py::return_value_policy::take_ownership);


m.def("parse_from_raw",
static_cast<Binary* (*) (const std::vector<uint8_t>&, const std::string&)>(&Parser::parse),
static_cast<Binary* (*) (const std::vector<uint8_t>&, const std::string&, DYNSYM_COUNT_METHODS)>(&Parser::parse),
"Parse the given raw data and return a " RST_CLASS_REF(lief.ELF.Binary) " object",
py::arg("raw"), py::arg("name") = "",
py::arg("raw"), py::arg("name") = "", py::arg("dynsym_count_method") = DYNSYM_COUNT_METHODS::COUNT_AUTO,
py::return_value_policy::take_ownership);
}
@@ -21,6 +21,9 @@
void init_ELF_module(py::module& m) {
py::module LIEF_ELF_module = m.def_submodule("ELF", "Python API for ELF");

// Enums
init_ELF_Structures_enum(LIEF_ELF_module);

// Objects
init_ELF_Parser_class(LIEF_ELF_module);
init_ELF_Binary_class(LIEF_ELF_module);
@@ -43,9 +46,6 @@ void init_ELF_module(py::module& m) {
init_ELF_GnuHash_class(LIEF_ELF_module);
init_ELF_Builder_class(LIEF_ELF_module);

// Enums
init_ELF_Structures_enum(LIEF_ELF_module);

py::module LIEF_ELF32_module = LIEF_ELF_module.def_submodule("ELF32", "");
init_ELF32_Structures(LIEF_ELF32_module);

@@ -746,4 +746,12 @@ void init_ELF_Structures_enum(py::module& m) {
.value(PY_ENUM(RELOC_i386::R_386_IRELATIVE))
.value(PY_ENUM(RELOC_i386::R_386_NUM))
.export_values();


py::enum_<DYNSYM_COUNT_METHODS>(m, "DYNSYM_COUNT_METHODS")
.value(PY_ENUM(DYNSYM_COUNT_METHODS::COUNT_AUTO))
.value(PY_ENUM(DYNSYM_COUNT_METHODS::COUNT_SECTION))
.value(PY_ENUM(DYNSYM_COUNT_METHODS::COUNT_HASH))
.value(PY_ENUM(DYNSYM_COUNT_METHODS::COUNT_RELOCATIONS))
.export_values();
}
@@ -152,3 +152,6 @@ Enums

.. doxygenenum:: LIEF::ELF::DYNAMIC_FLAGS
:project: lief

.. doxygenenum:: LIEF::ELF::DYNSYM_COUNT_METHODS
:project: lief
@@ -308,6 +308,15 @@ Relocations ARM
:undoc-members:


Dynamic symbols counting
~~~~~~~~~~~~~~~~~~~~~~~~

.. autoclass:: lief.ELF.DYNSYM_COUNT_METHODS
:members:
:inherited-members:
:undoc-members:





@@ -189,8 +189,11 @@ def print_relocations(binary):
type = str(ELF.RELOCATION_i386(relocation.type))
elif binary.header.machine_type == ELF.ARCH.ARM:
type = str(ELF.RELOCATION_ARM(relocation.type))
s = relocation.symbol
print(f_value.format(relocation.address, type.split(".")[-1], str(relocation.symbol.name)))
try:
s = relocation.symbol
print(f_value.format(relocation.address, type.split(".")[-1], str(relocation.symbol.name)))
except lief.not_found:
pass


if len(pltgot_relocations) > 0:
@@ -36,6 +36,7 @@ DLL_PUBLIC const char* to_string(RELOC_i386 e);
DLL_PUBLIC const char* to_string(ELF_CLASS e);
DLL_PUBLIC const char* to_string(ELF_DATA e);
DLL_PUBLIC const char* to_string(OS_ABI e);
DLL_PUBLIC const char* to_string(DYNSYM_COUNT_METHODS e);
} // namespace ELF
} // namespace LIEF

@@ -45,16 +45,33 @@ namespace ELF {
//! @brief Class which parse an ELF file and transform into a ELF::Binary
class DLL_PUBLIC Parser : public LIEF::Parser {
public:
static Binary* parse(const std::string& file);
static Binary* parse(const std::vector<uint8_t>& data, const std::string& name = "");

//! @brief Parse an ELF file an return a LIEF::ELF::Binary object
//!
//! For weird binaries (e.g. sectionless) you can choose which method use to count dynamic symbols
//!
//! @param[in] file Path to the ELF binary
//! @param[in] count_mtd Method used to count dynamic symbols. Default: LIEF::ELF::DYNSYM_COUNT_METHODS::COUNT_AUTO
//! @Return LIEF::ELF::Binary
static Binary* parse(const std::string& file, DYNSYM_COUNT_METHODS count_mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO);

//! @brief Parse the given raw data as an ELF binary and return a LIEF::ELF::Binary object
//!
//! For weird binaries (e.g. sectionless) you can choose which method use to count dynamic symbols
//!
//! @param[in] data Raw ELF
//! @param[in] name Binary name (optional)
//! @param[in] count_mtd Method used to count dynamic symbols. Default: LIEF::ELF::DYNSYM_COUNT_METHODS::COUNT_AUTO
//! @Return LIEF::ELF::Binary
static Binary* parse(const std::vector<uint8_t>& data, const std::string& name = "", DYNSYM_COUNT_METHODS count_mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO);

Parser& operator=(const Parser& copy) = delete;
Parser(const Parser& copy) = delete;

private:
Parser(void);
Parser(const std::string& file);
Parser(const std::vector<uint8_t>& data, const std::string& name);
Parser(const std::string& file, DYNSYM_COUNT_METHODS count_mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO);
Parser(const std::vector<uint8_t>& data, const std::string& name, DYNSYM_COUNT_METHODS count_mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO);
~Parser(void);

void init(const std::string& name = "");
@@ -88,11 +105,35 @@ class DLL_PUBLIC Parser : public LIEF::Parser {

uint64_t get_dynamic_string_table_from_sections(void) const;

//! @brief Return the number of dynamic symbols using the given method
template<typename ELF_T>
uint32_t get_numberof_dynamic_symbols(DYNSYM_COUNT_METHODS mtd) const;

//! @brief Count based on hash table (reliable)
template<typename ELF_T>
uint32_t nb_dynsym_hash(void) const;

//! @brief Count based on SYSV hash table
template<typename ELF_T>
uint32_t nb_dynsym_sysv_hash(void) const;

//! @brief Count based on GNU hash table
template<typename ELF_T>
uint32_t nb_dynsym_gnu_hash(void) const;

//! @brief Count based on sections (not very reliable)
template<typename ELF_T>
uint32_t nb_dynsym_section(void) const;

//! @brief Count based on PLT/GOT relocations (very reliable but not accurate)
template<typename ELF_T>
uint32_t nb_dynsym_relocations(void) const;

template<typename ELF_T>
void parse_dynamic_entries(uint64_t offset, uint64_t size);

template<typename ELF_T>
void parse_dynamic_symbols(uint64_t offset, uint64_t size);
void parse_dynamic_symbols(uint64_t offset);

//! @brief Parse static Symbol
//!
@@ -154,6 +195,7 @@ class DLL_PUBLIC Parser : public LIEF::Parser {
std::unique_ptr<VectorStream> stream_;
Binary* binary_;
uint32_t type_;
DYNSYM_COUNT_METHODS count_mtd_;
};


@@ -950,3 +950,12 @@ enum AUX_TYPE {
AT_L3_CACHESHAPE = 37
};

/** Methods that can be used by the LIEF::ELF::Parser
to count the number of dynamic symbols */
enum DYNSYM_COUNT_METHODS {
COUNT_AUTO = 0, /**< Automatic detection */
COUNT_SECTION = 1, /**< Count based on sections (not very reliable) */
COUNT_HASH = 2, /**< Count based on hash table (reliable) */
COUNT_RELOCATIONS = 3, /**< Count based on PLT/GOT relocations (very reliable but not accurate) */
};

@@ -756,6 +756,19 @@ const char* to_string(OS_ABI e) {
auto it = enumStrings.find(e);
return it == enumStrings.end() ? "UNDEFINED" : it->second;
}


const char* to_string(DYNSYM_COUNT_METHODS e) {
const std::map<DYNSYM_COUNT_METHODS, const char*> enumStrings {
{ DYNSYM_COUNT_METHODS::COUNT_AUTO, "AUTO"},
{ DYNSYM_COUNT_METHODS::COUNT_SECTION, "SECTION"},
{ DYNSYM_COUNT_METHODS::COUNT_HASH, "HASH"},
{ DYNSYM_COUNT_METHODS::COUNT_RELOCATIONS, "RELOCATIONS"},
};

auto it = enumStrings.find(e);
return it == enumStrings.end() ? "UNDEFINED" : it->second;
}
} // namespace ELF
} // namespace LIEF

@@ -40,14 +40,20 @@ namespace ELF {
Parser::~Parser(void) = default;
Parser::Parser(void) = default;

Parser::Parser(const std::vector<uint8_t>& data, const std::string& name) :
stream_{std::unique_ptr<VectorStream>(new VectorStream{data})}
Parser::Parser(const std::vector<uint8_t>& data, const std::string& name, DYNSYM_COUNT_METHODS count_mtd) :
stream_{std::unique_ptr<VectorStream>(new VectorStream{data})},
binary_{nullptr},
type_{0},
count_mtd_{count_mtd}
{
this->init(name);
}

Parser::Parser(const std::string& file) :
LIEF::Parser{file}
Parser::Parser(const std::string& file, DYNSYM_COUNT_METHODS count_mtd) :
LIEF::Parser{file},
binary_{nullptr},
type_{0},
count_mtd_{count_mtd}
{
if (not is_elf(file)) {
throw LIEF::bad_format("'" + file + "' is not an ELF");
@@ -90,13 +96,16 @@ void Parser::init(const std::string& name) {
}
}

Binary* Parser::parse(const std::string& filename) {
Parser parser{filename};
Binary* Parser::parse(const std::string& filename, DYNSYM_COUNT_METHODS count_mtd) {
Parser parser{filename, count_mtd};
return parser.binary_;
}

Binary* Parser::parse(const std::vector<uint8_t>& data, const std::string& name) {
Parser parser{data, name};
Binary* Parser::parse(
const std::vector<uint8_t>& data,
const std::string& name,
DYNSYM_COUNT_METHODS count_mtd) {
Parser parser{data, name, count_mtd};
return parser.binary_;
}

0 comments on commit de40c06

Please sign in to comment.