Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add a *purpose* property to ELF relocations
Adding such property enables to store plt/got and dynamic relocations
in a same container. (related to #51)
  • Loading branch information
romainthomas committed Jul 11, 2017
1 parent 44d5df3 commit b7b0bde
Show file tree
Hide file tree
Showing 18 changed files with 184 additions and 86 deletions.
6 changes: 3 additions & 3 deletions api/python/ELF/objects/pyBinary.cpp
Expand Up @@ -30,7 +30,7 @@ void init_ELF_Binary_class(py::module& m) {

// Binary object
py::class_<Binary, LIEF::Binary>(m, "Binary", "ELF binary representation")
.def(py::init<const std::string &, ELF_CLASS>())
.def(py::init<const std::string&, ELF_CLASS>())

.def_property_readonly("type",
&Binary::type,
Expand Down Expand Up @@ -77,12 +77,12 @@ void init_ELF_Binary_class(py::module& m) {
py::return_value_policy::reference_internal)

.def_property_readonly("dynamic_relocations",
static_cast<no_const_getter<it_relocations>>(&Binary::get_dynamic_relocations),
static_cast<no_const_getter<it_dynamic_relocations>>(&Binary::get_dynamic_relocations),
"Return an iterator to PLT/GOT " RST_CLASS_REF(lief.ELF.Relocation) "",
py::return_value_policy::reference_internal)

.def_property_readonly("pltgot_relocations",
static_cast<no_const_getter<it_relocations>>(&Binary::get_pltgot_relocations),
static_cast<no_const_getter<it_pltgot_relocations>>(&Binary::get_pltgot_relocations),
"Return an iterator to dynamics " RST_CLASS_REF(lief.ELF.Relocation) "",
py::return_value_policy::reference_internal)

Expand Down
5 changes: 5 additions & 0 deletions api/python/ELF/objects/pyRelocation.cpp
Expand Up @@ -40,6 +40,11 @@ void init_ELF_Relocation_class(py::module& m) {
static_cast<setter_t<int64_t>>(&Relocation::addend),
"Additional value")

.def_property("purpose",
static_cast<getter_t<RELOCATION_PURPOSES>>(&Relocation::purpose),
static_cast<setter_t<RELOCATION_PURPOSES>>(&Relocation::purpose),
"Purpose (" RST_CLASS_REF(lief.ELF.RELOCATION_PURPOSES) ") of the relocation")

.def_property("type",
static_cast<getter_t<uint32_t>>(&Relocation::type),
static_cast<setter_t<uint32_t>>(&Relocation::type),
Expand Down
8 changes: 8 additions & 0 deletions api/python/ELF/pyELFStructures.cpp
Expand Up @@ -905,4 +905,12 @@ void init_ELF_Structures_enum(py::module& m) {
.value(PY_ENUM(NOTE_ABIS::ELF_NOTE_OS_NETBSD))
.value(PY_ENUM(NOTE_ABIS::ELF_NOTE_OS_SYLLABLE))
.export_values();


py::enum_<RELOCATION_PURPOSES>(m, "RELOCATION_PURPOSES")
.value(PY_ENUM(RELOCATION_PURPOSES::RELOC_PURPOSE_NONE))
.value(PY_ENUM(RELOCATION_PURPOSES::RELOC_PURPOSE_PLTGOT))
.value(PY_ENUM(RELOCATION_PURPOSES::RELOC_PURPOSE_DYNAMIC))
.value(PY_ENUM(RELOCATION_PURPOSES::RELOC_PURPOSE_OBJECT))
.export_values();
}
2 changes: 1 addition & 1 deletion api/python/pyIterators.cpp
Expand Up @@ -31,7 +31,7 @@ void init_LIEF_iterators(py::module& m) {
init_ref_iterator<LIEF::ELF::it_segments>(m);
init_ref_iterator<LIEF::ELF::it_dynamic_entries>(m);
init_ref_iterator<LIEF::ELF::it_symbols>(m);
init_ref_iterator<LIEF::ELF::it_relocations>(m);
init_ref_iterator<LIEF::filter_iterator<LIEF::ELF::relocations_t>>(m);
init_ref_iterator<LIEF::ELF::it_symbols_version>(m);
init_ref_iterator<LIEF::ELF::it_symbols_version_requirement>(m);
init_ref_iterator<LIEF::ELF::it_symbols_version_definition>(m);
Expand Down
3 changes: 3 additions & 0 deletions doc/sphinx/api/cpp/elf.rst
Expand Up @@ -211,3 +211,6 @@ Enums

.. doxygenenum:: LIEF::ELF::NOTE_ABIS
:project: lief

.. doxygenenum:: LIEF::ELF::RELOCATION_PURPOSES
:project: lief
9 changes: 9 additions & 0 deletions doc/sphinx/api/python/elf.rst
Expand Up @@ -385,6 +385,15 @@ Note ABIs
:inherited-members:
:undoc-members:

Relocation purposes
~~~~~~~~~~~~~~~~~~~

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





Expand Down
14 changes: 5 additions & 9 deletions include/LIEF/ELF/Binary.hpp
Expand Up @@ -124,12 +124,12 @@ class DLL_PUBLIC Binary : public LIEF::Binary {
it_const_symbols_version_requirement get_symbols_version_requirement(void) const;

//! @brief Return dynamic relocations
it_relocations get_dynamic_relocations(void);
it_const_relocations get_dynamic_relocations(void) const;
it_dynamic_relocations get_dynamic_relocations(void);
it_const_dynamic_relocations get_dynamic_relocations(void) const;

//! @brief Return `plt.got` relocations
it_relocations get_pltgot_relocations(void);
it_const_relocations get_pltgot_relocations(void) const;
it_pltgot_relocations get_pltgot_relocations(void);
it_const_pltgot_relocations get_pltgot_relocations(void) const;

//! @brief ``true`` if GNU hash is used
//!
Expand Down Expand Up @@ -411,11 +411,7 @@ class DLL_PUBLIC Binary : public LIEF::Binary {
//! A list of static symbols
symbols_t static_symbols_;

//! The binary's dynamic Relocations if any
relocations_t dynamic_relocations_;

//! .rela.plt
relocations_t pltgot_relocations_;
relocations_t relocations_;

//! .gnu.version
symbols_version_t symbol_version_table_;
Expand Down
1 change: 1 addition & 0 deletions include/LIEF/ELF/EnumToString.hpp
Expand Up @@ -40,6 +40,7 @@ DLL_PUBLIC const char* to_string(OS_ABI e);
DLL_PUBLIC const char* to_string(DYNSYM_COUNT_METHODS e);
DLL_PUBLIC const char* to_string(NOTE_TYPES e);
DLL_PUBLIC const char* to_string(NOTE_ABIS e);
DLL_PUBLIC const char* to_string(RELOCATION_PURPOSES e);
} // namespace ELF
} // namespace LIEF

Expand Down
15 changes: 9 additions & 6 deletions include/LIEF/ELF/Relocation.hpp
Expand Up @@ -53,6 +53,7 @@ class DLL_PUBLIC Relocation : public Visitable {
bool is_rela(void) const;
bool is_rel(void) const;
ARCH architecture(void) const;
RELOCATION_PURPOSES purpose(void) const;

//! @brief Return the **bit** size of the value to patch
uint32_t size(void) const;
Expand All @@ -64,6 +65,7 @@ class DLL_PUBLIC Relocation : public Visitable {
void address(uint64_t address);
void addend(int64_t addend);
void type(uint32_t type);
void purpose(RELOCATION_PURPOSES purpose);

virtual void accept(Visitor& visitor) const override;

Expand All @@ -73,12 +75,13 @@ class DLL_PUBLIC Relocation : public Visitable {
DLL_PUBLIC friend std::ostream& operator<<(std::ostream& os, const Relocation& entry);

private:
uint64_t address_;
uint32_t type_;
int64_t addend_;
bool isRela_;
Symbol* symbol_;
ARCH architecture_;
uint64_t address_;
uint32_t type_;
int64_t addend_;
bool isRela_;
Symbol* symbol_;
ARCH architecture_;
RELOCATION_PURPOSES purpose_;
};

}
Expand Down
7 changes: 7 additions & 0 deletions include/LIEF/ELF/enums.inc
Expand Up @@ -976,3 +976,10 @@ enum NOTE_ABIS {
ELF_NOTE_OS_SYLLABLE = 5,
};

enum RELOCATION_PURPOSES {
RELOC_PURPOSE_NONE = 0,
RELOC_PURPOSE_PLTGOT = 1,
RELOC_PURPOSE_DYNAMIC = 2,
RELOC_PURPOSE_OBJECT = 3,
};

8 changes: 6 additions & 2 deletions include/LIEF/ELF/type_traits.hpp
Expand Up @@ -50,8 +50,12 @@ using it_symbols = ref_iterator<symbols_t&>;
using it_const_symbols = const_ref_iterator<const symbols_t&>;

using relocations_t = std::vector<Relocation*>;
using it_relocations = ref_iterator<relocations_t&>;
using it_const_relocations = const_ref_iterator<const relocations_t&>;

using it_pltgot_relocations = filter_iterator<relocations_t>;
using it_const_pltgot_relocations = const_filter_iterator<const relocations_t>;

using it_dynamic_relocations = filter_iterator<relocations_t>;
using it_const_dynamic_relocations = const_filter_iterator<const relocations_t>;

using symbols_version_t = std::vector<SymbolVersion*>;
using it_symbols_version = ref_iterator<symbols_version_t&>;
Expand Down
81 changes: 51 additions & 30 deletions src/ELF/Binary.cpp
Expand Up @@ -319,28 +319,35 @@ void Binary::remove_dynamic_symbol(Symbol* symbol) {

// Update relocations
auto&& it_relocation = std::find_if(
std::begin(this->pltgot_relocations_),
std::end(this->pltgot_relocations_),
std::begin(this->relocations_),
std::end(this->relocations_),
[&symbol] (const Relocation* relocation) {
return relocation != nullptr and relocation->has_symbol() and relocation->symbol() == *symbol;
return relocation != nullptr and
relocation->purpose() == RELOCATION_PURPOSES::RELOC_PURPOSE_PLTGOT and
relocation->has_symbol() and
relocation->symbol() == *symbol;
});

if (it_relocation != std::end(this->pltgot_relocations_)) {
if (it_relocation != std::end(this->relocations_)) {
delete *it_relocation;
this->pltgot_relocations_.erase(it_relocation);
this->relocations_.erase(it_relocation);
} else {
}


it_relocation = std::find_if(
std::begin(this->dynamic_relocations_),
std::end(this->dynamic_relocations_),
std::begin(this->relocations_),
std::end(this->relocations_),
[&symbol] (const Relocation* relocation) {
return relocation != nullptr and relocation->has_symbol() and relocation->symbol() == *symbol;
return relocation != nullptr and
relocation->purpose() == RELOCATION_PURPOSES::RELOC_PURPOSE_DYNAMIC and
relocation->has_symbol() and
relocation->symbol() == *symbol;
});
if (it_relocation != std::end(this->dynamic_relocations_)) {

if (it_relocation != std::end(this->relocations_)) {
delete *it_relocation;
this->dynamic_relocations_.erase(it_relocation);
this->relocations_.erase(it_relocation);
}

// Update symbol versions
Expand Down Expand Up @@ -368,22 +375,40 @@ void Binary::remove_dynamic_symbol(Symbol* symbol) {
// Dynamics
// --------

it_relocations Binary::get_dynamic_relocations(void) {
return it_relocations{std::ref(this->dynamic_relocations_)};
it_dynamic_relocations Binary::get_dynamic_relocations(void) {
return filter_iterator<relocations_t>{std::ref(this->relocations_),
[] (const Relocation* reloc) {
return reloc->purpose() == RELOCATION_PURPOSES::RELOC_PURPOSE_DYNAMIC;
}
};

}

it_const_relocations Binary::get_dynamic_relocations(void) const {
return it_const_relocations{std::cref(this->dynamic_relocations_)};
it_const_dynamic_relocations Binary::get_dynamic_relocations(void) const {
return const_filter_iterator<const relocations_t>{std::cref(this->relocations_),
[] (const Relocation* reloc) {
return reloc->purpose() == RELOCATION_PURPOSES::RELOC_PURPOSE_DYNAMIC;
}
};

}

// plt/got
// -------
it_relocations Binary::get_pltgot_relocations(void) {
return it_relocations{std::ref(this->pltgot_relocations_)};
it_pltgot_relocations Binary::get_pltgot_relocations(void) {
return filter_iterator<relocations_t>{std::ref(this->relocations_),
[] (const Relocation* reloc) {
return reloc->purpose() == RELOCATION_PURPOSES::RELOC_PURPOSE_PLTGOT;
}
};
}

it_const_relocations Binary::get_pltgot_relocations(void) const {
return it_const_relocations{std::cref(this->pltgot_relocations_)};
it_const_pltgot_relocations Binary::get_pltgot_relocations(void) const {
return const_filter_iterator<const relocations_t>{std::cref(this->relocations_),
[] (const Relocation* reloc) {
return reloc->purpose() == RELOCATION_PURPOSES::RELOC_PURPOSE_PLTGOT;
}
};
}

LIEF::symbols_t Binary::get_abstract_symbols(void) {
Expand Down Expand Up @@ -788,18 +813,19 @@ void Binary::patch_address(uint64_t address, uint64_t patch_value, size_t size)


void Binary::patch_pltgot(const Symbol& symbol, uint64_t address) {
it_pltgot_relocations pltgot_relocations = this->get_pltgot_relocations();
auto&& it_relocation = std::find_if(
std::begin(this->pltgot_relocations_),
std::end(this->pltgot_relocations_),
[&symbol] (const Relocation* relocation) {
return relocation->has_symbol() and relocation->symbol() == symbol;
std::begin(pltgot_relocations),
std::end(pltgot_relocations),
[&symbol] (const Relocation& relocation) {
return relocation.has_symbol() and relocation.symbol() == symbol;
});

if (it_relocation == std::end(this->pltgot_relocations_)) {
if (it_relocation == std::end(pltgot_relocations)) {
throw not_found("Unable to find the relocation associated with symbol '" + symbol.name() + "'");
}

uint64_t got_address = (*it_relocation)->address();
uint64_t got_address = (*it_relocation).address();
this->patch_address(got_address, address, sizeof(uint64_t));
//(*it_relocation)->address(0);
//delete *it_relocation;
Expand Down Expand Up @@ -1641,12 +1667,7 @@ std::ostream& Binary::print(std::ostream& os) const {

Binary::~Binary(void) {

for (Relocation* relocation : this->pltgot_relocations_) {
delete relocation;
}


for (Relocation* relocation : this->dynamic_relocations_) {
for (Relocation* relocation : this->relocations_) {
delete relocation;
}

Expand Down
37 changes: 21 additions & 16 deletions src/ELF/Builder.tcc
Expand Up @@ -50,11 +50,11 @@ void Builder::build(void) {
}
}

if (this->binary_->dynamic_relocations_.size() > 0) {
if (this->binary_->get_dynamic_relocations().size() > 0) {
this->build_dynamic_relocations<ELF_T>();
}

if (this->binary_->pltgot_relocations_.size() > 0) {
if (this->binary_->get_pltgot_relocations().size() > 0) {
this->build_pltgot_relocations<ELF_T>();
}

Expand Down Expand Up @@ -831,12 +831,14 @@ void Builder::build_dynamic_relocations(void) {
using Elf_Rel = typename ELF_T::Elf_Rel;
LOG(DEBUG) << "[+] Building dynamic relocations";

bool isRela = this->binary_->dynamic_relocations_[0]->is_rela();
it_dynamic_relocations dynamic_relocations = this->binary_->get_dynamic_relocations();

bool isRela = dynamic_relocations[0].is_rela();
if (not std::all_of(
std::begin(this->binary_->dynamic_relocations_),
std::end(this->binary_->dynamic_relocations_),
[isRela] (const Relocation* relocation) {
return relocation != nullptr and relocation->is_rela() == isRela;
std::begin(dynamic_relocations),
std::end(dynamic_relocations),
[isRela] (const Relocation& relocation) {
return relocation.is_rela() == isRela;
})) {
throw LIEF::type_error("Relocation are not of the same type");
}
Expand Down Expand Up @@ -889,9 +891,9 @@ void Builder::build_dynamic_relocations(void) {
Section& relocation_section = this->binary_->section_from_virtual_address((*it_dyn_relocation)->value());

if (isRela) {
(*it_dyn_relocation_size)->value(this->binary_->dynamic_relocations_.size() * sizeof(Elf_Rela));
(*it_dyn_relocation_size)->value(dynamic_relocations.size() * sizeof(Elf_Rela));
} else {
(*it_dyn_relocation_size)->value(this->binary_->dynamic_relocations_.size() * sizeof(Elf_Rel));
(*it_dyn_relocation_size)->value(dynamic_relocations.size() * sizeof(Elf_Rel));
}

std::vector<uint8_t> content;
Expand Down Expand Up @@ -961,13 +963,16 @@ void Builder::build_pltgot_relocations(void) {
using Elf_Rel = typename ELF_T::Elf_Rel;

LOG(DEBUG) << "[+] Building .plt.got relocations";
bool isRela = this->binary_->pltgot_relocations_[0]->is_rela();

it_pltgot_relocations pltgot_relocations = this->binary_->get_pltgot_relocations();

bool isRela = pltgot_relocations[0].is_rela();

if (not std::all_of(
std::begin(this->binary_->pltgot_relocations_),
std::end(this->binary_->pltgot_relocations_),
[isRela] (const Relocation* relocation) {
return relocation != nullptr and relocation->is_rela() == isRela;
std::begin(pltgot_relocations),
std::end(pltgot_relocations),
[isRela] (const Relocation& relocation) {
return relocation.is_rela() == isRela;
})) {
throw LIEF::type_error("Relocation are not of the same type");
}
Expand Down Expand Up @@ -999,9 +1004,9 @@ void Builder::build_pltgot_relocations(void) {

Section& relocation_section = this->binary_->section_from_virtual_address((*it_dyn_relocation)->value());
if (isRela) {
(*it_dyn_relocation_size)->value(this->binary_->pltgot_relocations_.size() * sizeof(Elf_Rela));
(*it_dyn_relocation_size)->value(pltgot_relocations.size() * sizeof(Elf_Rela));
} else {
(*it_dyn_relocation_size)->value(this->binary_->pltgot_relocations_.size() * sizeof(Elf_Rel));
(*it_dyn_relocation_size)->value(pltgot_relocations.size() * sizeof(Elf_Rel));
}

std::vector<uint8_t> content; // Section's content
Expand Down

0 comments on commit b7b0bde

Please sign in to comment.