Skip to content

Commit de40c06

Browse files
committed
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
1 parent a569cc1 commit de40c06

File tree

19 files changed

+449
-60
lines changed

19 files changed

+449
-60
lines changed

api/python/ELF/objects/pyParser.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,17 @@ void init_ELF_Parser_class(py::module& m) {
2323

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

3033

3134
m.def("parse_from_raw",
32-
static_cast<Binary* (*) (const std::vector<uint8_t>&, const std::string&)>(&Parser::parse),
35+
static_cast<Binary* (*) (const std::vector<uint8_t>&, const std::string&, DYNSYM_COUNT_METHODS)>(&Parser::parse),
3336
"Parse the given raw data and return a " RST_CLASS_REF(lief.ELF.Binary) " object",
34-
py::arg("raw"), py::arg("name") = "",
37+
py::arg("raw"), py::arg("name") = "", py::arg("dynsym_count_method") = DYNSYM_COUNT_METHODS::COUNT_AUTO,
3538
py::return_value_policy::take_ownership);
3639
}

api/python/ELF/pyELF.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
void init_ELF_module(py::module& m) {
2222
py::module LIEF_ELF_module = m.def_submodule("ELF", "Python API for ELF");
2323

24+
// Enums
25+
init_ELF_Structures_enum(LIEF_ELF_module);
26+
2427
// Objects
2528
init_ELF_Parser_class(LIEF_ELF_module);
2629
init_ELF_Binary_class(LIEF_ELF_module);
@@ -43,9 +46,6 @@ void init_ELF_module(py::module& m) {
4346
init_ELF_GnuHash_class(LIEF_ELF_module);
4447
init_ELF_Builder_class(LIEF_ELF_module);
4548

46-
// Enums
47-
init_ELF_Structures_enum(LIEF_ELF_module);
48-
4949
py::module LIEF_ELF32_module = LIEF_ELF_module.def_submodule("ELF32", "");
5050
init_ELF32_Structures(LIEF_ELF32_module);
5151

api/python/ELF/pyELFStructures.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,4 +746,12 @@ void init_ELF_Structures_enum(py::module& m) {
746746
.value(PY_ENUM(RELOC_i386::R_386_IRELATIVE))
747747
.value(PY_ENUM(RELOC_i386::R_386_NUM))
748748
.export_values();
749+
750+
751+
py::enum_<DYNSYM_COUNT_METHODS>(m, "DYNSYM_COUNT_METHODS")
752+
.value(PY_ENUM(DYNSYM_COUNT_METHODS::COUNT_AUTO))
753+
.value(PY_ENUM(DYNSYM_COUNT_METHODS::COUNT_SECTION))
754+
.value(PY_ENUM(DYNSYM_COUNT_METHODS::COUNT_HASH))
755+
.value(PY_ENUM(DYNSYM_COUNT_METHODS::COUNT_RELOCATIONS))
756+
.export_values();
749757
}

doc/sphinx/api/cpp/elf.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,6 @@ Enums
152152

153153
.. doxygenenum:: LIEF::ELF::DYNAMIC_FLAGS
154154
:project: lief
155+
156+
.. doxygenenum:: LIEF::ELF::DYNSYM_COUNT_METHODS
157+
:project: lief

doc/sphinx/api/python/elf.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,15 @@ Relocations ARM
308308
:undoc-members:
309309

310310

311+
Dynamic symbols counting
312+
~~~~~~~~~~~~~~~~~~~~~~~~
313+
314+
.. autoclass:: lief.ELF.DYNSYM_COUNT_METHODS
315+
:members:
316+
:inherited-members:
317+
:undoc-members:
318+
319+
311320

312321

313322

examples/python/elf_reader.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,11 @@ def print_relocations(binary):
189189
type = str(ELF.RELOCATION_i386(relocation.type))
190190
elif binary.header.machine_type == ELF.ARCH.ARM:
191191
type = str(ELF.RELOCATION_ARM(relocation.type))
192-
s = relocation.symbol
193-
print(f_value.format(relocation.address, type.split(".")[-1], str(relocation.symbol.name)))
192+
try:
193+
s = relocation.symbol
194+
print(f_value.format(relocation.address, type.split(".")[-1], str(relocation.symbol.name)))
195+
except lief.not_found:
196+
pass
194197

195198

196199
if len(pltgot_relocations) > 0:

include/LIEF/ELF/EnumToString.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ DLL_PUBLIC const char* to_string(RELOC_i386 e);
3636
DLL_PUBLIC const char* to_string(ELF_CLASS e);
3737
DLL_PUBLIC const char* to_string(ELF_DATA e);
3838
DLL_PUBLIC const char* to_string(OS_ABI e);
39+
DLL_PUBLIC const char* to_string(DYNSYM_COUNT_METHODS e);
3940
} // namespace ELF
4041
} // namespace LIEF
4142

