Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Parse relocations in ELF object file (Resolve #51)
New API:
  * lief.ELF.Binary.object_relocations - Object relocations
  * lief.ELF.Binary.relocations - All relocations(plt/got, dynamic, obj)
  • Loading branch information
romainthomas committed Jul 11, 2017
1 parent b7b0bde commit 483b8dc
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 53 deletions.
14 changes: 12 additions & 2 deletions api/python/ELF/objects/pyBinary.cpp
Expand Up @@ -78,12 +78,22 @@ void init_ELF_Binary_class(py::module& m) {

.def_property_readonly("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) "",
"Return an iterator over 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_pltgot_relocations>>(&Binary::get_pltgot_relocations),
"Return an iterator to dynamics " RST_CLASS_REF(lief.ELF.Relocation) "",
"Return an iterator over dynamics " RST_CLASS_REF(lief.ELF.Relocation) "",
py::return_value_policy::reference_internal)

.def_property_readonly("object_relocations",
static_cast<no_const_getter<it_object_relocations>>(&Binary::get_object_relocations),
"Return an iterator over object " RST_CLASS_REF(lief.ELF.Relocation) "",
py::return_value_policy::reference_internal)

.def_property_readonly("relocations",
static_cast<no_const_getter<it_relocations>>(&Binary::get_relocations),
"Return an iterator over **all** " RST_CLASS_REF(lief.ELF.Relocation) "s",
py::return_value_policy::reference_internal)

.def_property_readonly("symbols_version",
Expand Down
1 change: 1 addition & 0 deletions api/python/pyIterators.cpp
Expand Up @@ -33,6 +33,7 @@ void init_LIEF_iterators(py::module& m) {
init_ref_iterator<LIEF::ELF::it_symbols>(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_relocations>(m);
init_ref_iterator<LIEF::ELF::it_symbols_version_requirement>(m);
init_ref_iterator<LIEF::ELF::it_symbols_version_definition>(m);
init_ref_iterator<LIEF::filter_iterator<LIEF::ELF::symbols_t>>(m);
Expand Down
90 changes: 39 additions & 51 deletions examples/python/elf_reader.py
Expand Up @@ -199,62 +199,51 @@ def print_symbols(binary):
str(symbol_version)))

@exceptions_handler(Exception)
def print_relocations(binary):
dynamicrelocations = binary.dynamic_relocations
pltgot_relocations = binary.pltgot_relocations
def print_relocations(binary, relocations):
f_title = "|{:<10} | {:<10}| {:<8}| {:<15}| {:<30} |"
f_value = "|0x{:<8x} | {:<10}| {:<8d}| {:<15}| {:<30} |"

## Dynamic relocations ##
if len(dynamicrelocations) > 0:
print("== Dynamic Relocations ==\n")
f_title = "|{:<10} | {:<10}| {:<8}| {:<30} |"
f_value = "|0x{:<8x} | {:<10}| {:<8d}| {:<30} |"
print(f_title.format("Address", "Type", "Size", "Purpose", "Symbol"))

print(f_title.format("Address", "Type", "Size", "Symbol"))
for relocation in relocations:
type = str(relocation.type)
if binary.header.machine_type == ELF.ARCH.x86_64:
type = str(ELF.RELOCATION_X86_64(relocation.type))
elif binary.header.machine_type == ELF.ARCH.i386:
type = str(ELF.RELOCATION_i386(relocation.type))
elif binary.header.machine_type == ELF.ARCH.ARM:
type = str(ELF.RELOCATION_ARM(relocation.type))
elif binary.header.machine_type == ELF.ARCH.AARCH64:
type = str(ELF.RELOCATION_AARCH64(relocation.type))

for relocation in dynamicrelocations:
type = str(relocation.type)
if binary.header.machine_type == ELF.ARCH.x86_64:
type = str(ELF.RELOCATION_X86_64(relocation.type))
elif binary.header.machine_type == ELF.ARCH.i386:
type = str(ELF.RELOCATION_i386(relocation.type))
elif binary.header.machine_type == ELF.ARCH.ARM:
type = str(ELF.RELOCATION_ARM(relocation.type))
elif binary.header.machine_type == ELF.ARCH.AARCH64:
type = str(ELF.RELOCATION_AARCH64(relocation.type))
symbol_name = str(relocation.symbol.name) if relocation.has_symbol else ""

symbol_name = str(relocation.symbol.name) if relocation.has_symbol else ""
print(f_value.format(
relocation.address,
type.split(".")[-1],
relocation.size,
str(relocation.purpose).split(".")[-1],
symbol_name))

print(f_value.format(
relocation.address,
type.split(".")[-1],
relocation.size,
symbol_name))

@exceptions_handler(Exception)
def print_all_relocations(binary):
dynamicrelocations = binary.dynamic_relocations
pltgot_relocations = binary.pltgot_relocations
object_relocations = binary.object_relocations

if len(dynamicrelocations) > 0:
print("== Dynamic Relocations ==\n")
print_relocations(binary, dynamicrelocations)


if len(pltgot_relocations) > 0:
print("== PLT/GOT Relocations ==\n")
f_title = "|{:<10} | {:<10}| {:<8}| {:<30} |"
f_value = "|0x{:<8x} | {:<10}| {:<8d}| {:<30} |"

print(f_title.format("Address", "Type", "Size", "Symbol"))

for relocation in pltgot_relocations:
type = str(relocation.type)
if binary.header.machine_type == ELF.ARCH.x86_64:
type = str(ELF.RELOCATION_X86_64(relocation.type))
elif binary.header.machine_type == ELF.ARCH.i386:
type = str(ELF.RELOCATION_i386(relocation.type))
elif binary.header.machine_type == ELF.ARCH.ARM:
type = str(ELF.RELOCATION_ARM(relocation.type))
elif binary.header.machine_type == ELF.ARCH.AARCH64:
type = str(ELF.RELOCATION_AARCH64(relocation.type))

symbol_name = str(relocation.symbol.name) if relocation.has_symbol else ""
print(f_value.format(
relocation.address,
type.split(".")[-1],
relocation.size,
symbol_name))
print_relocations(binary, pltgot_relocations)

if len(object_relocations) > 0:
print("== Object Relocations ==\n")
print_relocations(binary, object_relocations)

@exceptions_handler(Exception)
def print_exported_symbols(binary):
Expand Down Expand Up @@ -444,7 +433,6 @@ def main():
action='store_true', dest='show_notes',
help='Display Notes')


options, args = optparser.parse_args()

if options.help or len(args) == 0:
Expand Down Expand Up @@ -480,18 +468,18 @@ def main():
print_symbols(binary)

if options.show_relocs or options.show_all:
print_relocations(binary)
print_all_relocations(binary)

if options.show_imported_symbols or options.show_all:
print_imported_symbols(binary)

if options.show_exported_symbols or options.show_all:
print_exported_symbols(binary)

if options.show_gnu_hash or options.show_all:
if (options.show_gnu_hash or options.show_all) and binary.use_gnu_hash:
print_gnu_hash(binary)

if options.show_sysv_hash or options.show_all:
if (options.show_sysv_hash or options.show_all) and binary.use_sysv_hash:
print_sysv_hash(binary)

if options.show_notes or options.show_all:
Expand Down
8 changes: 8 additions & 0 deletions include/LIEF/ELF/Binary.hpp
Expand Up @@ -131,6 +131,14 @@ class DLL_PUBLIC Binary : public LIEF::Binary {
it_pltgot_relocations get_pltgot_relocations(void);
it_const_pltgot_relocations get_pltgot_relocations(void) const;

//! @brief Return relocations used in an object file (``*.o``)
it_object_relocations get_object_relocations(void);
it_const_object_relocations get_object_relocations(void) const;

//! @brief Return **all** relocations present in the binary
it_relocations get_relocations(void);
it_const_relocations get_relocations(void) const;

//! @brief ``true`` if GNU hash is used
//!
//! @see get_gnu_hash and use_sysv_hash
Expand Down
9 changes: 9 additions & 0 deletions include/LIEF/ELF/Parser.hpp
Expand Up @@ -160,6 +160,15 @@ class DLL_PUBLIC Parser : public LIEF::Parser {
template<typename ELF_T>
void parse_pltgot_relocations(uint64_t offset, uint64_t size, bool isRela);


//! @brief Parse relocations using LIEF::ELF::Section.
//!
//! Parser::parse_dynamic_relocations and Parser::parse_pltgot_relocations
//! use parse relocations by using LIEF::ELF::Segment. This method parse relocations
//! that are not reachable through segments (For example Object file).
template<typename ELF_T>
void parse_section_relocations(uint64_t offset, uint64_t size, bool isRela);

//! @brief Parse SymbolVersionRequirement
//!
//! We use the virtual address stored in the
Expand Down
6 changes: 6 additions & 0 deletions include/LIEF/ELF/type_traits.hpp
Expand Up @@ -57,6 +57,12 @@ using it_const_pltgot_relocations = const_filter_iterator<const rel
using it_dynamic_relocations = filter_iterator<relocations_t>;
using it_const_dynamic_relocations = const_filter_iterator<const relocations_t>;

using it_object_relocations = filter_iterator<relocations_t>;
using it_const_object_relocations = const_filter_iterator<const relocations_t>;

using it_relocations = ref_iterator<relocations_t&>;
using it_const_relocations = const_ref_iterator<const relocations_t&>;

using symbols_version_t = std::vector<SymbolVersion*>;
using it_symbols_version = ref_iterator<symbols_version_t&>;
using it_const_symbols_version = const_ref_iterator<const symbols_version_t&>;
Expand Down
29 changes: 29 additions & 0 deletions src/ELF/Binary.cpp
Expand Up @@ -411,6 +411,35 @@ it_const_pltgot_relocations Binary::get_pltgot_relocations(void) const {
};
}


// objects
// -------
it_object_relocations Binary::get_object_relocations(void) {
return filter_iterator<relocations_t>{std::ref(this->relocations_),
[] (const Relocation* reloc) {
return reloc->purpose() == RELOCATION_PURPOSES::RELOC_PURPOSE_OBJECT;
}
};
}

it_const_object_relocations Binary::get_object_relocations(void) const {
return const_filter_iterator<const relocations_t>{std::cref(this->relocations_),
[] (const Relocation* reloc) {
return reloc->purpose() == RELOCATION_PURPOSES::RELOC_PURPOSE_OBJECT;
}
};
}

// All relocations
// ---------------
it_relocations Binary::get_relocations(void) {
return this->relocations_;
}

it_const_relocations Binary::get_relocations(void) const {
return this->relocations_;
}

LIEF::symbols_t Binary::get_abstract_symbols(void) {
return {std::begin(this->dynamic_symbols_), std::end(this->dynamic_symbols_)};
}
Expand Down
69 changes: 69 additions & 0 deletions src/ELF/Parser.tcc
Expand Up @@ -408,6 +408,22 @@ void Parser::parse_binary(void) {
}

// Try to parse using sections
for (const Section& section : this->binary_->get_sections()) {
if (section.type() == SECTION_TYPES::SHT_RELA or
section.type() == SECTION_TYPES::SHT_REL) {
try {
this->parse_section_relocations<ELF_T>(
section.file_offset(),
section.size(),
section.type() == SECTION_TYPES::SHT_RELA);
} catch (const exception& e) {
LOG(WARNING) << "Unable to parse relocations from section '"
<< section.name() << "'"
<< " (" << e.what() << ")";
}

}
}
//for (const std::shared_ptr<Section>& section : this->binary_->sections_) {
// if (section->name() == ".rela.plt" and
// (section->type() == SECTION_TYPES::SHT_RELA or
Expand Down Expand Up @@ -1293,6 +1309,59 @@ void Parser::parse_pltgot_relocations(uint64_t offset, uint64_t size, bool isRel
}
}

template<typename ELF_T>
void Parser::parse_section_relocations(uint64_t offset, uint64_t size, bool isRela) {
using Elf_Rela = typename ELF_T::Elf_Rela;
using Elf_Rel = typename ELF_T::Elf_Rel;

const uint64_t offset_relocations = offset;
const uint8_t shift = std::is_same<ELF_T, ELF32>::value ? 8 : 32;

if (isRela) {
const uint32_t nb_entries = static_cast<uint32_t>(size / sizeof(Elf_Rela));
const Elf_Rela* relocEntry = reinterpret_cast<const Elf_Rela*>(
this->stream_->read(offset_relocations, nb_entries * sizeof(Elf_Rela)));

for (uint32_t i = 0; i < nb_entries; ++i) {
Relocation* reloc = new Relocation{relocEntry};
reloc->architecture_ = this->binary_->header_.machine_type();
if (this->binary_->get_header().file_type() == ELF::E_TYPE::ET_REL and
this->binary_->get_segments().size() == 0) {
reloc->purpose(RELOCATION_PURPOSES::RELOC_PURPOSE_OBJECT);
}

const uint32_t idx = static_cast<uint32_t>(relocEntry->r_info >> shift);
if (idx > 0 and idx < this->binary_->dynamic_symbols_.size()) {
reloc->symbol_ = this->binary_->dynamic_symbols_[idx];
}

this->binary_->relocations_.push_back(reloc);
relocEntry++;
}
} else {
const uint32_t nb_entries = static_cast<uint32_t>(size / sizeof(Elf_Rel));
const Elf_Rel* relocEntry = reinterpret_cast<const Elf_Rel*>(
this->stream_->read(offset_relocations, nb_entries * sizeof(Elf_Rel)));
for (uint32_t i = 0; i < nb_entries; ++i) {
Relocation* reloc = new Relocation{relocEntry};
reloc->architecture_ = this->binary_->header_.machine_type();
if (this->binary_->get_header().file_type() == ELF::E_TYPE::ET_REL and
this->binary_->get_segments().size() == 0) {
reloc->purpose(RELOCATION_PURPOSES::RELOC_PURPOSE_OBJECT);
}


const uint32_t idx = static_cast<uint32_t>(relocEntry->r_info >> shift);
if (idx > 0 and idx < this->binary_->dynamic_symbols_.size()) {
reloc->symbol_ = this->binary_->dynamic_symbols_[idx];
}

this->binary_->relocations_.push_back(reloc);
relocEntry++;
}
}
}


template<typename ELF_T>
void Parser::parse_symbol_version_requirement(uint64_t offset, uint32_t nb_entries) {
Expand Down
1 change: 1 addition & 0 deletions src/ELF/Relocation.cpp
Expand Up @@ -318,6 +318,7 @@ std::ostream& operator<<(std::ostream& os, const Relocation& entry) {

os << std::setw(10) << entry.address()
<< std::setw(10) << relocation_type
<< std::setw(10) << std::dec << entry.size()
<< std::setw(10) << to_string(entry.purpose())
<< std::setw(10) << symbol_name;

Expand Down

0 comments on commit 483b8dc

Please sign in to comment.