4
0
mirror of https://github.com/QuasarApp/LIEF.git synced 2025-05-07 01:09:33 +00:00

Enable to add relocation associated with symbol

Resolve 
This commit is contained in:
Romain Thomas 2018-06-19 09:59:29 +02:00
parent cd9cb41687
commit a9f3cb8f9b
6 changed files with 255 additions and 57 deletions

@ -68,10 +68,11 @@ void create<Relocation>(py::module& m) {
&Relocation::has_symbol,
"``True`` if a " RST_CLASS_REF(lief.ELF.Symbol) " is associated with the relocations")
.def_property_readonly("symbol",
.def_property("symbol",
static_cast<Symbol& (Relocation::*)(void)>(&Relocation::symbol),
static_cast<void (Relocation::*)(Symbol*)>(&Relocation::symbol),
"" RST_CLASS_REF(lief.ELF.Symbol) " associated with the relocation",
py::return_value_policy::reference_internal)
py::return_value_policy::reference)
.def_property_readonly("has_section",
&Relocation::has_section,

@ -42,71 +42,71 @@ class LIEF_API Relocation : public LIEF::Relocation {
friend class Builder;
public:
Relocation(const Elf32_Rel* header);
Relocation(const Elf32_Rela* header);
Relocation(const Elf64_Rel* header);
Relocation(const Elf64_Rela* header);
Relocation(uint64_t address, uint32_t type = 0, int64_t addend = 0, bool isRela = false);
Relocation(const Elf32_Rel* header);
Relocation(const Elf32_Rela* header);
Relocation(const Elf64_Rel* header);
Relocation(const Elf64_Rela* header);
Relocation(uint64_t address, uint32_t type = 0, int64_t addend = 0, bool isRela = false);
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
Relocation(uint64_t address, T type, int64_t addend = 0, bool isRela = false) :
Relocation{address, static_cast<uint32_t>(type), addend, isRela}
{}
template<class T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
Relocation(uint64_t address, T type, int64_t addend = 0, bool isRela = false) :
Relocation{address, static_cast<uint32_t>(type), addend, isRela}
{}
Relocation(void);
virtual ~Relocation(void);
Relocation(void);
virtual ~Relocation(void);
Relocation& operator=(Relocation other);
Relocation(const Relocation& other);
void swap(Relocation& other);
Relocation& operator=(Relocation other);
Relocation(const Relocation& other);
void swap(Relocation& other);
//uint64_t address(void) const;
int64_t addend(void) const;
uint32_t type(void) const;
bool is_rela(void) const;
bool is_rel(void) const;
uint32_t info(void) const;
ARCH architecture(void) const;
RELOCATION_PURPOSES purpose(void) const;
//uint64_t address(void) const;
int64_t addend(void) const;
uint32_t type(void) const;
bool is_rela(void) const;
bool is_rel(void) const;
uint32_t info(void) const;
ARCH architecture(void) const;
RELOCATION_PURPOSES purpose(void) const;
//! @brief Return the **bit** size of the value to patch
//!
//! Return -1 if it fails
virtual size_t size(void) const override;
//! @brief Return the **bit** size of the value to patch
//!
//! Return -1 if it fails
virtual size_t size(void) const override;
bool has_symbol(void) const;
Symbol& symbol(void);
const Symbol& symbol(void) const;
bool has_symbol(void) const;
Symbol& symbol(void);
const Symbol& symbol(void) const;
//! True if the relocation has a section associated
bool has_section(void) const;
//! True if the relocation has a section associated
bool has_section(void) const;
//! Section associated with this relocation
Section& section(void);
const Section& section(void) const;
//! Section associated with this relocation
Section& section(void);
const Section& section(void) const;
//void address(uint64_t address);
void addend(int64_t addend);
void type(uint32_t type);
void purpose(RELOCATION_PURPOSES purpose);
void info(uint32_t v);
void addend(int64_t addend);
void type(uint32_t type);
void purpose(RELOCATION_PURPOSES purpose);
void info(uint32_t v);
void symbol(Symbol* symbol);
virtual void accept(Visitor& visitor) const override;
virtual void accept(Visitor& visitor) const override;
bool operator==(const Relocation& rhs) const;
bool operator!=(const Relocation& rhs) const;
bool operator==(const Relocation& rhs) const;
bool operator!=(const Relocation& rhs) const;
LIEF_API friend std::ostream& operator<<(std::ostream& os, const Relocation& entry);
LIEF_API friend std::ostream& operator<<(std::ostream& os, const Relocation& entry);
private:
uint32_t type_;
int64_t addend_;
bool isRela_;
Symbol* symbol_{nullptr};
ARCH architecture_;
RELOCATION_PURPOSES purpose_;
Section* section_{nullptr};
uint32_t info_;
uint32_t type_;
int64_t addend_;
bool isRela_;
Symbol* symbol_{nullptr};
ARCH architecture_;
RELOCATION_PURPOSES purpose_;
Section* section_{nullptr};
uint32_t info_;
};

@ -764,15 +764,36 @@ Relocation& Binary::add_dynamic_relocation(const Relocation& relocation) {
relocation_ptr->architecture_ = this->header().machine_type();
this->relocations_.push_back(relocation_ptr);
// Add symbol
if (relocation.has_symbol()) {
const Symbol& associated_sym = relocation.symbol();
Symbol* inner_sym = nullptr;
if (not this->has_dynamic_symbol(associated_sym.name())) {
inner_sym = &(this->add_dynamic_symbol(associated_sym));
} else {
inner_sym = &(this->get_dynamic_symbol(associated_sym.name()));
}
auto&& it_sym = std::find_if(
std::begin(this->dynamic_symbols_),
std::end(this->dynamic_symbols_),
[&inner_sym] (const Symbol* s) {
return s->name() == inner_sym->name();
});
const size_t idx = std::distance(std::begin(this->dynamic_symbols_), it_sym);
relocation_ptr->info(idx);
relocation_ptr->symbol(inner_sym);
}
// Update the Dynamic Section (Thanks to @yd0b0N)
bool is_rela = relocation.is_rela();
DYNAMIC_TAGS tag_sz = is_rela ? DYNAMIC_TAGS::DT_RELASZ : DYNAMIC_TAGS::DT_RELSZ;
DYNAMIC_TAGS tag_ent = is_rela ? DYNAMIC_TAGS::DT_RELAENT : DYNAMIC_TAGS::DT_RELENT;
if (this->has(tag_sz) and this->has(tag_ent)) {
DynamicEntry &dt_sz = this->get(tag_sz);
DynamicEntry &dt_ent = this->get(tag_ent);
dt_sz.value(dt_sz.value() + dt_ent.value());
DynamicEntry &dt_sz = this->get(tag_sz);
DynamicEntry &dt_ent = this->get(tag_ent);
dt_sz.value(dt_sz.value() + dt_ent.value());
}
return *relocation_ptr;
@ -783,6 +804,52 @@ Relocation& Binary::add_pltgot_relocation(const Relocation& relocation) {
Relocation* relocation_ptr = new Relocation{relocation};
relocation_ptr->purpose(RELOCATION_PURPOSES::RELOC_PURPOSE_PLTGOT);
relocation_ptr->architecture_ = this->header().machine_type();
// Add symbol
if (relocation.has_symbol()) {
const Symbol& associated_sym = relocation.symbol();
Symbol* inner_sym = nullptr;
if (not this->has_dynamic_symbol(associated_sym.name())) {
inner_sym = &(this->add_dynamic_symbol(associated_sym));
} else {
inner_sym = &(this->get_dynamic_symbol(associated_sym.name()));
}
auto&& it_sym = std::find_if(
std::begin(this->dynamic_symbols_),
std::end(this->dynamic_symbols_),
[&inner_sym] (const Symbol* s) {
return s->name() == inner_sym->name();
});
const size_t idx = std::distance(std::begin(this->dynamic_symbols_), it_sym);
relocation_ptr->info(idx);
relocation_ptr->symbol(inner_sym);
}
// Update the Dynamic Section
const bool is_rela = relocation.is_rela();
const bool is64 = (this->type() == ELF_CLASS::ELFCLASS64);
size_t reloc_size = 0;
if (is_rela) {
if (is64) {
reloc_size = sizeof(Elf64_Rela);
} else {
reloc_size = sizeof(Elf32_Rela);
}
} else {
if (is64) {
reloc_size = sizeof(Elf64_Rel);
} else {
reloc_size = sizeof(Elf32_Rel);
}
}
if (this->has(DYNAMIC_TAGS::DT_PLTRELSZ) and this->has(DYNAMIC_TAGS::DT_JMPREL)) {
DynamicEntry &dt_sz = this->get(DYNAMIC_TAGS::DT_PLTRELSZ);
dt_sz.value(dt_sz.value() + reloc_size);
}
this->relocations_.push_back(relocation_ptr);
return *relocation_ptr;
}
@ -1926,7 +1993,7 @@ void Binary::shift_relocations(uint64_t from, uint64_t shift) {
break;
}
*/
default:
{
LOG(WARNING) << "Relocations for architecture " << to_string(arch) << " is not supported!";

@ -290,6 +290,10 @@ void Relocation::info(uint32_t v) {
this->info_ = v;
}
void Relocation::symbol(Symbol* sym) {
this->symbol_ = sym;
}
void Relocation::purpose(RELOCATION_PURPOSES purpose) {
this->purpose_ = purpose;

@ -224,6 +224,10 @@ if (PYTHON_TESTS_ENABLED)
${PYTHON_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/test_bin2lib.py")
ADD_PYTHON_TEST(ELF_PYTHON_modify_relocations
${PYTHON_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/modify_relocations.py")
# Examples
# --------
ADD_PYTHON_TEST(EXAMPLE_PYTHON_elf_reader_ls

@ -0,0 +1,122 @@
#!/usr/bin/env python
import unittest
import logging
import os
import sys
import stat
import re
import subprocess
import tempfile
import shutil
from subprocess import Popen
import lief
from lief.ELF import Section
from unittest import TestCase
from utils import get_sample
class TestRelocations(TestCase):
def setUp(self):
self.logger = logging.getLogger(__name__)
self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_relocations')
self.logger.debug("temp dir: {}".format(self.tmp_dir))
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_simple(self):
sample_path = get_sample('ELF/ELF64_x86-64_binary_ls.bin')
output = os.path.join(self.tmp_dir, "ls.relocation")
ls = lief.parse(sample_path)
relocation = lief.ELF.Relocation(0x61D370, type=lief.ELF.RELOCATION_X86_64.JUMP_SLOT, is_rela=True)
symbol = lief.ELF.Symbol()
symbol.name = "printf123"
relocation.symbol = symbol
ls.add_pltgot_relocation(relocation)
ls.write(output)
st = os.stat(output)
os.chmod(output, st.st_mode | stat.S_IEXEC)
p = Popen([output, "--version"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
self.logger.debug(stdout.decode("utf8"))
self.assertIsNotNone(re.search(r'ls \(GNU coreutils\) ', stdout.decode("utf8")))
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_all(self):
sample_path = get_sample('ELF/ELF64_x86-64_binary_all.bin')
output = os.path.join(self.tmp_dir, "all.relocation")
target = lief.parse(sample_path)
relocation = lief.ELF.Relocation(0x201028, type=lief.ELF.RELOCATION_X86_64.JUMP_SLOT, is_rela=True)
symbol = lief.ELF.Symbol()
symbol.name = "printf123"
relocation.symbol = symbol
target.add_pltgot_relocation(relocation)
target.write(output)
st = os.stat(output)
os.chmod(output, st.st_mode | stat.S_IEXEC)
p = Popen([output], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
self.logger.debug(stdout.decode("utf8"))
self.assertIsNotNone(re.search(r'Hello World: 1', stdout.decode("utf8")))
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
def test_all32(self):
sample_path = get_sample('ELF/ELF32_x86_binary_all.bin')
output = os.path.join(self.tmp_dir, "all32.relocation")
output = "/tmp/foo"
target = lief.parse(sample_path)
relocation = lief.ELF.Relocation(0x2018, type=lief.ELF.RELOCATION_i386.JUMP_SLOT, is_rela=False)
symbol = lief.ELF.Symbol()
symbol.name = "printf123"
relocation.symbol = symbol
target.add_pltgot_relocation(relocation)
target.write(output)
st = os.stat(output)
os.chmod(output, st.st_mode | stat.S_IEXEC)
p = Popen([output], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
self.logger.debug(stdout.decode("utf8"))
self.assertIsNotNone(re.search(r'Hello World: 1', stdout.decode("utf8")))
def tearDown(self):
# Delete it
if os.path.isdir(self.tmp_dir):
#shutil.rmtree(self.tmp_dir)
pass
if __name__ == '__main__':
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
root_logger.addHandler(ch)
unittest.main(verbosity=2)