include/LIEF/ELF/Parser.hpp

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,33 @@ namespace ELF {
4545
//! @brief Class which parse an ELF file and transform into a ELF::Binary
4646
class DLL_PUBLIC Parser : public LIEF::Parser {
4747
public:
48-
static Binary* parse(const std::string& file);
49-
static Binary* parse(const std::vector<uint8_t>& data, const std::string& name = "");
48+
49+
//! @brief Parse an ELF file an return a LIEF::ELF::Binary object
50+
//!
51+
//! For weird binaries (e.g. sectionless) you can choose which method use to count dynamic symbols
52+
//!
53+
//! @param[in] file Path to the ELF binary
54+
//! @param[in] count_mtd Method used to count dynamic symbols. Default: LIEF::ELF::DYNSYM_COUNT_METHODS::COUNT_AUTO
55+
//! @Return LIEF::ELF::Binary
56+
static Binary* parse(const std::string& file, DYNSYM_COUNT_METHODS count_mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO);
57+
58+
//! @brief Parse the given raw data as an ELF binary and return a LIEF::ELF::Binary object
59+
//!
60+
//! For weird binaries (e.g. sectionless) you can choose which method use to count dynamic symbols
61+
//!
62+
//! @param[in] data Raw ELF
63+
//! @param[in] name Binary name (optional)
64+
//! @param[in] count_mtd Method used to count dynamic symbols. Default: LIEF::ELF::DYNSYM_COUNT_METHODS::COUNT_AUTO
65+
//! @Return LIEF::ELF::Binary
66+
static Binary* parse(const std::vector<uint8_t>& data, const std::string& name = "", DYNSYM_COUNT_METHODS count_mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO);
5067

5168
Parser& operator=(const Parser& copy) = delete;
5269
Parser(const Parser& copy) = delete;
5370

5471
private:
5572
Parser(void);
56-
Parser(const std::string& file);
57-
Parser(const std::vector<uint8_t>& data, const std::string& name);
73+
Parser(const std::string& file, DYNSYM_COUNT_METHODS count_mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO);
74+
Parser(const std::vector<uint8_t>& data, const std::string& name, DYNSYM_COUNT_METHODS count_mtd = DYNSYM_COUNT_METHODS::COUNT_AUTO);
5875
~Parser(void);
5976

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

89106
uint64_t get_dynamic_string_table_from_sections(void) const;
90107

108+
//! @brief Return the number of dynamic symbols using the given method
109+
template<typename ELF_T>
110+
uint32_t get_numberof_dynamic_symbols(DYNSYM_COUNT_METHODS mtd) const;
111+
112+
//! @brief Count based on hash table (reliable)
113+
template<typename ELF_T>
114+
uint32_t nb_dynsym_hash(void) const;
115+
116+
//! @brief Count based on SYSV hash table
117+
template<typename ELF_T>
118+
uint32_t nb_dynsym_sysv_hash(void) const;
119+
120+
//! @brief Count based on GNU hash table
121+
template<typename ELF_T>
122+
uint32_t nb_dynsym_gnu_hash(void) const;
123+
124+
//! @brief Count based on sections (not very reliable)
125+
template<typename ELF_T>
126+
uint32_t nb_dynsym_section(void) const;
127+
128+
//! @brief Count based on PLT/GOT relocations (very reliable but not accurate)
129+
template<typename ELF_T>
130+
uint32_t nb_dynsym_relocations(void) const;
131+
91132
template<typename ELF_T>
92133
void parse_dynamic_entries(uint64_t offset, uint64_t size);
93134

94135
template<typename ELF_T>
95-
void parse_dynamic_symbols(uint64_t offset, uint64_t size);
136+
void parse_dynamic_symbols(uint64_t offset);
96137

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

159201

include/LIEF/ELF/enums.inc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,3 +950,12 @@ enum AUX_TYPE {
950950
AT_L3_CACHESHAPE = 37
951951
};
952952

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

src/ELF/EnumToString.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,19 @@ const char* to_string(OS_ABI e) {
756756
auto it = enumStrings.find(e);
757757
return it == enumStrings.end() ? "UNDEFINED" : it->second;
758758
}
759+
760+
761+
const char* to_string(DYNSYM_COUNT_METHODS e) {
762+
const std::map<DYNSYM_COUNT_METHODS, const char*> enumStrings {
763+
{ DYNSYM_COUNT_METHODS::COUNT_AUTO, "AUTO"},
764+
{ DYNSYM_COUNT_METHODS::COUNT_SECTION, "SECTION"},
765+
{ DYNSYM_COUNT_METHODS::COUNT_HASH, "HASH"},
766+
{ DYNSYM_COUNT_METHODS::COUNT_RELOCATIONS, "RELOCATIONS"},
767+
};
768+
769+
auto it = enumStrings.find(e);
770+
return it == enumStrings.end() ? "UNDEFINED" : it->second;
771+
}
759772
} // namespace ELF
760773
} // namespace LIEF
761774

0 commit comments

Comments
 (0)