mirror of
https://github.com/QuasarApp/LIEF.git
synced 2025-05-07 01:09:33 +00:00
parent
cd9cb41687
commit
a9f3cb8f9b
api/python/ELF/objects
include/LIEF/ELF
src/ELF
tests/elf
@ -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
|
||||
|
122
tests/elf/modify_relocations.py
Normal file
122
tests/elf/modify_relocations.py
Normal file
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user