Skip to content

Commit d1b98d6

Browse files
pbrunetromainthomas
authored andcommitted
Add support for static relocation writing.
1 parent 2dde1af commit d1b98d6

File tree

6 files changed

+385
-30
lines changed

6 files changed

+385
-30
lines changed

include/LIEF/ELF/Builder.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ class LIEF_API Builder {
7575
template<typename ELF_T>
7676
void build_pltgot_relocations(void);
7777

78+
template<typename ELF_T>
79+
void build_section_relocations(void);
80+
7881
template<typename ELF_T>
7982
void build_hash_table(void);
8083

include/LIEF/ELF/Parser.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ class LIEF_API Parser : public LIEF::Parser {
189189
//! use parse relocations by using LIEF::ELF::Segment. This method parse relocations
190190
//! that are not reachable through segments (For example Object file).
191191
template<typename ELF_T, typename REL_T>
192-
void parse_section_relocations(uint64_t offset, uint64_t size, Section *applies_to = nullptr);
192+
void parse_section_relocations(Section const& section);
193193

194194
//! @brief Parse SymbolVersionRequirement
195195
//!

src/ELF/Builder.tcc

Lines changed: 181 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
#include "Object.tcc"
2525

26+
#include <cassert>
27+
2628
namespace LIEF {
2729
namespace ELF {
2830

@@ -117,6 +119,13 @@ void Builder::build(void) {
117119
}
118120
}
119121

122+
if (this->binary_->object_relocations().size() > 0) {
123+
try {
124+
this->build_section_relocations<ELF_T>();
125+
} catch (const LIEF::exception& e) {
126+
LOG(ERROR) << e.what();
127+
}
128+
}
120129

121130
// Build sections
122131
if (this->binary_->sections_.size() > 0) {
@@ -223,7 +232,8 @@ void Builder::build_sections(void) {
223232
using Elf_Shdr = typename ELF_T::Elf_Shdr;
224233
VLOG(VDEBUG) << "[+] Build sections";
225234

226-
const Header& header = this->binary_->header();
235+
// FIXME: Keep it global const and local non const
236+
Header& header = this->binary_->header();
227237
const Elf_Off section_headers_offset = header.section_headers_offset();
228238

229239
std::vector<std::string> stringTableOpti =
@@ -238,27 +248,55 @@ void Builder::build_sections(void) {
238248
}
239249

240250
Section* string_names_section = this->binary_->sections_[header.section_name_table_idx()];
241-
string_names_section->content(section_names);
242251

243-
// **Should** be safe since .shstr is located at the end of the binary
244-
//if (string_names_section->size() < section_names.size()) {
245-
// string_names_section = &(this->binary_->extend_section(*string_names_section, section_names.size() - string_names_section->size() + 1));
246-
//}
252+
auto&& it_symtab_section = std::find_if(
253+
std::begin(this->binary_->sections_),
254+
std::end(this->binary_->sections_),
255+
[] (const Section* section)
256+
{
257+
return section != nullptr and section->type() == ELF_SECTION_TYPES::SHT_SYMTAB;
258+
});
247259

248-
for (size_t i = 0; i < this->binary_->sections_.size(); i++) {
249-
const Section* section = this->binary_->sections_[i];
250-
VLOG(VDEBUG) << "Writing back '" << section->name() << "'";
260+
// If there is already a symtab section with a str_section that is the same
261+
// as the str_section of sections, create a new one for str_section of sections
262+
if (it_symtab_section != std::end(this->binary_->sections_)) {
263+
Section& symbol_section = **it_symtab_section;
264+
Section* symbol_str_section = nullptr;
265+
if (symbol_section.link() != 0 or
266+
symbol_section.link() < this->binary_->sections_.size()) {
267+
symbol_str_section = this->binary_->sections_[symbol_section.link()];
268+
}
251269

252-
auto&& it_offset_name = std::search(
253-
std::begin(section_names),
254-
std::end(section_names),
255-
section->name().c_str(),
256-
section->name().c_str() + section->name().size() + 1);
270+
if(symbol_str_section == string_names_section)
271+
{
272+
Section sec_str_section(".shstrtab", ELF_SECTION_TYPES::SHT_STRTAB);
273+
sec_str_section.content(section_names);
257274

258-
if (it_offset_name == std::end(section_names)) {
259-
throw LIEF::not_found(""); // TODO: msg
275+
auto& new_str_section = this->binary_->add(sec_str_section, false);
276+
277+
auto it = std::find_if(std::begin(this->binary_->sections_),
278+
std::end(this->binary_->sections_),
279+
[&new_str_section](Section* S) {
280+
return S == &new_str_section;
281+
});
282+
assert(it != std::end(this->binary_->sections_));
283+
284+
// FIXME: We should remove the old section
285+
header.section_name_table_idx(std::distance(std::begin(this->binary_->sections_), it));
286+
287+
return this->build<ELF_T>();
260288
}
289+
}
261290

291+
// FIXME: Handle if we add sections names and we shoudl increase section size
292+
string_names_section->content(section_names);
293+
294+
// First write every section and then the header because if we do all of it
295+
// in a row, we will write the old header section after some new header so they
296+
// will be remove
297+
for (size_t i = 0; i < this->binary_->sections_.size(); i++) {
298+
const Section* section = this->binary_->sections_[i];
299+
VLOG(VDEBUG) << "Writing back '" << section->name() << "'";
262300

263301
// Write Section's content
264302
if (section->size() > 0) {
@@ -278,7 +316,7 @@ void Builder::build_sections(void) {
278316
section->name().c_str() + section->name().size() + 1);
279317

280318
if (it_offset_name == std::end(section_names)) {
281-
throw LIEF::not_found(""); // TODO: msg
319+
throw LIEF::not_found("Section name not found"); // TODO: msg
282320
}
283321

284322
const Elf_Off offset_name = static_cast<Elf_Off>(std::distance(std::begin(section_names), it_offset_name));
@@ -438,6 +476,7 @@ void Builder::build_static_symbols(void) {
438476
content.write_conv<Elf_Sym>(sym_hdr);
439477
}
440478

479+
// FIXME: Handle increase of size in symbol_str_section
441480
symbol_str_section.content(std::move(string_table));
442481
symbol_section.content(std::move(content.raw()));
443482

@@ -1098,6 +1137,131 @@ void Builder::build_dynamic_symbols(void) {
10981137

10991138
}
11001139

1140+
template<typename ELF_T>
1141+
void Builder::build_section_relocations(void) {
1142+
using Elf_Addr = typename ELF_T::Elf_Addr;
1143+
using Elf_Xword = typename ELF_T::Elf_Xword;
1144+
using Elf_Sxword = typename ELF_T::Elf_Sxword;
1145+
1146+
using Elf_Rela = typename ELF_T::Elf_Rela;
1147+
using Elf_Rel = typename ELF_T::Elf_Rel;
1148+
VLOG(VDEBUG) << "[+] Building object relocations";
1149+
1150+
it_object_relocations object_relocations = this->binary_->object_relocations();
1151+
1152+
bool isRela = object_relocations[0].is_rela();
1153+
if (not std::all_of(
1154+
std::begin(object_relocations),
1155+
std::end(object_relocations),
1156+
[isRela] (const Relocation& relocation) {
1157+
return relocation.is_rela() == isRela;
1158+
})) {
1159+
throw LIEF::type_error("Object relocations are not of the same type");
1160+
}
1161+
1162+
it_sections sections = this->binary_->sections();
1163+
1164+
std::vector<Section*> rel_section;
1165+
for(Section& S: sections)
1166+
if(S.type() == ((isRela)?ELF_SECTION_TYPES::SHT_RELA:ELF_SECTION_TYPES::SHT_REL))
1167+
rel_section.push_back(&S);
1168+
1169+
1170+
// FIXME: Warn if not rel section found?
1171+
1172+
for(Section* section: rel_section) {
1173+
1174+
if (section->information() == 0 or section->information() >= sections.size())
1175+
throw LIEF::not_found("Unable to find associated section for SHT_REL{A} section");
1176+
1177+
const size_t sh_info = section->information();
1178+
1179+
Section& AssociatedSection = sections[sh_info];
1180+
1181+
std::vector<uint8_t> content;
1182+
for (const Relocation& relocation : this->binary_->object_relocations()) {
1183+
1184+
// Only write relocation in the matching section
1185+
// (relocation for .text in .rela.text)
1186+
// FIXME: static relocation on a new section will be ignored (SILENTLY!!)
1187+
if(relocation.section_ != &AssociatedSection)
1188+
continue;
1189+
1190+
uint32_t idx = 0;
1191+
if (relocation.has_symbol()) {
1192+
const Symbol& symbol = relocation.symbol();
1193+
auto it_name = std::find_if(
1194+
std::begin(this->binary_->dynamic_symbols_),
1195+
std::end(this->binary_->dynamic_symbols_),
1196+
[&symbol] (const Symbol* s) {
1197+
return s == &symbol;
1198+
});
1199+
1200+
if (it_name == std::end(this->binary_->dynamic_symbols_)) {
1201+
// FIXME: Do we have a way to walk both?
1202+
auto it_name = std::find_if(
1203+
std::begin(this->binary_->static_symbols_),
1204+
std::end(this->binary_->static_symbols_),
1205+
[&symbol] (const Symbol* s) {
1206+
return s == &symbol;
1207+
});
1208+
1209+
if (it_name == std::end(this->binary_->static_symbols_)) {
1210+
throw not_found("Unable to find the symbol associated with the relocation");
1211+
}
1212+
idx = static_cast<uint32_t>(std::distance(std::begin(this->binary_->static_symbols_), it_name));
1213+
} else
1214+
idx = static_cast<uint32_t>(std::distance(std::begin(this->binary_->dynamic_symbols_), it_name));
1215+
}
1216+
1217+
1218+
Elf_Xword info = 0;
1219+
if (std::is_same<ELF_T, ELF32>::value) {
1220+
info = (static_cast<Elf_Xword>(idx) << 8) | relocation.type();
1221+
} else {
1222+
info = (static_cast<Elf_Xword>(idx) << 32) | (relocation.type() & 0xffffffffL);
1223+
}
1224+
1225+
if (isRela) {
1226+
Elf_Rela relahdr;
1227+
relahdr.r_offset = static_cast<Elf_Addr>(relocation.address());
1228+
relahdr.r_info = static_cast<Elf_Xword>(info);
1229+
relahdr.r_addend = static_cast<Elf_Sxword>(relocation.addend());
1230+
1231+
content.insert(
1232+
std::end(content),
1233+
reinterpret_cast<uint8_t*>(&relahdr),
1234+
reinterpret_cast<uint8_t*>(&relahdr) + sizeof(Elf_Rela));
1235+
1236+
} else {
1237+
Elf_Rel relhdr;
1238+
relhdr.r_offset = static_cast<Elf_Addr>(relocation.address());
1239+
relhdr.r_info = static_cast<Elf_Xword>(info);
1240+
1241+
content.insert(
1242+
std::end(content),
1243+
reinterpret_cast<uint8_t*>(&relhdr),
1244+
reinterpret_cast<uint8_t*>(&relhdr) + sizeof(Elf_Rel));
1245+
}
1246+
1247+
}
1248+
1249+
VLOG(VDEBUG) << "Section associated with object relocations: " << section->name();
1250+
VLOG(VDEBUG) << "Is Rela: " << std::boolalpha << isRela;
1251+
// Relocation the '.rela.xxxx' section
1252+
if (content.size() > section->original_size()) {
1253+
Section rela_section(section->name(), (isRela)?ELF_SECTION_TYPES::SHT_RELA:ELF_SECTION_TYPES::SHT_REL);
1254+
rela_section.content(content);
1255+
this->binary_->add(rela_section, false);
1256+
this->binary_->remove(*section, true);
1257+
1258+
return this->build<ELF_T>();
1259+
1260+
}
1261+
section->content(std::move(content));
1262+
}
1263+
}
1264+
11011265
template<typename ELF_T>
11021266
void Builder::build_dynamic_relocations(void) {
11031267
using Elf_Addr = typename ELF_T::Elf_Addr;

src/ELF/Parser.tcc

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,21 @@ void Parser::parse_binary(void) {
339339
nb_entries,
340340
this->binary_->sections_[section->link()]);
341341
}
342+
343+
it_symtab_section = std::find_if(
344+
it_symtab_section + 1,
345+
std::end(this->binary_->sections_),
346+
[] (const Section* section)
347+
{
348+
return section != nullptr and section->type() == ELF_SECTION_TYPES::SHT_SYMTAB;
349+
});
350+
351+
if (it_symtab_section != std::end(this->binary_->sections_)) {
352+
LOG(WARNING) << "Support for multiple SHT_SYMTAB section is not implemented\n";
353+
}
342354
}
343355

356+
344357
// Parse Symbols's hash
345358
// ====================
346359

@@ -418,21 +431,14 @@ void Parser::parse_binary(void) {
418431
// Try to parse using sections
419432
if (this->binary_->relocations_.size() == 0) {
420433
for (const Section& section : this->binary_->sections()) {
421-
Section* section_associated = nullptr;
422-
if (section.information() > 0 and section.information() < this->binary_->sections_.size()) {
423-
const size_t sh_info = section.information();
424-
section_associated = this->binary_->sections_[sh_info];
425-
}
426434

427435
try {
428436
if (section.type() == ELF_SECTION_TYPES::SHT_REL) {
429437

430-
this->parse_section_relocations<ELF_T, typename ELF_T::Elf_Rel>(
431-
section.file_offset(), section.size(), section_associated);
438+
this->parse_section_relocations<ELF_T, typename ELF_T::Elf_Rel>(section);
432439
}
433440
else if (section.type() == ELF_SECTION_TYPES::SHT_RELA) {
434-
this->parse_section_relocations<ELF_T, typename ELF_T::Elf_Rela>(
435-
section.file_offset(), section.size(), section_associated);
441+
this->parse_section_relocations<ELF_T, typename ELF_T::Elf_Rela>(section);
436442
}
437443

438444
} catch (const exception& e) {
@@ -1326,17 +1332,34 @@ void Parser::parse_pltgot_relocations(uint64_t offset, uint64_t size) {
13261332
}
13271333

13281334
template<typename ELF_T, typename REL_T>
1329-
void Parser::parse_section_relocations(uint64_t offset, uint64_t size, Section *applies_to) {
1335+
void Parser::parse_section_relocations(Section const& section) {
13301336
using Elf_Rel = typename ELF_T::Elf_Rel;
13311337
using Elf_Rela = typename ELF_T::Elf_Rela;
13321338

13331339
static_assert(std::is_same<REL_T, Elf_Rel>::value or
13341340
std::is_same<REL_T, Elf_Rela>::value, "REL_T must be Elf_Rel or Elf_Rela");
13351341

1336-
const uint64_t offset_relocations = offset;
1342+
// A relocation section can reference two other sections: a symbol table,
1343+
// identified by the sh_info section header entry, and a section to modify,
1344+
// identified by the sh_link
1345+
// BUT: in practice sh_info and sh_link are inverted
1346+
Section* applies_to = nullptr;
1347+
if (section.information() > 0 and section.information() < this->binary_->sections_.size()) {
1348+
const size_t sh_info = section.information();
1349+
applies_to = this->binary_->sections_[sh_info];
1350+
}
1351+
1352+
// FIXME: Use it
1353+
// Section* section_associated = nullptr;
1354+
// if (section.link() > 0 and section.link() < this->binary_->sections_.size()) {
1355+
// const size_t sh_link = section.link();
1356+
// section_associated = this->binary_->sections_[sh_link];
1357+
// }
1358+
1359+
const uint64_t offset_relocations = section.file_offset();
13371360
const uint8_t shift = std::is_same<ELF_T, ELF32>::value ? 8 : 32;
13381361

1339-
uint32_t nb_entries = static_cast<uint32_t>(size / sizeof(REL_T));
1362+
uint32_t nb_entries = static_cast<uint32_t>(section.size() / sizeof(REL_T));
13401363
nb_entries = std::min<uint32_t>(nb_entries, Parser::NB_MAX_RELOCATIONS);
13411364

13421365
this->stream_->setpos(offset_relocations);

tests/elf/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ if (PYTHON_TESTS_ENABLED)
205205
${PYTHON_EXECUTABLE}
206206
"${CMAKE_CURRENT_SOURCE_DIR}/test_dynamic.py")
207207

208+
ADD_PYTHON_TEST(ELF_PYTHON_test_static
209+
${PYTHON_EXECUTABLE}
210+
"${CMAKE_CURRENT_SOURCE_DIR}/test_static.py")
208211

209212
ADD_PYTHON_TEST(ELF_PYTHON_hash_test
210213
${PYTHON_EXECUTABLE}

0 commit comments

Comments
 (0)